style: Implement new {small,large,dynamic} viewport units

Differential Revision: https://phabricator.services.mozilla.com/D143252
This commit is contained in:
Hiroyuki Ikezoe 2023-06-19 16:27:47 +02:00 committed by Martin Robinson
parent 7c538e8147
commit 129e06327a
7 changed files with 328 additions and 34 deletions

View file

@ -17,6 +17,7 @@ use crate::values::computed::font::GenericFontFamily;
use crate::values::computed::{ColorScheme, Length};
use crate::values::specified::color::SystemColor;
use crate::values::specified::font::FONT_MEDIUM_PX;
use crate::values::specified::ViewportVariant;
use crate::values::{CustomIdent, KeyframesName};
use app_units::{Au, AU_PER_PX};
use cssparser::RGBA;
@ -58,6 +59,9 @@ pub struct Device {
/// Whether any styles computed in the document relied on the viewport size
/// by using vw/vh/vmin/vmax units.
used_viewport_size: AtomicBool,
/// Whether any styles computed in the document relied on the viewport size
/// by using dvw/dvh/dvmin/dvmax units.
used_dynamic_viewport_size: AtomicBool,
/// The CssEnvironment object responsible of getting CSS environment
/// variables.
environment: CssEnvironment,
@ -100,6 +104,7 @@ impl Device {
used_root_font_size: AtomicBool::new(false),
used_font_metrics: AtomicBool::new(false),
used_viewport_size: AtomicBool::new(false),
used_dynamic_viewport_size: AtomicBool::new(false),
environment: CssEnvironment,
}
}
@ -267,6 +272,8 @@ impl Device {
self.used_root_font_size.store(false, Ordering::Relaxed);
self.used_font_metrics.store(false, Ordering::Relaxed);
self.used_viewport_size.store(false, Ordering::Relaxed);
self.used_dynamic_viewport_size
.store(false, Ordering::Relaxed);
}
/// Returns whether we ever looked up the root font size of the Device.
@ -337,7 +344,10 @@ impl Device {
/// Returns the current viewport size in app units, recording that it's been
/// used for viewport unit resolution.
pub fn au_viewport_size_for_viewport_unit_resolution(&self) -> Size2D<Au> {
pub fn au_viewport_size_for_viewport_unit_resolution(
&self,
variant: ViewportVariant,
) -> Size2D<Au> {
self.used_viewport_size.store(true, Ordering::Relaxed);
let pc = match self.pres_context() {
Some(pc) => pc,
@ -348,8 +358,42 @@ impl Device {
return self.page_size_minus_default_margin(pc);
}
let size = &pc.mSizeForViewportUnits;
Size2D::new(Au(size.width), Au(size.height))
match variant {
ViewportVariant::UADefault => {
let size = &pc.mSizeForViewportUnits;
Size2D::new(Au(size.width), Au(size.height))
},
ViewportVariant::Small => {
let size = &pc.mVisibleArea;
Size2D::new(Au(size.width), Au(size.height))
},
ViewportVariant::Large => {
let size = &pc.mVisibleArea;
// Looks like IntCoordTyped is treated as if it's u32 in Rust.
debug_assert!(
/* pc.mDynamicToolbarMaxHeight >=0 && */
pc.mDynamicToolbarMaxHeight < i32::MAX as u32
);
Size2D::new(
Au(size.width),
Au(size.height
+ pc.mDynamicToolbarMaxHeight as i32 * pc.mCurAppUnitsPerDevPixel),
)
},
ViewportVariant::Dynamic => {
self.used_dynamic_viewport_size.store(true, Ordering::Relaxed);
let size = &pc.mVisibleArea;
// Looks like IntCoordTyped is treated as if it's u32 in Rust.
debug_assert!(
/* pc.mDynamicToolbarHeight >=0 && */
pc.mDynamicToolbarHeight < i32::MAX as u32
);
Size2D::new(
Au(size.width),
Au(size.height + pc.mDynamicToolbarHeight as i32 * pc.mCurAppUnitsPerDevPixel),
)
},
}
}
/// Returns whether we ever looked up the viewport size of the Device.
@ -357,6 +401,11 @@ impl Device {
self.used_viewport_size.load(Ordering::Relaxed)
}
/// Returns whether we ever looked up the dynamic viewport size of the Device.
pub fn used_dynamic_viewport_size(&self) -> bool {
self.used_dynamic_viewport_size.load(Ordering::Relaxed)
}
/// Returns whether font metrics have been queried.
pub fn used_font_metrics(&self) -> bool {
self.used_font_metrics.load(Ordering::Relaxed)

View file

@ -40,7 +40,7 @@ impl ToComputedValue for specified::NoCalcLength {
context
.builder
.add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS);
length.to_computed_value(context.viewport_size_for_viewport_unit_resolution())
length.to_computed_value(context)
},
specified::NoCalcLength::ServoCharacterWidth(length) => {
length.to_computed_value(context.style().get_font().clone_font_size().size())

View file

@ -97,6 +97,7 @@ pub use self::transform::{TransformOrigin, TransformStyle, Translate};
pub use self::ui::CursorImage;
pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
pub use super::specified::TextTransform;
pub use super::specified::ViewportVariant;
pub use super::specified::{BorderStyle, TextDecorationLine};
pub use super::{Auto, Either, None_};
pub use app_units::Au;
@ -253,10 +254,13 @@ impl<'a> Context<'a> {
}
/// The current viewport size, used to resolve viewport units.
pub fn viewport_size_for_viewport_unit_resolution(&self) -> default::Size2D<Au> {
pub fn viewport_size_for_viewport_unit_resolution(
&self,
variant: ViewportVariant,
) -> default::Size2D<Au> {
self.builder
.device
.au_viewport_size_for_viewport_unit_resolution()
.au_viewport_size_for_viewport_unit_resolution(variant)
}
/// The default computed style we're getting our reset style from.

View file

@ -45,12 +45,24 @@ pub enum SortKey {
Cap,
Ch,
Deg,
Dvh,
Dvmax,
Dvmin,
Dvw,
Em,
Ex,
Ic,
Lvh,
Lvmax,
Lvmin,
Lvw,
Px,
Rem,
Sec,
Svh,
Svmax,
Svmin,
Svw,
Vh,
Vmax,
Vmin,

View file

@ -190,9 +190,21 @@ impl generic::CalcNodeLeaf for Leaf {
},
NoCalcLength::ViewportPercentage(ref vp) => match *vp {
ViewportPercentageLength::Vh(..) => SortKey::Vh,
ViewportPercentageLength::Svh(..) => SortKey::Svh,
ViewportPercentageLength::Lvh(..) => SortKey::Lvh,
ViewportPercentageLength::Dvh(..) => SortKey::Dvh,
ViewportPercentageLength::Vw(..) => SortKey::Vw,
ViewportPercentageLength::Svw(..) => SortKey::Svw,
ViewportPercentageLength::Lvw(..) => SortKey::Lvw,
ViewportPercentageLength::Dvw(..) => SortKey::Dvw,
ViewportPercentageLength::Vmax(..) => SortKey::Vmax,
ViewportPercentageLength::Svmax(..) => SortKey::Svmax,
ViewportPercentageLength::Lvmax(..) => SortKey::Lvmax,
ViewportPercentageLength::Dvmax(..) => SortKey::Dvmax,
ViewportPercentageLength::Vmin(..) => SortKey::Vmin,
ViewportPercentageLength::Svmin(..) => SortKey::Svmin,
ViewportPercentageLength::Lvmin(..) => SortKey::Lvmin,
ViewportPercentageLength::Dvmin(..) => SortKey::Dvmin,
},
NoCalcLength::ServoCharacterWidth(..) => unreachable!(),
},

View file

@ -21,7 +21,6 @@ use crate::values::CSSFloat;
use crate::Zero;
use app_units::Au;
use cssparser::{Parser, Token};
use euclid::default::Size2D;
use std::cmp;
use std::ops::{Add, Mul};
use style_traits::values::specified::AllowedNumericType;
@ -278,45 +277,180 @@ impl FontRelativeLength {
}
}
/// https://drafts.csswg.org/css-values/#viewport-variants
pub enum ViewportVariant {
/// https://drafts.csswg.org/css-values/#ua-default-viewport-size
UADefault,
/// https://drafts.csswg.org/css-values/#small-viewport-percentage-units
Small,
/// https://drafts.csswg.org/css-values/#large-viewport-percentage-units
Large,
/// https://drafts.csswg.org/css-values/#dynamic-viewport-percentage-units
Dynamic,
}
/// https://drafts.csswg.org/css-values/#viewport-relative-units
enum ViewportUnit {
/// *vw units.
Vw,
/// *vh units.
Vh,
/// *vmin units.
Vmin,
/// *vmax units.
Vmax,
}
/// A viewport-relative length.
///
/// <https://drafts.csswg.org/css-values/#viewport-relative-lengths>
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
pub enum ViewportPercentageLength {
/// A vw unit: https://drafts.csswg.org/css-values/#vw
/// <https://drafts.csswg.org/css-values/#valdef-length-vw>
#[css(dimension)]
Vw(CSSFloat),
/// A vh unit: https://drafts.csswg.org/css-values/#vh
/// <https://drafts.csswg.org/css-values/#valdef-length-svw>
#[css(dimension)]
Svw(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-lvw>
#[css(dimension)]
Lvw(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-dvw>
#[css(dimension)]
Dvw(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-vh>
#[css(dimension)]
Vh(CSSFloat),
/// <https://drafts.csswg.org/css-values/#vmin>
/// <https://drafts.csswg.org/css-values/#valdef-length-svh>
#[css(dimension)]
Svh(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-lvh>
#[css(dimension)]
Lvh(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-dvh>
#[css(dimension)]
Dvh(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-vmin>
#[css(dimension)]
Vmin(CSSFloat),
/// <https://drafts.csswg.org/css-values/#vmax>
/// <https://drafts.csswg.org/css-values/#valdef-length-svmin>
#[css(dimension)]
Svmin(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-lvmin>
#[css(dimension)]
Lvmin(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-dvmin>
#[css(dimension)]
Dvmin(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-vmax>
#[css(dimension)]
Vmax(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-svmax>
#[css(dimension)]
Svmax(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-lvmax>
#[css(dimension)]
Lvmax(CSSFloat),
/// <https://drafts.csswg.org/css-values/#valdef-length-dvmax>
#[css(dimension)]
Dvmax(CSSFloat),
}
impl ViewportPercentageLength {
/// Return true if this is a zero value.
fn is_zero(&self) -> bool {
match *self {
ViewportPercentageLength::Vw(v) |
ViewportPercentageLength::Vh(v) |
ViewportPercentageLength::Vmin(v) |
ViewportPercentageLength::Vmax(v) => v == 0.,
}
let (_, _, v) = self.unpack();
v == 0.
}
fn is_negative(&self) -> bool {
match *self {
ViewportPercentageLength::Vw(v) |
ViewportPercentageLength::Vh(v) |
ViewportPercentageLength::Vmin(v) |
ViewportPercentageLength::Vmax(v) => v < 0.,
}
let (_, _, v) = self.unpack();
v < 0.
}
fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) {
match *self {
ViewportPercentageLength::Vw(v) => (
ViewportVariant::UADefault,
ViewportUnit::Vw,
v,
),
ViewportPercentageLength::Svw(v) => (
ViewportVariant::Small,
ViewportUnit::Vw,
v,
),
ViewportPercentageLength::Lvw(v) => (
ViewportVariant::Large,
ViewportUnit::Vw,
v,
),
ViewportPercentageLength::Dvw(v) => (
ViewportVariant::Dynamic,
ViewportUnit::Vw,
v,
),
ViewportPercentageLength::Vh(v) => (
ViewportVariant::UADefault,
ViewportUnit::Vh,
v,
),
ViewportPercentageLength::Svh(v) => (
ViewportVariant::Small,
ViewportUnit::Vh,
v,
),
ViewportPercentageLength::Lvh(v) => (
ViewportVariant::Large,
ViewportUnit::Vh,
v),
ViewportPercentageLength::Dvh(v) => (
ViewportVariant::Dynamic,
ViewportUnit::Vh,
v,
),
ViewportPercentageLength::Vmin(v) => (
ViewportVariant::UADefault,
ViewportUnit::Vmin,
v,
),
ViewportPercentageLength::Svmin(v) => (
ViewportVariant::Small,
ViewportUnit::Vmin,
v,
),
ViewportPercentageLength::Lvmin(v) => (
ViewportVariant::Large,
ViewportUnit::Vmin,
v,
),
ViewportPercentageLength::Dvmin(v) => (
ViewportVariant::Dynamic,
ViewportUnit::Vmin,
v,
),
ViewportPercentageLength::Vmax(v) => (
ViewportVariant::UADefault,
ViewportUnit::Vmax,
v,
),
ViewportPercentageLength::Svmax(v) => (
ViewportVariant::Small,
ViewportUnit::Vmax,
v,
),
ViewportPercentageLength::Lvmax(v) => (
ViewportVariant::Large,
ViewportUnit::Vmax,
v,
),
ViewportPercentageLength::Dvmax(v) => (
ViewportVariant::Dynamic,
ViewportUnit::Vmax,
v,
),
}
}
fn try_sum(&self, other: &Self) -> Result<Self, ()> {
use self::ViewportPercentageLength::*;
@ -326,14 +460,29 @@ impl ViewportPercentageLength {
Ok(match (self, other) {
(&Vw(one), &Vw(other)) => Vw(one + other),
(&Svw(one), &Svw(other)) => Svw(one + other),
(&Lvw(one), &Lvw(other)) => Lvw(one + other),
(&Dvw(one), &Dvw(other)) => Dvw(one + other),
(&Vh(one), &Vh(other)) => Vh(one + other),
(&Svh(one), &Svh(other)) => Svh(one + other),
(&Lvh(one), &Lvh(other)) => Lvh(one + other),
(&Dvh(one), &Dvh(other)) => Dvh(one + other),
(&Vmin(one), &Vmin(other)) => Vmin(one + other),
(&Svmin(one), &Svmin(other)) => Svmin(one + other),
(&Lvmin(one), &Lvmin(other)) => Lvmin(one + other),
(&Dvmin(one), &Dvmin(other)) => Dvmin(one + other),
(&Vmax(one), &Vmax(other)) => Vmax(one + other),
(&Svmax(one), &Svmax(other)) => Svmax(one + other),
(&Lvmax(one), &Lvmax(other)) => Lvmax(one + other),
(&Dvmax(one), &Dvmax(other)) => Dvmax(one + other),
// See https://github.com/rust-lang/rust/issues/68867. rustc isn't
// able to figure it own on its own so we help.
_ => unsafe {
match *self {
Vw(..) | Vh(..) | Vmin(..) | Vmax(..) => {},
Vw(..) | Svw(..) | Lvw(..) | Dvw(..) |
Vh(..) | Svh(..) | Lvh(..) | Dvh(..) |
Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) |
Vmax(..) | Svmax(..) | Lvmax(..) | Dvmax(..) => {},
}
debug_unreachable!("Forgot to handle unit in try_sum()")
},
@ -341,15 +490,20 @@ impl ViewportPercentageLength {
}
/// Computes the given viewport-relative length for the given viewport size.
pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> CSSPixelLength {
let (factor, length) = match *self {
ViewportPercentageLength::Vw(length) => (length, viewport_size.width),
ViewportPercentageLength::Vh(length) => (length, viewport_size.height),
ViewportPercentageLength::Vmin(length) => {
(length, cmp::min(viewport_size.width, viewport_size.height))
pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
let (variant, unit, factor) = self.unpack();
let length = match unit {
ViewportUnit::Vw => context.viewport_size_for_viewport_unit_resolution(variant).width,
ViewportUnit::Vh => context.viewport_size_for_viewport_unit_resolution(variant).height,
ViewportUnit::Vmin => {
let base_size =
context.viewport_size_for_viewport_unit_resolution(variant);
cmp::min(base_size.width, base_size.height)
},
ViewportPercentageLength::Vmax(length) => {
(length, cmp::max(viewport_size.width, viewport_size.height))
ViewportUnit::Vmax => {
let base_size =
context.viewport_size_for_viewport_unit_resolution(variant);
cmp::max(base_size.width, base_size.height)
},
};
@ -578,15 +732,51 @@ impl NoCalcLength {
"vw" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(value))
},
"svw" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Svw(value))
},
"lvw" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Lvw(value))
},
"dvw" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Dvw(value))
},
"vh" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(value))
},
"svh" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Svh(value))
},
"lvh" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Lvh(value))
},
"dvh" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Dvh(value))
},
"vmin" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmin(value))
},
"svmin" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Svmin(value))
},
"lvmin" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Lvmin(value))
},
"dvmin" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Dvmin(value))
},
"vmax" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmax(value))
},
"svmax" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Svmax(value))
},
"lvmax" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Lvmax(value))
},
"dvmax" if !context.in_page_rule() => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Dvmax(value))
},
_ => return Err(()),
})
}
@ -770,9 +960,21 @@ impl Mul<CSSFloat> for ViewportPercentageLength {
fn mul(self, scalar: CSSFloat) -> ViewportPercentageLength {
match self {
ViewportPercentageLength::Vw(v) => ViewportPercentageLength::Vw(v * scalar),
ViewportPercentageLength::Svw(v) => ViewportPercentageLength::Svw(v * scalar),
ViewportPercentageLength::Lvw(v) => ViewportPercentageLength::Lvw(v * scalar),
ViewportPercentageLength::Dvw(v) => ViewportPercentageLength::Dvw(v * scalar),
ViewportPercentageLength::Vh(v) => ViewportPercentageLength::Vh(v * scalar),
ViewportPercentageLength::Svh(v) => ViewportPercentageLength::Svh(v * scalar),
ViewportPercentageLength::Lvh(v) => ViewportPercentageLength::Lvh(v * scalar),
ViewportPercentageLength::Dvh(v) => ViewportPercentageLength::Dvh(v * scalar),
ViewportPercentageLength::Vmin(v) => ViewportPercentageLength::Vmin(v * scalar),
ViewportPercentageLength::Svmin(v) => ViewportPercentageLength::Svmin(v * scalar),
ViewportPercentageLength::Lvmin(v) => ViewportPercentageLength::Lvmin(v * scalar),
ViewportPercentageLength::Dvmin(v) => ViewportPercentageLength::Dvmin(v * scalar),
ViewportPercentageLength::Vmax(v) => ViewportPercentageLength::Vmax(v * scalar),
ViewportPercentageLength::Svmax(v) => ViewportPercentageLength::Svmax(v * scalar),
ViewportPercentageLength::Lvmax(v) => ViewportPercentageLength::Lvmax(v * scalar),
ViewportPercentageLength::Dvmax(v) => ViewportPercentageLength::Dvmax(v * scalar),
}
}
}
@ -787,14 +989,29 @@ impl PartialOrd for ViewportPercentageLength {
match (self, other) {
(&Vw(ref one), &Vw(ref other)) => one.partial_cmp(other),
(&Svw(ref one), &Svw(ref other)) => one.partial_cmp(other),
(&Lvw(ref one), &Lvw(ref other)) => one.partial_cmp(other),
(&Dvw(ref one), &Dvw(ref other)) => one.partial_cmp(other),
(&Vh(ref one), &Vh(ref other)) => one.partial_cmp(other),
(&Svh(ref one), &Svh(ref other)) => one.partial_cmp(other),
(&Lvh(ref one), &Lvh(ref other)) => one.partial_cmp(other),
(&Dvh(ref one), &Dvh(ref other)) => one.partial_cmp(other),
(&Vmin(ref one), &Vmin(ref other)) => one.partial_cmp(other),
(&Svmin(ref one), &Svmin(ref other)) => one.partial_cmp(other),
(&Lvmin(ref one), &Lvmin(ref other)) => one.partial_cmp(other),
(&Dvmin(ref one), &Dvmin(ref other)) => one.partial_cmp(other),
(&Vmax(ref one), &Vmax(ref other)) => one.partial_cmp(other),
(&Svmax(ref one), &Svmax(ref other)) => one.partial_cmp(other),
(&Lvmax(ref one), &Lvmax(ref other)) => one.partial_cmp(other),
(&Dvmax(ref one), &Dvmax(ref other)) => one.partial_cmp(other),
// See https://github.com/rust-lang/rust/issues/68867. rustc isn't
// able to figure it own on its own so we help.
_ => unsafe {
match *self {
Vw(..) | Vh(..) | Vmin(..) | Vmax(..) => {},
Vw(..) | Svw(..) | Lvw(..) | Dvw(..) |
Vh(..) | Svh(..) | Lvh(..) | Dvh(..) |
Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) |
Vmax(..) | Svmax(..) | Lvmax(..) | Dvmax(..) => {},
}
debug_unreachable!("Forgot an arm in partial_cmp?")
},

View file

@ -60,7 +60,7 @@ pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber};
pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
pub use self::length::{MaxSize, Size};
pub use self::length::{NoCalcLength, ViewportPercentageLength};
pub use self::length::{NoCalcLength, ViewportPercentageLength, ViewportVariant};
pub use self::length::{
NonNegativeLength, NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto,
};