[librsvg] drawing_ctx: add draw_from_use_node method



commit 2b58cbf8d1bd0c3ab6cf4e0e6f1db69139629365
Author: Paolo Borelli <pborelli gnome org>
Date:   Thu Jan 2 18:44:20 2020 +0100

    drawing_ctx: add draw_from_use_node method
    
    Move the logic required to draw a node specified through the
    <use> element inside the drawing context.

 rsvg_internals/src/drawing_ctx.rs | 109 +++++++++++++++++++++++++++-
 rsvg_internals/src/structure.rs   | 149 ++++++++++----------------------------
 2 files changed, 144 insertions(+), 114 deletions(-)
---
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index 7d8bc367..377ca997 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -24,10 +24,11 @@ use crate::paint_server::{PaintServer, PaintSource};
 use crate::pattern::Pattern;
 use crate::properties::ComputedValues;
 use crate::property_defs::{
-    ClipRule, FillRule, Opacity, ShapeRendering, StrokeDasharray, StrokeLinecap, StrokeLinejoin,
+    ClipRule, FillRule, Opacity, Overflow, ShapeRendering, StrokeDasharray, StrokeLinecap,
+    StrokeLinejoin,
 };
 use crate::rect::{Rect, TransformRect};
-use crate::structure::{ClipPath, Mask};
+use crate::structure::{ClipPath, Mask, Symbol, Use};
 use crate::surface_utils::{shared_surface::SharedImageSurface, shared_surface::SurfaceType};
 use crate::unit_interval::UnitInterval;
 use crate::viewbox::ViewBox;
@@ -332,7 +333,7 @@ impl DrawingCtx {
         self.acquired_nodes.acquire(fragment, node_types)
     }
 
-    pub fn acquire_node_ref(&mut self, node: &RsvgNode) -> Result<AcquiredNode, AcquireError> {
+    fn acquire_node_ref(&mut self, node: &RsvgNode) -> Result<AcquiredNode, AcquireError> {
         self.acquired_nodes.push_node_ref(node)
     }
 
@@ -1002,6 +1003,108 @@ impl DrawingCtx {
 
         res
     }
+
+    pub fn draw_from_use_node(
+        &mut self,
+        node: &RsvgNode,
+        cascaded: &CascadedValues<'_>,
+        clipping: bool,
+    ) -> Result<BoundingBox, RenderingError> {
+        let node_data = node.borrow();
+        let use_ = node_data.get_impl::<Use>();
+
+        // <use> is an element that is used directly, unlike
+        // <pattern>, which is used through a fill="url(#...)"
+        // reference.  However, <use> will always reference another
+        // element, potentially itself or an ancestor of itself (or
+        // another <use> which references the first one, etc.).  So,
+        // we acquire the <use> element itself so that circular
+        // references can be caught.
+        let _self_acquired = self.acquire_node_ref(node).map_err(|e| {
+            if let AcquireError::CircularReference(_) = e {
+                rsvg_log!("circular reference in element {}", node);
+                RenderingError::CircularReference
+            } else {
+                unreachable!();
+            }
+        })?;
+
+        let link = use_.get_link();
+        if link.is_none() {
+            return Ok(self.empty_bbox());
+        }
+
+        let acquired = match self.acquire_node(link.unwrap(), &[]) {
+            Ok(acquired) => acquired,
+
+            Err(AcquireError::CircularReference(node)) => {
+                rsvg_log!("circular reference in element {}", node);
+                return Err(RenderingError::CircularReference);
+            }
+
+            Err(AcquireError::MaxReferencesExceeded) => {
+                return Err(RenderingError::InstancingLimit);
+            }
+
+            Err(AcquireError::InvalidLinkType(_)) => unreachable!(),
+
+            Err(AcquireError::LinkNotFound(fragment)) => {
+                rsvg_log!("element {} references nonexistent \"{}\"", node, fragment);
+                return Ok(self.empty_bbox());
+            }
+        };
+
+        let values = cascaded.get();
+        let params = self.get_view_params();
+        let use_rect = use_.get_rect(values, &params);
+
+        // width or height set to 0 disables rendering of the element
+        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
+        if use_rect.is_empty() {
+            return Ok(self.empty_bbox());
+        }
+
+        let child = acquired.get();
+
+        if child.borrow().get_type() != NodeType::Symbol {
+            let cr = self.get_cairo_context();
+            cr.translate(use_rect.x0, use_rect.y0);
+
+            self.with_discrete_layer(node, values, clipping, &mut |dc| {
+                dc.draw_node_from_stack(
+                    &CascadedValues::new_from_values(&child, values),
+                    &child,
+                    clipping,
+                )
+            })
+        } else {
+            let node_data = child.borrow();
+            let symbol = node_data.get_impl::<Symbol>();
+
+            let clip_mode = if !values.is_overflow()
+                || (values.overflow == Overflow::Visible && child.borrow().is_overflow())
+            {
+                Some(ClipMode::ClipToVbox)
+            } else {
+                None
+            };
+
+            self.with_discrete_layer(node, values, clipping, &mut |dc| {
+                let _params = dc.push_new_viewport(
+                    symbol.get_viewbox(),
+                    use_rect,
+                    symbol.get_preserve_aspect_ratio(),
+                    clip_mode,
+                );
+
+                child.draw_children(
+                    &CascadedValues::new_from_values(&child, values),
+                    dc,
+                    clipping,
+                )
+            })
+        }
+    }
 }
 
 #[derive(Debug)]
