1 | //! Wrapper for pathops/SkPathOps.h |
2 | use crate::{prelude::*, Path, Rect}; |
3 | use skia_bindings::{self as sb, SkOpBuilder}; |
4 | use std::fmt; |
5 | |
6 | pub use skia_bindings::SkPathOp as PathOp; |
7 | variant_name!(PathOp::XOR); |
8 | |
9 | // TODO: I am not so sure if we should export these global functions. |
10 | |
11 | pub fn op(one: &Path, two: &Path, op: PathOp) -> Option<Path> { |
12 | let mut result: Handle = Path::default(); |
13 | unsafe { sb::Op(one:one.native(), two:two.native(), op, result:result.native_mut()) }.if_true_some(result) |
14 | } |
15 | |
16 | pub fn simplify(path: &Path) -> Option<Path> { |
17 | let mut result: Handle = Path::default(); |
18 | unsafe { sb::Simplify(path:path.native(), result:result.native_mut()) }.if_true_some(result) |
19 | } |
20 | |
21 | pub fn tight_bounds(path: &Path) -> Option<Rect> { |
22 | let mut result: Rect = Rect::default(); |
23 | unsafe { sb::TightBounds(path:path.native(), result:result.native_mut()) }.if_true_some(result) |
24 | } |
25 | |
26 | pub fn as_winding(path: &Path) -> Option<Path> { |
27 | let mut result: Handle = Path::default(); |
28 | unsafe { sb::AsWinding(path:path.native(), result:result.native_mut()) }.if_true_some(result) |
29 | } |
30 | |
31 | pub type OpBuilder = Handle<SkOpBuilder>; |
32 | unsafe_send_sync!(OpBuilder); |
33 | |
34 | impl NativeDrop for SkOpBuilder { |
35 | fn drop(&mut self) { |
36 | unsafe { sb::C_SkOpBuilder_destruct(self) } |
37 | } |
38 | } |
39 | |
40 | impl Default for Handle<SkOpBuilder> { |
41 | fn default() -> Self { |
42 | Self::construct(|opb: *mut SkOpBuilder| unsafe { sb::C_SkOpBuilder_Construct(uninitialized:opb) }) |
43 | } |
44 | } |
45 | |
46 | impl fmt::Debug for OpBuilder { |
47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
48 | f.debug_struct(name:"OpBuilder" ).finish() |
49 | } |
50 | } |
51 | |
52 | impl OpBuilder { |
53 | pub fn add(&mut self, path: &Path, operator: PathOp) -> &mut Self { |
54 | unsafe { |
55 | self.native_mut().add(path:path.native(), operator); |
56 | } |
57 | self |
58 | } |
59 | |
60 | pub fn resolve(&mut self) -> Option<Path> { |
61 | let mut path: Handle = Path::default(); |
62 | unsafe { self.native_mut().resolve(result:path.native_mut()) }.if_true_some(path) |
63 | } |
64 | } |
65 | |
66 | impl Path { |
67 | pub fn op(&self, path: &Path, path_op: PathOp) -> Option<Self> { |
68 | op(self, two:path, path_op) |
69 | } |
70 | |
71 | pub fn simplify(&self) -> Option<Self> { |
72 | simplify(self) |
73 | } |
74 | |
75 | pub fn tight_bounds(&self) -> Option<Rect> { |
76 | tight_bounds(self) |
77 | } |
78 | |
79 | pub fn as_winding(&self) -> Option<Path> { |
80 | as_winding(self) |
81 | } |
82 | } |
83 | |
84 | #[test ] |
85 | fn test_tight_bounds() { |
86 | let mut path: Handle = Path::new(); |
87 | path.add_rect(Rect::from_point_and_size((10.0, 10.0), (10.0, 10.0)), dir_start:None); |
88 | path.add_rect(Rect::from_point_and_size((15.0, 15.0), (10.0, 10.0)), dir_start:None); |
89 | let tight_bounds: Rect = Rect::from_point_and_size((10.0, 10.0), (15.0, 15.0)); |
90 | assert_eq!(path.tight_bounds().unwrap(), tight_bounds); |
91 | } |
92 | |
93 | #[test ] |
94 | fn test_union() { |
95 | let mut path: Handle = Path::new(); |
96 | path.add_rect(Rect::from_point_and_size((10.0, 10.0), (10.0, 10.0)), dir_start:None); |
97 | let mut path2: Handle = Path::new(); |
98 | path2.add_rect(Rect::from_point_and_size((15.0, 15.0), (10.0, 10.0)), dir_start:None); |
99 | let union: Handle = path.op(&path2, PathOp::Union).unwrap(); |
100 | let expected: Rect = Rect::from_point_and_size((10.0, 10.0), (15.0, 15.0)); |
101 | assert_eq!(union.tight_bounds().unwrap(), expected); |
102 | } |
103 | |
104 | #[test ] |
105 | fn test_intersect() { |
106 | let mut path: Handle = Path::new(); |
107 | path.add_rect(Rect::from_point_and_size((10.0, 10.0), (10.0, 10.0)), dir_start:None); |
108 | let mut path2: Handle = Path::new(); |
109 | path2.add_rect(Rect::from_point_and_size((15.0, 15.0), (10.0, 10.0)), dir_start:None); |
110 | let intersected: Handle = path.op(&path2, PathOp::Intersect).unwrap(); |
111 | let expected: Rect = Rect::from_point_and_size((15.0, 15.0), (5.0, 5.0)); |
112 | assert_eq!(intersected.tight_bounds().unwrap(), expected); |
113 | } |
114 | |