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&mut DebugStruct<'_, '_>.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(name:"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 self.native().fRunHead == Self::EMPTY_RUN_HEAD_PTR
65 }
66
67 pub fn is_rect(&self) -> bool {
68 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: Handle = 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: Handle = 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: Handle = a.clone();
265 a.op_region(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(rgn: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&mut DebugStruct<'_, '_>.debug_struct("Iterator")
337 .field("is_done", &self.is_done())
338 .field(name:"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: IRect = *self.rect();
395 Iterator::next(self);
396 Some(r)
397 }
398}
399
400#[test]
401fn test_iterator() {
402 let r1: IRect = IRect::new(left:10, top:10, right:12, bottom:14);
403 let r2: IRect = IRect::new(left:100, top:100, right:120, bottom:140);
404 let mut r: Handle = 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&mut DebugStruct<'_, '_>.debug_struct("Cliperator")
427 .field("is_done", &self.is_done())
428 .field(name:"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(nt:unsafe {
436 SkRegion_Cliperator::new(region:region.native(), clip: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<'a> iter::Iterator for Cliperator<'a> {
454 type Item = IRect;
455 fn next(&mut self) -> Option<Self::Item> {
456 if self.is_done() {
457 return None;
458 }
459 let rect: IRect = *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(name:"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(nt:unsafe {
486 SkRegion_Spanerator::new(region:region.native(), y, left, right)
487 })
488 }
489}
490
491impl<'a> iter::Iterator for Spanerator<'a> {
492 type Item = (i32, i32);
493
494 fn next(&mut self) -> Option<Self::Item> {
495 unsafe {
496 let mut left: i32 = 0;
497 let mut right: i32 = 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: Handle = Region::new();
508 #[allow(clippy::redundant_clone)]
509 let _cloned: Handle = region.clone();
510}
511
512#[test]
513fn can_compare() {
514 let r1: Handle = Region::new();
515 #[allow(clippy::redundant_clone)]
516 let r2: Handle = r1.clone();
517 assert!(r1 == r2);
518}
519