1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::prelude::*;
use crate::{Path, Rect};
use skia_bindings as sb;
use skia_bindings::{SkOpBuilder, SkPath, SkPathOp};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(i32)]
pub enum PathOp {
Difference = SkPathOp::kDifference_SkPathOp as _,
Intersect = SkPathOp::kIntersect_SkPathOp as _,
Union = SkPathOp::kUnion_SkPathOp as _,
XOR = SkPathOp::kXOR_SkPathOp as _,
ReverseDifference = SkPathOp::kReverseDifference_SkPathOp as _,
}
impl NativeTransmutable<SkPathOp> for PathOp {}
#[test]
fn test_path_op_layout() {
PathOp::test_layout();
}
pub fn op(one: &Path, two: &Path, op: PathOp) -> Option<Path> {
let mut result = Path::default();
unsafe {
sb::Op(
one.native(),
two.native(),
op.into_native(),
result.native_mut(),
)
}
.if_true_some(result)
}
pub fn simplify(path: &Path) -> Option<Path> {
let mut result = Path::default();
unsafe { sb::Simplify(path.native(), result.native_mut()) }.if_true_some(result)
}
pub fn tight_bounds(path: &Path) -> Option<Rect> {
let mut result = Rect::default();
unsafe { sb::TightBounds(path.native(), result.native_mut()) }.if_true_some(result)
}
pub fn as_winding(path: &Path) -> Option<Path> {
let mut result = Path::default();
unsafe { sb::AsWinding(path.native(), result.native_mut()) }.if_true_some(result)
}
pub type OpBuilder = Handle<SkOpBuilder>;
impl NativeDrop for SkOpBuilder {
fn drop(&mut self) {
unsafe { sb::C_SkOpBuilder_destruct(self) }
}
}
impl Default for Handle<SkOpBuilder> {
fn default() -> Self {
Self::construct(|opb| unsafe { sb::C_SkOpBuilder_Construct(opb) })
}
}
impl Handle<SkOpBuilder> {
pub fn add(&mut self, path: &Path, operator: PathOp) -> &mut Self {
unsafe {
self.native_mut().add(path.native(), operator.into_native());
}
self
}
pub fn resolve(&mut self) -> Option<Path> {
let mut path = Path::default();
unsafe { self.native_mut().resolve(path.native_mut()) }.if_true_some(path)
}
}
impl Handle<SkPath> {
pub fn op(&self, path: &Path, path_op: PathOp) -> Option<Self> {
op(self, path, path_op)
}
pub fn simplify(&self) -> Option<Self> {
simplify(self)
}
pub fn tight_bounds(&self) -> Option<Rect> {
tight_bounds(self)
}
pub fn as_winding(&self) -> Option<Path> {
as_winding(self)
}
}
#[test]
fn test_tight_bounds() {
let mut path = Path::new();
path.add_rect(Rect::from_point_and_size((10.0, 10.0), (10.0, 10.0)), None);
path.add_rect(Rect::from_point_and_size((15.0, 15.0), (10.0, 10.0)), None);
let tight_bounds: Rect = Rect::from_point_and_size((10.0, 10.0), (15.0, 15.0));
assert_eq!(path.tight_bounds().unwrap(), tight_bounds);
}
#[test]
fn test_union() {
let mut path = Path::new();
path.add_rect(Rect::from_point_and_size((10.0, 10.0), (10.0, 10.0)), None);
let mut path2 = Path::new();
path2.add_rect(Rect::from_point_and_size((15.0, 15.0), (10.0, 10.0)), None);
let union = path.op(&path2, PathOp::Union).unwrap();
let expected: Rect = Rect::from_point_and_size((10.0, 10.0), (15.0, 15.0));
assert_eq!(union.tight_bounds().unwrap(), expected);
}
#[test]
fn test_intersect() {
let mut path = Path::new();
path.add_rect(Rect::from_point_and_size((10.0, 10.0), (10.0, 10.0)), None);
let mut path2 = Path::new();
path2.add_rect(Rect::from_point_and_size((15.0, 15.0), (10.0, 10.0)), None);
let intersected = path.op(&path2, PathOp::Intersect).unwrap();
let expected: Rect = Rect::from_point_and_size((15.0, 15.0), (5.0, 5.0));
assert_eq!(intersected.tight_bounds().unwrap(), expected);
}