use std::cell::Cell;
use std::rc::Rc;
use super::flatten::intersect_clips;
use crate::shape::PlacedShape;
#[derive(Debug, Clone)]
pub struct ClipRef(Rc<Cell<PlacedShape>>);
impl ClipRef {
pub fn shape(&self) -> PlacedShape {
self.0.get()
}
pub(crate) fn placed(shape: PlacedShape) -> Self {
Self(Rc::new(Cell::new(shape)))
}
fn place(&self, shape: PlacedShape) {
self.0.set(shape);
}
pub(crate) fn is(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ClipIndex(usize);
struct Placed {
reference: ClipRef,
own: PlacedShape,
under: Under,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Under {
Inherited(Option<ClipIndex>),
Nothing,
}
#[derive(Default)]
pub(crate) struct ClipTree {
placed: Vec<Placed>,
}
impl ClipTree {
pub(crate) fn mark(&self) -> usize {
self.placed.len()
}
pub(crate) fn clear(&mut self) {
let Self { placed } = self;
placed.clear();
}
pub(crate) fn capacity(&self) -> usize {
self.placed.capacity()
}
fn shape(&self, index: ClipIndex) -> PlacedShape {
self.placed[index.0].reference.shape()
}
pub(crate) fn reference(&self, index: ClipIndex) -> ClipRef {
self.placed[index.0].reference.clone()
}
fn cut(&self, own: PlacedShape, under: Under) -> PlacedShape {
match under {
Under::Inherited(Some(parent)) => intersect_clips(&self.shape(parent), &own),
Under::Inherited(None) | Under::Nothing => own,
}
}
fn push(&mut self, reference: ClipRef, own: PlacedShape, under: Under) -> ClipIndex {
let index = ClipIndex(self.placed.len());
self.placed.push(Placed {
reference,
own,
under,
});
index
}
pub(crate) fn place(&mut self, own: PlacedShape, under: Under) -> ClipIndex {
let resolved = self.cut(own, under);
self.push(ClipRef::placed(resolved), own, under)
}
pub(crate) fn replay(
&mut self,
clips: &[CachedClip],
dx: f32,
dy: f32,
inherited: Option<ClipIndex>,
) {
let start = self.placed.len();
for clip in clips {
let own = clip.own.translated(dx, dy);
let under = match clip.parent {
CachedParent::Within(offset) => Under::Inherited(Some(ClipIndex(start + offset))),
CachedParent::Inherited => Under::Inherited(inherited),
CachedParent::Nothing => Under::Nothing,
};
clip.reference.place(self.cut(own, under));
self.push(clip.reference.clone(), own, under);
}
}
pub(crate) fn since(&self, mark: usize) -> Vec<CachedClip> {
self.placed[mark..]
.iter()
.map(|placed| CachedClip {
reference: placed.reference.clone(),
own: placed.own,
parent: match placed.under {
Under::Inherited(Some(ClipIndex(index))) if index >= mark => {
CachedParent::Within(index - mark)
}
Under::Inherited(_) => CachedParent::Inherited,
Under::Nothing => CachedParent::Nothing,
},
})
.collect()
}
}
#[derive(Debug, Clone)]
pub struct CachedClip {
pub(crate) reference: ClipRef,
pub(crate) own: PlacedShape,
pub(crate) parent: CachedParent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum CachedParent {
Within(usize),
Inherited,
Nothing,
}