rsvg/filters/
component_transfer.rs

1use std::cmp::min;
2
3use cssparser::Parser;
4use markup5ever::{expanded_name, local_name, ns};
5
6use crate::document::AcquiredNodes;
7use crate::element::{set_attribute, ElementData, ElementTrait};
8use crate::error::*;
9use crate::node::{CascadedValues, Node, NodeBorrow};
10use crate::parse_identifiers;
11use crate::parsers::{CommaSeparatedList, Parse, ParseValue};
12use crate::properties::ColorInterpolationFilters;
13use crate::rect::IRect;
14use crate::session::Session;
15use crate::surface_utils::{
16    iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
17};
18use crate::util::clamp;
19use crate::xml::Attributes;
20
21use super::bounds::BoundsBuilder;
22use super::context::{FilterContext, FilterOutput};
23use super::{
24    FilterEffect, FilterError, FilterResolveError, Input, InputRequirements, Primitive,
25    PrimitiveParams, ResolvedPrimitive,
26};
27
28/// The `feComponentTransfer` filter primitive.
29#[derive(Default)]
30pub struct FeComponentTransfer {
31    base: Primitive,
32    params: ComponentTransfer,
33}
34
35/// Resolved `feComponentTransfer` primitive for rendering.
36#[derive(Clone, Default)]
37pub struct ComponentTransfer {
38    pub in1: Input,
39    pub functions: Functions,
40    pub color_interpolation_filters: ColorInterpolationFilters,
41}
42
43impl ElementTrait for FeComponentTransfer {
44    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
45        self.params.in1 = self.base.parse_one_input(attrs, session);
46    }
47}
48
49/// Component transfer function types.
50#[derive(Clone, Debug, PartialEq)]
51pub enum FunctionType {
52    Identity,
53    Table,
54    Discrete,
55    Linear,
56    Gamma,
57}
58
59impl Parse for FunctionType {
60    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
61        Ok(parse_identifiers!(
62            parser,
63            "identity" => FunctionType::Identity,
64            "table" => FunctionType::Table,
65            "discrete" => FunctionType::Discrete,
66            "linear" => FunctionType::Linear,
67            "gamma" => FunctionType::Gamma,
68        )?)
69    }
70}
71
72/// The compute function parameters.
73struct FunctionParameters {
74    table_values: Vec<f64>,
75    slope: f64,
76    intercept: f64,
77    amplitude: f64,
78    exponent: f64,
79    offset: f64,
80}
81
82#[derive(Clone, Debug, Default, PartialEq)]
83pub struct Functions {
84    pub r: FeFuncR,
85    pub g: FeFuncG,
86    pub b: FeFuncB,
87    pub a: FeFuncA,
88}
89
90/// The compute function type.
91type Function = fn(&FunctionParameters, f64) -> f64;
92
93/// The identity component transfer function.
94fn identity(_: &FunctionParameters, value: f64) -> f64 {
95    value
96}
97
98/// The table component transfer function.
99fn table(params: &FunctionParameters, value: f64) -> f64 {
100    let n = params.table_values.len() - 1;
101    let k = (value * (n as f64)).floor() as usize;
102
103    let k = min(k, n); // Just in case.
104
105    if k == n {
106        return params.table_values[k];
107    }
108
109    let vk = params.table_values[k];
110    let vk1 = params.table_values[k + 1];
111    let k = k as f64;
112    let n = n as f64;
113
114    vk + (value - k / n) * n * (vk1 - vk)
115}
116
117/// The discrete component transfer function.
118fn discrete(params: &FunctionParameters, value: f64) -> f64 {
119    let n = params.table_values.len();
120    let k = (value * (n as f64)).floor() as usize;
121
122    params.table_values[min(k, n - 1)]
123}
124
125/// The linear component transfer function.
126fn linear(params: &FunctionParameters, value: f64) -> f64 {
127    params.slope * value + params.intercept
128}
129
130/// The gamma component transfer function.
131fn gamma(params: &FunctionParameters, value: f64) -> f64 {
132    params.amplitude * value.powf(params.exponent) + params.offset
133}
134
135/// Common values for `feFuncX` elements
136///
137/// The elements `feFuncR`, `feFuncG`, `feFuncB`, `feFuncA` all have the same parameters; this structure
138/// contains them.  Later we define newtypes on this struct as [`FeFuncR`], etc.
139#[derive(Clone, Debug, PartialEq)]
140pub struct FeFuncCommon {
141    pub function_type: FunctionType,
142    pub table_values: Vec<f64>,
143    pub slope: f64,
144    pub intercept: f64,
145    pub amplitude: f64,
146    pub exponent: f64,
147    pub offset: f64,
148}
149
150impl Default for FeFuncCommon {
151    #[inline]
152    fn default() -> Self {
153        Self {
154            function_type: FunctionType::Identity,
155            table_values: Vec::new(),
156            slope: 1.0,
157            intercept: 0.0,
158            amplitude: 1.0,
159            exponent: 1.0,
160            offset: 0.0,
161        }
162    }
163}
164
165// All FeFunc* elements are defined here; they just delegate their attributes
166// to the FeFuncCommon inside.
167macro_rules! impl_func {
168    ($(#[$attr:meta])*
169     $name:ident
170    ) => {
171        #[derive(Clone, Debug, Default, PartialEq)]
172        pub struct $name(pub FeFuncCommon);
173
174        impl ElementTrait for $name {
175            fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
176                self.0.set_attributes(attrs, session);
177            }
178        }
179    };
180}
181
182impl_func!(
183    /// The `feFuncR` element.
184    FeFuncR
185);
186
187impl_func!(
188    /// The `feFuncG` element.
189    FeFuncG
190);
191
192impl_func!(
193    /// The `feFuncB` element.
194    FeFuncB
195);
196
197impl_func!(
198    /// The `feFuncA` element.
199    FeFuncA
200);
201
202impl FeFuncCommon {
203    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
204        for (attr, value) in attrs.iter() {
205            match attr.expanded() {
206                expanded_name!("", "type") => {
207                    set_attribute(&mut self.function_type, attr.parse(value), session)
208                }
209                expanded_name!("", "tableValues") => {
210                    // #691: Limit list to 256 to mitigate malicious SVGs
211                    let mut number_list = CommaSeparatedList::<f64, 0, 256>(Vec::new());
212                    set_attribute(&mut number_list, attr.parse(value), session);
213                    self.table_values = number_list.0;
214                }
215                expanded_name!("", "slope") => {
216                    set_attribute(&mut self.slope, attr.parse(value), session)
217                }
218                expanded_name!("", "intercept") => {
219                    set_attribute(&mut self.intercept, attr.parse(value), session)
220                }
221                expanded_name!("", "amplitude") => {
222                    set_attribute(&mut self.amplitude, attr.parse(value), session)
223                }
224                expanded_name!("", "exponent") => {
225                    set_attribute(&mut self.exponent, attr.parse(value), session)
226                }
227                expanded_name!("", "offset") => {
228                    set_attribute(&mut self.offset, attr.parse(value), session)
229                }
230
231                _ => (),
232            }
233        }
234
235        // The table function type with empty table_values is considered
236        // an identity function.
237        match self.function_type {
238            FunctionType::Table | FunctionType::Discrete => {
239                if self.table_values.is_empty() {
240                    self.function_type = FunctionType::Identity;
241                }
242            }
243            _ => (),
244        }
245    }
246
247    fn function_parameters(&self) -> FunctionParameters {
248        FunctionParameters {
249            table_values: self.table_values.clone(),
250            slope: self.slope,
251            intercept: self.intercept,
252            amplitude: self.amplitude,
253            exponent: self.exponent,
254            offset: self.offset,
255        }
256    }
257
258    fn function(&self) -> Function {
259        match self.function_type {
260            FunctionType::Identity => identity,
261            FunctionType::Table => table,
262            FunctionType::Discrete => discrete,
263            FunctionType::Linear => linear,
264            FunctionType::Gamma => gamma,
265        }
266    }
267}
268
269macro_rules! func_or_default {
270    ($func_node:ident, $func_type:ident) => {
271        match $func_node {
272            Some(ref f) => match &*f.borrow_element_data() {
273                ElementData::$func_type(e) => (**e).clone(),
274                _ => unreachable!(),
275            },
276            _ => $func_type::default(),
277        }
278    };
279}
280
281macro_rules! get_func_x_node {
282    ($func_node:ident, $func_type:ident) => {
283        $func_node
284            .children()
285            .rev()
286            .filter(|c| c.is_element())
287            .find(|c| matches!(*c.borrow_element_data(), ElementData::$func_type(_)))
288    };
289}
290
291impl ComponentTransfer {
292    pub fn render(
293        &self,
294        bounds_builder: BoundsBuilder,
295        ctx: &FilterContext,
296    ) -> Result<FilterOutput, FilterError> {
297        let input_1 = ctx.get_input(&self.in1, self.color_interpolation_filters)?;
298        let bounds: IRect = bounds_builder
299            .add_input(&input_1)
300            .compute(ctx)
301            .clipped
302            .into();
303
304        // Create the output surface.
305        let mut surface = ExclusiveImageSurface::new(
306            ctx.source_graphic().width(),
307            ctx.source_graphic().height(),
308            input_1.surface().surface_type(),
309        )?;
310
311        fn compute_func(func: &FeFuncCommon) -> impl Fn(u8, f64, f64) -> u8 {
312            let compute = func.function();
313            let params = func.function_parameters();
314
315            move |value, alpha, new_alpha| {
316                let value = f64::from(value) / 255f64;
317
318                let unpremultiplied = if alpha == 0f64 { 0f64 } else { value / alpha };
319
320                let new_value = compute(&params, unpremultiplied);
321                let new_value = clamp(new_value, 0f64, 1f64);
322
323                ((new_value * new_alpha * 255f64) + 0.5) as u8
324            }
325        }
326
327        let compute_r = compute_func(&self.functions.r.0);
328        let compute_g = compute_func(&self.functions.g.0);
329        let compute_b = compute_func(&self.functions.b.0);
330
331        // Alpha gets special handling since everything else depends on it.
332        let compute_a = self.functions.a.0.function();
333        let params_a = self.functions.a.0.function_parameters();
334        let compute_a = |alpha| compute_a(&params_a, alpha);
335
336        // Do the actual processing.
337        surface.modify(&mut |data, stride| {
338            for (x, y, pixel) in Pixels::within(input_1.surface(), bounds) {
339                let alpha = f64::from(pixel.a) / 255f64;
340                let new_alpha = compute_a(alpha);
341
342                let output_pixel = Pixel {
343                    r: compute_r(pixel.r, alpha, new_alpha),
344                    g: compute_g(pixel.g, alpha, new_alpha),
345                    b: compute_b(pixel.b, alpha, new_alpha),
346                    a: ((new_alpha * 255f64) + 0.5) as u8,
347                };
348
349                data.set_pixel(stride, output_pixel, x, y);
350            }
351        });
352
353        Ok(FilterOutput {
354            surface: surface.share()?,
355            bounds,
356        })
357    }
358
359    pub fn get_input_requirements(&self) -> InputRequirements {
360        self.in1.get_requirements()
361    }
362}
363
364impl FilterEffect for FeComponentTransfer {
365    fn resolve(
366        &self,
367        _acquired_nodes: &mut AcquiredNodes<'_>,
368        node: &Node,
369    ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
370        let cascaded = CascadedValues::new_from_node(node);
371        let values = cascaded.get();
372
373        let mut params = self.params.clone();
374        params.functions = get_functions(node)?;
375        params.color_interpolation_filters = values.color_interpolation_filters();
376
377        Ok(vec![ResolvedPrimitive {
378            primitive: self.base.clone(),
379            params: PrimitiveParams::ComponentTransfer(params),
380        }])
381    }
382}
383
384/// Takes a feComponentTransfer and walks its children to produce the feFuncX arguments.
385fn get_functions(node: &Node) -> Result<Functions, FilterResolveError> {
386    let func_r_node = get_func_x_node!(node, FeFuncR);
387    let func_g_node = get_func_x_node!(node, FeFuncG);
388    let func_b_node = get_func_x_node!(node, FeFuncB);
389    let func_a_node = get_func_x_node!(node, FeFuncA);
390
391    let r = func_or_default!(func_r_node, FeFuncR);
392    let g = func_or_default!(func_g_node, FeFuncG);
393    let b = func_or_default!(func_b_node, FeFuncB);
394    let a = func_or_default!(func_a_node, FeFuncA);
395
396    Ok(Functions { r, g, b, a })
397}
398
399#[cfg(test)]
400mod tests {
401    use super::*;
402    use crate::document::Document;
403
404    #[test]
405    fn extracts_functions() {
406        let document = Document::load_from_bytes(
407            br#"<?xml version="1.0" encoding="UTF-8"?>
408<svg xmlns="http://www.w3.org/2000/svg">
409  <filter id="filter">
410    <feComponentTransfer id="component_transfer">
411      <!-- no feFuncR so it should get the defaults -->
412
413      <feFuncG type="table" tableValues="0.0 1.0 2.0"/>
414
415      <feFuncB type="table"/>
416      <!-- duplicate this to test that last-one-wins -->
417      <feFuncB type="discrete" tableValues="0.0, 1.0" slope="1.0" intercept="2.0" amplitude="3.0" exponent="4.0" offset="5.0"/>
418
419      <!-- no feFuncA so it should get the defaults -->
420    </feComponentTransfer>
421  </filter>
422</svg>
423"#
424        );
425
426        let component_transfer = document.lookup_internal_node("component_transfer").unwrap();
427        let functions = get_functions(&component_transfer).unwrap();
428
429        assert_eq!(
430            functions,
431            Functions {
432                r: FeFuncR::default(),
433
434                g: FeFuncG(FeFuncCommon {
435                    function_type: FunctionType::Table,
436                    table_values: vec![0.0, 1.0, 2.0],
437                    ..FeFuncCommon::default()
438                }),
439
440                b: FeFuncB(FeFuncCommon {
441                    function_type: FunctionType::Discrete,
442                    table_values: vec![0.0, 1.0],
443                    slope: 1.0,
444                    intercept: 2.0,
445                    amplitude: 3.0,
446                    exponent: 4.0,
447                    offset: 5.0,
448                }),
449
450                a: FeFuncA::default(),
451            }
452        );
453    }
454}