| 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::new(10, 10, 12, 14); |
| 403 | let r2 = IRect::new(100, 100, 120, 140); |
| 404 | let mut r = 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.native(), 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 iter::Iterator for Cliperator<'_> { |
| 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.native(), y, left, right) |
| 487 | }) |
| 488 | } |
| 489 | } |
| 490 | |
| 491 | impl iter::Iterator for Spanerator<'_> { |
| 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 = Region::new(); |
| 508 | #[allow (clippy::redundant_clone)] |
| 509 | let _cloned = region.clone(); |
| 510 | } |
| 511 | |
| 512 | #[test ] |
| 513 | fn can_compare() { |
| 514 | let r1 = Region::new(); |
| 515 | #[allow (clippy::redundant_clone)] |
| 516 | let r2 = r1.clone(); |
| 517 | assert!(r1 == r2); |
| 518 | } |
| 519 | |