[librsvg] ViewBox: Represent unspecified view boxes as Option<ViewBox>
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] ViewBox: Represent unspecified view boxes as Option<ViewBox>
- Date: Fri, 1 Sep 2017 14:46:38 +0000 (UTC)
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]