[librsvg: 1/15] FilterContext: validate the transforms at creation time
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/15] FilterContext: validate the transforms at creation time
- Date: Thu, 8 Apr 2021 22:52:27 +0000 (UTC)
commit 9ae570c8b6d28e4da30752a42dddac4b2c808847
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Apr 7 17:29:59 2021 -0500
FilterContext: validate the transforms at creation time
This will let us assume that the transforms are valid in the rest of
the code.
src/filters/context.rs | 16 ++++---
src/filters/mod.rs | 115 +++++++++++++++++++++++++------------------------
2 files changed, 69 insertions(+), 62 deletions(-)
---
diff --git a/src/filters/context.rs b/src/filters/context.rs
index 54c38671..398e0565 100644
--- a/src/filters/context.rs
+++ b/src/filters/context.rs
@@ -107,11 +107,11 @@ impl FilterContext {
computed_from_node_being_filtered: &ComputedValues,
stroke_paint: UserSpacePaintSource,
fill_paint: UserSpacePaintSource,
- source_surface: SharedImageSurface,
+ source_surface: &SharedImageSurface,
draw_ctx: &mut DrawingCtx,
draw_transform: Transform,
node_bbox: BoundingBox,
- ) -> Self {
+ ) -> Result<Self, FilterError> {
// The rect can be empty (for example, if the filter is applied to an empty group).
// However, with userSpaceOnUse it's still possible to create images with a filter.
let bbox_rect = node_bbox.rect.unwrap_or_default();
@@ -144,6 +144,12 @@ impl FilterContext {
.post_transform(&draw_transform),
};
+ if !(affine.is_invertible() && paffine.is_invertible()) {
+ return Err(FilterError::InvalidParameter(
+ "transform is not invertible".to_string(),
+ ));
+ }
+
let effects_region = {
let params = draw_ctx.push_coord_units(filter_units);
let filter_rect = filter.get_rect(&computed_from_node_being_filtered, ¶ms);
@@ -166,11 +172,11 @@ impl FilterContext {
bbox.rect.unwrap()
};
- Self {
+ Ok(Self {
computed_from_node_being_filtered: computed_from_node_being_filtered.clone(),
stroke_paint,
fill_paint,
- source_surface,
+ source_surface: source_surface.clone(),
last_result: None,
previous_results: HashMap::new(),
background_surface: OnceCell::new(),
@@ -180,7 +186,7 @@ impl FilterContext {
effects_region,
_affine: affine,
paffine,
- }
+ })
}
/// Returns the computed values from the node that referenced this filter.
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
index ba8a6f5d..6efa7fc5 100644
--- a/src/filters/mod.rs
+++ b/src/filters/mod.rs
@@ -254,75 +254,76 @@ pub fn render(
.resolve(acquired_nodes, values.fill_opacity().0, values.color().0)?
.to_user_space(&node_bbox, draw_ctx, values);
- let mut filter_ctx = FilterContext::new(
+ if let Ok(mut filter_ctx) = FilterContext::new(
&filter,
computed_from_node_being_filtered,
stroke_paint_source,
fill_paint_source,
- source_surface,
+ &source_surface,
draw_ctx,
transform,
node_bbox,
- );
-
- // If paffine is non-invertible, we won't draw anything. Also bbox combining in bounds
- // computations will panic due to non-invertible martrix.
- if !filter_ctx.paffine().is_invertible() {
- return Ok(filter_ctx.into_output()?);
- }
-
- let primitives = filter_node
- .children()
- .filter(|c| c.is_element())
- // Skip nodes in error.
- .filter(|c| {
- let in_error = c.borrow_element().is_in_error();
-
- if in_error {
- rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
- }
-
- !in_error
- })
- // Keep only filter primitives (those that implement the Filter trait)
- .filter(|c| c.borrow_element().as_filter_effect().is_some());
-
- for c in primitives {
- let elt = c.borrow_element();
- let filter = elt.as_filter_effect().unwrap();
-
- let start = Instant::now();
-
- if let Err(err) = filter
- .resolve(&c)
- .and_then(|(primitive, params)| {
- render_primitive(
- &primitive.resolve(),
- ¶ms,
- &filter_ctx,
- acquired_nodes,
- draw_ctx,
- )
+ ) {
+ let primitives = filter_node
+ .children()
+ .filter(|c| c.is_element())
+ // Skip nodes in error.
+ .filter(|c| {
+ let in_error = c.borrow_element().is_in_error();
+
+ if in_error {
+ rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
+ }
+
+ !in_error
})
- .and_then(|result| filter_ctx.store_result(result))
- {
- rsvg_log!("(filter primitive {} returned an error: {})", c, err);
-
- // Exit early on Cairo errors. Continue rendering otherwise.
- if let FilterError::CairoError(status) = err {
- return Err(RenderingError::from(status));
+ // Keep only filter primitives (those that implement the Filter trait)
+ .filter(|c| c.borrow_element().as_filter_effect().is_some());
+
+ for c in primitives {
+ let elt = c.borrow_element();
+ let filter = elt.as_filter_effect().unwrap();
+
+ let start = Instant::now();
+
+ if let Err(err) = filter
+ .resolve(&c)
+ .and_then(|(primitive, params)| {
+ render_primitive(
+ &primitive.resolve(),
+ ¶ms,
+ &filter_ctx,
+ acquired_nodes,
+ draw_ctx,
+ )
+ })
+ .and_then(|result| filter_ctx.store_result(result))
+ {
+ rsvg_log!("(filter primitive {} returned an error: {})", c, err);
+
+ // Exit early on Cairo errors. Continue rendering otherwise.
+ if let FilterError::CairoError(status) = err {
+ return Err(RenderingError::from(status));
+ }
}
+
+ let elapsed = start.elapsed();
+ rsvg_log!(
+ "(rendered filter primitive {} in\n {} seconds)",
+ c,
+ elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
+ );
}
- let elapsed = start.elapsed();
- rsvg_log!(
- "(rendered filter primitive {} in\n {} seconds)",
- c,
- elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
- );
+ Ok(filter_ctx.into_output()?)
+ } else {
+ // Ignore errors that happened when creating the FilterContext
+ Ok(SharedImageSurface::empty(
+ source_surface.width(),
+ source_surface.height(),
+ SurfaceType::AlphaOnly,
+ )?)
}
-
- Ok(filter_ctx.into_output()?)
}
#[rustfmt::skip]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]