1use crate::document::AcquiredNodes;
2use crate::element::ElementTrait;
3use crate::node::Node;
4use crate::properties::ColorInterpolationFilters;
5use crate::rect::IRect;
6use crate::rsvg_log;
7use crate::session::Session;
8use crate::xml::Attributes;
9
10use super::bounds::BoundsBuilder;
11use super::context::{FilterContext, FilterInput, FilterOutput};
12use super::{
13 FilterEffect, FilterError, FilterResolveError, Input, InputRequirements, Primitive,
14 PrimitiveParams, ResolvedPrimitive,
15};
16
17#[derive(Default)]
19pub struct FeTile {
20 base: Primitive,
21 params: Tile,
22}
23
24#[derive(Clone, Default)]
26pub struct Tile {
27 in1: Input,
28}
29
30impl ElementTrait for FeTile {
31 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
32 self.params.in1 = self.base.parse_one_input(attrs, session);
33 }
34}
35
36impl Tile {
37 pub fn render(
38 &self,
39 bounds_builder: BoundsBuilder,
40 ctx: &FilterContext,
41 ) -> Result<FilterOutput, FilterError> {
42 let input_1 = ctx.get_input(&self.in1, ColorInterpolationFilters::Auto)?;
50
51 let bounds: IRect = bounds_builder.compute(ctx).clipped.into();
53
54 let surface = match input_1 {
55 FilterInput::StandardInput(input_surface) => input_surface,
56 FilterInput::PrimitiveOutput(FilterOutput {
57 surface: input_surface,
58 bounds: input_bounds,
59 }) => {
60 if input_bounds.is_empty() {
61 rsvg_log!(
62 ctx.session(),
63 "(feTile with empty input_bounds; returning just the input surface)"
64 );
65
66 input_surface
67 } else {
68 rsvg_log!(
69 ctx.session(),
70 "(feTile bounds={:?}, input_bounds={:?})",
71 bounds,
72 input_bounds
73 );
74
75 let tile_surface = input_surface.tile(input_bounds)?;
76
77 ctx.source_graphic().paint_image_tiled(
78 bounds,
79 &tile_surface,
80 input_bounds.x0,
81 input_bounds.y0,
82 )?
83 }
84 }
85 };
86
87 Ok(FilterOutput { surface, bounds })
88 }
89
90 pub fn get_input_requirements(&self) -> InputRequirements {
91 self.in1.get_requirements()
92 }
93}
94
95impl FilterEffect for FeTile {
96 fn resolve(
97 &self,
98 _acquired_nodes: &mut AcquiredNodes<'_>,
99 _node: &Node,
100 ) -> Result<Vec<ResolvedPrimitive>, FilterResolveError> {
101 Ok(vec![ResolvedPrimitive {
102 primitive: self.base.clone(),
103 params: PrimitiveParams::Tile(self.params.clone()),
104 }])
105 }
106}