From fc9321bb238f6e5a9f4c568372b276076fb36b38 Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Thu, 21 May 2020 06:45:10 +0000 Subject: [PATCH] style: Let aspect-ratio (css-sizing-4) support 'auto | '. 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 --- components/style/lib.rs | 23 ++++++ components/style/properties/data.py | 2 +- .../properties/longhands/position.mako.rs | 14 ++-- components/style/values/computed/mod.rs | 15 +++- components/style/values/computed/position.rs | 6 +- components/style/values/generics/position.rs | 75 +++++++++++++++++++ components/style/values/specified/mod.rs | 18 ++++- components/style/values/specified/position.rs | 50 ++++++++++++- 8 files changed, 185 insertions(+), 18 deletions(-) diff --git a/components/style/lib.rs b/components/style/lib.rs index 7ec3ded33959..52b77a7507e7 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -272,3 +272,26 @@ where ::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 One for T +where + T: num_traits::One + PartialEq, +{ + fn one() -> Self { + ::one() + } + + fn is_one(&self) -> bool { + *self == One::one() + } +} diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 56ac30dd4586..8e6cdd79a1b6 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -328,6 +328,7 @@ def specified_is_copy(self): "AlignItems", "AlignSelf", "Appearance", + "AspectRatio", "BreakBetween", "BreakWithin", "BackgroundRepeat", @@ -364,7 +365,6 @@ def specified_is_copy(self): "MozScriptSizeMultiplier", "TextDecorationSkipInk", "NonNegativeNumber", - "Number", "OffsetRotate", "Opacity", "OutlineStyle", diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 04d735201d4f..3af5f86561b7 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -447,17 +447,13 @@ ${helpers.predefined_type( 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( "aspect-ratio", - "Number", - "computed::Number::zero()", + "AspectRatio", + "computed::AspectRatio::auto()", engines="gecko servo-2013", - animation_value_type="ComputedValue", - spec="Internal, for now", - enabled_in="", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-sizing-4/#aspect-ratio", + gecko_pref="layout.css.aspect-ratio.enabled", servo_restyle_damage="reflow", )} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index aba433d74436..f2d29eecac31 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -21,7 +21,7 @@ use crate::media_queries::Device; use crate::properties; use crate::properties::{ComputedValues, LonghandId, StyleBuilder}; use crate::rule_cache::RuleCacheConditions; -use crate::{ArcSlice, Atom}; +use crate::{ArcSlice, Atom, One}; use euclid::default::Size2D; use servo_arc::Arc; use std::cell::RefCell; @@ -68,6 +68,7 @@ pub use self::list::Quotes; pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::outline::OutlineStyle; pub use self::percentage::{NonNegativePercentage, Percentage}; +pub use self::position::AspectRatio; pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex}; pub use self::rect::NonNegativeLengthOrNumberRect; pub use self::resolution::Resolution; @@ -600,6 +601,18 @@ impl From 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 pub type ZeroToOneNumber = ZeroToOne; diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs index 554c36295c7b..6d09e327e63f 100644 --- a/components/style/values/computed/position.rs +++ b/components/style/values/computed/position.rs @@ -7,7 +7,8 @@ //! //! [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::PositionComponent as GenericPositionComponent; use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; @@ -68,3 +69,6 @@ impl GenericPositionComponent for LengthPercentage { /// A computed value for the `z-index` property. pub type ZIndex = GenericZIndex; + +/// A computed value for the `aspect-ratio` property. +pub type AspectRatio = GenericAspectRatio; diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index 00a9a219df4a..8e2c362ef0bd 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -5,6 +5,10 @@ //! Generic types for CSS handling of specified and computed values of //! [`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). #[derive( Animate, @@ -150,3 +154,74 @@ impl ZIndex { } } } + +/// A generic value for the `` 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(pub N, pub N); + +impl ToCss for Ratio +where + N: ToCss + One + std::cmp::PartialEq, +{ + fn to_css(&self, dest: &mut CssWriter) -> 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 { + /// The value. + Ratio(#[css(field_bound)] Ratio), + /// The keyword `auto`. + Auto, +} + +pub use self::GenericAspectRatio as AspectRatio; + +impl AspectRatio { + /// Returns `auto` + #[inline] + pub fn auto() -> Self { + AspectRatio::Auto + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index c1c11d5f8164..8fc7dade9ec4 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -18,9 +18,8 @@ use crate::context::QuirksMode; use crate::parser::{Parse, ParserContext}; use crate::values::serialize_atom_identifier; use crate::values::specified::calc::CalcNode; -use crate::{Atom, Namespace, Prefix, Zero}; +use crate::{Atom, Namespace, One, Prefix, Zero}; use cssparser::{Parser, Token}; -use num_traits::One; use std::f32; use std::fmt::{self, Write}; use std::ops::Add; @@ -72,6 +71,7 @@ pub use self::list::Quotes; pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::outline::OutlineStyle; pub use self::percentage::Percentage; +pub use self::position::AspectRatio; pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto}; pub use self::position::{PositionComponent, ZIndex}; 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 { /// Returns a new non-negative number with the value `val`. 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] fn one() -> Self { Self::new(1) diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index 33b9ddcf5b50..cd1dacc8f262 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -12,13 +12,14 @@ use crate::selector_map::PrecomputedHashMap; use crate::str::HTML_SPACE_CHARACTERS; use crate::values::computed::LengthPercentage as ComputedLengthPercentage; 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::PositionComponent as GenericPositionComponent; 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::specified::{AllowQuirks, Integer, LengthPercentage}; -use crate::Atom; -use crate::Zero; +use crate::values::specified::{AllowQuirks, Integer, LengthPercentage, NonNegativeNumber}; +use crate::{Atom, One, Zero}; use cssparser::Parser; use selectors::parser::SelectorParseErrorKind; use servo_arc::Arc; @@ -877,3 +878,46 @@ impl GridTemplateAreas { /// A specified value for the `z-index` property. pub type ZIndex = GenericZIndex; + +/// A specified value for the `aspect-ratio` property. +pub type AspectRatio = GenericAspectRatio; + +// 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> { + 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 { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + 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 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)); + } +}