1use crate::{prelude::*, scalar, Matrix, Path, Point, Vector};
2use skia_bindings::{self as sb, SkContourMeasure, SkContourMeasureIter, SkRefCntBase};
3use std::fmt;
4
5pub type ContourMeasure = RCHandle<SkContourMeasure>;
6unsafe_send_sync!(ContourMeasure);
7
8impl NativeRefCountedBase for SkContourMeasure {
9 type Base = SkRefCntBase;
10}
11
12bitflags! {
13 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14 pub struct MatrixFlags : u32 {
15 const GET_POSITION = sb::SkContourMeasure_MatrixFlags_kGetPosition_MatrixFlag as _;
16 const GET_TANGENT = sb::SkContourMeasure_MatrixFlags_kGetTangent_MatrixFlag as _;
17 const GET_POS_AND_TAN = Self::GET_POSITION.bits() | Self::GET_TANGENT.bits();
18 }
19}
20
21impl Default for MatrixFlags {
22 fn default() -> Self {
23 Self::GET_POS_AND_TAN
24 }
25}
26
27impl fmt::Debug for ContourMeasure {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 f&mut DebugStruct<'_, '_>.debug_struct("ContourMeasure")
30 .field("length", &self.length())
31 .field(name:"is_closed", &self.is_closed())
32 .finish()
33 }
34}
35
36impl ContourMeasure {
37 pub fn length(&self) -> scalar {
38 unsafe { sb::C_SkContourMeasure_length(self.native()) }
39 }
40
41 #[must_use]
42 pub fn pos_tan(&self, distance: scalar) -> Option<(Point, Vector)> {
43 let mut p = Point::default();
44 let mut v = Vector::default();
45 unsafe {
46 self.native()
47 .getPosTan(distance, p.native_mut(), v.native_mut())
48 }
49 .if_true_some((p, v))
50 }
51
52 #[must_use]
53 pub fn get_matrix(
54 &self,
55 distance: scalar,
56 flags: impl Into<Option<MatrixFlags>>,
57 ) -> Option<Matrix> {
58 let mut m = Matrix::default();
59 unsafe {
60 self.native().getMatrix(
61 distance,
62 m.native_mut(),
63 // note: depending on the OS, different representation types are generated for
64 // MatrixFlags, so the try_into() is required, even though clippy complains about
65 // it.
66 #[allow(clippy::useless_conversion)]
67 flags.into().unwrap_or_default().bits().try_into().unwrap(),
68 )
69 }
70 .if_true_some(m)
71 }
72
73 #[must_use]
74 pub fn segment(
75 &self,
76 start_d: scalar,
77 stop_d: scalar,
78 start_with_move_to: bool,
79 ) -> Option<Path> {
80 let mut p = Path::default();
81 unsafe {
82 self.native()
83 .getSegment(start_d, stop_d, p.native_mut(), start_with_move_to)
84 }
85 .if_true_some(p)
86 }
87
88 pub fn is_closed(&self) -> bool {
89 unsafe { sb::C_SkContourMeasure_isClosed(self.native()) }
90 }
91}
92
93pub type ContourMeasureIter = Handle<SkContourMeasureIter>;
94unsafe_send_sync!(ContourMeasureIter);
95
96impl NativeDrop for SkContourMeasureIter {
97 fn drop(&mut self) {
98 unsafe {
99 sb::C_SkContourMeasureIter_destruct(self);
100 }
101 }
102}
103
104impl Iterator for ContourMeasureIter {
105 type Item = ContourMeasure;
106
107 fn next(&mut self) -> Option<Self::Item> {
108 ContourMeasure::from_ptr(unsafe { sb::C_SkContourMeasureIter_next(self.native_mut()) })
109 }
110}
111
112impl fmt::Debug for ContourMeasureIter {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 f.debug_struct(name:"ContourMeasureIter").finish()
115 }
116}
117
118impl ContourMeasureIter {
119 // Canonical new:
120 pub fn new(path: &Path, force_closed: bool, res_scale: impl Into<Option<scalar>>) -> Self {
121 Self::from_path(path, force_closed, res_scale)
122 }
123
124 // TODO: rename to of_path? for_path?
125 // TODO: may deprecate in favor of Self::new().
126 pub fn from_path(
127 path: &Path,
128 force_closed: bool,
129 res_scale: impl Into<Option<scalar>>,
130 ) -> Self {
131 Self::from_native_c(unsafe {
132 SkContourMeasureIter::new1(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
133 })
134 }
135
136 pub fn reset(
137 &mut self,
138 path: &Path,
139 force_closed: bool,
140 res_scale: impl Into<Option<scalar>>,
141 ) -> &mut Self {
142 unsafe {
143 self.native_mut()
144 .reset(path.native(), force_closed, res_scale.into().unwrap_or(1.0))
145 }
146 self
147 }
148}
149