diff --git a/rsvg_internals/src/structure.rs b/rsvg_internals/src/structure.rs
index c6b50af6..4bfa1d9c 100644
--- a/rsvg_internals/src/structure.rs
+++ b/rsvg_internals/src/structure.rs
@@ -9,13 +9,11 @@ use crate::coord_units::CoordUnits;
 use crate::dpi::Dpi;
 use crate::drawing_ctx::{ClipMode, DrawingCtx, ViewParams};
 use crate::error::*;
-use crate::float_eq_cairo::ApproxEqCairo;
 use crate::length::*;
 use crate::node::*;
 use crate::parsers::{Parse, ParseValue};
 use crate::properties::ComputedValues;
 use crate::property_bag::PropertyBag;
-use crate::property_defs::Overflow;
 use crate::rect::Rect;
 use crate::viewbox::*;
 
@@ -273,6 +271,33 @@ pub struct Use {
     h: Option<Length<Vertical>>,
 }
 
+impl Use {
+    pub fn get_link(&self) -> Option<&Fragment> {
+        self.link.as_ref()
+    }
+
+    pub fn get_rect(&self, values: &ComputedValues, params: &ViewParams) -> Rect {
+        let x = self.x.normalize(values, &params);
+        let y = self.y.normalize(values, &params);
+
+        // If attributes ‘width’ and/or ‘height’ are not specified,
+        // [...] use values of '100%' for these attributes.
+        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
+        // "If the ‘use’ element references a ‘symbol’ element"
+
+        let w = self
+            .w
+            .unwrap_or_else(|| Length::<Horizontal>::parse_str("100%").unwrap())
+            .normalize(values, &params);
+        let h = self
+            .h
+            .unwrap_or_else(|| Length::<Vertical>::parse_str("100%").unwrap())
+            .normalize(values, &params);
+
+        Rect::new(x, y, x + w, y + h)
+    }
+}
+
 impl NodeTrait for Use {
     fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
         for (attr, value) in pbag.iter() {
@@ -306,115 +331,7 @@ impl NodeTrait for Use {
         draw_ctx: &mut DrawingCtx,
         clipping: bool,
     ) -> Result<BoundingBox, RenderingError> {
-        let values = cascaded.get();
-
-        if self.link.is_none() {
-            return Ok(draw_ctx.empty_bbox());
-        }
-
-        let link = self.link.as_ref().unwrap();
-
-        // <use> is an element that is used directly, unlike
-        // <pattern>, which is used through a fill="url(#...)"
-        // reference.  However, <use> will always reference another
-        // element, potentially itself or an ancestor of itself (or
-        // another <use> which references the first one, etc.).  So,
-        // we acquire the <use> element itself so that circular
-        // references can be caught.
-        let _self_acquired = draw_ctx.acquire_node_ref(node).map_err(|e| {
-            if let AcquireError::CircularReference(_) = e {
-                rsvg_log!("circular reference in element {}", node);
-                RenderingError::CircularReference
-            } else {
-                unreachable!();
-            }
-        })?;
-
-        let acquired = match draw_ctx.acquire_node(link, &[]) {
-            Ok(acquired) => acquired,
-
-            Err(AcquireError::CircularReference(node)) => {
-                rsvg_log!("circular reference in element {}", node);
-                return Err(RenderingError::CircularReference);
-            }
-
-            Err(AcquireError::MaxReferencesExceeded) => {
-                return Err(RenderingError::InstancingLimit);
-            }
-
-            Err(AcquireError::InvalidLinkType(_)) => unreachable!(),
-
-            Err(AcquireError::LinkNotFound(fragment)) => {
-                rsvg_log!("element {} references nonexistent \"{}\"", node, fragment);
-                return Ok(draw_ctx.empty_bbox());
-            }
-        };
-
-        let child = acquired.get();
-
-        let params = draw_ctx.get_view_params();
-
-        let nx = self.x.normalize(values, &params);
-        let ny = self.y.normalize(values, &params);
-
-        // If attributes ‘width’ and/or ‘height’ are not specified,
-        // [...] use values of '100%' for these attributes.
-        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
-        // "If the ‘use’ element references a ‘symbol’ element"
-
-        let nw = self
-            .w
-            .unwrap_or_else(|| Length::<Horizontal>::parse_str("100%").unwrap())
-            .normalize(values, &params);
-        let nh = self
-            .h
-            .unwrap_or_else(|| Length::<Vertical>::parse_str("100%").unwrap())
-            .normalize(values, &params);
-
-        // width or height set to 0 disables rendering of the element
-        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
-        if nw.approx_eq_cairo(0.0) || nh.approx_eq_cairo(0.0) {
-            return Ok(draw_ctx.empty_bbox());
-        }
-
-        if child.borrow().get_type() != NodeType::Symbol {
-            let cr = draw_ctx.get_cairo_context();
-            cr.translate(nx, ny);
-
-            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
-                dc.draw_node_from_stack(
-                    &CascadedValues::new_from_values(&child, values),
-                    &child,
-                    clipping,
-                )
-            })
-        } else {
-            let node_data = child.borrow();
-            let symbol = node_data.get_impl::<Symbol>();
-
-            let clip_mode = if !values.is_overflow()
-                || (values.overflow == Overflow::Visible && child.borrow().is_overflow())
-            {
-                Some(ClipMode::ClipToVbox)
-            } else {
-                None
-            };
-
-            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
-                let _params = dc.push_new_viewport(
-                    symbol.vbox,
-                    Rect::new(nx, ny, nx + nw, ny + nh),
-                    symbol.preserve_aspect_ratio,
-                    clip_mode,
-                );
-
-                child.draw_children(
-                    &CascadedValues::new_from_values(&child, values),
-                    dc,
-                    clipping,
-                )
-            })
-        }
+        draw_ctx.draw_from_use_node(node, cascaded, clipping)
     }
 }
 
@@ -424,6 +341,16 @@ pub struct Symbol {
     vbox: Option<ViewBox>,
 }
 
+impl Symbol {
+    pub fn get_viewbox(&self) -> Option<ViewBox> {
+        self.vbox
+    }
+
+    pub fn get_preserve_aspect_ratio(&self) -> AspectRatio {
+        self.preserve_aspect_ratio
+    }
+}
+
 impl NodeTrait for Symbol {
     fn set_atts(&mut self, _parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
         for (attr, value) in pbag.iter() {


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