Small image handling cleanup

Use a dedicated structure for femtovg based textures
This commit is contained in:
Simon Hausmann 2021-02-10 20:36:32 +01:00
parent 1793ef4d77
commit ad0d2f04e1
2 changed files with 50 additions and 45 deletions

View file

@ -38,6 +38,7 @@ fontdb = { version = "0.5.1", default-features = false }
resvg = { version= "0.13", optional = true, default-features = false } resvg = { version= "0.13", optional = true, default-features = false }
usvg = { version= "0.13", optional = true, default-features = false } usvg = { version= "0.13", optional = true, default-features = false }
tiny-skia = { version= "0.4.2", optional = true, default-features = false } tiny-skia = { version= "0.4.2", optional = true, default-features = false }
derive_more = "0.99.5"
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
web_sys = { version = "0.3", package = "web-sys", features=["console", "WebGlContextAttributes"] } web_sys = { version = "0.3", package = "web-sys", features=["console", "WebGlContextAttributes"] }

View file

@ -15,8 +15,7 @@ use sixtyfps_corelib::{graphics::Size, slice::Slice, Property, Resource, SharedS
use super::{CanvasRc, GLItemRenderer, GLRendererData}; use super::{CanvasRc, GLItemRenderer, GLRendererData};
enum ImageData { struct Texture {
Texture {
id: femtovg::ImageId, id: femtovg::ImageId,
canvas: CanvasRc, canvas: CanvasRc,
/// If present, this boolean property indicates whether the image has been uploaded yet or /// If present, this boolean property indicates whether the image has been uploaded yet or
@ -24,24 +23,40 @@ enum ImageData {
/// used for remote HTML image loading and the property will be used to correctly track dependencies /// used for remote HTML image loading and the property will be used to correctly track dependencies
/// to graphics items that query for the size. /// to graphics items that query for the size.
upload_pending: Option<core::pin::Pin<Box<Property<bool>>>>, upload_pending: Option<core::pin::Pin<Box<Property<bool>>>>,
}, }
impl Texture {
fn size(&self) -> Option<Size> {
if self
.upload_pending
.as_ref()
.map_or(false, |pending_property| pending_property.as_ref().get())
{
None
} else {
self.canvas
.borrow()
.image_info(self.id)
.map(|info| [info.width() as f32, info.height() as f32].into())
.ok()
}
}
}
impl Drop for Texture {
fn drop(&mut self) {
self.canvas.borrow_mut().delete_image(self.id);
}
}
#[derive(derive_more::From)]
enum ImageData {
Texture(Texture),
DecodedImage(image::DynamicImage), DecodedImage(image::DynamicImage),
#[cfg(feature = "svg")] #[cfg(feature = "svg")]
SVG(usvg::Tree), SVG(usvg::Tree),
} }
impl Drop for ImageData {
fn drop(&mut self) {
match self {
ImageData::Texture { id, canvas, .. } => {
canvas.borrow_mut().delete_image(*id);
}
ImageData::DecodedImage(..) => {}
ImageData::SVG(..) => {}
}
}
}
pub(crate) struct CachedImage(RefCell<ImageData>); pub(crate) struct CachedImage(RefCell<ImageData>);
impl CachedImage { impl CachedImage {
@ -54,11 +69,14 @@ impl CachedImage {
image_id: femtovg::ImageId, image_id: femtovg::ImageId,
upload_pending_notifier: Option<core::pin::Pin<Box<Property<bool>>>>, upload_pending_notifier: Option<core::pin::Pin<Box<Property<bool>>>>,
) -> Self { ) -> Self {
Self(RefCell::new(ImageData::Texture { Self(RefCell::new(
Texture {
id: image_id, id: image_id,
canvas: canvas.clone(), canvas: canvas.clone(),
upload_pending: upload_pending_notifier, upload_pending: upload_pending_notifier,
})) }
.into(),
))
} }
#[cfg(feature = "svg")] #[cfg(feature = "svg")]
@ -216,11 +234,11 @@ impl CachedImage {
} }
.unwrap(); .unwrap();
*img = ImageData::Texture { id: image_id, canvas: canvas.clone(), upload_pending: None } *img = Texture { id: image_id, canvas: canvas.clone(), upload_pending: None }.into()
}; };
match &img { match &img {
ImageData::Texture { id, .. } => *id, ImageData::Texture(Texture { id, .. }) => *id,
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -229,32 +247,18 @@ impl CachedImage {
use image::GenericImageView; use image::GenericImageView;
match &*self.0.borrow() { match &*self.0.borrow() {
ImageData::Texture { id, canvas, upload_pending } => { ImageData::Texture(texture) => texture.size(),
if upload_pending
.as_ref()
.map_or(false, |pending_property| pending_property.as_ref().get())
{
None
} else {
canvas
.borrow()
.image_info(*id)
.map(|info| (info.width() as f32, info.height() as f32))
.ok()
}
}
ImageData::DecodedImage(decoded_image) => { ImageData::DecodedImage(decoded_image) => {
let (width, height) = decoded_image.dimensions(); let (width, height) = decoded_image.dimensions();
Some((width as f32, height as f32)) Some([width as f32, height as f32].into())
} }
#[cfg(feature = "svg")] #[cfg(feature = "svg")]
ImageData::SVG(tree) => { ImageData::SVG(tree) => {
let size = tree.svg_node().size.to_screen_size(); let size = tree.svg_node().size.to_screen_size();
Some((size.width() as f32, size.height() as f32)) Some([size.width() as f32, size.height() as f32].into())
} }
} }
.map(|(width, height)| euclid::size2(width, height))
} }
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]