[librsvg: 5/7] Turn NodeData into an enum with variants for Element and Text



commit 741a0c0bb4c9bc5dc4b246a92d9ba2e26275d45d
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Mar 12 15:19:29 2020 -0600

    Turn NodeData into an enum with variants for Element and Text
    
    pub enum NodeData {
        Element(Element),
        Text(NodeChars),
    }
    
    The old NodeData is now Element.
    
    This will let us box the Element, so that it takes as little space as
    possible for the enum when it has a NodeData::Text value.
    
    To make this easier for the rest of the code, now there is a
    NodeBorrow trait, implemented for RsvgNode and imported pretty much
    everywhere, with the following methods:
    
    pub trait NodeBorrow {
        /// Returns `false` for NodeData::Text, `true` otherwise.
        fn is_element(&self) -> bool;
    
        /// Borrows a `NodeChars` reference.
        ///
        /// Panics: will panic if `&self` is not a `NodeData::Text` node
        fn borrow_chars(&self) -> Ref<NodeChars>;
    
        /// Borrows an `Element` reference
        ///
        /// Panics: will panic if `&self` is not a `NodeData::Element` node
        fn borrow_element(&self) -> Ref<Element>;
    
        /// Borrows an `Element` reference mutably
        ///
        /// Panics: will panic if `&self` is not a `NodeData::Element` node
        fn borrow_element_mut(&mut self) -> RefMut<Element>;
    }
    
    So, instead of doing node.borrow() -> Ref<NodeData>, we now can do
    node.borrow_element() directly, for example.
    
    The calling code is still supposed to first ensure that a node
    is_element() or not, just like it was doing
    `get_type() == NodeType::Foo` before doing get_impl::<Foo>().

 rsvg_internals/src/css.rs                        |  22 +--
 rsvg_internals/src/document.rs                   |  19 +--
 rsvg_internals/src/drawing_ctx.rs                |  31 ++--
 rsvg_internals/src/filters/component_transfer.rs |  26 ++--
 rsvg_internals/src/filters/context.rs            |  10 +-
 rsvg_internals/src/filters/light/lighting.rs     |  19 ++-
 rsvg_internals/src/filters/merge.rs              |  10 +-
 rsvg_internals/src/filters/mod.rs                |  27 ++--
 rsvg_internals/src/gradient.rs                   |  12 +-
 rsvg_internals/src/handle.rs                     |   8 +-
 rsvg_internals/src/marker.rs                     |   2 +-
 rsvg_internals/src/node.rs                       | 175 ++++++++++++++++-------
 rsvg_internals/src/pattern.rs                    |   9 +-
 rsvg_internals/src/structure.rs                  |   4 +-
 rsvg_internals/src/text.rs                       |  19 +--
 rsvg_internals/src/xml.rs                        |  12 +-
 16 files changed, 248 insertions(+), 157 deletions(-)
---
diff --git a/rsvg_internals/src/css.rs b/rsvg_internals/src/css.rs
index dcc7d81f..8bd635b7 100644
--- a/rsvg_internals/src/css.rs
+++ b/rsvg_internals/src/css.rs
@@ -92,7 +92,7 @@ use url::Url;
 use crate::allowed_url::AllowedUrl;
 use crate::error::*;
 use crate::io::{self, BinaryData};
-use crate::node::{NodeCascade, NodeType, RsvgNode};
+use crate::node::{NodeBorrow, NodeCascade, NodeType, RsvgNode};
 use crate::properties::{parse_property, ComputedValues, ParsedProperty};
 
 /// A parsed CSS declaration
