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 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 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 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
230pub 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
286pub 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
306impl 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
328impl 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}