Implement color filter support for Primitive::Svg in iced_tiny_skia
This commit is contained in:
parent
aa4b5bb6b9
commit
424ac81773
2 changed files with 50 additions and 19 deletions
|
|
@ -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 &_),
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue