mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
style: Use macro for path parser.
There are a lot of duplicates, so we use macro to refine them. Depends on D2963 Differential Revision: https://phabricator.services.mozilla.com/D2966
This commit is contained in:
parent
dce2e2927f
commit
b85c734c41
1 changed files with 78 additions and 163 deletions
|
@ -70,6 +70,34 @@ struct PathParser<'a> {
|
||||||
path: Vec<PathCommand>,
|
path: Vec<PathCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! parse_arguments {
|
||||||
|
(
|
||||||
|
$parser:ident,
|
||||||
|
$abs:ident,
|
||||||
|
$enum:ident,
|
||||||
|
[ $para:ident => $func:ident $(, $other_para:ident => $other_func:ident)* ]
|
||||||
|
) => {
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
let $para = $func(&mut $parser.chars)?;
|
||||||
|
$(
|
||||||
|
skip_comma_wsp(&mut $parser.chars);
|
||||||
|
let $other_para = $other_func(&mut $parser.chars)?;
|
||||||
|
)*
|
||||||
|
$parser.path.push(PathCommand::$enum { $para $(, $other_para)*, $abs });
|
||||||
|
|
||||||
|
// End of string or the next character is a possible new command.
|
||||||
|
if !skip_wsp(&mut $parser.chars) ||
|
||||||
|
$parser.chars.peek().map_or(true, |c| c.is_ascii_alphabetic()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
skip_comma_wsp(&mut $parser.chars);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> PathParser<'a> {
|
impl<'a> PathParser<'a> {
|
||||||
/// Parse a sub-path.
|
/// Parse a sub-path.
|
||||||
fn parse_subpath(&mut self) -> Result<(), ()> {
|
fn parse_subpath(&mut self) -> Result<(), ()> {
|
||||||
|
@ -87,46 +115,30 @@ impl<'a> PathParser<'a> {
|
||||||
match self.chars.next() {
|
match self.chars.next() {
|
||||||
Some(command) => {
|
Some(command) => {
|
||||||
let abs = command.is_uppercase();
|
let abs = command.is_uppercase();
|
||||||
match command {
|
macro_rules! parse_command {
|
||||||
'Z' | 'z' => {
|
( $($($p:pat)|+ => $parse_func:ident,)* ) => {
|
||||||
// Note: A "closepath" coulbe be followed immediately by "moveto" or
|
match command {
|
||||||
// any other command, so we don't break this loop.
|
$(
|
||||||
self.path.push(PathCommand::ClosePath);
|
$($p)|+ => {
|
||||||
},
|
skip_wsp(&mut self.chars);
|
||||||
'L' | 'l' => {
|
self.$parse_func(abs)?;
|
||||||
skip_wsp(&mut self.chars);
|
},
|
||||||
self.parse_lineto(abs)?;
|
)*
|
||||||
},
|
_ => return Err(()),
|
||||||
'H' | 'h' => {
|
}
|
||||||
skip_wsp(&mut self.chars);
|
}
|
||||||
self.parse_h_lineto(abs)?;
|
|
||||||
},
|
|
||||||
'V' | 'v' => {
|
|
||||||
skip_wsp(&mut self.chars);
|
|
||||||
self.parse_v_lineto(abs)?;
|
|
||||||
},
|
|
||||||
'C' | 'c' => {
|
|
||||||
skip_wsp(&mut self.chars);
|
|
||||||
self.parse_curveto(abs)?;
|
|
||||||
},
|
|
||||||
'S' | 's' => {
|
|
||||||
skip_wsp(&mut self.chars);
|
|
||||||
self.parse_smooth_curveto(abs)?;
|
|
||||||
},
|
|
||||||
'Q' | 'q' => {
|
|
||||||
skip_wsp(&mut self.chars);
|
|
||||||
self.parse_quadratic_bezier_curveto(abs)?;
|
|
||||||
},
|
|
||||||
'T' | 't' => {
|
|
||||||
skip_wsp(&mut self.chars);
|
|
||||||
self.parse_smooth_quadratic_bezier_curveto(abs)?;
|
|
||||||
},
|
|
||||||
'A' | 'a' => {
|
|
||||||
skip_wsp(&mut self.chars);
|
|
||||||
self.parse_elliprical_arc(abs)?;
|
|
||||||
},
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
}
|
||||||
|
parse_command!(
|
||||||
|
'Z' | 'z' => parse_closepath,
|
||||||
|
'L' | 'l' => parse_lineto,
|
||||||
|
'H' | 'h' => parse_h_lineto,
|
||||||
|
'V' | 'v' => parse_v_lineto,
|
||||||
|
'C' | 'c' => parse_curveto,
|
||||||
|
'S' | 's' => parse_smooth_curveto,
|
||||||
|
'Q' | 'q' => parse_quadratic_bezier_curveto,
|
||||||
|
'T' | 't' => parse_smooth_quadratic_bezier_curveto,
|
||||||
|
'A' | 'a' => parse_elliprical_arc,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
_ => break, // no more commands.
|
_ => break, // no more commands.
|
||||||
}
|
}
|
||||||
|
@ -158,128 +170,51 @@ impl<'a> PathParser<'a> {
|
||||||
self.parse_lineto(absolute)
|
self.parse_lineto(absolute)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse "closepath" command.
|
||||||
|
fn parse_closepath(&mut self, _absolute: bool) -> Result<(), ()> {
|
||||||
|
self.path.push(PathCommand::ClosePath);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse "lineto" command.
|
/// Parse "lineto" command.
|
||||||
fn parse_lineto(&mut self, absolute: bool) -> Result<(), ()> {
|
fn parse_lineto(&mut self, absolute: bool) -> Result<(), ()> {
|
||||||
loop {
|
parse_arguments!(self, absolute, LineTo, [ point => parse_coord ])
|
||||||
let point = parse_coord(&mut self.chars)?;
|
|
||||||
self.path.push(PathCommand::LineTo { point, absolute });
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse horizontal "lineto" command.
|
/// Parse horizontal "lineto" command.
|
||||||
fn parse_h_lineto(&mut self, absolute: bool) -> Result<(), ()> {
|
fn parse_h_lineto(&mut self, absolute: bool) -> Result<(), ()> {
|
||||||
loop {
|
parse_arguments!(self, absolute, HorizontalLineTo, [ x => parse_number ])
|
||||||
let x = parse_number(&mut self.chars)?;
|
|
||||||
self.path.push(PathCommand::HorizontalLineTo { x, absolute });
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse vertical "lineto" command.
|
/// Parse vertical "lineto" command.
|
||||||
fn parse_v_lineto(&mut self, absolute: bool) -> Result<(), ()> {
|
fn parse_v_lineto(&mut self, absolute: bool) -> Result<(), ()> {
|
||||||
loop {
|
parse_arguments!(self, absolute, VerticalLineTo, [ y => parse_number ])
|
||||||
let y = parse_number(&mut self.chars)?;
|
|
||||||
self.path.push(PathCommand::VerticalLineTo { y, absolute });
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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: bool) -> Result<(), ()> {
|
||||||
loop {
|
parse_arguments!(self, absolute, CurveTo, [
|
||||||
let control1 = parse_coord(&mut self.chars)?;
|
control1 => parse_coord, control2 => parse_coord, point => parse_coord
|
||||||
skip_comma_wsp(&mut self.chars);
|
])
|
||||||
let control2 = parse_coord(&mut self.chars)?;
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
let point = parse_coord(&mut self.chars)?;
|
|
||||||
|
|
||||||
self.path.push(PathCommand::CurveTo { control1, control2, point, absolute });
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse smooth "curveto" command.
|
/// Parse smooth "curveto" command.
|
||||||
fn parse_smooth_curveto(&mut self, absolute: bool) -> Result<(), ()> {
|
fn parse_smooth_curveto(&mut self, absolute: bool) -> Result<(), ()> {
|
||||||
loop {
|
parse_arguments!(self, absolute, SmoothCurveTo, [
|
||||||
let control2 = parse_coord(&mut self.chars)?;
|
control2 => parse_coord, point => parse_coord
|
||||||
skip_comma_wsp(&mut self.chars);
|
])
|
||||||
let point = parse_coord(&mut self.chars)?;
|
|
||||||
|
|
||||||
self.path.push(PathCommand::SmoothCurveTo { control2, point, absolute });
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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: bool) -> Result<(), ()> {
|
||||||
loop {
|
parse_arguments!(self, absolute, QuadBezierCurveTo, [
|
||||||
let control1 = parse_coord(&mut self.chars)?;
|
control1 => parse_coord, point => parse_coord
|
||||||
skip_comma_wsp(&mut self.chars);
|
])
|
||||||
let point = parse_coord(&mut self.chars)?;
|
|
||||||
|
|
||||||
self.path.push(PathCommand::QuadBezierCurveTo { control1, point, absolute });
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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: bool) -> Result<(), ()> {
|
||||||
loop {
|
parse_arguments!(self, absolute, SmoothQuadBezierCurveTo, [ point => parse_coord ])
|
||||||
let point = parse_coord(&mut self.chars)?;
|
|
||||||
|
|
||||||
self.path.push(PathCommand::SmoothQuadBezierCurveTo { point, absolute });
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse elliptical arc curve command.
|
/// Parse elliptical arc curve command.
|
||||||
|
@ -293,34 +228,14 @@ impl<'a> PathParser<'a> {
|
||||||
iter.next();
|
iter.next();
|
||||||
Ok(value)
|
Ok(value)
|
||||||
};
|
};
|
||||||
|
parse_arguments!(self, absolute, EllipticalArc, [
|
||||||
loop {
|
rx => parse_number,
|
||||||
let rx = parse_number(&mut self.chars)?;
|
ry => parse_number,
|
||||||
skip_comma_wsp(&mut self.chars);
|
angle => parse_number,
|
||||||
let ry = parse_number(&mut self.chars)?;
|
large_arc_flag => parse_flag,
|
||||||
skip_comma_wsp(&mut self.chars);
|
sweep_flag => parse_flag,
|
||||||
let angle = parse_number(&mut self.chars)?;
|
point => parse_coord
|
||||||
skip_comma_wsp(&mut self.chars);
|
])
|
||||||
let large_arc_flag = parse_flag(&mut self.chars)?;
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
let sweep_flag = parse_flag(&mut self.chars)?;
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
let point = parse_coord(&mut self.chars)?;
|
|
||||||
|
|
||||||
self.path.push(
|
|
||||||
PathCommand::EllipticalArc {
|
|
||||||
rx, ry, angle, large_arc_flag, sweep_flag, point, absolute
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skip_comma_wsp(&mut self.chars);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue