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 as SurfaceOperator;
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 compositing operations.
25
154
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
26
pub enum Operator {
27
    #[default]
28
38
    Over,
29
    In,
30
    Out,
31
    Atop,
32
    Xor,
33
    Arithmetic,
34
}
35

            
36
/// The `feComposite` filter primitive.
37
36
#[derive(Default)]
38
pub struct FeComposite {
39
36
    base: Primitive,
40
36
    params: Composite,
41
}
42

            
43
/// Resolved `feComposite` primitive for rendering.
44
152
#[derive(Clone, Default)]
45
pub struct Composite {
46
76
    pub in1: Input,
47
76
    pub in2: Input,
48
76
    pub operator: Operator,
49
76
    pub k1: f64,
50
76
    pub k2: f64,
51
76
    pub k3: f64,
52
76
    pub k4: f64,
53
76
    pub color_interpolation_filters: ColorInterpolationFilters,
54
}
55

            
56
impl ElementTrait for FeComposite {
57
36
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
58
36
        let (in1, in2) = self.base.parse_two_inputs(attrs, session);
59
36
        self.params.in1 = in1;
60
36
        self.params.in2 = in2;
61

            
62
36
        for (attr, value) in attrs.iter() {
63
150
            match attr.expanded() {
64
                expanded_name!("", "operator") => {
65
35
                    set_attribute(&mut self.params.operator, attr.parse(value), session)
66
                }
67
                expanded_name!("", "k1") => {
68
11
                    set_attribute(&mut self.params.k1, attr.parse(value), session)
69
                }
70
                expanded_name!("", "k2") => {
71
12
                    set_attribute(&mut self.params.k2, attr.parse(value), session)
72
                }
73
                expanded_name!("", "k3") => {
74
12
                    set_attribute(&mut self.params.k3, attr.parse(value), session)
75
                }
76
                expanded_name!("", "k4") => {
77
11
                    set_attribute(&mut self.params.k4, attr.parse(value), session)
78
                }
79
                _ => (),
80
            }
81
150
        }
82
36
    }
83
}
84

            
85
impl Composite {
86
40
    pub fn render(
87
        &self,
88
        bounds_builder: BoundsBuilder,
89
        ctx: &FilterContext,
90
        acquired_nodes: &mut AcquiredNodes<'_>,
91
        draw_ctx: &mut DrawingCtx,
92
    ) -> Result<FilterOutput, FilterError> {
93
40
        let input_1 = ctx.get_input(
94
            acquired_nodes,
95
            draw_ctx,
96
            &self.in1,
97
40
            self.color_interpolation_filters,
98
        )?;
99
40
        let input_2 = ctx.get_input(
100
            acquired_nodes,
101
            draw_ctx,
102
40
            &self.in2,
103
40
            self.color_interpolation_filters,
104
        )?;
105
40
        let bounds: IRect = bounds_builder
106
            .add_input(&input_1)
107
            .add_input(&input_2)
108
            .compute(ctx)
109
            .clipped
110
            .into();
111

            
112
80
        let surface = if self.operator == Operator::Arithmetic {
113
24
            input_1.surface().compose_arithmetic(
114
12
                input_2.surface(),
115
                bounds,
116
12
                self.k1,
117
12
                self.k2,
118
12
                self.k3,
119
12
                self.k4,
120
            )?
121
        } else {
122
56
            input_1
123
                .surface()
124
28
                .compose(input_2.surface(), bounds, self.operator.into())?
125
        };
126

            
127
40
        Ok(FilterOutput { surface, bounds })
128
40
    }
129
}
130

            
131
impl FilterEffect for FeComposite {
132
38
    fn resolve(
133
        &self,
134
        _acquired_nodes: &mut AcquiredNodes<'_>,
135
        node: &Node,
136
    ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
137
38
        let cascaded = CascadedValues::new_from_node(node);
138
38
        let values = cascaded.get();
139

            
140
38
        let mut params = self.params.clone();
141
38
        params.color_interpolation_filters = values.color_interpolation_filters();
142

            
143
38
        Ok(vec![ResolvedPrimitive {
144
38
            primitive: self.base.clone(),
145
38
            params: PrimitiveParams::Composite(params),
146
        }])
147
38
    }
148
}
149

            
150
impl Parse for Operator {
151
35
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
152
35
        Ok(parse_identifiers!(
153
            parser,
154
            "over" => Operator::Over,
155
            "in" => Operator::In,
156
            "out" => Operator::Out,
157
            "atop" => Operator::Atop,
158
            "xor" => Operator::Xor,
159
            "arithmetic" => Operator::Arithmetic,
160
        )?)
161
35
    }
162
}
163

            
164
impl From<Operator> for SurfaceOperator {
165
    #[inline]
166
28
    fn from(x: Operator) -> SurfaceOperator {
167
        use Operator::*;
168

            
169
28
        match x {
170
3
            Over => SurfaceOperator::Over,
171
18
            In => SurfaceOperator::In,
172
3
            Out => SurfaceOperator::Out,
173
2
            Atop => SurfaceOperator::Atop,
174
2
            Xor => SurfaceOperator::Xor,
175

            
176
            _ => panic!("can't convert Operator::Arithmetic to a shared_surface::Operator"),
177
        }
178
28
    }
179
}