1use std::cmp::min;
2
3use cssparser::Parser;
4use markup5ever::{expanded_name, local_name, ns};
5
6use crate::document::AcquiredNodes;
7use crate::element::{set_attribute, ElementData, ElementTrait};
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 iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
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 => {
239 if self.table_values.is_empty() {
240 self.function_type = FunctionType::Identity;
241 }
242 }
243 _ => (),
244 }
245 }
246
247 fn function_parameters(&self) -> FunctionParameters {
248 FunctionParameters {
249 table_values: self.table_values.clone(),
250 slope: self.slope,
251 intercept: self.intercept,
252 amplitude: self.amplitude,
253 exponent: self.exponent,
254 offset: self.offset,
255 }
256 }
257
258 fn function(&self) -> Function {
259 match self.function_type {
260 FunctionType::Identity => identity,
261 FunctionType::Table => table,
262 FunctionType::Discrete => discrete,
263 FunctionType::Linear => linear,
264 FunctionType::Gamma => gamma,
265 }
266 }
267}
268
269macro_rules! func_or_default {
270 ($func_node:ident, $func_type:ident) => {
271 match $func_node {
272 Some(ref f) => match &*f.borrow_element_data() {
273 ElementData::$func_type(e) => (**e).clone(),
274 _ => unreachable!(),
275 },
276 _ => $func_type::default(),
277 }
278 };
279}
280
281macro_rules! get_func_x_node {
282 ($func_node:ident, $func_type:ident) => {
283 $func_node
284 .children()
285 .rev()
286 .filter(|c| c.is_element())
287 .find(|c| matches!(*c.borrow_element_data(), ElementData::$func_type(_)))
288 };
289}
290
291impl ComponentTransfer {
292 pub fn render(
293 &self,
294 bounds_builder: BoundsBuilder,
295 ctx: &FilterContext,
296 ) -> Result<FilterOutput, FilterError> {
297 let input_1 = ctx.get_input(&self.in1, self.color_interpolation_filters)?;
298 let bounds: IRect = bounds_builder
299 .add_input(&input_1)
300 .compute(ctx)
301 .clipped
302 .into();
303
304 let mut surface = ExclusiveImageSurface::new(
306 ctx.source_graphic().width(),
307 ctx.source_graphic().height(),
308 input_1.surface().surface_type(),
309 )?;
310
311 fn compute_func(func: &FeFuncCommon) -> impl Fn(u8, f64, f64) -> u8 {
312 let compute = func.function();
313 let params = func.function_parameters();
314
315 move |value, alpha, new_alpha| {
316 let value = f64::from(value) / 255f64;
317
318 let unpremultiplied = if alpha == 0f64 { 0f64 } else { value / alpha };
319
320 let new_value = compute(¶ms, unpremultiplied);
321 let new_value = clamp(new_value, 0f64, 1f64);
322
323 ((new_value * new_alpha * 255f64) + 0.5) as u8
324 }
325 }
326
327 let compute_r = compute_func(&self.functions.r.0);
328 let compute_g = compute_func(&self.functions.g.0);
329 let compute_b = compute_func(&self.functions.b.0);
330
331 let compute_a = self.functions.a.0.function();
333 let params_a = self.functions.a.0.function_parameters();
334 let compute_a = |alpha| compute_a(¶ms_a, alpha);
335
336 surface.modify(&mut |data, stride| {
338 for (x, y, pixel) in Pixels::within(input_1.surface(), bounds) {
339 let alpha = f64::from(pixel.a) / 255f64;
340 let new_alpha = compute_a(alpha);
341
342 let output_pixel = Pixel {
343 r: compute_r(pixel.r, alpha, new_alpha),
344 g: compute_g(pixel.g, alpha, new_alpha),
345 b: compute_b(pixel.b, alpha, new_alpha),
346 a: ((new_alpha * 255f64) + 0.5) as u8,
347 };
348
349 data.set_pixel(stride, output_pixel, x, y);
350 }
351 });
352
353 Ok(FilterOutput {
354 surface: surface.share()?,
355 bounds,
356 })
357 }
358
359 pub fn get_input_requirements(&self) -> InputRequirements {
360 self.in1.get_requirements()
361 }
362}
363
364impl FilterEffect for FeComponentTransfer {
365 fn resolve(
366 &self,
367 _acquired_nodes: &mut AcquiredNodes<'_>,
368 node: &Node,
369 ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
370 let cascaded = CascadedValues::new_from_node(node);
371 let values = cascaded.get();
372
373 let mut params = self.params.clone();
374 params.functions = get_functions(node)?;
375 params.color_interpolation_filters = values.color_interpolation_filters();
376
377 Ok(vec![ResolvedPrimitive {
378 primitive: self.base.clone(),
379 params: PrimitiveParams::ComponentTransfer(params),
380 }])
381 }
382}
383
384fn get_functions(node: &Node) -> Result<Functions, FilterResolveError> {
386 let func_r_node = get_func_x_node!(node, FeFuncR);
387 let func_g_node = get_func_x_node!(node, FeFuncG);
388 let func_b_node = get_func_x_node!(node, FeFuncB);
389 let func_a_node = get_func_x_node!(node, FeFuncA);
390
391 let r = func_or_default!(func_r_node, FeFuncR);
392 let g = func_or_default!(func_g_node, FeFuncG);
393 let b = func_or_default!(func_b_node, FeFuncB);
394 let a = func_or_default!(func_a_node, FeFuncA);
395
396 Ok(Functions { r, g, b, a })
397}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402 use crate::document::Document;
403
404 #[test]
405 fn extracts_functions() {
406 let document = Document::load_from_bytes(
407 br#"<?xml version="1.0" encoding="UTF-8"?>
408<svg xmlns="http://www.w3.org/2000/svg">
409 <filter id="filter">
410 <feComponentTransfer id="component_transfer">
411 <!-- no feFuncR so it should get the defaults -->
412
413 <feFuncG type="table" tableValues="0.0 1.0 2.0"/>
414
415 <feFuncB type="table"/>
416 <!-- duplicate this to test that last-one-wins -->
417 <feFuncB type="discrete" tableValues="0.0, 1.0" slope="1.0" intercept="2.0" amplitude="3.0" exponent="4.0" offset="5.0"/>
418
419 <!-- no feFuncA so it should get the defaults -->
420 </feComponentTransfer>
421 </filter>
422</svg>
423"#
424 );
425
426 let component_transfer = document.lookup_internal_node("component_transfer").unwrap();
427 let functions = get_functions(&component_transfer).unwrap();
428
429 assert_eq!(
430 functions,
431 Functions {
432 r: FeFuncR::default(),
433
434 g: FeFuncG(FeFuncCommon {
435 function_type: FunctionType::Table,
436 table_values: vec![0.0, 1.0, 2.0],
437 ..FeFuncCommon::default()
438 }),
439
440 b: FeFuncB(FeFuncCommon {
441 function_type: FunctionType::Discrete,
442 table_values: vec![0.0, 1.0],
443 slope: 1.0,
444 intercept: 2.0,
445 amplitude: 3.0,
446 exponent: 4.0,
447 offset: 5.0,
448 }),
449
450 a: FeFuncA::default(),
451 }
452 );
453 }
454}