diff options
author | Marge Bot <marge-bot@gnome.org> | 2023-01-25 03:26:46 +0000 |
---|---|---|
committer | Marge Bot <marge-bot@gnome.org> | 2023-01-25 03:26:46 +0000 |
commit | 3b93fce5929a83bc23cc652570d9f0478b0fd9e8 (patch) | |
tree | 1a06661739d2da36750f8f946b47a16e82099b73 | |
parent | 7a682574f19d9a7f4d7fcd876c8383a1fa203f04 (diff) | |
parent | 722728cebc7eb4c13806eea4044a051e84fb826e (diff) | |
download | librsvg-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.rs | 3 | ||||
-rw-r--r-- | src/filters/mod.rs | 12 | ||||
-rw-r--r-- | src/filters/offset.rs | 1 | ||||
-rw-r--r-- | src/filters/tile.rs | 30 | ||||
-rw-r--r-- | src/surface_utils/shared_surface.rs | 8 | ||||
-rw-r--r-- | tests/fixtures/render-crash/bug928-empty-feTile-bounds.svg | 12 | ||||
-rw-r--r-- | tests/src/render_crash.rs | 1 |
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"); |