rsvg/
element.rs

1//! SVG Elements.
2
3use markup5ever::{expanded_name, local_name, ns, QualName};
4use std::collections::{HashMap, HashSet};
5use std::fmt;
6use std::sync::OnceLock;
7
8use crate::accept_language::UserLanguage;
9use crate::bbox::BoundingBox;
10use crate::cond::{RequiredExtensions, RequiredFeatures, SystemLanguage};
11use crate::css::{Declaration, Origin};
12use crate::document::AcquiredNodes;
13use crate::drawing_ctx::{DrawingCtx, Viewport};
14use crate::error::*;
15use crate::filter::Filter;
16use crate::filters::{
17    blend::FeBlend,
18    color_matrix::FeColorMatrix,
19    component_transfer::{FeComponentTransfer, FeFuncA, FeFuncB, FeFuncG, FeFuncR},
20    composite::FeComposite,
21    convolve_matrix::FeConvolveMatrix,
22    displacement_map::FeDisplacementMap,
23    drop_shadow::FeDropShadow,
24    flood::FeFlood,
25    gaussian_blur::FeGaussianBlur,
26    image::FeImage,
27    lighting::{FeDiffuseLighting, FeDistantLight, FePointLight, FeSpecularLighting, FeSpotLight},
28    merge::{FeMerge, FeMergeNode},
29    morphology::FeMorphology,
30    offset::FeOffset,
31    tile::FeTile,
32    turbulence::FeTurbulence,
33    FilterEffect,
34};
35use crate::gradient::{LinearGradient, RadialGradient, Stop};
36use crate::image::Image;
37use crate::layout::Layer;
38use crate::marker::Marker;
39use crate::node::*;
40use crate::pattern::Pattern;
41use crate::properties::{ComputedValues, SpecifiedValues};
42use crate::rsvg_log;
43use crate::session::Session;
44use crate::shapes::{Circle, Ellipse, Line, Path, Polygon, Polyline, Rect};
45use crate::structure::{ClipPath, Group, Link, Mask, NonRendering, Svg, Switch, Symbol, Use};
46use crate::style::Style;
47use crate::text::{TRef, TSpan, Text};
48use crate::text2::Text2;
49use crate::xml::Attributes;
50
51pub type DrawResult = Result<Box<BoundingBox>, Box<InternalRenderingError>>;
52
53pub trait ElementTrait {
54    /// Sets per-element attributes.
55    ///
56    /// Each element is supposed to iterate the `attributes`, and parse any ones it needs.
57    /// SVG specifies that unknown attributes should be ignored, and known attributes with invalid
58    /// values should be ignored so that the attribute ends up with its "initial value".
59    ///
60    /// You can use the [`set_attribute`] function to do that.
61    fn set_attributes(&mut self, _attributes: &Attributes, _session: &Session) {}
62
63    /// Draw an element.
64    ///
65    /// Each element is supposed to draw itself as needed.
66    fn draw(
67        &self,
68        _node: &Node,
69        _acquired_nodes: &mut AcquiredNodes<'_>,
70        _cascaded: &CascadedValues<'_>,
71        viewport: &Viewport,
72        _draw_ctx: &mut DrawingCtx,
73        _clipping: bool,
74    ) -> DrawResult {
75        // by default elements don't draw themselves
76        Ok(viewport.empty_bbox())
77    }
78
79    /// Create a layout object for the current element.
80    ///
81    /// This resolves property values, coordinates, lengths, etc. and produces a layout
82    /// item for rendering.
83    fn layout(
84        &self,
85        _node: &Node,
86        _acquired_nodes: &mut AcquiredNodes<'_>,
87        _cascaded: &CascadedValues<'_>,
88        _viewport: &Viewport,
89        _draw_ctx: &mut DrawingCtx,
90        _clipping: bool,
91    ) -> Result<Option<Layer>, Box<InternalRenderingError>> {
92        Ok(None)
93    }
94}
95
96/// Sets `dest` if `parse_result` is `Ok()`, otherwise just logs the error.
97///
98/// Implementations of the [`ElementTrait`] trait generally scan a list of attributes
99/// for the ones they can handle, and parse their string values.  Per the SVG spec, an attribute
100/// with an invalid value should be ignored, and it should fall back to the default value.
101///
102/// In librsvg, those default values are set in each element's implementation of the [`Default`] trait:
103/// at element creation time, each element gets initialized to its `Default`, and then each attribute
104/// gets parsed.  This function will set that attribute's value only if parsing was successful.
105///
106/// In case the `parse_result` is an error, this function will log an appropriate notice
107/// via the [`Session`].
108pub fn set_attribute<T>(dest: &mut T, parse_result: Result<T, ElementError>, session: &Session) {
109    match parse_result {
110        Ok(v) => *dest = v,
111        Err(e) => {
112            // FIXME: this does not provide a clue of what was the problematic element.
113            // We need tracking of the current parsing position to do that.
114            rsvg_log!(session, "ignoring attribute with invalid value: {}", e);
115        }
116    }
117}
118
119pub struct Element {
120    element_name: QualName,
121    attributes: Attributes,
122    specified_values: SpecifiedValues,
123    important_styles: HashSet<QualName>,
124    values: ComputedValues,
125    required_extensions: Option<RequiredExtensions>,
126    required_features: Option<RequiredFeatures>,
127    system_language: Option<SystemLanguage>,
128    pub element_data: ElementData,
129}
130
131impl fmt::Display for Element {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        write!(f, "{}", self.element_name().local)?;
134        write!(f, " id={}", self.get_id().unwrap_or("None"))?;
135        Ok(())
136    }
137}
138
139/// Parsed contents of an element node in the DOM.
140///
141/// This enum uses `Box<Foo>` in order to make each variant the size of
142/// a pointer.
143pub enum ElementData {
144    Circle(Box<Circle>),
145    ClipPath(Box<ClipPath>),
146    Ellipse(Box<Ellipse>),
147    Filter(Box<Filter>),
148    Group(Box<Group>),
149    Image(Box<Image>),
150    Line(Box<Line>),
151    LinearGradient(Box<LinearGradient>),
152    Link(Box<Link>),
153    Marker(Box<Marker>),
154    Mask(Box<Mask>),
155    NonRendering(Box<NonRendering>),
156    Path(Box<Path>),
157    Pattern(Box<Pattern>),
158    Polygon(Box<Polygon>),
159    Polyline(Box<Polyline>),
160    RadialGradient(Box<RadialGradient>),
161    Rect(Box<Rect>),
162    Stop(Box<Stop>),
163    Style(Box<Style>),
164    Svg(Box<Svg>),
165    Switch(Box<Switch>),
166    Symbol(Box<Symbol>),
167    Text(Box<Text>),
168    Text2(Box<Text2>),
169    TRef(Box<TRef>),
170    TSpan(Box<TSpan>),
171    Use(Box<Use>),
172
173    // Filter primitives, these start with "Fe" as element names are e.g. "feBlend"
174    FeBlend(Box<FeBlend>),
175    FeColorMatrix(Box<FeColorMatrix>),
176    FeComponentTransfer(Box<FeComponentTransfer>),
177    FeComposite(Box<FeComposite>),
178    FeConvolveMatrix(Box<FeConvolveMatrix>),
179    FeDiffuseLighting(Box<FeDiffuseLighting>),
180    FeDisplacementMap(Box<FeDisplacementMap>),
181    FeDistantLight(Box<FeDistantLight>),
182    FeDropShadow(Box<FeDropShadow>),
183    FeFlood(Box<FeFlood>),
184    FeFuncA(Box<FeFuncA>),
185    FeFuncB(Box<FeFuncB>),
186    FeFuncG(Box<FeFuncG>),
187    FeFuncR(Box<FeFuncR>),
188    FeGaussianBlur(Box<FeGaussianBlur>),
189    FeImage(Box<FeImage>),
190    FeMerge(Box<FeMerge>),
191    FeMergeNode(Box<FeMergeNode>),
192    FeMorphology(Box<FeMorphology>),
193    FeOffset(Box<FeOffset>),
194    FePointLight(Box<FePointLight>),
195    FeSpecularLighting(Box<FeSpecularLighting>),
196    FeSpotLight(Box<FeSpotLight>),
197    FeTile(Box<FeTile>),
198    FeTurbulence(Box<FeTurbulence>),
199}
200
201#[rustfmt::skip]
202fn get_element_creators() -> &'static HashMap<&'static str, (ElementDataCreateFn, ElementCreateFlags)> {
203    use ElementCreateFlags::*;
204
205    ELEMENT_CREATORS.get_or_init(|| {
206        // Lines in comments are elements that we don't support.
207        let creators_table: Vec<(&str, ElementDataCreateFn, ElementCreateFlags)> = vec![
208            // name, supports_class, create_fn
209            ("a",                   create_link,                  Default),
210            /* ("altGlyph",         ), */
211            /* ("altGlyphDef",      ), */
212            /* ("altGlyphItem",     ), */
213            /* ("animate",          ), */
214            /* ("animateColor",     ), */
215            /* ("animateMotion",    ), */
216            /* ("animateTransform", ), */
217            ("circle",              create_circle,                Default),
218            ("clipPath",            create_clip_path,             Default),
219            /* ("color-profile",    ), */
220            /* ("cursor",           ), */
221            ("defs",                create_defs,                  Default),
222            /* ("desc",             ), */
223            ("ellipse",             create_ellipse,               Default),
224            ("feBlend",             create_fe_blend,              Default),
225            ("feColorMatrix",       create_fe_color_matrix,       Default),
226            ("feComponentTransfer", create_fe_component_transfer, Default),
227            ("feComposite",         create_fe_composite,          Default),
228            ("feConvolveMatrix",    create_fe_convolve_matrix,    Default),
229            ("feDiffuseLighting",   create_fe_diffuse_lighting,   Default),
230            ("feDisplacementMap",   create_fe_displacement_map,   Default),
231            ("feDistantLight",      create_fe_distant_light,      IgnoreClass),
232            ("feDropShadow",        create_fe_drop_shadow,        Default),
233            ("feFuncA",             create_fe_func_a,             IgnoreClass),
234            ("feFuncB",             create_fe_func_b,             IgnoreClass),
235            ("feFuncG",             create_fe_func_g,             IgnoreClass),
236            ("feFuncR",             create_fe_func_r,             IgnoreClass),
237            ("feFlood",             create_fe_flood,              Default),
238            ("feGaussianBlur",      create_fe_gaussian_blur,      Default),
239            ("feImage",             create_fe_image,              Default),
240            ("feMerge",             create_fe_merge,              Default),
241            ("feMergeNode",         create_fe_merge_node,         IgnoreClass),
242            ("feMorphology",        create_fe_morphology,         Default),
243            ("feOffset",            create_fe_offset,             Default),
244            ("fePointLight",        create_fe_point_light,        IgnoreClass),
245            ("feSpecularLighting",  create_fe_specular_lighting,  Default),
246            ("feSpotLight",         create_fe_spot_light,         IgnoreClass),
247            ("feTile",              create_fe_tile,               Default),
248            ("feTurbulence",        create_fe_turbulence,         Default),
249            ("filter",              create_filter,                Default),
250            /* ("font",             ), */
251            /* ("font-face",        ), */
252            /* ("font-face-format", ), */
253            /* ("font-face-name",   ), */
254            /* ("font-face-src",    ), */
255            /* ("font-face-uri",    ), */
256            /* ("foreignObject",    ), */
257            ("g",                   create_group,                 Default),
258            /* ("glyph",            ), */
259            /* ("glyphRef",         ), */
260            /* ("hkern",            ), */
261            ("image",               create_image,                 Default),
262            ("line",                create_line,                  Default),
263            ("linearGradient",      create_linear_gradient,       Default),
264            ("marker",              create_marker,                Default),
265            ("mask",                create_mask,                  Default),
266            /* ("metadata",         ), */
267            /* ("missing-glyph",    ), */
268            /* ("mpath",            ), */
269            /* ("multiImage",       ), */
270            ("path",                create_path,                  Default),
271            ("pattern",             create_pattern,               Default),
272            ("polygon",             create_polygon,               Default),
273            ("polyline",            create_polyline,              Default),
274            ("radialGradient",      create_radial_gradient,       Default),
275            ("rect",                create_rect,                  Default),
276            /* ("script",           ), */
277            /* ("set",              ), */
278            ("stop",                create_stop,                  Default),
279            ("style",               create_style,                 IgnoreClass),
280            /* ("subImage",         ), */
281            /* ("subImageRef",      ), */
282            ("svg",                 create_svg,                   Default),
283            ("switch",              create_switch,                Default),
284            ("symbol",              create_symbol,                Default),
285            ("text",                create_text,                  Default),
286            ("text2",               create_text2,                 Default),
287            /* ("textPath",         ), */
288            /* ("title",            ), */
289            ("tref",                create_tref,                  Default),
290            ("tspan",               create_tspan,                 Default),
291            ("use",                 create_use,                   Default),
292            /* ("view",             ), */
293            /* ("vkern",            ), */
294        ];
295
296        creators_table.into_iter().map(|(n, c, f)| (n, (c, f))).collect()
297    })
298}
299
300impl Element {
301    /// Takes an XML element name and consumes a list of attribute/value pairs to create an [`Element`].
302    ///
303    /// This operation does not fail.  Unknown element names simply produce a [`NonRendering`]
304    /// element.
305    pub fn new(session: &Session, name: &QualName, mut attributes: Attributes) -> Element {
306        let (create_fn, flags): (ElementDataCreateFn, ElementCreateFlags) = if name.ns == ns!(svg) {
307            match get_element_creators().get(name.local.as_ref()) {
308                // hack in the SVG namespace for supported element names
309                Some(&(create_fn, flags)) => (create_fn, flags),
310
311                // Whenever we encounter a element name we don't understand, represent it as a
312                // non-rendering element.  This is like a group, but it doesn't do any rendering
313                // of children.  The effect is that we will ignore all children of unknown elements.
314                None => (create_non_rendering, ElementCreateFlags::Default),
315            }
316        } else {
317            (create_non_rendering, ElementCreateFlags::Default)
318        };
319
320        if flags == ElementCreateFlags::IgnoreClass {
321            attributes.clear_class();
322        };
323
324        let element_data = create_fn(session, &attributes);
325
326        let mut e = Self {
327            element_name: name.clone(),
328            attributes,
329            specified_values: Default::default(),
330            important_styles: Default::default(),
331            values: Default::default(),
332            required_extensions: Default::default(),
333            required_features: Default::default(),
334            system_language: Default::default(),
335            element_data,
336        };
337
338        e.set_conditional_processing_attributes(session);
339        e.set_presentation_attributes(session);
340
341        e
342    }
343
344    pub fn element_name(&self) -> &QualName {
345        &self.element_name
346    }
347
348    pub fn get_attributes(&self) -> &Attributes {
349        &self.attributes
350    }
351
352    pub fn get_id(&self) -> Option<&str> {
353        self.attributes.get_id()
354    }
355
356    pub fn get_class(&self) -> Option<&str> {
357        self.attributes.get_class()
358    }
359
360    pub fn inherit_xml_lang(&mut self, parent: Option<Node>) {
361        self.specified_values
362            .inherit_xml_lang(&mut self.values, parent);
363    }
364
365    pub fn get_specified_values(&self) -> &SpecifiedValues {
366        &self.specified_values
367    }
368
369    pub fn get_computed_values(&self) -> &ComputedValues {
370        &self.values
371    }
372
373    pub fn set_computed_values(&mut self, values: &ComputedValues) {
374        self.values = values.clone();
375    }
376
377    pub fn get_cond(&self, user_language: &UserLanguage) -> bool {
378        self.required_extensions
379            .as_ref()
380            .map(|v| v.eval())
381            .unwrap_or(true)
382            && self
383                .required_features
384                .as_ref()
385                .map(|v| v.eval())
386                .unwrap_or(true)
387            && self
388                .system_language
389                .as_ref()
390                .map(|v| v.eval(user_language))
391                .unwrap_or(true)
392    }
393
394    fn set_conditional_processing_attributes(&mut self, session: &Session) {
395        for (attr, value) in self.attributes.iter() {
396            match attr.expanded() {
397                expanded_name!("", "requiredExtensions") => {
398                    self.required_extensions = Some(RequiredExtensions::from_attribute(value));
399                }
400
401                expanded_name!("", "requiredFeatures") => {
402                    self.required_features = Some(RequiredFeatures::from_attribute(value));
403                }
404
405                expanded_name!("", "systemLanguage") => {
406                    self.system_language = Some(SystemLanguage::from_attribute(value, session));
407                }
408
409                _ => {}
410            }
411        }
412    }
413
414    /// Hands the `attrs` to the node's state, to apply the presentation attributes.
415    fn set_presentation_attributes(&mut self, session: &Session) {
416        self.specified_values
417            .parse_presentation_attributes(session, &self.attributes);
418    }
419
420    // Applies a style declaration to the node's specified_values
421    pub fn apply_style_declaration(&mut self, declaration: &Declaration, origin: Origin) {
422        self.specified_values.set_property_from_declaration(
423            declaration,
424            origin,
425            &mut self.important_styles,
426        );
427    }
428
429    /// Applies CSS styles from the "style" attribute
430    pub fn set_style_attribute(&mut self, session: &Session) {
431        let style = self
432            .attributes
433            .iter()
434            .find(|(attr, _)| attr.expanded() == expanded_name!("", "style"))
435            .map(|(_, value)| value);
436
437        if let Some(style) = style {
438            self.specified_values.parse_style_declarations(
439                style,
440                Origin::Author,
441                &mut self.important_styles,
442                session,
443            );
444        }
445    }
446
447    #[rustfmt::skip]
448    pub fn as_filter_effect(&self) -> Option<&dyn FilterEffect> {
449        use ElementData::*;
450
451        match &self.element_data {
452            FeBlend(fe) =>              Some(&**fe),
453            FeColorMatrix(fe) =>        Some(&**fe),
454            FeComponentTransfer(fe) =>  Some(&**fe),
455            FeComposite(fe) =>          Some(&**fe),
456            FeConvolveMatrix(fe) =>     Some(&**fe),
457            FeDiffuseLighting(fe) =>    Some(&**fe),
458            FeDisplacementMap(fe) =>    Some(&**fe),
459            FeDropShadow(fe) =>         Some(&**fe),
460            FeFlood(fe) =>              Some(&**fe),
461            FeGaussianBlur(fe) =>       Some(&**fe),
462            FeImage(fe) =>              Some(&**fe),
463            FeMerge(fe) =>              Some(&**fe),
464            FeMorphology(fe) =>         Some(&**fe),
465            FeOffset(fe) =>             Some(&**fe),
466            FeSpecularLighting(fe) =>   Some(&**fe),
467            FeTile(fe) =>               Some(&**fe),
468            FeTurbulence(fe) =>         Some(&**fe),
469            _ => None,
470        }
471    }
472
473    /// Returns whether an element of a particular type is only accessed by reference
474    // from other elements' attributes.  The element could in turn cause other nodes
475    // to get referenced, potentially causing reference cycles.
476    pub fn is_accessed_by_reference(&self) -> bool {
477        use ElementData::*;
478
479        matches!(
480            self.element_data,
481            ClipPath(_)
482                | Filter(_)
483                | LinearGradient(_)
484                | Marker(_)
485                | Mask(_)
486                | Pattern(_)
487                | RadialGradient(_)
488        )
489    }
490
491    /// The main drawing function for elements.
492    pub fn draw(
493        &self,
494        node: &Node,
495        acquired_nodes: &mut AcquiredNodes<'_>,
496        cascaded: &CascadedValues<'_>,
497        viewport: &Viewport,
498        draw_ctx: &mut DrawingCtx,
499        clipping: bool,
500    ) -> DrawResult {
501        let values = cascaded.get();
502        if values.is_displayed() {
503            self.element_data
504                .draw(node, acquired_nodes, cascaded, viewport, draw_ctx, clipping)
505        } else {
506            Ok(viewport.empty_bbox())
507        }
508    }
509
510    /// The main layout function for elements.
511    pub fn layout(
512        &self,
513        node: &Node,
514        acquired_nodes: &mut AcquiredNodes<'_>,
515        cascaded: &CascadedValues<'_>,
516        viewport: &Viewport,
517        draw_ctx: &mut DrawingCtx,
518        clipping: bool,
519    ) -> Result<Option<Layer>, Box<InternalRenderingError>> {
520        let values = cascaded.get();
521        if values.is_displayed() {
522            self.element_data
523                .layout(node, acquired_nodes, cascaded, viewport, draw_ctx, clipping)
524        } else {
525            Ok(None)
526        }
527    }
528}
529
530impl ElementData {
531    /// Dispatcher for the draw method of concrete element implementations.
532    #[rustfmt::skip]
533    fn draw(
534        &self,
535        node: &Node,
536        acquired_nodes: &mut AcquiredNodes<'_>,
537        cascaded: &CascadedValues<'_>,
538        viewport: &Viewport,
539        draw_ctx: &mut DrawingCtx,
540        clipping: bool,
541    ) -> DrawResult {
542        use ElementData::*;
543
544        let data: &dyn ElementTrait = match self {
545            Circle(d) =>               &**d,
546            ClipPath(d) =>             &**d,
547            Ellipse(d) =>              &**d,
548            Filter(d) =>               &**d,
549            Group(d) =>                &**d,
550            Image(d) =>                &**d,
551            Line(d) =>                 &**d,
552            LinearGradient(d) =>       &**d,
553            Link(d) =>                 &**d,
554            Marker(d) =>               &**d,
555            Mask(d) =>                 &**d,
556            NonRendering(d) =>         &**d,
557            Path(d) =>                 &**d,
558            Pattern(d) =>              &**d,
559            Polygon(d) =>              &**d,
560            Polyline(d) =>             &**d,
561            RadialGradient(d) =>       &**d,
562            Rect(d) =>                 &**d,
563            Stop(d) =>                 &**d,
564            Style(d) =>                &**d,
565            Svg(d) =>                  &**d,
566            Switch(d) =>               &**d,
567            Symbol(d) =>               &**d,
568            Text(d) =>                 &**d,
569            Text2(d) =>                 &**d,
570            TRef(d) =>                 &**d,
571            TSpan(d) =>                &**d,
572            Use(d) =>                  &**d,
573
574            FeBlend(d) =>              &**d,
575            FeColorMatrix(d) =>        &**d,
576            FeComponentTransfer(d) =>  &**d,
577            FeComposite(d) =>          &**d,
578            FeConvolveMatrix(d) =>     &**d,
579            FeDiffuseLighting(d) =>    &**d,
580            FeDisplacementMap(d) =>    &**d,
581            FeDistantLight(d) =>       &**d,
582            FeDropShadow(d) =>         &**d,
583            FeFlood(d) =>              &**d,
584            FeFuncA(d) =>              &**d,
585            FeFuncB(d) =>              &**d,
586            FeFuncG(d) =>              &**d,
587            FeFuncR(d) =>              &**d,
588            FeGaussianBlur(d) =>       &**d,
589            FeImage(d) =>              &**d,
590            FeMerge(d) =>              &**d,
591            FeMergeNode(d) =>          &**d,
592            FeMorphology(d) =>         &**d,
593            FeOffset(d) =>             &**d,
594            FePointLight(d) =>         &**d,
595            FeSpecularLighting(d) =>   &**d,
596            FeSpotLight(d) =>          &**d,
597            FeTile(d) =>               &**d,
598            FeTurbulence(d) =>         &**d,
599        };
600
601        data.draw(node, acquired_nodes, cascaded, viewport, draw_ctx, clipping)
602    }
603
604    /// Dispatcher for the layout method of concrete element implementations.
605    #[rustfmt::skip]
606    fn layout(
607        &self,
608        node: &Node,
609        acquired_nodes: &mut AcquiredNodes<'_>,
610        cascaded: &CascadedValues<'_>,
611        viewport: &Viewport,
612        draw_ctx: &mut DrawingCtx,
613        clipping: bool,
614    ) -> Result<Option<Layer>, Box<InternalRenderingError>> {
615        use ElementData::*;
616
617        let data: &dyn ElementTrait = match self {
618            Circle(d) =>               &**d,
619            ClipPath(d) =>             &**d,
620            Ellipse(d) =>              &**d,
621            Filter(d) =>               &**d,
622            Group(d) =>                &**d,
623            Image(d) =>                &**d,
624            Line(d) =>                 &**d,
625            LinearGradient(d) =>       &**d,
626            Link(d) =>                 &**d,
627            Marker(d) =>               &**d,
628            Mask(d) =>                 &**d,
629            NonRendering(d) =>         &**d,
630            Path(d) =>                 &**d,
631            Pattern(d) =>              &**d,
632            Polygon(d) =>              &**d,
633            Polyline(d) =>             &**d,
634            RadialGradient(d) =>       &**d,
635            Rect(d) =>                 &**d,
636            Stop(d) =>                 &**d,
637            Style(d) =>                &**d,
638            Svg(d) =>                  &**d,
639            Switch(d) =>               &**d,
640            Symbol(d) =>               &**d,
641            Text(d) =>                 &**d,
642            Text2(d) =>                 &**d,
643            TRef(d) =>                 &**d,
644            TSpan(d) =>                &**d,
645            Use(d) =>                  &**d,
646
647            FeBlend(d) =>              &**d,
648            FeColorMatrix(d) =>        &**d,
649            FeComponentTransfer(d) =>  &**d,
650            FeComposite(d) =>          &**d,
651            FeConvolveMatrix(d) =>     &**d,
652            FeDiffuseLighting(d) =>    &**d,
653            FeDisplacementMap(d) =>    &**d,
654            FeDistantLight(d) =>       &**d,
655            FeDropShadow(d) =>         &**d,
656            FeFlood(d) =>              &**d,
657            FeFuncA(d) =>              &**d,
658            FeFuncB(d) =>              &**d,
659            FeFuncG(d) =>              &**d,
660            FeFuncR(d) =>              &**d,
661            FeGaussianBlur(d) =>       &**d,
662            FeImage(d) =>              &**d,
663            FeMerge(d) =>              &**d,
664            FeMergeNode(d) =>          &**d,
665            FeMorphology(d) =>         &**d,
666            FeOffset(d) =>             &**d,
667            FePointLight(d) =>         &**d,
668            FeSpecularLighting(d) =>   &**d,
669            FeSpotLight(d) =>          &**d,
670            FeTile(d) =>               &**d,
671            FeTurbulence(d) =>         &**d,
672        };
673
674        data.layout(node, acquired_nodes, cascaded, viewport, draw_ctx, clipping)
675    }
676}
677
678macro_rules! e {
679    ($name:ident, $element_type:ident) => {
680        pub fn $name(session: &Session, attributes: &Attributes) -> ElementData {
681            let mut payload = Box::<$element_type>::default();
682            payload.set_attributes(attributes, session);
683
684            ElementData::$element_type(payload)
685        }
686    };
687}
688
689#[rustfmt::skip]
690mod creators {
691    use super::*;
692
693    e!(create_circle,                   Circle);
694    e!(create_clip_path,                ClipPath);
695    e!(create_defs,                     NonRendering);
696    e!(create_ellipse,                  Ellipse);
697    e!(create_fe_blend,                 FeBlend);
698    e!(create_fe_color_matrix,          FeColorMatrix);
699    e!(create_fe_component_transfer,    FeComponentTransfer);
700    e!(create_fe_func_a,                FeFuncA);
701    e!(create_fe_func_b,                FeFuncB);
702    e!(create_fe_func_g,                FeFuncG);
703    e!(create_fe_func_r,                FeFuncR);
704    e!(create_fe_composite,             FeComposite);
705    e!(create_fe_convolve_matrix,       FeConvolveMatrix);
706    e!(create_fe_diffuse_lighting,      FeDiffuseLighting);
707    e!(create_fe_displacement_map,      FeDisplacementMap);
708    e!(create_fe_distant_light,         FeDistantLight);
709    e!(create_fe_drop_shadow,           FeDropShadow);
710    e!(create_fe_flood,                 FeFlood);
711    e!(create_fe_gaussian_blur,         FeGaussianBlur);
712    e!(create_fe_image,                 FeImage);
713    e!(create_fe_merge,                 FeMerge);
714    e!(create_fe_merge_node,            FeMergeNode);
715    e!(create_fe_morphology,            FeMorphology);
716    e!(create_fe_offset,                FeOffset);
717    e!(create_fe_point_light,           FePointLight);
718    e!(create_fe_specular_lighting,     FeSpecularLighting);
719    e!(create_fe_spot_light,            FeSpotLight);
720    e!(create_fe_tile,                  FeTile);
721    e!(create_fe_turbulence,            FeTurbulence);
722    e!(create_filter,                   Filter);
723    e!(create_group,                    Group);
724    e!(create_image,                    Image);
725    e!(create_line,                     Line);
726    e!(create_linear_gradient,          LinearGradient);
727    e!(create_link,                     Link);
728    e!(create_marker,                   Marker);
729    e!(create_mask,                     Mask);
730    e!(create_non_rendering,            NonRendering);
731    e!(create_path,                     Path);
732    e!(create_pattern,                  Pattern);
733    e!(create_polygon,                  Polygon);
734    e!(create_polyline,                 Polyline);
735    e!(create_radial_gradient,          RadialGradient);
736    e!(create_rect,                     Rect);
737    e!(create_stop,                     Stop);
738    e!(create_style,                    Style);
739    e!(create_svg,                      Svg);
740    e!(create_switch,                   Switch);
741    e!(create_symbol,                   Symbol);
742    e!(create_text,                     Text);
743    e!(create_text2,                    Text2);
744    e!(create_tref,                     TRef);
745    e!(create_tspan,                    TSpan);
746    e!(create_use,                      Use);
747
748    /* Hack to make multiImage sort-of work
749     *
750     * disabled for now, as markup5ever doesn't have local names for
751     * multiImage, subImage, subImageRef.  Maybe we can just... create them ourselves?
752     *
753     * Is multiImage even in SVG2?
754     */
755    /*
756    e!(create_multi_image,              Switch);
757    e!(create_sub_image,                Group);
758    e!(create_sub_image_ref,            Image);
759    */
760}
761
762use creators::*;
763
764type ElementDataCreateFn = fn(session: &Session, attributes: &Attributes) -> ElementData;
765
766#[derive(Copy, Clone, PartialEq)]
767enum ElementCreateFlags {
768    Default,
769    IgnoreClass,
770}
771
772static ELEMENT_CREATORS: OnceLock<
773    HashMap<&'static str, (ElementDataCreateFn, ElementCreateFlags)>,
774> = OnceLock::new();