[librsvg: 28/30] filters: do not use BoundingBox to calculate filter bounds
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 28/30] filters: do not use BoundingBox to calculate filter bounds
- Date: Mon, 28 Dec 2020 20:06:30 +0000 (UTC)
commit e75f40b15a00a33e0dbfc335227629d258c06605
Author: Paolo Borelli <pborelli gnome org>
Date: Mon Dec 28 15:03:23 2020 +0100
filters: do not use BoundingBox to calculate filter bounds
We are building a plain rect, so stick with Rect instead of going
through the BoundingBox abstraction. This makes code easier to
follow and even makes it shorter.
I left a FIXME about inversibility of the transform, but not that
the same panic would already be present also in the bbox code.
src/filters/bounds.rs | 68 +++++++++++++++++++++-----------------------------
src/filters/context.rs | 14 +++++------
2 files changed, 34 insertions(+), 48 deletions(-)
---
diff --git a/src/filters/bounds.rs b/src/filters/bounds.rs
index 0f56bdcb..3f0bb58b 100644
--- a/src/filters/bounds.rs
+++ b/src/filters/bounds.rs
@@ -1,8 +1,8 @@
//! Filter primitive subregion computation.
-use crate::bbox::BoundingBox;
use crate::drawing_ctx::DrawingCtx;
use crate::length::*;
use crate::rect::{IRect, Rect};
+use crate::transform::Transform;
use super::context::{FilterContext, FilterInput};
@@ -12,8 +12,14 @@ pub struct BoundsBuilder<'a> {
/// The filter context.
ctx: &'a FilterContext,
- /// The current bounding box.
- bbox: BoundingBox,
+ /// The transform to use when generating the rect
+ transform: Transform,
+
+ /// The inverse transform used when adding rects
+ inverse: Transform,
+
+ /// The current bounding rectangle.
+ rect: Option<Rect>,
/// Whether one of the input nodes is standard input.
standard_input_was_referenced: bool,
@@ -35,10 +41,12 @@ impl<'a> BoundsBuilder<'a> {
width: Option<ULength<Horizontal>>,
height: Option<ULength<Vertical>>,
) -> Self {
+ // FIXME: we panic if paffine is not invertible... do we need to check here?
Self {
ctx,
- // The transform is paffine because we're using that fact in apply_properties().
- bbox: BoundingBox::new().with_transform(ctx.paffine()),
+ transform: ctx.paffine(),
+ inverse: ctx.paffine().invert().unwrap(),
+ rect: None,
standard_input_was_referenced: false,
x,
y,
@@ -51,8 +59,7 @@ impl<'a> BoundsBuilder<'a> {
#[inline]
pub fn add_input(mut self, input: &FilterInput) -> Self {
// If a standard input was referenced, the default value is the filter effects region
- // regardless of other referenced inputs. This means we can skip computing the bounding
- // box.
+ // regardless of other referenced inputs. This means we can skip computing the bounds.
if self.standard_input_was_referenced {
return self;
}
@@ -62,8 +69,8 @@ impl<'a> BoundsBuilder<'a> {
self.standard_input_was_referenced = true;
}
FilterInput::PrimitiveOutput(ref output) => {
- let input_bbox = BoundingBox::new().with_rect(output.bounds.into());
- self.bbox.insert(&input_bbox);
+ let input_rect = self.inverse.transform_rect(&Rect::from(output.bounds));
+ self.rect = Some(self.rect.map_or(input_rect, |r| input_rect.union(&r)));
}
}
@@ -72,12 +79,9 @@ impl<'a> BoundsBuilder<'a> {
/// Returns the final exact bounds.
pub fn into_rect(self, draw_ctx: &mut DrawingCtx) -> Rect {
- let mut bbox = self.apply_properties(draw_ctx);
-
- let effects_region = self.ctx.effects_region();
- bbox.clip(&effects_region);
-
- bbox.rect.unwrap()
+ self.into_rect_without_clipping(draw_ctx)
+ .intersection(&self.ctx.effects_region())
+ .unwrap_or_else(Rect::default)
}
/// Returns the final pixel bounds.
@@ -85,35 +89,21 @@ impl<'a> BoundsBuilder<'a> {
self.into_rect(draw_ctx).into()
}
- /// Returns the final pixel bounds without clipping to the filter effects region.
- ///
- /// Used by feImage.
+ /// Returns the final exact bounds without clipping to the filter effects region.
pub fn into_rect_without_clipping(self, draw_ctx: &mut DrawingCtx) -> Rect {
- self.apply_properties(draw_ctx).rect.unwrap()
- }
-
- /// Applies the filter primitive properties.
- fn apply_properties(mut self, draw_ctx: &mut DrawingCtx) -> BoundingBox {
- if self.bbox.rect.is_none() || self.standard_input_was_referenced {
- // The default value is the filter effects region.
- let effects_region = self.ctx.effects_region();
-
- // Clear out the rect.
- self.bbox.clear();
-
- // Convert into the paffine coordinate system.
- self.bbox.insert(&effects_region);
- }
+ // The default value is the filter effects region converted into
+ // the paffine coordinate system.
+ let mut rect = match self.rect {
+ Some(r) if !self.standard_input_was_referenced => r,
+ _ => self.inverse.transform_rect(&self.ctx.effects_region()),
+ };
// If any of the properties were specified, we need to respect them.
+ // These replacements are possible because of the paffince coordinate system.
if self.x.is_some() || self.y.is_some() || self.width.is_some() || self.height.is_some() {
let params = draw_ctx.push_coord_units(self.ctx.primitive_units());
let values = self.ctx.get_computed_values_from_node_being_filtered();
- // These replacements are correct only because self.bbox is used with the
- // paffine transform.
- let rect = self.bbox.rect.as_mut().unwrap();
-
if let Some(x) = self.x {
let w = rect.width();
rect.x0 = x.normalize(values, ¶ms);
@@ -133,8 +123,6 @@ impl<'a> BoundsBuilder<'a> {
}
// Convert into the surface coordinate system.
- let mut bbox = BoundingBox::new();
- bbox.insert(&self.bbox);
- bbox
+ self.transform.transform_rect(&rect)
}
}
diff --git a/src/filters/context.rs b/src/filters/context.rs
index d83eee46..fec42c84 100644
--- a/src/filters/context.rs
+++ b/src/filters/context.rs
@@ -62,7 +62,7 @@ pub struct FilterContext {
/// Primtive units
primitive_units: CoordUnits,
/// The filter effects region.
- effects_region: BoundingBox,
+ effects_region: Rect,
/// Whether the currently rendered filter primitive uses linear RGB for color operations.
///
/// This affects `get_input()` and `store_result()` which should perform linearization and
@@ -153,7 +153,7 @@ impl FilterContext {
let other_bbox = BoundingBox::new().with_rect(rect);
bbox.clip(&other_bbox);
- bbox
+ bbox.rect.unwrap()
};
Self {
@@ -260,7 +260,7 @@ impl FilterContext {
/// Returns the filter effects region.
#[inline]
- pub fn effects_region(&self) -> BoundingBox {
+ pub fn effects_region(&self) -> Rect {
self.effects_region
}
@@ -291,7 +291,7 @@ impl FilterContext {
Input::SourceAlpha => self
.source_graphic()
- .extract_alpha(self.effects_region().rect.unwrap().into())
+ .extract_alpha(self.effects_region().into())
.map_err(FilterError::CairoError)
.map(FilterInput::StandardInput),
@@ -303,7 +303,7 @@ impl FilterContext {
.background_image(draw_ctx)
.and_then(|surface| {
surface
- .extract_alpha(self.effects_region().rect.unwrap().into())
+ .extract_alpha(self.effects_region().into())
.map_err(FilterError::CairoError)
})
.map(FilterInput::StandardInput),
@@ -356,9 +356,7 @@ impl FilterContext {
// Convert the input surface to the desired format.
let (surface, bounds) = match raw {
- FilterInput::StandardInput(ref surface) => {
- (surface, self.effects_region().rect.unwrap().into())
- }
+ FilterInput::StandardInput(ref surface) => (surface, self.effects_region().into()),
FilterInput::PrimitiveOutput(FilterOutput {
ref surface,
ref bounds,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]