rsvg/
element.rs

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