use super::*;
pub struct SkiaSoftwareSurface {
pixels: Vec<u8>,
size: (i32, i32),
cache: SkiaCache,
}
impl SkiaSoftwareSurface {
pub fn new(cache_budget: usize) -> Self {
Self {
pixels: Vec::new(),
size: (0, 0),
cache: SkiaCache::new(cache_budget),
}
}
fn ensure_surface(&mut self, width: i32, height: i32) {
let size = (width.max(1), height.max(1));
if self.size != size {
self.size = size;
self.pixels.resize(size.0 as usize * size.1 as usize * 4, 0);
self.cache.trim(MemoryPressure::Critical);
}
}
pub fn draw(&mut self, scene: &Scene, frame: &FrameInfo<'_>) -> Result<(), String> {
let viewport = frame.viewport();
self.ensure_surface(viewport.width(), viewport.height());
let info = ImageInfo::new(self.size, ColorType::BGRA8888, AlphaType::Premul, None);
let mut surface = surfaces::wrap_pixels(
&info,
self.pixels.as_mut_slice(),
self.size.0 as usize * 4,
None,
)
.ok_or_else(|| "Skia could not wrap the retained software surface".to_owned())?;
paint_scene_damage(surface.canvas(), &mut self.cache, scene, frame)
}
pub fn pixels(&self) -> &[u8] {
&self.pixels
}
pub fn size(&self) -> (i32, i32) {
self.size
}
pub fn trim(&mut self, pressure: MemoryPressure) {
self.cache.trim(pressure);
if pressure == MemoryPressure::Critical {
self.pixels.clear();
self.size = (0, 0);
}
}
pub fn set_cache_budget(&mut self, budget_bytes: usize) {
self.cache.set_budget(budget_bytes);
}
pub fn cache_stats(&self) -> SkiaCacheStats {
self.cache.stats()
}
}
pub fn paint_scene_damage(
canvas: &Canvas,
cache: &mut SkiaCache,
scene: &Scene,
frame: &FrameInfo<'_>,
) -> Result<(), String> {
cache.begin_frame();
let clips: Vec<PhysicalRect> = if frame.is_full_redraw() {
vec![frame.viewport()]
} else {
frame.damage().to_vec()
};
let mut painter = SkiaPainter { cache };
for clip in clips {
canvas.save();
canvas.clip_rect(physical_rect(clip), None, false);
canvas.clear(SkColor::TRANSPARENT);
painter.draw_commands(canvas, scene.commands(), Some(ui_rect_from_physical(clip)))?;
canvas.restore();
}
Ok(())
}