@@ -450,17 +450,17 @@ impl selectors::Element for RsvgElement {
     }
 
     fn has_local_name(&self, local_name: &LocalName) -> bool {
-        self.0.borrow().element_name().local == *local_name
+        self.0.borrow_element().element_name().local == *local_name
     }
 
     /// Empty string for no namespace
     fn has_namespace(&self, ns: &Namespace) -> bool {
-        self.0.borrow().element_name().ns == *ns
+        self.0.borrow_element().element_name().ns == *ns
     }
 
     /// Whether this element and the `other` element have the same local name and namespace.
     fn is_same_type(&self, other: &Self) -> bool {
-        self.0.borrow().element_name() == other.0.borrow().element_name()
+        self.0.borrow_element().element_name() == other.0.borrow_element().element_name()
     }
 
     fn attr_matches(
@@ -508,7 +508,7 @@ impl selectors::Element for RsvgElement {
 
     fn has_id(&self, id: &LocalName, case_sensitivity: CaseSensitivity) -> bool {
         self.0
-            .borrow()
+            .borrow_element()
             .get_id()
             .map(|self_id| case_sensitivity.eq(self_id.as_bytes(), id.as_ref().as_bytes()))
             .unwrap_or(false)
@@ -516,7 +516,7 @@ impl selectors::Element for RsvgElement {
 
     fn has_class(&self, name: &LocalName, case_sensitivity: CaseSensitivity) -> bool {
         self.0
-            .borrow()
+            .borrow_element()
             .get_class()
             .map(|classes| {
                 classes
@@ -548,8 +548,7 @@ impl selectors::Element for RsvgElement {
     fn is_empty(&self) -> bool {
         !self.0.has_children()
             || self.0.children().all(|child| {
-                child.borrow().get_type() == NodeType::Chars
-                    && child.borrow().get_chars().is_empty()
+                child.borrow().get_type() == NodeType::Chars && child.borrow_chars().is_empty()
             })
     }
 
@@ -736,7 +735,7 @@ impl Stylesheet {
 
 /// Runs the CSS cascade on the specified tree from all the stylesheets
 pub fn cascade(root: &mut RsvgNode, stylesheets: &[Stylesheet], extra: &[Stylesheet]) {
-    for mut node in root.descendants() {
+    for mut node in root.descendants().filter(|n| n.is_element()) {
         let mut matches = Vec::new();
 
         let mut match_ctx = MatchingContext::new(
@@ -755,10 +754,11 @@ pub fn cascade(root: &mut RsvgNode, stylesheets: &[Stylesheet], extra: &[Stylesh
         matches.as_mut_slice().sort();
 
         for m in matches {
-            node.borrow_mut().apply_style_declaration(m.declaration);
+            node.borrow_element_mut()
+                .apply_style_declaration(m.declaration);
         }
 
-        node.borrow_mut().set_style_attribute();
+        node.borrow_element_mut().set_style_attribute();
     }
 
     let values = ComputedValues::default();
diff --git a/rsvg_internals/src/document.rs b/rsvg_internals/src/document.rs
index 06db47b3..46d94a98 100644
--- a/rsvg_internals/src/document.rs
+++ b/rsvg_internals/src/document.rs
@@ -14,7 +14,7 @@ use crate::error::{AcquireError, LoadingError};
 use crate::handle::LoadOptions;
 use crate::io::{self, BinaryData};
 use crate::limits;
-use crate::node::{NodeData, NodeType, RsvgNode};
+use crate::node::{NodeBorrow, NodeData, NodeType, RsvgNode};
 use crate::property_bag::PropertyBag;
 use crate::structure::{IntrinsicDimensions, Svg};
 use crate::surface_utils::shared_surface::SharedImageSurface;
@@ -95,10 +95,10 @@ impl Document {
     /// Gets the dimension parameters of the toplevel `<svg>`.
     pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
         let root = self.root();
-        let node_data = root.borrow();
+        let elt = root.borrow_element();
 
-        assert!(node_data.get_type() == NodeType::Svg);
-        node_data.get_impl::<Svg>().get_intrinsic_dimensions()
+        assert!(elt.get_type() == NodeType::Svg);
+        elt.get_impl::<Svg>().get_intrinsic_dimensions()
     }
 
     /// Runs the CSS cascade on the document tree
@@ -434,15 +434,18 @@ impl DocumentBuilder {
     ) -> RsvgNode {
         let mut node = create_node(name, pbag);
 
-        if let Some(id) = node.borrow().get_id() {
+        if let Some(id) = node.borrow_element().get_id() {
             // This is so we don't overwrite an existing id
             self.ids
                 .entry(id.to_string())
                 .or_insert_with(|| node.clone());
         }
 
-        node.borrow_mut()
-            .set_atts(parent.as_ref().clone(), pbag, self.load_options.locale());
+        node.borrow_element_mut().set_atts(
+            parent.as_ref().clone(),
+            pbag,
+            self.load_options.locale(),
+        );
 
         if let Some(mut parent) = parent {
             parent.append(node.clone());
@@ -484,7 +487,7 @@ impl DocumentBuilder {
             child
         };
 
-        chars_node.borrow().get_chars().append(text);
+        chars_node.borrow_chars().append(text);
     }
 
     pub fn resolve_href(&self, href: &str) -> Result<AllowedUrl, AllowedUrlError> {
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index afa33959..7a5c60e2 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -18,7 +18,7 @@ use crate::error::{AcquireError, RenderingError};
 use crate::filters;
 use crate::gradient::{LinearGradient, RadialGradient};
 use crate::marker;
-use crate::node::{CascadedValues, NodeDraw, NodeType, RsvgNode};
+use crate::node::{CascadedValues, NodeBorrow, NodeDraw, NodeType, RsvgNode};
 use crate::paint_server::{PaintServer, PaintSource};
 use crate::path_builder::*;
 use crate::pattern::Pattern;
@@ -318,7 +318,7 @@ impl DrawingCtx {
         bbox: &BoundingBox,
     ) -> Result<(), RenderingError> {
         if let Some(node) = clip_node {
-            let units = node.borrow().get_impl::<ClipPath>().get_units();
+            let units = node.borrow_element().get_impl::<ClipPath>().get_units();
 
             if units == CoordUnits::ObjectBoundingBox && bbox.rect.is_none() {
                 // The node being clipped is empty / doesn't have a
@@ -397,7 +397,7 @@ impl DrawingCtx {
         };
 
         let mask_transform = mask_node
-            .borrow()
+            .borrow_element()
             .get_transform()
             .post_transform(&transform);
 
@@ -576,7 +576,7 @@ impl DrawingCtx {
 
                             res = res.and_then(|bbox| {
                                 dc.generate_cairo_mask(
-                                    &mask_node.borrow().get_impl::<Mask>(),
+                                    &mask_node.borrow_element().get_impl::<Mask>(),
                                     &mask_node,
                                     affines.for_temporary_surface,
                                     &bbox,
@@ -742,7 +742,7 @@ impl DrawingCtx {
             Ok(acquired) => {
                 let filter_node = acquired.get();
 
-                if !filter_node.borrow().is_in_error() {
+                if !filter_node.borrow_element().is_in_error() {
                     // FIXME: deal with out of memory here
                     filters::render(
                         &filter_node,
@@ -816,7 +816,7 @@ impl DrawingCtx {
 
                         had_paint_server = match node.borrow().get_type() {
                             NodeType::LinearGradient => node
-                                .borrow()
+                                .borrow_element()
                                 .get_impl::<LinearGradient>()
                                 .resolve_fallbacks_and_set_pattern(
                                     &node,
@@ -826,7 +826,7 @@ impl DrawingCtx {
                                     bbox,
                                 )?,
                             NodeType::RadialGradient => node
-                                .borrow()
+                                .borrow_element()
                                 .get_impl::<RadialGradient>()
                                 .resolve_fallbacks_and_set_pattern(
                                     &node,
@@ -836,7 +836,7 @@ impl DrawingCtx {
                                     bbox,
                                 )?,
                             NodeType::Pattern => node
-                                .borrow()
+                                .borrow_element()
                                 .get_impl::<Pattern>()
                                 .resolve_fallbacks_and_set_pattern(
                                     &node,
@@ -1112,8 +1112,8 @@ impl DrawingCtx {
         cascaded: &CascadedValues<'_>,
         clipping: bool,
     ) -> Result<BoundingBox, RenderingError> {
-        let node_data = node.borrow();
-        let use_ = node_data.get_impl::<Use>();
+        let elt = node.borrow_element();
+        let use_ = elt.get_impl::<Use>();
 
         // <use> is an element that is used directly, unlike
         // <pattern>, which is used through a fill="url(#...)"
@@ -1181,11 +1181,11 @@ impl DrawingCtx {
                 )
             })
         } else {
-            let node_data = child.borrow();
-            let symbol = node_data.get_impl::<Symbol>();
+            let elt = child.borrow_element();
+            let symbol = elt.get_impl::<Symbol>();
 
             let clip_mode = if !values.is_overflow()
-                || (values.overflow == Overflow::Visible && child.borrow().is_overflow())
+                || (values.overflow == Overflow::Visible && child.borrow_element().is_overflow())
             {
                 Some(ClipMode::ClipToVbox)
             } else {
@@ -1270,7 +1270,10 @@ fn get_clip_in_user_and_object_space(
         .and_then(|acquired| {
             let clip_node = acquired.get().clone();
 
-            let units = clip_node.borrow().get_impl::<ClipPath>().get_units();
+            let units = clip_node
+                .borrow_element()
+                .get_impl::<ClipPath>()
+                .get_units();
 
             match units {
                 CoordUnits::UserSpaceOnUse => Some((Some(clip_node), None)),
diff --git a/rsvg_internals/src/filters/component_transfer.rs 
b/rsvg_internals/src/filters/component_transfer.rs
index 91af86f1..89907746 100644
--- a/rsvg_internals/src/filters/component_transfer.rs
+++ b/rsvg_internals/src/filters/component_transfer.rs
@@ -6,7 +6,7 @@ use markup5ever::{expanded_name, local_name, namespace_url, ns};
 use crate::document::AcquiredNodes;
 use crate::drawing_ctx::DrawingCtx;
 use crate::error::*;
-use crate::node::{NodeResult, NodeTrait, NodeType, RsvgNode};
+use crate::node::{NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::number_list::{NumberList, NumberListLength};
 use crate::parsers::{Parse, ParseValue};
 use crate::property_bag::PropertyBag;
@@ -257,7 +257,7 @@ macro_rules! func_or_default {
     ($func_node:ident, $func_type:ty, $func_data:ident, $func_default:ident) => {
         match $func_node {
             Some(ref f) => {
-                $func_data = f.borrow();
+                $func_data = f.borrow_element();
                 $func_data.get_impl::<$func_type>()
             }
             _ => &$func_default,
@@ -295,7 +295,7 @@ impl FilterEffect for FeComponentTransfer {
             node.children()
                 .rev()
                 .filter(|c| c.borrow().get_type() == node_type)
-                .find(|c| c.borrow().get_impl::<F>().channel() == channel)
+                .find(|c| c.borrow_element().get_impl::<F>().channel() == channel)
         };
 
         let func_r_node = get_node::<FeFuncR>(node, NodeType::FeFuncR, Channel::R);
@@ -307,7 +307,7 @@ impl FilterEffect for FeComponentTransfer {
             .iter()
             .filter_map(|x| x.as_ref())
         {
-            if node.borrow().is_in_error() {
+            if node.borrow_element().is_in_error() {
                 return Err(FilterError::ChildNodeInError);
             }
         }
@@ -319,15 +319,15 @@ impl FilterEffect for FeComponentTransfer {
         let func_a_default = FeFuncA::default();
 
         // We need to tell the borrow checker that these live long enough
-        let func_r_data;
-        let func_g_data;
-        let func_b_data;
-        let func_a_data;
-
-        let func_r = func_or_default!(func_r_node, FeFuncR, func_r_data, func_r_default);
-        let func_g = func_or_default!(func_g_node, FeFuncG, func_g_data, func_g_default);
-        let func_b = func_or_default!(func_b_node, FeFuncB, func_b_data, func_b_default);
-        let func_a = func_or_default!(func_a_node, FeFuncA, func_a_data, func_a_default);
+        let func_r_element;
+        let func_g_element;
+        let func_b_element;
+        let func_a_element;
+
+        let func_r = func_or_default!(func_r_node, FeFuncR, func_r_element, func_r_default);
+        let func_g = func_or_default!(func_g_node, FeFuncG, func_g_element, func_g_default);
+        let func_b = func_or_default!(func_b_node, FeFuncB, func_b_element, func_b_default);
+        let func_a = func_or_default!(func_a_node, FeFuncA, func_a_element, func_a_default);
 
         #[inline]
         fn compute_func<'a, F>(func: &'a F) -> impl Fn(u8, f64, f64) -> u8 + 'a
diff --git a/rsvg_internals/src/filters/context.rs b/rsvg_internals/src/filters/context.rs
index 9a1556e0..5d2f748b 100644
--- a/rsvg_internals/src/filters/context.rs
+++ b/rsvg_internals/src/filters/context.rs
@@ -7,7 +7,7 @@ use crate::coord_units::CoordUnits;
 use crate::document::AcquiredNodes;
 use crate::drawing_ctx::{DrawingCtx, ViewParams};
 use crate::filter::Filter;
-use crate::node::RsvgNode;
+use crate::node::{NodeBorrow, RsvgNode};
 use crate::paint_server::PaintServer;
 use crate::properties::ComputedValues;
 use crate::rect::IRect;
@@ -111,8 +111,8 @@ impl FilterContext {
         // However, with userSpaceOnUse it's still possible to create images with a filter.
         let bbox_rect = node_bbox.rect.unwrap_or_default();
 
-        let node_data = filter_node.borrow();
-        let filter = node_data.get_impl::<Filter>();
+        let elt = filter_node.borrow_element();
+        let filter = elt.get_impl::<Filter>();
 
         let affine = match filter.get_filter_units() {
             CoordUnits::UserSpaceOnUse => draw_transform,
@@ -256,8 +256,8 @@ impl FilterContext {
 
     /// Pushes the viewport size based on the value of `primitiveUnits`.
     pub fn get_view_params(&self, draw_ctx: &mut DrawingCtx) -> ViewParams {
-        let node_data = self.node.borrow();
-        let filter = node_data.get_impl::<Filter>();
+        let elt = self.node.borrow_element();
+        let filter = elt.get_impl::<Filter>();
 
         // See comments in compute_effects_region() for how this works.
         if filter.get_primitive_units() == CoordUnits::ObjectBoundingBox {
diff --git a/rsvg_internals/src/filters/light/lighting.rs b/rsvg_internals/src/filters/light/lighting.rs
index 020411cd..01b41a3e 100644
--- a/rsvg_internals/src/filters/light/lighting.rs
+++ b/rsvg_internals/src/filters/light/lighting.rs
@@ -18,7 +18,7 @@ use crate::filters::{
     },
     FilterEffect, FilterError, PrimitiveWithInput,
 };
-use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
+use crate::node::{CascadedValues, NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::parsers::{NumberOptionalNumber, ParseValue};
 use crate::property_bag::PropertyBag;
 use crate::surface_utils::{
@@ -504,14 +504,23 @@ fn find_light_source(node: &RsvgNode, ctx: &FilterContext) -> Result<LightSource
     }
 
     let node = node.unwrap();
-    if node.borrow().is_in_error() {
+    if node.borrow_element().is_in_error() {
         return Err(FilterError::ChildNodeInError);
     }
 
     let light_source = match node.borrow().get_type() {
-        NodeType::FeDistantLight => node.borrow().get_impl::<FeDistantLight>().transform(ctx),
-        NodeType::FePointLight => node.borrow().get_impl::<FePointLight>().transform(ctx),
-        NodeType::FeSpotLight => node.borrow().get_impl::<FeSpotLight>().transform(ctx),
+        NodeType::FeDistantLight => node
+            .borrow_element()
+            .get_impl::<FeDistantLight>()
+            .transform(ctx),
+        NodeType::FePointLight => node
+            .borrow_element()
+            .get_impl::<FePointLight>()
+            .transform(ctx),
+        NodeType::FeSpotLight => node
+            .borrow_element()
+            .get_impl::<FeSpotLight>()
+            .transform(ctx),
         _ => unreachable!(),
     };
 
diff --git a/rsvg_internals/src/filters/merge.rs b/rsvg_internals/src/filters/merge.rs
index c70975f2..ddaac9d1 100644
--- a/rsvg_internals/src/filters/merge.rs
+++ b/rsvg_internals/src/filters/merge.rs
@@ -2,7 +2,7 @@ use markup5ever::{expanded_name, local_name, namespace_url, ns};
 
 use crate::document::AcquiredNodes;
 use crate::drawing_ctx::DrawingCtx;
-use crate::node::{NodeResult, NodeTrait, NodeType, RsvgNode};
+use crate::node::{NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::parsers::ParseValue;
 use crate::property_bag::PropertyBag;
 use crate::rect::IRect;
@@ -92,14 +92,16 @@ impl FilterEffect for FeMerge {
             .children()
             .filter(|c| c.borrow().get_type() == NodeType::FeMergeNode)
         {
-            if child.borrow().is_in_error() {
+            let elt = child.borrow_element();
+
+            if elt.is_in_error() {
                 return Err(FilterError::ChildNodeInError);
             }
 
             let input = ctx.get_input(
                 acquired_nodes,
                 draw_ctx,
-                child.borrow().get_impl::<FeMergeNode>().in_.as_ref(),
+                elt.get_impl::<FeMergeNode>().in_.as_ref(),
             )?;
             bounds = bounds.add_input(&input);
         }
@@ -111,7 +113,7 @@ impl FilterEffect for FeMerge {
             .children()
             .filter(|c| c.borrow().get_type() == NodeType::FeMergeNode)
         {
-            output_surface = Some(child.borrow().get_impl::<FeMergeNode>().render(
+            output_surface = Some(child.borrow_element().get_impl::<FeMergeNode>().render(
                 ctx,
                 acquired_nodes,
                 draw_ctx,
diff --git a/rsvg_internals/src/filters/mod.rs b/rsvg_internals/src/filters/mod.rs
index 79f61572..d3aee6d7 100644
--- a/rsvg_internals/src/filters/mod.rs
+++ b/rsvg_internals/src/filters/mod.rs
@@ -12,7 +12,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::error::{RenderingError, ValueErrorKind};
 use crate::filter::Filter;
 use crate::length::*;
-use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
+use crate::node::{CascadedValues, NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::parsers::ParseValue;
 use crate::properties::ComputedValues;
 use crate::property_bag::PropertyBag;
@@ -118,7 +118,12 @@ impl NodeTrait for Primitive {
         let primitiveunits = parent
             .and_then(|parent| {
                 if parent.borrow().get_type() == NodeType::Filter {
-                    Some(parent.borrow().get_impl::<Filter>().get_primitive_units())
+                    Some(
+                        parent
+                            .borrow_element()
+                            .get_impl::<Filter>()
+                            .get_primitive_units(),
+                    )
                 } else {
                     None
                 }
@@ -248,8 +253,8 @@ pub fn render(
     node_bbox: BoundingBox,
 ) -> Result<SharedImageSurface, RenderingError> {
     let filter_node = &*filter_node;
-    assert_eq!(filter_node.borrow().get_type(), NodeType::Filter);
-    assert!(!filter_node.borrow().is_in_error());
+    assert_eq!(filter_node.borrow_element().get_type(), NodeType::Filter);
+    assert!(!filter_node.borrow_element().is_in_error());
 
     let mut filter_ctx = FilterContext::new(
         filter_node,
@@ -267,9 +272,10 @@ pub fn render(
 
     let primitives = filter_node
         .children()
+        .filter(|c| c.is_element())
         // Skip nodes in error.
         .filter(|c| {
-            let in_error = c.borrow().is_in_error();
+            let in_error = c.borrow_element().is_in_error();
 
             if in_error {
                 rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
@@ -278,7 +284,12 @@ pub fn render(
             !in_error
         })
         // Keep only filter primitives (those that implement the Filter trait)
-        .filter(|c| c.borrow().get_node_trait().as_filter_effect().is_some())
+        .filter(|c| {
+            c.borrow_element()
+                .get_node_trait()
+                .as_filter_effect()
+                .is_some()
+        })
         // Check if the node wants linear RGB.
         .map(|c| {
             let linear_rgb = {
@@ -292,8 +303,8 @@ pub fn render(
         });
 
     for (c, linear_rgb) in primitives {
-        let node_data = c.borrow();
-        let filter = node_data.get_node_trait().as_filter_effect().unwrap();
+        let elt = c.borrow_element();
+        let filter = elt.get_node_trait().as_filter_effect().unwrap();
 
         let mut render = |filter_ctx: &mut FilterContext| {
             if let Err(err) = filter
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index db44c184..fe46f4fb 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -11,7 +11,7 @@ use crate::document::{AcquiredNode, AcquiredNodes, NodeStack};
 use crate::drawing_ctx::{DrawingCtx, ViewParams};
 use crate::error::*;
 use crate::length::*;
-use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
+use crate::node::{CascadedValues, NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::paint_server::{AsPaintSource, PaintSource};
 use crate::parsers::{Parse, ParseValue};
 use crate::properties::ComputedValues;
@@ -448,8 +448,8 @@ impl UnresolvedGradient {
 
         assert!(node_type == NodeType::LinearGradient || node_type == NodeType::RadialGradient);
 
-        for child_node in node.children() {
-            let child = child_node.borrow();
+        for child_node in node.children().filter(|c| c.is_element()) {
+            let child = child_node.borrow_element();
 
             if child.get_type() != NodeType::Stop {
                 continue;
@@ -661,7 +661,7 @@ macro_rules! impl_paint_source {
                             return Err(AcquireError::CircularReference(acquired_node.clone()));
                         }
 
-                        let borrowed_node = acquired_node.borrow();
+                        let borrowed_node = acquired_node.borrow_element();
                         let unresolved = match borrowed_node.get_type() {
                             $node_type => {
                                 let a_gradient = borrowed_node.get_impl::<$gradient>();
@@ -851,7 +851,7 @@ mod tests {
             Box::new(LinearGradient::default()),
         ));
 
-        let borrow = node.borrow();
+        let borrow = node.borrow_element();
         let g = borrow.get_impl::<LinearGradient>();
         let Unresolved { gradient, .. } = g.get_unresolved(&node);
         let gradient = gradient.resolve_from_defaults();
@@ -865,7 +865,7 @@ mod tests {
             Box::new(RadialGradient::default()),
         ));
 
-        let borrow = node.borrow();
+        let borrow = node.borrow_element();
         let g = borrow.get_impl::<RadialGradient>();
         let Unresolved { gradient, .. } = g.get_unresolved(&node);
         let gradient = gradient.resolve_from_defaults();
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index a615654d..87b7fc5f 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -14,7 +14,7 @@ use crate::document::{AcquiredNodes, Document};
 use crate::dpi::Dpi;
 use crate::drawing_ctx::DrawingCtx;
 use crate::error::{DefsLookupErrorKind, LoadingError, RenderingError};
-use crate::node::{CascadedValues, RsvgNode};
+use crate::node::{CascadedValues, NodeBorrow, RsvgNode};
 use crate::rect::{IRect, Rect};
 use crate::structure::{IntrinsicDimensions, Svg};
 use url::Url;
@@ -334,8 +334,10 @@ impl Handle {
             let cascaded = CascadedValues::new_from_node(&node);
             let values = cascaded.get();
 
-            if let Some((root_width, root_height)) =
-                node.borrow().get_impl::<Svg>().get_size(&values, dpi)
+            if let Some((root_width, root_height)) = node
+                .borrow_element()
+                .get_impl::<Svg>()
+                .get_size(&values, dpi)
             {
                 let rect = IRect::from_size(root_width, root_height);
 
diff --git a/rsvg_internals/src/marker.rs b/rsvg_internals/src/marker.rs
index bac0efc3..5f716c24 100644
--- a/rsvg_internals/src/marker.rs
+++ b/rsvg_internals/src/marker.rs
@@ -573,7 +573,7 @@ fn emit_marker_by_name(
     if let Ok(acquired) = acquired_nodes.acquire(name, &[NodeType::Marker]) {
         let node = acquired.get();
 
-        node.borrow().get_impl::<Marker>().render(
+        node.borrow_element().get_impl::<Marker>().render(
             &node,
             acquired_nodes,
             draw_ctx,
diff --git a/rsvg_internals/src/node.rs b/rsvg_internals/src/node.rs
index 8ee42567..e44abffc 100644
--- a/rsvg_internals/src/node.rs
+++ b/rsvg_internals/src/node.rs
@@ -14,8 +14,8 @@
 
 use downcast_rs::*;
 use locale_config::Locale;
-use markup5ever::{expanded_name, local_name, namespace_url, ns, LocalName, Namespace, QualName};
-use std::cell::Ref;
+use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};
+use std::cell::{Ref, RefMut};
 use std::collections::HashSet;
 use std::fmt;
 
@@ -43,8 +43,13 @@ pub type RsvgNode = rctree::Node<NodeData>;
 /// See the [module documentation](index.html) for more information.
 pub type RsvgWeakNode = rctree::WeakNode<NodeData>;
 
-/// Contents of a tree node
-pub struct NodeData {
+pub enum NodeData {
+    Element(Element),
+    Text(NodeChars),
+}
+
+/// Contents of an element node in the DOM
+pub struct Element {
     node_type: NodeType,
     element_name: QualName,
     id: Option<String>,    // id attribute from XML element
@@ -67,7 +72,7 @@ impl NodeData {
         class: Option<&str>,
         node_impl: Box<dyn NodeTrait>,
     ) -> NodeData {
-        NodeData {
+        NodeData::Element(Element {
             node_type,
             element_name: element_name.clone(),
             id: id.map(str::to_string),
@@ -80,21 +85,24 @@ impl NodeData {
             cond: true,
             style_attr: String::new(),
             node_impl,
-        }
+        })
     }
 
     pub fn new_chars() -> NodeData {
-        Self::new_element(
-            NodeType::Chars,
-            &QualName::new(
-                None,
-                Namespace::from("https://wiki.gnome.org/Projects/LibRsvg";),
-                LocalName::from("rsvg-chars"),
-            ),
-            None,
-            None,
-            Box::new(NodeChars::new()),
-        )
+        NodeData::Text(NodeChars::new())
+    }
+
+    pub fn get_type(&self) -> NodeType {
+        match *self {
+            NodeData::Element(ref e) => e.node_type,
+            NodeData::Text(_) => NodeType::Chars,
+        }
+    }
+}
+
+impl Element {
+    pub fn get_type(&self) -> NodeType {
+        self.node_type
     }
 
     pub fn get_node_trait(&self) -> &dyn NodeTrait {
@@ -109,14 +117,6 @@ impl NodeData {
         }
     }
 
-    pub fn get_type(&self) -> NodeType {
-        self.node_type
-    }
-
-    pub fn get_chars(&self) -> &NodeChars {
-        self.get_impl::<NodeChars>()
-    }
-
     pub fn element_name(&self) -> &QualName {
         &self.element_name
     }
@@ -280,12 +280,25 @@ impl NodeData {
 
 impl fmt::Display for NodeData {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{:?} id={}",
-            self.get_type(),
-            self.get_id().unwrap_or("None")
-        )
+        write!(f, "{:?}", self.get_type())?;
+
+        match *self {
+            NodeData::Element(ref e) => {
+                write!(f, " id={}", e.get_id().unwrap_or("None"))?;
+            }
+
+            _ => (),
+        }
+
+        Ok(())
+    }
+}
+
+impl fmt::Display for Element {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self.get_type())?;
+        write!(f, " id={}", self.get_id().unwrap_or("None"))?;
+        Ok(())
     }
 }
 
@@ -304,7 +317,7 @@ pub struct CascadedValues<'a> {
 }
 
 enum CascadedInner<'a> {
-    FromNode(Ref<'a, NodeData>),
+    FromNode(Ref<'a, Element>),
     FromValues(ComputedValues),
 }
 
@@ -317,7 +330,7 @@ impl<'a> CascadedValues<'a> {
     pub fn new(&self, node: &'a RsvgNode) -> CascadedValues<'a> {
         match self.inner {
             CascadedInner::FromNode(_) => CascadedValues {
-                inner: CascadedInner::FromNode(node.borrow()),
+                inner: CascadedInner::FromNode(node.borrow_element()),
             },
 
             CascadedInner::FromValues(ref v) => CascadedValues::new_from_values(node, v),
@@ -331,7 +344,7 @@ impl<'a> CascadedValues<'a> {
     /// `new()` to derive the cascade from an existing one.
     pub fn new_from_node(node: &RsvgNode) -> CascadedValues<'_> {
         CascadedValues {
-            inner: CascadedInner::FromNode(node.borrow()),
+            inner: CascadedInner::FromNode(node.borrow_element()),
         }
     }
 
@@ -342,7 +355,9 @@ impl<'a> CascadedValues<'a> {
     /// `<use>`'s own cascade, not wih the element's original cascade.
     pub fn new_from_values(node: &'a RsvgNode, values: &ComputedValues) -> CascadedValues<'a> {
         let mut v = values.clone();
-        node.borrow().specified_values.to_computed_values(&mut v);
+        node.borrow_element()
+            .specified_values
+            .to_computed_values(&mut v);
 
         CascadedValues {
             inner: CascadedInner::FromValues(v),
@@ -355,7 +370,7 @@ impl<'a> CascadedValues<'a> {
     /// `ComputedValues` from the `CascadedValues` that got passed to `draw()`.
     pub fn get(&'a self) -> &'a ComputedValues {
         match self.inner {
-            CascadedInner::FromNode(ref node) => &node.values,
+            CascadedInner::FromNode(ref element) => &element.values,
             CascadedInner::FromValues(ref v) => v,
         }
     }
@@ -478,6 +493,57 @@ pub enum NodeType {
     FeTurbulence,
 }
 
+/// Helper trait to get different NodeData variants
+pub trait NodeBorrow {
+    /// Returns `false` for NodeData::Text, `true` otherwise.
+    fn is_element(&self) -> bool;
+
+    /// Borrows a `NodeChars` reference.
+    ///
+    /// Panics: will panic if `&self` is not a `NodeData::Text` node
+    fn borrow_chars(&self) -> Ref<NodeChars>;
+
+    /// Borrows an `Element` reference
+    ///
+    /// Panics: will panic if `&self` is not a `NodeData::Element` node
+    fn borrow_element(&self) -> Ref<Element>;
+
+    /// Borrows an `Element` reference mutably
+    ///
+    /// Panics: will panic if `&self` is not a `NodeData::Element` node
+    fn borrow_element_mut(&mut self) -> RefMut<Element>;
+}
+
+impl NodeBorrow for RsvgNode {
+    fn is_element(&self) -> bool {
+        match *self.borrow() {
+            NodeData::Element(_) => true,
+            _ => false,
+        }
+    }
+
+    fn borrow_chars(&self) -> Ref<NodeChars> {
+        Ref::map(self.borrow(), |n| match *n {
+            NodeData::Text(ref c) => c,
+            _ => panic!("tried to borrow_chars for a non-text node"),
+        })
+    }
+
+    fn borrow_element(&self) -> Ref<Element> {
+        Ref::map(self.borrow(), |n| match *n {
+            NodeData::Element(ref e) => e,
+            _ => panic!("tried to borrow_element for a non-element node"),
+        })
+    }
+
+    fn borrow_element_mut(&mut self) -> RefMut<Element> {
+        RefMut::map(self.borrow_mut(), |n| match *n {
+            NodeData::Element(ref mut e) => e,
+            _ => panic!("tried to borrow_element_mut for a non-element node"),
+        })
+    }
+}
+
 /// Helper trait for cascading recursively
 pub trait NodeCascade {
     fn cascade(&mut self, values: &ComputedValues);
@@ -488,13 +554,13 @@ impl NodeCascade for RsvgNode {
         let mut values = values.clone();
 
         {
-            let mut node_mut = self.borrow_mut();
+            let mut elt = self.borrow_element_mut();
 
-            node_mut.specified_values.to_computed_values(&mut values);
-            node_mut.values = values.clone();
+            elt.specified_values.to_computed_values(&mut values);
+            elt.values = values.clone();
         }
 
-        for mut child in self.children() {
+        for mut child in self.children().filter(|c| c.is_element()) {
             child.cascade(&values);
         }
     }
@@ -527,18 +593,23 @@ impl NodeDraw for RsvgNode {
         draw_ctx: &mut DrawingCtx,
         clipping: bool,
     ) -> Result<BoundingBox, RenderingError> {
-        if !self.borrow().is_in_error() {
-            let transform = self.borrow().get_transform();
-            draw_ctx.with_saved_transform(Some(transform), &mut |dc| {
-                self.borrow()
-                    .get_node_trait()
-                    .draw(self, acquired_nodes, cascaded, dc, clipping)
-            })
-        } else {
-            rsvg_log!("(not rendering element {} because it is in error)", self);
+        match *self.borrow() {
+            NodeData::Element(ref e) => {
+                if !e.is_in_error() {
+                    let transform = e.get_transform();
+                    draw_ctx.with_saved_transform(Some(transform), &mut |dc| {
+                        e.get_node_trait()
+                            .draw(self, acquired_nodes, cascaded, dc, clipping)
+                    })
+                } else {
+                    rsvg_log!("(not rendering element {} because it is in error)", self);
+
+                    // maybe we should actually return a RenderingError::NodeIsInError here?
+                    Ok(draw_ctx.empty_bbox())
+                }
+            }
 
-            // maybe we should actually return a RenderingError::NodeIsInError here?
-            Ok(draw_ctx.empty_bbox())
+            _ => Ok(draw_ctx.empty_bbox()),
         }
     }
 
@@ -551,7 +622,7 @@ impl NodeDraw for RsvgNode {
     ) -> Result<BoundingBox, RenderingError> {
         let mut bbox = draw_ctx.empty_bbox();
 
-        for child in self.children() {
+        for child in self.children().filter(|c| c.is_element()) {
             let child_bbox = draw_ctx.draw_node_from_stack(
                 &child,
                 acquired_nodes,
diff --git a/rsvg_internals/src/pattern.rs b/rsvg_internals/src/pattern.rs
index 2eef1a8e..beaa484e 100644
--- a/rsvg_internals/src/pattern.rs
+++ b/rsvg_internals/src/pattern.rs
@@ -188,7 +188,7 @@ impl PaintSource for Pattern {
                             return Err(AcquireError::CircularReference(acquired_node.clone()));
                         }
 
-                        let borrowed_node = acquired_node.borrow();
+                        let borrowed_node = acquired_node.borrow_element();
                         let borrowed_pattern = borrowed_node.get_impl::<Pattern>();
                         let unresolved = borrowed_pattern.get_unresolved(&acquired_node);
 
@@ -478,10 +478,7 @@ impl UnresolvedChildren {
     fn from_node(node: &RsvgNode) -> UnresolvedChildren {
         let weak = node.downgrade();
 
-        if node
-            .children()
-            .any(|child| child.borrow().get_type() != NodeType::Chars)
-        {
+        if node.children().any(|child| child.is_element()) {
             UnresolvedChildren::WithChildren(weak)
         } else {
             UnresolvedChildren::Unresolved
@@ -578,7 +575,7 @@ mod tests {
             Box::new(Pattern::default()),
         ));
 
-        let borrow = node.borrow();
+        let borrow = node.borrow_element();
         let p = borrow.get_impl::<Pattern>();
         let Unresolved { pattern, .. } = p.get_unresolved(&node);
         let pattern = pattern.resolve_from_defaults();
diff --git a/rsvg_internals/src/structure.rs b/rsvg_internals/src/structure.rs
index a1034f97..e87992c5 100644
--- a/rsvg_internals/src/structure.rs
+++ b/rsvg_internals/src/structure.rs
@@ -76,8 +76,8 @@ impl NodeTrait for Switch {
         draw_ctx.with_discrete_layer(node, acquired_nodes, values, clipping, &mut |an, dc| {
             if let Some(child) = node
                 .children()
-                .filter(|c| c.borrow().get_type() != NodeType::Chars)
-                .find(|c| c.borrow().get_cond())
+                .filter(|c| c.is_element())
+                .find(|c| c.borrow_element().get_cond())
             {
                 dc.draw_node_from_stack(
                     &child,
diff --git a/rsvg_internals/src/text.rs b/rsvg_internals/src/text.rs
index e59af753..cc2c2369 100644
--- a/rsvg_internals/src/text.rs
+++ b/rsvg_internals/src/text.rs
@@ -12,7 +12,7 @@ use crate::error::*;
 use crate::float_eq_cairo::ApproxEqCairo;
 use crate::font_props::FontWeightSpec;
 use crate::length::*;
-use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
+use crate::node::{CascadedValues, NodeBorrow, NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::parsers::ParseValue;
 use crate::properties::ComputedValues;
 use crate::property_bag::PropertyBag;
@@ -432,14 +432,13 @@ fn children_to_chunks(
             NodeType::Chars => {
                 let values = cascaded.get();
                 child
-                    .borrow()
-                    .get_chars()
+                    .borrow_chars()
                     .to_chunks(&child, values, chunks, dx, dy, depth);
             }
 
             NodeType::TSpan => {
                 let cascaded = CascadedValues::new(cascaded, &child);
-                child.borrow().get_impl::<TSpan>().to_chunks(
+                child.borrow_element().get_impl::<TSpan>().to_chunks(
                     &child,
                     acquired_nodes,
                     &cascaded,
@@ -451,7 +450,7 @@ fn children_to_chunks(
 
             NodeType::TRef => {
                 let cascaded = CascadedValues::new(cascaded, &child);
-                child.borrow().get_impl::<TRef>().to_chunks(
+                child.borrow_element().get_impl::<TRef>().to_chunks(
                     &child,
                     acquired_nodes,
                     &cascaded,
@@ -568,12 +567,6 @@ impl NodeChars {
     }
 }
 
-impl NodeTrait for NodeChars {
-    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
-        Ok(())
-    }
-}
-
 #[derive(Default)]
 pub struct Text {
     x: Length<Horizontal>,
@@ -717,9 +710,9 @@ fn extract_chars_children_to_chunks_recursively(
     for child in node.children() {
         match child.borrow().get_type() {
             NodeType::Chars => child
-                .borrow()
-                .get_chars()
+                .borrow_chars()
                 .to_chunks(&child, values, chunks, None, None, depth),
+
             _ => extract_chars_children_to_chunks_recursively(chunks, &child, values, depth + 1),
         }
     }
diff --git a/rsvg_internals/src/xml.rs b/rsvg_internals/src/xml.rs
index 2a61c2a6..f83f8017 100644
--- a/rsvg_internals/src/xml.rs
+++ b/rsvg_internals/src/xml.rs
@@ -16,7 +16,7 @@ use crate::document::{Document, DocumentBuilder};
 use crate::error::LoadingError;
 use crate::io::{self, get_input_stream_for_loading};
 use crate::limits::MAX_LOADED_ELEMENTS;
-use crate::node::{NodeType, RsvgNode};
+use crate::node::{NodeBorrow, NodeType, RsvgNode};
 use crate::property_bag::PropertyBag;
 use crate::style::{Style, StyleType};
 use crate::xml2_load::Xml2Parser;
@@ -361,7 +361,7 @@ impl XmlState {
         assert!(current_node.borrow().get_type() == NodeType::Style);
 
         let style_type = current_node
-            .borrow()
+            .borrow_element()
             .get_impl::<Style>()
             .style_type()
             .unwrap_or(StyleType::TextCss);
@@ -370,10 +370,10 @@ impl XmlState {
             let stylesheet_text = current_node
                 .children()
                 .map(|child| {
-                    let child_borrow = child.borrow();
-
-                    assert!(child_borrow.get_type() == NodeType::Chars);
-                    child_borrow.get_chars().get_string()
+                    // Note that here we assume that the only children of <style>
+                    // are indeed text nodes.
+                    let child_borrow = child.borrow_chars();
+                    child_borrow.get_string()
                 })
                 .collect::<String>();
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]