style: Distinguish between specified and computed URLs.

This is needed to serialize computed URLs correctly from getComputedStyle.

Bug: 1461288
Reviewed-by: xidorn
MozReview-Commit-ID: 9wakhqNrszb
This commit is contained in:
Emilio Cobos Álvarez 2018-05-14 12:29:40 +02:00
parent a6328ba3ce
commit 1314f47da5
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
11 changed files with 375 additions and 295 deletions

View file

@ -14,6 +14,7 @@ use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::animated::color::RGBA;
use values::computed::{Angle, Number};
use values::computed::length::Length;
use values::computed::url::ComputedUrl;
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter;
@ -42,11 +43,11 @@ pub struct FilterList(pub Vec<Filter>);
/// An animated value for a single `filter`.
#[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow>;
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
/// An animated value for a single `filter`.
#[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Number, Length, Impossible>;
pub type Filter = GenericFilter<Angle, Number, Length, Impossible, ComputedUrl>;
/// An animated value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, Length>;

View file

@ -15,9 +15,7 @@ use values::computed::Angle as ComputedAngle;
use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use values::computed::MaxLength as ComputedMaxLength;
use values::computed::MozLength as ComputedMozLength;
#[cfg(feature = "servo")]
use values::computed::url::ComputedUrl;
use values::specified::url::SpecifiedUrl;
pub mod color;
pub mod effects;
@ -260,8 +258,6 @@ macro_rules! trivial_to_animated_value {
trivial_to_animated_value!(Au);
trivial_to_animated_value!(ComputedAngle);
trivial_to_animated_value!(SpecifiedUrl);
#[cfg(feature = "servo")]
trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool);
trivial_to_animated_value!(f32);

View file

