skia_safe/core/
region.rs

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