Implement the unitless length quirk for background-position

This commit is contained in:
Anthony Ramine 2017-04-24 11:24:43 +02:00
parent f68e2fded9
commit 080f74ca63
4 changed files with 68 additions and 19 deletions

View file

@ -194,8 +194,8 @@
sub_properties="background-position-x background-position-y" sub_properties="background-position-x background-position-y"
spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position"> spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position">
use properties::longhands::{background_position_x,background_position_y}; use properties::longhands::{background_position_x,background_position_y};
use values::specified::AllowQuirks;
use values::specified::position::Position; use values::specified::position::Position;
use parser::Parse;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let mut position_x = background_position_x::SpecifiedValue(Vec::new()); let mut position_x = background_position_x::SpecifiedValue(Vec::new());
@ -204,7 +204,7 @@
try!(input.parse_comma_separated(|input| { try!(input.parse_comma_separated(|input| {
loop { loop {
if let Ok(value) = input.try(|input| Position::parse(context, input)) { if let Ok(value) = input.try(|input| Position::parse_quirky(context, input, AllowQuirks::Yes)) {
position_x.0.push(value.horizontal); position_x.0.push(value.horizontal);
position_y.0.push(value.vertical); position_y.0.push(value.vertical);
any = true; any = true;

View file

@ -17,7 +17,7 @@ use std::ops::Mul;
use style_traits::ToCss; use style_traits::ToCss;
use style_traits::values::specified::AllowedLengthType; use style_traits::values::specified::AllowedLengthType;
use stylesheets::CssRuleType; use stylesheets::CssRuleType;
use super::{Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time, ToComputedValue}; use super::{AllowQuirks, Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time, ToComputedValue};
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal}; use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal};
use values::ExtremumLength; use values::ExtremumLength;
use values::computed::{ComputedValueAsSpecified, Context}; use values::computed::{ComputedValueAsSpecified, Context};
@ -1154,7 +1154,10 @@ impl LengthOrPercentage {
LengthOrPercentage::Length(NoCalcLength::zero()) LengthOrPercentage::Length(NoCalcLength::zero())
} }
fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType) fn parse_internal(context: &ParserContext,
input: &mut Parser,
num_context: AllowedLengthType,
allow_quirks: AllowQuirks)
-> Result<LengthOrPercentage, ()> -> Result<LengthOrPercentage, ()>
{ {
match try!(input.next()) { match try!(input.next()) {
@ -1162,12 +1165,9 @@ impl LengthOrPercentage {
NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length), NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length),
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) => Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))), Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
Token::Number(ref value) => { Token::Number(value) if value.value == 0. ||
if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() { (num_context.is_ok(value.value) && allow_quirks.allowed(context.quirks_mode)) =>
return Err(()) Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value))),
}
Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(AbsoluteLength::Px(value.value))))
}
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(|i| { let calc = try!(input.parse_nested_block(|i| {
CalcLengthOrPercentage::parse_length_or_percentage(context, i) CalcLengthOrPercentage::parse_length_or_percentage(context, i)
@ -1181,14 +1181,14 @@ impl LengthOrPercentage {
/// Parse a non-negative length. /// Parse a non-negative length.
#[inline] #[inline]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> { pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> {
Self::parse_internal(context, input, AllowedLengthType::NonNegative) Self::parse_internal(context, input, AllowedLengthType::NonNegative, AllowQuirks::No)
} }
/// Parse a length, treating dimensionless numbers as pixels /// Parse a length, treating dimensionless numbers as pixels
/// ///
/// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value /// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value
pub fn parse_numbers_are_pixels(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> { pub fn parse_numbers_are_pixels(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> {
if let Ok(lop) = input.try(|i| Self::parse_internal(context, i, AllowedLengthType::All)) { if let Ok(lop) = input.try(|i| Self::parse(context, i)) {
return Ok(lop) return Ok(lop)
} }
@ -1204,7 +1204,7 @@ impl LengthOrPercentage {
pub fn parse_numbers_are_pixels_non_negative(context: &ParserContext, pub fn parse_numbers_are_pixels_non_negative(context: &ParserContext,
input: &mut Parser) input: &mut Parser)
-> Result<LengthOrPercentage, ()> { -> Result<LengthOrPercentage, ()> {
if let Ok(lop) = input.try(|i| Self::parse_internal(context, i, AllowedLengthType::NonNegative)) { if let Ok(lop) = input.try(|i| Self::parse_non_negative(context, i)) {
return Ok(lop) return Ok(lop)
} }
@ -1230,7 +1230,18 @@ impl LengthOrPercentage {
impl Parse for LengthOrPercentage { impl Parse for LengthOrPercentage {
#[inline] #[inline]
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Self::parse_internal(context, input, AllowedLengthType::All) Self::parse_quirky(context, input, AllowQuirks::No)
}
}
impl LengthOrPercentage {
/// Parses a length or a percentage, allowing the unitless length quirk.
/// https://quirks.spec.whatwg.org/#the-unitless-length-quirk
#[inline]
pub fn parse_quirky(context: &ParserContext,
input: &mut Parser,
allow_quirks: AllowQuirks) -> Result<Self, ()> {
Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks)
} }
} }

View file

@ -7,6 +7,7 @@
//! TODO(emilio): Enhance docs. //! TODO(emilio): Enhance docs.
use app_units::Au; use app_units::Au;
use context::QuirksMode;
use cssparser::{self, Parser, Token}; use cssparser::{self, Parser, Token};
use euclid::size::Size2D; use euclid::size::Size2D;
use parser::{ParserContext, Parse}; use parser::{ParserContext, Parse};
@ -1326,3 +1327,19 @@ pub type ClipRectOrAuto = Either<ClipRect, Auto>;
/// <color> | auto /// <color> | auto
pub type ColorOrAuto = Either<CSSColor, Auto>; pub type ColorOrAuto = Either<CSSColor, Auto>;
/// Whether quirks are allowed in this context.
#[derive(Clone, Copy, PartialEq)]
pub enum AllowQuirks {
/// Quirks are allowed.
Yes,
/// Quirks are not allowed.
No,
}
impl AllowQuirks {
/// Returns `true` if quirks are allowed in this context.
pub fn allowed(self, quirks_mode: QuirksMode) -> bool {
self == AllowQuirks::Yes && quirks_mode == QuirksMode::Quirks
}
}

View file

@ -19,7 +19,7 @@ use values::computed::position as computed_position;
use values::generics::position::{Position as GenericPosition, PositionValue, PositionWithKeyword}; use values::generics::position::{Position as GenericPosition, PositionValue, PositionWithKeyword};
use values::generics::position::HorizontalPosition as GenericHorizontalPosition; use values::generics::position::HorizontalPosition as GenericHorizontalPosition;
use values::generics::position::VerticalPosition as GenericVerticalPosition; use values::generics::position::VerticalPosition as GenericVerticalPosition;
use values::specified::{LengthOrPercentage, Percentage}; use values::specified::{AllowQuirks, LengthOrPercentage, Percentage};
pub use values::generics::position::Keyword; pub use values::generics::position::Keyword;
@ -132,13 +132,23 @@ impl Position {
impl Parse for Position { impl Parse for Position {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
let first = input.try(|i| PositionComponent::parse(context, i))?; Position::parse_quirky(context, input, AllowQuirks::No)
let second = input.try(|i| PositionComponent::parse(context, i)) }
}
impl Position {
/// Parses, with quirks.
pub fn parse_quirky(context: &ParserContext,
input: &mut Parser,
allow_quirks: AllowQuirks)
-> Result<Self, ()> {
let first = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))?;
let second = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))
.unwrap_or(Either::Second(Keyword::Center)); .unwrap_or(Either::Second(Keyword::Center));
if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) { if let Ok(third) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
// There's a 3rd value. // There's a 3rd value.
if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) { if let Ok(fourth) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
// There's a 4th value. // There's a 4th value.
Position::from_components(Some(second), Some(fourth), Some(first), Some(third)) Position::from_components(Some(second), Some(fourth), Some(first), Some(third))
} else { } else {
@ -173,6 +183,17 @@ impl Parse for Position {
} }
} }
impl PositionComponent {
/// Parses, with quirks.
fn parse_quirky(context: &ParserContext,
input: &mut Parser,
allow_quirks: AllowQuirks) -> Result<Self, ()> {
input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
.map(Either::First)
.or_else(|()| input.try(Keyword::parse).map(Either::Second))
}
}
impl PositionValue<LengthOrPercentage> { impl PositionValue<LengthOrPercentage> {
/// Generic function for the computed value of a position. /// Generic function for the computed value of a position.
fn computed_value(&self, context: &Context) -> ComputedLengthOrPercentage { fn computed_value(&self, context: &Context) -> ComputedLengthOrPercentage {