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 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 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 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
227pub 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
283pub 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
303impl 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
325impl 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}