style: Let aspect-ratio (css-sizing-4) support 'auto | <ratio>'.

In order to test its parsing and serialization, we expose it but protect
it behind a pref.

Besides, I would like to drop layout.css.aspect-ratio-number.enabled in
the next patch because the spec has been updated. It seems we don't have
to keep this pref and we should always use Number.

Differential Revision: https://phabricator.services.mozilla.com/D74955
This commit is contained in:
Boris Chiou 2020-05-21 06:45:10 +00:00 committed by Emilio Cobos Álvarez
parent bd23e05c47
commit fc9321bb23
8 changed files with 185 additions and 18 deletions

View file

@ -272,3 +272,26 @@ where
<Self as num_traits::Zero>::is_zero(self) <Self as num_traits::Zero>::is_zero(self)
} }
} }
/// A trait pretty much similar to num_traits::One, but without the need of
/// implementing `Mul`.
pub trait One {
/// Reutrns the one value.
fn one() -> Self;
/// Returns whether this value is one.
fn is_one(&self) -> bool;
}
impl<T> One for T
where
T: num_traits::One + PartialEq,
{
fn one() -> Self {
<Self as num_traits::One>::one()
}
fn is_one(&self) -> bool {
*self == One::one()
}
}

View file

@ -328,6 +328,7 @@ class Longhand(object):
"AlignItems", "AlignItems",
"AlignSelf", "AlignSelf",
"Appearance", "Appearance",
"AspectRatio",
"BreakBetween", "BreakBetween",
"BreakWithin", "BreakWithin",
"BackgroundRepeat", "BackgroundRepeat",
@ -364,7 +365,6 @@ class Longhand(object):
"MozScriptSizeMultiplier", "MozScriptSizeMultiplier",
"TextDecorationSkipInk", "TextDecorationSkipInk",
"NonNegativeNumber", "NonNegativeNumber",
"Number",
"OffsetRotate", "OffsetRotate",
"Opacity", "Opacity",
"OutlineStyle", "OutlineStyle",

View file

@ -447,17 +447,13 @@ ${helpers.predefined_type(
servo_restyle_damage="reflow", servo_restyle_damage="reflow",
)} )}
// NOTE(emilio): Before exposing this property to content, we probably need to
// change syntax and such, and make it apply to more elements.
//
// For now, it's used only for mapped attributes.
${helpers.predefined_type( ${helpers.predefined_type(
"aspect-ratio", "aspect-ratio",
"Number", "AspectRatio",
"computed::Number::zero()", "computed::AspectRatio::auto()",
engines="gecko servo-2013", engines="gecko servo-2013",
animation_value_type="ComputedValue", animation_value_type="discrete",
spec="Internal, for now", spec="https://drafts.csswg.org/css-sizing-4/#aspect-ratio",
enabled_in="", gecko_pref="layout.css.aspect-ratio.enabled",
servo_restyle_damage="reflow", servo_restyle_damage="reflow",
)} )}

View file

@ -21,7 +21,7 @@ use crate::media_queries::Device;
use crate::properties; use crate::properties;
use crate::properties::{ComputedValues, LonghandId, StyleBuilder}; use crate::properties::{ComputedValues, LonghandId, StyleBuilder};
use crate::rule_cache::RuleCacheConditions; use crate::rule_cache::RuleCacheConditions;
use crate::{ArcSlice, Atom}; use crate::{ArcSlice, Atom, One};
use euclid::default::Size2D; use euclid::default::Size2D;
use servo_arc::Arc; use servo_arc::Arc;
use std::cell::RefCell; use std::cell::RefCell;
@ -68,6 +68,7 @@ pub use self::list::Quotes;
pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::motion::{OffsetPath, OffsetRotate};
pub use self::outline::OutlineStyle; pub use self::outline::OutlineStyle;
pub use self::percentage::{NonNegativePercentage, Percentage}; pub use self::percentage::{NonNegativePercentage, Percentage};
pub use self::position::AspectRatio;
pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex}; pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex};
pub use self::rect::NonNegativeLengthOrNumberRect; pub use self::rect::NonNegativeLengthOrNumberRect;
pub use self::resolution::Resolution; pub use self::resolution::Resolution;
@ -600,6 +601,18 @@ impl From<NonNegativeNumber> for CSSFloat {
} }
} }
impl One for NonNegativeNumber {
#[inline]
fn one() -> Self {
NonNegative(1.0)
}
#[inline]
fn is_one(&self) -> bool {
self.0 == 1.0
}
}
/// A wrapper of Number, but the value between 0 and 1 /// A wrapper of Number, but the value between 0 and 1
pub type ZeroToOneNumber = ZeroToOne<CSSFloat>; pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;

