1
use cssparser::Parser;
2
use markup5ever::{expanded_name, local_name, namespace_url, ns};
3

            
4
use crate::document::AcquiredNodes;
5
use crate::drawing_ctx::DrawingCtx;
6
use crate::element::{set_attribute, ElementTrait};
7
use crate::error::*;
8
use crate::node::{CascadedValues, Node};
9
use crate::parse_identifiers;
10
use crate::parsers::{Parse, ParseValue};
11
use crate::properties::ColorInterpolationFilters;
12
use crate::rect::IRect;
13
use crate::session::Session;
14
use crate::surface_utils::shared_surface::Operator;
15
use crate::xml::Attributes;
16

            
17
use super::bounds::BoundsBuilder;
18
use super::context::{FilterContext, FilterOutput};
19
use super::{
20
    FilterEffect, FilterError, FilterResolveError, Input, Primitive, PrimitiveParams,
21
    ResolvedPrimitive,
22
};
23

            
24
/// Enumeration of the possible blending modes.
25
22
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
26
enum Mode {
27
    #[default]
28
7
    Normal,
29
    Multiply,
30
    Screen,
31
    Darken,
32
    Lighten,
33
    Overlay,
34
    ColorDodge,
35
    ColorBurn,
36
    HardLight,
37
    SoftLight,
38
    Difference,
39
    Exclusion,
40
    HslHue,
41
    HslSaturation,
42
    HslColor,
43
    HslLuminosity,
44
}
45

            
46
/// The `feBlend` filter primitive.
47
7
#[derive(Default)]
48
pub struct FeBlend {
49
7
    base: Primitive,
50
7
    params: Blend,
51
}
52

            
53
/// Resolved `feBlend` primitive for rendering.
54
30
#[derive(Clone, Default)]
55
pub struct Blend {
56
15
    in1: Input,
57
15
    in2: Input,
58
15
    mode: Mode,
59
15
    color_interpolation_filters: ColorInterpolationFilters,
60
}
61

            
62
impl ElementTrait for FeBlend {
63
7
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
64
7
        let (in1, in2) = self.base.parse_two_inputs(attrs, session);
65
7
        self.params.in1 = in1;
66
7
        self.params.in2 = in2;
67

            
68
7
        for (attr, value) in attrs.iter() {
69
22
            if let expanded_name!("", "mode") = attr.expanded() {
70
7
                set_attribute(&mut self.params.mode, attr.parse(value), session);
71
            }
72
22
        }
73
7
    }
74
}
75

            
76
impl Blend {
77
7
    pub fn render(
78
        &self,
79
        bounds_builder: BoundsBuilder,
80
        ctx: &FilterContext,
81
        acquired_nodes: &mut AcquiredNodes<'_>,
82
        draw_ctx: &mut DrawingCtx,
83
    ) -> Result<FilterOutput, FilterError> {
84
7
        let input_1 = ctx.get_input(
85
            acquired_nodes,
86
            draw_ctx,
87
            &self.in1,
88
7
            self.color_interpolation_filters,
89
        )?;
90
7
        let input_2 = ctx.get_input(
91
            acquired_nodes,
92
            draw_ctx,
93
7
            &self.in2,
94
7
            self.color_interpolation_filters,
95
        )?;
96
7
        let bounds: IRect = bounds_builder
97
            .add_input(&input_1)
98
            .add_input(&input_2)
99
            .compute(ctx)
100
            .clipped
101
            .into();
102

            
103
14
        let surface = input_1
104
            .surface()
105
7
            .compose(input_2.surface(), bounds, self.mode.into())?;
106

            
107
7
        Ok(FilterOutput { surface, bounds })
108
7
    }
109
}
110

            
111
impl FilterEffect for FeBlend {
112
8
    fn resolve(
113
        &self,
114
        _acquired_nodes: &mut AcquiredNodes<'_>,
115
        node: &Node,
116
    ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
117
8
        let cascaded = CascadedValues::new_from_node(node);
118
8
        let values = cascaded.get();
119

            
120
8
        let mut params = self.params.clone();
121
8
        params.color_interpolation_filters = values.color_interpolation_filters();
122

            
123
8
        Ok(vec![ResolvedPrimitive {
124
8
            primitive: self.base.clone(),
125
8
            params: PrimitiveParams::Blend(params),
126
        }])
127
8
    }
128
}
129

            
130
impl Parse for Mode {
131
7
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
132
14
        Ok(parse_identifiers!(
133
            parser,
134
            "normal" => Mode::Normal,
135
            "multiply" => Mode::Multiply,
136
            "screen" => Mode::Screen,
137
            "darken" => Mode::Darken,
138
            "lighten" => Mode::Lighten,
139
            "overlay" => Mode::Overlay,
140
            "color-dodge" => Mode::ColorDodge,
141
            "color-burn" => Mode::ColorBurn,
142
            "hard-light" => Mode::HardLight,
143
            "soft-light" => Mode::SoftLight,
144
            "difference" => Mode::Difference,
145
            "exclusion" => Mode::Exclusion,
146
            "hue" => Mode::HslHue,
147
            "saturation" => Mode::HslSaturation,
148
            "color" => Mode::HslColor,
149
            "luminosity" => Mode::HslLuminosity,
150
        )?)
151
7
    }
152
}
153

            
154
impl From<Mode> for Operator {
155
    #[inline]
156
7
    fn from(x: Mode) -> Self {
157
        use Mode::*;
158

            
159
7
        match x {
160
1
            Normal => Operator::Over,
161
3
            Multiply => Operator::Multiply,
162
1
            Screen => Operator::Screen,
163
1
            Darken => Operator::Darken,
164
1
            Lighten => Operator::Lighten,
165
            Overlay => Operator::Overlay,
166
            ColorDodge => Operator::ColorDodge,
167
            ColorBurn => Operator::ColorBurn,
168
            HardLight => Operator::HardLight,
169
            SoftLight => Operator::SoftLight,
170
            Difference => Operator::Difference,
171
            Exclusion => Operator::Exclusion,
172
            HslHue => Operator::HslHue,
173
            HslSaturation => Operator::HslSaturation,
174
            HslColor => Operator::HslColor,
175
            HslLuminosity => Operator::HslLuminosity,
176
        }
177
7
    }
178
}