[librsvg] ViewBox: Represent unspecified view boxes as Option<ViewBox>



commit 5afb3a858f63e7dedf6ef7b73726acb3d2072175
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Aug 31 20:03:22 2017 -0500

    ViewBox: Represent unspecified view boxes as Option<ViewBox>
    
    We still have RsvgViewBox with an "active" boolean field for the C
    code.  The Rust code now handles Option<ViewBox> throughout, and only
    exposes that to C with rsvg_node_svg_get_view_box().

 rust/src/marker.rs    |   28 +++++++--------
 rust/src/pattern.rs   |   26 ++++++++------
 rust/src/structure.rs |   46 +++++++++++--------------
 rust/src/viewbox.rs   |   89 ++++++++++++++++++++++---------------------------
 4 files changed, 89 insertions(+), 100 deletions(-)
---
diff --git a/rust/src/marker.rs b/rust/src/marker.rs
index 5b9fdda..25ee6c2 100644
--- a/rust/src/marker.rs
+++ b/rust/src/marker.rs
@@ -86,7 +86,7 @@ struct NodeMarker {
     height: Cell<RsvgLength>,
     orient: Cell<MarkerOrient>,
     aspect: Cell<AspectRatio>,
-    vbox:   Cell<RsvgViewBox>
+    vbox:   Cell<Option<ViewBox>>
 }
 
 impl NodeMarker {
@@ -99,7 +99,7 @@ impl NodeMarker {
             height: Cell::new (NodeMarker::get_default_size ()),
             orient: Cell::new (MarkerOrient::default ()),
             aspect: Cell::new (AspectRatio::default ()),
-            vbox:   Cell::new (RsvgViewBox::default ())
+            vbox:   Cell::new (None)
         }
     }
 
@@ -137,16 +137,14 @@ impl NodeMarker {
             affine.scale (line_width, line_width);
         }
 
