Auto merge of #19457 - emilio:color-calc, r=SimonSapin

style: support calc() in color functions.

Depends on #19456 and https://github.com/servo/rust-cssparser/pull/207.

Fixes https://bugzilla.mozilla.org/show_bug.cgi?id=984021

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19457)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-12-05 03:37:18 -06:00 committed by GitHub
commit 3cef09ae21
20 changed files with 248 additions and 90 deletions

28
Cargo.lock generated
View file

@ -281,7 +281,7 @@ dependencies = [
"azure 0.23.0 (git+https://github.com/servo/rust-azure)", "azure 0.23.0 (git+https://github.com/servo/rust-azure)",
"canvas_traits 0.0.1", "canvas_traits 0.0.1",
"compositing 0.0.1", "compositing 0.0.1",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -298,7 +298,7 @@ dependencies = [
name = "canvas_traits" name = "canvas_traits"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -561,7 +561,7 @@ dependencies = [
[[package]] [[package]]
name = "cssparser" name = "cssparser"
version = "0.22.0" version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1038,7 +1038,7 @@ name = "geckoservo"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1109,7 +1109,7 @@ dependencies = [
name = "gfx_tests" name = "gfx_tests"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1", "gfx 0.0.1",
"ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1", "style 0.0.1",
@ -1696,7 +1696,7 @@ name = "malloc_size_of"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"hashglobe 0.1.0", "hashglobe 0.1.0",
"mozjs 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2560,7 +2560,7 @@ dependencies = [
"caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"deny_public_fields 0.0.1", "deny_public_fields 0.0.1",
"devtools_traits 0.0.1", "devtools_traits 0.0.1",
"dom_struct 0.0.1", "dom_struct 0.0.1",
@ -2636,7 +2636,7 @@ dependencies = [
"app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"canvas_traits 0.0.1", "canvas_traits 0.0.1",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1", "gfx_traits 0.0.1",
"html5ever 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2717,7 +2717,7 @@ name = "selectors"
version = "0.19.0" version = "0.19.0"
dependencies = [ dependencies = [
"bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1", "malloc_size_of 0.0.1",
@ -3133,7 +3133,7 @@ dependencies = [
"bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fallible 0.0.1", "fallible 0.0.1",
@ -3192,7 +3192,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3214,7 +3214,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1", "malloc_size_of 0.0.1",
"malloc_size_of_derive 0.0.1", "malloc_size_of_derive 0.0.1",
@ -3230,7 +3230,7 @@ name = "stylo_tests"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"geckoservo 0.0.1", "geckoservo 0.0.1",
@ -3811,7 +3811,7 @@ dependencies = [
"checksum core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc9fb3d6cb663e6fd7cf1c63f9b144ee2b1e4a78595a0451dd34bff85b9a3387" "checksum core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc9fb3d6cb663e6fd7cf1c63f9b144ee2b1e4a78595a0451dd34bff85b9a3387"
"checksum core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5dc0a78ab2ac23b6ea7b3fe5fe93b227900dc0956979735b8f68032417976dd4" "checksum core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5dc0a78ab2ac23b6ea7b3fe5fe93b227900dc0956979735b8f68032417976dd4"
"checksum core-text 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcad23756dd1dc4b47bf6a914ace27aadb8fa68889db5837af2308d018d0467c" "checksum core-text 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcad23756dd1dc4b47bf6a914ace27aadb8fa68889db5837af2308d018d0467c"
"checksum cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44313341610282488e1156ad1fedebca51c54766c87a041d0287b10499c04ba1" "checksum cssparser 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83b169a4a5c49826a93ab1778008771b3b05bca95deea76e6c723c667dbc74b8"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df" "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum cubeb-ffi 0.0.2 (git+https://github.com/djg/cubeb-pulse-rs?branch=dev)" = "<none>" "checksum cubeb-ffi 0.0.2 (git+https://github.com/djg/cubeb-pulse-rs?branch=dev)" = "<none>"
"checksum cubeb-pulse 0.0.2 (git+https://github.com/djg/cubeb-pulse-rs?branch=dev)" = "<none>" "checksum cubeb-pulse 0.0.2 (git+https://github.com/djg/cubeb-pulse-rs?branch=dev)" = "<none>"

View file

@ -13,7 +13,7 @@ path = "lib.rs"
azure = {git = "https://github.com/servo/rust-azure"} azure = {git = "https://github.com/servo/rust-azure"}
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
compositing = {path = "../compositing"} compositing = {path = "../compositing"}
cssparser = "0.22.0" cssparser = "0.23.0"
euclid = "0.15" euclid = "0.15"
fnv = "1.0" fnv = "1.0"
gleam = "0.4" gleam = "0.4"

View file

@ -10,7 +10,7 @@ name = "canvas_traits"
path = "lib.rs" path = "lib.rs"
[dependencies] [dependencies]
cssparser = "0.22.0" cssparser = "0.23.0"
euclid = "0.15" euclid = "0.15"
ipc-channel = "0.9" ipc-channel = "0.9"
lazy_static = "0.2" lazy_static = "0.2"

View file

@ -13,7 +13,7 @@ servo = ["mozjs", "string_cache", "url", "webrender_api", "xml5ever"]
[dependencies] [dependencies]
app_units = "0.5.5" app_units = "0.5.5"
cssparser = "0.22.0" cssparser = "0.23.0"
euclid = "0.15" euclid = "0.15"
hashglobe = { path = "../hashglobe" } hashglobe = { path = "../hashglobe" }
mozjs = { version = "0.1.8", features = ["promises"], optional = true } mozjs = { version = "0.1.8", features = ["promises"], optional = true }

View file

@ -39,7 +39,7 @@ byteorder = "1.0"
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
caseless = "0.1.0" caseless = "0.1.0"
cookie = "0.10" cookie = "0.10"
cssparser = "0.22.0" cssparser = "0.23.0"
deny_public_fields = {path = "../deny_public_fields"} deny_public_fields = {path = "../deny_public_fields"}
devtools_traits = {path = "../devtools_traits"} devtools_traits = {path = "../devtools_traits"}
dom_struct = {path = "../dom_struct"} dom_struct = {path = "../dom_struct"}

View file

@ -13,7 +13,7 @@ path = "lib.rs"
app_units = "0.5" app_units = "0.5"
atomic_refcell = "0.1" atomic_refcell = "0.1"
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
cssparser = "0.22.0" cssparser = "0.23.0"
euclid = "0.15" euclid = "0.15"
gfx_traits = {path = "../gfx_traits"} gfx_traits = {path = "../gfx_traits"}
html5ever = "0.21.0" html5ever = "0.21.0"

View file

@ -25,7 +25,7 @@ bench = []
[dependencies] [dependencies]
bitflags = "1.0" bitflags = "1.0"
matches = "0.1" matches = "0.1"
cssparser = "0.22.0" cssparser = "0.23.0"
log = "0.3" log = "0.3"
fnv = "1.0" fnv = "1.0"
malloc_size_of = { path = "../malloc_size_of" } malloc_size_of = { path = "../malloc_size_of" }

View file

@ -35,7 +35,7 @@ atomic_refcell = "0.1"
bitflags = "1.0" bitflags = "1.0"
byteorder = "1.0" byteorder = "1.0"
cfg-if = "0.1.0" cfg-if = "0.1.0"
cssparser = "0.22.0" cssparser = "0.23.0"
encoding_rs = {version = "0.7", optional = true} encoding_rs = {version = "0.7", optional = true}
euclid = "0.15" euclid = "0.15"
fallible = { path = "../fallible" } fallible = { path = "../fallible" }

View file

@ -76,7 +76,6 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
Token::PrefixMatch => write!(f, "prefix match (^=)"), Token::PrefixMatch => write!(f, "prefix match (^=)"),
Token::SuffixMatch => write!(f, "suffix match ($=)"), Token::SuffixMatch => write!(f, "suffix match ($=)"),
Token::SubstringMatch => write!(f, "substring match (*=)"), Token::SubstringMatch => write!(f, "substring match (*=)"),
Token::Column => write!(f, "column (||)"),
Token::CDO => write!(f, "CDO (<!--)"), Token::CDO => write!(f, "CDO (<!--)"),
Token::CDC => write!(f, "CDC (-->)"), Token::CDC => write!(f, "CDC (-->)"),
Token::Function(ref name) => write!(f, "function {}", name), Token::Function(ref name) => write!(f, "function {}", name),

View file

@ -81,6 +81,13 @@ impl Angle {
self.value.radians() self.value.radians()
} }
/// Returns the amount of degrees this angle represents.
#[inline]
pub fn degrees(self) -> f32 {
use std::f32::consts::PI;
self.radians() * 360. / (2. * PI)
}
/// Returns `0deg`. /// Returns `0deg`.
pub fn zero() -> Self { pub fn zero() -> Self {
Self::from_degrees(0.0, false) Self::from_degrees(0.0, false)

View file

@ -6,7 +6,7 @@
//! //!
//! [calc]: https://drafts.csswg.org/css-values/#calc-notation //! [calc]: https://drafts.csswg.org/css-values/#calc-notation
use cssparser::{Parser, Token}; use cssparser::{Parser, Token, NumberOrPercentage, AngleOrNumber};
use parser::ParserContext; use parser::ParserContext;
#[allow(unused_imports)] use std::ascii::AsciiExt; #[allow(unused_imports)] use std::ascii::AsciiExt;
use std::fmt; use std::fmt;
@ -202,9 +202,8 @@ impl CalcNode {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
expected_unit: CalcUnit) expected_unit: CalcUnit,
-> Result<Self, ParseError<'i>> ) -> Result<Self, ParseError<'i>> {
{
let mut root = Self::parse_product(context, input, expected_unit)?; let mut root = Self::parse_product(context, input, expected_unit)?;
loop { loop {
@ -613,4 +612,39 @@ impl CalcNode {
.to_time() .to_time()
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} }
/// Convenience parsing function for `<number>` or `<percentage>`.
pub fn parse_number_or_percentage<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<NumberOrPercentage, ParseError<'i>> {
let node = Self::parse(context, input, CalcUnit::Percentage)?;
if let Ok(value) = node.to_number() {
return Ok(NumberOrPercentage::Number { value })
}
match node.to_percentage() {
Ok(unit_value) => Ok(NumberOrPercentage::Percentage { unit_value }),
Err(()) => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
}
/// Convenience parsing function for `<number>` or `<angle>`.
pub fn parse_angle_or_number<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<AngleOrNumber, ParseError<'i>> {
let node = Self::parse(context, input, CalcUnit::Angle)?;
if let Ok(angle) = node.to_angle() {
let degrees = angle.degrees();
return Ok(AngleOrNumber::Angle { degrees })
}
match node.to_number() {
Ok(value) => Ok(AngleOrNumber::Number { value }),
Err(()) => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
}
} }

View file

@ -4,7 +4,8 @@
//! Specified color values. //! Specified color values.
use cssparser::{Color as CSSParserColor, Parser, RGBA, Token, BasicParseError, BasicParseErrorKind}; use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, RGBA, Token};
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use gecko_bindings::structs::nscolor; use gecko_bindings::structs::nscolor;
use itoa; use itoa;
@ -16,6 +17,7 @@ use std::io::Write;
use style_traits::{ToCss, ParseError, StyleParseErrorKind, ValueParseErrorKind}; use style_traits::{ToCss, ParseError, StyleParseErrorKind, ValueParseErrorKind};
use super::AllowQuirks; use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue}; use values::computed::{Color as ComputedColor, Context, ToComputedValue};
use values::specified::calc::CalcNode;
/// Specified color value /// Specified color value
#[derive(Clone, Debug, MallocSizeOf, PartialEq)] #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
@ -43,7 +45,6 @@ pub enum Color {
InheritFromBodyQuirk, InheritFromBodyQuirk,
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
mod gecko { mod gecko {
define_css_keyword_enum! { SpecialColorKeyword: define_css_keyword_enum! { SpecialColorKeyword:
@ -61,9 +62,127 @@ impl From<RGBA> for Color {
} }
} }
struct ColorComponentParser<'a, 'b: 'a>(&'a ParserContext<'b>);
impl<'a, 'b: 'a, 'i: 'a> ::cssparser::ColorComponentParser<'i> for ColorComponentParser<'a, 'b> {
type Error = StyleParseErrorKind<'i>;
fn parse_angle_or_number<'t>(
&self,
input: &mut Parser<'i, 't>,
) -> Result<AngleOrNumber, ParseError<'i>> {
#[allow(unused_imports)] use std::ascii::AsciiExt;
use values::specified::Angle;
let location = input.current_source_location();
let token = input.next()?.clone();
match token {
Token::Dimension { value, ref unit, .. } => {
let angle = Angle::parse_dimension(
value,
unit,
/* from_calc = */ false,
);
let degrees = match angle {
Ok(angle) => angle.degrees(),
Err(()) => return Err(location.new_unexpected_token_error(token.clone())),
};
Ok(AngleOrNumber::Angle { degrees })
}
Token::Number { value, .. } => {
Ok(AngleOrNumber::Number { value })
}
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
input.parse_nested_block(|i| CalcNode::parse_angle_or_number(self.0, i))
}
t => return Err(location.new_unexpected_token_error(t)),
}
}
fn parse_percentage<'t>(
&self,
input: &mut Parser<'i, 't>,
) -> Result<f32, ParseError<'i>> {
use values::specified::Percentage;
Ok(Percentage::parse(self.0, input)?.get())
}
fn parse_number<'t>(
&self,
input: &mut Parser<'i, 't>,
) -> Result<f32, ParseError<'i>> {
use values::specified::Number;
Ok(Number::parse(self.0, input)?.get())
}
fn parse_number_or_percentage<'t>(
&self,
input: &mut Parser<'i, 't>,
) -> Result<NumberOrPercentage, ParseError<'i>> {
#[allow(unused_imports)] use std::ascii::AsciiExt;
let location = input.current_source_location();
match input.next()?.clone() {
Token::Number { value, .. } => Ok(NumberOrPercentage::Number { value }),
Token::Percentage { unit_value, .. } => {
Ok(NumberOrPercentage::Percentage { unit_value })
},
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
input.parse_nested_block(|i| CalcNode::parse_number_or_percentage(self.0, i))
}
t => return Err(location.new_unexpected_token_error(t))
}
}
}
impl Parse for Color { impl Parse for Color {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Color::parse_color(input) #[allow(unused_imports)] use std::ascii::AsciiExt;
// Currently we only store authored value for color keywords,
// because all browsers serialize those values as keywords for
// specified value.
let start = input.state();
let authored = input.expect_ident_cloned().ok();
input.reset(&start);
let compontent_parser = ColorComponentParser(&*context);
match input.try(|i| CSSParserColor::parse_with(&compontent_parser, i)) {
Ok(value) => {
Ok(match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
CSSParserColor::RGBA(rgba) => Color::Numeric {
parsed: rgba,
authored: authored.map(|s| s.to_ascii_lowercase().into_boxed_str()),
},
})
}
Err(e) => {
#[cfg(feature = "gecko")]
{
if let Ok(system) = input.try(SystemColor::parse) {
return Ok(Color::System(system));
}
if let Ok(c) = gecko::SpecialColorKeyword::parse(input) {
return Ok(Color::Special(c));
}
}
match e.kind {
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(t)) => {
Err(e.location.new_custom_error(
StyleParseErrorKind::ValueError(ValueParseErrorKind::InvalidColor(t))
))
}
_ => Err(e)
}
}
}
} }
} }
@ -86,9 +205,9 @@ impl ToCss for Color {
/// A wrapper of cssparser::Color::parse_hash. /// A wrapper of cssparser::Color::parse_hash.
/// ///
/// That function should never return CurrentColor, so it makes no sense /// That function should never return CurrentColor, so it makes no sense to
/// to handle a cssparser::Color here. This should really be done in /// handle a cssparser::Color here. This should really be done in cssparser
/// cssparser directly rather than here. /// directly rather than here.
fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> { fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
CSSParserColor::parse_hash(value).map(|color| { CSSParserColor::parse_hash(value).map(|color| {
match color { match color {
@ -125,16 +244,17 @@ impl Color {
/// Parse a color, with quirks. /// Parse a color, with quirks.
/// ///
/// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk> /// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk>
pub fn parse_quirky<'i, 't>(context: &ParserContext, pub fn parse_quirky<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks,
-> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
input.try(|i| Self::parse(context, i)).or_else(|e| { input.try(|i| Self::parse(context, i)).or_else(|e| {
if !allow_quirks.allowed(context.quirks_mode) { if !allow_quirks.allowed(context.quirks_mode) {
return Err(e); return Err(e);
} }
Color::parse_quirky_color(input) Color::parse_quirky_color(input)
.map(|rgba| Color::rgba(rgba)) .map(Color::rgba)
.map_err(|_| e) .map_err(|_| e)
}) })
} }
@ -205,52 +325,6 @@ impl Color {
_ => true, _ => true,
} }
} }
/// Parse a <color> value.
pub fn parse_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
// Currently we only store authored value for color keywords,
// because all browsers serialize those values as keywords for
// specified value.
let start = input.state();
let authored = match input.next() {
Ok(&Token::Ident(ref s)) => Some(s.clone()),
_ => None,
};
input.reset(&start);
match input.try(CSSParserColor::parse) {
Ok(value) =>
Ok(match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
CSSParserColor::RGBA(rgba) => {
Color::Numeric {
parsed: rgba,
authored: authored.map(|s| s.to_lowercase().into_boxed_str()),
}
}
}),
Err(e) => {
#[cfg(feature = "gecko")]
{
if let Ok(system) = input.try(SystemColor::parse) {
return Ok(Color::System(system));
}
if let Ok(c) = gecko::SpecialColorKeyword::parse(input) {
return Ok(Color::Special(c));
}
}
match e {
BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location } => {
Err(location.new_custom_error(
StyleParseErrorKind::ValueError(ValueParseErrorKind::InvalidColor(t))
))
}
e => Err(e.into())
}
}
}
}
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]

View file

@ -15,7 +15,7 @@ gecko = []
[dependencies] [dependencies]
app_units = "0.5" app_units = "0.5"
cssparser = "0.22.0" cssparser = "0.23.0"
bitflags = "1.0" bitflags = "1.0"
euclid = "0.15" euclid = "0.15"
malloc_size_of = { path = "../malloc_size_of" } malloc_size_of = { path = "../malloc_size_of" }

View file

@ -15,7 +15,7 @@ gecko_debug = ["style/gecko_debug"]
[dependencies] [dependencies]
atomic_refcell = "0.1" atomic_refcell = "0.1"
cssparser = "0.22.0" cssparser = "0.23.0"
env_logger = {version = "0.4", default-features = false} # disable `regex` to reduce code size env_logger = {version = "0.4", default-features = false} # disable `regex` to reduce code size
libc = "0.2" libc = "0.2"
log = {version = "0.3.5", features = ["release_max_level_info"]} log = {version = "0.3.5", features = ["release_max_level_info"]}

View file

@ -4563,8 +4563,17 @@ fn parse_color(
) -> Result<specified::Color, ()> { ) -> Result<specified::Color, ()> {
let mut input = ParserInput::new(value); let mut input = ParserInput::new(value);
let mut parser = Parser::new(&mut input); let mut parser = Parser::new(&mut input);
let url_data = unsafe { dummy_url_data() };
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
);
let start_position = parser.position(); let start_position = parser.position();
parser.parse_entirely(specified::Color::parse_color).map_err(|err| { parser.parse_entirely(|i| specified::Color::parse(&context, i)).map_err(|err| {
if let Some(error_reporter) = error_reporter { if let Some(error_reporter) = error_reporter {
match err.kind { match err.kind {
ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => { ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => {

View file

@ -10,7 +10,7 @@ path = "lib.rs"
doctest = false doctest = false
[dependencies] [dependencies]
cssparser = "0.22.0" cssparser = "0.23.0"
gfx = {path = "../../../components/gfx"} gfx = {path = "../../../components/gfx"}
ipc-channel = "0.9" ipc-channel = "0.9"
style = {path = "../../../components/style"} style = {path = "../../../components/style"}

View file

@ -12,7 +12,7 @@ doctest = false
[dependencies] [dependencies]
byteorder = "1.0" byteorder = "1.0"
app_units = "0.5" app_units = "0.5"
cssparser = "0.22.0" cssparser = "0.23.0"
euclid = "0.15" euclid = "0.15"
html5ever = "0.21" html5ever = "0.21"
parking_lot = "0.4" parking_lot = "0.4"

View file

@ -13,7 +13,7 @@ doctest = false
[dependencies] [dependencies]
atomic_refcell = "0.1" atomic_refcell = "0.1"
cssparser = "0.22.0" cssparser = "0.23.0"
env_logger = "0.4" env_logger = "0.4"
euclid = "0.15" euclid = "0.15"
geckoservo = {path = "../../../ports/geckolib"} geckoservo = {path = "../../../ports/geckolib"}

View file

@ -303223,6 +303223,12 @@
{} {}
] ]
], ],
"css/css-values/calc-in-color-001.html": [
[
"/css/css-values/calc-in-color-001.html",
{}
]
],
"css/css-values/calc-serialization.html": [ "css/css-values/calc-serialization.html": [
[ [
"/css/css-values/calc-serialization.html", "/css/css-values/calc-serialization.html",
@ -503720,6 +503726,10 @@
"be08a1510714e8b4fbc4d35582db5708924d06b2", "be08a1510714e8b4fbc4d35582db5708924d06b2",
"reftest" "reftest"
], ],
"css/css-values/calc-in-color-001.html": [
"32a0face898f08b854ac392c75368282d718be32",
"testharness"
],
"css/css-values/calc-in-media-queries-001.html": [ "css/css-values/calc-in-media-queries-001.html": [
"f8fdd8373eaca7a03d6a089b4faf71825c8bfaf2", "f8fdd8373eaca7a03d6a089b4faf71825c8bfaf2",
"reftest" "reftest"

View file

@ -0,0 +1,25 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: calc() function in &lt;color&gt;</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="help" href="https://drafts.csswg.org/css-values/#funcdef-calc">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="testNode"></div>
<script>
const div = document.querySelector("#testNode");
const TESTS = {
// specified -> expected
"rgb(calc(0), calc(255 + 0), calc(140 - 139 - 1))": "rgb(0, 255, 0)",
"rgba(calc(0%) calc(100%) calc(0%) / calc(10% * 10))": "rgb(0, 255, 0)",
"hsl(calc(5deg * (360 / 5)), calc(10% * 10), calc(10% * 10))": "rgb(255, 255, 255)"
}
test(function() {
for (let test in TESTS) {
div.style.backgroundColor = "";
div.style.backgroundColor = test;
assert_equals(getComputedStyle(div).backgroundColor, TESTS[test], test);
}
}, "calc() in color functions");
</script>