summaryrefslogtreecommitdiffstats
path: root/servo/components/style/values/specified/svg_path.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--servo/components/style/values/specified/svg_path.rs562
1 files changed, 173 insertions, 389 deletions
diff --git a/servo/components/style/values/specified/svg_path.rs b/servo/components/style/values/specified/svg_path.rs
index 1eb9866dd1..56342b48bb 100644
--- a/servo/components/style/values/specified/svg_path.rs
+++ b/servo/components/style/values/specified/svg_path.rs
@@ -5,10 +5,13 @@
//! Specified types for SVG Path.
use crate::parser::{Parse, ParserContext};
-use crate::values::animated::{lists, Animate, Procedure, ToAnimatedZero};
+use crate::values::animated::{lists, Animate, Procedure};
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
+use crate::values::generics::basic_shape::GenericShapeCommand;
+use crate::values::generics::basic_shape::{ArcSize, ArcSweep, ByTo, CoordinatePair};
use crate::values::CSSFloat;
use cssparser::Parser;
+use num_traits::FromPrimitive;
use std::fmt::{self, Write};
use std::iter::{Cloned, Peekable};
use std::slice;
@@ -70,6 +73,7 @@ impl SVGPathData {
#[cfg(feature = "gecko")]
pub fn decode_from_f32_array(path: &[f32]) -> Result<Self, ()> {
use crate::gecko_bindings::structs::dom::SVGPathSeg_Binding::*;
+ use crate::values::generics::basic_shape::GenericShapeCommand::*;
let mut result: Vec<PathCommand> = Vec::new();
let mut i: usize = 0;
@@ -80,85 +84,84 @@ impl SVGPathData {
let seg_type = path[i].to_bits() as u16;
i = i + 1;
match seg_type {
- PATHSEG_CLOSEPATH => result.push(PathCommand::ClosePath),
+ PATHSEG_CLOSEPATH => result.push(Close),
PATHSEG_MOVETO_ABS | PATHSEG_MOVETO_REL => {
debug_assert!(i + 1 < path.len());
- result.push(PathCommand::MoveTo {
+ result.push(Move {
point: CoordPair::new(path[i], path[i + 1]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_MOVETO_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_MOVETO_ABS),
});
i = i + 2;
},
PATHSEG_LINETO_ABS | PATHSEG_LINETO_REL => {
debug_assert!(i + 1 < path.len());
- result.push(PathCommand::LineTo {
+ result.push(Line {
point: CoordPair::new(path[i], path[i + 1]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_LINETO_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_LINETO_ABS),
});
i = i + 2;
},
PATHSEG_CURVETO_CUBIC_ABS | PATHSEG_CURVETO_CUBIC_REL => {
debug_assert!(i + 5 < path.len());
- result.push(PathCommand::CurveTo {
+ result.push(CubicCurve {
control1: CoordPair::new(path[i], path[i + 1]),
control2: CoordPair::new(path[i + 2], path[i + 3]),
point: CoordPair::new(path[i + 4], path[i + 5]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_CUBIC_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_CUBIC_ABS),
});
i = i + 6;
},
PATHSEG_CURVETO_QUADRATIC_ABS | PATHSEG_CURVETO_QUADRATIC_REL => {
debug_assert!(i + 3 < path.len());
- result.push(PathCommand::QuadBezierCurveTo {
+ result.push(QuadCurve {
control1: CoordPair::new(path[i], path[i + 1]),
point: CoordPair::new(path[i + 2], path[i + 3]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_QUADRATIC_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_QUADRATIC_ABS),
});
i = i + 4;
},
PATHSEG_ARC_ABS | PATHSEG_ARC_REL => {
debug_assert!(i + 6 < path.len());
- result.push(PathCommand::EllipticalArc {
- rx: path[i],
- ry: path[i + 1],
- angle: path[i + 2],
- large_arc_flag: ArcFlag(path[i + 3] != 0.0f32),
- sweep_flag: ArcFlag(path[i + 4] != 0.0f32),
+ result.push(Arc {
+ radii: CoordPair::new(path[i], path[i + 1]),
+ rotate: path[i + 2],
+ arc_size: ArcSize::from_u8((path[i + 3] != 0.0f32) as u8).unwrap(),
+ arc_sweep: ArcSweep::from_u8((path[i + 4] != 0.0f32) as u8).unwrap(),
point: CoordPair::new(path[i + 5], path[i + 6]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_ARC_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_ARC_ABS),
});
i = i + 7;
},
PATHSEG_LINETO_HORIZONTAL_ABS | PATHSEG_LINETO_HORIZONTAL_REL => {
debug_assert!(i < path.len());
- result.push(PathCommand::HorizontalLineTo {
+ result.push(HLine {
x: path[i],
- absolute: IsAbsolute::new(seg_type == PATHSEG_LINETO_HORIZONTAL_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_LINETO_HORIZONTAL_ABS),
});
i = i + 1;
},
PATHSEG_LINETO_VERTICAL_ABS | PATHSEG_LINETO_VERTICAL_REL => {
debug_assert!(i < path.len());
- result.push(PathCommand::VerticalLineTo {
+ result.push(VLine {
y: path[i],
- absolute: IsAbsolute::new(seg_type == PATHSEG_LINETO_VERTICAL_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_LINETO_VERTICAL_ABS),
});
i = i + 1;
},
PATHSEG_CURVETO_CUBIC_SMOOTH_ABS | PATHSEG_CURVETO_CUBIC_SMOOTH_REL => {
debug_assert!(i + 3 < path.len());
- result.push(PathCommand::SmoothCurveTo {
+ result.push(SmoothCubic {
control2: CoordPair::new(path[i], path[i + 1]),
point: CoordPair::new(path[i + 2], path[i + 3]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS),
});
i = i + 4;
},
PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS | PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL => {
debug_assert!(i + 1 < path.len());
- result.push(PathCommand::SmoothQuadBezierCurveTo {
+ result.push(SmoothQuad {
point: CoordPair::new(path[i], path[i + 1]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS),
});
i = i + 2;
},
@@ -215,7 +218,7 @@ impl ToCss for SVGPathData {
{
let mut writer = SequenceWriter::new(dest, " ");
for command in self.commands() {
- writer.item(command)?;
+ writer.write_item(|inner| command.to_css_for_svg(inner))?;
}
}
dest.write_char('"')
@@ -268,79 +271,7 @@ impl ComputeSquaredDistance for SVGPathData {
/// points of the Bézier curve in the spec.
///
/// https://www.w3.org/TR/SVG11/paths.html#PathData
-#[derive(
- Animate,
- Clone,
- ComputeSquaredDistance,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToAnimatedZero,
- ToComputedValue,
- ToResolvedValue,
- ToShmem,
-)]
-#[allow(missing_docs)]
-#[repr(C, u8)]
-pub enum PathCommand {
- /// The unknown type.
- /// https://www.w3.org/TR/SVG/paths.html#__svg__SVGPathSeg__PATHSEG_UNKNOWN
- Unknown,
- /// The "moveto" command.
- MoveTo {
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The "lineto" command.
- LineTo {
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The horizontal "lineto" command.
- HorizontalLineTo { x: CSSFloat, absolute: IsAbsolute },
- /// The vertical "lineto" command.
- VerticalLineTo { y: CSSFloat, absolute: IsAbsolute },
- /// The cubic Bézier curve command.
- CurveTo {
- control1: CoordPair,
- control2: CoordPair,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The smooth curve command.
- SmoothCurveTo {
- control2: CoordPair,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The quadratic Bézier curve command.
- QuadBezierCurveTo {
- control1: CoordPair,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The smooth quadratic Bézier curve command.
- SmoothQuadBezierCurveTo {
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The elliptical arc curve command.
- EllipticalArc {
- rx: CSSFloat,
- ry: CSSFloat,
- angle: CSSFloat,
- large_arc_flag: ArcFlag,
- sweep_flag: ArcFlag,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The "closepath" command.
- ClosePath,
-}
+pub type PathCommand = GenericShapeCommand<CSSFloat, CSSFloat>;
/// For internal SVGPath normalization.
#[allow(missing_docs)]
@@ -355,177 +286,157 @@ impl PathCommand {
///
/// See discussion: https://github.com/w3c/svgwg/issues/321
fn normalize(&self, state: &mut PathTraversalState) -> Self {
- use self::PathCommand::*;
+ use crate::values::generics::basic_shape::GenericShapeCommand::*;
match *self {
- Unknown => Unknown,
- ClosePath => {
+ Close => {
state.pos = state.subpath_start;
- ClosePath
+ Close
},
- MoveTo {
- mut point,
- absolute,
- } => {
- if !absolute.is_yes() {
+ Move { by_to, mut point } => {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
state.subpath_start = point;
- MoveTo {
+ Move {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
}
},
- LineTo {
- mut point,
- absolute,
- } => {
- if !absolute.is_yes() {
+ Line { by_to, mut point } => {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
- LineTo {
+ Line {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
}
},
- HorizontalLineTo { mut x, absolute } => {
- if !absolute.is_yes() {
+ HLine { by_to, mut x } => {
+ if !by_to.is_abs() {
x += state.pos.x;
}
state.pos.x = x;
- HorizontalLineTo {
- x,
- absolute: IsAbsolute::Yes,
- }
+ HLine { by_to: ByTo::To, x }
},
- VerticalLineTo { mut y, absolute } => {
- if !absolute.is_yes() {
+ VLine { by_to, mut y } => {
+ if !by_to.is_abs() {
y += state.pos.y;
}
state.pos.y = y;
- VerticalLineTo {
- y,
- absolute: IsAbsolute::Yes,
- }
+ VLine { by_to: ByTo::To, y }
},
- CurveTo {
+ CubicCurve {
+ by_to,
+ mut point,
mut control1,
mut control2,
- mut point,
- absolute,
} => {
- if !absolute.is_yes() {
+ if !by_to.is_abs() {
+ point += state.pos;
control1 += state.pos;
control2 += state.pos;
- point += state.pos;
}
state.pos = point;
- CurveTo {
+ CubicCurve {
+ by_to: ByTo::To,
+ point,
control1,
control2,
- point,
- absolute: IsAbsolute::Yes,
}
},
- SmoothCurveTo {
- mut control2,
+ QuadCurve {
+ by_to,
mut point,
- absolute,
+ mut control1,
} => {
- if !absolute.is_yes() {
- control2 += state.pos;
+ if !by_to.is_abs() {
point += state.pos;
+ control1 += state.pos;
}
state.pos = point;
- SmoothCurveTo {
- control2,
+ QuadCurve {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
+ control1,
}
},
- QuadBezierCurveTo {
- mut control1,
+ SmoothCubic {
+ by_to,
mut point,
- absolute,
+ mut control2,
} => {
- if !absolute.is_yes() {
- control1 += state.pos;
+ if !by_to.is_abs() {
point += state.pos;
+ control2 += state.pos;
}
state.pos = point;
- QuadBezierCurveTo {
- control1,
+ SmoothCubic {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
+ control2,
}
},
- SmoothQuadBezierCurveTo {
- mut point,
- absolute,
- } => {
- if !absolute.is_yes() {
+ SmoothQuad { by_to, mut point } => {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
- SmoothQuadBezierCurveTo {
+ SmoothQuad {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
}
},
- EllipticalArc {
- rx,
- ry,
- angle,
- large_arc_flag,
- sweep_flag,
+ Arc {
+ by_to,
mut point,
- absolute,
+ radii,
+ arc_sweep,
+ arc_size,
+ rotate,
} => {
- if !absolute.is_yes() {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
- EllipticalArc {
- rx,
- ry,
- angle,
- large_arc_flag,
- sweep_flag,
+ Arc {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
+ radii,
+ arc_sweep,
+ arc_size,
+ rotate,
}
},
}
}
-}
-impl ToCss for PathCommand {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ /// The serialization of the svg path.
+ fn to_css_for_svg<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
- use self::PathCommand::*;
+ use crate::values::generics::basic_shape::GenericShapeCommand::*;
match *self {
- Unknown => dest.write_char('X'),
- ClosePath => dest.write_char('Z'),
- MoveTo { point, absolute } => {
- dest.write_char(if absolute.is_yes() { 'M' } else { 'm' })?;
+ Close => dest.write_char('Z'),
+ Move { by_to, point } => {
+ dest.write_char(if by_to.is_abs() { 'M' } else { 'm' })?;
dest.write_char(' ')?;
point.to_css(dest)
},
- LineTo { point, absolute } => {
- dest.write_char(if absolute.is_yes() { 'L' } else { 'l' })?;
+ Line { by_to, point } => {
+ dest.write_char(if by_to.is_abs() { 'L' } else { 'l' })?;
dest.write_char(' ')?;
point.to_css(dest)
},
- CurveTo {
+ CubicCurve {
+ by_to,
+ point,
control1,
control2,
- point,
- absolute,
} => {
- dest.write_char(if absolute.is_yes() { 'C' } else { 'c' })?;
+ dest.write_char(if by_to.is_abs() { 'C' } else { 'c' })?;
dest.write_char(' ')?;
control1.to_css(dest)?;
dest.write_char(' ')?;
@@ -533,63 +444,60 @@ impl ToCss for PathCommand {
dest.write_char(' ')?;
point.to_css(dest)
},
- QuadBezierCurveTo {
- control1,
+ QuadCurve {
+ by_to,
point,
- absolute,
+ control1,
} => {
- dest.write_char(if absolute.is_yes() { 'Q' } else { 'q' })?;
+ dest.write_char(if by_to.is_abs() { 'Q' } else { 'q' })?;
dest.write_char(' ')?;
control1.to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
- EllipticalArc {
- rx,
- ry,
- angle,
- large_arc_flag,
- sweep_flag,
+ Arc {
+ by_to,
point,
- absolute,
+ radii,
+ arc_sweep,
+ arc_size,
+ rotate,
} => {
- dest.write_char(if absolute.is_yes() { 'A' } else { 'a' })?;
- dest.write_char(' ')?;
- rx.to_css(dest)?;
+ dest.write_char(if by_to.is_abs() { 'A' } else { 'a' })?;
dest.write_char(' ')?;
- ry.to_css(dest)?;
+ radii.to_css(dest)?;
dest.write_char(' ')?;
- angle.to_css(dest)?;
+ rotate.to_css(dest)?;
dest.write_char(' ')?;
- large_arc_flag.to_css(dest)?;
+ (arc_size as i32).to_css(dest)?;
dest.write_char(' ')?;
- sweep_flag.to_css(dest)?;
+ (arc_sweep as i32).to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
- HorizontalLineTo { x, absolute } => {
- dest.write_char(if absolute.is_yes() { 'H' } else { 'h' })?;
+ HLine { by_to, x } => {
+ dest.write_char(if by_to.is_abs() { 'H' } else { 'h' })?;
dest.write_char(' ')?;
x.to_css(dest)
},
- VerticalLineTo { y, absolute } => {
- dest.write_char(if absolute.is_yes() { 'V' } else { 'v' })?;
+ VLine { by_to, y } => {
+ dest.write_char(if by_to.is_abs() { 'V' } else { 'v' })?;
dest.write_char(' ')?;
y.to_css(dest)
},
- SmoothCurveTo {
- control2,
+ SmoothCubic {
+ by_to,
point,
- absolute,
+ control2,
} => {
- dest.write_char(if absolute.is_yes() { 'S' } else { 's' })?;
+ dest.write_char(if by_to.is_abs() { 'S' } else { 's' })?;
dest.write_char(' ')?;
control2.to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
- SmoothQuadBezierCurveTo { point, absolute } => {
- dest.write_char(if absolute.is_yes() { 'T' } else { 't' })?;
+ SmoothQuad { by_to, point } => {
+ dest.write_char(if by_to.is_abs() { 'T' } else { 't' })?;
dest.write_char(' ')?;
point.to_css(dest)
},
@@ -597,135 +505,8 @@ impl ToCss for PathCommand {
}
}
-/// The path command absolute type.
-#[allow(missing_docs)]
-#[derive(
- Animate,
- Clone,
- ComputeSquaredDistance,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToAnimatedZero,
- ToComputedValue,
- ToResolvedValue,
- ToShmem,
-)]
-#[repr(u8)]
-pub enum IsAbsolute {
- Yes,
- No,
-}
-
-impl IsAbsolute {
- /// Return true if this is IsAbsolute::Yes.
- #[inline]
- pub fn is_yes(&self) -> bool {
- *self == IsAbsolute::Yes
- }
-
- /// Return Yes if value is true. Otherwise, return No.
- #[inline]
- fn new(value: bool) -> Self {
- if value {
- IsAbsolute::Yes
- } else {
- IsAbsolute::No
- }
- }
-}
-
/// The path coord type.
-#[allow(missing_docs)]
-#[derive(
- AddAssign,
- Animate,
- Clone,
- ComputeSquaredDistance,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToAnimatedZero,
- ToComputedValue,
- ToCss,
- ToResolvedValue,
- ToShmem,
-)]
-#[repr(C)]
-pub struct CoordPair {
- x: CSSFloat,
- y: CSSFloat,
-}
-
-impl CoordPair {
- /// Create a CoordPair.
- #[inline]
- pub fn new(x: CSSFloat, y: CSSFloat) -> Self {
- CoordPair { x, y }
- }
-}
-
-/// The EllipticalArc flag type.
-#[derive(
- Clone,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToComputedValue,
- ToResolvedValue,
- ToShmem,
-)]
-#[repr(C)]
-pub struct ArcFlag(bool);
-
-impl ToCss for ArcFlag {
- #[inline]
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: fmt::Write,
- {
- (self.0 as i32).to_css(dest)
- }
-}
-
-impl Animate for ArcFlag {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- (self.0 as i32)
- .animate(&(other.0 as i32), procedure)
- .map(|v| ArcFlag(v > 0))
- }
-}
-
-impl ComputeSquaredDistance for ArcFlag {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- (self.0 as i32).compute_squared_distance(&(other.0 as i32))
- }
-}
-
-impl ToAnimatedZero for ArcFlag {
- #[inline]
- fn to_animated_zero(&self) -> Result<Self, ()> {
- // The 2 ArcFlags in EllipticalArc determine which one of the 4 different arcs will be
- // used. (i.e. From 4 combinations). In other words, if we change the flag, we get a
- // different arc. Therefore, we return *self.
- // https://svgwg.org/svg2-draft/paths.html#PathDataEllipticalArcCommands
- Ok(*self)
- }
-}
+pub type CoordPair = CoordinatePair<CSSFloat>;
/// SVG Path parser.
struct PathParser<'a> {
@@ -736,7 +517,7 @@ struct PathParser<'a> {
macro_rules! parse_arguments {
(
$parser:ident,
- $abs:ident,
+ $by_to:ident,
$enum:ident,
[ $para:ident => $func:ident $(, $other_para:ident => $other_func:ident)* ]
) => {
@@ -747,7 +528,9 @@ macro_rules! parse_arguments {
skip_comma_wsp(&mut $parser.chars);
let $other_para = $other_func(&mut $parser.chars)?;
)*
- $parser.path.push(PathCommand::$enum { $para $(, $other_para)*, $abs });
+ $parser.path.push(
+ PathCommand::$enum { $by_to, $para $(, $other_para)* }
+ );
// End of string or the next character is a possible new command.
if !skip_wsp(&mut $parser.chars) ||
@@ -785,23 +568,23 @@ impl<'a> PathParser<'a> {
}
let command = self.chars.next().unwrap();
- let abs = if command.is_ascii_uppercase() {
- IsAbsolute::Yes
+ let by_to = if command.is_ascii_uppercase() {
+ ByTo::To
} else {
- IsAbsolute::No
+ ByTo::By
};
skip_wsp(&mut self.chars);
match command {
b'Z' | b'z' => self.parse_closepath(),
- b'L' | b'l' => self.parse_lineto(abs),
- b'H' | b'h' => self.parse_h_lineto(abs),
- b'V' | b'v' => self.parse_v_lineto(abs),
- b'C' | b'c' => self.parse_curveto(abs),
- b'S' | b's' => self.parse_smooth_curveto(abs),
- b'Q' | b'q' => self.parse_quadratic_bezier_curveto(abs),
- b'T' | b't' => self.parse_smooth_quadratic_bezier_curveto(abs),
- b'A' | b'a' => self.parse_elliptical_arc(abs),
+ b'L' | b'l' => self.parse_lineto(by_to),
+ b'H' | b'h' => self.parse_h_lineto(by_to),
+ b'V' | b'v' => self.parse_v_lineto(by_to),
+ b'C' | b'c' => self.parse_curveto(by_to),
+ b'S' | b's' => self.parse_smooth_curveto(by_to),
+ b'Q' | b'q' => self.parse_quadratic_bezier_curveto(by_to),
+ b'T' | b't' => self.parse_smooth_quadratic_bezier_curveto(by_to),
+ b'A' | b'a' => self.parse_elliptical_arc(by_to),
_ => return Err(()),
}?;
}
@@ -817,12 +600,8 @@ impl<'a> PathParser<'a> {
skip_wsp(&mut self.chars);
let point = parse_coord(&mut self.chars)?;
- let absolute = if command == b'M' {
- IsAbsolute::Yes
- } else {
- IsAbsolute::No
- };
- self.path.push(PathCommand::MoveTo { point, absolute });
+ let by_to = if command == b'M' { ByTo::To } else { ByTo::By };
+ self.path.push(PathCommand::Move { by_to, point });
// End of string or the next character is a possible new command.
if !skip_wsp(&mut self.chars) || self.chars.peek().map_or(true, |c| c.is_ascii_alphabetic())
@@ -833,69 +612,74 @@ impl<'a> PathParser<'a> {
// If a moveto is followed by multiple pairs of coordinates, the subsequent
// pairs are treated as implicit lineto commands.
- self.parse_lineto(absolute)
+ self.parse_lineto(by_to)
}
/// Parse "closepath" command.
fn parse_closepath(&mut self) -> Result<(), ()> {
- self.path.push(PathCommand::ClosePath);
+ self.path.push(PathCommand::Close);
Ok(())
}
/// Parse "lineto" command.
- fn parse_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, LineTo, [ point => parse_coord ])
+ fn parse_lineto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, Line, [ point => parse_coord ])
}
/// Parse horizontal "lineto" command.
- fn parse_h_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, HorizontalLineTo, [ x => parse_number ])
+ fn parse_h_lineto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, HLine, [ x => parse_number ])
}
/// Parse vertical "lineto" command.
- fn parse_v_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, VerticalLineTo, [ y => parse_number ])
+ fn parse_v_lineto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, VLine, [ y => parse_number ])
}
/// Parse cubic Bézier curve command.
- fn parse_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, CurveTo, [
+ fn parse_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, CubicCurve, [
control1 => parse_coord, control2 => parse_coord, point => parse_coord
])
}
/// Parse smooth "curveto" command.
- fn parse_smooth_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, SmoothCurveTo, [
+ fn parse_smooth_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, SmoothCubic, [
control2 => parse_coord, point => parse_coord
])
}
/// Parse quadratic Bézier curve command.
- fn parse_quadratic_bezier_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, QuadBezierCurveTo, [
+ fn parse_quadratic_bezier_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, QuadCurve, [
control1 => parse_coord, point => parse_coord
])
}
/// Parse smooth quadratic Bézier curveto command.
- fn parse_smooth_quadratic_bezier_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, SmoothQuadBezierCurveTo, [ point => parse_coord ])
+ fn parse_smooth_quadratic_bezier_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, SmoothQuad, [ point => parse_coord ])
}
/// Parse elliptical arc curve command.
- fn parse_elliptical_arc(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
+ fn parse_elliptical_arc(&mut self, by_to: ByTo) -> Result<(), ()> {
// Parse a flag whose value is '0' or '1'; otherwise, return Err(()).
- let parse_flag = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| match iter.next() {
- Some(c) if c == b'0' || c == b'1' => Ok(ArcFlag(c == b'1')),
+ let parse_arc_size = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| match iter.next() {
+ Some(c) if c == b'1' => Ok(ArcSize::Large),
+ Some(c) if c == b'0' => Ok(ArcSize::Small),
+ _ => Err(()),
+ };
+ let parse_arc_sweep = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| match iter.next() {
+ Some(c) if c == b'1' => Ok(ArcSweep::Cw),
+ Some(c) if c == b'0' => Ok(ArcSweep::Ccw),
_ => Err(()),
};
- parse_arguments!(self, absolute, EllipticalArc, [
- rx => parse_number,
- ry => parse_number,
- angle => parse_number,
- large_arc_flag => parse_flag,
- sweep_flag => parse_flag,
+ parse_arguments!(self, by_to, Arc, [
+ radii => parse_coord,
+ rotate => parse_number,
+ arc_size => parse_arc_size,
+ arc_sweep => parse_arc_sweep,
point => parse_coord
])
}