diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index e4634d7eab9..a54b02a756d 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -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 { + pub fn au_viewport_size_for_viewport_unit_resolution( + &self, + variant: ViewportVariant, + ) -> Size2D { 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) diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index b8ff80587e6..896001cbcd8 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -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()) diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index ef1c88a43e5..8f09f0c32ac 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -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 { + pub fn viewport_size_for_viewport_unit_resolution( + &self, + variant: ViewportVariant, + ) -> default::Size2D { 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. diff --git a/components/style/values/generics/calc.rs b/components/style/values/generics/calc.rs index d9044bbb818..859a0f4d8c8 100644 --- a/components/style/values/generics/calc.rs +++ b/components/style/values/generics/calc.rs @@ -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, diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index f5448591f21..ee3c91c4e76 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -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!(), }, diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index e092f254bd4..0c84df9c0b6 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -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. /// /// #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] pub enum ViewportPercentageLength { - /// A vw unit: https://drafts.csswg.org/css-values/#vw + /// #[css(dimension)] Vw(CSSFloat), - /// A vh unit: https://drafts.csswg.org/css-values/#vh + /// + #[css(dimension)] + Svw(CSSFloat), + /// + #[css(dimension)] + Lvw(CSSFloat), + /// + #[css(dimension)] + Dvw(CSSFloat), + /// #[css(dimension)] Vh(CSSFloat), - /// + /// + #[css(dimension)] + Svh(CSSFloat), + /// + #[css(dimension)] + Lvh(CSSFloat), + /// + #[css(dimension)] + Dvh(CSSFloat), + /// #[css(dimension)] Vmin(CSSFloat), - /// + /// + #[css(dimension)] + Svmin(CSSFloat), + /// + #[css(dimension)] + Lvmin(CSSFloat), + /// + #[css(dimension)] + Dvmin(CSSFloat), + /// #[css(dimension)] Vmax(CSSFloat), + /// + #[css(dimension)] + Svmax(CSSFloat), + /// + #[css(dimension)] + Lvmax(CSSFloat), + /// + #[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 { 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) -> 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 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?") }, diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 7292088920d..4db2a265dad 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -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, };