@ -4,22 +4,10 @@
//! Computed values for counter properties
#[cfg(feature = "servo")]
use computed_values::list_style_type::T as ListStyleType;
use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind;
use style_traits::{ParseError, StyleParseErrorKind};
use values::CustomIdent;
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
use values::computed::url::ComputedImageUrl;
use values::generics::counters as generics;
use values::generics::counters::CounterIncrement as GenericCounterIncrement;
use values::generics::counters::CounterReset as GenericCounterReset;
#[cfg(feature = "gecko")]
use values::specified::Attr;
#[cfg(feature = "gecko")]
use values::specified::url::SpecifiedImageUrl;
pub use values::specified::{Content, ContentItem};
/// A computed value for the `counter-increment` property.
pub type CounterIncrement = GenericCounterIncrement<i32>;
@ -27,134 +15,9 @@ pub type CounterIncrement = GenericCounterIncrement<i32>;
/// A computed value for the `counter-increment` property.
pub type CounterReset = GenericCounterReset<i32>;
impl Content {
/// Set `content` property to `normal`.
#[inline]
pub fn normal() -> Self {
Content::Normal
}
/// A computed value for the `content` property.
pub type Content = generics::Content<ComputedImageUrl>;
#[cfg(feature = "servo")]
fn parse_counter_style(input: &mut Parser) -> ListStyleType {
input
.try(|input| {
input.expect_comma()?;
ListStyleType::parse(input)
})
.unwrap_or(ListStyleType::Decimal)
}
/// A computed content item.
pub type ContentItem = generics::ContentItem<ComputedImageUrl>;
#[cfg(feature = "gecko")]
fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyleOrNone {
input
.try(|input| {
input.expect_comma()?;
CounterStyleOrNone::parse(context, input)
})
.unwrap_or(CounterStyleOrNone::decimal())
}
}
impl Parse for Content {
// normal | none | [ <string> | <counter> | open-quote | close-quote | no-open-quote |
// no-close-quote ]+
// TODO: <uri>, attr(<identifier>)
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input
.try(|input| input.expect_ident_matching("normal"))
.is_ok()
{
return Ok(Content::Normal);
}
if input
.try(|input| input.expect_ident_matching("none"))
.is_ok()
{
return Ok(Content::None);
}
#[cfg(feature = "gecko")]
{
if input
.try(|input| input.expect_ident_matching("-moz-alt-content"))
.is_ok()
{
return Ok(Content::MozAltContent);
}
}
let mut content = vec![];
loop {
#[cfg(feature = "gecko")]
{
if let Ok(url) = input.try(|i| SpecifiedImageUrl::parse(_context, i)) {
content.push(ContentItem::Url(url));
continue;
}
}
// FIXME: remove clone() when lifetimes are non-lexical
match input.next().map(|t| t.clone()) {
Ok(Token::QuotedString(ref value)) => {
content.push(ContentItem::String(
value.as_ref().to_owned().into_boxed_str(),
));
},
Ok(Token::Function(ref name)) => {
let result = match_ignore_ascii_case! { &name,
"counter" => Some(input.parse_nested_block(|input| {
let location = input.current_source_location();
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
#[cfg(feature = "servo")]
let style = Content::parse_counter_style(input);
#[cfg(feature = "gecko")]
let style = Content::parse_counter_style(_context, input);
Ok(ContentItem::Counter(name, style))
})),
"counters" => Some(input.parse_nested_block(|input| {
let location = input.current_source_location();
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
input.expect_comma()?;
let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str();
#[cfg(feature = "servo")]
let style = Content::parse_counter_style(input);
#[cfg(feature = "gecko")]
let style = Content::parse_counter_style(_context, input);
Ok(ContentItem::Counters(name, separator, style))
})),
#[cfg(feature = "gecko")]
"attr" => Some(input.parse_nested_block(|input| {
Ok(ContentItem::Attr(Attr::parse_function(_context, input)?))
})),
_ => None
};
match result {
Some(result) => content.push(result?),
None => {
return Err(input.new_custom_error(
StyleParseErrorKind::UnexpectedFunction(name.clone()),
))
},
}
},
Ok(Token::Ident(ref ident)) => {
content.push(match_ignore_ascii_case! { &ident,
"open-quote" => ContentItem::OpenQuote,
"close-quote" => ContentItem::CloseQuote,
"no-open-quote" => ContentItem::NoOpenQuote,
"no-close-quote" => ContentItem::NoCloseQuote,
_ => return Err(input.new_custom_error(
SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
});
},
Err(_) => break,
Ok(t) => return Err(input.new_unexpected_token_error(t)),
}
}
if content.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(Content::Items(content.into_boxed_slice()))
}
}

View file

@ -9,6 +9,7 @@ use values::Impossible;
use values::computed::{Angle, NonNegativeNumber};
use values::computed::color::RGBAColor;
use values::computed::length::{Length, NonNegativeLength};
use values::computed::url::ComputedUrl;
use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow;
@ -18,11 +19,11 @@ pub type BoxShadow = GenericBoxShadow<Option<RGBAColor>, Length, NonNegativeLeng
/// A computed value for a single `filter`.
#[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow>;
pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow, ComputedUrl>;
/// A computed value for a single `filter`.
#[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible>;
pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible, ComputedUrl>;
/// A computed value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Option<RGBAColor>, Length, NonNegativeLength>;

View file

@ -4,8 +4,14 @@
//! Generic types for counters-related CSS values.
#[cfg(feature = "servo")]
use computed_values::list_style_type::T as ListStyleType;
use std::ops::Deref;
use values::CustomIdent;
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
#[cfg(feature = "gecko")]
use values::specified::Attr;
/// A name / value pair for counters.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
@ -74,3 +80,78 @@ impl<I> Default for Counters<I> {
Counters(vec![].into_boxed_slice())
}
}
#[cfg(feature = "servo")]
type CounterStyleType = ListStyleType;
#[cfg(feature = "gecko")]
type CounterStyleType = CounterStyleOrNone;
#[cfg(feature = "servo")]
#[inline]
fn is_decimal(counter_type: &CounterStyleType) -> bool {
*counter_type == ListStyleType::Decimal
}
#[cfg(feature = "gecko")]
#[inline]
fn is_decimal(counter_type: &CounterStyleType) -> bool {
*counter_type == CounterStyleOrNone::decimal()
}
/// The specified value for the `content` property.
///
/// https://drafts.csswg.org/css-content/#propdef-content
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum Content<ImageUrl> {
/// `normal` reserved keyword.
Normal,
/// `none` reserved keyword.
None,
/// `-moz-alt-content`.
#[cfg(feature = "gecko")]
MozAltContent,
/// Content items.
Items(#[css(iterable)] Box<[ContentItem<ImageUrl>]>),
}
impl<ImageUrl> Content<ImageUrl> {
/// Set `content` property to `normal`.
#[inline]
pub fn normal() -> Self {
Content::Normal
}
}
/// Items for the `content` property.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum ContentItem<ImageUrl> {
/// Literal string content.
String(Box<str>),
/// `counter(name, style)`.
#[css(comma, function)]
Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType),
/// `counters(name, separator, style)`.
#[css(comma, function)]
Counters(
CustomIdent,
Box<str>,
#[css(skip_if = "is_decimal")] CounterStyleType,
),
/// `open-quote`.
OpenQuote,
/// `close-quote`.
CloseQuote,
/// `no-open-quote`.
NoOpenQuote,
/// `no-close-quote`.
NoCloseQuote,
/// `attr([namespace? `|`]? ident)`
#[cfg(feature = "gecko")]
Attr(Attr),
/// `url(url)`
Url(ImageUrl),
}

