[librsvg: 1/4] Move composition code in surface_utils.
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/4] Move composition code in surface_utils.
- Date: Sat, 28 Dec 2019 18:43:34 +0000 (UTC)
commit d78a352bec288314c85636ea091753f016fd1940
Author: Paolo Borelli <pborelli gnome org>
Date: Fri Dec 27 22:18:06 2019 +0100
Move composition code in surface_utils.
Move pixel operations in the surface_utils module.
rsvg_internals/benches/composite.rs | 5 +-
rsvg_internals/src/filters/composite.rs | 113 ++----------------
rsvg_internals/src/surface_utils/shared_surface.rs | 131 ++++++++++++++++++++-
3 files changed, 140 insertions(+), 109 deletions(-)
---
diff --git a/rsvg_internals/benches/composite.rs b/rsvg_internals/benches/composite.rs
index 48a69097..bdcc581f 100644
--- a/rsvg_internals/benches/composite.rs
+++ b/rsvg_internals/benches/composite.rs
@@ -5,9 +5,10 @@ use criterion::{black_box, Criterion};
use cairo;
use rsvg_internals;
-use rsvg_internals::filters::composite::composite_arithmetic;
use rsvg_internals::rect::IRect;
-use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
+use rsvg_internals::surface_utils::shared_surface::{
+ composite_arithmetic, SharedImageSurface, SurfaceType,
+};
const SURFACE_SIDE: i32 = 512;
const BOUNDS: IRect = IRect {
diff --git a/rsvg_internals/src/filters/composite.rs b/rsvg_internals/src/filters/composite.rs
index da3bc3f1..138bbcf4 100644
--- a/rsvg_internals/src/filters/composite.rs
+++ b/rsvg_internals/src/filters/composite.rs
@@ -1,4 +1,3 @@
-use cairo::{self, ImageSurface};
use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};
@@ -7,14 +6,6 @@ use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::{Parse, ParseValue};
use crate::property_bag::PropertyBag;
-use crate::rect::IRect;
-use crate::surface_utils::{
- iterators::Pixels,
- shared_surface::SharedImageSurface,
- ImageSurfaceDataExt,
- Pixel,
-};
-use crate::util::clamp;
use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
@@ -80,55 +71,6 @@ impl NodeTrait for FeComposite {
}
}
-/// Performs the arithmetic composite operation. Public for benchmarking.
-#[inline]
-pub fn composite_arithmetic(
- input_surface: &SharedImageSurface,
- input_2_surface: &SharedImageSurface,
- output_surface: &mut cairo::ImageSurface,
- bounds: IRect,
- k1: f64,
- k2: f64,
- k3: f64,
- k4: f64,
-) {
- let output_stride = output_surface.get_stride() as usize;
- {
- let mut output_data = output_surface.get_data().unwrap();
-
- for (x, y, pixel, pixel_2) in Pixels::new(input_surface, bounds)
- .map(|(x, y, p)| (x, y, p, input_2_surface.get_pixel(x, y)))
- {
- let i1a = f64::from(pixel.a) / 255f64;
- let i2a = f64::from(pixel_2.a) / 255f64;
- let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
- let oa = clamp(oa, 0f64, 1f64);
-
- // Contents of image surfaces are transparent by default, so if the resulting pixel is
- // transparent there's no need to do anything.
- if oa > 0f64 {
- let compute = |i1, i2| {
- let i1 = f64::from(i1) / 255f64;
- let i2 = f64::from(i2) / 255f64;
-
- let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
- let o = clamp(o, 0f64, oa);
-
- ((o * 255f64) + 0.5) as u8
- };
-
- let output_pixel = Pixel {
- r: compute(pixel.r, pixel_2.r),
- g: compute(pixel.g, pixel_2.g),
- b: compute(pixel.b, pixel_2.b),
- a: ((oa * 255f64) + 0.5) as u8,
- };
- output_data.set_pixel(output_stride, output_pixel, x, y);
- }
- }
- }
-}
-
impl FilterEffect for FeComposite {
fn render(
&self,
@@ -145,63 +87,26 @@ impl FilterEffect for FeComposite {
.add_input(&input_2)
.into_irect(draw_ctx);
- // If we're combining two alpha-only surfaces, the result is alpha-only. Otherwise the
- // result is whatever the non-alpha-only type we're working on (which can be either sRGB or
- // linear sRGB depending on color-interpolation-filters).
- let surface_type = if input.surface().is_alpha_only() {
- input_2.surface().surface_type()
- } else {
- if !input_2.surface().is_alpha_only() {
- // All surface types should match (this is enforced by get_input()).
- assert_eq!(
- input_2.surface().surface_type(),
- input.surface().surface_type()
- );
- }
-
- input.surface().surface_type()
- };
-
- let output_surface = if self.operator == Operator::Arithmetic {
- let mut output_surface = ImageSurface::create(
- cairo::Format::ARgb32,
- input.surface().width(),
- input.surface().height(),
- )?;
-
- composite_arithmetic(
- input.surface(),
+ let surface = if self.operator == Operator::Arithmetic {
+ input.surface().compose_arithmetic(
input_2.surface(),
- &mut output_surface,
bounds,
self.k1,
self.k2,
self.k3,
self.k4,
- );
-
- output_surface
+ )?
} else {
- let output_surface = input_2.surface().copy_surface(bounds)?;
-
- 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();
-
- input.surface().set_as_source_surface(&cr, 0f64, 0f64);
- cr.set_operator(self.operator.into());
- cr.paint();
-
- output_surface
+ input.surface().compose(
+ input_2.surface(),
+ bounds,
+ cairo::Operator::from(self.operator),
+ )?
};
Ok(FilterResult {
name: self.base.result.clone(),
- output: FilterOutput {
- surface: SharedImageSurface::new(output_surface, surface_type)?,
- bounds,
- },
+ output: FilterOutput { surface, bounds },
})
}
diff --git a/rsvg_internals/src/surface_utils/shared_surface.rs
b/rsvg_internals/src/surface_utils/shared_surface.rs
index 53a5b040..0e4aba1f 100644
--- a/rsvg_internals/src/surface_utils/shared_surface.rs
+++ b/rsvg_internals/src/surface_utils/shared_surface.rs
@@ -16,9 +16,7 @@ use crate::util::clamp;
use super::{
iterators::{PixelRectangle, Pixels},
- EdgeMode,
- ImageSurfaceDataExt,
- Pixel,
+ EdgeMode, ImageSurfaceDataExt, Pixel,
};
/// Types of pixel data in a `SharedImageSurface`.
@@ -35,6 +33,25 @@ pub enum SurfaceType {
AlphaOnly,
}
+impl SurfaceType {
+ /// Combines surface types
+ ///
+ /// If combining two alpha-only surfaces, the result is alpha-only.
+ /// If one is alpha-only, the result is the other.
+ /// If none is alpha-only, the types should be the same.
+ ///
+ /// # Panics
+ /// Panics if the surface types are not alpha-only and differ.
+ pub fn combine(self, other: SurfaceType) -> SurfaceType {
+ match (self, other) {
+ (SurfaceType::AlphaOnly, t) => t,
+ (t, SurfaceType::AlphaOnly) => t,
+ (t1, t2) if t1 == t2 => t1,
+ _ => panic!(),
+ }
+ }
+}
+
/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
@@ -886,6 +903,65 @@ impl SharedImageSurface {
SharedImageSurface::new(output_surface, self.surface_type)
}
+ /// Performs the combination of two input surfaces using Porter-Duff
+ /// compositing operators
+ ///
+ /// # Panics
+ /// Panics if the two surface types are not compatible.
+ #[inline]
+ pub fn compose(
+ &self,
+ other: &SharedImageSurface,
+ bounds: IRect,
+ operator: cairo::Operator,
+ ) -> Result<SharedImageSurface, cairo::Status> {
+ let output_surface = other.copy_surface(bounds)?;
+
+ {
+ 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();
+
+ self.set_as_source_surface(&cr, 0.0, 0.0);
+ cr.set_operator(operator);
+ cr.paint();
+ }
+
+ SharedImageSurface::new(
+ output_surface,
+ self.surface_type.combine(other.surface_type),
+ )
+ }
+
+ /// Performs the combination of two input surfaces.
+ ///
+ /// Each pixel of the resulting image is computed using the following formula:
+ /// `res = k1*i1*i2 + k2*i1 + k3*i2 + k4`
+ ///
+ /// # Panics
+ /// Panics if the two surface types are not compatible.
+ #[inline]
+ pub fn compose_arithmetic(
+ &self,
+ other: &SharedImageSurface,
+ bounds: IRect,
+ k1: f64,
+ k2: f64,
+ k3: f64,
+ k4: f64,
+ ) -> Result<SharedImageSurface, cairo::Status> {
+ let mut output_surface =
+ cairo::ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;
+
+ composite_arithmetic(self, other, &mut output_surface, bounds, k1, k2, k3, k4);
+
+ SharedImageSurface::new(
+ output_surface,
+ self.surface_type.combine(other.surface_type),
+ )
+ }
+
/// Returns a raw pointer to the underlying surface.
///
/// # Safety
@@ -896,6 +972,55 @@ impl SharedImageSurface {
}
}
+/// Performs the arithmetic composite operation. Public for benchmarking.
+#[inline]
+pub fn composite_arithmetic(
+ surface1: &SharedImageSurface,
+ surface2: &SharedImageSurface,
+ output_surface: &mut cairo::ImageSurface,
+ bounds: IRect,
+ k1: f64,
+ k2: f64,
+ k3: f64,
+ k4: f64,
+) {
+ let output_stride = output_surface.get_stride() as usize;
+ {
+ let mut output_data = output_surface.get_data().unwrap();
+
+ for (x, y, pixel, pixel_2) in
+ Pixels::new(surface1, bounds).map(|(x, y, p)| (x, y, p, surface2.get_pixel(x, y)))
+ {
+ let i1a = f64::from(pixel.a) / 255f64;
+ let i2a = f64::from(pixel_2.a) / 255f64;
+ let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
+ let oa = clamp(oa, 0f64, 1f64);
+
+ // Contents of image surfaces are transparent by default, so if the resulting pixel is
+ // transparent there's no need to do anything.
+ if oa > 0f64 {
+ let compute = |i1, i2| {
+ let i1 = f64::from(i1) / 255f64;
+ let i2 = f64::from(i2) / 255f64;
+
+ let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
+ let o = clamp(o, 0f64, oa);
+
+ ((o * 255f64) + 0.5) as u8
+ };
+
+ let output_pixel = Pixel {
+ r: compute(pixel.r, pixel_2.r),
+ g: compute(pixel.g, pixel_2.g),
+ b: compute(pixel.b, pixel_2.b),
+ a: ((oa * 255f64) + 0.5) as u8,
+ };
+ output_data.set_pixel(output_stride, output_pixel, x, y);
+ }
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]