From d8785f3a220dd61bb9a578c8ba94591acd4dad48 Mon Sep 17 00:00:00 2001 From: David Shin Date: Mon, 17 Oct 2022 17:26:12 +0000 Subject: [PATCH] style: Implement parsing of container relative lengths - For now, implementation always returns the fallback value, i.e. small viewport lengths. - Enabled via existing pref `layout.css.container-queries.enabled`. Differential Revision: https://phabricator.services.mozilla.com/D158054 --- components/style/values/computed/length.rs | 7 + components/style/values/generics/calc.rs | 6 + components/style/values/specified/calc.rs | 10 +- components/style/values/specified/length.rs | 182 +++++++++++++++++++- 4 files changed, 202 insertions(+), 3 deletions(-) diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index dc556bdd933..d7c4281fd33 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -58,6 +58,13 @@ impl specified::NoCalcLength { .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS); length.to_computed_value(context) }, + specified::NoCalcLength::ContainerRelative(length) => { + // Fallback uses small viewport size. + context + .builder + .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS); + length.to_computed_value(context) + }, specified::NoCalcLength::ServoCharacterWidth(length) => { length.to_computed_value(context.style().get_font().clone_font_size().size()) }, diff --git a/components/style/values/generics/calc.rs b/components/style/values/generics/calc.rs index c4f63552440..301ffb5cd62 100644 --- a/components/style/values/generics/calc.rs +++ b/components/style/values/generics/calc.rs @@ -44,6 +44,12 @@ pub enum SortKey { Percentage, Cap, Ch, + Cqb, + Cqh, + Cqi, + Cqmax, + Cqmin, + Cqw, Deg, Dvb, Dvh, diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 654925754ec..d27b408f3cc 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -9,8 +9,8 @@ use crate::parser::ParserContext; use crate::values::generics::calc as generic; use crate::values::generics::calc::{MinMaxOp, SortKey}; -use crate::values::specified::length::ViewportPercentageLength; use crate::values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength}; +use crate::values::specified::length::{ContainerRelativeLength, ViewportPercentageLength}; use crate::values::specified::{self, Angle, Time}; use crate::values::{CSSFloat, CSSInteger}; use cssparser::{AngleOrNumber, CowRcStr, NumberOrPercentage, Parser, Token}; @@ -258,6 +258,14 @@ impl generic::CalcNodeLeaf for Leaf { ViewportPercentageLength::Lvi(..) => SortKey::Lvi, ViewportPercentageLength::Dvi(..) => SortKey::Dvi, }, + NoCalcLength::ContainerRelative(ref cq) => match *cq { + ContainerRelativeLength::Cqw(..) => SortKey::Cqw, + ContainerRelativeLength::Cqh(..) => SortKey::Cqh, + ContainerRelativeLength::Cqi(..) => SortKey::Cqi, + ContainerRelativeLength::Cqb(..) => SortKey::Cqb, + ContainerRelativeLength::Cqmin(..) => SortKey::Cqmin, + ContainerRelativeLength::Cqmax(..) => SortKey::Cqmax, + }, NoCalcLength::ServoCharacterWidth(..) => unreachable!(), }, } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index df7138ff97c..f9b22352b8e 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -642,6 +642,102 @@ impl Add for AbsoluteLength { } } +/// A container query length. +/// +/// +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] +pub enum ContainerRelativeLength { + /// 1% of query container's width + #[css(dimension)] + Cqw(CSSFloat), + /// 1% of query container's height + #[css(dimension)] + Cqh(CSSFloat), + /// 1% of query container's inline size + #[css(dimension)] + Cqi(CSSFloat), + /// 1% of query container's block size + #[css(dimension)] + Cqb(CSSFloat), + /// The smaller value of `cqi` or `cqb` + #[css(dimension)] + Cqmin(CSSFloat), + /// The larger value of `cqi` or `cqb` + #[css(dimension)] + Cqmax(CSSFloat), +} + +impl ContainerRelativeLength { + fn unitless_value(&self) -> CSSFloat { + match *self { + ContainerRelativeLength::Cqw(v) | + ContainerRelativeLength::Cqh(v) | + ContainerRelativeLength::Cqi(v) | + ContainerRelativeLength::Cqb(v) | + ContainerRelativeLength::Cqmin(v) | + ContainerRelativeLength::Cqmax(v) => v, + } + } + + fn is_zero(&self) -> bool { + self.unitless_value() == 0. + } + + fn is_negative(&self) -> bool { + self.unitless_value() < 0. + } + + fn try_sum(&self, other: &Self) -> Result { + use self::ContainerRelativeLength::*; + + if std::mem::discriminant(self) != std::mem::discriminant(other) { + return Err(()); + } + + Ok(match (self, other) { + (&Cqw(one), &Cqw(other)) => Cqw(one + other), + (&Cqh(one), &Cqh(other)) => Cqh(one + other), + (&Cqi(one), &Cqi(other)) => Cqi(one + other), + (&Cqb(one), &Cqb(other)) => Cqb(one + other), + (&Cqmin(one), &Cqmin(other)) => Cqmin(one + other), + (&Cqmax(one), &Cqmax(other)) => Cqmax(one + other), + + // See https://github.com/rust-lang/rust/issues/68867, then + // https://github.com/rust-lang/rust/pull/95161. rustc isn't + // able to figure it own on its own so we help. + _ => unsafe { + match *self { + Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {}, + } + debug_unreachable!("Forgot to handle unit in try_sum()") + }, + }) + } + + /// Computes the given container-relative length. + pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength { + // TODO(dshin): For now, use the small viewport size. + let small_viewport_size = match *self { + ContainerRelativeLength::Cqw(v) => ViewportPercentageLength::Svw(v), + ContainerRelativeLength::Cqh(v) => ViewportPercentageLength::Svh(v), + ContainerRelativeLength::Cqi(v) => ViewportPercentageLength::Svi(v), + ContainerRelativeLength::Cqb(v) => ViewportPercentageLength::Svb(v), + ContainerRelativeLength::Cqmin(v) => ViewportPercentageLength::Svmin(v), + ContainerRelativeLength::Cqmax(v) => ViewportPercentageLength::Svmax(v), + }; + small_viewport_size.to_computed_value(context) + } +} + +#[cfg(feature = "gecko")] +fn are_container_queries_enabled() -> bool { + static_prefs::pref!("layout.css.container-queries.enabled") +} +#[cfg(feature = "servo")] +fn are_container_queries_enabled() -> bool { + false +} + /// A `` without taking `calc` expressions into account /// /// @@ -662,6 +758,10 @@ pub enum NoCalcLength { /// ViewportPercentage(ViewportPercentageLength), + /// A container query length. + /// + /// + ContainerRelative(ContainerRelativeLength), /// HTML5 "character width", as defined in HTML5 ยง 14.5.4. /// /// This cannot be specified by the user directly and is only generated by @@ -679,6 +779,7 @@ impl Mul for NoCalcLength { NoCalcLength::Absolute(v) => NoCalcLength::Absolute(v * scalar), NoCalcLength::FontRelative(v) => NoCalcLength::FontRelative(v * scalar), NoCalcLength::ViewportPercentage(v) => NoCalcLength::ViewportPercentage(v * scalar), + NoCalcLength::ContainerRelative(v) => NoCalcLength::ContainerRelative(v * scalar), NoCalcLength::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"), } } @@ -691,6 +792,7 @@ impl NoCalcLength { NoCalcLength::Absolute(v) => v.unitless_value(), NoCalcLength::FontRelative(v) => v.unitless_value(), NoCalcLength::ViewportPercentage(v) => v.unitless_value(), + NoCalcLength::ContainerRelative(v) => v.unitless_value(), NoCalcLength::ServoCharacterWidth(c) => c.0 as f32, } } @@ -701,6 +803,7 @@ impl NoCalcLength { NoCalcLength::Absolute(v) => v.is_negative(), NoCalcLength::FontRelative(v) => v.is_negative(), NoCalcLength::ViewportPercentage(v) => v.is_negative(), + NoCalcLength::ContainerRelative(v) => v.is_negative(), NoCalcLength::ServoCharacterWidth(c) => c.0 < 0, } } @@ -711,8 +814,11 @@ impl NoCalcLength { /// because the font they're relative to should be zoomed already. pub fn should_zoom_text(&self) -> bool { match *self { - Self::Absolute(..) | Self::ViewportPercentage(..) => true, - Self::ServoCharacterWidth(..) | Self::FontRelative(..) => false, + Self::Absolute(..) | + Self::ViewportPercentage(..) | + Self::ContainerRelative(..) => true, + Self::ServoCharacterWidth(..) | + Self::FontRelative(..) => false, } } @@ -810,6 +916,26 @@ impl NoCalcLength { "dvi" if !context.in_page_rule() => { NoCalcLength::ViewportPercentage(ViewportPercentageLength::Dvi(value)) }, + // Container query lengths. Inherit the limitation from viewport units since + // we may fall back to them. + "cqw" if !context.in_page_rule() && are_container_queries_enabled() => { + NoCalcLength::ContainerRelative(ContainerRelativeLength::Cqw(value)) + }, + "cqh" if !context.in_page_rule() && are_container_queries_enabled() => { + NoCalcLength::ContainerRelative(ContainerRelativeLength::Cqh(value)) + }, + "cqi" if !context.in_page_rule() && are_container_queries_enabled() => { + NoCalcLength::ContainerRelative(ContainerRelativeLength::Cqi(value)) + }, + "cqb" if !context.in_page_rule() && are_container_queries_enabled() => { + NoCalcLength::ContainerRelative(ContainerRelativeLength::Cqb(value)) + }, + "cqmin" if !context.in_page_rule() && are_container_queries_enabled() => { + NoCalcLength::ContainerRelative(ContainerRelativeLength::Cqmin(value)) + }, + "cqmax" if !context.in_page_rule() && are_container_queries_enabled() => { + NoCalcLength::ContainerRelative(ContainerRelativeLength::Cqmax(value)) + }, _ => return Err(()), }) } @@ -828,6 +954,9 @@ impl NoCalcLength { (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => { ViewportPercentage(one.try_sum(other)?) }, + (&ContainerRelative(ref one), &ContainerRelative(ref other)) => { + ContainerRelative(one.try_sum(other)?) + }, (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => { ServoCharacterWidth(CharacterWidth(one.0 + other.0)) }, @@ -838,6 +967,7 @@ impl NoCalcLength { Absolute(..) | FontRelative(..) | ViewportPercentage(..) | + ContainerRelative(..) | ServoCharacterWidth(..) => {}, } debug_unreachable!("Forgot to handle unit in try_sum()") @@ -877,6 +1007,7 @@ impl PartialOrd for NoCalcLength { (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => { one.partial_cmp(other) }, + (&ContainerRelative(ref one), &ContainerRelative(ref other)) => one.partial_cmp(other), (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => { one.0.partial_cmp(&other.0) }, @@ -887,6 +1018,7 @@ impl PartialOrd for NoCalcLength { Absolute(..) | FontRelative(..) | ViewportPercentage(..) | + ContainerRelative(..) | ServoCharacterWidth(..) => {}, } debug_unreachable!("Forgot an arm in partial_cmp?") @@ -905,6 +1037,7 @@ impl Zero for NoCalcLength { NoCalcLength::Absolute(v) => v.is_zero(), NoCalcLength::FontRelative(v) => v.is_zero(), NoCalcLength::ViewportPercentage(v) => v.is_zero(), + NoCalcLength::ContainerRelative(v) => v.is_zero(), NoCalcLength::ServoCharacterWidth(v) => v.0 == 0, } } @@ -986,6 +1119,51 @@ impl Mul for FontRelativeLength { } } +impl Mul for ContainerRelativeLength { + type Output = ContainerRelativeLength; + + #[inline] + fn mul(self, scalar: CSSFloat) -> ContainerRelativeLength { + match self { + ContainerRelativeLength::Cqw(v) => ContainerRelativeLength::Cqw(v * scalar), + ContainerRelativeLength::Cqh(v) => ContainerRelativeLength::Cqh(v * scalar), + ContainerRelativeLength::Cqi(v) => ContainerRelativeLength::Cqi(v * scalar), + ContainerRelativeLength::Cqb(v) => ContainerRelativeLength::Cqb(v * scalar), + ContainerRelativeLength::Cqmin(v) => ContainerRelativeLength::Cqmin(v * scalar), + ContainerRelativeLength::Cqmax(v) => ContainerRelativeLength::Cqmax(v * scalar), + } + } +} + +impl PartialOrd for ContainerRelativeLength { + fn partial_cmp(&self, other: &Self) -> Option { + use self::ContainerRelativeLength::*; + + if std::mem::discriminant(self) != std::mem::discriminant(other) { + return None; + } + + match (self, other) { + (&Cqw(ref one), &Cqw(ref other)) => one.partial_cmp(other), + (&Cqh(ref one), &Cqh(ref other)) => one.partial_cmp(other), + (&Cqi(ref one), &Cqi(ref other)) => one.partial_cmp(other), + (&Cqb(ref one), &Cqb(ref other)) => one.partial_cmp(other), + (&Cqmin(ref one), &Cqmin(ref other)) => one.partial_cmp(other), + (&Cqmax(ref one), &Cqmax(ref other)) => one.partial_cmp(other), + + // See https://github.com/rust-lang/rust/issues/68867, then + // https://github.com/rust-lang/rust/pull/95161. rustc isn't + // able to figure it own on its own so we help. + _ => unsafe { + match *self { + Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {}, + } + debug_unreachable!("Forgot to handle unit in try_sum()") + }, + } + } +} + impl Mul for ViewportPercentageLength { type Output = ViewportPercentageLength;