rsvg/filters/
blend.rs

1use cssparser::Parser;
2use markup5ever::{expanded_name, local_name, ns};
3
4use crate::document::AcquiredNodes;
5use crate::element::{set_attribute, ElementTrait};
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::shared_surface::Operator;
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/// Enumeration of the possible blending modes.
24#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
25enum Mode {
26    #[default]
27    Normal,
28    Multiply,
29    Screen,
30    Darken,
31    Lighten,
32    Overlay,
33    ColorDodge,
34    ColorBurn,
35    HardLight,
36    SoftLight,
37    Difference,
38    Exclusion,
39    HslHue,
40    HslSaturation,
41    HslColor,
42    HslLuminosity,
43}
44
45/// The `feBlend` filter primitive.
46#[derive(Default)]
47pub struct FeBlend {
48    base: Primitive,
49    params: Blend,
50}
51
52/// Resolved `feBlend` primitive for rendering.
53#[derive(Clone, Default)]
54pub struct Blend {
55    in1: Input,
56    in2: Input,
57    mode: Mode,
58    color_interpolation_filters: ColorInterpolationFilters,
59}
60
61impl ElementTrait for FeBlend {
62    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
63        let (in1, in2) = self.base.parse_two_inputs(attrs, session);
64        self.params.in1 = in1;
65        self.params.in2 = in2;
66
67        for (attr, value) in attrs.iter() {
68            if let expanded_name!("", "mode") = attr.expanded() {
69                set_attribute(&mut self.params.mode, attr.parse(value), session);
70            }
71        }
72    }
73}
74
75impl Blend {
76    pub fn render(
77        &self,
78        bounds_builder: BoundsBuilder,
79        ctx: &FilterContext,
80    ) -> Result<FilterOutput, FilterError> {
81        let input_1 = ctx.get_input(&self.in1, self.color_interpolation_filters)?;
82        let input_2 = ctx.get_input(&self.in2, self.color_interpolation_filters)?;
83        let bounds: IRect = bounds_builder
84            .add_input(&input_1)
85            .add_input(&input_2)
86            .compute(ctx)
87            .clipped
88            .into();
89
90        let surface = input_1
91            .surface()
92            .compose(input_2.surface(), bounds, self.mode.into())?;
93
94        Ok(FilterOutput { surface, bounds })
95    }
96
97    pub fn get_input_requirements(&self) -> InputRequirements {
98        self.in1
99            .get_requirements()
100            .fold(self.in2.get_requirements())
101    }
102}
103
104impl FilterEffect for FeBlend {
105    fn resolve(
106        &self,
107        _acquired_nodes: &mut AcquiredNodes<'_>,
108        node: &Node,
109    ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
110        let cascaded = CascadedValues::new_from_node(node);
111        let values = cascaded.get();
112
113        let mut params = self.params.clone();
114        params.color_interpolation_filters = values.color_interpolation_filters();
115
116        Ok(vec![ResolvedPrimitive {
117            primitive: self.base.clone(),
118            params: PrimitiveParams::Blend(params),
119        }])
120    }
121}
122
123impl Parse for Mode {
124    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
125        Ok(parse_identifiers!(
126            parser,
127            "normal" => Mode::Normal,
128            "multiply" => Mode::Multiply,
129            "screen" => Mode::Screen,
130            "darken" => Mode::Darken,
131            "lighten" => Mode::Lighten,
132            "overlay" => Mode::Overlay,
133            "color-dodge" => Mode::ColorDodge,
134            "color-burn" => Mode::ColorBurn,
135            "hard-light" => Mode::HardLight,
136            "soft-light" => Mode::SoftLight,
137            "difference" => Mode::Difference,
138            "exclusion" => Mode::Exclusion,
139            "hue" => Mode::HslHue,
140            "saturation" => Mode::HslSaturation,
141            "color" => Mode::HslColor,
142            "luminosity" => Mode::HslLuminosity,
143        )?)
144    }
145}
146
147impl From<Mode> for Operator {
148    #[inline]
149    fn from(x: Mode) -> Self {
150        use Mode::*;
151
152        match x {
153            Normal => Operator::Over,
154            Multiply => Operator::Multiply,
155            Screen => Operator::Screen,
156            Darken => Operator::Darken,
157            Lighten => Operator::Lighten,
158            Overlay => Operator::Overlay,
159            ColorDodge => Operator::ColorDodge,
160            ColorBurn => Operator::ColorBurn,
161            HardLight => Operator::HardLight,
162            SoftLight => Operator::SoftLight,
163            Difference => Operator::Difference,
164            Exclusion => Operator::Exclusion,
165            HslHue => Operator::HslHue,
166            HslSaturation => Operator::HslSaturation,
167            HslColor => Operator::HslColor,
168            HslLuminosity => Operator::HslLuminosity,
169        }
170    }
171}