skia_safe/core/
contour_measure.rs

1use crate::{prelude::*, scalar, Matrix, Path, PathBuilder, PathVerb, Point, Vector};
2use skia_bindings::{
3    self as sb, SkContourMeasure, SkContourMeasureIter, SkContourMeasure_ForwardVerbIterator,
4    SkContourMeasure_VerbMeasure, SkRefCntBase,
5};
6use std::{fmt, marker::PhantomData};
7
8pub type ContourMeasure = RCHandle<SkContourMeasure>;
9unsafe_send_sync!(ContourMeasure);
10
11impl NativeRefCountedBase for SkContourMeasure {
12    type Base = SkRefCntBase;
13}
14
15bitflags! {
16    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17    pub struct MatrixFlags : u32 {
18        const GET_POSITION = sb::SkContourMeasure_MatrixFlags_kGetPosition_MatrixFlag as _;
19        const GET_TANGENT = sb::SkContourMeasure_MatrixFlags_kGetTangent_MatrixFlag as _;
20        const GET_POS_AND_TAN = Self::GET_POSITION.bits() | Self::GET_TANGENT.bits();
21    }
22}
23
24impl Default for MatrixFlags {
25    fn default() -> Self {
26        Self::GET_POS_AND_TAN
27    }
28}
29
30impl fmt::Debug for ContourMeasure {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        f.debug_struct("ContourMeasure")
33            .field("length", &self.length())
34            .field("is_closed", &self.is_closed())
35            .finish()
36    }
37}
38
39impl ContourMeasure {
40    pub fn length(&self) -> scalar {
41        unsafe { sb::C_SkContourMeasure_length(self.native()) }
42    }
43
44    #[must_use]
45    pub fn pos_tan(&self, distance: scalar) -> Option<(Point, Vector)> {
46        let mut p = Point::default();
47        let mut v = Vector::default();
48        unsafe {
49            self.native()
50                .getPosTan(distance, p.native_mut(), v.native_mut())
51        }
52        .then_some((p, v))
53    }
54
55    #[must_use]
56    pub fn get_matrix(
57        &self,
58        distance: scalar,
59        flags: impl Into<Option<MatrixFlags>>,
60    ) -> Option<Matrix> {
61        let mut m = Matrix::default();
62        unsafe {
63            self.native().getMatrix(
64                distance,
65                m.native_mut(),
66                // note: depending on the OS, different representation types are generated for
67                // MatrixFlags, so the try_into() is required, even though clippy complains about
68                // it.
69                #[allow(clippy::useless_conversion)]
70                flags.into().unwrap_or_default().bits().try_into().unwrap(),
71            )
72        }
73        .then_some(m)
74    }
75
76    #[must_use]
77    pub fn segment(
78        &self,
79        start_d: scalar,
80        stop_d: scalar,
81        path_builder: &mut PathBuilder,
82        start_with_move_to: bool,
83    ) -> bool {
84        unsafe {
85            self.native().getSegment(
86                start_d,
87                stop_d,
88                path_builder.native_mut(),
89                start_with_move_to,
90            )
91        }
92    }
93
94    pub fn is_closed(&self) -> bool {
95        unsafe { sb::C_SkContourMeasure_isClosed(self.native()) }
96    }
97
98    pub fn verbs(&self) -> ForwardVerbIterator {
99        let iterator =
100            construct(|iterator| unsafe { sb::C_SkContourMeasure_begin(self.native(), iterator) });
101
102        ForwardVerbIterator {
103            iterator,
104            contour_measure: self,
105        }
106    }
107}
108
109pub struct ForwardVerbIterator<'a> {
110    iterator: SkContourMeasure_ForwardVerbIterator,
111    contour_measure: &'a ContourMeasure,
112}
113unsafe_send_sync!(ForwardVerbIterator<'_>);
114
115impl fmt::Debug for ForwardVerbIterator<'_> {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        f.debug_struct("ForwardVerbIterator").finish()
118    }
119}
120
121impl PartialEq for ForwardVerbIterator<'_> {
122    fn eq(&self, other: &Self) -> bool {
123        unsafe {
124            sb::C_SkContourMeasure_ForwardVerbIterator_Equals(&self.iterator, &other.iterator)
125        }
126    }
127}
128
129impl<'a> Iterator for ForwardVerbIterator<'a> {
130    type Item = VerbMeasure<'a>;
131
132    fn next(&mut self) -> Option<Self::Item> {
133        let end = construct(|end| unsafe {
134            sb::C_SkContourMeasure_end(self.contour_measure.native(), end)
135        });
136        if unsafe { sb::C_SkContourMeasure_ForwardVerbIterator_Equals(&self.iterator, &end) } {
137            return None;
138        }
139        let item = construct(|item| unsafe {
140            sb::C_SkContourMeasure_ForwardVerbIterator_item(&self.iterator, item)
141        });
142        unsafe { sb::C_SkContourMeasure_ForwardVerbIterator_next(&mut self.iterator) };
143        Some(VerbMeasure {
144            verb_measure: item,
145            _pd: PhantomData,
146        })
147    }
148}
149
150pub struct VerbMeasure<'a> {
151    verb_measure: SkContourMeasure_VerbMeasure,
152    _pd: PhantomData<ForwardVerbIterator<'a>>,
153}
154unsafe_send_sync!(VerbMeasure<'_>);
155
156impl fmt::Debug for VerbMeasure<'_> {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        f.debug_struct("VerbMeasure")
159            .field("verb", &self.verb())
160            .field("distance", &self.distance())
161            .field("points", &self.points())
162            .finish()
163    }
164}
165
166impl VerbMeasure<'_> {
167    pub fn verb(&self) -> PathVerb {
168        self.verb_measure.fVerb
169    }
170
171    pub fn distance(&self) -> scalar {
172        self.verb_measure.fDistance
173    }
174
175    pub fn points(&self) -> &[Point] {
176        unsafe {
177            safer::from_raw_parts(
178                Point::from_native_ptr(self.verb_measure.fPts.fPtr),
179                self.verb_measure.fPts.fSize,
180            )
181        }
182    }
183}
184
185pub type ContourMeasureIter = Handle<SkContourMeasureIter>;
186unsafe_send_sync!(ContourMeasureIter);
187
188impl NativeDrop for SkContourMeasureIter {
189    fn drop(&mut self) {
190        unsafe {
191            sb::C_SkContourMeasureIter_destruct(self);
192        }
193    }
194}
195
196impl Iterator for ContourMeasureIter {
197    type Item = ContourMeasure;
198
199    fn next(&mut self) -> Option<Self::Item> {
200        ContourMeasure::from_ptr(unsafe { sb::C_SkContourMeasureIter_next(self.native_mut()) })
201    }
202}
203
204impl fmt::Debug for ContourMeasureIter {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        f.debug_struct("ContourMeasureIter").finish()
207    }
208}
209
210impl ContourMeasureIter {
211    // Canonical new:
212    pub fn new(path: &Path, force_closed: bool, res_scale: impl Into<Option<scalar>>) -> Self {
213        Self::from_path(path, force_closed, res_scale)
214    }
215
216    // TODO: rename to of_path? for_path?
217    // TODO: may deprecate in favor of Self::new().
218    pub fn from_path(
219        path: &Path,
220        force_closed: bool,
221        res_scale: impl Into<Option<scalar>>,
222    ) -> Self {
223        Self::from_native_c(unsafe {
224            SkContourMeasureIter::new1(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
225        })
226    }
227
228    pub fn reset(
229        &mut self,
230        path: &Path,
231        force_closed: bool,
232        res_scale: impl Into<Option<scalar>>,
233    ) -> &mut Self {
234        unsafe {
235            self.native_mut()
236                .reset(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
237        }
238        self
239    }
240}
241
242#[cfg(test)]
243mod tests {
244    use super::ContourMeasureIter;
245    use crate::{Path, Rect};
246
247    #[test]
248    fn contour_and_verb_measure() {
249        let mut p = Path::new();
250        p.add_rect(Rect::new(0.0, 0.0, 10.0, 10.0), None);
251        let measure = ContourMeasureIter::new(&p, true, None);
252        for contour in measure {
253            for verb in contour.verbs() {
254                println!("verb: {verb:?}")
255            }
256        }
257    }
258}