Auto merge of #21653 - emilio:gecko-sync, r=emilio

style: sync changes from mozilla-central.

See each individual commit for details.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21653)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-09-09 10:22:38 -04:00 committed by GitHub
commit a39a57c076
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 255 additions and 43 deletions

View file

@ -379,7 +379,7 @@ ${helpers.predefined_type(
"OffsetPath", "OffsetPath",
"computed::OffsetPath::none()", "computed::OffsetPath::none()",
products="gecko", products="gecko",
animation_value_type="none", animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled", gecko_pref="layout.css.motion-path.enabled",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB", flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
spec="https://drafts.fxtf.org/motion-1/#offset-path-property", spec="https://drafts.fxtf.org/motion-1/#offset-path-property",

View file

@ -392,3 +392,14 @@ where
)) ))
} }
} }
impl<T> ToAnimatedZero for Box<[T]>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
let v = self.iter().map(|v| v.to_animated_zero()).collect::<Result<Vec<_>, _>>()?;
Ok(v.into_boxed_slice())
}
}

View file

@ -54,7 +54,6 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
Shape(BasicShape, Option<ReferenceBox>), Shape(BasicShape, Option<ReferenceBox>),
#[animation(error)] #[animation(error)]
Box(ReferenceBox), Box(ReferenceBox),
#[animation(error)]
#[css(function)] #[css(function)]
Path(Path), Path(Path),
#[animation(error)] #[animation(error)]
@ -152,10 +151,12 @@ pub enum FillRule {
/// ///
/// https://drafts.csswg.org/css-shapes-2/#funcdef-path /// https://drafts.csswg.org/css-shapes-2/#funcdef-path
#[css(comma)] #[css(comma)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] #[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct Path { pub struct Path {
/// The filling rule for the svg path. /// The filling rule for the svg path.
#[css(skip_if = "fill_is_default")] #[css(skip_if = "fill_is_default")]
#[animation(constant)]
pub fill: FillRule, pub fill: FillRule,
/// The svg path data. /// The svg path data.
pub path: SVGPathData, pub path: SVGPathData,
@ -177,6 +178,13 @@ where
{ {
this.compute_squared_distance(other) this.compute_squared_distance(other)
}, },
(
&ShapeSource::Path(ref this),
&ShapeSource::Path(ref other),
) if this.fill == other.fill =>
{
this.path.compute_squared_distance(&other.path)
}
_ => Err(()), _ => Err(()),
} }
} }

View file

