Implement color filter support for Primitive::Svg in iced_tiny_skia

This commit is contained in:
Héctor Ramón Jiménez 2023-03-09 04:48:35 +01:00
parent aa4b5bb6b9
commit 424ac81773
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
2 changed files with 50 additions and 19 deletions

View file

@ -197,10 +197,11 @@ impl Backend {
Primitive::Svg { Primitive::Svg {
handle, handle,
bounds, bounds,
color: _, // TODO: Implement color filter color,
} => { } => {
self.vector_pipeline.draw( self.vector_pipeline.draw(
handle, handle,
*color,
(*bounds + translation) * scale_factor, (*bounds + translation) * scale_factor,
pixels, pixels,
clip_bounds.map(|_| clip_mask as &_), clip_bounds.map(|_| clip_mask as &_),

View file

@ -1,5 +1,5 @@
use crate::core::svg::{Data, Handle}; use crate::core::svg::{Data, Handle};
use crate::core::{Rectangle, Size}; use crate::core::{Color, Rectangle, Size};
use resvg::usvg; use resvg::usvg;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -29,15 +29,16 @@ impl Pipeline {
pub fn draw( pub fn draw(
&mut self, &mut self,
handle: &Handle, handle: &Handle,
color: Option<Color>,
bounds: Rectangle, bounds: Rectangle,
pixels: &mut tiny_skia::PixmapMut<'_>, pixels: &mut tiny_skia::PixmapMut<'_>,
clip_mask: Option<&tiny_skia::ClipMask>, clip_mask: Option<&tiny_skia::ClipMask>,
) { ) {
if let Some(image) = self if let Some(image) = self.cache.borrow_mut().draw(
.cache handle,
.borrow_mut() color,
.draw(handle, Size::new(bounds.width as u32, bounds.height as u32)) Size::new(bounds.width as u32, bounds.height as u32),
{ ) {
pixels.draw_pixmap( pixels.draw_pixmap(
bounds.x as i32, bounds.x as i32,
bounds.y as i32, bounds.y as i32,
@ -58,8 +59,15 @@ impl Pipeline {
struct Cache { struct Cache {
trees: FxHashMap<u64, Option<resvg::usvg::Tree>>, trees: FxHashMap<u64, Option<resvg::usvg::Tree>>,
tree_hits: FxHashSet<u64>, tree_hits: FxHashSet<u64>,
rasters: FxHashMap<(u64, Size<u32>), tiny_skia::Pixmap>, rasters: FxHashMap<RasterKey, tiny_skia::Pixmap>,
raster_hits: FxHashSet<(u64, Size<u32>)>, raster_hits: FxHashSet<RasterKey>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct RasterKey {
id: u64,
color: Option<[u8; 4]>,
size: Size<u32>,
} }
impl Cache { impl Cache {
@ -101,16 +109,21 @@ impl Cache {
fn draw( fn draw(
&mut self, &mut self,
handle: &Handle, handle: &Handle,
color: Option<Color>,
size: Size<u32>, size: Size<u32>,
) -> Option<tiny_skia::PixmapRef<'_>> { ) -> Option<tiny_skia::PixmapRef<'_>> {
if size.width == 0 || size.height == 0 { if size.width == 0 || size.height == 0 {
return None; return None;
} }
let id = handle.id(); let key = RasterKey {
id: handle.id(),
color: color.map(Color::into_rgba8),
size,
};
#[allow(clippy::map_entry)] #[allow(clippy::map_entry)]
if !self.rasters.contains_key(&(id, size)) { if !self.rasters.contains_key(&key) {
let tree = self.load(handle)?; let tree = self.load(handle)?;
let mut image = tiny_skia::Pixmap::new(size.width, size.height)?; let mut image = tiny_skia::Pixmap::new(size.width, size.height)?;
@ -126,18 +139,35 @@ impl Cache {
image.as_mut(), image.as_mut(),
)?; )?;
// Swap R and B channels for `softbuffer` presentation if let Some([r, g, b, a]) = key.color {
for pixel in bytemuck::cast_slice_mut::<u8, u32>(image.data_mut()) { // TODO: Blend alpha
*pixel = *pixel & 0xFF00FF00 let color = tiny_skia::ColorU8::from_rgba(b, g, r, a)
| ((0x000000FF & *pixel) << 16) .premultiply()
| ((0x00FF0000 & *pixel) >> 16); .get()
& 0x00FFFFFF;
// Apply color filter
for pixel in
bytemuck::cast_slice_mut::<u8, u32>(image.data_mut())
{
*pixel = *pixel & 0xFF000000 | color;
}
} else {
// Swap R and B channels for `softbuffer` presentation
for pixel in
bytemuck::cast_slice_mut::<u8, u32>(image.data_mut())
{
*pixel = *pixel & 0xFF00FF00
| ((0x000000FF & *pixel) << 16)
| ((0x00FF0000 & *pixel) >> 16);
}
} }
self.rasters.insert((id, size), image); self.rasters.insert(key, image);
} }
self.raster_hits.insert((id, size)); self.raster_hits.insert(key);
self.rasters.get(&(id, size)).map(tiny_skia::Pixmap::as_ref) self.rasters.get(&key).map(tiny_skia::Pixmap::as_ref)
} }
fn trim(&mut self) { fn trim(&mut self) {