1use std::fmt;
2use std::marker::PhantomData;
3
4use skia_bindings::{
5 self as sb, SkContourMeasure, SkContourMeasureIter, SkContourMeasure_ForwardVerbIterator,
6 SkContourMeasure_VerbMeasure, SkRefCntBase,
7};
8
9use crate::{prelude::*, scalar, Matrix, Path, PathBuilder, PathVerb, Point, Vector};
10
11pub type ContourMeasure = RCHandle<SkContourMeasure>;
12unsafe_send_sync!(ContourMeasure);
13
14impl NativeRefCountedBase for SkContourMeasure {
15 type Base = SkRefCntBase;
16}
17
18bitflags! {
19 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
21 pub struct MatrixFlags : u32 {
22 const GET_POSITION = sb::SkContourMeasure_MatrixFlags_kGetPosition_MatrixFlag as _;
24 const GET_TANGENT = sb::SkContourMeasure_MatrixFlags_kGetTangent_MatrixFlag as _;
26 const GET_POS_AND_TAN = Self::GET_POSITION.bits() | Self::GET_TANGENT.bits();
28 }
29}
30
31impl Default for MatrixFlags {
32 fn default() -> Self {
33 Self::GET_POS_AND_TAN
34 }
35}
36
37impl fmt::Debug for ContourMeasure {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("ContourMeasure")
40 .field("length", &self.length())
41 .field("is_closed", &self.is_closed())
42 .finish()
43 }
44}
45
46impl ContourMeasure {
47 pub fn length(&self) -> scalar {
49 unsafe { sb::C_SkContourMeasure_length(self.native()) }
50 }
51
52 #[must_use]
57 pub fn pos_tan(&self, distance: scalar) -> Option<(Point, Vector)> {
58 let mut p = Point::default();
59 let mut v = Vector::default();
60 unsafe {
61 self.native()
62 .getPosTan(distance, p.native_mut(), v.native_mut())
63 }
64 .then_some((p, v))
65 }
66
67 #[must_use]
68 pub fn get_matrix(
76 &self,
77 distance: scalar,
78 flags: impl Into<Option<MatrixFlags>>,
79 ) -> Option<Matrix> {
80 let mut m = Matrix::default();
81 unsafe {
82 self.native().getMatrix(
83 distance,
84 m.native_mut(),
85 #[allow(clippy::useless_conversion)]
89 flags.into().unwrap_or_default().bits().try_into().unwrap(),
90 )
91 }
92 .then_some(m)
93 }
94
95 #[deprecated(since = "0.94.0", note = "Use get_segment()")]
96 #[must_use]
97 pub fn segment(
110 &self,
111 start_d: scalar,
112 stop_d: scalar,
113 path_builder: &mut PathBuilder,
114 start_with_move_to: bool,
115 ) -> bool {
116 self.get_segment(start_d, stop_d, path_builder, start_with_move_to)
117 }
118
119 #[must_use]
120 pub fn get_segment(
133 &self,
134 start_d: scalar,
135 stop_d: scalar,
136 path_builder: &mut PathBuilder,
137 start_with_move_to: bool,
138 ) -> bool {
139 unsafe {
140 self.native().getSegment(
141 start_d,
142 stop_d,
143 path_builder.native_mut(),
144 start_with_move_to,
145 )
146 }
147 }
148
149 pub fn is_closed(&self) -> bool {
151 unsafe { sb::C_SkContourMeasure_isClosed(self.native()) }
152 }
153
154 pub fn verbs(&self) -> ForwardVerbIterator {
156 let iterator =
157 construct(|iterator| unsafe { sb::C_SkContourMeasure_begin(self.native(), iterator) });
158
159 ForwardVerbIterator {
160 iterator,
161 contour_measure: self,
162 }
163 }
164}
165
166pub struct ForwardVerbIterator<'a> {
168 iterator: SkContourMeasure_ForwardVerbIterator,
169 contour_measure: &'a ContourMeasure,
170}
171unsafe_send_sync!(ForwardVerbIterator<'_>);
172
173impl fmt::Debug for ForwardVerbIterator<'_> {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 f.debug_struct("ForwardVerbIterator").finish()
176 }
177}
178
179impl PartialEq for ForwardVerbIterator<'_> {
180 fn eq(&self, other: &Self) -> bool {
181 unsafe {
182 sb::C_SkContourMeasure_ForwardVerbIterator_Equals(&self.iterator, &other.iterator)
183 }
184 }
185}
186
187impl<'a> Iterator for ForwardVerbIterator<'a> {
188 type Item = VerbMeasure<'a>;
189
190 fn next(&mut self) -> Option<Self::Item> {
191 let end = construct(|end| unsafe {
192 sb::C_SkContourMeasure_end(self.contour_measure.native(), end)
193 });
194 if unsafe { sb::C_SkContourMeasure_ForwardVerbIterator_Equals(&self.iterator, &end) } {
195 return None;
196 }
197 let item = construct(|item| unsafe {
198 sb::C_SkContourMeasure_ForwardVerbIterator_item(&self.iterator, item)
199 });
200 unsafe { sb::C_SkContourMeasure_ForwardVerbIterator_next(&mut self.iterator) };
201 Some(VerbMeasure {
202 verb_measure: item,
203 _pd: PhantomData,
204 })
205 }
206}
207
208pub struct VerbMeasure<'a> {
210 verb_measure: SkContourMeasure_VerbMeasure,
211 _pd: PhantomData<ForwardVerbIterator<'a>>,
212}
213unsafe_send_sync!(VerbMeasure<'_>);
214
215impl fmt::Debug for VerbMeasure<'_> {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 f.debug_struct("VerbMeasure")
218 .field("verb", &self.verb())
219 .field("distance", &self.distance())
220 .field("points", &self.points())
221 .finish()
222 }
223}
224
225impl VerbMeasure<'_> {
226 pub fn verb(&self) -> PathVerb {
228 self.verb_measure.fVerb
229 }
230
231 pub fn distance(&self) -> scalar {
233 self.verb_measure.fDistance
234 }
235
236 pub fn points(&self) -> &[Point] {
238 unsafe {
239 safer::from_raw_parts(
240 Point::from_native_ptr(self.verb_measure.fPts.fPtr),
241 self.verb_measure.fPts.fSize,
242 )
243 }
244 }
245}
246
247pub type ContourMeasureIter = Handle<SkContourMeasureIter>;
248unsafe_send_sync!(ContourMeasureIter);
249
250impl NativeDrop for SkContourMeasureIter {
251 fn drop(&mut self) {
252 unsafe {
253 sb::C_SkContourMeasureIter_destruct(self);
254 }
255 }
256}
257
258impl Iterator for ContourMeasureIter {
259 type Item = ContourMeasure;
260
261 fn next(&mut self) -> Option<Self::Item> {
272 ContourMeasure::from_ptr(unsafe { sb::C_SkContourMeasureIter_next(self.native_mut()) })
273 }
274}
275
276impl fmt::Debug for ContourMeasureIter {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 f.debug_struct("ContourMeasureIter").finish()
279 }
280}
281
282impl ContourMeasureIter {
283 pub fn new(path: &Path, force_closed: bool, res_scale: impl Into<Option<scalar>>) -> Self {
295 Self::from_path(path, force_closed, res_scale)
296 }
297
298 pub fn from_path(
310 path: &Path,
311 force_closed: bool,
312 res_scale: impl Into<Option<scalar>>,
313 ) -> Self {
314 Self::from_native_c(unsafe {
315 SkContourMeasureIter::new1(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
316 })
317 }
318
319 pub fn reset(
328 &mut self,
329 path: &Path,
330 force_closed: bool,
331 res_scale: impl Into<Option<scalar>>,
332 ) -> &mut Self {
333 unsafe {
334 self.native_mut()
335 .reset(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
336 }
337 self
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use super::ContourMeasureIter;
344 use crate::{Path, Rect};
345
346 #[test]
347 fn contour_and_verb_measure() {
348 let p = Path::rect(Rect::new(0.0, 0.0, 10.0, 10.0), None);
349 let measure = ContourMeasureIter::new(&p, true, None);
350 for contour in measure {
351 for verb in contour.verbs() {
352 println!("verb: {verb:?}")
353 }
354 }
355 }
356}