@ -12,7 +12,8 @@ use values::specified::SVGPathData;
/// The offset-path value. /// The offset-path value.
/// ///
/// https://drafts.fxtf.org/motion-1/#offset-path-property /// https://drafts.fxtf.org/motion-1/#offset-path-property
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)]
pub enum OffsetPath { pub enum OffsetPath {
// We could merge SVGPathData into ShapeSource, so we could reuse them. However, // We could merge SVGPathData into ShapeSource, so we could reuse them. However,
// we don't want to support other value for offset-path, so use SVGPathData only for now. // we don't want to support other value for offset-path, so use SVGPathData only for now.
@ -20,6 +21,7 @@ pub enum OffsetPath {
#[css(function)] #[css(function)]
Path(SVGPathData), Path(SVGPathData),
/// None value. /// None value.
#[animation(error)]
None, None,
// Bug 1186329: Implement ray(), <basic-shape>, <geometry-box>, and <url>. // Bug 1186329: Implement ray(), <basic-shape>, <geometry-box>, and <url>.
} }

View file

@ -8,16 +8,20 @@ use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::iter::{Cloned, Peekable}; use std::iter::{Cloned, Peekable};
use std::ops::AddAssign;
use std::slice; use std::slice;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use style_traits::values::SequenceWriter; use style_traits::values::SequenceWriter;
use values::CSSFloat; use values::CSSFloat;
use values::animated::{Animate, Procedure};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// The SVG path data. /// The SVG path data.
/// ///
/// https://www.w3.org/TR/SVG11/paths.html#PathData /// https://www.w3.org/TR/SVG11/paths.html#PathData
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedZero,
ToComputedValue)]
pub struct SVGPathData(Box<[PathCommand]>); pub struct SVGPathData(Box<[PathCommand]>);
impl SVGPathData { impl SVGPathData {
@ -34,6 +38,17 @@ impl SVGPathData {
debug_assert!(!self.0.is_empty()); debug_assert!(!self.0.is_empty());
&self.0 &self.0
} }
/// Create a normalized copy of this path by converting each relative command to an absolute
/// command.
fn normalize(&self) -> Self {
let mut state = PathTraversalState {
subpath_start: CoordPair::new(0.0, 0.0),
pos: CoordPair::new(0.0, 0.0),
};
let result = self.0.iter().map(|seg| seg.normalize(&mut state)).collect::<Vec<_>>();
SVGPathData(result.into_boxed_slice())
}
} }
impl ToCss for SVGPathData { impl ToCss for SVGPathData {
@ -82,6 +97,33 @@ impl Parse for SVGPathData {
} }
} }
impl Animate for SVGPathData {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
if self.0.len() != other.0.len() {
return Err(());
}
let result = self.normalize().0
.iter()
.zip(other.normalize().0.iter())
.map(|(a, b)| a.animate(&b, procedure))
.collect::<Result<Vec<_>, _>>()?;
Ok(SVGPathData::new(result.into_boxed_slice()))
}
}
impl ComputeSquaredDistance for SVGPathData {
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
if self.0.len() != other.0.len() {
return Err(());
}
self.normalize().0
.iter()
.zip(other.normalize().0.iter())
.map(|(this, other)| this.compute_squared_distance(&other))
.sum()
}
}
/// The SVG path command. /// The SVG path command.
/// The fields of these commands are self-explanatory, so we skip the documents. /// The fields of these commands are self-explanatory, so we skip the documents.
@ -89,7 +131,8 @@ impl Parse for SVGPathData {
/// points of the Bézier curve in the spec. /// points of the Bézier curve in the spec.
/// ///
/// https://www.w3.org/TR/SVG11/paths.html#PathData /// https://www.w3.org/TR/SVG11/paths.html#PathData
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToAnimatedZero)]
#[allow(missing_docs)] #[allow(missing_docs)]
#[repr(C, u8)] #[repr(C, u8)]
pub enum PathCommand { pub enum PathCommand {
@ -97,35 +140,131 @@ pub enum PathCommand {
/// https://www.w3.org/TR/SVG/paths.html#__svg__SVGPathSeg__PATHSEG_UNKNOWN /// https://www.w3.org/TR/SVG/paths.html#__svg__SVGPathSeg__PATHSEG_UNKNOWN
Unknown, Unknown,
/// The "moveto" command. /// The "moveto" command.
MoveTo { point: CoordPair, absolute: bool }, MoveTo { point: CoordPair, absolute: IsAbsolute },
/// The "lineto" command. /// The "lineto" command.
LineTo { point: CoordPair, absolute: bool }, LineTo { point: CoordPair, absolute: IsAbsolute },
/// The horizontal "lineto" command. /// The horizontal "lineto" command.
HorizontalLineTo { x: CSSFloat, absolute: bool }, HorizontalLineTo { x: CSSFloat, absolute: IsAbsolute },
/// The vertical "lineto" command. /// The vertical "lineto" command.
VerticalLineTo { y: CSSFloat, absolute: bool }, VerticalLineTo { y: CSSFloat, absolute: IsAbsolute },
/// The cubic Bézier curve command. /// The cubic Bézier curve command.
CurveTo { control1: CoordPair, control2: CoordPair, point: CoordPair, absolute: bool }, CurveTo { control1: CoordPair, control2: CoordPair, point: CoordPair, absolute: IsAbsolute },
/// The smooth curve command. /// The smooth curve command.
SmoothCurveTo { control2: CoordPair, point: CoordPair, absolute: bool }, SmoothCurveTo { control2: CoordPair, point: CoordPair, absolute: IsAbsolute },
/// The quadratic Bézier curve command. /// The quadratic Bézier curve command.
QuadBezierCurveTo { control1: CoordPair, point: CoordPair, absolute: bool }, QuadBezierCurveTo { control1: CoordPair, point: CoordPair, absolute: IsAbsolute },
/// The smooth quadratic Bézier curve command. /// The smooth quadratic Bézier curve command.
SmoothQuadBezierCurveTo { point: CoordPair, absolute: bool }, SmoothQuadBezierCurveTo { point: CoordPair, absolute: IsAbsolute },
/// The elliptical arc curve command. /// The elliptical arc curve command.
EllipticalArc { EllipticalArc {
rx: CSSFloat, rx: CSSFloat,
ry: CSSFloat, ry: CSSFloat,
angle: CSSFloat, angle: CSSFloat,
large_arc_flag: bool, #[animation(constant)]
sweep_flag: bool, large_arc_flag: ArcFlag,
#[animation(constant)]
sweep_flag: ArcFlag,
point: CoordPair, point: CoordPair,
absolute: bool absolute: IsAbsolute
}, },
/// The "closepath" command. /// The "closepath" command.
ClosePath, ClosePath,
} }
/// For internal SVGPath normalization.
#[allow(missing_docs)]
struct PathTraversalState {
subpath_start: CoordPair,
pos: CoordPair,
}
impl PathCommand {
/// Create a normalized copy of this PathCommand. Absolute commands will be copied as-is while
/// for relative commands an equivalent absolute command will be returned.
///
/// See discussion: https://github.com/w3c/svgwg/issues/321
fn normalize(&self, state: &mut PathTraversalState) -> Self {
use self::PathCommand::*;
match *self {
Unknown => Unknown,
ClosePath => {
state.pos = state.subpath_start;
ClosePath
},
MoveTo { mut point, absolute } => {
if !absolute.is_yes() {
point += state.pos;
}
state.pos = point;
state.subpath_start = point;
MoveTo { point, absolute: IsAbsolute::Yes }
},
LineTo { mut point, absolute } => {
if !absolute.is_yes() {
point += state.pos;
}
state.pos = point;
LineTo { point, absolute: IsAbsolute::Yes }
},
HorizontalLineTo { mut x, absolute } => {
if !absolute.is_yes() {
x += state.pos.0;
}
state.pos.0 = x;
HorizontalLineTo { x, absolute: IsAbsolute::Yes }
},
VerticalLineTo { mut y, absolute } => {
if !absolute.is_yes() {
y += state.pos.1;
}
state.pos.1 = y;
VerticalLineTo { y, absolute: IsAbsolute::Yes }
},
CurveTo { mut control1, mut control2, mut point, absolute } => {
if !absolute.is_yes() {
control1 += state.pos;
control2 += state.pos;
point += state.pos;
}
state.pos = point;
CurveTo { control1, control2, point, absolute: IsAbsolute::Yes }
},
SmoothCurveTo { mut control2, mut point, absolute } => {
if !absolute.is_yes() {
control2 += state.pos;
point += state.pos;
}
state.pos = point;
SmoothCurveTo { control2, point, absolute: IsAbsolute::Yes }
},
QuadBezierCurveTo { mut control1, mut point, absolute } => {
if !absolute.is_yes() {
control1 += state.pos;
point += state.pos;
}
state.pos = point;
QuadBezierCurveTo { control1, point, absolute: IsAbsolute::Yes }
},
SmoothQuadBezierCurveTo { mut point, absolute } => {
if !absolute.is_yes() {
point += state.pos;
}
state.pos = point;
SmoothQuadBezierCurveTo { point, absolute: IsAbsolute::Yes }
},
EllipticalArc { rx, ry, angle, large_arc_flag, sweep_flag, mut point, absolute } => {
if !absolute.is_yes() {
point += state.pos;
}
state.pos = point;
EllipticalArc {
rx, ry, angle, large_arc_flag, sweep_flag, point, absolute: IsAbsolute::Yes
}
},
}
}
}
impl ToCss for PathCommand { impl ToCss for PathCommand {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where where
@ -136,17 +275,17 @@ impl ToCss for PathCommand {
Unknown => dest.write_char('X'), Unknown => dest.write_char('X'),
ClosePath => dest.write_char('Z'), ClosePath => dest.write_char('Z'),
MoveTo { point, absolute } => { MoveTo { point, absolute } => {
dest.write_char(if absolute { 'M' } else { 'm' })?; dest.write_char(if absolute.is_yes() { 'M' } else { 'm' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
point.to_css(dest) point.to_css(dest)
} }
LineTo { point, absolute } => { LineTo { point, absolute } => {
dest.write_char(if absolute { 'L' } else { 'l' })?; dest.write_char(if absolute.is_yes() { 'L' } else { 'l' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
point.to_css(dest) point.to_css(dest)
} }
CurveTo { control1, control2, point, absolute } => { CurveTo { control1, control2, point, absolute } => {
dest.write_char(if absolute { 'C' } else { 'c' })?; dest.write_char(if absolute.is_yes() { 'C' } else { 'c' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
control1.to_css(dest)?; control1.to_css(dest)?;
dest.write_char(' ')?; dest.write_char(' ')?;
@ -155,14 +294,14 @@ impl ToCss for PathCommand {
point.to_css(dest) point.to_css(dest)
}, },
QuadBezierCurveTo { control1, point, absolute } => { QuadBezierCurveTo { control1, point, absolute } => {
dest.write_char(if absolute { 'Q' } else { 'q' })?; dest.write_char(if absolute.is_yes() { 'Q' } else { 'q' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
control1.to_css(dest)?; control1.to_css(dest)?;
dest.write_char(' ')?; dest.write_char(' ')?;
point.to_css(dest) point.to_css(dest)
}, },
EllipticalArc { rx, ry, angle, large_arc_flag, sweep_flag, point, absolute } => { EllipticalArc { rx, ry, angle, large_arc_flag, sweep_flag, point, absolute } => {
dest.write_char(if absolute { 'A' } else { 'a' })?; dest.write_char(if absolute.is_yes() { 'A' } else { 'a' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
rx.to_css(dest)?; rx.to_css(dest)?;
dest.write_char(' ')?; dest.write_char(' ')?;
@ -170,31 +309,31 @@ impl ToCss for PathCommand {
dest.write_char(' ')?; dest.write_char(' ')?;
angle.to_css(dest)?; angle.to_css(dest)?;
dest.write_char(' ')?; dest.write_char(' ')?;
(large_arc_flag as i32).to_css(dest)?; large_arc_flag.to_css(dest)?;
dest.write_char(' ')?; dest.write_char(' ')?;
(sweep_flag as i32).to_css(dest)?; sweep_flag.to_css(dest)?;
dest.write_char(' ')?; dest.write_char(' ')?;
point.to_css(dest) point.to_css(dest)
}, },
HorizontalLineTo { x, absolute } => { HorizontalLineTo { x, absolute } => {
dest.write_char(if absolute { 'H' } else { 'h' })?; dest.write_char(if absolute.is_yes() { 'H' } else { 'h' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
x.to_css(dest) x.to_css(dest)
}, },
VerticalLineTo { y, absolute } => { VerticalLineTo { y, absolute } => {
dest.write_char(if absolute { 'V' } else { 'v' })?; dest.write_char(if absolute.is_yes() { 'V' } else { 'v' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
y.to_css(dest) y.to_css(dest)
}, },
SmoothCurveTo { control2, point, absolute } => { SmoothCurveTo { control2, point, absolute } => {
dest.write_char(if absolute { 'S' } else { 's' })?; dest.write_char(if absolute.is_yes() { 'S' } else { 's' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
control2.to_css(dest)?; control2.to_css(dest)?;
dest.write_char(' ')?; dest.write_char(' ')?;
point.to_css(dest) point.to_css(dest)
}, },
SmoothQuadBezierCurveTo { point, absolute } => { SmoothQuadBezierCurveTo { point, absolute } => {
dest.write_char(if absolute { 'T' } else { 't' })?; dest.write_char(if absolute.is_yes() { 'T' } else { 't' })?;
dest.write_char(' ')?; dest.write_char(' ')?;
point.to_css(dest) point.to_css(dest)
}, },
@ -202,9 +341,27 @@ impl ToCss for PathCommand {
} }
} }
/// The path command absolute type.
#[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToAnimatedZero)]
#[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
}
}
/// The path coord type. /// The path coord type.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToAnimatedZero, ToCss)]
#[repr(C)] #[repr(C)]
pub struct CoordPair(CSSFloat, CSSFloat); pub struct CoordPair(CSSFloat, CSSFloat);
@ -216,6 +373,36 @@ impl CoordPair {
} }
} }
impl AddAssign for CoordPair {
#[inline]
fn add_assign(&mut self, other: Self) {
self.0 += other.0;
self.1 += other.1;
}
}
/// The EllipticalArc flag type.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
#[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 ComputeSquaredDistance for ArcFlag {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
(self.0 as i32).compute_squared_distance(&(other.0 as i32))
}
}
/// SVG Path parser. /// SVG Path parser.
struct PathParser<'a> { struct PathParser<'a> {
@ -276,7 +463,11 @@ impl<'a> PathParser<'a> {
match self.chars.next() { match self.chars.next() {
Some(command) => { Some(command) => {
let abs = command.is_ascii_uppercase(); let abs = if command.is_ascii_uppercase() {
IsAbsolute::Yes
} else {
IsAbsolute::No
};
macro_rules! parse_command { macro_rules! parse_command {
( $($($p:pat)|+ => $parse_func:ident,)* ) => { ( $($($p:pat)|+ => $parse_func:ident,)* ) => {
match command { match command {
@ -299,7 +490,7 @@ impl<'a> PathParser<'a> {
b'S' | b's' => parse_smooth_curveto, b'S' | b's' => parse_smooth_curveto,
b'Q' | b'q' => parse_quadratic_bezier_curveto, b'Q' | b'q' => parse_quadratic_bezier_curveto,
b'T' | b't' => parse_smooth_quadratic_bezier_curveto, b'T' | b't' => parse_smooth_quadratic_bezier_curveto,
b'A' | b'a' => parse_elliprical_arc, b'A' | b'a' => parse_elliptical_arc,
); );
}, },
_ => break, // no more commands. _ => break, // no more commands.
@ -317,7 +508,7 @@ impl<'a> PathParser<'a> {
skip_wsp(&mut self.chars); skip_wsp(&mut self.chars);
let point = parse_coord(&mut self.chars)?; let point = parse_coord(&mut self.chars)?;
let absolute = command == b'M'; let absolute = if command == b'M' { IsAbsolute::Yes } else { IsAbsolute::No };
self.path.push(PathCommand::MoveTo { point, absolute } ); self.path.push(PathCommand::MoveTo { point, absolute } );
// End of string or the next character is a possible new command. // End of string or the next character is a possible new command.
@ -333,58 +524,58 @@ impl<'a> PathParser<'a> {
} }
/// Parse "closepath" command. /// Parse "closepath" command.
fn parse_closepath(&mut self, _absolute: bool) -> Result<(), ()> { fn parse_closepath(&mut self, _absolute: IsAbsolute) -> Result<(), ()> {
self.path.push(PathCommand::ClosePath); self.path.push(PathCommand::ClosePath);
Ok(()) Ok(())
} }
/// Parse "lineto" command. /// Parse "lineto" command.
fn parse_lineto(&mut self, absolute: bool) -> Result<(), ()> { fn parse_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
parse_arguments!(self, absolute, LineTo, [ point => parse_coord ]) parse_arguments!(self, absolute, LineTo, [ point => parse_coord ])
} }
/// Parse horizontal "lineto" command. /// Parse horizontal "lineto" command.
fn parse_h_lineto(&mut self, absolute: bool) -> Result<(), ()> { fn parse_h_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
parse_arguments!(self, absolute, HorizontalLineTo, [ x => parse_number ]) parse_arguments!(self, absolute, HorizontalLineTo, [ x => parse_number ])
} }
/// Parse vertical "lineto" command. /// Parse vertical "lineto" command.
fn parse_v_lineto(&mut self, absolute: bool) -> Result<(), ()> { fn parse_v_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
parse_arguments!(self, absolute, VerticalLineTo, [ y => parse_number ]) parse_arguments!(self, absolute, VerticalLineTo, [ y => parse_number ])
} }
/// Parse cubic Bézier curve command. /// Parse cubic Bézier curve command.
fn parse_curveto(&mut self, absolute: bool) -> Result<(), ()> { fn parse_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
parse_arguments!(self, absolute, CurveTo, [ parse_arguments!(self, absolute, CurveTo, [
control1 => parse_coord, control2 => parse_coord, point => parse_coord control1 => parse_coord, control2 => parse_coord, point => parse_coord
]) ])
} }
/// Parse smooth "curveto" command. /// Parse smooth "curveto" command.
fn parse_smooth_curveto(&mut self, absolute: bool) -> Result<(), ()> { fn parse_smooth_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
parse_arguments!(self, absolute, SmoothCurveTo, [ parse_arguments!(self, absolute, SmoothCurveTo, [
control2 => parse_coord, point => parse_coord control2 => parse_coord, point => parse_coord
]) ])
} }
/// Parse quadratic Bézier curve command. /// Parse quadratic Bézier curve command.
fn parse_quadratic_bezier_curveto(&mut self, absolute: bool) -> Result<(), ()> { fn parse_quadratic_bezier_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
parse_arguments!(self, absolute, QuadBezierCurveTo, [ parse_arguments!(self, absolute, QuadBezierCurveTo, [
control1 => parse_coord, point => parse_coord control1 => parse_coord, point => parse_coord
]) ])
} }
/// Parse smooth quadratic Bézier curveto command. /// Parse smooth quadratic Bézier curveto command.
fn parse_smooth_quadratic_bezier_curveto(&mut self, absolute: bool) -> Result<(), ()> { fn parse_smooth_quadratic_bezier_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
parse_arguments!(self, absolute, SmoothQuadBezierCurveTo, [ point => parse_coord ]) parse_arguments!(self, absolute, SmoothQuadBezierCurveTo, [ point => parse_coord ])
} }
/// Parse elliptical arc curve command. /// Parse elliptical arc curve command.
fn parse_elliprical_arc(&mut self, absolute: bool) -> Result<(), ()> { fn parse_elliptical_arc(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
// Parse a flag whose value is '0' or '1'; otherwise, return Err(()). // Parse a flag whose value is '0' or '1'; otherwise, return Err(()).
let parse_flag = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| -> Result<bool, ()> { let parse_flag = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| {
match iter.next() { match iter.next() {
Some(c) if c == b'0' || c == b'1' => Ok(c == b'1'), Some(c) if c == b'0' || c == b'1' => Ok(ArcFlag(c == b'1')),
_ => Err(()), _ => Err(()),
} }
}; };