diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index da424959e74..f196ccd6941 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -15,6 +15,7 @@ use style_traits::ToCss; use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; use values::computed::position::Position; use values::specified::{self, HorizontalDirection, SizeKeyword, VerticalDirection}; +use values::specified::image::CompatMode; use values::specified::url::SpecifiedUrl; @@ -124,17 +125,22 @@ pub struct Gradient { pub repeating: bool, /// Gradient kind can be linear or radial. pub gradient_kind: GradientKind, + /// Compatibility mode. + pub compat_mode: CompatMode, } impl ToCss for Gradient { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.compat_mode == CompatMode::WebKit { + try!(dest.write_str("-webkit-")); + } if self.repeating { try!(dest.write_str("repeating-")); } match self.gradient_kind { GradientKind::Linear(angle_or_corner) => { try!(dest.write_str("linear-gradient(")); - try!(angle_or_corner.to_css(dest)); + try!(angle_or_corner.to_css(dest, self.compat_mode)); }, GradientKind::Radial(ref shape, position) => { try!(dest.write_str("radial-gradient(")); @@ -178,25 +184,30 @@ impl ToComputedValue for specified::Gradient { let specified::Gradient { ref stops, repeating, - ref gradient_kind + ref gradient_kind, + compat_mode, } = *self; Gradient { stops: stops.iter().map(|s| s.to_computed_value(context)).collect(), repeating: repeating, gradient_kind: gradient_kind.to_computed_value(context), + compat_mode: compat_mode, } } + #[inline] fn from_computed_value(computed: &Gradient) -> Self { let Gradient { ref stops, repeating, - ref gradient_kind + ref gradient_kind, + compat_mode, } = *computed; specified::Gradient { stops: stops.iter().map(ToComputedValue::from_computed_value).collect(), repeating: repeating, gradient_kind: ToComputedValue::from_computed_value(gradient_kind), + compat_mode: compat_mode, } } } @@ -602,12 +613,14 @@ impl ToComputedValue for specified::AngleOrCorner { } } -impl ToCss for AngleOrCorner { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl AngleOrCorner { + fn to_css(&self, dest: &mut W, mode: CompatMode) -> fmt::Result where W: fmt::Write { match *self { AngleOrCorner::Angle(angle) => angle.to_css(dest), AngleOrCorner::Corner(horizontal, vertical) => { - try!(dest.write_str("to ")); + if mode == CompatMode::Modern { + try!(dest.write_str("to ")); + } try!(horizontal.to_css(dest)); try!(dest.write_str(" ")); try!(vertical.to_css(dest)); diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 4123ed7da67..610646b3c00 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -98,10 +98,15 @@ pub struct Gradient { pub repeating: bool, /// Gradients can be linear or radial. pub gradient_kind: GradientKind, + /// Compatibility mode. + pub compat_mode: CompatMode, } impl ToCss for Gradient { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.compat_mode == CompatMode::WebKit { + try!(dest.write_str("-webkit-")); + } if self.repeating { try!(dest.write_str("repeating-")); } @@ -109,7 +114,7 @@ impl ToCss for Gradient { match self.gradient_kind { GradientKind::Linear(angle_or_corner) => { try!(dest.write_str("linear-gradient(")); - try!(angle_or_corner.to_css(dest)); + try!(angle_or_corner.to_css(dest, self.compat_mode)); if angle_or_corner == AngleOrCorner::None { skipcomma = true; } @@ -136,9 +141,9 @@ impl ToCss for Gradient { impl Gradient { /// Parses a gradient from the given arguments. pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result { - let parse_linear_gradient = |input: &mut Parser| { + let parse_linear_gradient = |input: &mut Parser, mode| { input.parse_nested_block(|input| { - let kind = try!(GradientKind::parse_linear(context, input)); + let kind = try!(GradientKind::parse_linear(context, input, mode)); let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i))); Ok((kind, stops)) }) @@ -151,13 +156,23 @@ impl Gradient { }) }; let mut repeating = false; + let mut compat_mode = CompatMode::Modern; let (gradient_kind, stops) = match_ignore_ascii_case! { &try!(input.expect_function()), "linear-gradient" => { - try!(parse_linear_gradient(input)) + try!(parse_linear_gradient(input, compat_mode)) + }, + "-webkit-linear-gradient" => { + compat_mode = CompatMode::WebKit; + try!(parse_linear_gradient(input, compat_mode)) }, "repeating-linear-gradient" => { repeating = true; - try!(parse_linear_gradient(input)) + try!(parse_linear_gradient(input, compat_mode)) + }, + "-webkit-repeating-linear-gradient" => { + repeating = true; + compat_mode = CompatMode::WebKit; + try!(parse_linear_gradient(input, compat_mode)) }, "radial-gradient" => { try!(parse_radial_gradient(input)) @@ -178,6 +193,7 @@ impl Gradient { stops: stops, repeating: repeating, gradient_kind: gradient_kind, + compat_mode: compat_mode, }) } } @@ -198,10 +214,20 @@ pub enum GradientKind { Radial(EndingShape, Position), } +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +/// Whether we used the modern notation or the compatibility `-webkit` prefix. +pub enum CompatMode { + /// Modern syntax. + Modern, + /// `-webkit` prefix. + WebKit, +} + impl GradientKind { /// Parses a linear gradient kind from the given arguments. - pub fn parse_linear(context: &ParserContext, input: &mut Parser) -> Result { - let angle_or_corner = try!(AngleOrCorner::parse(context, input)); + fn parse_linear(context: &ParserContext, input: &mut Parser, mode: CompatMode) -> Result { + let angle_or_corner = try!(AngleOrCorner::parse(context, input, mode)); Ok(GradientKind::Linear(angle_or_corner)) } @@ -342,13 +368,15 @@ pub enum AngleOrCorner { None, } -impl ToCss for AngleOrCorner { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl AngleOrCorner { + fn to_css(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result where W: fmt::Write { match *self { AngleOrCorner::None => Ok(()), AngleOrCorner::Angle(angle) => angle.to_css(dest), AngleOrCorner::Corner(horizontal, vertical) => { - try!(dest.write_str("to ")); + if compat_mode == CompatMode::Modern { + try!(dest.write_str("to ")); + } let mut horizontal_present = false; if let Some(horizontal) = horizontal { try!(horizontal.to_css(dest)); @@ -366,21 +394,22 @@ impl ToCss for AngleOrCorner { } } -impl Parse for AngleOrCorner { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("to")).is_ok() { +impl AngleOrCorner { + fn parse(context: &ParserContext, input: &mut Parser, mode: CompatMode) -> Result { + if let Ok(angle) = input.try(|i| Angle::parse(context, i)) { + try!(input.expect_comma()); + return Ok(AngleOrCorner::Angle(angle)) + } + if mode == CompatMode::WebKit || input.try(|input| input.expect_ident_matching("to")).is_ok() { let (horizontal, vertical) = - if let Ok(value) = input.try(HorizontalDirection::parse) { - (Some(value), input.try(VerticalDirection::parse).ok()) - } else { - let value = try!(VerticalDirection::parse(input)); - (input.try(HorizontalDirection::parse).ok(), Some(value)) - }; + if let Ok(value) = input.try(HorizontalDirection::parse) { + (Some(value), input.try(VerticalDirection::parse).ok()) + } else { + let value = try!(VerticalDirection::parse(input)); + (input.try(HorizontalDirection::parse).ok(), Some(value)) + }; try!(input.expect_comma()); Ok(AngleOrCorner::Corner(horizontal, vertical)) - } else if let Ok(angle) = input.try(|i| Angle::parse(context, i)) { - try!(input.expect_comma()); - Ok(AngleOrCorner::Angle(angle)) } else { Ok(AngleOrCorner::None) }