summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@gnome.org>2023-02-09 14:31:43 -0600
committerFederico Mena Quintero <federico@gnome.org>2023-02-09 19:34:28 -0600
commit0847de0a610e147ae5ff4aecad6270d42380bb0f (patch)
tree3209c4a59b30502d9564d223c54d31d68a709e38
parent3a309538c35701be765a814dd4f9dbd27103cac0 (diff)
downloadlibrsvg-0847de0a610e147ae5ff4aecad6270d42380bb0f.tar.gz
(#743): implement the feDropShadow element
Fixes https://gitlab.gnome.org/GNOME/librsvg/-/issues/743 Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/793>
-rw-r--r--Makefile.am1
-rw-r--r--src/element.rs9
-rw-r--r--src/filters/drop_shadow.rs88
-rw-r--r--src/filters/mod.rs5
-rw-r--r--tests/fixtures/reftests/svg2/bug743-fe-drop-shadow-ref.svg17
-rw-r--r--tests/fixtures/reftests/svg2/bug743-fe-drop-shadow.svg10
-rw-r--r--tests/src/filters.rs8
7 files changed, 136 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index ac169ee9..24e47b34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -63,6 +63,7 @@ LIBRSVG_SRC = \
src/filters/context.rs \
src/filters/convolve_matrix.rs \
src/filters/displacement_map.rs \
+ src/filters/drop_shadow.rs \
src/filters/error.rs \
src/filters/flood.rs \
src/filters/gaussian_blur.rs \
diff --git a/src/element.rs b/src/element.rs
index bf5c1a30..2ee4e693 100644
--- a/src/element.rs
+++ b/src/element.rs
@@ -21,6 +21,7 @@ use crate::filters::{
composite::FeComposite,
convolve_matrix::FeConvolveMatrix,
displacement_map::FeDisplacementMap,
+ drop_shadow::FeDropShadow,
flood::FeFlood,
gaussian_blur::FeGaussianBlur,
image::FeImage,
@@ -315,6 +316,7 @@ pub enum Element {
FeDiffuseLighting(Box<ElementInner<FeDiffuseLighting>>),
FeDisplacementMap(Box<ElementInner<FeDisplacementMap>>),
FeDistantLight(Box<ElementInner<FeDistantLight>>),
+ FeDropShadow(Box<ElementInner<FeDropShadow>>),
FeFlood(Box<ElementInner<FeFlood>>),
FeFuncA(Box<ElementInner<FeFuncA>>),
FeFuncB(Box<ElementInner<FeFuncB>>),
@@ -372,6 +374,7 @@ macro_rules! call_inner {
Element::FeDiffuseLighting(i) => i.$method($($args),*),
Element::FeDisplacementMap(i) => i.$method($($args),*),
Element::FeDistantLight(i) => i.$method($($args),*),
+ Element::FeDropShadow(i) => i.$method($($args),*),
Element::FeFlood(i) => i.$method($($args),*),
Element::FeFuncA(i) => i.$method($($args),*),
Element::FeFuncB(i) => i.$method($($args),*),
@@ -494,6 +497,7 @@ impl Element {
Element::FeConvolveMatrix(ref fe) => Some(&fe.element_impl),
Element::FeDiffuseLighting(ref fe) => Some(&fe.element_impl),
Element::FeDisplacementMap(ref fe) => Some(&fe.element_impl),
+ Element::FeDropShadow(ref fe) => Some(&fe.element_impl),
Element::FeFlood(ref fe) => Some(&fe.element_impl),
Element::FeGaussianBlur(ref fe) => Some(&fe.element_impl),
Element::FeImage(ref fe) => Some(&fe.element_impl),
@@ -591,8 +595,9 @@ mod creators {
e!(create_fe_composite, FeComposite);
e!(create_fe_convolve_matrix, FeConvolveMatrix);
e!(create_fe_diffuse_lighting, FeDiffuseLighting);
- e!(create_fe_distant_light, FeDistantLight);
e!(create_fe_displacement_map, FeDisplacementMap);
+ e!(create_fe_distant_light, FeDistantLight);
+ e!(create_fe_drop_shadow, FeDropShadow);
e!(create_fe_flood, FeFlood);
e!(create_fe_gaussian_blur, FeGaussianBlur);
e!(create_fe_image, FeImage);
@@ -685,6 +690,7 @@ static ELEMENT_CREATORS: Lazy<HashMap<&'static str, (ElementCreateFn, ElementCre
("feDiffuseLighting", create_fe_diffuse_lighting, Default),
("feDisplacementMap", create_fe_displacement_map, Default),
("feDistantLight", create_fe_distant_light, IgnoreClass),
+ ("feDropShadow", create_fe_drop_shadow, Default),
("feFuncA", create_fe_func_a, IgnoreClass),
("feFuncB", create_fe_func_b, IgnoreClass),
("feFuncG", create_fe_func_g, IgnoreClass),
@@ -788,6 +794,7 @@ mod sizes {
print_size!(FeDiffuseLighting);
print_size!(FeDistantLight);
print_size!(FeDisplacementMap);
+ print_size!(FeDropShadow);
print_size!(FeFlood);
print_size!(FeGaussianBlur);
print_size!(FeImage);
diff --git a/src/filters/drop_shadow.rs b/src/filters/drop_shadow.rs
new file mode 100644
index 00000000..3969d5e5
--- /dev/null
+++ b/src/filters/drop_shadow.rs
@@ -0,0 +1,88 @@
+use markup5ever::{expanded_name, local_name, namespace_url, ns};
+
+use crate::document::AcquiredNodes;
+use crate::element::{set_attribute, SetAttributes};
+use crate::filter_func::drop_shadow_primitives;
+use crate::node::{CascadedValues, Node};
+use crate::paint_server::resolve_color;
+use crate::parsers::{NumberOptionalNumber, ParseValue};
+use crate::session::Session;
+use crate::xml::Attributes;
+
+use super::{FilterEffect, FilterResolveError, Input, Primitive, ResolvedPrimitive};
+
+/// The `feDropShadow` element.
+#[derive(Default)]
+pub struct FeDropShadow {
+ base: Primitive,
+ params: DropShadow,
+}
+
+/// Resolved `feDropShadow` parameters for rendering.
+#[derive(Clone)]
+pub struct DropShadow {
+ pub in1: Input,
+ pub dx: f64,
+ pub dy: f64,
+ pub std_deviation: NumberOptionalNumber<f64>,
+}
+
+impl Default for DropShadow {
+ /// Defaults come from https://www.w3.org/TR/filter-effects/#feDropShadowElement
+ fn default() -> Self {
+ Self {
+ in1: Default::default(),
+ dx: 2.0,
+ dy: 2.0,
+ std_deviation: NumberOptionalNumber(2.0, 2.0),
+ }
+ }
+}
+
+impl SetAttributes for FeDropShadow {
+ fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
+ self.params.in1 = self.base.parse_one_input(attrs, session);
+
+ for (attr, value) in attrs.iter() {
+ match attr.expanded() {
+ expanded_name!("", "dx") => {
+ set_attribute(&mut self.params.dx, attr.parse(value), session);
+ }
+
+ expanded_name!("", "dy") => {
+ set_attribute(&mut self.params.dy, attr.parse(value), session);
+ }
+
+ expanded_name!("", "stdDeviation") => {
+ set_attribute(&mut self.params.std_deviation, attr.parse(value), session);
+ }
+
+ _ => (),
+ }
+ }
+ }
+}
+
+impl FilterEffect for FeDropShadow {
+ fn resolve(
+ &self,
+ _acquired_nodes: &mut AcquiredNodes<'_>,
+ node: &Node,
+ ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
+ let cascaded = CascadedValues::new_from_node(node);
+ let values = cascaded.get();
+
+ let color = resolve_color(
+ &values.flood_color().0,
+ values.flood_opacity().0,
+ values.color().0,
+ );
+
+ Ok(drop_shadow_primitives(
+ self.params.dx,
+ self.params.dy,
+ self.params.std_deviation,
+ color,
+ ))
+ }
+}
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
index 8b0f37d5..e6f4724e 100644
--- a/src/filters/mod.rs
+++ b/src/filters/mod.rs
@@ -49,6 +49,7 @@ pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
+pub mod drop_shadow;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
@@ -349,6 +350,10 @@ fn render_primitive(
let bounds_builder = primitive.get_bounds(ctx);
+ // Note that feDropShadow is not handled here. When its FilterElement::resolve() is called,
+ // it returns a series of lower-level primitives (flood, blur, offset, etc.) that make up
+ // the drop-shadow effect.
+
match primitive.params {
Blend(ref p) => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
ColorMatrix(ref p) => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
diff --git a/tests/fixtures/reftests/svg2/bug743-fe-drop-shadow-ref.svg b/tests/fixtures/reftests/svg2/bug743-fe-drop-shadow-ref.svg
new file mode 100644
index 00000000..034f8b37
--- /dev/null
+++ b/tests/fixtures/reftests/svg2/bug743-fe-drop-shadow-ref.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
+ <filter id="drop-shadow" filterUnits="userSpaceOnUse">
+ <feGaussianBlur in="SourceAlpha" stdDeviation="5 10"/>
+ <feOffset dx="5" dy="10" result="offsetblur"/>
+ <feFlood flood-color="black" flood-opacity="0.5"/>
+ <feComposite in2="offsetblur" operator="in"/>
+ <feMerge>
+ <feMergeNode/>
+ <feMergeNode in="SourceGraphic"/>
+ </feMerge>
+ </filter>
+
+ <rect x="0" y="0" width="100%" height="100%" fill="white"/>
+
+ <rect x="50" y="50" width="50" height="50" fill="blue" stroke="magenta" stroke-width="6" filter="url(#drop-shadow)"/>
+</svg>
diff --git a/tests/fixtures/reftests/svg2/bug743-fe-drop-shadow.svg b/tests/fixtures/reftests/svg2/bug743-fe-drop-shadow.svg
new file mode 100644
index 00000000..7054201f
--- /dev/null
+++ b/tests/fixtures/reftests/svg2/bug743-fe-drop-shadow.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
+ <filter id="drop-shadow" filterUnits="userSpaceOnUse">
+ <feDropShadow dx="5" dy="10" stdDeviation="5 10" flood-color="black" flood-opacity="0.5"/>
+ </filter>
+
+ <rect x="0" y="0" width="100%" height="100%" fill="white"/>
+
+ <rect x="50" y="50" width="50" height="50" fill="blue" stroke="magenta" stroke-width="6" filter="url(#drop-shadow)"/>
+</svg>
diff --git a/tests/src/filters.rs b/tests/src/filters.rs
index f756a781..9517e651 100644
--- a/tests/src/filters.rs
+++ b/tests/src/filters.rs
@@ -1,8 +1,8 @@
use cairo;
use crate::reference_utils::{Compare, Evaluate, Reference};
-use crate::test_compare_render_output;
use crate::utils::{load_svg, render_document, SurfaceSize};
+use crate::{test_compare_render_output, test_svg_reference};
#[test]
fn invalid_filter_reference_cancels_filter_chain() {
@@ -363,3 +363,9 @@ test_compare_render_output!(
</svg>
"##,
);
+
+test_svg_reference!(
+ bug_743_fe_drop_shadow,
+ "tests/fixtures/reftests/svg2/bug743-fe-drop-shadow.svg",
+ "tests/fixtures/reftests/svg2/bug743-fe-drop-shadow-ref.svg"
+);