skia_safe/core/
path_measure.rs1use crate::{prelude::*, scalar, ContourMeasure, Matrix, Path, PathBuilder, Point, Vector};
2use skia_bindings::{self as sb, SkPathMeasure};
3use std::fmt;
4
5pub type PathMeasure = Handle<SkPathMeasure>;
6
7impl NativeDrop for SkPathMeasure {
8 fn drop(&mut self) {
9 unsafe { sb::C_SkPathMeasure_destruct(self) }
10 }
11}
12
13bitflags! {
14 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15 pub struct MatrixFlags : u32 {
16 const GET_POSITION = sb::SkPathMeasure_MatrixFlags_kGetPosition_MatrixFlag as _;
17 const GET_TANGENT = sb::SkPathMeasure_MatrixFlags_kGetTangent_MatrixFlag as _;
18 const GET_POS_AND_TAN = Self::GET_POSITION.bits() | Self::GET_TANGENT.bits();
19 }
20}
21
22impl Default for MatrixFlags {
23 fn default() -> Self {
24 Self::GET_POS_AND_TAN
25 }
26}
27
28impl Default for PathMeasure {
29 fn default() -> Self {
30 Self::from_native_c(unsafe { SkPathMeasure::new() })
31 }
32}
33
34impl fmt::Debug for PathMeasure {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 f.debug_struct("PathMeasure")
37 .field("current_measure", &self.current_measure())
42 .finish()
43 }
44}
45
46impl PathMeasure {
63 pub fn new(path: &Path, force_closed: bool, res_scale: impl Into<Option<scalar>>) -> Self {
64 Self::from_native_c(unsafe {
65 SkPathMeasure::new1(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
66 })
67 }
68
69 #[deprecated(since = "0.48.0", note = "Use PathMeasure::new")]
70 pub fn from_path(
71 path: &Path,
72 force_closed: bool,
73 res_scale: impl Into<Option<scalar>>,
74 ) -> Self {
75 Self::new(path, force_closed, res_scale)
76 }
77
78 pub fn set_path(&mut self, path: &Path, force_closed: bool) -> &mut Self {
79 unsafe { self.native_mut().setPath(path.native(), force_closed) }
80 self
81 }
82
83 pub fn length(&mut self) -> scalar {
84 unsafe { self.native_mut().getLength() }
85 }
86
87 #[must_use]
89 pub fn pos_tan(&mut self, distance: scalar) -> Option<(Point, Vector)> {
90 let mut position = Point::default();
91 let mut tangent = Vector::default();
92 unsafe {
93 self.native_mut()
94 .getPosTan(distance, position.native_mut(), tangent.native_mut())
95 }
96 .then_some((position, tangent))
97 }
98
99 #[deprecated(since = "0.88.0", note = "Use get_matrix()")]
100 #[must_use]
101 pub fn matrix(
102 &mut self,
103 distance: scalar,
104 flags: impl Into<Option<MatrixFlags>>,
105 ) -> Option<Matrix> {
106 let mut m = Matrix::default();
107 unsafe {
108 self.native_mut().getMatrix(
109 distance,
110 m.native_mut(),
111 #[allow(clippy::useless_conversion)]
113 flags.into().unwrap_or_default().bits().try_into().unwrap(),
114 )
115 }
116 .then_some(m)
117 }
118
119 #[must_use]
120 pub fn get_matrix(
121 &mut self,
122 distance: scalar,
123 matrix: &mut Matrix,
124 flags: impl Into<Option<MatrixFlags>>,
125 ) -> bool {
126 unsafe {
127 self.native_mut().getMatrix(
128 distance,
129 matrix.native_mut(),
130 #[allow(clippy::useless_conversion)]
132 flags.into().unwrap_or_default().bits().try_into().unwrap(),
133 )
134 }
135 }
136
137 #[deprecated(since = "0.88.0", note = "Use get_segment()")]
138 pub fn segment(
139 &mut self,
140 start_d: scalar,
141 stop_d: scalar,
142 start_with_move_to: bool,
143 ) -> Option<Path> {
144 let mut p = PathBuilder::default();
145 unsafe {
146 self.native_mut()
147 .getSegment(start_d, stop_d, p.native_mut(), start_with_move_to)
148 }
149 .then_some(p.detach())
150 }
151
152 pub fn get_segment(
153 &mut self,
154 start_d: scalar,
155 stop_d: scalar,
156 dst: &mut PathBuilder,
157 start_with_move_to: bool,
158 ) -> bool {
159 unsafe {
160 self.native_mut()
161 .getSegment(start_d, stop_d, dst.native_mut(), start_with_move_to)
162 }
163 }
164
165 #[allow(clippy::wrong_self_convention)]
166 pub fn is_closed(&mut self) -> bool {
167 unsafe { self.native_mut().isClosed() }
168 }
169
170 pub fn next_contour(&mut self) -> bool {
172 unsafe { self.native_mut().nextContour() }
173 }
174
175 pub fn current_measure(&self) -> &Option<ContourMeasure> {
176 ContourMeasure::from_unshared_ptr_ref(&self.native().fContour.fPtr)
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use crate::{Path, PathMeasure, Point};
183
184 #[test]
185 fn current_measure() {
186 let mut path = Path::circle((0., 0.), 10.0, None);
187 path.add_path(
188 &Path::circle((100., 100.), 27.0, None),
189 Point::default(),
190 None,
191 );
192 let mut measure = PathMeasure::new(&path, false, None);
193 while measure.next_contour() {
194 eprintln!("contour: {:?}", measure.current_measure());
195 }
196 assert!(measure.current_measure().is_none());
197 }
198}