Skip to main content

skia_safe/core/
region.rs

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