summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarge Bot <marge-bot@gnome.org>2023-01-25 03:26:46 +0000
committerMarge Bot <marge-bot@gnome.org>2023-01-25 03:26:46 +0000
commit3b93fce5929a83bc23cc652570d9f0478b0fd9e8 (patch)
tree1a06661739d2da36750f8f946b47a16e82099b73
parent7a682574f19d9a7f4d7fcd876c8383a1fa203f04 (diff)
parent722728cebc7eb4c13806eea4044a051e84fb826e (diff)
downloadlibrsvg-3b93fce5929a83bc23cc652570d9f0478b0fd9e8.tar.gz
Merge branch 'empty-filter-bounds' into 'main'
Fix panic when feTile gets an empty source region Closes #928 See merge request GNOME/librsvg!787
-rw-r--r--src/filters/flood.rs3
-rw-r--r--src/filters/mod.rs12
-rw-r--r--src/filters/offset.rs1
-rw-r--r--src/filters/tile.rs30
-rw-r--r--src/surface_utils/shared_surface.rs8
-rw-r--r--tests/fixtures/render-crash/bug928-empty-feTile-bounds.svg12
-rw-r--r--tests/src/render_crash.rs1
7 files changed, 59 insertions, 8 deletions
diff --git a/src/filters/flood.rs b/src/filters/flood.rs
index a3f06422..50838207 100644
--- a/src/filters/flood.rs
+++ b/src/filters/flood.rs
@@ -36,9 +36,10 @@ impl Flood {
bounds_builder: BoundsBuilder,
ctx: &FilterContext,
_acquired_nodes: &mut AcquiredNodes<'_>,
- _draw_ctx: &mut DrawingCtx,
+ draw_ctx: &mut DrawingCtx,
) -> Result<FilterOutput, FilterError> {
let bounds: IRect = bounds_builder.compute(ctx).clipped.into();
+ rsvg_log!(draw_ctx.session(), "(feFlood bounds={:?}", bounds);
let surface = ctx.source_graphic().flood(bounds, self.color)?;
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
index c2ec8168..0bd1cefa 100644
--- a/src/filters/mod.rs
+++ b/src/filters/mod.rs
@@ -272,6 +272,12 @@ pub fn render(
node_bbox,
)
.and_then(|mut filter_ctx| {
+ // the message has an unclosed parenthesis; we'll close it below.
+ rsvg_log!(
+ session,
+ "(rendering filter with effects_region={:?}",
+ filter_ctx.effects_region()
+ );
for user_space_primitive in &filter.primitives {
let start = Instant::now();
@@ -299,6 +305,9 @@ pub fn render(
err
);
+ // close the opening parenthesis from the message at the start of this function
+ rsvg_log!(session, ")");
+
// Exit early on Cairo errors. Continue rendering otherwise.
if let FilterError::CairoError(status) = err {
return Err(FilterError::CairoError(status));
@@ -307,6 +316,9 @@ pub fn render(
}
}
+ // close the opening parenthesis from the message at the start of this function
+ rsvg_log!(session, ")");
+
Ok(filter_ctx.into_output()?)
})
.or_else(|err| match err {
diff --git a/src/filters/offset.rs b/src/filters/offset.rs
index acdbab1a..27698b05 100644
--- a/src/filters/offset.rs
+++ b/src/filters/offset.rs
@@ -76,6 +76,7 @@ impl Offset {
.compute(ctx)
.clipped
.into();
+ rsvg_log!(draw_ctx.session(), "(feOffset bounds={:?}", bounds);
let (dx, dy) = ctx.paffine().transform_distance(self.dx, self.dy);
diff --git a/src/filters/tile.rs b/src/filters/tile.rs
index 0bd4417c..e3bf940a 100644
--- a/src/filters/tile.rs
+++ b/src/filters/tile.rs
@@ -64,14 +64,30 @@ impl Tile {
surface: input_surface,
bounds: input_bounds,
}) => {
- let tile_surface = input_surface.tile(input_bounds)?;
+ if input_bounds.is_empty() {
+ rsvg_log!(
+ draw_ctx.session(),
+ "(feTile with empty input_bounds; returning just the input surface)"
+ );
- ctx.source_graphic().paint_image_tiled(
- bounds,
- &tile_surface,
- input_bounds.x0,
- input_bounds.y0,
- )?
+ input_surface
+ } else {
+ rsvg_log!(
+ draw_ctx.session(),
+ "(feTile bounds={:?}, input_bounds={:?})",
+ bounds,
+ input_bounds
+ );
+
+ let tile_surface = input_surface.tile(input_bounds)?;
+
+ ctx.source_graphic().paint_image_tiled(
+ bounds,
+ &tile_surface,
+ input_bounds.x0,
+ input_bounds.y0,
+ )?
+ }
}
};
diff --git a/src/surface_utils/shared_surface.rs b/src/surface_utils/shared_surface.rs
index 0bd74353..4fdd66c2 100644
--- a/src/surface_utils/shared_surface.rs
+++ b/src/surface_utils/shared_surface.rs
@@ -1079,8 +1079,16 @@ impl ImageSurface<Shared> {
}
/// Creates a new surface with the size and content specified in `bounds`
+ ///
+ /// # Panics
+ /// Panics if `bounds` is an empty rectangle, since `SharedImageSurface` cannot
+ /// represent zero-sized images.
#[inline]
pub fn tile(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Error> {
+ // Cairo lets us create zero-sized surfaces, but the call to SharedImageSurface::wrap()
+ // below will panic in that case. So, disallow requesting a zero-sized subregion.
+ assert!(!bounds.is_empty());
+
let output_surface =
cairo::ImageSurface::create(cairo::Format::ARgb32, bounds.width(), bounds.height())?;
diff --git a/tests/fixtures/render-crash/bug928-empty-feTile-bounds.svg b/tests/fixtures/render-crash/bug928-empty-feTile-bounds.svg
new file mode 100644
index 00000000..9920080f
--- /dev/null
+++ b/tests/fixtures/render-crash/bug928-empty-feTile-bounds.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+ <filter id="filter">
+ <!-- We want to test that feTile gets an empty input region, since
+ the feFlood's bounds are outside the default filter effects
+ region.
+ -->
+ <feFlood flood-color="lime" x="50" y="50" width="10" height="10"/>
+ <feTile/>
+ </filter>
+
+ <rect x="10" y="10" width="10" height="10" filter="url(#filter)"/>
+</svg>
diff --git a/tests/src/render_crash.rs b/tests/src/render_crash.rs
index 311aa38d..da58192a 100644
--- a/tests/src/render_crash.rs
+++ b/tests/src/render_crash.rs
@@ -62,6 +62,7 @@ mod tests {
t!(bug721_pattern_cycle_from_child_svg, "bug721-pattern-cycle-from-child.svg");
t!(bug721_pattern_cycle_from_other_child_svg, "bug721-pattern-cycle-from-other-child.svg");
t!(bug777155_zero_sized_pattern_svg, "bug777155-zero-sized-pattern.svg");
+ t!(bug928_empty_fetile_bounds_svg, "bug928-empty-feTile-bounds.svg");
t!(femerge_color_interpolation_srgb_svg, "feMerge-color-interpolation-srgb.svg");
t!(filters_non_invertible_paffine_svg, "filters-non-invertible-paffine.svg");
t!(gradient_with_empty_bbox_svg, "gradient-with-empty-bbox.svg");