View file

@ -7,7 +7,8 @@
//! //!
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
use crate::values::computed::{Integer, LengthPercentage, Percentage}; use crate::values::computed::{Integer, LengthPercentage, NonNegativeNumber, Percentage};
use crate::values::generics::position::AspectRatio as GenericAspectRatio;
use crate::values::generics::position::Position as GenericPosition; use crate::values::generics::position::Position as GenericPosition;
use crate::values::generics::position::PositionComponent as GenericPositionComponent; use crate::values::generics::position::PositionComponent as GenericPositionComponent;
use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto;
@ -68,3 +69,6 @@ impl GenericPositionComponent for LengthPercentage {
/// A computed value for the `z-index` property. /// A computed value for the `z-index` property.
pub type ZIndex = GenericZIndex<Integer>; pub type ZIndex = GenericZIndex<Integer>;
/// A computed value for the `aspect-ratio` property.
pub type AspectRatio = GenericAspectRatio<NonNegativeNumber>;

View file

@ -5,6 +5,10 @@
//! Generic types for CSS handling of specified and computed values of //! Generic types for CSS handling of specified and computed values of
//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)
use crate::One;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
/// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position).
#[derive( #[derive(
Animate, Animate,
@ -150,3 +154,74 @@ impl<Integer> ZIndex<Integer> {
} }
} }
} }
/// A generic value for the `<ratio>` value.
// FIXME: Use this for aspect-ratio in both css-sizing-4 and media-queries in the following patch.
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct Ratio<N>(pub N, pub N);
impl<N> ToCss for Ratio<N>
where
N: ToCss + One + std::cmp::PartialEq,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.0.to_css(dest)?;
// The second defaults to 1. So if it is one, we omit it in serialization.
if !self.1.is_one() {
dest.write_str(" / ")?;
self.1.to_css(dest)?;
}
Ok(())
}
}
/// A generic value for the `aspect-ratio` property.
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
pub enum GenericAspectRatio<N> {
/// The <ratio> value.
Ratio(#[css(field_bound)] Ratio<N>),
/// The keyword `auto`.
Auto,
}
pub use self::GenericAspectRatio as AspectRatio;
impl<R> AspectRatio<R> {
/// Returns `auto`
#[inline]
pub fn auto() -> Self {
AspectRatio::Auto
}
}

View file

@ -18,9 +18,8 @@ use crate::context::QuirksMode;
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::serialize_atom_identifier; use crate::values::serialize_atom_identifier;
use crate::values::specified::calc::CalcNode; use crate::values::specified::calc::CalcNode;
use crate::{Atom, Namespace, Prefix, Zero}; use crate::{Atom, Namespace, One, Prefix, Zero};
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use num_traits::One;
use std::f32; use std::f32;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::ops::Add; use std::ops::Add;
@ -72,6 +71,7 @@ pub use self::list::Quotes;
pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::motion::{OffsetPath, OffsetRotate};
pub use self::outline::OutlineStyle; pub use self::outline::OutlineStyle;
pub use self::percentage::Percentage; pub use self::percentage::Percentage;
pub use self::position::AspectRatio;
pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto}; pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto};
pub use self::position::{PositionComponent, ZIndex}; pub use self::position::{PositionComponent, ZIndex};
pub use self::rect::NonNegativeLengthOrNumberRect; pub use self::rect::NonNegativeLengthOrNumberRect;
@ -375,6 +375,18 @@ impl Parse for NonNegativeNumber {
} }
} }
impl One for NonNegativeNumber {
#[inline]
fn one() -> Self {
NonNegativeNumber::new(1.0)
}
#[inline]
fn is_one(&self) -> bool {
self.0.get() == 1.0
}
}
impl NonNegativeNumber { impl NonNegativeNumber {
/// Returns a new non-negative number with the value `val`. /// Returns a new non-negative number with the value `val`.
pub fn new(val: CSSFloat) -> Self { pub fn new(val: CSSFloat) -> Self {
@ -537,7 +549,7 @@ impl Zero for Integer {
} }
} }
impl One for Integer { impl num_traits::One for Integer {
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {
Self::new(1) Self::new(1)

View file

@ -12,13 +12,14 @@ use crate::selector_map::PrecomputedHashMap;
use crate::str::HTML_SPACE_CHARACTERS; use crate::str::HTML_SPACE_CHARACTERS;
use crate::values::computed::LengthPercentage as ComputedLengthPercentage; use crate::values::computed::LengthPercentage as ComputedLengthPercentage;
use crate::values::computed::{Context, Percentage, ToComputedValue}; use crate::values::computed::{Context, Percentage, ToComputedValue};
use crate::values::generics::position::AspectRatio as GenericAspectRatio;
use crate::values::generics::position::Position as GenericPosition; use crate::values::generics::position::Position as GenericPosition;
use crate::values::generics::position::PositionComponent as GenericPositionComponent; use crate::values::generics::position::PositionComponent as GenericPositionComponent;
use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto;
use crate::values::generics::position::Ratio as GenericRatio;
use crate::values::generics::position::ZIndex as GenericZIndex; use crate::values::generics::position::ZIndex as GenericZIndex;
use crate::values::specified::{AllowQuirks, Integer, LengthPercentage}; use crate::values::specified::{AllowQuirks, Integer, LengthPercentage, NonNegativeNumber};
use crate::Atom; use crate::{Atom, One, Zero};
use crate::Zero;
use cssparser::Parser; use cssparser::Parser;
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc; use servo_arc::Arc;
@ -877,3 +878,46 @@ impl GridTemplateAreas {
/// A specified value for the `z-index` property. /// A specified value for the `z-index` property.
pub type ZIndex = GenericZIndex<Integer>; pub type ZIndex = GenericZIndex<Integer>;
/// A specified value for the `aspect-ratio` property.
pub type AspectRatio = GenericAspectRatio<NonNegativeNumber>;
// FIXME: Add field_bound for parse custom derive, so we can drop this.
impl Parse for AspectRatio {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input
.try(|input| input.expect_ident_matching("auto"))
.is_ok()
{
return Ok(AspectRatio::Auto);
}
GenericRatio::parse(context, input).map(AspectRatio::Ratio)
}
}
// https://drafts.csswg.org/css-values-4/#ratios
impl Parse for GenericRatio<NonNegativeNumber> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let a = NonNegativeNumber::parse(context, input)?;
let b = match input.try_parse(|input| input.expect_delim('/')) {
Ok(()) => NonNegativeNumber::parse(context, input)?,
_ => One::one(),
};
// The computed value of a <ratio> is the pair of numbers provided, unless
// both numbers are zero, in which case the computed value is the pair (1, 0)
// (same as 1 / 0).
// https://drafts.csswg.org/css-values-4/#ratios
if a.is_zero() && b.is_zero() {
return Ok(GenericRatio(One::one(), Zero::zero()));
}
return Ok(GenericRatio(a, b));
}
}