use std::collections::HashMap;
use skia_safe::{Color, ISize, Image, Picture, Point, Rect, surfaces};
use crate::tree::ControlId;
use crate::types::Thickness;
pub struct BakeRequest {
pub id: u32,
picture: Picture,
size: ISize,
origin: Point,
}
impl BakeRequest {
pub fn bake(&self) -> Option<Image> {
draw(&self.picture, self.size, self.origin)
}
}
pub(crate) fn rasterize(picture: &Picture, bounds: Rect) -> Option<Image> {
draw(picture, size_of(bounds), Point::new(bounds.left, bounds.top))
}
fn size_of(bounds: Rect) -> ISize {
ISize::new((bounds.width().round() as i32).max(1), (bounds.height().round() as i32).max(1))
}
fn draw(picture: &Picture, size: ISize, origin: Point) -> Option<Image> {
let mut surface = surfaces::raster_n32_premul(size)?;
let canvas = surface.canvas();
canvas.clear(Color::TRANSPARENT);
canvas.translate((-origin.x, -origin.y));
canvas.draw_picture(picture, None, None);
Some(surface.image_snapshot())
}
pub(crate) struct Flying {
pub id: u32,
pub control: ControlId,
pub epoch: u32,
pub bounds: Rect,
pub margin: Thickness,
pub scale: f32,
}
#[derive(Default)]
pub(crate) struct Bakes {
pub enabled: bool,
next: u32,
pub requests: Vec<BakeRequest>,
pub flying: HashMap<usize, Flying>,
failed: HashMap<usize, (ControlId, u32)>,
}
impl Bakes {
pub fn flying(&self, id: ControlId) -> bool {
self.flying.get(&(id.index as usize)).is_some_and(|f| f.control == id)
}
pub fn send(&mut self, id: ControlId, picture: Picture, epoch: u32, bounds: Rect, margin: Thickness, scale: f32) {
self.next = self.next.wrapping_add(1);
let (size, origin) = (size_of(bounds), Point::new(bounds.left, bounds.top));
self.requests.push(BakeRequest { id: self.next, picture, size, origin });
let flying = Flying { id: self.next, control: id, epoch, bounds, margin, scale };
self.flying.insert(id.index as usize, flying);
}
pub fn failed(&self, id: ControlId) -> Option<u32> {
self.failed.get(&(id.index as usize)).filter(|f| f.0 == id).map(|f| f.1)
}
pub fn set_failed(&mut self, id: ControlId, epoch: u32) {
self.failed.insert(id.index as usize, (id, epoch));
}
pub fn arrived(&mut self, id: u32) -> Option<(usize, Flying)> {
let slot = *self.flying.iter().find(|(_, f)| f.id == id)?.0;
self.flying.remove(&slot).map(|f| (slot, f))
}
}