rsvg/filters/
displacement_map.rs1use cssparser::Parser;
2use markup5ever::{expanded_name, local_name, ns};
3
4use crate::document::AcquiredNodes;
5use crate::element::{ElementTrait, set_attribute};
6use crate::error::*;
7use crate::node::{CascadedValues, Node};
8use crate::parse_identifiers;
9use crate::parsers::{Parse, ParseValue};
10use crate::properties::ColorInterpolationFilters;
11use crate::rect::IRect;
12use crate::session::Session;
13use crate::surface_utils::{iterators::Pixels, shared_surface::ExclusiveImageSurface};
14use crate::xml::Attributes;
15
16use super::bounds::BoundsBuilder;
17use super::context::{FilterContext, FilterOutput};
18use super::{
19 FilterEffect, FilterError, FilterResolveError, Input, InputRequirements, Primitive,
20 PrimitiveParams, ResolvedPrimitive,
21};
22
23#[derive(Default, Clone, Copy)]
25enum ColorChannel {
26 R,
27 G,
28 B,
29 #[default]
30 A,
31}
32
33#[derive(Default)]
35pub struct FeDisplacementMap {
36 base: Primitive,
37 params: DisplacementMap,
38}
39
40#[derive(Clone, Default)]
42pub struct DisplacementMap {
43 in1: Input,
44 in2: Input,
45 scale: f64,
46 x_channel_selector: ColorChannel,
47 y_channel_selector: ColorChannel,
48 color_interpolation_filters: ColorInterpolationFilters,
49}
50
51impl ElementTrait for FeDisplacementMap {
52 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
53 let (in1, in2) = self.base.parse_two_inputs(attrs, session);
54 self.params.in1 = in1;
55 self.params.in2 = in2;
56
57 for (attr, value) in attrs.iter() {
58 match attr.expanded() {
59 expanded_name!("", "scale") => {
60 set_attribute(&mut self.params.scale, attr.parse(value), session)
61 }
62 expanded_name!("", "xChannelSelector") => {
63 set_attribute(
64 &mut self.params.x_channel_selector,
65 attr.parse(value),
66 session,
67 );
68 }
69 expanded_name!("", "yChannelSelector") => {
70 set_attribute(
71 &mut self.params.y_channel_selector,
72 attr.parse(value),
73 session,
74 );
75 }
76 _ => (),
77 }
78 }
79 }
80}
81
82impl DisplacementMap {
83 pub fn render(
84 &self,
85 bounds_builder: BoundsBuilder,
86 ctx: &FilterContext,
87 ) -> Result<FilterOutput, FilterError> {
88 let input_1 = ctx.get_input(&self.in1, ColorInterpolationFilters::Auto)?;
95 let displacement_input = ctx.get_input(&self.in2, self.color_interpolation_filters)?;
96 let bounds: IRect = bounds_builder
97 .add_input(&input_1)
98 .add_input(&displacement_input)
99 .compute(ctx)
100 .clipped
101 .into();
102
103 let displacement_surface = displacement_input.surface().unpremultiply(bounds)?;
105
106 let (sx, sy) = ctx.paffine().transform_distance(self.scale, self.scale);
107
108 let mut surface = ExclusiveImageSurface::new(
109 ctx.source_graphic().width(),
110 ctx.source_graphic().height(),
111 input_1.surface().surface_type(),
112 )?;
113
114 surface.draw(&mut |cr| {
115 for (x, y, displacement_pixel) in Pixels::within(&displacement_surface, bounds) {
116 let get_value = |channel| match channel {
117 ColorChannel::R => displacement_pixel.r,
118 ColorChannel::G => displacement_pixel.g,
119 ColorChannel::B => displacement_pixel.b,
120 ColorChannel::A => displacement_pixel.a,
121 };
122
123 let process = |x| f64::from(x) / 255.0 - 0.5;
124
125 let dx = process(get_value(self.x_channel_selector));
126 let dy = process(get_value(self.y_channel_selector));
127
128 let x = f64::from(x);
129 let y = f64::from(y);
130 let ox = sx * dx;
131 let oy = sy * dy;
132
133 cr.rectangle(x, y, 1.0, 1.0);
136 cr.reset_clip();
137 cr.clip();
138
139 input_1.surface().set_as_source_surface(&cr, -ox, -oy)?;
140 cr.paint()?;
141 }
142
143 Ok(())
144 })?;
145
146 Ok(FilterOutput {
147 surface: surface.share()?,
148 bounds,
149 })
150 }
151
152 pub fn get_input_requirements(&self) -> InputRequirements {
153 self.in1
154 .get_requirements()
155 .fold(self.in2.get_requirements())
156 }
157}
158
159impl FilterEffect for FeDisplacementMap {
160 fn resolve(
161 &self,
162 _acquired_nodes: &mut AcquiredNodes<'_>,
163 node: &Node,
164 ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
165 let cascaded = CascadedValues::new_from_node(node);
166 let values = cascaded.get();
167
168 let mut params = self.params.clone();
169 params.color_interpolation_filters = values.color_interpolation_filters();
170
171 Ok(vec![ResolvedPrimitive {
172 primitive: self.base.clone(),
173 params: PrimitiveParams::DisplacementMap(params),
174 }])
175 }
176}
177
178impl Parse for ColorChannel {
179 fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
180 Ok(parse_identifiers!(
181 parser,
182 "R" => ColorChannel::R,
183 "G" => ColorChannel::G,
184 "B" => ColorChannel::B,
185 "A" => ColorChannel::A,
186 )?)
187 }
188}