-        let vbox = self.vbox.get ();
-
-        if vbox.is_active () {
-            let (_, _, w, h) = self.aspect.get ().compute (vbox.rect.width, vbox.rect.height,
+        if let Some (vbox) = self.vbox.get () {
+            let (_, _, w, h) = self.aspect.get ().compute (vbox.0.width, vbox.0.height,
                                                            0.0, 0.0,
                                                            marker_width, marker_height);
 
-            affine.scale (w / vbox.rect.width, h / vbox.rect.height);
+            affine.scale (w / vbox.0.width, h / vbox.0.height);
 
-            drawing_ctx::push_view_box (draw_ctx, vbox.rect.width, vbox.rect.height);
+            drawing_ctx::push_view_box (draw_ctx, vbox.0.width, vbox.0.height);
         }
 
         affine.translate (-self.ref_x.get ().normalize (draw_ctx),
@@ -165,12 +163,12 @@ impl NodeMarker {
         let state = drawing_ctx::get_current_state (draw_ctx);
 
         if !drawing_ctx::state_is_overflow (state) {
-            if vbox.is_active () {
+            if let Some (vbox) = self.vbox.get () {
                 drawing_ctx::add_clipping_rect (draw_ctx,
-                                                vbox.rect.x,
-                                                vbox.rect.y,
-                                                vbox.rect.width,
-                                                vbox.rect.height);
+                                                vbox.0.x,
+                                                vbox.0.y,
+                                                vbox.0.width,
+                                                vbox.0.height);
             } else {
                 drawing_ctx::add_clipping_rect (draw_ctx,
                                                 0.0,
@@ -186,7 +184,7 @@ impl NodeMarker {
 
         drawing_ctx::state_pop (draw_ctx);
 
-        if vbox.is_active () {
+        if let Some (_) = self.vbox.get () {
             drawing_ctx::pop_view_box (draw_ctx);
         }
     }
@@ -206,7 +204,7 @@ impl NodeTrait for NodeMarker {
 
         self.orient.set (property_bag::parse_or_default (pbag, "orient")?);
         self.aspect.set (property_bag::parse_or_default (pbag, "preserveAspectRatio")?);
-        self.vbox.set   (property_bag::parse_or_default (pbag, "viewBox")?);
+        self.vbox.set   (property_bag::parse_or_none (pbag, "viewBox")?);
         self.aspect.set (property_bag::parse_or_default (pbag, "preserveAspectRatio")?);
 
         Ok (())
diff --git a/rust/src/pattern.rs b/rust/src/pattern.rs
index f8b7486..53dd72f 100644
--- a/rust/src/pattern.rs
+++ b/rust/src/pattern.rs
@@ -28,7 +28,11 @@ use viewbox::*;
 pub struct Pattern {
     pub units:                 Option<PaintServerUnits>,
     pub content_units:         Option<PatternContentUnits>,
-    pub vbox:                  Option<RsvgViewBox>,
+    // This Option<Option<ViewBox>> is a bit strange.  We want a field
+    // with value None to mean, "this field isn't resolved yet".  However,
+    // the vbox can very well be *not* specified in the SVG file.
+    // In that case, the fully resolved pattern will have a .vbox=Some(None) value.
+    pub vbox:                  Option<Option<ViewBox>>,
     pub preserve_aspect_ratio: Option<AspectRatio>,
     pub affine:                Option<cairo::Matrix>,
     pub fallback:              Option<String>,
@@ -141,7 +145,7 @@ impl Pattern {
 
         fallback_to! (self.units,                 Some (PaintServerUnits::default ()));
         fallback_to! (self.content_units,         Some (PatternContentUnits::default ()));
-        fallback_to! (self.vbox,                  Some (RsvgViewBox::new_inactive ()));
+        fallback_to! (self.vbox,                  Some (None));
         fallback_to! (self.preserve_aspect_ratio, Some (AspectRatio::default ()));
         fallback_to! (self.affine,                Some (cairo::Matrix::identity ()));
 
@@ -196,7 +200,7 @@ impl NodeTrait for NodePattern {
 
         p.units         = property_bag::parse_or_none (pbag, "patternUnits")?;
         p.content_units = property_bag::parse_or_none (pbag, "patternContentUnits")?;
-        p.vbox          = property_bag::parse_or_none (pbag, "viewBox")?;
+        p.vbox          = property_bag::parse_or_none (pbag, "viewBox")?.map (|v| Some(v)).or (None);
 
         p.preserve_aspect_ratio = property_bag::parse_or_none (pbag, "preserveAspectRatio")?;
 
@@ -371,26 +375,26 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
     let pushed_view_box: bool;
 
     // Create the pattern contents coordinate system
-    if vbox.is_active () {
+    if let Some (vbox) = vbox {
         // If there is a vbox, use that
-        let (mut x, mut y, w, h) = preserve_aspect_ratio.compute (vbox.rect.width,
-                                                                  vbox.rect.height,
+        let (mut x, mut y, w, h) = preserve_aspect_ratio.compute (vbox.0.width,
+                                                                  vbox.0.height,
                                                                   0.0,
                                                                   0.0,
                                                                   pattern_width * bbwscale,
                                                                   pattern_height * bbhscale);
 
-        x -= vbox.rect.x * w / vbox.rect.width;
-        y -= vbox.rect.y * h / vbox.rect.height;
+        x -= vbox.0.x * w / vbox.0.width;
+        y -= vbox.0.y * h / vbox.0.height;
 
-        caffine = cairo::Matrix::new (w / vbox.rect.width,
+        caffine = cairo::Matrix::new (w / vbox.0.width,
                                       0.0,
                                       0.0,
-                                      h / vbox.rect.height,
+                                      h / vbox.0.height,
                                       x,
                                       y);
 
-        drawing_ctx::push_view_box (draw_ctx, vbox.rect.width, vbox.rect.height);
+        drawing_ctx::push_view_box (draw_ctx, vbox.0.width, vbox.0.height);
         pushed_view_box = true;
     } else if content_units == PatternContentUnits (PaintServerUnits::ObjectBoundingBox) {
         // If coords are in terms of the bounding box, use them
diff --git a/rust/src/structure.rs b/rust/src/structure.rs
index 2611819..bd45720 100644
--- a/rust/src/structure.rs
+++ b/rust/src/structure.rs
@@ -115,7 +115,7 @@ struct NodeSvg {
     y:                     Cell<RsvgLength>,
     w:                     Cell<RsvgLength>,
     h:                     Cell<RsvgLength>,
-    vbox:                  Cell<RsvgViewBox>,
+    vbox:                  Cell<Option<ViewBox>>,
     atts:                  Cell<*mut RsvgPropertyBag>
 }
 
@@ -127,7 +127,7 @@ impl NodeSvg {
             y:                     Cell::new (RsvgLength::parse ("0", LengthDir::Vertical).unwrap ()),
             w:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Horizontal).unwrap ()),
             h:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Vertical).unwrap ()),
-            vbox:                  Cell::new (RsvgViewBox::default ()),
+            vbox:                  Cell::new (None),
             atts:                  Cell::new (ptr::null_mut ())
         }
     }
@@ -165,7 +165,7 @@ impl NodeTrait for NodeSvg {
             self.h.set (h);
         }
 
-        self.vbox.set (property_bag::parse_or_default (pbag, "viewBox")?);
+        self.vbox.set (property_bag::parse_or_none (pbag, "viewBox")?);
 
         // The "style" sub-element is not loaded yet here, so we need
         // to store other attributes to be applied later.
@@ -192,25 +192,23 @@ impl NodeTrait for NodeSvg {
 
         let affine_old = drawing_ctx::get_current_state_affine (draw_ctx);
 
-        let vbox = self.vbox.get ();
-
-        if vbox.is_active () {
+        if let Some (vbox) = self.vbox.get () {
             // viewBox width==0 or height==0 disables rendering of the element
             // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
-            if double_equals (vbox.rect.width, 0.0) || double_equals (vbox.rect.height, 0.0) {
+            if double_equals (vbox.0.width, 0.0) || double_equals (vbox.0.height, 0.0) {
                 return;
             }
 
-            let (x, y, w, h) = self.preserve_aspect_ratio.get ().compute (vbox.rect.width, vbox.rect.height,
+            let (x, y, w, h) = self.preserve_aspect_ratio.get ().compute (vbox.0.width, vbox.0.height,
                                                                           nx, ny, nw, nh);
 
             let mut affine = affine_old;
             affine.translate (x, y);
-            affine.scale (w / vbox.rect.width, h / vbox.rect.height);
-            affine.translate (-vbox.rect.x, -vbox.rect.y);
+            affine.scale (w / vbox.0.width, h / vbox.0.height);
+            affine.translate (-vbox.0.x, -vbox.0.y);
             drawing_ctx::set_current_state_affine (draw_ctx, affine);
 
-            drawing_ctx::push_view_box (draw_ctx, vbox.rect.width, vbox.rect.height);
+            drawing_ctx::push_view_box (draw_ctx, vbox.0.width, vbox.0.height);
         } else {
             let mut affine = affine_old;
             affine.translate (nx, ny);
@@ -375,25 +373,23 @@ impl NodeTrait for NodeUse {
             drawing_ctx::pop_discrete_layer (draw_ctx);
         } else {
             child.with_impl (|symbol: &NodeSymbol| {
-                let vbox = symbol.vbox.get ();
-
-                if vbox.is_active () {
-                    let (x, y, w, h) = symbol.preserve_aspect_ratio.get ().compute (vbox.rect.width, 
vbox.rect.height,
+                if let Some (vbox) = symbol.vbox.get () {
+                    let (x, y, w, h) = symbol.preserve_aspect_ratio.get ().compute (vbox.0.width, 
vbox.0.height,
                                                                                     nx, ny, nw, nh);
 
                     let mut affine = drawing_ctx::get_current_state_affine (draw_ctx);
                     affine.translate (x, y);
-                    affine.scale (w / vbox.rect.width, h / vbox.rect.height);
-                    affine.translate (-vbox.rect.x, -vbox.rect.y);
+                    affine.scale (w / vbox.0.width, h / vbox.0.height);
+                    affine.translate (-vbox.0.x, -vbox.0.y);
                     drawing_ctx::set_current_state_affine (draw_ctx, affine);
 
-                    drawing_ctx::push_view_box (draw_ctx, vbox.rect.width, vbox.rect.height);
+                    drawing_ctx::push_view_box (draw_ctx, vbox.0.width, vbox.0.height);
 
                     drawing_ctx::push_discrete_layer (draw_ctx);
 
                     if !drawing_ctx::state_is_overflow (state) || (!drawing_ctx::state_has_overflow (state)
                                                                    && drawing_ctx::state_is_overflow 
(child.get_state ())) {
-                        drawing_ctx::add_clipping_rect (draw_ctx, vbox.rect.x, vbox.rect.y, vbox.rect.width, 
vbox.rect.height);
+                        drawing_ctx::add_clipping_rect (draw_ctx, vbox.0.x, vbox.0.y, vbox.0.width, 
vbox.0.height);
                     }
                 } else {
                     let mut affine = drawing_ctx::get_current_state_affine (draw_ctx);
@@ -410,7 +406,7 @@ impl NodeTrait for NodeUse {
                 drawing_ctx::state_pop (draw_ctx);
                 drawing_ctx::pop_discrete_layer (draw_ctx);
 
-                if vbox.is_active () {
+                if let Some (_) = symbol.vbox.get () {
                     drawing_ctx::pop_view_box (draw_ctx);
                 }
             });
@@ -428,14 +424,14 @@ impl NodeTrait for NodeUse {
 
 struct NodeSymbol {
     preserve_aspect_ratio: Cell<AspectRatio>,
-    vbox:                  Cell<RsvgViewBox>
+    vbox:                  Cell<Option<ViewBox>>
 }
 
 impl NodeSymbol {
     fn new () -> NodeSymbol {
         NodeSymbol {
             preserve_aspect_ratio: Cell::new (AspectRatio::default ()),
-            vbox:                  Cell::new (RsvgViewBox::default ())
+            vbox:                  Cell::new (None)
         }
     }
 }
@@ -443,7 +439,7 @@ impl NodeSymbol {
 impl NodeTrait for NodeSymbol {
     fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
         self.preserve_aspect_ratio.set (property_bag::parse_or_default (pbag, "preserveAspectRatio")?);
-        self.vbox.set (property_bag::parse_or_default (pbag, "viewBox")?);
+        self.vbox.set (property_bag::parse_or_none (pbag, "viewBox")?);
 
         Ok (())
     }
@@ -522,13 +518,13 @@ pub extern fn rsvg_node_svg_get_view_box (raw_node: *const RsvgNode) -> RsvgView
     assert! (!raw_node.is_null ());
     let node: &RsvgNode = unsafe { & *raw_node };
 
-    let mut vbox = RsvgViewBox::default ();
+    let mut vbox: Option<ViewBox> = None;
 
     node.with_impl (|svg: &NodeSvg| {
         vbox = svg.vbox.get ();
     });
 
-    vbox
+    RsvgViewBox::from (vbox)
 }
 
 extern "C" {
diff --git a/rust/src/viewbox.rs b/rust/src/viewbox.rs
index 3c1806a..9abe7a2 100644
--- a/rust/src/viewbox.rs
+++ b/rust/src/viewbox.rs
@@ -18,35 +18,29 @@ pub struct RsvgViewBox {
     active:   glib_sys::gboolean
 }
 
-impl RsvgViewBox {
-    pub fn new (rect: cairo::Rectangle,
-                active: bool) -> RsvgViewBox {
-        RsvgViewBox {
-            rect: rect,
-            active: active.to_glib ()
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct ViewBox(pub cairo::Rectangle);
+
+impl From<Option<ViewBox>> for RsvgViewBox {
+    fn from(v: Option<ViewBox>) -> RsvgViewBox {
+        if let Some(vb) = v {
+            RsvgViewBox {
+                rect: vb.0,
+                active: true.to_glib ()
+            }
+        } else {
+            RsvgViewBox {
+                rect: cairo::Rectangle { x: 0.0,
+                                         y: 0.0,
+                                         width: 0.0,
+                                         height: 0.0 },
+                active: false.to_glib ()
+            }
         }
     }
-
-    pub fn new_inactive () -> RsvgViewBox {
-        RsvgViewBox::new (cairo::Rectangle { x: 0.0,
-                                             y: 0.0,
-                                             width: 0.0,
-                                             height: 0.0 },
-                          false)
-    }
-
-    pub fn is_active (&self) -> bool {
-        from_glib (self.active)
-    }
-}
-
-impl Default for RsvgViewBox {
-    fn default () -> RsvgViewBox {
-        RsvgViewBox::new_inactive ()
-    }
 }
 
-impl FromStr for RsvgViewBox {
+impl FromStr for ViewBox {
     type Err = AttributeError;
 
     // Parse a viewBox attribute
@@ -57,18 +51,17 @@ impl FromStr for RsvgViewBox {
     // x, y, w, h
     //
     // Where w and h must be nonnegative.
-    fn from_str (s: &str) -> Result<RsvgViewBox, AttributeError> {
+    fn from_str (s: &str) -> Result<ViewBox, AttributeError> {
         let v = parsers::number_list (s, ListLength::Exact (4))
             .map_err (|_| ParseError::new ("string does not match 'x [,] y [,] w [,] h'"))?;
 
         let (x, y, w, h) = (v[0], v[1], v[2], v[3]);
 
         if w >= 0.0 && h >= 0.0 {
-            Ok (RsvgViewBox::new (cairo::Rectangle { x: x,
-                                                     y: y,
-                                                     width: w,
-                                                     height: h },
-                                  true))
+            Ok (ViewBox(cairo::Rectangle { x: x,
+                                           y: y,
+                                           width: w,
+                                           height: h }))
         } else {
             Err (AttributeError::Value ("width and height must not be negative".to_string ()))
         }
@@ -82,31 +75,29 @@ mod tests {
 
     #[test]
     fn parses_valid_viewboxes () {
-        assert_eq! (RsvgViewBox::from_str ("  1 2 3 4"),
-                    Ok (RsvgViewBox::new (cairo::Rectangle { x: 1.0,
-                                                             y: 2.0,
-                                                             width: 3.0,
-                                                             height: 4.0 },
-                                          true)));
-
-        assert_eq! (RsvgViewBox::from_str (" -1.5 -2.5e1,34,56e2  "),
-                    Ok (RsvgViewBox::new (cairo::Rectangle { x: -1.5,
-                                                             y: -25.0,
-                                                             width: 34.0,
-                                                             height: 5600.0 },
-                                          true)));
+        assert_eq! (ViewBox::from_str ("  1 2 3 4"),
+                    Ok (ViewBox (cairo::Rectangle { x: 1.0,
+                                                    y: 2.0,
+                                                    width: 3.0,
+                                                    height: 4.0 })));
+
+        assert_eq! (ViewBox::from_str (" -1.5 -2.5e1,34,56e2  "),
+                    Ok (ViewBox (cairo::Rectangle { x: -1.5,
+                                                    y: -25.0,
+                                                    width: 34.0,
+                                                    height: 5600.0 })));
     }
 
     #[test]
     fn parsing_invalid_viewboxes_yields_error () {
-        assert! (is_parse_error (&RsvgViewBox::from_str ("")));
+        assert! (is_parse_error (&ViewBox::from_str ("")));
 
-        assert! (is_value_error (&RsvgViewBox::from_str (" 1,2,-3,-4 ")));
+        assert! (is_value_error (&ViewBox::from_str (" 1,2,-3,-4 ")));
 
-        assert! (is_parse_error (&RsvgViewBox::from_str ("qwerasdfzxcv")));
+        assert! (is_parse_error (&ViewBox::from_str ("qwerasdfzxcv")));
 
-        assert! (is_parse_error (&RsvgViewBox::from_str (" 1 2 3 4   5")));
+        assert! (is_parse_error (&ViewBox::from_str (" 1 2 3 4   5")));
 
-        assert! (is_parse_error (&RsvgViewBox::from_str (" 1 2 foo 3 4")));
+        assert! (is_parse_error (&ViewBox::from_str (" 1 2 foo 3 4")));
     }
 }


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