render: Made render use a real Error enum and not generic box<error>
This commit is contained in:
parent
726217c6c2
commit
03eb769a33
|
@ -3110,6 +3110,8 @@ dependencies = [
|
|||
"png",
|
||||
"smallvec",
|
||||
"swf",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -124,6 +124,9 @@ pub enum Error {
|
|||
#[error("Invalid SWF: {0}")]
|
||||
InvalidSwf(#[from] crate::tag_utils::Error),
|
||||
|
||||
#[error("Invalid bitmap")]
|
||||
InvalidBitmap(#[from] ruffle_render::error::Error),
|
||||
|
||||
#[error("Unexpected content of type {1}, expected {0}")]
|
||||
UnexpectedData(ContentType, ContentType),
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ flate2 = "1.0.24"
|
|||
smallvec = { version = "1.9.0", features = ["union"] }
|
||||
downcast-rs = "1.2.0"
|
||||
lyon = { version = "1.0.0", optional = true }
|
||||
thiserror = "1.0"
|
||||
wasm-bindgen = { version = "=0.2.82", optional = true }
|
||||
|
||||
[dependencies.jpeg-decoder]
|
||||
version = "0.2.6"
|
||||
|
@ -25,4 +27,5 @@ approx = "0.5.1"
|
|||
|
||||
[features]
|
||||
default = []
|
||||
tessellator = ["lyon"]
|
||||
tessellator = ["lyon"]
|
||||
web = ["wasm-bindgen"]
|
|
@ -11,7 +11,7 @@ log = "0.4"
|
|||
ruffle_web_common = { path = "../../web/common" }
|
||||
wasm-bindgen = "=0.2.82"
|
||||
fnv = "1.0.7"
|
||||
ruffle_render = { path = ".." }
|
||||
ruffle_render = { path = "..", features = ["web"] }
|
||||
swf = { path = "../../swf" }
|
||||
|
||||
[dependencies.web-sys]
|
||||
|
|
|
@ -3,12 +3,13 @@ use ruffle_render::backend::null::NullBitmapSource;
|
|||
use ruffle_render::backend::{RenderBackend, ShapeHandle, ViewportDimensions};
|
||||
use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle, BitmapSource};
|
||||
use ruffle_render::color_transform::ColorTransform;
|
||||
use ruffle_render::error::Error as BitmapError;
|
||||
use ruffle_render::matrix::Matrix;
|
||||
use ruffle_render::shape_utils::{DistilledShape, DrawCommand, LineScaleMode, LineScales};
|
||||
use ruffle_render::transform::Transform;
|
||||
use ruffle_web_common::{JsError, JsResult};
|
||||
use swf::{BlendMode, Color};
|
||||
use wasm_bindgen::{Clamped, JsCast};
|
||||
use wasm_bindgen::{Clamped, JsCast, JsValue};
|
||||
use web_sys::{
|
||||
CanvasGradient, CanvasPattern, CanvasRenderingContext2d, CanvasWindingRule, DomMatrix, Element,
|
||||
HtmlCanvasElement, ImageData, Path2d,
|
||||
|
@ -139,7 +140,7 @@ struct BitmapData {
|
|||
|
||||
impl BitmapData {
|
||||
/// Puts the image data into a newly created <canvas>, and caches it.
|
||||
fn new(bitmap: Bitmap) -> Result<Self, Error> {
|
||||
fn new(bitmap: Bitmap) -> Result<Self, JsValue> {
|
||||
let bitmap = bitmap.to_rgba();
|
||||
let image_data =
|
||||
ImageData::new_with_u8_clamped_array(Clamped(bitmap.data()), bitmap.width())
|
||||
|
@ -736,15 +737,15 @@ impl RenderBackend for WebCanvasRenderBackend {
|
|||
bitmap.get_pixels()
|
||||
}
|
||||
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, BitmapError> {
|
||||
let handle = self.next_bitmap_handle;
|
||||
self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1);
|
||||
let bitmap_data = BitmapData::new(bitmap)?;
|
||||
let bitmap_data = BitmapData::new(bitmap).map_err(BitmapError::JavascriptError)?;
|
||||
self.bitmaps.insert(handle, bitmap_data);
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), Error> {
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), BitmapError> {
|
||||
self.bitmaps.remove(&bitmap);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -755,12 +756,13 @@ impl RenderBackend for WebCanvasRenderBackend {
|
|||
width: u32,
|
||||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<BitmapHandle, Error> {
|
||||
) -> Result<BitmapHandle, BitmapError> {
|
||||
// TODO: Could be optimized to a single put_image_data call
|
||||
// in case it is already stored as a canvas+context.
|
||||
self.bitmaps.insert(
|
||||
handle,
|
||||
BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))?,
|
||||
BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))
|
||||
.map_err(BitmapError::JavascriptError)?,
|
||||
);
|
||||
Ok(handle)
|
||||
}
|
||||
|
|
|
@ -1 +1,32 @@
|
|||
pub type Error = Box<dyn std::error::Error>;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Bitmap texture is larger than the rendering device supports")]
|
||||
TooLarge,
|
||||
|
||||
#[error("Unknown bitmap format")]
|
||||
UnknownType,
|
||||
|
||||
#[error("Invalid ZLIB compression")]
|
||||
InvalidZlibCompression,
|
||||
|
||||
#[error("Invalid JPEG")]
|
||||
InvalidJpeg(#[from] jpeg_decoder::Error),
|
||||
|
||||
#[error("Invalid PNG")]
|
||||
InvalidPng(#[from] png::DecodingError),
|
||||
|
||||
#[error("Invalid GIF")]
|
||||
InvalidGif(#[from] gif::DecodingError),
|
||||
|
||||
#[error("Empty GIF")]
|
||||
EmptyGif,
|
||||
|
||||
#[error("Unsupported DefineBitsLossless{0} format {1:?}")]
|
||||
UnsupportedLosslessFormat(u8, swf::BitmapFormat),
|
||||
|
||||
#[cfg(feature = "web")]
|
||||
#[error("Javascript error")]
|
||||
JavascriptError(wasm_bindgen::JsValue),
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ pub fn decode_define_bits_jpeg(data: &[u8], alpha_data: Option<&[u8]>) -> Result
|
|||
JpegTagFormat::Jpeg => decode_jpeg(data, alpha_data),
|
||||
JpegTagFormat::Png => decode_png(data),
|
||||
JpegTagFormat::Gif => decode_gif(data),
|
||||
JpegTagFormat::Unknown => Err("Unknown bitmap data format".into()),
|
||||
JpegTagFormat::Unknown => Err(Error::UnknownType),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,15 +87,14 @@ pub fn remove_invalid_jpeg_data(mut data: &[u8]) -> Cow<[u8]> {
|
|||
|
||||
/// Decodes a JPEG with optional alpha data.
|
||||
/// The decoded bitmap will have pre-multiplied alpha.
|
||||
fn decode_jpeg(
|
||||
jpeg_data: &[u8],
|
||||
alpha_data: Option<&[u8]>,
|
||||
) -> Result<Bitmap, Box<dyn std::error::Error>> {
|
||||
fn decode_jpeg(jpeg_data: &[u8], alpha_data: Option<&[u8]>) -> Result<Bitmap, Error> {
|
||||
let jpeg_data = remove_invalid_jpeg_data(jpeg_data);
|
||||
|
||||
let mut decoder = jpeg_decoder::Decoder::new(&jpeg_data[..]);
|
||||
decoder.read_info()?;
|
||||
let metadata = decoder.info().ok_or("Unable to get image info")?;
|
||||
let metadata = decoder
|
||||
.info()
|
||||
.expect("info() should always return Some if read_info returned Ok");
|
||||
let decoded_data = decoder.decode()?;
|
||||
|
||||
let decoded_data = match metadata.pixel_format {
|
||||
|
@ -174,9 +173,7 @@ fn decode_jpeg(
|
|||
/// Decodes the bitmap data in DefineBitsLossless tag into RGBA.
|
||||
/// DefineBitsLossless is Zlib encoded pixel data (similar to PNG), possibly
|
||||
/// palletized.
|
||||
pub fn decode_define_bits_lossless(
|
||||
swf_tag: &swf::DefineBitsLossless,
|
||||
) -> Result<Bitmap, Box<dyn std::error::Error>> {
|
||||
pub fn decode_define_bits_lossless(swf_tag: &swf::DefineBitsLossless) -> Result<Bitmap, Error> {
|
||||
// Decompress the image data (DEFLATE compression).
|
||||
let mut decoded_data = decompress_zlib(swf_tag.data)?;
|
||||
|
||||
|
@ -302,11 +299,10 @@ pub fn decode_define_bits_lossless(
|
|||
out_data
|
||||
}
|
||||
_ => {
|
||||
return Err(format!(
|
||||
"Unexpected DefineBitsLossless{} format: {:?} ",
|
||||
swf_tag.version, swf_tag.format,
|
||||
)
|
||||
.into());
|
||||
return Err(Error::UnsupportedLosslessFormat(
|
||||
swf_tag.version,
|
||||
swf_tag.format,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -374,7 +370,7 @@ fn decode_gif(data: &[u8]) -> Result<Bitmap, Error> {
|
|||
let mut decode_options = gif::DecodeOptions::new();
|
||||
decode_options.set_color_output(gif::ColorOutput::RGBA);
|
||||
let mut reader = decode_options.read_info(data)?;
|
||||
let frame = reader.read_next_frame()?.ok_or("No frames in GIF")?;
|
||||
let frame = reader.read_next_frame()?.ok_or(Error::EmptyGif)?;
|
||||
// GIFs embedded in a DefineBitsJPEG tag will not have premultiplied alpha and need to be converted before sending to the renderer.
|
||||
let mut data = frame.buffer.to_vec();
|
||||
premultiply_alpha_rgba(&mut data);
|
||||
|
@ -411,10 +407,12 @@ pub fn unmultiply_alpha_rgba(rgba: &mut [u8]) {
|
|||
}
|
||||
|
||||
/// Decodes zlib-compressed data.
|
||||
fn decompress_zlib(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
|
||||
fn decompress_zlib(data: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
let mut out_data = Vec::new();
|
||||
let mut decoder = flate2::bufread::ZlibDecoder::new(data);
|
||||
decoder.read_to_end(&mut out_data)?;
|
||||
decoder
|
||||
.read_to_end(&mut out_data)
|
||||
.map_err(|_| Error::InvalidZlibCompression)?;
|
||||
out_data.shrink_to_fit();
|
||||
Ok(out_data)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
|
|||
js-sys = "0.3.59"
|
||||
log = "0.4"
|
||||
ruffle_web_common = { path = "../../web/common" }
|
||||
ruffle_render = { path = "..", features = ["tessellator"] }
|
||||
ruffle_render = { path = "..", features = ["tessellator", "web"] }
|
||||
wasm-bindgen = "=0.2.82"
|
||||
bytemuck = { version = "1.12.1", features = ["derive"] }
|
||||
fnv = "1.0.7"
|
||||
|
|
|
@ -3,6 +3,7 @@ use fnv::FnvHashMap;
|
|||
use ruffle_render::backend::null::NullBitmapSource;
|
||||
use ruffle_render::backend::{RenderBackend, ShapeHandle, ViewportDimensions};
|
||||
use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle, BitmapSource};
|
||||
use ruffle_render::error::Error as BitmapError;
|
||||
use ruffle_render::shape_utils::DistilledShape;
|
||||
use ruffle_render::tessellator::{
|
||||
Gradient as TessGradient, GradientType, ShapeTessellator, Vertex as TessVertex,
|
||||
|
@ -1242,7 +1243,7 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
self.bitmap_registry.get(&bitmap).map(|e| e.bitmap.clone())
|
||||
}
|
||||
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, BitmapError> {
|
||||
let format = match bitmap.format() {
|
||||
BitmapFormat::Rgb => Gl::RGB,
|
||||
BitmapFormat::Rgba => Gl::RGBA,
|
||||
|
@ -1262,7 +1263,8 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
Gl::UNSIGNED_BYTE,
|
||||
Some(bitmap.data()),
|
||||
)
|
||||
.into_js_result()?;
|
||||
.into_js_result()
|
||||
.map_err(|e| BitmapError::JavascriptError(e.into()))?;
|
||||
|
||||
// You must set the texture parameters for non-power-of-2 textures to function in WebGL1.
|
||||
self.gl
|
||||
|
@ -1293,7 +1295,7 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), Error> {
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), BitmapError> {
|
||||
self.bitmap_registry.remove(&bitmap);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1304,11 +1306,12 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
width: u32,
|
||||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<BitmapHandle, Error> {
|
||||
) -> Result<BitmapHandle, BitmapError> {
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||
&entry.texture_wrapper
|
||||
} else {
|
||||
return Err("update_texture: Bitmap is not regsitered".into());
|
||||
log::warn!("Tried to replace nonexistent texture");
|
||||
return Ok(handle);
|
||||
};
|
||||
|
||||
self.gl.bind_texture(Gl::TEXTURE_2D, Some(&texture.texture));
|
||||
|
@ -1325,7 +1328,8 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
Gl::UNSIGNED_BYTE,
|
||||
Some(&rgba),
|
||||
)
|
||||
.into_js_result()?;
|
||||
.into_js_result()
|
||||
.map_err(|e| BitmapError::JavascriptError(e.into()))?;
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use fnv::FnvHashMap;
|
|||
use ruffle_render::backend::{RenderBackend, ShapeHandle, ViewportDimensions};
|
||||
use ruffle_render::bitmap::{Bitmap, BitmapHandle, BitmapSource};
|
||||
use ruffle_render::color_transform::ColorTransform;
|
||||
use ruffle_render::error::Error as BitmapError;
|
||||
use ruffle_render::shape_utils::DistilledShape;
|
||||
use ruffle_render::tessellator::{
|
||||
DrawType as TessDrawType, Gradient as TessGradient, GradientType, ShapeTessellator,
|
||||
|
@ -1415,17 +1416,11 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
self.bitmap_registry.get(&bitmap).map(|e| e.bitmap.clone())
|
||||
}
|
||||
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, BitmapError> {
|
||||
if bitmap.width() > self.descriptors.limits.max_texture_dimension_2d
|
||||
|| bitmap.height() > self.descriptors.limits.max_texture_dimension_2d
|
||||
{
|
||||
return Err(format!(
|
||||
"Bitmap texture cannot be larger than {}px on either dimension (requested {} x {})",
|
||||
self.descriptors.limits.max_texture_dimension_2d,
|
||||
bitmap.width(),
|
||||
bitmap.height()
|
||||
)
|
||||
.into());
|
||||
return Err(BitmapError::TooLarge);
|
||||
}
|
||||
|
||||
let bitmap = bitmap.to_rgba();
|
||||
|
@ -1512,7 +1507,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, handle: BitmapHandle) -> Result<(), Error> {
|
||||
fn unregister_bitmap(&mut self, handle: BitmapHandle) -> Result<(), BitmapError> {
|
||||
self.bitmap_registry.remove(&handle);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1523,11 +1518,12 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
width: u32,
|
||||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<BitmapHandle, Error> {
|
||||
) -> Result<BitmapHandle, BitmapError> {
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||
&entry.texture_wrapper.texture
|
||||
} else {
|
||||
return Err("update_texture: Bitmap not registered".into());
|
||||
log::warn!("Tried to replace nonexistent texture");
|
||||
return Ok(handle);
|
||||
};
|
||||
|
||||
let extent = wgpu::Extent3d {
|
||||
|
|
|
@ -14,6 +14,12 @@ impl std::fmt::Display for JsError {
|
|||
|
||||
impl std::error::Error for JsError {}
|
||||
|
||||
impl From<JsError> for JsValue {
|
||||
fn from(error: JsError) -> Self {
|
||||
error.value
|
||||
}
|
||||
}
|
||||
|
||||
pub trait JsResult<T> {
|
||||
/// Converts a `JsValue` into a standard `Error`.
|
||||
fn warn_on_error(&self);
|
||||
|
|
Loading…
Reference in New Issue