diff --git a/components/plugins/lib.rs b/components/plugins/lib.rs index a7d356f47ee..662eeedc385 100644 --- a/components/plugins/lib.rs +++ b/components/plugins/lib.rs @@ -50,3 +50,49 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box lints::InheritancePass as LintPassObject); } + +#[macro_export] +macro_rules! define_css_keyword_enum { + ($name: ident: $( $css: expr => $variant: ident ),+,) => { + define_css_keyword_enum!($name: $( $css => $variant ),+) + }; + ($name: ident: $( $css: expr => $variant: ident ),+) => { + #[allow(non_camel_case_types)] + #[deriving(Clone, Eq, PartialEq, FromPrimitive)] + pub enum $name { + $( $variant ),+ + } + + impl $name { + pub fn parse(component_value: &::cssparser::ast::ComponentValue) -> Result<$name, ()> { + use std::ascii::AsciiExt; + match component_value { + &::cssparser::ast::Ident(ref value) => { + match value.to_ascii_lower().as_slice() { + $( concat!($css) => Ok($name::$variant), )+ + _ => Err(()) + } + } + _ => Err(()) + } + } + } + + impl ::std::fmt::Show for $name { + #[inline] + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use cssparser::ToCss; + self.fmt_to_css(f) + } + } + + impl ::cssparser::ToCss for $name { + fn to_css(&self, dest: &mut W) -> ::text_writer::Result + where W: ::text_writer::TextWriter { + match self { + $( &$name::$variant => dest.write_str($css) ),+ + } + } + } + } +} diff --git a/components/style/lib.rs b/components/style/lib.rs index fec6c2d5b61..19f62ff36dd 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -18,6 +18,7 @@ extern crate collections; extern crate geom; extern crate serialize; extern crate sync; +extern crate text_writer; extern crate url; extern crate cssparser; @@ -27,6 +28,9 @@ extern crate string_cache; #[phase(plugin)] extern crate string_cache_macros; +#[phase(plugin)] +extern crate plugins; + #[phase(plugin)] extern crate lazy_static; diff --git a/components/style/properties/common_types.rs b/components/style/properties/common_types.rs index 9dcd65d6fc5..52a0fb3be40 100644 --- a/components/style/properties/common_types.rs +++ b/components/style/properties/common_types.rs @@ -14,11 +14,11 @@ pub mod specified { use std::ascii::AsciiExt; use std::f64::consts::PI; use std::fmt; - use std::fmt::{Formatter, FormatError, Show}; + use std::fmt::{Formatter, Show}; use url::Url; - use cssparser; - use cssparser::ast; + use cssparser::{mod, ast, ToCss, CssStringWriter}; use cssparser::ast::*; + use text_writer::{mod, TextWriter}; use parsing_utils::{mod, BufferedIter, ParserIter}; use super::{Au, CSSFloat}; @@ -42,11 +42,16 @@ pub mod specified { }) } } + impl fmt::Show for CSSColor { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for CSSColor { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self.authored { - Some(ref s) => write!(f, "{}", s), - None => write!(f, "{}", self.parsed), + Some(ref s) => dest.write_str(s.as_slice()), + None => self.parsed.to_css(dest), } } } @@ -57,22 +62,30 @@ pub mod specified { pub authored: Option, } impl fmt::Show for CSSRGBA { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for CSSRGBA { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self.authored { - Some(ref s) => write!(f, "{}", s), - None => write!(f, "{}", self.parsed), + Some(ref s) => dest.write_str(s.as_slice()), + None => self.parsed.to_css(dest), } } } #[deriving(Clone, PartialEq)] pub struct CSSImage(pub Option); + impl fmt::Show for CSSImage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &CSSImage(ref url) = self; - match url { - &Some(ref image) => write!(f, "{}", image), - &None => write!(f, "none"), + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for CSSImage { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { + match self { + &CSSImage(Some(ref image)) => image.to_css(dest), + &CSSImage(None) => dest.write_str("none"), } } } @@ -97,17 +110,24 @@ pub mod specified { // Vmin(CSSFloat), // Vmax(CSSFloat), } + impl fmt::Show for Length { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for Length { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self { - &Length::Au(length) => write!(f, "{}", length), - &Length::Em(length) => write!(f, "{}em", length), - &Length::Ex(length) => write!(f, "{}ex", length), - &Length::Rem(length) => write!(f, "{}rem", length), - &Length::ServoCharacterWidth(_) => panic!("internal CSS values should never be serialized"), + &Length::Au(length) => write!(dest, "{}px", length.to_subpx()), + &Length::Em(length) => write!(dest, "{}em", length), + &Length::Ex(length) => write!(dest, "{}ex", length), + &Length::Rem(length) => write!(dest, "{}rem", length), + &Length::ServoCharacterWidth(_) + => panic!("internal CSS values should never be serialized"), } } } + const AU_PER_PX: CSSFloat = 60.; const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; @@ -156,11 +176,17 @@ pub mod specified { Length(Length), Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] } + impl fmt::Show for LengthOrPercentage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for LengthOrPercentage { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self { - &LengthOrPercentage::Length(length) => write!(f, "{}", length), - &LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.), + &LengthOrPercentage::Length(length) => length.to_css(dest), + &LengthOrPercentage::Percentage(percentage) + => write!(dest, "{}%", percentage * 100.), } } } @@ -195,12 +221,18 @@ pub mod specified { Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] Auto, } + impl fmt::Show for LengthOrPercentageOrAuto { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for LengthOrPercentageOrAuto { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self { - &LengthOrPercentageOrAuto::Length(length) => write!(f, "{}", length), - &LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.), - &LengthOrPercentageOrAuto::Auto => write!(f, "auto"), + &LengthOrPercentageOrAuto::Length(length) => length.to_css(dest), + &LengthOrPercentageOrAuto::Percentage(percentage) + => write!(dest, "{}%", percentage * 100.), + &LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), } } } @@ -235,12 +267,18 @@ pub mod specified { Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] None, } + impl fmt::Show for LengthOrPercentageOrNone { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for LengthOrPercentageOrNone { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self { - &LengthOrPercentageOrNone::Length(length) => write!(f, "{}", length), - &LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.), - &LengthOrPercentageOrNone::None => write!(f, "none"), + &LengthOrPercentageOrNone::Length(length) => length.to_css(dest), + &LengthOrPercentageOrNone::Percentage(percentage) + => write!(dest, "{}%", percentage * 100.), + &LengthOrPercentageOrNone::None => dest.write_str("none"), } } } @@ -312,10 +350,14 @@ pub mod specified { #[deriving(Clone, PartialEq, PartialOrd)] pub struct Angle(pub CSSFloat); - impl Show for Angle { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + impl fmt::Show for Angle { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for Angle { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { let Angle(value) = *self; - write!(f, "{}", value) + write!(dest, "{}rad", value) } } @@ -353,11 +395,20 @@ pub mod specified { LinearGradient(LinearGradient), } - impl Show for Image { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + impl fmt::Show for Image { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for Image { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self { - &Image::Url(ref url) => write!(f, "url(\"{}\")", url), - &Image::LinearGradient(ref grad) => write!(f, "linear-gradient({})", grad), + &Image::Url(ref url) => { + try!(dest.write_str("url(\"")); + try!(write!(CssStringWriter::new(dest), "{}", url)); + try!(dest.write_str("\")")); + Ok(()) + } + &Image::LinearGradient(ref gradient) => gradient.to_css(dest) } } } @@ -405,12 +456,19 @@ pub mod specified { pub stops: Vec, } - impl Show for LinearGradient { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { - let _ = write!(f, "{}", self.angle_or_corner); + impl fmt::Show for LinearGradient { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for LinearGradient { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { + try!(dest.write_str("linear-gradient(")); + try!(self.angle_or_corner.to_css(dest)); for stop in self.stops.iter() { - let _ = write!(f, ", {}", stop); + try!(dest.write_str(", ")); + try!(stop.to_css(dest)); } + try!(dest.write_char(')')); Ok(()) } } @@ -422,11 +480,21 @@ pub mod specified { Corner(HorizontalDirection, VerticalDirection), } - impl Show for AngleOrCorner { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + impl fmt::Show for AngleOrCorner { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for AngleOrCorner { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self { - &AngleOrCorner::Angle(angle) => write!(f, "{}", angle), - &AngleOrCorner::Corner(horiz, vert) => write!(f, "to {} {}", horiz, vert), + &AngleOrCorner::Angle(angle) => angle.to_css(dest), + &AngleOrCorner::Corner(horizontal, vertical) => { + try!(dest.write_str("to ")); + try!(horizontal.to_css(dest)); + try!(dest.write_char(' ')); + try!(vertical.to_css(dest)); + Ok(()) + } } } } @@ -442,45 +510,23 @@ pub mod specified { pub position: Option, } - impl Show for ColorStop { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { - let _ = write!(f, "{}", self.color); - self.position.map(|pos| { - let _ = write!(f, " {}", pos); - }); + impl fmt::Show for ColorStop { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for ColorStop { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { + try!(self.color.to_css(dest)); + if let Some(position) = self.position { + try!(dest.write_char(' ')); + try!(position.to_css(dest)); + } Ok(()) } } - #[deriving(Clone, PartialEq)] - pub enum HorizontalDirection { - Left, - Right, - } - - impl Show for HorizontalDirection { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { - match self { - &HorizontalDirection::Left => write!(f, "left"), - &HorizontalDirection::Right => write!(f, "right"), - } - } - } - - #[deriving(Clone, PartialEq)] - pub enum VerticalDirection { - Top, - Bottom, - } - - impl Show for VerticalDirection { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { - match self { - &VerticalDirection::Top => write!(f, "top"), - &VerticalDirection::Bottom => write!(f, "bottom"), - } - } - } + define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right) + define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom) fn parse_color_stop(source: ParserIter) -> Result { let color = match source.next() {