use crate::prelude::*;
use crate::{Contains, IPoint, IRect, IVector, Path, QuickReject};
use skia_bindings as sb;
use skia_bindings::{
SkRegion, SkRegion_Cliperator, SkRegion_Iterator, SkRegion_Op, SkRegion_RunHead,
SkRegion_Spanerator,
};
use std::marker::PhantomData;
use std::{iter, mem, ptr};
pub type Region = Handle<SkRegion>;
impl NativeDrop for SkRegion {
fn drop(&mut self) {
unsafe { sb::C_SkRegion_destruct(self) }
}
}
impl NativeClone for SkRegion {
fn clone(&self) -> Self {
unsafe { SkRegion::new1(self) }
}
}
impl NativePartialEq for SkRegion {
fn eq(&self, rhs: &Self) -> bool {
unsafe { sb::C_SkRegion_Equals(self, rhs) }
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(i32)]
pub enum RegionOp {
Difference = SkRegion_Op::kDifference_Op as _,
Intersect = SkRegion_Op::kIntersect_Op as _,
Union = SkRegion_Op::kUnion_Op as _,
XOR = SkRegion_Op::kXOR_Op as _,
ReverseDifference = SkRegion_Op::kReverseDifference_Op as _,
Replace = SkRegion_Op::kReplace_Op as _,
}
impl NativeTransmutable<SkRegion_Op> for RegionOp {}
#[test]
fn test_region_op_layout() {
RegionOp::test_layout()
}
impl Handle<SkRegion> {
pub fn new() -> Region {
Self::from_native(unsafe { SkRegion::new() })
}
pub fn from_rect(rect: impl AsRef<IRect>) -> Region {
Self::from_native(unsafe { SkRegion::new2(rect.as_ref().native()) })
}
pub fn set(&mut self, src: &Region) -> bool {
unsafe { sb::C_SkRegion_set(self.native_mut(), src.native()) }
}
pub fn swap(&mut self, other: &mut Region) {
unsafe { self.native_mut().swap(other.native_mut()) }
}
const EMPTY_RUN_HEAD_PTR: *mut SkRegion_RunHead = -1 as _;
const RECT_RUN_HEAD_PTR: *mut SkRegion_RunHead = ptr::null_mut();
pub fn is_empty(&self) -> bool {
self.native().fRunHead == Self::EMPTY_RUN_HEAD_PTR
}
pub fn is_rect(&self) -> bool {
self.native().fRunHead == Self::RECT_RUN_HEAD_PTR
}
pub fn is_complex(&self) -> bool {
!self.is_empty() && !self.is_rect()
}
pub fn bounds(&self) -> &IRect {
IRect::from_native_ref(&self.native().fBounds)
}
pub fn compute_region_complexity(&self) -> usize {
unsafe { self.native().computeRegionComplexity().try_into().unwrap() }
}
#[deprecated(since = "0.12.0", note = "use get_boundary_path()")]
pub fn boundary_path(&self, path: &mut Path) -> bool {
self.get_boundary_path(path)
}
pub fn get_boundary_path(&self, path: &mut Path) -> bool {
unsafe { self.native().getBoundaryPath(path.native_mut()) }
}
pub fn set_empty(&mut self) -> bool {
unsafe { self.native_mut().setEmpty() }
}
pub fn set_rect(&mut self, rect: impl AsRef<IRect>) -> bool {
unsafe { self.native_mut().setRect(rect.as_ref().native()) }
}
pub fn set_rect_ltbr(&mut self, left: i32, top: i32, right: i32, bottom: i32) -> bool {
self.set_rect(IRect::new(left, top, right, bottom))
}
pub fn set_rects(&mut self, rects: &[IRect]) -> bool {
unsafe {
self.native_mut()
.setRects(rects.native().as_ptr(), rects.len().try_into().unwrap())
}
}
pub fn set_region(&mut self, region: &Region) -> bool {
unsafe { self.native_mut().setRegion(region.native()) }
}
pub fn set_path(&mut self, path: &Path, clip: &Region) -> bool {
unsafe { self.native_mut().setPath(path.native(), clip.native()) }
}
pub fn intersects_rect(&self, rect: impl AsRef<IRect>) -> bool {
unsafe { self.native().intersects(rect.as_ref().native()) }
}
pub fn intersects_region(&self, other: &Region) -> bool {
unsafe { self.native().intersects1(other.native()) }
}
pub fn contains_point(&self, point: IPoint) -> bool {
unsafe { self.native().contains(point.x, point.y) }
}
pub fn contains_rect(&self, rect: impl AsRef<IRect>) -> bool {
unsafe { self.native().contains1(rect.as_ref().native()) }
}
pub fn contains_region(&self, other: &Region) -> bool {
unsafe { self.native().contains2(other.native()) }
}
pub fn quick_contains(&self, r: impl AsRef<IRect>) -> bool {
let r = r.as_ref();
self.quick_contains_ltrb(r.left, r.top, r.right, r.bottom)
}
pub fn quick_contains_ltrb(&self, left: i32, top: i32, right: i32, bottom: i32) -> bool {
unsafe { sb::C_SkRegion_quickContains(self.native(), left, top, right, bottom) }
}
pub fn quick_reject_rect(&self, rect: impl AsRef<IRect>) -> bool {
let rect = rect.as_ref();
self.is_empty() || rect.is_empty() || !IRect::intersects(&self.bounds(), rect)
}
pub fn quick_reject_region(&self, rgn: &Region) -> bool {
self.is_empty() || rgn.is_empty() || !IRect::intersects(&self.bounds(), &rgn.bounds())
}
pub fn translate(&mut self, d: impl Into<IVector>) {
let d = d.into();
let self_ptr = self.native_mut() as *mut _;
unsafe { self.native().translate(d.x, d.y, self_ptr) }
}
pub fn translated(&self, d: impl Into<IVector>) -> Region {
let mut r = self.clone();
r.translate(d);
r
}
pub fn op_rect(&mut self, rect: impl AsRef<IRect>, op: RegionOp) -> bool {
let self_ptr = self.native_mut() as *const _;
unsafe {
self.native_mut()
.op1(self_ptr, rect.as_ref().native(), op.into_native())
}
}
pub fn op_region(&mut self, region: &Region, op: RegionOp) -> bool {
let self_ptr = self.native_mut() as *const _;
unsafe {
self.native_mut()
.op2(self_ptr, region.native(), op.into_native())
}
}
pub fn op_rect_region(
&mut self,
rect: impl AsRef<IRect>,
region: &Region,
op: RegionOp,
) -> bool {
unsafe {
self.native_mut()
.op(rect.as_ref().native(), region.native(), op.into_native())
}
}
pub fn op_region_rect(
&mut self,
region: &Region,
rect: impl AsRef<IRect>,
op: RegionOp,
) -> bool {
unsafe {
self.native_mut()
.op1(region.native(), rect.as_ref().native(), op.into_native())
}
}
pub fn write_to_memory(&self, buf: &mut Vec<u8>) {
unsafe {
let size = self.native().writeToMemory(ptr::null_mut());
buf.resize(size, 0);
let written = self.native().writeToMemory(buf.as_mut_ptr() as _);
debug_assert!(written == size);
}
}
pub fn read_from_memory(&mut self, buf: &[u8]) -> usize {
unsafe {
self.native_mut()
.readFromMemory(buf.as_ptr() as _, buf.len())
}
}
}
pub trait Combine<A, B>: Sized {
fn combine(a: &A, op: RegionOp, b: &B) -> Self;
fn difference(a: &A, b: &B) -> Self {
Self::combine(a, RegionOp::Difference, b)
}
fn intersect(a: &A, b: &B) -> Self {
Self::combine(a, RegionOp::Intersect, b)
}
fn xor(a: &A, b: &B) -> Self {
Self::combine(a, RegionOp::XOR, b)
}
fn union(a: &A, b: &B) -> Self {
Self::combine(a, RegionOp::Union, b)
}
fn reverse_difference(a: &A, b: &B) -> Self {
Self::combine(a, RegionOp::ReverseDifference, b)
}
fn replace(a: &A, b: &B) -> Self {
Self::combine(a, RegionOp::Replace, b)
}
}
impl Combine<IRect, Region> for Handle<SkRegion> {
fn combine(rect: &IRect, op: RegionOp, region: &Region) -> Self {
let mut r = Region::new();
r.op_rect_region(rect, region, op);
r
}
}
impl Combine<Region, IRect> for Handle<SkRegion> {
fn combine(region: &Region, op: RegionOp, rect: &IRect) -> Self {
let mut r = Region::new();
r.op_region_rect(region, rect, op);
r
}
}
impl Combine<Region, Region> for Handle<SkRegion> {
fn combine(a: &Region, op: RegionOp, b: &Region) -> Self {
let mut a = a.clone();
a.op_region(b, op);
a
}
}
pub trait Intersects<T> {
fn intersects(&self, other: &T) -> bool;
}
impl Intersects<IRect> for Region {
fn intersects(&self, rect: &IRect) -> bool {
self.intersects_rect(rect)
}
}
impl Intersects<Region> for Region {
fn intersects(&self, other: &Region) -> bool {
self.intersects_region(other)
}
}
impl Contains<IPoint> for Region {
fn contains(&self, point: IPoint) -> bool {
self.contains_point(point)
}
}
impl Contains<&IRect> for Region {
fn contains(&self, rect: &IRect) -> bool {
self.contains_rect(rect)
}
}
impl Contains<&Region> for Region {
fn contains(&self, other: &Region) -> bool {
self.contains_region(other)
}
}
impl QuickReject<IRect> for Region {
fn quick_reject(&self, rect: &IRect) -> bool {
self.quick_reject_rect(rect)
}
}
impl QuickReject<Region> for Region {
fn quick_reject(&self, other: &Region) -> bool {
self.quick_reject_region(other)
}
}
#[derive(Clone)]
#[repr(transparent)]
pub struct Iterator<'a>(SkRegion_Iterator, PhantomData<&'a Region>);
impl<'a> NativeTransmutable<SkRegion_Iterator> for Iterator<'a> {}
#[test]
fn test_iterator_layout() {
Iterator::test_layout();
}
impl<'a> Iterator<'a> {
pub fn new_empty() -> Iterator<'a> {
Iterator::construct(|iterator| unsafe {
sb::C_SkRegion_Iterator_Construct(iterator);
})
}
pub fn new(region: &'a Region) -> Iterator<'a> {
Iterator::from_native(unsafe { SkRegion_Iterator::new(region.native()) })
}
pub fn rewind(&mut self) -> bool {
unsafe { self.native_mut().rewind() }
}
pub fn reset(mut self, region: &Region) -> Iterator {
unsafe {
self.native_mut().reset(region.native());
let r = mem::transmute_copy(&self);
mem::forget(self);
r
}
}
pub fn is_done(&self) -> bool {
self.native().fDone
}
pub fn next(&mut self) {
unsafe {
self.native_mut().next();
}
}
pub fn rect(&self) -> &IRect {
IRect::from_native_ref(&self.native().fRect)
}
pub fn rgn(&self) -> Option<&Region> {
unsafe {
let r = sb::C_SkRegion_Iterator_rgn(self.native()).into_option()?;
Some(transmute_ref(&*r))
}
}
}
impl<'a> iter::Iterator for Iterator<'a> {
type Item = IRect;
fn next(&mut self) -> Option<Self::Item> {
if self.is_done() {
return None;
}
let r = *self.rect();
Iterator::next(self);
Some(r)
}
}
#[test]
fn test_iterator() {
let r1 = IRect::new(10, 10, 12, 14);
let r2 = IRect::new(100, 100, 120, 140);
let mut r = Region::new();
r.set_rects(&[r1, r2]);
let rects: Vec<IRect> = Iterator::new(&r).collect();
assert_eq!(rects.len(), 2);
assert_eq!(rects[0], r1);
assert_eq!(rects[1], r2);
}
#[derive(Clone)]
#[repr(transparent)]
pub struct Cliperator<'a>(SkRegion_Cliperator, PhantomData<&'a Region>);
impl<'a> NativeTransmutable<SkRegion_Cliperator> for Cliperator<'a> {}
#[test]
fn test_cliperator_layout() {
Cliperator::test_layout();
}
impl<'a> Drop for Cliperator<'a> {
fn drop(&mut self) {
unsafe { sb::C_SkRegion_Cliperator_destruct(self.native_mut()) }
}
}
impl<'a> Cliperator<'a> {
pub fn new(region: &'a Region, clip: impl AsRef<IRect>) -> Cliperator<'a> {
Cliperator::from_native(unsafe {
SkRegion_Cliperator::new(region.native(), clip.as_ref().native())
})
}
pub fn is_done(&self) -> bool {
self.native().fDone
}
pub fn next(&mut self) {
unsafe { self.native_mut().next() }
}
pub fn rect(&self) -> &IRect {
IRect::from_native_ref(&self.native().fRect)
}
}
impl<'a> iter::Iterator for Cliperator<'a> {
type Item = IRect;
fn next(&mut self) -> Option<Self::Item> {
if self.is_done() {
return None;
}
let rect = *self.rect();
self.next();
Some(rect)
}
}
#[derive(Clone)]
#[repr(transparent)]
pub struct Spanerator<'a>(SkRegion_Spanerator, PhantomData<&'a Region>);
impl<'a> NativeTransmutable<SkRegion_Spanerator> for Spanerator<'a> {}
#[test]
fn test_spanerator_layout() {
Spanerator::test_layout();
}
impl<'a> Drop for Spanerator<'a> {
fn drop(&mut self) {
unsafe { sb::C_SkRegion_Spanerator_destruct(self.native_mut()) }
}
}
impl<'a> Spanerator<'a> {
pub fn new(region: &'a Region, y: i32, left: i32, right: i32) -> Spanerator<'a> {
Spanerator::from_native(unsafe {
SkRegion_Spanerator::new(region.native(), y, left, right)
})
}
}
impl<'a> iter::Iterator for Spanerator<'a> {
type Item = (i32, i32);
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let mut left = 0;
let mut right = 0;
self.native_mut()
.next(&mut left, &mut right)
.if_true_some((left, right))
}
}
}
#[test]
fn new_clone_drop() {
let region = Region::new();
let _cloned = region.clone();
}
#[test]
fn can_compare() {
let r1 = Region::new();
let r2 = r1.clone();
assert!(r1 == r2);
}