Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions tiny_skia/src/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ use std::fs;
use std::panic;
use std::sync::Arc;

const SMALL_SVG_OVERSAMPLE_LIMIT: u32 = 128;
const SMALL_SVG_OVERSAMPLE_FACTOR: u32 = 2;

fn oversample_size(size: Size<u32>) -> Size<u32> {
let factor = if size.width.max(size.height) <= SMALL_SVG_OVERSAMPLE_LIMIT {
SMALL_SVG_OVERSAMPLE_FACTOR
} else {
1
};

Size::new(
size.width.saturating_mul(factor),
size.height.saturating_mul(factor),
)
}

#[derive(Debug)]
pub struct Pipeline {
cache: RefCell<Cache>,
Expand Down Expand Up @@ -40,16 +56,23 @@ impl Pipeline {
transform: Transform,
clip_mask: Option<&tiny_skia::Mask>,
) {
let requested_size =
oversample_size(Size::new(bounds.width as u32, bounds.height as u32));

if let Some(image) = self.cache.borrow_mut().draw(
handle,
color,
// XX Do not apply transform scaling for rotation to the size
Size::new((bounds.width) as u32, (bounds.height) as u32),
requested_size,
) {
let width_scale = bounds.width / image.width() as f32;
let height_scale = bounds.height / image.height() as f32;
let transform = transform.pre_scale(width_scale, height_scale);

// XX Do not apply transform scaling for rotation to the position
pixels.draw_pixmap(
(bounds.x) as i32,
(bounds.y) as i32,
(bounds.x / width_scale) as i32,
(bounds.y / height_scale) as i32,
image,
&tiny_skia::PixmapPaint {
opacity,
Expand Down
45 changes: 36 additions & 9 deletions wgpu/src/image/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ pub struct Cache {
}

type ColorFilter = Option<[u8; 4]>;
const SMALL_SVG_OVERSAMPLE_LIMIT: u32 = 128;
const SMALL_SVG_OVERSAMPLE_FACTOR: u32 = 2;

fn oversample_dimensions(width: u32, height: u32) -> (u32, u32) {
let factor = if width.max(height) <= SMALL_SVG_OVERSAMPLE_LIMIT {
SMALL_SVG_OVERSAMPLE_FACTOR
} else {
1
};

(
width.saturating_mul(factor),
height.saturating_mul(factor),
)
}

impl Cache {
/// Load svg
Expand Down Expand Up @@ -108,9 +123,11 @@ impl Cache {
(scale * size.width).ceil() as u32,
(scale * size.height).ceil() as u32,
);
let (raster_width, raster_height) =
oversample_dimensions(width, height);

let color = color.map(Color::into_rgba8);
let key = (id, width, height, color);
let key = (id, raster_width, raster_height, color);

// TODO: Optimize!
// We currently rerasterize the SVG when its size changes. This is slow
Expand All @@ -125,22 +142,23 @@ impl Cache {

match self.load(handle) {
Svg::Loaded(tree) => {
if width == 0 || height == 0 {
if raster_width == 0 || raster_height == 0 {
return None;
}

// TODO: Optimize!
// We currently rerasterize the SVG when its size changes. This is slow
// as heck. A GPU rasterizer like `pathfinder` may perform better.
// It would be cool to be able to smooth resize the `svg` example.
let mut img = tiny_skia::Pixmap::new(width, height)?;
let mut img =
tiny_skia::Pixmap::new(raster_width, raster_height)?;

let tree_size = tree.size().to_int_size();

let target_size = if width > height {
tree_size.scale_to_width(width)
let target_size = if raster_width > raster_height {
tree_size.scale_to_width(raster_width)
} else {
tree_size.scale_to_height(height)
tree_size.scale_to_height(raster_height)
};

let transform = if let Some(target_size) = target_size {
Expand Down Expand Up @@ -181,9 +199,18 @@ impl Cache {
}

let allocation = atlas
.upload(device, encoder, belt, width, height, &rgba)?;

log::debug!("allocating {id} {width}x{height}");
.upload(
device,
encoder,
belt,
raster_width,
raster_height,
&rgba,
)?;

log::debug!(
"allocating {id} {raster_width}x{raster_height}"
);

let _ = self.svg_hits.insert(id);
let _ = self.rasterized_hits.insert(key);
Expand Down