[librsvg: 1/3] filters: move cairo code out of the image filter
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/3] filters: move cairo code out of the image filter
- Date: Thu, 9 Jan 2020 20:01:18 +0000 (UTC)
commit 11f3c2d12a7fbae5c916e20d009b4a305c45686a
Author: Paolo Borelli <pborelli gnome org>
Date: Tue Jan 7 17:00:40 2020 +0100
filters: move cairo code out of the image filter
Factor out a paint_image method on SharedImageSurface
rsvg_internals/src/drawing_ctx.rs | 26 ++--
rsvg_internals/src/filters/error.rs | 15 +++
rsvg_internals/src/filters/image.rs | 141 ++++++---------------
rsvg_internals/src/surface_utils/shared_surface.rs | 42 +++++-
4 files changed, 112 insertions(+), 112 deletions(-)
---
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index fd2d7881..0a17833b 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -935,30 +935,34 @@ impl DrawingCtx {
.map_err(|_| RenderingError::InvalidHref)
}
- pub fn draw_node_on_surface(
+ pub fn draw_node_to_surface(
&mut self,
node: &RsvgNode,
cascaded: &CascadedValues<'_>,
- surface: &cairo::ImageSurface,
affine: cairo::Matrix,
- width: f64,
- height: f64,
- ) -> Result<BoundingBox, RenderingError> {
+ width: i32,
+ height: i32,
+ ) -> Result<SharedImageSurface, RenderingError> {
+ let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;
+
let save_cr = self.cr.clone();
let save_rect = self.rect;
- let cr = cairo::Context::new(surface);
- cr.set_matrix(affine);
+ {
+ let cr = cairo::Context::new(&surface);
+ cr.set_matrix(affine);
- self.cr = cr;
- self.rect = Rect::from_size(width, height);
+ self.cr = cr;
- let res = self.draw_node_from_stack(cascaded, node, false);
+ self.rect = Rect::from_size(f64::from(width), f64::from(height));
+
+ let _ = self.draw_node_from_stack(cascaded, node, false)?;
+ }
self.cr = save_cr;
self.rect = save_rect;
- res
+ Ok(SharedImageSurface::new(surface, SurfaceType::SRgb)?)
}
pub fn draw_node_from_stack(
diff --git a/rsvg_internals/src/filters/error.rs b/rsvg_internals/src/filters/error.rs
index f70e96b3..21055bf5 100644
--- a/rsvg_internals/src/filters/error.rs
+++ b/rsvg_internals/src/filters/error.rs
@@ -1,6 +1,8 @@
use std::error::Error;
use std::fmt;
+use crate::error::RenderingError;
+
/// An enumeration of errors that can occur during filter primitive rendering.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum FilterError {
@@ -60,3 +62,16 @@ impl From<cairo::Status> for FilterError {
FilterError::CairoError(x)
}
}
+
+impl From<RenderingError> for FilterError {
+ #[inline]
+ fn from(e: RenderingError) -> Self {
+ if let RenderingError::Cairo(status) = e {
+ FilterError::CairoError(status)
+ } else {
+ // FIXME: this is just a dummy value; we should probably have a way to indicate
+ // an error in the underlying drawing process.
+ FilterError::CairoError(cairo::Status::InvalidStatus)
+ }
+ }
+}
diff --git a/rsvg_internals/src/filters/image.rs b/rsvg_internals/src/filters/image.rs
index d43a1694..fddcb084 100644
--- a/rsvg_internals/src/filters/image.rs
+++ b/rsvg_internals/src/filters/image.rs
@@ -8,7 +8,6 @@ use crate::node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
use crate::parsers::ParseValue;
use crate::property_bag::PropertyBag;
use crate::rect::Rect;
-use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::viewbox::ViewBox;
use super::context::{FilterContext, FilterOutput, FilterResult};
@@ -41,56 +40,32 @@ impl FeImage {
draw_ctx: &mut DrawingCtx,
bounds: Rect,
fragment: &Fragment,
- ) -> Result<cairo::ImageSurface, FilterError> {
+ ) -> Result<FilterResult, FilterError> {
let acquired_drawable = draw_ctx
.acquire_node(fragment, &[])
.map_err(|_| FilterError::InvalidInput)?;
let drawable = acquired_drawable.get();
- let surface = cairo::ImageSurface::create(
- cairo::Format::ARgb32,
- ctx.source_graphic().width(),
- ctx.source_graphic().height(),
- )?;
-
let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();
-
let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);
- draw_ctx
- .draw_node_on_surface(
- &drawable,
- &cascaded,
- &surface,
- ctx.paffine(),
- f64::from(ctx.source_graphic().width()),
- f64::from(ctx.source_graphic().height()),
- )
- .map_err(|e| {
- if let RenderingError::Cairo(status) = e {
- FilterError::CairoError(status)
- } else {
- // FIXME: this is just a dummy value; we should probably have a way to indicate
- // an error in the underlying drawing process.
- FilterError::CairoError(cairo::Status::InvalidStatus)
- }
- })?;
-
- // Clip the output to bounds.
- let output_surface = cairo::ImageSurface::create(
- cairo::Format::ARgb32,
+ let image = draw_ctx.draw_node_to_surface(
+ &drawable,
+ &cascaded,
+ ctx.paffine(),
ctx.source_graphic().width(),
ctx.source_graphic().height(),
)?;
- let cr = cairo::Context::new(&output_surface);
- let r = cairo::Rectangle::from(bounds);
- cr.rectangle(r.x, r.y, r.width, r.height);
- cr.clip();
- cr.set_source_surface(&surface, 0f64, 0f64);
- cr.paint();
+ let surface = ctx.source_graphic().paint_image(bounds, &image, None)?;
- Ok(output_surface)
+ Ok(FilterResult {
+ name: self.base.result.clone(),
+ output: FilterOutput {
+ surface,
+ bounds: bounds.into(),
+ },
+ })
}
/// Renders the filter if the source is an external image.
@@ -98,58 +73,35 @@ impl FeImage {
&self,
ctx: &FilterContext,
draw_ctx: &DrawingCtx,
- bounds: &Rect,
+ bounds: Rect,
unclipped_bounds: &Rect,
- href: &Href,
- ) -> Result<cairo::ImageSurface, FilterError> {
- let surface = if let Href::PlainUrl(ref url) = *href {
- // FIXME: translate the error better here
- draw_ctx
- .lookup_image(&url)
- .map_err(|_| FilterError::InvalidInput)?
- } else {
- unreachable!();
- };
-
- let output_surface = cairo::ImageSurface::create(
- cairo::Format::ARgb32,
- ctx.source_graphic().width(),
- ctx.source_graphic().height(),
- )?;
+ url: &str,
+ ) -> Result<FilterResult, FilterError> {
+ // FIXME: translate the error better here
+ let image = draw_ctx
+ .lookup_image(url)
+ .map_err(|_| FilterError::InvalidInput)?;
// TODO: this goes through a f64->i32->f64 conversion.
- let r = self.aspect.compute(
+ let rect = self.aspect.compute(
&ViewBox(Rect::from_size(
- f64::from(surface.width()),
- f64::from(surface.height()),
+ f64::from(image.width()),
+ f64::from(image.height()),
)),
&unclipped_bounds,
);
- if r.is_empty() {
- return Ok(output_surface);
- }
-
- let ptn = surface.to_cairo_pattern();
- let mut matrix = cairo::Matrix::new(
- r.width() / f64::from(surface.width()),
- 0.0,
- 0.0,
- r.height() / f64::from(surface.height()),
- r.x0,
- r.y0,
- );
- matrix.invert();
- ptn.set_matrix(matrix);
-
- let cr = cairo::Context::new(&output_surface);
- let r = cairo::Rectangle::from(*bounds);
- cr.rectangle(r.x, r.y, r.width, r.height);
- cr.clip();
- cr.set_source(&ptn);
- cr.paint();
-
- Ok(output_surface)
+ let surface = ctx
+ .source_graphic()
+ .paint_image(bounds, &image, Some(rect))?;
+
+ Ok(FilterResult {
+ name: self.base.result.clone(),
+ output: FilterOutput {
+ surface,
+ bounds: bounds.into(),
+ },
+ })
}
}
@@ -190,24 +142,13 @@ impl FilterEffect for FeImage {
let bounds_builder = self.base.get_bounds(ctx);
let bounds = bounds_builder.into_rect(draw_ctx);
- if let Some(href) = self.href.as_ref() {
- let output_surface = match href {
- Href::PlainUrl(_) => {
- let unclipped_bounds = bounds_builder.into_rect_without_clipping(draw_ctx);
- self.render_external_image(ctx, draw_ctx, &bounds, &unclipped_bounds, href)?
- }
- Href::WithFragment(ref frag) => self.render_node(ctx, draw_ctx, bounds, frag)?,
- };
-
- Ok(FilterResult {
- name: self.base.result.clone(),
- output: FilterOutput {
- surface: SharedImageSurface::new(output_surface, SurfaceType::SRgb)?,
- bounds: bounds.into(),
- },
- })
- } else {
- Err(FilterError::InvalidInput)
+ match self.href.as_ref() {
+ Some(Href::PlainUrl(url)) => {
+ let unclipped_bounds = bounds_builder.into_rect_without_clipping(draw_ctx);
+ self.render_external_image(ctx, draw_ctx, bounds, &unclipped_bounds, url)
+ }
+ Some(Href::WithFragment(ref frag)) => self.render_node(ctx, draw_ctx, bounds, frag),
+ _ => Err(FilterError::InvalidInput),
}
}
diff --git a/rsvg_internals/src/surface_utils/shared_surface.rs
b/rsvg_internals/src/surface_utils/shared_surface.rs
index f36dd9da..9b4abb0f 100644
--- a/rsvg_internals/src/surface_utils/shared_surface.rs
+++ b/rsvg_internals/src/surface_utils/shared_surface.rs
@@ -8,7 +8,7 @@ use gdk_pixbuf::{Colorspace, Pixbuf};
use glib::translate::{Stash, ToGlibPtr};
use nalgebra::{storage::Storage, Dim, Matrix};
-use crate::rect::IRect;
+use crate::rect::{IRect, Rect};
use crate::surface_utils::srgb;
use crate::unit_interval::UnitInterval;
use crate::util::clamp;
@@ -961,6 +961,46 @@ impl SharedImageSurface {
SharedImageSurface::new(output_surface, self.surface_type)
}
+ /// Returns a new surface of the same size, with the contents of the
+ /// specified image, optionally transformed to match a given box
+ #[inline]
+ pub fn paint_image(
+ &self,
+ bounds: Rect,
+ image: &SharedImageSurface,
+ rect: Option<Rect>,
+ ) -> Result<SharedImageSurface, cairo::Status> {
+ let output_surface =
+ cairo::ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;
+
+ if rect.is_none() || !rect.unwrap().is_empty() {
+ let cr = cairo::Context::new(&output_surface);
+ let r = cairo::Rectangle::from(bounds);
+ cr.rectangle(r.x, r.y, r.width, r.height);
+ cr.clip();
+
+ image.set_as_source_surface(&cr, 0f64, 0f64);
+
+ if let Some(rect) = rect {
+ let mut matrix = cairo::Matrix::new(
+ rect.width() / f64::from(image.width()),
+ 0.0,
+ 0.0,
+ rect.height() / f64::from(image.height()),
+ rect.x0,
+ rect.y0,
+ );
+ matrix.invert();
+
+ cr.get_source().set_matrix(matrix);
+ }
+
+ cr.paint();
+ }
+
+ SharedImageSurface::new(output_surface, image.surface_type)
+ }
+
/// Performs the combination of two input surfaces using Porter-Duff
/// compositing operators
///
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]