1use std::{fmt, iter, marker::PhantomData, mem, ptr};
2
3use crate::{prelude::*, Contains, IPoint, IRect, IVector, Path, PathBuilder, QuickReject};
4use skia_bindings::{
5 self as sb, SkRegion, SkRegion_Cliperator, SkRegion_Iterator, SkRegion_RunHead,
6 SkRegion_Spanerator,
7};
8
9pub type Region = Handle<SkRegion>;
10unsafe_send_sync!(Region);
11
12impl NativeDrop for SkRegion {
13 fn drop(&mut self) {
14 unsafe { sb::C_SkRegion_destruct(self) }
15 }
16}
17
18impl NativeClone for SkRegion {
19 fn clone(&self) -> Self {
20 unsafe { SkRegion::new1(self) }
21 }
22}
23
24impl NativePartialEq for SkRegion {
25 fn eq(&self, rhs: &Self) -> bool {
26 unsafe { sb::C_SkRegion_Equals(self, rhs) }
27 }
28}
29
30impl fmt::Debug for Region {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 f.debug_struct("Region")
33 .field("is_empty", &self.is_empty())
34 .field("is_rect", &self.is_rect())
35 .field("is_complex", &self.is_complex())
36 .field("bounds", &self.bounds())
37 .finish()
38 }
39}
40
41pub use skia_bindings::SkRegion_Op as RegionOp;
42variant_name!(RegionOp::ReverseDifference);
43
44impl Region {
45 pub fn new() -> Region {
46 Self::from_native_c(unsafe { SkRegion::new() })
47 }
48
49 pub fn from_rect(rect: impl AsRef<IRect>) -> Region {
50 Self::from_native_c(unsafe { SkRegion::new2(rect.as_ref().native()) })
51 }
52
53 pub fn set(&mut self, src: &Region) -> bool {
54 unsafe { sb::C_SkRegion_set(self.native_mut(), src.native()) }
55 }
56
57 pub fn swap(&mut self, other: &mut Region) {
58 unsafe { self.native_mut().swap(other.native_mut()) }
59 }
60
61 const EMPTY_RUN_HEAD_PTR: *mut SkRegion_RunHead = -1 as _;
62 const RECT_RUN_HEAD_PTR: *mut SkRegion_RunHead = ptr::null_mut();
63
64 pub fn is_empty(&self) -> bool {
65 ptr::eq(self.native().fRunHead, Self::EMPTY_RUN_HEAD_PTR)
66 }
67
68 pub fn is_rect(&self) -> bool {
69 ptr::eq(self.native().fRunHead, Self::RECT_RUN_HEAD_PTR)
70 }
71
72 pub fn is_complex(&self) -> bool {
73 !self.is_empty() && !self.is_rect()
74 }
75
76 pub fn bounds(&self) -> &IRect {
77 IRect::from_native_ref(&self.native().fBounds)
78 }
79
80 pub fn compute_region_complexity(&self) -> usize {
81 unsafe { self.native().computeRegionComplexity().try_into().unwrap() }
82 }
83
84 pub fn add_boundary_path(&self, path: &mut PathBuilder) -> bool {
85 unsafe { self.native().addBoundaryPath(path.native_mut()) }
86 }
87
88 pub fn get_boundary_path(&self, path: &mut Path) -> bool {
89 unsafe { self.native().getBoundaryPath1(path.native_mut()) }
90 }
91
92 pub fn boundary_path(&self) -> Option<Path> {
93 let mut path = Path::default();
94 unsafe { self.native().getBoundaryPath1(path.native_mut()) }.then_some(path)
95 }
96
97 pub fn set_empty(&mut self) -> bool {
98 unsafe { self.native_mut().setEmpty() }
99 }
100
101 pub fn set_rect(&mut self, rect: impl AsRef<IRect>) -> bool {
102 unsafe { self.native_mut().setRect(rect.as_ref().native()) }
103 }
104
105 pub fn set_rects(&mut self, rects: &[IRect]) -> bool {
106 unsafe {
107 self.native_mut()
108 .setRects(rects.native().as_ptr(), rects.len().try_into().unwrap())
109 }
110 }
111
112 pub fn set_region(&mut self, region: &Region) -> bool {
113 unsafe { self.native_mut().setRegion(region.native()) }
114 }
115
116 pub fn set_path(&mut self, path: &Path, clip: &Region) -> bool {
117 unsafe { self.native_mut().setPath(path.native(), clip.native()) }
118 }
119
120 pub fn intersects_rect(&self, rect: impl AsRef<IRect>) -> bool {
123 unsafe { self.native().intersects(rect.as_ref().native()) }
124 }
125
126 pub fn intersects_region(&self, other: &Region) -> bool {
127 unsafe { self.native().intersects1(other.native()) }
128 }
129
130 pub fn contains_point(&self, point: IPoint) -> bool {
133 unsafe { self.native().contains(point.x, point.y) }
134 }
135
136 pub fn contains_rect(&self, rect: impl AsRef<IRect>) -> bool {
137 unsafe { self.native().contains1(rect.as_ref().native()) }
138 }
139
140 pub fn contains_region(&self, other: &Region) -> bool {
141 unsafe { self.native().contains2(other.native()) }
142 }
143
144 pub fn quick_contains(&self, r: impl AsRef<IRect>) -> bool {
145 let r = r.as_ref();
146 unsafe { sb::C_SkRegion_quickContains(self.native(), r.native()) }
147 }
148
149 pub fn quick_reject_rect(&self, rect: impl AsRef<IRect>) -> bool {
152 let rect = rect.as_ref();
153 self.is_empty() || rect.is_empty() || !IRect::intersects(self.bounds(), rect)
154 }
155
156 pub fn quick_reject_region(&self, rgn: &Region) -> bool {
157 self.is_empty() || rgn.is_empty() || !IRect::intersects(self.bounds(), rgn.bounds())
158 }
159
160 pub fn translate(&mut self, d: impl Into<IVector>) {
161 let d = d.into();
162 let self_ptr = self.native_mut() as *mut _;
163 unsafe { self.native().translate(d.x, d.y, self_ptr) }
164 }
165
166 #[must_use]
167 pub fn translated(&self, d: impl Into<IVector>) -> Self {
168 let mut r = self.clone();
169 r.translate(d);
170 r
171 }
172
173 pub fn op_rect(&mut self, rect: impl AsRef<IRect>, op: RegionOp) -> bool {
174 let self_ptr = self.native_mut() as *const _;
175 unsafe { self.native_mut().op1(self_ptr, rect.as_ref().native(), op) }
176 }
177
178 pub fn op_region(&mut self, region: &Region, op: RegionOp) -> bool {
179 let self_ptr = self.native_mut() as *const _;
180 unsafe { self.native_mut().op2(self_ptr, region.native(), op) }
181 }
182
183 pub fn op_rect_region(
184 &mut self,
185 rect: impl AsRef<IRect>,
186 region: &Region,
187 op: RegionOp,
188 ) -> bool {
189 unsafe {
190 self.native_mut()
191 .op(rect.as_ref().native(), region.native(), op)
192 }
193 }
194
195 pub fn op_region_rect(
196 &mut self,
197 region: &Region,
198 rect: impl AsRef<IRect>,
199 op: RegionOp,
200 ) -> bool {
201 unsafe {
202 self.native_mut()
203 .op1(region.native(), rect.as_ref().native(), op)
204 }
205 }
206
207 pub fn write_to_memory(&self, buf: &mut Vec<u8>) {
208 unsafe {
209 let size = self.native().writeToMemory(ptr::null_mut());
210 buf.resize(size, 0);
211 let written = self.native().writeToMemory(buf.as_mut_ptr() as _);
212 debug_assert!(written == size);
213 }
214 }
215
216 pub fn read_from_memory(&mut self, buf: &[u8]) -> usize {
217 unsafe {
218 self.native_mut()
219 .readFromMemory(buf.as_ptr() as _, buf.len())
220 }
221 }
222}
223
224pub trait Combine<A, B>: Sized {
229 fn combine(a: &A, op: RegionOp, b: &B) -> Self;
230
231 fn difference(a: &A, b: &B) -> Self {
232 Self::combine(a, RegionOp::Difference, b)
233 }
234
235 fn intersect(a: &A, b: &B) -> Self {
236 Self::combine(a, RegionOp::Intersect, b)
237 }
238
239 fn xor(a: &A, b: &B) -> Self {
240 Self::combine(a, RegionOp::XOR, b)
241 }
242
243 fn union(a: &A, b: &B) -> Self {
244 Self::combine(a, RegionOp::Union, b)
245 }
246
247 fn reverse_difference(a: &A, b: &B) -> Self {
248 Self::combine(a, RegionOp::ReverseDifference, b)
249 }
250
251 fn replace(a: &A, b: &B) -> Self {
252 Self::combine(a, RegionOp::Replace, b)
253 }
254}
255
256impl Combine<IRect, Region> for Handle<SkRegion> {
257 fn combine(rect: &IRect, op: RegionOp, region: &Region) -> Self {
258 let mut r = Region::new();
259 r.op_rect_region(rect, region, op);
260 r
261 }
262}
263
264impl Combine<Region, IRect> for Handle<SkRegion> {
265 fn combine(region: &Region, op: RegionOp, rect: &IRect) -> Self {
266 let mut r = Region::new();
267 r.op_region_rect(region, rect, op);
268 r
269 }
270}
271
272impl Combine<Region, Region> for Handle<SkRegion> {
273 fn combine(a: &Region, op: RegionOp, b: &Region) -> Self {
274 let mut a = a.clone();
275 a.op_region(b, op);
276 a
277 }
278}
279
280pub trait Intersects<T> {
285 fn intersects(&self, other: &T) -> bool;
286}
287
288impl Intersects<IRect> for Region {
289 fn intersects(&self, rect: &IRect) -> bool {
290 self.intersects_rect(rect)
291 }
292}
293
294impl Intersects<Region> for Region {
295 fn intersects(&self, other: &Region) -> bool {
296 self.intersects_region(other)
297 }
298}
299
300impl Contains<IPoint> for Region {
305 fn contains(&self, point: IPoint) -> bool {
306 self.contains_point(point)
307 }
308}
309
310impl Contains<&IRect> for Region {
311 fn contains(&self, rect: &IRect) -> bool {
312 self.contains_rect(rect)
313 }
314}
315
316impl Contains<&Region> for Region {
317 fn contains(&self, other: &Region) -> bool {
318 self.contains_region(other)
319 }
320}
321
322impl QuickReject<IRect> for Region {
327 fn quick_reject(&self, rect: &IRect) -> bool {
328 self.quick_reject_rect(rect)
329 }
330}
331
332impl QuickReject<Region> for Region {
333 fn quick_reject(&self, other: &Region) -> bool {
334 self.quick_reject_region(other)
335 }
336}
337
338#[derive(Clone)]
339#[repr(transparent)]
340pub struct Iterator<'a>(SkRegion_Iterator, PhantomData<&'a Region>);
341
342native_transmutable!(SkRegion_Iterator, Iterator<'_>);
343
344impl fmt::Debug for Iterator<'_> {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 f.debug_struct("Iterator")
347 .field("is_done", &self.is_done())
348 .field("rect", self.rect())
349 .finish()
350 }
351}
352
353impl<'a> Iterator<'a> {
354 pub fn new_empty() -> Self {
355 Iterator::construct(|iterator| unsafe {
356 sb::C_SkRegion_Iterator_Construct(iterator);
357 })
358 }
359
360 pub fn new(region: &'a Region) -> Iterator<'a> {
361 Iterator::from_native_c(unsafe { SkRegion_Iterator::new(region.native()) })
362 }
363
364 pub fn rewind(&mut self) -> bool {
365 unsafe { self.native_mut().rewind() }
366 }
367
368 pub fn reset(mut self, region: &Region) -> Iterator {
369 unsafe {
370 self.native_mut().reset(region.native());
371 mem::transmute(self)
372 }
373 }
374
375 pub fn is_done(&self) -> bool {
376 self.native().fDone
377 }
378
379 pub fn next(&mut self) {
380 unsafe {
381 self.native_mut().next();
382 }
383 }
384
385 pub fn rect(&self) -> &IRect {
386 IRect::from_native_ref(&self.native().fRect)
387 }
388
389 pub fn rgn(&self) -> Option<&Region> {
390 unsafe {
391 let r = sb::C_SkRegion_Iterator_rgn(self.native()).into_non_null()?;
392 Some(Region::from_native_ref(r.as_ref()))
393 }
394 }
395}
396
397impl iter::Iterator for Iterator<'_> {
398 type Item = IRect;
399
400 fn next(&mut self) -> Option<Self::Item> {
401 if self.is_done() {
402 return None;
403 }
404 let r = *self.rect();
405 Iterator::next(self);
406 Some(r)
407 }
408}
409
410#[test]
411fn test_iterator() {
412 let r1 = IRect::new(10, 10, 12, 14);
413 let r2 = IRect::new(100, 100, 120, 140);
414 let mut r = Region::new();
415 r.set_rects(&[r1, r2]);
416 let rects: Vec<IRect> = Iterator::new(&r).collect();
417 assert_eq!(rects.len(), 2);
418 assert_eq!(rects[0], r1);
419 assert_eq!(rects[1], r2);
420}
421
422#[derive(Clone)]
423#[repr(transparent)]
424pub struct Cliperator<'a>(SkRegion_Cliperator, PhantomData<&'a Region>);
425
426native_transmutable!(SkRegion_Cliperator, Cliperator<'_>);
427
428impl Drop for Cliperator<'_> {
429 fn drop(&mut self) {
430 unsafe { sb::C_SkRegion_Cliperator_destruct(self.native_mut()) }
431 }
432}
433
434impl fmt::Debug for Cliperator<'_> {
435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436 f.debug_struct("Cliperator")
437 .field("is_done", &self.is_done())
438 .field("rect", &self.rect())
439 .finish()
440 }
441}
442
443impl<'a> Cliperator<'a> {
444 pub fn new(region: &'a Region, clip: impl AsRef<IRect>) -> Cliperator<'a> {
445 Cliperator::from_native_c(unsafe {
446 SkRegion_Cliperator::new(region.native(), clip.as_ref().native())
447 })
448 }
449
450 pub fn is_done(&self) -> bool {
451 self.native().fDone
452 }
453
454 pub fn next(&mut self) {
455 unsafe { self.native_mut().next() }
456 }
457
458 pub fn rect(&self) -> &IRect {
459 IRect::from_native_ref(&self.native().fRect)
460 }
461}
462
463impl iter::Iterator for Cliperator<'_> {
464 type Item = IRect;
465 fn next(&mut self) -> Option<Self::Item> {
466 if self.is_done() {
467 return None;
468 }
469 let rect = *self.rect();
470 self.next();
471 Some(rect)
472 }
473}
474
475#[derive(Clone)]
476#[repr(transparent)]
477pub struct Spanerator<'a>(SkRegion_Spanerator, PhantomData<&'a Region>);
478
479native_transmutable!(SkRegion_Spanerator, Spanerator<'_>);
480
481impl Drop for Spanerator<'_> {
482 fn drop(&mut self) {
483 unsafe { sb::C_SkRegion_Spanerator_destruct(self.native_mut()) }
484 }
485}
486
487impl fmt::Debug for Spanerator<'_> {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 f.debug_struct("Spanerator").finish()
490 }
491}
492
493impl<'a> Spanerator<'a> {
494 pub fn new(region: &'a Region, y: i32, left: i32, right: i32) -> Spanerator<'a> {
495 Spanerator::from_native_c(unsafe {
496 SkRegion_Spanerator::new(region.native(), y, left, right)
497 })
498 }
499}
500
501impl iter::Iterator for Spanerator<'_> {
502 type Item = (i32, i32);
503
504 fn next(&mut self) -> Option<Self::Item> {
505 unsafe {
506 let mut left = 0;
507 let mut right = 0;
508 self.native_mut()
509 .next(&mut left, &mut right)
510 .then_some((left, right))
511 }
512 }
513}
514
515#[test]
516fn new_clone_drop() {
517 let region = Region::new();
518 #[allow(clippy::redundant_clone)]
519 let _cloned = region.clone();
520}
521
522#[test]
523fn can_compare() {
524 let r1 = Region::new();
525 #[allow(clippy::redundant_clone)]
526 let r2 = r1.clone();
527 assert!(r1 == r2);
528}