1 | use crate::{prelude::*, Contains, IPoint, IRect, IVector, Path, QuickReject}; |
2 | use skia_bindings::{ |
3 | self as sb, SkRegion, SkRegion_Cliperator, SkRegion_Iterator, SkRegion_RunHead, |
4 | SkRegion_Spanerator, |
5 | }; |
6 | use std::{fmt, iter, marker::PhantomData, mem, ptr}; |
7 | |
8 | pub type Region = Handle<SkRegion>; |
9 | unsafe_send_sync!(Region); |
10 | |
11 | impl NativeDrop for SkRegion { |
12 | fn drop(&mut self) { |
13 | unsafe { sb::C_SkRegion_destruct(self) } |
14 | } |
15 | } |
16 | |
17 | impl NativeClone for SkRegion { |
18 | fn clone(&self) -> Self { |
19 | unsafe { SkRegion::new1(self) } |
20 | } |
21 | } |
22 | |
23 | impl NativePartialEq for SkRegion { |
24 | fn eq(&self, rhs: &Self) -> bool { |
25 | unsafe { sb::C_SkRegion_Equals(self, rhs) } |
26 | } |
27 | } |
28 | |
29 | impl 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 | |
40 | pub use skia_bindings::SkRegion_Op as RegionOp; |
41 | variant_name!(RegionOp::ReverseDifference); |
42 | |
43 | impl 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 | |
218 | pub 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 | |
246 | impl 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 | |
254 | impl 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 | |
262 | impl 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 | |
274 | pub trait Intersects<T> { |
275 | fn intersects(&self, other: &T) -> bool; |
276 | } |
277 | |
278 | impl Intersects<IRect> for Region { |
279 | fn intersects(&self, rect: &IRect) -> bool { |
280 | self.intersects_rect(rect) |
281 | } |
282 | } |
283 | |
284 | impl 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 | |
294 | impl Contains<IPoint> for Region { |
295 | fn contains(&self, point: IPoint) -> bool { |
296 | self.contains_point(point) |
297 | } |
298 | } |
299 | |
300 | impl Contains<&IRect> for Region { |
301 | fn contains(&self, rect: &IRect) -> bool { |
302 | self.contains_rect(rect) |
303 | } |
304 | } |
305 | |
306 | impl 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 | |
316 | impl QuickReject<IRect> for Region { |
317 | fn quick_reject(&self, rect: &IRect) -> bool { |
318 | self.quick_reject_rect(rect) |
319 | } |
320 | } |
321 | |
322 | impl 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)] |
330 | pub struct Iterator<'a>(SkRegion_Iterator, PhantomData<&'a Region>); |
331 | |
332 | native_transmutable!(SkRegion_Iterator, Iterator<'_>, iterator_layout); |
333 | |
334 | impl 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 | |
343 | impl<'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 | |
387 | impl 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 ] |
401 | fn 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)] |
414 | pub struct Cliperator<'a>(SkRegion_Cliperator, PhantomData<&'a Region>); |
415 | |
416 | native_transmutable!(SkRegion_Cliperator, Cliperator<'_>, cliperator_layout); |
417 | |
418 | impl Drop for Cliperator<'_> { |
419 | fn drop(&mut self) { |
420 | unsafe { sb::C_SkRegion_Cliperator_destruct(self.native_mut()) } |
421 | } |
422 | } |
423 | |
424 | impl 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 | |
433 | impl<'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 | |
453 | impl<'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)] |
467 | pub struct Spanerator<'a>(SkRegion_Spanerator, PhantomData<&'a Region>); |
468 | |
469 | native_transmutable!(SkRegion_Spanerator, Spanerator<'_>, spanerator_layout); |
470 | |
471 | impl Drop for Spanerator<'_> { |
472 | fn drop(&mut self) { |
473 | unsafe { sb::C_SkRegion_Spanerator_destruct(self.native_mut()) } |
474 | } |
475 | } |
476 | |
477 | impl fmt::Debug for Spanerator<'_> { |
478 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
479 | f.debug_struct(name:"Spanerator" ).finish() |
480 | } |
481 | } |
482 | |
483 | impl<'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 | |
491 | impl<'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 ] |
506 | fn new_clone_drop() { |
507 | let region: Handle = Region::new(); |
508 | #[allow (clippy::redundant_clone)] |
509 | let _cloned: Handle = region.clone(); |
510 | } |
511 | |
512 | #[test ] |
513 | fn 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 | |