diff options
Diffstat (limited to 'rsvg/src/viewbox.rs')
-rw-r--r-- | rsvg/src/viewbox.rs | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/rsvg/src/viewbox.rs b/rsvg/src/viewbox.rs new file mode 100644 index 00000000..e6ad39a9 --- /dev/null +++ b/rsvg/src/viewbox.rs @@ -0,0 +1,87 @@ +//! Parser for the `viewBox` attribute. + +use cssparser::Parser; +use std::ops::Deref; + +use crate::error::*; +use crate::parsers::{NumberList, Parse}; +use crate::rect::Rect; + +/// Newtype around a [`Rect`], used to represent the `viewBox` attribute. +/// +/// A `ViewBox` is a new user-space coordinate system mapped onto the rectangle defined by +/// the current viewport. See <https://www.w3.org/TR/SVG2/coords.html#ViewBoxAttribute> +/// +/// `ViewBox` derefs to [`Rect`], so you can use [`Rect`]'s methods and fields directly like +/// `vbox.x0` or `vbox.width()`. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct ViewBox(Rect); + +impl Deref for ViewBox { + type Target = Rect; + + fn deref(&self) -> &Rect { + &self.0 + } +} + +impl From<Rect> for ViewBox { + fn from(r: Rect) -> ViewBox { + ViewBox(r) + } +} + +impl Parse for ViewBox { + // Parse a viewBox attribute + // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute + // + // viewBox: double [,] double [,] double [,] double [,] + // + // x, y, w, h + // + // Where w and h must be nonnegative. + fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<ViewBox, ParseError<'i>> { + let loc = parser.current_source_location(); + + let NumberList::<4, 4>(v) = NumberList::parse(parser)?; + let (x, y, width, height) = (v[0], v[1], v[2], v[3]); + + if width >= 0.0 && height >= 0.0 { + Ok(ViewBox(Rect::new(x, y, x + width, y + height))) + } else { + Err(loc.new_custom_error(ValueErrorKind::value_error( + "width and height must not be negative", + ))) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_valid_viewboxes() { + assert_eq!( + ViewBox::parse_str(" 1 2 3 4").unwrap(), + ViewBox(Rect::new(1.0, 2.0, 4.0, 6.0)) + ); + + assert_eq!( + ViewBox::parse_str(" -1.5 -2.5e1,34,56e2 ").unwrap(), + ViewBox(Rect::new(-1.5, -25.0, 32.5, 5575.0)) + ); + } + + #[test] + fn parsing_invalid_viewboxes_yields_error() { + assert!(ViewBox::parse_str("").is_err()); + assert!(ViewBox::parse_str(" 1,2,-3,-4 ").is_err()); + assert!(ViewBox::parse_str("qwerasdfzxcv").is_err()); + assert!(ViewBox::parse_str(" 1 2 3 4 5").is_err()); + assert!(ViewBox::parse_str(" 1 2 foo 3 4").is_err()); + + // https://gitlab.gnome.org/GNOME/librsvg/issues/344 + assert!(ViewBox::parse_str("0 0 9E80.7").is_err()); + } +} |