use std::fmt;
use xmlparser::{
FromSpan,
Stream,
StrSpan,
};
use error::{
StreamError,
StreamResult,
};
use {
StreamExt,
};
#[derive(Clone, Copy, PartialEq, Debug)]
#[allow(missing_docs)]
pub enum Token {
Matrix {
a: f64,
b: f64,
c: f64,
d: f64,
e: f64,
f: f64,
},
Translate {
tx: f64,
ty: f64,
},
Scale {
sx: f64,
sy: f64,
},
Rotate {
angle: f64,
},
SkewX {
angle: f64,
},
SkewY {
angle: f64,
},
}
#[derive(Clone, Copy, PartialEq)]
pub struct Tokenizer<'a> {
stream: Stream<'a>,
rotate_ts: Option<(f64, f64)>,
last_angle: Option<f64>,
}
impl<'a> FromSpan<'a> for Tokenizer<'a> {
fn from_span(span: StrSpan<'a>) -> Self {
Tokenizer {
stream: Stream::from_span(span),
rotate_ts: None,
last_angle: None,
}
}
}
impl<'a> fmt::Debug for Tokenizer<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TransformTokenizer({:?})", self.stream.span())
}
}
impl<'a> Iterator for Tokenizer<'a> {
type Item = StreamResult<Token>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(a) = self.last_angle {
self.last_angle = None;
return Some(Ok(Token::Rotate {
angle: a,
}));
}
if let Some((x, y)) = self.rotate_ts {
self.rotate_ts = None;
return Some(Ok(Token::Translate {
tx: -x,
ty: -y,
}));
}
self.stream.skip_spaces();
if self.stream.at_end() {
return None;
}
Some(self.parse_next())
}
}
impl<'a> Tokenizer<'a> {
fn parse_next(&mut self) -> StreamResult<Token> {
let s = &mut self.stream;
let name = s.consume_name()?;
s.skip_spaces();
s.consume_byte(b'(')?;
let t = match name.as_bytes() {
b"matrix" => {
Token::Matrix {
a: s.parse_list_number()?,
b: s.parse_list_number()?,
c: s.parse_list_number()?,
d: s.parse_list_number()?,
e: s.parse_list_number()?,
f: s.parse_list_number()?,
}
}
b"translate" => {
let x = s.parse_list_number()?;
s.skip_spaces();
let y = if s.is_curr_byte_eq(b')') {
0.0
} else {
s.parse_list_number()?
};
Token::Translate {
tx: x,
ty: y,
}
}
b"scale" => {
let x = s.parse_list_number()?;
s.skip_spaces();
let y = if s.is_curr_byte_eq(b')') {
x
} else {
s.parse_list_number()?
};
Token::Scale {
sx: x,
sy: y,
}
}
b"rotate" => {
let a = s.parse_list_number()?;
s.skip_spaces();
if !s.is_curr_byte_eq(b')') {
let cx = s.parse_list_number()?;
let cy = s.parse_list_number()?;
self.rotate_ts = Some((cx, cy));
self.last_angle = Some(a);
Token::Translate {
tx: cx,
ty: cy,
}
} else {
Token::Rotate {
angle: a,
}
}
}
b"skewX" => {
Token::SkewX {
angle: s.parse_list_number()?,
}
}
b"skewY" => {
Token::SkewY {
angle: s.parse_list_number()?,
}
}
_ => {
let pos = s.gen_error_pos();
return Err(StreamError::InvalidTransformPrefix(pos));
}
};
s.skip_spaces();
s.consume_byte(b')')?;
s.skip_spaces();
if s.is_curr_byte_eq(b',') {
s.advance(1);
}
Ok(t)
}
}