1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0. If a copy of the MPL was not distributed with this
3 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 
5 use std::cmp;
6 use std::rc::Rc;
7 
8 use rgb::FromSlice;
9 use log::warn;
10 use usvg::ColorInterpolation as ColorSpace;
11 
12 use crate::prelude::*;
13 use crate::filter::{self, Filter, ImageExt, IntoSvgFilters, Error};
14 use crate::ConvTransform;
15 use super::ReCairoContextExt;
16 
17 type Image = filter::Image<cairo::ImageSurface>;
18 type FilterInputs<'a> = filter::FilterInputs<'a, cairo::ImageSurface>;
19 type FilterResult = filter::FilterResult<cairo::ImageSurface>;
20 
21 
apply( filter: &usvg::Filter, bbox: Option<Rect>, ts: &usvg::Transform, opt: &Options, tree: &usvg::Tree, background: Option<&cairo::ImageSurface>, fill_paint: Option<&cairo::ImageSurface>, stroke_paint: Option<&cairo::ImageSurface>, canvas: &mut cairo::ImageSurface, )22 pub fn apply(
23     filter: &usvg::Filter,
24     bbox: Option<Rect>,
25     ts: &usvg::Transform,
26     opt: &Options,
27     tree: &usvg::Tree,
28     background: Option<&cairo::ImageSurface>,
29     fill_paint: Option<&cairo::ImageSurface>,
30     stroke_paint: Option<&cairo::ImageSurface>,
31     canvas: &mut cairo::ImageSurface,
32 ) {
33     CairoFilter::apply(filter, bbox, ts, opt, tree, background, fill_paint, stroke_paint, canvas);
34 }
35 
36 
37 impl ImageExt for cairo::ImageSurface {
width(&self) -> u3238     fn width(&self) -> u32 {
39         self.get_width() as u32
40     }
41 
height(&self) -> u3242     fn height(&self) -> u32 {
43         self.get_height() as u32
44     }
45 
try_clone(&self) -> Result<Self, Error>46     fn try_clone(&self) -> Result<Self, Error> {
47         let new_image = create_image(self.width(), self.height())?;
48 
49         let cr = cairo::Context::new(&new_image);
50         cr.set_source_surface(self, 0.0, 0.0);
51         cr.paint();
52 
53         Ok(new_image)
54     }
55 
clip(&mut self, region: ScreenRect)56     fn clip(&mut self, region: ScreenRect) {
57         let cr = cairo::Context::new(self);
58         cr.set_source_rgba(0.0, 0.0, 0.0, 0.0);
59         cr.set_operator(cairo::Operator::Clear);
60 
61         cr.rectangle(0.0, 0.0, self.width() as f64, region.y() as f64);
62         cr.rectangle(0.0, 0.0, region.x() as f64, self.height() as f64);
63         cr.rectangle(region.right() as f64, 0.0, self.width() as f64, self.height() as f64);
64         cr.rectangle(0.0, region.bottom() as f64, self.width() as f64, self.height() as f64);
65 
66         cr.fill();
67     }
68 
clear(&mut self)69     fn clear(&mut self) {
70         let cr = cairo::Context::new(self);
71         cr.set_operator(cairo::Operator::Clear);
72         cr.set_source_rgba(0.0, 0.0, 0.0, 0.0);
73         cr.paint();
74     }
75 
into_srgb(&mut self)76     fn into_srgb(&mut self) {
77         if let Ok(ref mut data) = self.get_data() {
78             svgfilters::demultiply_alpha(data.as_bgra_mut());
79             svgfilters::from_linear_rgb(data.as_bgra_mut());
80             svgfilters::multiply_alpha(data.as_bgra_mut());
81         } else {
82             warn!("Cairo surface is already borrowed.");
83         }
84     }
85 
into_linear_rgb(&mut self)86     fn into_linear_rgb(&mut self) {
87         if let Ok(ref mut data) = self.get_data() {
88             svgfilters::demultiply_alpha(data.as_bgra_mut());
89             svgfilters::into_linear_rgb(data.as_bgra_mut());
90             svgfilters::multiply_alpha(data.as_bgra_mut());
91         } else {
92             warn!("Cairo surface is already borrowed.");
93         }
94     }
95 }
96 
create_image(width: u32, height: u32) -> Result<cairo::ImageSurface, Error>97 fn create_image(width: u32, height: u32) -> Result<cairo::ImageSurface, Error> {
98     cairo::ImageSurface::create(cairo::Format::ARgb32, width as i32, height as i32)
99         .map_err(|_| Error::AllocFailed)
100 }
101 
copy_image( image: &cairo::ImageSurface, region: ScreenRect, ) -> Result<cairo::ImageSurface, Error>102 fn copy_image(
103     image: &cairo::ImageSurface,
104     region: ScreenRect,
105 ) -> Result<cairo::ImageSurface, Error> {
106     let x = cmp::max(0, region.x()) as f64;
107     let y = cmp::max(0, region.y()) as f64;
108 
109     let new_image = create_image(region.width(), region.height())?;
110 
111     let cr = cairo::Context::new(&new_image);
112     cr.set_source_surface(&*image, -x, -y);
113     cr.paint();
114 
115     Ok(new_image)
116 }
117 
118 struct CairoFilter;
119 
120 impl Filter<cairo::ImageSurface> for CairoFilter {
get_input( input: &usvg::FilterInput, region: ScreenRect, inputs: &FilterInputs, results: &[FilterResult], ) -> Result<Image, Error>121     fn get_input(
122         input: &usvg::FilterInput,
123         region: ScreenRect,
124         inputs: &FilterInputs,
125         results: &[FilterResult],
126     ) -> Result<Image, Error> {
127         let convert = |in_image, region| {
128             let image = if let Some(image) = in_image {
129                 copy_image(image, region)?
130             } else {
131                 create_image(region.width(), region.height())?
132             };
133 
134             Ok(Image {
135                 image: Rc::new(image),
136                 region: region.translate_to(0, 0),
137                 color_space: ColorSpace::SRGB,
138             })
139         };
140 
141         let convert_alpha = |mut image: cairo::ImageSurface| {
142             // Set RGB to black. Keep alpha as is.
143             if let Ok(ref mut data) = image.get_data() {
144                 for p in data.chunks_mut(4) {
145                     p[0] = 0;
146                     p[1] = 0;
147                     p[2] = 0;
148                 }
149             } else {
150                 warn!("Cairo surface is already borrowed.");
151             }
152 
153             Ok(Image {
154                 image: Rc::new(image),
155                 region: region.translate_to(0, 0),
156                 color_space: ColorSpace::SRGB,
157             })
158         };
159 
160         match input {
161             usvg::FilterInput::SourceGraphic => {
162                 let image = copy_image(inputs.source, region)?;
163 
164                 Ok(Image {
165                     image: Rc::new(image),
166                     region: region.translate_to(0, 0),
167                     color_space: ColorSpace::SRGB,
168                 })
169             }
170             usvg::FilterInput::SourceAlpha => {
171                 let image = copy_image(inputs.source, region)?;
172                 convert_alpha(image)
173             }
174             usvg::FilterInput::BackgroundImage => {
175                 convert(inputs.background, region)
176             }
177             usvg::FilterInput::BackgroundAlpha => {
178                 let image = Self::get_input(
179                     &usvg::FilterInput::BackgroundImage, region, inputs, results,
180                 )?;
181                 let image = image.take()?;
182                 convert_alpha(image)
183             }
184             usvg::FilterInput::FillPaint => {
185                 convert(inputs.fill_paint, region.translate_to(0, 0))
186             }
187             usvg::FilterInput::StrokePaint => {
188                 convert(inputs.stroke_paint, region.translate_to(0, 0))
189             }
190             usvg::FilterInput::Reference(ref name) => {
191                 if let Some(ref v) = results.iter().rev().find(|v| v.name == *name) {
192                     Ok(v.image.clone())
193                 } else {
194                     // Technically unreachable.
195                     warn!("Unknown filter primitive reference '{}'.", name);
196                     Self::get_input(&usvg::FilterInput::SourceGraphic, region, inputs, results)
197                 }
198             }
199         }
200     }
201 
apply_blur( fe: &usvg::FeGaussianBlur, units: usvg::Units, cs: ColorSpace, bbox: Option<Rect>, ts: &usvg::Transform, input: Image, ) -> Result<Image, Error>202     fn apply_blur(
203         fe: &usvg::FeGaussianBlur,
204         units: usvg::Units,
205         cs: ColorSpace,
206         bbox: Option<Rect>,
207         ts: &usvg::Transform,
208         input: Image,
209     ) -> Result<Image, Error> {
210         let (std_dx, std_dy, box_blur)
211             = try_opt_or!(Self::resolve_std_dev(fe, units, bbox, ts), Ok(input));
212 
213         let mut buffer = input.into_color_space(cs)?.take()?;
214         let (w, h) = (buffer.width(), buffer.height());
215         if let Ok(ref mut data) = buffer.get_data() {
216             let img = svgfilters::ImageRefMut::new(data.as_bgra_mut(), w, h);
217             if box_blur {
218                 svgfilters::box_blur(std_dx, std_dy, img);
219             } else {
220                 svgfilters::iir_blur(std_dx, std_dy, img);
221             }
222         }
223 
224         Ok(Image::from_image(buffer, cs))
225     }
226 
apply_offset( fe: &usvg::FeOffset, units: usvg::Units, bbox: Option<Rect>, ts: &usvg::Transform, input: Image, ) -> Result<Image, Error>227     fn apply_offset(
228         fe: &usvg::FeOffset,
229         units: usvg::Units,
230         bbox: Option<Rect>,
231         ts: &usvg::Transform,
232         input: Image,
233     ) -> Result<Image, Error> {
234         let (dx, dy) = try_opt_or!(Self::scale_coordinates(fe.dx, fe.dy, units, bbox, ts), Ok(input));
235         if dx.is_fuzzy_zero() && dy.is_fuzzy_zero() {
236             return Ok(input);
237         }
238 
239         // TODO: do not use an additional buffer
240         let buffer = create_image(input.width(), input.height())?;
241 
242         let cr = cairo::Context::new(&buffer);
243         cr.set_source_surface(input.as_ref(), dx, dy);
244         cr.paint();
245 
246         Ok(Image::from_image(buffer, input.color_space))
247     }
248 
apply_blend( fe: &usvg::FeBlend, cs: ColorSpace, region: ScreenRect, input1: Image, input2: Image, ) -> Result<Image, Error>249     fn apply_blend(
250         fe: &usvg::FeBlend,
251         cs: ColorSpace,
252         region: ScreenRect,
253         input1: Image,
254         input2: Image,
255     ) -> Result<Image, Error> {
256         let input1 = input1.into_color_space(cs)?;
257         let input2 = input2.into_color_space(cs)?;
258 
259         let buffer = create_image(region.width(), region.height())?;
260         let cr = cairo::Context::new(&buffer);
261 
262         cr.set_source_surface(input2.as_ref(), 0.0, 0.0);
263         cr.paint();
264 
265         let operator = match fe.mode {
266             usvg::FeBlendMode::Normal => cairo::Operator::Over,
267             usvg::FeBlendMode::Multiply => cairo::Operator::Multiply,
268             usvg::FeBlendMode::Screen => cairo::Operator::Screen,
269             usvg::FeBlendMode::Darken => cairo::Operator::Darken,
270             usvg::FeBlendMode::Lighten => cairo::Operator::Lighten,
271         };
272 
273         cr.set_operator(operator);
274         cr.set_source_surface(input1.as_ref(), 0.0, 0.0);
275         cr.paint();
276 
277         Ok(Image::from_image(buffer, cs))
278     }
279 
apply_composite( fe: &usvg::FeComposite, cs: ColorSpace, region: ScreenRect, input1: Image, input2: Image, ) -> Result<Image, Error>280     fn apply_composite(
281         fe: &usvg::FeComposite,
282         cs: ColorSpace,
283         region: ScreenRect,
284         input1: Image,
285         input2: Image,
286     ) -> Result<Image, Error> {
287         let mut buffer1 = input1.into_color_space(cs)?.take()?;
288         let mut buffer2 = input2.into_color_space(cs)?.take()?;
289 
290         let mut buffer = create_image(region.width(), region.height())?;
291 
292         if let Operator::Arithmetic { k1, k2, k3, k4 } = fe.operator {
293             let (w, h) = (region.width(), region.height());
294             svgfilters::arithmetic_composite(
295                 k1, k2, k3, k4,
296                 svgfilters::ImageRef::new(buffer1.get_data().unwrap().as_bgra(), w, h),
297                 svgfilters::ImageRef::new(buffer2.get_data().unwrap().as_bgra(), w, h),
298                 svgfilters::ImageRefMut::new(buffer.get_data().unwrap().as_bgra_mut(), w, h),
299             );
300 
301             return Ok(Image::from_image(buffer, cs));
302         }
303 
304         let cr = cairo::Context::new(&buffer);
305 
306         cr.set_source_surface(&buffer2, 0.0, 0.0);
307         cr.paint();
308 
309         use usvg::FeCompositeOperator as Operator;
310         let operator = match fe.operator {
311             Operator::Over => cairo::Operator::Over,
312             Operator::In => cairo::Operator::In,
313             Operator::Out => cairo::Operator::Out,
314             Operator::Atop => cairo::Operator::Atop,
315             Operator::Xor => cairo::Operator::Xor,
316             Operator::Arithmetic { .. } => cairo::Operator::Over,
317         };
318 
319         cr.set_operator(operator);
320         cr.set_source_surface(&buffer1, 0.0, 0.0);
321         cr.paint();
322 
323         Ok(Image::from_image(buffer, cs))
324     }
325 
apply_merge( fe: &usvg::FeMerge, cs: ColorSpace, region: ScreenRect, inputs: &FilterInputs, results: &[FilterResult], ) -> Result<Image, Error>326     fn apply_merge(
327         fe: &usvg::FeMerge,
328         cs: ColorSpace,
329         region: ScreenRect,
330         inputs: &FilterInputs,
331         results: &[FilterResult],
332     ) -> Result<Image, Error> {
333         let buffer = create_image(region.width(), region.height())?;
334         let cr = cairo::Context::new(&buffer);
335 
336         for input in &fe.inputs {
337             let input = Self::get_input(input, region, inputs, results)?;
338             let input = input.into_color_space(cs)?;
339 
340             cr.set_source_surface(input.as_ref(), 0.0, 0.0);
341             cr.paint();
342         }
343 
344         Ok(Image::from_image(buffer, cs))
345     }
346 
apply_flood( fe: &usvg::FeFlood, region: ScreenRect, ) -> Result<Image, Error>347     fn apply_flood(
348         fe: &usvg::FeFlood,
349         region: ScreenRect,
350     ) -> Result<Image, Error> {
351         let buffer = create_image(region.width(), region.height())?;
352 
353         let cr = cairo::Context::new(&buffer);
354         cr.set_source_color(fe.color, fe.opacity);
355         cr.paint();
356 
357         Ok(Image::from_image(buffer, ColorSpace::SRGB))
358     }
359 
apply_tile( input: Image, region: ScreenRect, ) -> Result<Image, Error>360     fn apply_tile(
361         input: Image,
362         region: ScreenRect,
363     ) -> Result<Image, Error> {
364         let buffer = create_image(region.width(), region.height())?;
365 
366         let subregion = input.region.translate(-region.x(), -region.y());
367 
368         let tile = copy_image(&input.image, subregion)?;
369         let brush_ts = usvg::Transform::new_translate(subregion.x() as f64, subregion.y() as f64);
370 
371         let patt = cairo::SurfacePattern::create(&tile);
372         patt.set_extend(cairo::Extend::Repeat);
373         patt.set_filter(cairo::Filter::Best);
374 
375         let cr = cairo::Context::new(&buffer);
376         let mut m: cairo::Matrix = brush_ts.to_native();
377         m.invert();
378         patt.set_matrix(m);
379 
380         cr.set_source(&patt);
381         cr.rectangle(0.0, 0.0, region.width() as f64, region.height() as f64);
382         cr.fill();
383 
384         Ok(Image::from_image(buffer, ColorSpace::SRGB))
385     }
386 
apply_image( fe: &usvg::FeImage, region: ScreenRect, subregion: ScreenRect, opt: &Options, tree: &usvg::Tree, ts: &usvg::Transform, ) -> Result<Image, Error>387     fn apply_image(
388         fe: &usvg::FeImage,
389         region: ScreenRect,
390         subregion: ScreenRect,
391         opt: &Options,
392         tree: &usvg::Tree,
393         ts: &usvg::Transform,
394     ) -> Result<Image, Error> {
395         let buffer = create_image(region.width(), region.height())?;
396 
397         match fe.data {
398             usvg::FeImageKind::Image(ref data, format) => {
399                 let cr = cairo::Context::new(&buffer);
400 
401                 let dx = (subregion.x() - region.x()) as f64;
402                 let dy = (subregion.y() - region.y()) as f64;
403                 cr.translate(dx, dy);
404 
405                 let view_box = usvg::ViewBox {
406                     rect: subregion.translate_to(0, 0).to_rect(),
407                     aspect: fe.aspect,
408                 };
409 
410                 if format == usvg::ImageFormat::SVG {
411                     super::image::draw_svg(data, view_box, opt, &cr);
412                 } else {
413                     super::image::draw_raster(format, data, view_box, fe.rendering_mode, opt, &cr);
414                 }
415             }
416             usvg::FeImageKind::Use(ref id) => {
417                 if let Some(ref node) = tree.defs_by_id(id).or(tree.node_by_id(id)) {
418                     let mut layers = super::create_layers(region.size());
419                     let cr = cairo::Context::new(&buffer);
420 
421                     let (sx, sy) = ts.get_scale();
422                     cr.scale(sx, sy);
423                     cr.transform(node.transform().to_native());
424 
425                     super::render_node(node, opt, &mut crate::RenderState::Ok, &mut layers, &cr);
426                 }
427             }
428         }
429 
430         Ok(Image::from_image(buffer, ColorSpace::SRGB))
431     }
432 
apply_component_transfer( fe: &usvg::FeComponentTransfer, cs: ColorSpace, input: Image, ) -> Result<Image, Error>433     fn apply_component_transfer(
434         fe: &usvg::FeComponentTransfer,
435         cs: ColorSpace,
436         input: Image,
437     ) -> Result<Image, Error> {
438         let mut buffer = input.into_color_space(cs)?.take()?;
439         let (w, h) = (buffer.width(), buffer.height());
440         if let Ok(ref mut data) = buffer.get_data() {
441             svgfilters::demultiply_alpha(data.as_bgra_mut());
442 
443             svgfilters::component_transfer(
444                 fe.func_b.into_svgf(),
445                 fe.func_g.into_svgf(),
446                 fe.func_r.into_svgf(),
447                 fe.func_a.into_svgf(),
448                 svgfilters::ImageRefMut::new(data.as_bgra_mut(), w, h),
449             );
450 
451             svgfilters::multiply_alpha(data.as_bgra_mut());
452         }
453 
454         Ok(Image::from_image(buffer, cs))
455     }
456 
apply_color_matrix( fe: &usvg::FeColorMatrix, cs: ColorSpace, input: Image, ) -> Result<Image, Error>457     fn apply_color_matrix(
458         fe: &usvg::FeColorMatrix,
459         cs: ColorSpace,
460         input: Image,
461     ) -> Result<Image, Error> {
462         let mut buffer = input.into_color_space(cs)?.take()?;
463         let (w, h) = (buffer.width(), buffer.height());
464         if let Ok(ref mut data) = buffer.get_data() {
465             svgfilters::demultiply_alpha(data.as_bgra_mut());
466             svgfilters::color_matrix(
467                 fe.kind.into_svgf(), svgfilters::ImageRefMut::new(data.as_bgra_mut(), w, h),
468             );
469             svgfilters::multiply_alpha(data.as_bgra_mut());
470         }
471 
472         Ok(Image::from_image(buffer, cs))
473     }
474 
apply_convolve_matrix( fe: &usvg::FeConvolveMatrix, cs: ColorSpace, input: Image, ) -> Result<Image, Error>475     fn apply_convolve_matrix(
476         fe: &usvg::FeConvolveMatrix,
477         cs: ColorSpace,
478         input: Image,
479     ) -> Result<Image, Error> {
480         let mut buffer = input.into_color_space(cs)?.take()?;
481 
482         if fe.preserve_alpha {
483             if let Ok(ref mut data) = buffer.get_data() {
484                 svgfilters::demultiply_alpha(data.as_bgra_mut());
485             }
486         }
487 
488         let (w, h) = (buffer.width(), buffer.height());
489         if let Ok(ref mut data) = buffer.get_data() {
490             svgfilters::convolve_matrix(
491                 fe.matrix.into_svgf(), fe.divisor.value(), fe.bias,
492                 fe.edge_mode.into_svgf(), fe.preserve_alpha,
493                 svgfilters::ImageRefMut::new(data.as_bgra_mut(), w, h),
494             );
495         }
496 
497         Ok(Image::from_image(buffer, cs))
498     }
499 
apply_morphology( fe: &usvg::FeMorphology, units: usvg::Units, cs: ColorSpace, bbox: Option<Rect>, ts: &usvg::Transform, input: Image, ) -> Result<Image, Error>500     fn apply_morphology(
501         fe: &usvg::FeMorphology,
502         units: usvg::Units,
503         cs: ColorSpace,
504         bbox: Option<Rect>,
505         ts: &usvg::Transform,
506         input: Image,
507     ) -> Result<Image, Error> {
508         let mut buffer = input.into_color_space(cs)?.take()?;
509         let (rx, ry) = try_opt_or!(
510             Self::scale_coordinates(fe.radius_x.value(), fe.radius_y.value(), units, bbox, ts),
511             Ok(Image::from_image(buffer, cs))
512         );
513 
514         if !(rx > 0.0 && ry > 0.0) {
515             buffer.clear();
516             return Ok(Image::from_image(buffer, cs));
517         }
518 
519         let (w, h) = (buffer.width(), buffer.height());
520         if let Ok(ref mut data) = buffer.get_data() {
521             svgfilters::morphology(
522                 fe.operator.into_svgf(), rx, ry,
523                 svgfilters::ImageRefMut::new(data.as_bgra_mut(), w, h),
524             );
525         }
526 
527         Ok(Image::from_image(buffer, cs))
528     }
529 
apply_displacement_map( fe: &usvg::FeDisplacementMap, region: ScreenRect, units: usvg::Units, cs: ColorSpace, bbox: Option<Rect>, ts: &usvg::Transform, input1: Image, input2: Image, ) -> Result<Image, Error>530     fn apply_displacement_map(
531         fe: &usvg::FeDisplacementMap,
532         region: ScreenRect,
533         units: usvg::Units,
534         cs: ColorSpace,
535         bbox: Option<Rect>,
536         ts: &usvg::Transform,
537         input1: Image,
538         input2: Image,
539     ) -> Result<Image, Error> {
540         let mut buffer1 = input1.into_color_space(cs)?.take()?;
541         let mut buffer2 = input2.into_color_space(cs)?.take()?;
542         let (sx, sy) = try_opt_or!(
543             Self::scale_coordinates(fe.scale, fe.scale, units, bbox, ts),
544             Ok(Image::from_image(buffer1, cs))
545         );
546 
547         let mut buffer = create_image(region.width(), region.height())?;
548 
549         let (w, h) = (buffer.width(), buffer.height());
550         if let (Ok(buffer1), Ok(buffer2), Ok(mut buffer))
551             = (buffer1.get_data(), buffer2.get_data(), buffer.get_data())
552         {
553             svgfilters::displacement_map(
554                 fe.x_channel_selector.into_svgf(),
555                 fe.y_channel_selector.into_svgf(),
556                 sx, sy,
557                 svgfilters::ImageRef::new(buffer1.as_bgra(), w, h),
558                 svgfilters::ImageRef::new(buffer2.as_bgra(), w, h),
559                 svgfilters::ImageRefMut::new(buffer.as_bgra_mut(), w, h),
560             );
561         }
562 
563         Ok(Image::from_image(buffer, cs))
564     }
565 
apply_turbulence( fe: &usvg::FeTurbulence, region: ScreenRect, cs: ColorSpace, ts: &usvg::Transform, ) -> Result<Image, Error>566     fn apply_turbulence(
567         fe: &usvg::FeTurbulence,
568         region: ScreenRect,
569         cs: ColorSpace,
570         ts: &usvg::Transform,
571     ) -> Result<Image, Error> {
572         let mut buffer = create_image(region.width(), region.height())?;
573         let (sx, sy) = ts.get_scale();
574         if sx.is_fuzzy_zero() || sy.is_fuzzy_zero() {
575             return Ok(Image::from_image(buffer, cs));
576         }
577 
578         let (w, h) = (buffer.width(), buffer.height());
579         if let Ok(ref mut data) = buffer.get_data() {
580             svgfilters::turbulence(
581                 region.x() as f64, region.y() as f64,
582                 sx, sy,
583                 fe.base_frequency.x.value().into(), fe.base_frequency.y.value().into(),
584                 fe.num_octaves,
585                 fe.seed,
586                 fe.stitch_tiles,
587                 fe.kind == usvg::FeTurbulenceKind::FractalNoise,
588                 svgfilters::ImageRefMut::new(data.as_bgra_mut(), w, h),
589             );
590 
591             svgfilters::multiply_alpha(data.as_bgra_mut());
592         }
593 
594         Ok(Image::from_image(buffer, cs))
595     }
596 
apply_diffuse_lighting( fe: &usvg::FeDiffuseLighting, region: ScreenRect, cs: ColorSpace, ts: &usvg::Transform, input: Image, ) -> Result<Image, Error>597     fn apply_diffuse_lighting(
598         fe: &usvg::FeDiffuseLighting,
599         region: ScreenRect,
600         cs: ColorSpace,
601         ts: &usvg::Transform,
602         input: Image,
603     ) -> Result<Image, Error> {
604         let mut input = input.take()?;
605         let mut buffer = create_image(region.width(), region.height())?;
606 
607         let light_source = crate::filter::transform_light_source(region, ts, fe.light_source);
608 
609         let (w, h) = (buffer.width(), buffer.height());
610         if let (Ok(ref buf_in), Ok(ref mut buf_out)) = (input.get_data(), buffer.get_data()) {
611             svgfilters::diffuse_lighting(
612                 fe.surface_scale,
613                 fe.diffuse_constant,
614                 fe.lighting_color.into_svgf(),
615                 light_source.into_svgf(),
616                 svgfilters::ImageRef::new(buf_in.as_bgra(), w, h),
617                 svgfilters::ImageRefMut::new(buf_out.as_bgra_mut(), w, h),
618             );
619         }
620 
621         Ok(Image::from_image(buffer, cs))
622     }
623 
apply_specular_lighting( fe: &usvg::FeSpecularLighting, region: ScreenRect, cs: ColorSpace, ts: &usvg::Transform, input: Image, ) -> Result<Image, Error>624     fn apply_specular_lighting(
625         fe: &usvg::FeSpecularLighting,
626         region: ScreenRect,
627         cs: ColorSpace,
628         ts: &usvg::Transform,
629         input: Image,
630     ) -> Result<Image, Error> {
631         let mut input = input.take()?;
632         let mut buffer = create_image(region.width(), region.height())?;
633 
634         let light_source = crate::filter::transform_light_source(region, ts, fe.light_source);
635 
636         let (w, h) = (buffer.width(), buffer.height());
637         if let (Ok(ref buf_in), Ok(ref mut buf_out)) = (input.get_data(), buffer.get_data()) {
638             svgfilters::specular_lighting(
639                 fe.surface_scale,
640                 fe.specular_constant,
641                 fe.specular_exponent,
642                 fe.lighting_color.into_svgf(),
643                 light_source.into_svgf(),
644                 svgfilters::ImageRef::new(buf_in.as_bgra(), w, h),
645                 svgfilters::ImageRefMut::new(buf_out.as_bgra_mut(), w, h),
646             );
647         }
648 
649         Ok(Image::from_image(buffer, cs))
650     }
651 
apply_to_canvas( input: Image, region: ScreenRect, canvas: &mut cairo::ImageSurface, ) -> Result<(), Error>652     fn apply_to_canvas(
653         input: Image,
654         region: ScreenRect,
655         canvas: &mut cairo::ImageSurface,
656     ) -> Result<(), Error> {
657         let input = input.into_color_space(ColorSpace::SRGB)?;
658 
659         let cr = cairo::Context::new(canvas);
660 
661         cr.set_operator(cairo::Operator::Clear);
662         cr.set_source_rgba(0.0, 0.0, 0.0, 0.0);
663         cr.paint();
664 
665         cr.set_operator(cairo::Operator::Over);
666         cr.set_source_surface(input.as_ref(), region.x() as f64, region.y() as f64);
667         cr.paint();
668 
669         Ok(())
670     }
671 }
672