1use std::{fmt, mem};
2
3use crate::{
4 matrix, path, prelude::*, scalar, Matrix, Path, PathDirection, PathFillType, PathVerb, Point,
5 RRect, Rect, Vector,
6};
7use skia_bindings::{self as sb, SkPathBuilder, SkPath_AddPathMode};
8
9pub use skia_bindings::SkPathBuilder_ArcSize as ArcSize;
10variant_name!(ArcSize::Large);
11
12pub type PathBuilder = RefHandle<SkPathBuilder>;
17unsafe_send_sync!(PathBuilder);
18
19impl NativeDrop for SkPathBuilder {
20 fn drop(&mut self) {
21 unsafe { sb::C_SkPathBuilder_delete(self) }
22 }
23}
24
25impl Default for PathBuilder {
26 fn default() -> Self {
27 Self::new()
28 }
29}
30
31impl Clone for PathBuilder {
32 fn clone(&self) -> Self {
33 Self::from_ptr(unsafe { sb::C_SkPathBuilder_clone(self.native()) }).unwrap()
34 }
35}
36
37impl fmt::Debug for PathBuilder {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("PathBuilder")
40 .field("fill_type", &self.fill_type())
41 .finish()
42 }
43}
44
45impl From<PathBuilder> for Path {
46 fn from(mut value: PathBuilder) -> Self {
47 value.detach()
48 }
49}
50
51impl PathBuilder {
52 pub fn new() -> Self {
53 Self::from_ptr(unsafe { sb::C_SkPathBuilder_new() }).unwrap()
54 }
55
56 pub fn new_path(path: &Path) -> Self {
63 Self::from_ptr(unsafe { sb::C_SkPathBuilder_newFromPath(path.native()) }).unwrap()
64 }
65
66 pub fn fill_type(&self) -> PathFillType {
67 self.native().fFillType
68 }
69
70 pub fn compute_bounds(&self) -> Rect {
71 Rect::construct(|r| unsafe { sb::C_SkPathBuilder_computeBounds(self.native(), r) })
72 }
73
74 pub fn snapshot(&self) -> Path {
75 Path::construct(|path| unsafe { sb::C_SkPathBuilder_snapshot(self.native(), path) })
76 }
77
78 pub fn detach(&mut self) -> Path {
79 Path::construct(|path| unsafe { sb::C_SkPathBuilder_detach(self.native_mut(), path) })
80 }
81
82 pub fn set_fill_type(&mut self, ft: PathFillType) -> &mut Self {
83 self.native_mut().fFillType = ft;
84 self
85 }
86
87 pub fn set_is_volatile(&mut self, is_volatile: bool) -> &mut Self {
88 self.native_mut().fIsVolatile = is_volatile;
89 self
90 }
91
92 pub fn reset(&mut self) -> &mut Self {
93 unsafe {
94 self.native_mut().reset();
95 }
96 self
97 }
98
99 pub fn move_to(&mut self, pt: impl Into<Point>) -> &mut Self {
100 unsafe {
101 self.native_mut().moveTo(pt.into().into_native());
102 }
103 self
104 }
105
106 pub fn line_to(&mut self, pt: impl Into<Point>) -> &mut Self {
107 unsafe {
108 self.native_mut().lineTo(pt.into().into_native());
109 }
110 self
111 }
112
113 pub fn quad_to(&mut self, p1: impl Into<Point>, p2: impl Into<Point>) -> &mut Self {
114 unsafe {
115 self.native_mut()
116 .quadTo(p1.into().into_native(), p2.into().into_native());
117 }
118 self
119 }
120
121 pub fn conic_to(&mut self, p1: impl Into<Point>, p2: impl Into<Point>, w: scalar) -> &mut Self {
122 unsafe {
123 self.native_mut()
124 .conicTo(p1.into().into_native(), p2.into().into_native(), w);
125 }
126 self
127 }
128
129 pub fn cubic_to(
130 &mut self,
131 p1: impl Into<Point>,
132 p2: impl Into<Point>,
133 p3: impl Into<Point>,
134 ) -> &mut Self {
135 unsafe {
136 self.native_mut().cubicTo(
137 p1.into().into_native(),
138 p2.into().into_native(),
139 p3.into().into_native(),
140 )
141 };
142 self
143 }
144
145 pub fn close(&mut self) -> &mut Self {
146 unsafe {
147 self.native_mut().close();
148 }
149 self
150 }
151
152 pub fn polyline_to(&mut self, points: &[Point]) -> &mut Self {
153 unsafe {
154 sb::C_SkPathBuilder_polylineTo(
155 self.native_mut(),
156 points.native().as_ptr(),
157 points.len(),
158 );
159 }
160 self
161 }
162
163 pub fn r_move_to(&mut self, pt: impl Into<Point>) -> &mut Self {
164 unsafe {
165 self.native_mut().rMoveTo(pt.into().into_native());
166 }
167 self
168 }
169
170 pub fn r_line_to(&mut self, pt: impl Into<Point>) -> &mut Self {
171 unsafe {
172 self.native_mut().rLineTo(pt.into().into_native());
173 }
174 self
175 }
176
177 pub fn r_quad_to(&mut self, pt1: impl Into<Point>, pt2: impl Into<Point>) -> &mut Self {
178 unsafe {
179 self.native_mut()
180 .rQuadTo(pt1.into().into_native(), pt2.into().into_native());
181 }
182 self
183 }
184
185 pub fn r_conic_to(
186 &mut self,
187 pt1: impl Into<Point>,
188 pt2: impl Into<Point>,
189 w: scalar,
190 ) -> &mut Self {
191 unsafe {
192 self.native_mut()
193 .rConicTo(pt1.into().into_native(), pt2.into().into_native(), w);
194 }
195 self
196 }
197
198 pub fn r_cubic_to(
199 &mut self,
200 pt1: impl Into<Point>,
201 pt2: impl Into<Point>,
202 pt3: impl Into<Point>,
203 ) -> &mut Self {
204 unsafe {
205 self.native_mut().rCubicTo(
206 pt1.into().into_native(),
207 pt2.into().into_native(),
208 pt3.into().into_native(),
209 );
210 }
211 self
212 }
213
214 pub fn r_arc_to(
215 &mut self,
216 r: (scalar, scalar),
217 x_axis_rotate: scalar,
218 large_arc: ArcSize,
219 sweep: PathDirection,
220 d: impl Into<Vector>,
221 ) -> &mut Self {
222 let d = d.into();
223 unsafe {
224 self.native_mut()
225 .rArcTo(r.0, r.1, x_axis_rotate, large_arc, sweep, d.x, d.y);
226 }
227 self
228 }
229
230 pub fn arc_to(
231 &mut self,
232 oval: impl AsRef<Rect>,
233 start_angle_deg: scalar,
234 sweep_angle_deg: scalar,
235 force_move_to: bool,
236 ) -> &mut Self {
237 unsafe {
238 self.native_mut().arcTo(
239 oval.as_ref().native(),
240 start_angle_deg,
241 sweep_angle_deg,
242 force_move_to,
243 );
244 }
245 self
246 }
247
248 pub fn arc_to_tangent(
249 &mut self,
250 p1: impl Into<Point>,
251 p2: impl Into<Point>,
252 radius: scalar,
253 ) -> &mut Self {
254 unsafe {
255 self.native_mut()
256 .arcTo1(p1.into().into_native(), p2.into().into_native(), radius);
257 }
258 self
259 }
260
261 pub fn arc_to_radius(
262 &mut self,
263 r: impl Into<Point>,
264 x_axis_rotate: scalar,
265 large_arc: ArcSize,
266 sweep: PathDirection,
267 xy: impl Into<Point>,
268 ) -> &mut Self {
269 unsafe {
270 self.native_mut().arcTo2(
271 r.into().into_native(),
272 x_axis_rotate,
273 large_arc,
274 sweep,
275 xy.into().into_native(),
276 );
277 }
278 self
279 }
280
281 pub fn add_arc(
282 &mut self,
283 oval: impl AsRef<Rect>,
284 start_angle_deg: scalar,
285 sweep_angle_deg: scalar,
286 ) -> &mut Self {
287 unsafe {
288 self.native_mut()
289 .addArc(oval.as_ref().native(), start_angle_deg, sweep_angle_deg);
290 }
291 self
292 }
293
294 pub fn add_rect(
295 &mut self,
296 rect: impl AsRef<Rect>,
297 dir: impl Into<Option<PathDirection>>,
298 start_index: impl Into<Option<usize>>,
299 ) -> &mut Self {
300 let dir = dir.into().unwrap_or_default();
301 let start_index = start_index.into().unwrap_or(0);
302 unsafe {
303 self.native_mut()
304 .addRect(rect.as_ref().native(), dir, start_index.try_into().unwrap());
305 }
306 self
307 }
308
309 pub fn add_oval(
310 &mut self,
311 rect: impl AsRef<Rect>,
312 dir: impl Into<Option<PathDirection>>,
313 start_index: impl Into<Option<usize>>,
314 ) -> &mut Self {
315 let dir = dir.into().unwrap_or_default();
316 let start_index = start_index.into().unwrap_or(1);
318 unsafe {
319 self.native_mut()
320 .addOval(rect.as_ref().native(), dir, start_index.try_into().unwrap());
321 }
322 self
323 }
324
325 pub fn add_rrect(
326 &mut self,
327 rect: impl AsRef<RRect>,
328 dir: impl Into<Option<PathDirection>>,
329 start_index: impl Into<Option<usize>>,
330 ) -> &mut Self {
331 let dir = dir.into().unwrap_or_default();
332 let start_index =
334 start_index
335 .into()
336 .unwrap_or(if dir == PathDirection::CW { 6 } else { 7 });
337 unsafe {
338 self.native_mut().addRRect(
339 rect.as_ref().native(),
340 dir,
341 start_index.try_into().unwrap(),
342 );
343 }
344 self
345 }
346
347 pub fn add_circle(
348 &mut self,
349 center: impl Into<Point>,
350 radius: scalar,
351 dir: impl Into<Option<PathDirection>>,
352 ) -> &mut Self {
353 let center = center.into();
354 let dir = dir.into().unwrap_or_default();
355 unsafe {
356 self.native_mut().addCircle(center.x, center.y, radius, dir);
357 }
358 self
359 }
360
361 pub fn add_polygon(&mut self, pts: &[Point], close: bool) -> &mut Self {
362 unsafe {
363 sb::C_SkPathBuilder_addPolygon(
364 self.native_mut(),
365 pts.native().as_ptr(),
366 pts.len(),
367 close,
368 );
369 }
370 self
371 }
372
373 pub fn add_path(&mut self, path: &Path) -> &mut Self {
374 unsafe {
375 self.native_mut()
376 .addPath(path.native(), 0., 0., SkPath_AddPathMode::Append)
377 };
378 self
379 }
380
381 pub fn add_path_with_transform(
382 &mut self,
383 src: &Path,
384 matrix: &Matrix,
385 mode: impl Into<Option<path::AddPathMode>>,
386 ) {
387 unsafe {
388 self.native_mut().addPath1(
389 src.native(),
390 matrix.native(),
391 mode.into().unwrap_or(path::AddPathMode::Append),
392 )
393 };
394 }
395
396 pub fn inc_reserve(&mut self, extra_pt_count: usize, extra_verb_count: usize) {
397 unsafe {
398 self.native_mut().incReserve(
399 extra_pt_count.try_into().unwrap(),
400 extra_verb_count.try_into().unwrap(),
401 )
402 }
403 }
404
405 pub fn offset(&mut self, d: impl Into<Vector>) -> &mut Self {
406 let d = d.into();
407 unsafe {
408 self.native_mut().offset(d.x, d.y);
409 }
410 self
411 }
412
413 pub fn transform(
414 &mut self,
415 matrix: &Matrix,
416 pc: impl Into<Option<matrix::ApplyPerspectiveClip>>,
417 ) -> &mut Self {
418 let pc = pc.into().unwrap_or(matrix::ApplyPerspectiveClip::Yes);
419 unsafe {
420 self.native_mut().transform(matrix.native(), pc);
421 }
422 self
423 }
424
425 pub fn is_finite(&self) -> bool {
426 unsafe { self.native().isFinite() }
427 }
428
429 pub fn toggle_inverse_fill_type(&mut self) -> &mut Self {
430 let n = self.native_mut();
431 n.fFillType = unsafe { mem::transmute::<u8, sb::SkPathFillType>(n.fFillType as u8 ^ 2) };
432 self
433 }
434
435 pub fn is_empty(&self) -> bool {
436 unsafe { sb::C_SkPathBuilder_isEmpty(self.native()) }
437 }
438
439 pub fn get_last_pt(&self) -> Option<Point> {
440 let mut p = Point::default();
441 unsafe { sb::C_SkPathBuilder_getLastPt(self.native(), p.native_mut()) }.then_some(p)
442 }
443
444 pub fn set_last_pt(&mut self, p: impl Into<Point>) {
445 let p = p.into();
446 unsafe { self.native_mut().setLastPt(p.x, p.y) };
447 }
448
449 pub fn count_points(&self) -> usize {
450 unsafe { sb::C_SkPathBuilder_countPoints(self.native()) }
451 }
452
453 pub fn is_inverse_fill_type(&self) -> bool {
454 PathFillType::is_inverse(self.fill_type())
455 }
456
457 pub fn points(&self) -> &[Point] {
458 unsafe {
459 let mut len = 0;
460 let points = sb::C_SkPathBuilder_points(self.native(), &mut len);
461 safer::from_raw_parts(Point::from_native_ptr(points), len)
462 }
463 }
464
465 pub fn verbs(&self) -> &[PathVerb] {
466 unsafe {
467 let mut len = 0;
468 let verbs = sb::C_SkPathBuilder_verbs(self.native(), &mut len);
469 safer::from_raw_parts(verbs, len)
470 }
471 }
472}
473
474#[cfg(test)]
475mod tests {
476 use crate::{paint, surfaces, Paint};
477
478 use super::*;
479
480 #[test]
481 fn test_creation_snapshot_and_detach() {
482 let mut builder = PathBuilder::new();
483 let _path = builder.snapshot();
484 let _path = builder.detach();
485 }
486
487 #[test]
488 fn issue_1195() {
489 let mut surface = surfaces::raster_n32_premul((1000, 1000)).unwrap();
490 let canvas = surface.canvas();
491 let mut paint = Paint::default();
492 paint.set_style(paint::Style::Stroke);
493 let mut path = PathBuilder::new();
494 path.move_to((250., 250.));
495 path.cubic_to((300., 300.), (700., 700.), (750., 750.));
496 let pathsh = path.snapshot();
497 canvas.draw_path(&pathsh, &paint);
498 }
499}