1use std::cmp::min;
2
3use cssparser::Parser;
4use markup5ever::{expanded_name, local_name, ns};
5
6use crate::document::AcquiredNodes;
7use crate::element::{ElementData, ElementTrait, set_attribute};
8use crate::error::*;
9use crate::node::{CascadedValues, Node, NodeBorrow};
10use crate::parse_identifiers;
11use crate::parsers::{CommaSeparatedList, Parse, ParseValue};
12use crate::properties::ColorInterpolationFilters;
13use crate::rect::IRect;
14use crate::session::Session;
15use crate::surface_utils::{
16 ImageSurfaceDataExt, Pixel, iterators::Pixels, shared_surface::ExclusiveImageSurface,
17};
18use crate::util::clamp;
19use crate::xml::Attributes;
20
21use super::bounds::BoundsBuilder;
22use super::context::{FilterContext, FilterOutput};
23use super::{
24 FilterEffect, FilterError, FilterResolveError, Input, InputRequirements, Primitive,
25 PrimitiveParams, ResolvedPrimitive,
26};
27
28#[derive(Default)]
30pub struct FeComponentTransfer {
31 base: Primitive,
32 params: ComponentTransfer,
33}
34
35#[derive(Clone, Default)]
37pub struct ComponentTransfer {
38 pub in1: Input,
39 pub functions: Functions,
40 pub color_interpolation_filters: ColorInterpolationFilters,
41}
42
43impl ElementTrait for FeComponentTransfer {
44 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
45 self.params.in1 = self.base.parse_one_input(attrs, session);
46 }
47}
48
49#[derive(Clone, Debug, PartialEq)]
51pub enum FunctionType {
52 Identity,
53 Table,
54 Discrete,
55 Linear,
56 Gamma,
57}
58
59impl Parse for FunctionType {
60 fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
61 Ok(parse_identifiers!(
62 parser,
63 "identity" => FunctionType::Identity,
64 "table" => FunctionType::Table,
65 "discrete" => FunctionType::Discrete,
66 "linear" => FunctionType::Linear,
67 "gamma" => FunctionType::Gamma,
68 )?)
69 }
70}
71
72struct FunctionParameters {
74 table_values: Vec<f64>,
75 slope: f64,
76 intercept: f64,
77 amplitude: f64,
78 exponent: f64,
79 offset: f64,
80}
81
82#[derive(Clone, Debug, Default, PartialEq)]
83pub struct Functions {
84 pub r: FeFuncR,
85 pub g: FeFuncG,
86 pub b: FeFuncB,
87 pub a: FeFuncA,
88}
89
90type Function = fn(&FunctionParameters, f64) -> f64;
92
93fn identity(_: &FunctionParameters, value: f64) -> f64 {
95 value
96}
97
98fn table(params: &FunctionParameters, value: f64) -> f64 {
100 let n = params.table_values.len() - 1;
101 let k = (value * (n as f64)).floor() as usize;
102
103 let k = min(k, n); if k == n {
106 return params.table_values[k];
107 }
108
109 let vk = params.table_values[k];
110 let vk1 = params.table_values[k + 1];
111 let k = k as f64;
112 let n = n as f64;
113
114 vk + (value - k / n) * n * (vk1 - vk)
115}
116
117fn discrete(params: &FunctionParameters, value: f64) -> f64 {
119 let n = params.table_values.len();
120 let k = (value * (n as f64)).floor() as usize;
121
122 params.table_values[min(k, n - 1)]
123}
124
125fn linear(params: &FunctionParameters, value: f64) -> f64 {
127 params.slope * value + params.intercept
128}
129
130fn gamma(params: &FunctionParameters, value: f64) -> f64 {
132 params.amplitude * value.powf(params.exponent) + params.offset
133}
134
135#[derive(Clone, Debug, PartialEq)]
140pub struct FeFuncCommon {
141 pub function_type: FunctionType,
142 pub table_values: Vec<f64>,
143 pub slope: f64,
144 pub intercept: f64,
145 pub amplitude: f64,
146 pub exponent: f64,
147 pub offset: f64,
148}
149
150impl Default for FeFuncCommon {
151 #[inline]
152 fn default() -> Self {
153 Self {
154 function_type: FunctionType::Identity,
155 table_values: Vec::new(),
156 slope: 1.0,
157 intercept: 0.0,
158 amplitude: 1.0,
159 exponent: 1.0,
160 offset: 0.0,
161 }
162 }
163}
164
165macro_rules! impl_func {
168 ($(#[$attr:meta])*
169 $name:ident
170 ) => {
171 #[derive(Clone, Debug, Default, PartialEq)]
172 pub struct $name(pub FeFuncCommon);
173
174 impl ElementTrait for $name {
175 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
176 self.0.set_attributes(attrs, session);
177 }
178 }
179 };
180}
181
182impl_func!(
183 FeFuncR
185);
186
187impl_func!(
188 FeFuncG
190);
191
192impl_func!(
193 FeFuncB
195);
196
197impl_func!(
198 FeFuncA
200);
201
202impl FeFuncCommon {
203 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
204 for (attr, value) in attrs.iter() {
205 match attr.expanded() {
206 expanded_name!("", "type") => {
207 set_attribute(&mut self.function_type, attr.parse(value), session)
208 }
209 expanded_name!("", "tableValues") => {
210 let mut number_list = CommaSeparatedList::<f64, 0, 256>(Vec::new());
212 set_attribute(&mut number_list, attr.parse(value), session);
213 self.table_values = number_list.0;
214 }
215 expanded_name!("", "slope") => {
216 set_attribute(&mut self.slope, attr.parse(value), session)
217 }
218 expanded_name!("", "intercept") => {
219 set_attribute(&mut self.intercept, attr.parse(value), session)
220 }
221 expanded_name!("", "amplitude") => {
222 set_attribute(&mut self.amplitude, attr.parse(value), session)
223 }
224 expanded_name!("", "exponent") => {
225 set_attribute(&mut self.exponent, attr.parse(value), session)
226 }
227 expanded_name!("", "offset") => {
228 set_attribute(&mut self.offset, attr.parse(value), session)
229 }
230
231 _ => (),
232 }
233 }
234
235 match self.function_type {
238 FunctionType::Table | FunctionType::Discrete if self.table_values.is_empty() => {
239 self.function_type = FunctionType::Identity;
240 }
241 _ => (),
242 }
243 }
244
245 fn function_parameters(&self) -> FunctionParameters {
246 FunctionParameters {
247 table_values: self.table_values.clone(),
248 slope: self.slope,
249 intercept: self.intercept,
250 amplitude: self.amplitude,
251 exponent: self.exponent,
252 offset: self.offset,
253 }
254 }
255
256 fn function(&self) -> Function {
257 match self.function_type {
258 FunctionType::Identity => identity,
259 FunctionType::Table => table,
260 FunctionType::Discrete => discrete,
261 FunctionType::Linear => linear,
262 FunctionType::Gamma => gamma,
263 }
264 }
265}
266
267macro_rules! func_or_default {
268 ($func_node:ident, $func_type:ident) => {
269 match $func_node {
270 Some(ref f) => match &*f.borrow_element_data() {
271 ElementData::$func_type(e) => (**e).clone(),
272 _ => unreachable!(),
273 },
274 _ => $func_type::default(),
275 }
276 };
277}
278
279macro_rules! get_func_x_node {
280 ($func_node:ident, $func_type:ident) => {
281 $func_node
282 .children()
283 .rev()
284 .filter(|c| c.is_element())
285 .find(|c| matches!(*c.borrow_element_data(), ElementData::$func_type(_)))
286 };
287}
288
289impl ComponentTransfer {
290 pub fn render(
291 &self,
292 bounds_builder: BoundsBuilder,
293 ctx: &FilterContext,
294 ) -> Result<FilterOutput, FilterError> {
295 let input_1 = ctx.get_input(&self.in1, self.color_interpolation_filters)?;
296 let bounds: IRect = bounds_builder
297 .add_input(&input_1)
298 .compute(ctx)
299 .clipped
300 .into();
301
302 let mut surface = ExclusiveImageSurface::new(
304 ctx.source_graphic().width(),
305 ctx.source_graphic().height(),
306 input_1.surface().surface_type(),
307 )?;
308
309 fn compute_func(func: &FeFuncCommon) -> impl Fn(u8, f64, f64) -> u8 {
310 let compute = func.function();
311 let params = func.function_parameters();
312
313 move |value, alpha, new_alpha| {
314 let value = f64::from(value) / 255f64;
315
316 let unpremultiplied = if alpha == 0f64 { 0f64 } else { value / alpha };
317
318 let new_value = compute(¶ms, unpremultiplied);
319 let new_value = clamp(new_value, 0f64, 1f64);
320
321 ((new_value * new_alpha * 255f64) + 0.5) as u8
322 }
323 }
324
325 let compute_r = compute_func(&self.functions.r.0);
326 let compute_g = compute_func(&self.functions.g.0);
327 let compute_b = compute_func(&self.functions.b.0);
328
329 let compute_a = self.functions.a.0.function();
331 let params_a = self.functions.a.0.function_parameters();
332 let compute_a = |alpha| compute_a(¶ms_a, alpha);
333
334 surface.modify(&mut |data, stride| {
336 for (x, y, pixel) in Pixels::within(input_1.surface(), bounds) {
337 let alpha = f64::from(pixel.a) / 255f64;
338 let new_alpha = compute_a(alpha);
339
340 let output_pixel = Pixel {
341 r: compute_r(pixel.r, alpha, new_alpha),
342 g: compute_g(pixel.g, alpha, new_alpha),
343 b: compute_b(pixel.b, alpha, new_alpha),
344 a: ((new_alpha * 255f64) + 0.5) as u8,
345 };
346
347 data.set_pixel(stride, output_pixel, x, y);
348 }
349 });
350
351 Ok(FilterOutput {
352 surface: surface.share()?,
353 bounds,
354 })
355 }
356
357 pub fn get_input_requirements(&self) -> InputRequirements {
358 self.in1.get_requirements()
359 }
360}
361
362impl FilterEffect for FeComponentTransfer {
363 fn resolve(
364 &self,
365 _acquired_nodes: &mut AcquiredNodes<'_>,
366 node: &Node,
367 ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
368 let cascaded = CascadedValues::new_from_node(node);
369 let values = cascaded.get();
370
371 let mut params = self.params.clone();
372 params.functions = get_functions(node)?;
373 params.color_interpolation_filters = values.color_interpolation_filters();
374
375 Ok(vec![ResolvedPrimitive {
376 primitive: self.base.clone(),
377 params: PrimitiveParams::ComponentTransfer(params),
378 }])
379 }
380}
381
382fn get_functions(node: &Node) -> Result<Functions, FilterResolveError> {
384 let func_r_node = get_func_x_node!(node, FeFuncR);
385 let func_g_node = get_func_x_node!(node, FeFuncG);
386 let func_b_node = get_func_x_node!(node, FeFuncB);
387 let func_a_node = get_func_x_node!(node, FeFuncA);
388
389 let r = func_or_default!(func_r_node, FeFuncR);
390 let g = func_or_default!(func_g_node, FeFuncG);
391 let b = func_or_default!(func_b_node, FeFuncB);
392 let a = func_or_default!(func_a_node, FeFuncA);
393
394 Ok(Functions { r, g, b, a })
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400 use crate::document::Document;
401
402 #[test]
403 fn extracts_functions() {
404 let document = Document::load_from_bytes(
405 br#"<?xml version="1.0" encoding="UTF-8"?>
406<svg xmlns="http://www.w3.org/2000/svg">
407 <filter id="filter">
408 <feComponentTransfer id="component_transfer">
409 <!-- no feFuncR so it should get the defaults -->
410
411 <feFuncG type="table" tableValues="0.0 1.0 2.0"/>
412
413 <feFuncB type="table"/>
414 <!-- duplicate this to test that last-one-wins -->
415 <feFuncB type="discrete" tableValues="0.0, 1.0" slope="1.0" intercept="2.0" amplitude="3.0" exponent="4.0" offset="5.0"/>
416
417 <!-- no feFuncA so it should get the defaults -->
418 </feComponentTransfer>
419 </filter>
420</svg>
421"#
422 );
423
424 let component_transfer = document.lookup_internal_node("component_transfer").unwrap();
425 let functions = get_functions(&component_transfer).unwrap();
426
427 assert_eq!(
428 functions,
429 Functions {
430 r: FeFuncR::default(),
431
432 g: FeFuncG(FeFuncCommon {
433 function_type: FunctionType::Table,
434 table_values: vec![0.0, 1.0, 2.0],
435 ..FeFuncCommon::default()
436 }),
437
438 b: FeFuncB(FeFuncCommon {
439 function_type: FunctionType::Discrete,
440 table_values: vec![0.0, 1.0],
441 slope: 1.0,
442 intercept: 2.0,
443 amplitude: 3.0,
444 exponent: 4.0,
445 offset: 5.0,
446 }),
447
448 a: FeFuncA::default(),
449 }
450 );
451 }
452}