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 as SurfaceOperator;
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(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
25pub enum Operator {
26 #[default]
27 Over,
28 In,
29 Out,
30 Atop,
31 Xor,
32 Arithmetic,
33}
34
35#[derive(Default)]
37pub struct FeComposite {
38 base: Primitive,
39 params: Composite,
40}
41
42#[derive(Clone, Default)]
44pub struct Composite {
45 pub in1: Input,
46 pub in2: Input,
47 pub operator: Operator,
48 pub k1: f64,
49 pub k2: f64,
50 pub k3: f64,
51 pub k4: f64,
52 pub color_interpolation_filters: ColorInterpolationFilters,
53}
54
55impl ElementTrait for FeComposite {
56 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
57 let (in1, in2) = self.base.parse_two_inputs(attrs, session);
58 self.params.in1 = in1;
59 self.params.in2 = in2;
60
61 for (attr, value) in attrs.iter() {
62 match attr.expanded() {
63 expanded_name!("", "operator") => {
64 set_attribute(&mut self.params.operator, attr.parse(value), session)
65 }
66 expanded_name!("", "k1") => {
67 set_attribute(&mut self.params.k1, attr.parse(value), session)
68 }
69 expanded_name!("", "k2") => {
70 set_attribute(&mut self.params.k2, attr.parse(value), session)
71 }
72 expanded_name!("", "k3") => {
73 set_attribute(&mut self.params.k3, attr.parse(value), session)
74 }
75 expanded_name!("", "k4") => {
76 set_attribute(&mut self.params.k4, attr.parse(value), session)
77 }
78 _ => (),
79 }
80 }
81 }
82}
83
84impl Composite {
85 pub fn render(
86 &self,
87 bounds_builder: BoundsBuilder,
88 ctx: &FilterContext,
89 ) -> Result<FilterOutput, FilterError> {
90 let input_1 = ctx.get_input(&self.in1, self.color_interpolation_filters)?;
91 let input_2 = ctx.get_input(&self.in2, self.color_interpolation_filters)?;
92 let bounds: IRect = bounds_builder
93 .add_input(&input_1)
94 .add_input(&input_2)
95 .compute(ctx)
96 .clipped
97 .into();
98
99 let surface = if self.operator == Operator::Arithmetic {
100 input_1.surface().compose_arithmetic(
101 input_2.surface(),
102 bounds,
103 self.k1,
104 self.k2,
105 self.k3,
106 self.k4,
107 )?
108 } else {
109 input_1
110 .surface()
111 .compose(input_2.surface(), bounds, self.operator.into())?
112 };
113
114 Ok(FilterOutput { surface, bounds })
115 }
116
117 pub fn get_input_requirements(&self) -> InputRequirements {
118 self.in1
119 .get_requirements()
120 .fold(self.in2.get_requirements())
121 }
122}
123
124impl FilterEffect for FeComposite {
125 fn resolve(
126 &self,
127 _acquired_nodes: &mut AcquiredNodes<'_>,
128 node: &Node,
129 ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
130 let cascaded = CascadedValues::new_from_node(node);
131 let values = cascaded.get();
132
133 let mut params = self.params.clone();
134 params.color_interpolation_filters = values.color_interpolation_filters();
135
136 Ok(vec![ResolvedPrimitive {
137 primitive: self.base.clone(),
138 params: PrimitiveParams::Composite(params),
139 }])
140 }
141}
142
143impl Parse for Operator {
144 fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
145 Ok(parse_identifiers!(
146 parser,
147 "over" => Operator::Over,
148 "in" => Operator::In,
149 "out" => Operator::Out,
150 "atop" => Operator::Atop,
151 "xor" => Operator::Xor,
152 "arithmetic" => Operator::Arithmetic,
153 )?)
154 }
155}
156
157impl From<Operator> for SurfaceOperator {
158 #[inline]
159 fn from(x: Operator) -> SurfaceOperator {
160 use Operator::*;
161
162 match x {
163 Over => SurfaceOperator::Over,
164 In => SurfaceOperator::In,
165 Out => SurfaceOperator::Out,
166 Atop => SurfaceOperator::Atop,
167 Xor => SurfaceOperator::Xor,
168
169 _ => panic!("can't convert Operator::Arithmetic to a shared_surface::Operator"),
170 }
171 }
172}