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