skia_safe/core/
contour_measure.rs

1use crate::{prelude::*, scalar, Matrix, Path, 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        .if_true_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        .if_true_some(m)
74    }
75
76    #[must_use]
77    pub fn segment(
78        &self,
79        start_d: scalar,
80        stop_d: scalar,
81        start_with_move_to: bool,
82    ) -> Option<Path> {
83        let mut p = Path::default();
84        unsafe {
85            self.native()
86                .getSegment(start_d, stop_d, p.native_mut(), start_with_move_to)
87        }
88        .if_true_some(p)
89    }
90
91    pub fn is_closed(&self) -> bool {
92        unsafe { sb::C_SkContourMeasure_isClosed(self.native()) }
93    }
94
95    pub fn verbs(&self) -> ForwardVerbIterator {
96        let iterator =
97            construct(|iterator| unsafe { sb::C_SkContourMeasure_begin(self.native(), iterator) });
98
99        ForwardVerbIterator {
100            iterator,
101            contour_measure: self,
102        }
103    }
104}
105
106pub struct ForwardVerbIterator<'a> {
107    iterator: SkContourMeasure_ForwardVerbIterator,
108    contour_measure: &'a ContourMeasure,
109}
110unsafe_send_sync!(ForwardVerbIterator<'_>);
111
112impl fmt::Debug for ForwardVerbIterator<'_> {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        f.debug_struct("ForwardVerbIterator").finish()
115    }
116}
117
118impl PartialEq for ForwardVerbIterator<'_> {
119    fn eq(&self, other: &Self) -> bool {
120        unsafe {
121            sb::C_SkContourMeasure_ForwardVerbIterator_Equals(&self.iterator, &other.iterator)
122        }
123    }
124}
125
126impl<'a> Iterator for ForwardVerbIterator<'a> {
127    type Item = VerbMeasure<'a>;
128
129    fn next(&mut self) -> Option<Self::Item> {
130        let end = construct(|end| unsafe {
131            sb::C_SkContourMeasure_end(self.contour_measure.native(), end)
132        });
133        if unsafe { sb::C_SkContourMeasure_ForwardVerbIterator_Equals(&self.iterator, &end) } {
134            return None;
135        }
136        let item = construct(|item| unsafe {
137            sb::C_SkContourMeasure_ForwardVerbIterator_item(&self.iterator, item)
138        });
139        unsafe { sb::C_SkContourMeasure_ForwardVerbIterator_next(&mut self.iterator) };
140        Some(VerbMeasure {
141            verb_measure: item,
142            _pd: PhantomData,
143        })
144    }
145}
146
147pub struct VerbMeasure<'a> {
148    verb_measure: SkContourMeasure_VerbMeasure,
149    _pd: PhantomData<ForwardVerbIterator<'a>>,
150}
151unsafe_send_sync!(VerbMeasure<'_>);
152
153impl fmt::Debug for VerbMeasure<'_> {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        f.debug_struct("VerbMeasure")
156            .field("verb", &self.verb())
157            .field("distance", &self.distance())
158            .field("points", &self.points())
159            .finish()
160    }
161}
162
163impl VerbMeasure<'_> {
164    pub fn verb(&self) -> PathVerb {
165        self.verb_measure.fVerb
166    }
167
168    pub fn distance(&self) -> scalar {
169        self.verb_measure.fDistance
170    }
171
172    pub fn points(&self) -> &[Point] {
173        unsafe {
174            safer::from_raw_parts(
175                Point::from_native_ptr(self.verb_measure.fPts.fPtr),
176                self.verb_measure.fPts.fSize,
177            )
178        }
179    }
180}
181
182pub type ContourMeasureIter = Handle<SkContourMeasureIter>;
183unsafe_send_sync!(ContourMeasureIter);
184
185impl NativeDrop for SkContourMeasureIter {
186    fn drop(&mut self) {
187        unsafe {
188            sb::C_SkContourMeasureIter_destruct(self);
189        }
190    }
191}
192
193impl Iterator for ContourMeasureIter {
194    type Item = ContourMeasure;
195
196    fn next(&mut self) -> Option<Self::Item> {
197        ContourMeasure::from_ptr(unsafe { sb::C_SkContourMeasureIter_next(self.native_mut()) })
198    }
199}
200
201impl fmt::Debug for ContourMeasureIter {
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        f.debug_struct("ContourMeasureIter").finish()
204    }
205}
206
207impl ContourMeasureIter {
208    // Canonical new:
209    pub fn new(path: &Path, force_closed: bool, res_scale: impl Into<Option<scalar>>) -> Self {
210        Self::from_path(path, force_closed, res_scale)
211    }
212
213    // TODO: rename to of_path? for_path?
214    // TODO: may deprecate in favor of Self::new().
215    pub fn from_path(
216        path: &Path,
217        force_closed: bool,
218        res_scale: impl Into<Option<scalar>>,
219    ) -> Self {
220        Self::from_native_c(unsafe {
221            SkContourMeasureIter::new1(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
222        })
223    }
224
225    pub fn reset(
226        &mut self,
227        path: &Path,
228        force_closed: bool,
229        res_scale: impl Into<Option<scalar>>,
230    ) -> &mut Self {
231        unsafe {
232            self.native_mut()
233                .reset(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
234        }
235        self
236    }
237}
238
239#[cfg(test)]
240mod test {
241    use super::ContourMeasureIter;
242    use crate::{Path, Rect};
243
244    #[test]
245    fn contour_and_verb_measure() {
246        let mut p = Path::new();
247        p.add_rect(Rect::new(0.0, 0.0, 10.0, 10.0), None);
248        let measure = ContourMeasureIter::new(&p, true, None);
249        for contour in measure {
250            for verb in contour.verbs() {
251                println!("verb: {verb:?}")
252            }
253        }
254    }
255}