[librsvg: 8/9] feImage: detect circular references now that primitives are resolved early
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 8/9] feImage: detect circular references now that primitives are resolved early
- Date: Tue, 27 Apr 2021 17:54:46 +0000 (UTC)
commit 098d3e84457e072a636caec5fdf049811aaa9655
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Apr 21 19:29:29 2021 -0500
feImage: detect circular references now that primitives are resolved early
This introduces a `Source` enum, where the interesting cases are these
for feImage:
enum Source {
Node(Node),
ExternalImage(String),
}
In the `Node` case, we later use that node for
`acquired_nodes.acquire_ref()` while rendering the feImage. This
makes it possible to catch circular references when there is a a
feImage that references a node, that references a filter, that
references the same node.
src/filters/image.rs | 73 +++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 55 insertions(+), 18 deletions(-)
---
diff --git a/src/filters/image.rs b/src/filters/image.rs
index 9c677e24..c9ffac3c 100644
--- a/src/filters/image.rs
+++ b/src/filters/image.rs
@@ -26,18 +26,31 @@ pub struct FeImage {
params: ImageParams,
}
-/// Resolved `feImage` primitive for rendering.
#[derive(Clone, Default)]
struct ImageParams {
aspect: AspectRatio,
href: Option<String>,
}
+/// Resolved `feImage` primitive for rendering.
pub struct Image {
- params: ImageParams,
+ aspect: AspectRatio,
+ source: Source,
feimage_values: ComputedValues,
}
+/// What a feImage references for rendering.
+enum Source {
+ /// Nothing is referenced; ignore the filter.
+ None,
+
+ /// Reference to a node.
+ Node(Node),
+
+ /// Reference to an external image. This is just a URL.
+ ExternalImage(String),
+}
+
impl Image {
/// Renders the filter if the source is an existing node.
fn render_node(
@@ -46,13 +59,8 @@ impl Image {
acquired_nodes: &mut AcquiredNodes<'_>,
draw_ctx: &mut DrawingCtx,
bounds: Rect,
- node_id: &NodeId,
+ referenced_node: &Node,
) -> Result<SharedImageSurface, FilterError> {
- let acquired = acquired_nodes
- .acquire(node_id)
- .map_err(|_| FilterError::InvalidInput)?;
- let referenced_node = acquired.get();
-
// https://www.w3.org/TR/filter-effects/#feImageElement
//
// The filters spec says, "... otherwise [rendering a referenced object], the
@@ -89,7 +97,7 @@ impl Image {
.lookup_image(url)
.map_err(|_| FilterError::InvalidInput)?;
- let rect = self.params.aspect.compute(
+ let rect = self.aspect.compute(
&ViewBox::from(Rect::from_size(
f64::from(image.width()),
f64::from(image.height()),
@@ -138,14 +146,27 @@ impl Image {
) -> Result<FilterOutput, FilterError> {
let bounds = bounds_builder.compute(ctx);
- let href = self.params.href.as_ref().ok_or(FilterError::InvalidInput)?;
+ let surface = match &self.source {
+ Source::None => return Err(FilterError::InvalidInput),
+
+ Source::Node(node) => {
+ if let Ok(acquired) = acquired_nodes.acquire_ref(node) {
+ self.render_node(
+ ctx,
+ acquired_nodes,
+ draw_ctx,
+ bounds.clipped,
+ &acquired.get(),
+ )?
+ } else {
+ return Err(FilterError::InvalidInput);
+ }
+ }
- let surface = if let Ok(node_id) = NodeId::parse(href) {
- // if href has a fragment specified, render as a node
- self.render_node(ctx, acquired_nodes, draw_ctx, bounds.clipped, &node_id)
- } else {
- self.render_external_image(ctx, acquired_nodes, draw_ctx, &bounds, href)
- }?;
+ Source::ExternalImage(ref href) => {
+ self.render_external_image(ctx, acquired_nodes, draw_ctx, &bounds, href)?
+ }
+ };
Ok(FilterOutput {
surface,
@@ -157,16 +178,32 @@ impl Image {
impl FilterEffect for FeImage {
fn resolve(
&self,
- _acquired_nodes: &mut AcquiredNodes<'_>,
+ acquired_nodes: &mut AcquiredNodes<'_>,
node: &Node,
) -> Result<ResolvedPrimitive, FilterResolveError> {
let cascaded = CascadedValues::new_from_node(node);
let feimage_values = cascaded.get().clone();
+ let source = match self.params.href {
+ None => Source::None,
+
+ Some(ref s) => {
+ if let Ok(node_id) = NodeId::parse(s) {
+ acquired_nodes
+ .acquire(&node_id)
+ .map(|acquired| Source::Node(acquired.get().clone()))
+ .unwrap_or(Source::None)
+ } else {
+ Source::ExternalImage(s.to_string())
+ }
+ }
+ };
+
Ok(ResolvedPrimitive {
primitive: self.base.clone(),
params: PrimitiveParams::Image(Image {
- params: self.params.clone(),
+ aspect: self.params.aspect,
+ source,
feimage_values,
}),
})
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]