mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Implement webkit-prefixed linear gradients
This is half of https://github.com/servo/servo/issues/15441.
This commit is contained in:
parent
e01529a647
commit
133b599a6f
2 changed files with 70 additions and 28 deletions
|
@ -15,6 +15,7 @@ use style_traits::ToCss;
|
||||||
use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
|
use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
|
||||||
use values::computed::position::Position;
|
use values::computed::position::Position;
|
||||||
use values::specified::{self, HorizontalDirection, SizeKeyword, VerticalDirection};
|
use values::specified::{self, HorizontalDirection, SizeKeyword, VerticalDirection};
|
||||||
|
use values::specified::image::CompatMode;
|
||||||
use values::specified::url::SpecifiedUrl;
|
use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,17 +125,22 @@ pub struct Gradient {
|
||||||
pub repeating: bool,
|
pub repeating: bool,
|
||||||
/// Gradient kind can be linear or radial.
|
/// Gradient kind can be linear or radial.
|
||||||
pub gradient_kind: GradientKind,
|
pub gradient_kind: GradientKind,
|
||||||
|
/// Compatibility mode.
|
||||||
|
pub compat_mode: CompatMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Gradient {
|
impl ToCss for Gradient {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
if self.compat_mode == CompatMode::WebKit {
|
||||||
|
try!(dest.write_str("-webkit-"));
|
||||||
|
}
|
||||||
if self.repeating {
|
if self.repeating {
|
||||||
try!(dest.write_str("repeating-"));
|
try!(dest.write_str("repeating-"));
|
||||||
}
|
}
|
||||||
match self.gradient_kind {
|
match self.gradient_kind {
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
GradientKind::Linear(angle_or_corner) => {
|
||||||
try!(dest.write_str("linear-gradient("));
|
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) => {
|
GradientKind::Radial(ref shape, position) => {
|
||||||
try!(dest.write_str("radial-gradient("));
|
try!(dest.write_str("radial-gradient("));
|
||||||
|
@ -178,25 +184,30 @@ impl ToComputedValue for specified::Gradient {
|
||||||
let specified::Gradient {
|
let specified::Gradient {
|
||||||
ref stops,
|
ref stops,
|
||||||
repeating,
|
repeating,
|
||||||
ref gradient_kind
|
ref gradient_kind,
|
||||||
|
compat_mode,
|
||||||
} = *self;
|
} = *self;
|
||||||
Gradient {
|
Gradient {
|
||||||
stops: stops.iter().map(|s| s.to_computed_value(context)).collect(),
|
stops: stops.iter().map(|s| s.to_computed_value(context)).collect(),
|
||||||
repeating: repeating,
|
repeating: repeating,
|
||||||
gradient_kind: gradient_kind.to_computed_value(context),
|
gradient_kind: gradient_kind.to_computed_value(context),
|
||||||
|
compat_mode: compat_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &Gradient) -> Self {
|
fn from_computed_value(computed: &Gradient) -> Self {
|
||||||
let Gradient {
|
let Gradient {
|
||||||
ref stops,
|
ref stops,
|
||||||
repeating,
|
repeating,
|
||||||
ref gradient_kind
|
ref gradient_kind,
|
||||||
|
compat_mode,
|
||||||
} = *computed;
|
} = *computed;
|
||||||
specified::Gradient {
|
specified::Gradient {
|
||||||
stops: stops.iter().map(ToComputedValue::from_computed_value).collect(),
|
stops: stops.iter().map(ToComputedValue::from_computed_value).collect(),
|
||||||
repeating: repeating,
|
repeating: repeating,
|
||||||
gradient_kind: ToComputedValue::from_computed_value(gradient_kind),
|
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 {
|
impl AngleOrCorner {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W, mode: CompatMode) -> fmt::Result where W: fmt::Write {
|
||||||
match *self {
|
match *self {
|
||||||
AngleOrCorner::Angle(angle) => angle.to_css(dest),
|
AngleOrCorner::Angle(angle) => angle.to_css(dest),
|
||||||
AngleOrCorner::Corner(horizontal, vertical) => {
|
AngleOrCorner::Corner(horizontal, vertical) => {
|
||||||
try!(dest.write_str("to "));
|
if mode == CompatMode::Modern {
|
||||||
|
try!(dest.write_str("to "));
|
||||||
|
}
|
||||||
try!(horizontal.to_css(dest));
|
try!(horizontal.to_css(dest));
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
try!(vertical.to_css(dest));
|
try!(vertical.to_css(dest));
|
||||||
|
|
|
@ -98,10 +98,15 @@ pub struct Gradient {
|
||||||
pub repeating: bool,
|
pub repeating: bool,
|
||||||
/// Gradients can be linear or radial.
|
/// Gradients can be linear or radial.
|
||||||
pub gradient_kind: GradientKind,
|
pub gradient_kind: GradientKind,
|
||||||
|
/// Compatibility mode.
|
||||||
|
pub compat_mode: CompatMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Gradient {
|
impl ToCss for Gradient {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
if self.compat_mode == CompatMode::WebKit {
|
||||||
|
try!(dest.write_str("-webkit-"));
|
||||||
|
}
|
||||||
if self.repeating {
|
if self.repeating {
|
||||||
try!(dest.write_str("repeating-"));
|
try!(dest.write_str("repeating-"));
|
||||||
}
|
}
|
||||||
|
@ -109,7 +114,7 @@ impl ToCss for Gradient {
|
||||||
match self.gradient_kind {
|
match self.gradient_kind {
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
GradientKind::Linear(angle_or_corner) => {
|
||||||
try!(dest.write_str("linear-gradient("));
|
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 {
|
if angle_or_corner == AngleOrCorner::None {
|
||||||
skipcomma = true;
|
skipcomma = true;
|
||||||
}
|
}
|
||||||
|
@ -136,9 +141,9 @@ impl ToCss for Gradient {
|
||||||
impl Gradient {
|
impl Gradient {
|
||||||
/// Parses a gradient from the given arguments.
|
/// Parses a gradient from the given arguments.
|
||||||
pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result<Gradient, ()> {
|
pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result<Gradient, ()> {
|
||||||
let parse_linear_gradient = |input: &mut Parser| {
|
let parse_linear_gradient = |input: &mut Parser, mode| {
|
||||||
input.parse_nested_block(|input| {
|
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)));
|
let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i)));
|
||||||
Ok((kind, stops))
|
Ok((kind, stops))
|
||||||
})
|
})
|
||||||
|
@ -151,13 +156,23 @@ impl Gradient {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let mut repeating = false;
|
let mut repeating = false;
|
||||||
|
let mut compat_mode = CompatMode::Modern;
|
||||||
let (gradient_kind, stops) = match_ignore_ascii_case! { &try!(input.expect_function()),
|
let (gradient_kind, stops) = match_ignore_ascii_case! { &try!(input.expect_function()),
|
||||||
"linear-gradient" => {
|
"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-linear-gradient" => {
|
||||||
repeating = true;
|
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" => {
|
"radial-gradient" => {
|
||||||
try!(parse_radial_gradient(input))
|
try!(parse_radial_gradient(input))
|
||||||
|
@ -178,6 +193,7 @@ impl Gradient {
|
||||||
stops: stops,
|
stops: stops,
|
||||||
repeating: repeating,
|
repeating: repeating,
|
||||||
gradient_kind: gradient_kind,
|
gradient_kind: gradient_kind,
|
||||||
|
compat_mode: compat_mode,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,10 +214,20 @@ pub enum GradientKind {
|
||||||
Radial(EndingShape, Position),
|
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 {
|
impl GradientKind {
|
||||||
/// Parses a linear gradient kind from the given arguments.
|
/// Parses a linear gradient kind from the given arguments.
|
||||||
pub fn parse_linear(context: &ParserContext, input: &mut Parser) -> Result<GradientKind, ()> {
|
fn parse_linear(context: &ParserContext, input: &mut Parser, mode: CompatMode) -> Result<GradientKind, ()> {
|
||||||
let angle_or_corner = try!(AngleOrCorner::parse(context, input));
|
let angle_or_corner = try!(AngleOrCorner::parse(context, input, mode));
|
||||||
Ok(GradientKind::Linear(angle_or_corner))
|
Ok(GradientKind::Linear(angle_or_corner))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,13 +368,15 @@ pub enum AngleOrCorner {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for AngleOrCorner {
|
impl AngleOrCorner {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result where W: fmt::Write {
|
||||||
match *self {
|
match *self {
|
||||||
AngleOrCorner::None => Ok(()),
|
AngleOrCorner::None => Ok(()),
|
||||||
AngleOrCorner::Angle(angle) => angle.to_css(dest),
|
AngleOrCorner::Angle(angle) => angle.to_css(dest),
|
||||||
AngleOrCorner::Corner(horizontal, vertical) => {
|
AngleOrCorner::Corner(horizontal, vertical) => {
|
||||||
try!(dest.write_str("to "));
|
if compat_mode == CompatMode::Modern {
|
||||||
|
try!(dest.write_str("to "));
|
||||||
|
}
|
||||||
let mut horizontal_present = false;
|
let mut horizontal_present = false;
|
||||||
if let Some(horizontal) = horizontal {
|
if let Some(horizontal) = horizontal {
|
||||||
try!(horizontal.to_css(dest));
|
try!(horizontal.to_css(dest));
|
||||||
|
@ -366,21 +394,22 @@ impl ToCss for AngleOrCorner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AngleOrCorner {
|
impl AngleOrCorner {
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(context: &ParserContext, input: &mut Parser, mode: CompatMode) -> Result<Self, ()> {
|
||||||
if input.try(|input| input.expect_ident_matching("to")).is_ok() {
|
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) =
|
let (horizontal, vertical) =
|
||||||
if let Ok(value) = input.try(HorizontalDirection::parse) {
|
if let Ok(value) = input.try(HorizontalDirection::parse) {
|
||||||
(Some(value), input.try(VerticalDirection::parse).ok())
|
(Some(value), input.try(VerticalDirection::parse).ok())
|
||||||
} else {
|
} else {
|
||||||
let value = try!(VerticalDirection::parse(input));
|
let value = try!(VerticalDirection::parse(input));
|
||||||
(input.try(HorizontalDirection::parse).ok(), Some(value))
|
(input.try(HorizontalDirection::parse).ok(), Some(value))
|
||||||
};
|
};
|
||||||
try!(input.expect_comma());
|
try!(input.expect_comma());
|
||||||
Ok(AngleOrCorner::Corner(horizontal, vertical))
|
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 {
|
} else {
|
||||||
Ok(AngleOrCorner::None)
|
Ok(AngleOrCorner::None)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue