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
This commit is contained in:
David Shin 2022-10-17 17:26:12 +00:00 committed by Martin Robinson
parent 4dd841a036
commit d8785f3a22
4 changed files with 202 additions and 3 deletions

View file

@ -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())
},

View file

@ -44,6 +44,12 @@ pub enum SortKey {
Percentage,
Cap,
Ch,
Cqb,
Cqh,
Cqi,
Cqmax,
Cqmin,
Cqw,
Deg,
Dvb,
Dvh,

View file

@ -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!(),
},
}

View file

@ -642,6 +642,102 @@ impl Add<AbsoluteLength> for AbsoluteLength {
}
}
/// A container query length.
///
/// <https://drafts.csswg.org/css-contain-3/#container-lengths>
#[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<Self, ()> {
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 `<length>` without taking `calc` expressions into account
///
/// <https://drafts.csswg.org/css-values/#lengths>
@ -662,6 +758,10 @@ pub enum NoCalcLength {
/// <https://drafts.csswg.org/css-values/#viewport-relative-lengths>
ViewportPercentage(ViewportPercentageLength),
/// A container query length.
///
/// <https://drafts.csswg.org/css-contain-3/#container-lengths>
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<CSSFloat> 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<CSSFloat> for FontRelativeLength {
}
}
impl Mul<CSSFloat> 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<cmp::Ordering> {
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<CSSFloat> for ViewportPercentageLength {
type Output = ViewportPercentageLength;