skia_safe/core/
contour_measure.rs1use 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 #[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 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 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}