1use crate::direction::Direction;
5use crate::path_iter::PathIter;
6use crate::pathkit;
7use crate::point::Point;
8use crate::rect::Rect;
9use crate::rect_corner::RectCorner;
10use crate::rrect::RRect;
11
12pub struct Path {
14 inner: pathkit::SkPath,
15}
16
17impl Path {
18 pub fn new() -> Self {
20 Self {
21 inner: unsafe { pathkit::SkPath::new() },
22 }
23 }
24
25 pub fn from_path(other: &Path) -> Self {
27 Self {
28 inner: unsafe { pathkit::SkPath::new1(&other.inner as *const _) },
29 }
30 }
31
32 pub fn reset(&mut self) {
34 unsafe {
35 self.inner.reset();
36 }
37 }
38
39 pub fn is_empty(&self) -> bool {
41 unsafe { self.inner.countPoints() == 0 }
42 }
43
44 pub fn count_points(&self) -> i32 {
46 unsafe { self.inner.countPoints() }
47 }
48
49 pub fn count_verbs(&self) -> i32 {
51 unsafe { self.inner.countVerbs() }
52 }
53
54 pub fn iter(&self, force_close: bool) -> PathIter<'_> {
59 PathIter::new(self, force_close)
60 }
61
62 pub fn get_point(&self, index: i32) -> Option<Point> {
64 let n = self.count_points();
65 if index >= 0 && index < n {
66 let pt = unsafe { self.inner.getPoint(index) };
67 Some(pt.into())
68 } else {
69 None
70 }
71 }
72
73 pub fn tight_bounds(&self) -> Rect {
78 let bounds = unsafe { self.inner.computeTightBounds() };
79 bounds.into()
80 }
81
82 pub fn is_last_contour_closed(&self) -> bool {
84 unsafe { self.inner.isLastContourClosed() }
85 }
86
87 pub fn conservatively_contains_rect(&self, rect: &Rect) -> bool {
90 let r: pathkit::SkRect = (*rect).into();
91 unsafe { self.inner.conservativelyContainsRect(&r) }
92 }
93
94 pub fn is_rect(&self) -> Option<(Rect, bool)> {
96 let mut out_rect = pathkit::SkRect {
97 fLeft: 0.0,
98 fTop: 0.0,
99 fRight: 0.0,
100 fBottom: 0.0,
101 };
102 let mut is_closed = false;
103 let mut direction = pathkit::SkPathDirection::kCW;
104 let ok = unsafe {
105 self.inner.isRect(
106 &mut out_rect as *mut _,
107 &mut is_closed as *mut _,
108 &mut direction as *mut _,
109 )
110 };
111 if ok {
112 Some((out_rect.into(), is_closed))
113 } else {
114 None
115 }
116 }
117
118 pub fn contains(&self, x: f32, y: f32) -> bool {
123 unsafe { self.inner.contains(x, y) }
124 }
125
126 pub fn move_to(&mut self, x: f32, y: f32) -> &mut Self {
130 unsafe {
131 self.inner.moveTo(x, y);
132 }
133 self
134 }
135
136 pub fn line_to(&mut self, x: f32, y: f32) -> &mut Self {
141 unsafe {
142 self.inner.lineTo(x, y);
143 }
144 self
145 }
146
147 pub fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) -> &mut Self {
149 unsafe {
150 self.inner.quadTo(x1, y1, x2, y2);
151 }
152 self
153 }
154
155 pub fn cubic_to(
157 &mut self,
158 x1: f32,
159 y1: f32,
160 x2: f32,
161 y2: f32,
162 x3: f32,
163 y3: f32,
164 ) -> &mut Self {
165 unsafe {
166 self.inner.cubicTo(x1, y1, x2, y2, x3, y3);
167 }
168 self
169 }
170
171 pub fn close(&mut self) -> &mut Self {
173 unsafe {
174 self.inner.close();
175 }
176 self
177 }
178
179 pub fn add_rect(&mut self, rect: &Rect, dir: Direction, start: RectCorner) -> &mut Self {
181 let r: pathkit::SkRect = (*rect).into();
182 unsafe {
183 self.inner.addRect(&r, dir.into(), start.into());
184 }
185 self
186 }
187
188 pub fn add_oval(&mut self, rect: &Rect, dir: Direction) -> &mut Self {
190 let r: pathkit::SkRect = (*rect).into();
191 unsafe {
192 self.inner.addOval(&r, dir.into());
193 }
194 self
195 }
196
197 pub fn add_circle(&mut self, cx: f32, cy: f32, radius: f32, dir: Direction) -> &mut Self {
202 unsafe {
203 self.inner.addCircle(cx, cy, radius, dir.into());
204 }
205 self
206 }
207
208 pub fn add_round_rect(
212 &mut self,
213 rect: &Rect,
214 rx: f32,
215 ry: f32,
216 dir: Direction,
217 ) -> &mut Self {
218 let r: pathkit::SkRect = (*rect).into();
219 unsafe {
220 self.inner.addRoundRect(&r, rx, ry, dir.into());
221 }
222 self
223 }
224
225 pub fn add_rrect(&mut self, rrect: &RRect, dir: Direction) -> &mut Self {
227 unsafe {
228 self.inner.addRRect(rrect.as_raw() as *const _, dir.into());
229 }
230 self
231 }
232
233 pub fn add_rrect_with_start(
235 &mut self,
236 rrect: &RRect,
237 dir: Direction,
238 start: RectCorner,
239 ) -> &mut Self {
240 unsafe {
241 self.inner.addRRect1(rrect.as_raw() as *const _, dir.into(), start.into());
242 }
243 self
244 }
245
246 pub fn is_rrect(&self) -> Option<RRect> {
248 let mut out = pathkit::SkRRect {
249 fRect: pathkit::SkRect {
250 fLeft: 0.0,
251 fTop: 0.0,
252 fRight: 0.0,
253 fBottom: 0.0,
254 },
255 fRadii: [
256 pathkit::SkPoint { fX: 0.0, fY: 0.0 },
257 pathkit::SkPoint { fX: 0.0, fY: 0.0 },
258 pathkit::SkPoint { fX: 0.0, fY: 0.0 },
259 pathkit::SkPoint { fX: 0.0, fY: 0.0 },
260 ],
261 fType: 0,
262 };
263 let ok = unsafe { self.inner.isRRect(&mut out as *mut _) };
264 if ok {
265 Some(RRect::from_raw(out))
266 } else {
267 None
268 }
269 }
270
271 pub(crate) fn as_raw(&self) -> &pathkit::SkPath {
273 &self.inner
274 }
275
276 pub(crate) fn as_raw_mut(&mut self) -> &mut pathkit::SkPath {
278 &mut self.inner
279 }
280}
281
282impl Default for Path {
283 fn default() -> Self {
284 Self::new()
285 }
286}
287
288impl Clone for Path {
289 fn clone(&self) -> Self {
290 Self::from_path(self)
291 }
292}
293
294impl std::fmt::Debug for Path {
295 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296 f.debug_struct("Path")
297 .field("points", &self.count_points())
298 .field("verbs", &self.count_verbs())
299 .field("bounds", &self.tight_bounds())
300 .finish()
301 }
302}