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