skia_safe/core/
region.rs

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    // there is also a trait for intersects() below.
121
122    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    // contains() trait below.
131
132    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    // see also the quick_reject() trait below.
150
151    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
224//
225// combine overloads (static)
226//
227
228pub 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
280//
281// intersects overloads
282//
283
284pub 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
300//
301// contains overloads
302//
303
304impl 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
322//
323// quick_reject overloads
324//
325
326impl 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}