View file

@ -4,9 +4,6 @@
//! Generic types for CSS values related to effects.
#[cfg(feature = "gecko")]
use values::specified::url::SpecifiedUrl;
/// A generic value for a single `box-shadow`.
#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedZero, ToCss)]
@ -23,9 +20,10 @@ pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// A generic value for a single `filter`.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[animation(no_bound(Url))]
#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum Filter<Angle, Factor, Length, DropShadow> {
pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
/// `blur(<length>)`
#[css(function)]
Blur(Length),
@ -58,8 +56,7 @@ pub enum Filter<Angle, Factor, Length, DropShadow> {
DropShadow(DropShadow),
/// `<url>`
#[animation(error)]
#[cfg(feature = "gecko")]
Url(SpecifiedUrl),
Url(Url),
}
/// A generic value for the `drop-shadow()` filter and the `text-shadow` property.

View file

@ -8,18 +8,19 @@
use computed_values::list_style_type::T as ListStyleType;
use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind;
use style_traits::{ParseError, StyleParseErrorKind};
use values::CustomIdent;
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
use values::generics::counters as generics;
use values::generics::counters::CounterIncrement as GenericCounterIncrement;
use values::generics::counters::CounterPair;
use values::generics::counters::CounterReset as GenericCounterReset;
use values::specified::Integer;
use values::specified::url::SpecifiedImageUrl;
#[cfg(feature = "gecko")]
use values::specified::Attr;
use values::specified::Integer;
#[cfg(feature = "gecko")]
use values::specified::url::SpecifiedImageUrl;
/// A specified value for the `counter-increment` property.
pub type CounterIncrement = GenericCounterIncrement<Integer>;
@ -79,69 +80,129 @@ fn parse_counters<'i, 't>(
}
}
#[cfg(feature = "servo")]
type CounterStyleType = ListStyleType;
#[cfg(feature = "gecko")]
type CounterStyleType = CounterStyleOrNone;
#[cfg(feature = "servo")]
#[inline]
fn is_decimal(counter_type: &CounterStyleType) -> bool {
*counter_type == ListStyleType::Decimal
}
#[cfg(feature = "gecko")]
#[inline]
fn is_decimal(counter_type: &CounterStyleType) -> bool {
*counter_type == CounterStyleOrNone::decimal()
}
/// The specified value for the `content` property.
///
/// https://drafts.csswg.org/css-content/#propdef-content
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum Content {
/// `normal` reserved keyword.
Normal,
/// `none` reserved keyword.
None,
/// `-moz-alt-content`.
pub type Content = generics::Content<SpecifiedImageUrl>;
/// The specified value for a content item in the `content` property.
pub type ContentItem = generics::ContentItem<SpecifiedImageUrl>;
impl Content {
#[cfg(feature = "servo")]
fn parse_counter_style(_: &ParserContext, input: &mut Parser) -> ListStyleType {
input
.try(|input| {
input.expect_comma()?;
ListStyleType::parse(input)
})
.unwrap_or(ListStyleType::Decimal)
}
#[cfg(feature = "gecko")]
MozAltContent,
/// Content items.
Items(#[css(iterable)] Box<[ContentItem]>),
fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyleOrNone {
input
.try(|input| {
input.expect_comma()?;
CounterStyleOrNone::parse(context, input)
})
.unwrap_or(CounterStyleOrNone::decimal())
}
}
/// Items for the `content` property.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum ContentItem {
/// Literal string content.
String(Box<str>),
/// `counter(name, style)`.
#[css(comma, function)]
Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType),
/// `counters(name, separator, style)`.
#[css(comma, function)]
Counters(
CustomIdent,
Box<str>,
#[css(skip_if = "is_decimal")] CounterStyleType,
),
/// `open-quote`.
OpenQuote,
/// `close-quote`.
CloseQuote,
/// `no-open-quote`.
NoOpenQuote,
/// `no-close-quote`.
NoCloseQuote,
/// `attr([namespace? `|`]? ident)`
#[cfg(feature = "gecko")]
Attr(Attr),
/// `url(url)`
#[cfg(feature = "gecko")]
Url(SpecifiedImageUrl),
impl Parse for Content {
// normal | none | [ <string> | <counter> | open-quote | close-quote | no-open-quote |
// no-close-quote ]+
// TODO: <uri>, attr(<identifier>)
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input
.try(|input| input.expect_ident_matching("normal"))
.is_ok()
{
return Ok(generics::Content::Normal);
}
if input
.try(|input| input.expect_ident_matching("none"))
.is_ok()
{
return Ok(generics::Content::None);
}
#[cfg(feature = "gecko")]
{
if input
.try(|input| input.expect_ident_matching("-moz-alt-content"))
.is_ok()
{
return Ok(generics::Content::MozAltContent);
}
}
let mut content = vec![];
loop {
#[cfg(feature = "gecko")]
{
if let Ok(url) = input.try(|i| SpecifiedImageUrl::parse(context, i)) {
content.push(generics::ContentItem::Url(url));
continue;
}
}
// FIXME: remove clone() when lifetimes are non-lexical
match input.next().map(|t| t.clone()) {
Ok(Token::QuotedString(ref value)) => {
content.push(generics::ContentItem::String(
value.as_ref().to_owned().into_boxed_str(),
));
},
Ok(Token::Function(ref name)) => {
let result = match_ignore_ascii_case! { &name,
"counter" => Some(input.parse_nested_block(|input| {
let location = input.current_source_location();
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
let style = Content::parse_counter_style(context, input);
Ok(generics::ContentItem::Counter(name, style))
})),
"counters" => Some(input.parse_nested_block(|input| {
let location = input.current_source_location();
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
input.expect_comma()?;
let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str();
let style = Content::parse_counter_style(context, input);
Ok(generics::ContentItem::Counters(name, separator, style))
})),
#[cfg(feature = "gecko")]
"attr" => Some(input.parse_nested_block(|input| {
Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?))
})),
_ => None
};
match result {
Some(result) => content.push(result?),
None => {
return Err(input.new_custom_error(
StyleParseErrorKind::UnexpectedFunction(name.clone()),
))
},
}
},
Ok(Token::Ident(ref ident)) => {
content.push(match_ignore_ascii_case! { &ident,
"open-quote" => generics::ContentItem::OpenQuote,
"close-quote" => generics::ContentItem::CloseQuote,
"no-open-quote" => generics::ContentItem::NoOpenQuote,
"no-close-quote" => generics::ContentItem::NoCloseQuote,
_ => return Err(input.new_custom_error(
SelectorParseErrorKind::UnexpectedIdent(ident.clone())
))
});
},
Err(_) => break,
Ok(t) => return Err(input.new_unexpected_token_error(t)),
}
}
if content.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(generics::Content::Items(content.into_boxed_slice()))
}
}

View file

@ -19,7 +19,6 @@ use values::generics::effects::SimpleShadow as GenericSimpleShadow;
use values::specified::{Angle, NumberOrPercentage};
use values::specified::color::RGBAColor;
use values::specified::length::{Length, NonNegativeLength};
#[cfg(feature = "gecko")]
use values::specified::url::SpecifiedUrl;
/// A specified value for a single shadow of the `box-shadow` property.
@ -28,11 +27,11 @@ pub type BoxShadow =
/// A specified value for a single `filter`.
#[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow>;
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow, SpecifiedUrl>;
/// A specified value for a single `filter`.
#[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible>;
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible, SpecifiedUrl>;
/// A value for the `<factor>` parts in `Filter`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]