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 #[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 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 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}