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#[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#[derive(Default)]
47pub struct FeBlend {
48 base: Primitive,
49 params: Blend,
50}
51
52#[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}