diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 1f3e862df495..bd02a7ac944a 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1146,7 +1146,7 @@ fn static_assert() { } pub fn set_font_size(&mut self, v: FontSize) { - use crate::values::generics::font::KeywordSize; + use crate::values::specified::font::KeywordSize; let size = v.size(); self.gecko.mScriptUnconstrainedSize = size.0; @@ -1167,7 +1167,7 @@ fn static_assert() { KeywordSize::XXXLarge => structs::NS_STYLE_FONT_SIZE_XXXLARGE, } as u8; self.gecko.mFontSizeFactor = info.factor; - self.gecko.mFontSizeOffset = info.offset.0.to_i32_au(); + self.gecko.mFontSizeOffset = info.offset.to_i32_au(); } else { self.gecko.mFontSizeKeyword = structs::NS_STYLE_FONT_SIZE_NO_KEYWORD as u8; self.gecko.mFontSizeFactor = 1.; @@ -1176,7 +1176,7 @@ fn static_assert() { } pub fn clone_font_size(&self) -> FontSize { - use crate::values::generics::font::{KeywordInfo, KeywordSize}; + use crate::values::specified::font::{KeywordInfo, KeywordSize}; let size = Au(self.gecko.mSize).into(); let kw = match self.gecko.mFontSizeKeyword as u32 { structs::NS_STYLE_FONT_SIZE_XXSMALL => KeywordSize::XXSmall, diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index b8ce027be4e9..148b6fe33f68 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -401,7 +401,7 @@ ${helpers.predefined_type( is_system_font: true, }, font_size: FontSize { - size: cx.maybe_zoom_text(Au(system.size).into()), + size: NonNegative(cx.maybe_zoom_text(Au(system.size).into())), keyword_info: None }, font_weight, diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index 407a547013f8..0063a6946baa 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -9,11 +9,11 @@ use crate::gecko_bindings::sugar::refptr::RefPtr; #[cfg(feature = "gecko")] use crate::gecko_bindings::{bindings, structs}; use crate::values::animated::{ToAnimatedValue, ToAnimatedZero}; -use crate::values::computed::{Angle, Context, Integer, NonNegativeLength, NonNegativePercentage}; +use crate::values::computed::{Angle, Context, Integer, Length, NonNegativeLength, NonNegativePercentage}; use crate::values::computed::{Number, Percentage, ToComputedValue}; -use crate::values::generics::font as generics; +use crate::values::generics::{font as generics, NonNegative}; use crate::values::generics::font::{FeatureTagValue, FontSettings, VariationValue}; -use crate::values::specified::font::{self as specified, MAX_FONT_WEIGHT, MIN_FONT_WEIGHT}; +use crate::values::specified::font::{self as specified, KeywordInfo, MAX_FONT_WEIGHT, MIN_FONT_WEIGHT}; use crate::values::specified::length::{FontBaseSize, NoCalcLength}; use crate::values::CSSFloat; use crate::Atom; @@ -88,9 +88,6 @@ pub struct FontSize { pub keyword_info: Option, } -/// Additional information for computed keyword-derived font sizes. -pub type KeywordInfo = generics::KeywordInfo; - impl FontWeight { /// Value for normal pub fn normal() -> Self { @@ -162,17 +159,17 @@ impl FontSize { } impl ToAnimatedValue for FontSize { - type AnimatedValue = NonNegativeLength; + type AnimatedValue = Length; #[inline] fn to_animated_value(self) -> Self::AnimatedValue { - self.size + self.size.0 } #[inline] fn from_animated_value(animated: Self::AnimatedValue) -> Self { FontSize { - size: animated.clamp(), + size: NonNegative(animated.clamp_to_non_negative()), keyword_info: None, } } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 80b16dcecc91..88eb8f3955a7 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -297,7 +297,7 @@ impl specified::CalcLengthPercentage { ) -> LengthPercentage { self.to_computed_value_with_zoom( context, - |abs| context.maybe_zoom_text(abs.into()).0, + |abs| context.maybe_zoom_text(abs.into()), base_size, ) } @@ -360,8 +360,8 @@ impl LengthPercentage { self.unclamped_length().px() == 0.0 && self.percentage.0 == 0.0 } - // CSSFloat doesn't implement Hash, so does CSSPixelLength. Therefore, we still use Au as the - // hash key. + // CSSFloat doesn't implement Hash, so does CSSPixelLength. Therefore, we + // still use Au as the hash key. #[allow(missing_docs)] pub fn to_hash_key(&self) -> (Au, NotNan) { ( @@ -840,14 +840,6 @@ impl NonNegativeLength { self } } - - /// Scale this NonNegativeLength. - /// We scale NonNegativeLength by zero if the factor is negative because it doesn't - /// make sense to scale a negative factor on a non-negative length. - #[inline] - pub fn scale_by(&self, factor: f32) -> Self { - Self::new(self.0.px() * factor.max(0.)) - } } impl From for NonNegativeLength { diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index bd78d376b35f..d5a617466753 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -230,7 +230,7 @@ impl<'a> Context<'a> { /// Apply text-zoom if enabled. #[cfg(feature = "gecko")] - pub fn maybe_zoom_text(&self, size: NonNegativeLength) -> NonNegativeLength { + pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength { // We disable zoom for by unsetting the // -x-text-zoom property, which leads to a false value // in mAllowZoom @@ -243,7 +243,7 @@ impl<'a> Context<'a> { /// (Servo doesn't do text-zoom) #[cfg(feature = "servo")] - pub fn maybe_zoom_text(&self, size: NonNegativeLength) -> NonNegativeLength { + pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength { size } } diff --git a/components/style/values/generics/font.rs b/components/style/values/generics/font.rs index eb8eac191f00..2972fa01c683 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -5,14 +5,13 @@ //! Generic types for font stuff. use crate::parser::{Parse, ParserContext}; -use app_units::Au; use byteorder::{BigEndian, ReadBytesExt}; use cssparser::Parser; use num_traits::One; use std::fmt::{self, Write}; use std::io::Cursor; -use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; -use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, ParseError}; +use style_traits::{StyleParseErrorKind, ToCss}; /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value #[derive( @@ -172,104 +171,6 @@ impl Parse for FontTag { } } -#[derive( - Animate, - Clone, - ComputeSquaredDistance, - Copy, - Debug, - MallocSizeOf, - PartialEq, - ToAnimatedValue, - ToAnimatedZero, - ToCss, - ToShmem, -)] -/// Additional information for keyword-derived font sizes. -pub struct KeywordInfo { - /// The keyword used - pub kw: KeywordSize, - /// A factor to be multiplied by the computed size of the keyword - #[css(skip)] - pub factor: f32, - /// An additional Au offset to add to the kw*factor in the case of calcs - #[css(skip)] - pub offset: Length, -} - -impl KeywordInfo -where - Au: Into, -{ - /// KeywordInfo value for font-size: medium - pub fn medium() -> Self { - KeywordSize::Medium.into() - } -} - -impl From for KeywordInfo -where - Au: Into, -{ - fn from(x: KeywordSize) -> Self { - KeywordInfo { - kw: x, - factor: 1., - offset: Au(0).into(), - } - } -} - -impl SpecifiedValueInfo for KeywordInfo { - fn collect_completion_keywords(f: KeywordsCollectFn) { - ::collect_completion_keywords(f); - } -} - -/// CSS font keywords -#[derive( - Animate, - Clone, - ComputeSquaredDistance, - Copy, - Debug, - MallocSizeOf, - Parse, - PartialEq, - SpecifiedValueInfo, - ToAnimatedValue, - ToAnimatedZero, - ToCss, - ToShmem, -)] -#[allow(missing_docs)] -pub enum KeywordSize { - #[css(keyword = "xx-small")] - XXSmall, - XSmall, - Small, - Medium, - Large, - XLarge, - #[css(keyword = "xx-large")] - XXLarge, - #[css(keyword = "xxx-large")] - XXXLarge, -} - -impl KeywordSize { - /// Convert to an HTML value - #[inline] - pub fn html_size(self) -> u8 { - self as u8 - } -} - -impl Default for KeywordSize { - fn default() -> Self { - KeywordSize::Medium - } -} /// A generic value for the `font-style` property. /// diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 127b1bfc2fb0..d42272e396b5 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -11,9 +11,9 @@ use crate::properties::longhands::system_font::SystemFont; use crate::values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily}; use crate::values::computed::{font as computed, Length, NonNegativeLength}; use crate::values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage}; -use crate::values::computed::{Context, ToComputedValue}; +use crate::values::computed::{CSSPixelLength, Context, ToComputedValue}; use crate::values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag}; -use crate::values::generics::font::{KeywordSize, VariationValue}; +use crate::values::generics::font::VariationValue; use crate::values::generics::NonNegative; use crate::values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX}; use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage}; @@ -481,6 +481,115 @@ impl ToComputedValue for FontStretch { } } +/// CSS font keywords +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToAnimatedZero, + ToCss, + ToShmem, +)] +#[allow(missing_docs)] +pub enum KeywordSize { + #[css(keyword = "xx-small")] + XXSmall, + XSmall, + Small, + Medium, + Large, + XLarge, + #[css(keyword = "xx-large")] + XXLarge, + #[css(keyword = "xxx-large")] + XXXLarge, +} + +impl KeywordSize { + /// Convert to an HTML value + #[inline] + pub fn html_size(self) -> u8 { + self as u8 + } +} + +impl Default for KeywordSize { + fn default() -> Self { + KeywordSize::Medium + } +} + +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + MallocSizeOf, + PartialEq, + ToAnimatedValue, + ToAnimatedZero, + ToCss, + ToShmem, +)] +/// Additional information for keyword-derived font sizes. +pub struct KeywordInfo { + /// The keyword used + pub kw: KeywordSize, + /// A factor to be multiplied by the computed size of the keyword + #[css(skip)] + pub factor: f32, + /// An additional fixed offset to add to the kw * factor in the case of + /// `calc()`. + #[css(skip)] + pub offset: CSSPixelLength, +} + +impl KeywordInfo { + /// KeywordInfo value for font-size: medium + pub fn medium() -> Self { + Self::new(KeywordSize::Medium) + } + + fn new(kw: KeywordSize) -> Self { + KeywordInfo { + kw, + factor: 1., + offset: CSSPixelLength::new(0.), + } + } + + /// Computes the final size for this font-size keyword, accounting for + /// text-zoom. + fn to_computed_value(&self, context: &Context) -> CSSPixelLength { + let base = context.maybe_zoom_text(self.kw.to_computed_value(context).0); + base * self.factor + context.maybe_zoom_text(self.offset) + } + + /// Given a parent keyword info (self), apply an additional factor/offset to + /// it. + pub fn compose(self, factor: f32, offset: CSSPixelLength) -> Self { + KeywordInfo { + kw: self.kw, + factor: self.factor * factor, + offset: self.offset * factor + offset, + } + } +} + +impl SpecifiedValueInfo for KeywordInfo { + fn collect_completion_keywords(f: KeywordsCollectFn) { + ::collect_completion_keywords(f); + } +} + #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] /// A specified font-size value pub enum FontSize { @@ -652,27 +761,6 @@ impl ToComputedValue for FontSizeAdjust { } } -/// Additional information for specified keyword-derived font sizes. -pub type KeywordInfo = generics::KeywordInfo; - -impl KeywordInfo { - /// Computes the final size for this font-size keyword, accounting for - /// text-zoom. - pub fn to_computed_value(&self, context: &Context) -> NonNegativeLength { - let base = context.maybe_zoom_text(self.kw.to_computed_value(context)); - base.scale_by(self.factor) + context.maybe_zoom_text(self.offset) - } - - /// Given a parent keyword info (self), apply an additional factor/offset to it - pub fn compose(self, factor: f32, offset: NonNegativeLength) -> Self { - KeywordInfo { - kw: self.kw, - factor: self.factor * factor, - offset: self.offset.scale_by(factor) + offset, - } - } -} - /// This is the ratio applied for font-size: larger /// and smaller by both Firefox and Chrome const LARGER_FONT_SIZE_RATIO: f32 = 1.2; @@ -790,7 +878,7 @@ impl FontSize { /// pub fn from_html_size(size: u8) -> Self { FontSize::Keyword( - match size { + KeywordInfo::new(match size { // If value is less than 1, let it be 1. 0 | 1 => KeywordSize::XSmall, 2 => KeywordSize::Small, @@ -800,8 +888,7 @@ impl FontSize { 6 => KeywordSize::XXLarge, // If value is greater than 7, let it be 7. _ => KeywordSize::XXXLarge, - } - .into(), + }) ) } @@ -819,7 +906,7 @@ impl FontSize { .get_parent_font() .clone_font_size() .keyword_info - .map(|i| i.compose(factor, Au(0).into())) + .map(|i| i.compose(factor, CSSPixelLength::new(0.))) }; let mut info = None; let size = match *self { @@ -829,16 +916,16 @@ impl FontSize { // Tack the em unit onto the factor info = compose_keyword(em); } - value.to_computed_value(context, base_size).into() + value.to_computed_value(context, base_size) }, FontSize::Length(LengthPercentage::Length(NoCalcLength::ServoCharacterWidth( value, - ))) => value.to_computed_value(base_size.resolve(context)).into(), + ))) => value.to_computed_value(base_size.resolve(context)), FontSize::Length(LengthPercentage::Length(NoCalcLength::Absolute(ref l))) => { - context.maybe_zoom_text(l.to_computed_value(context).into()) + context.maybe_zoom_text(l.to_computed_value(context)) }, FontSize::Length(LengthPercentage::Length(ref l)) => { - l.to_computed_value(context).into() + l.to_computed_value(context) }, FontSize::Length(LengthPercentage::Percentage(pc)) => { // If the parent font was keyword-derived, this is too. @@ -871,29 +958,33 @@ impl FontSize { context, FontBaseSize::InheritedStyleButStripEmUnits, ) - .length_component(); + .unclamped_length(); - info = parent.keyword_info.map(|i| i.compose(ratio, abs.into())); + info = parent.keyword_info.map(|i| i.compose(ratio, abs)); } let calc = calc.to_computed_value_zoomed(context, base_size); - calc.to_used_value(base_size.resolve(context)).into() + // FIXME(emilio): we _could_ use clamp_to_non_negative() + // everywhere, without affecting behavior in theory, since the + // others should reject negatives during parsing. But SMIL + // allows parsing negatives, and relies on us _not_ doing that + // clamping. That's so bonkers :( + CSSPixelLength::from(calc.to_used_value(base_size.resolve(context))) + .clamp_to_non_negative() }, FontSize::Keyword(i) => { // As a specified keyword, this is keyword derived info = Some(i); - i.to_computed_value(context) + i.to_computed_value(context).clamp_to_non_negative() }, FontSize::Smaller => { info = compose_keyword(1. / LARGER_FONT_SIZE_RATIO); FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO) .to_computed_value(context, base_size) - .into() }, FontSize::Larger => { info = compose_keyword(LARGER_FONT_SIZE_RATIO); FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO) .to_computed_value(context, base_size) - .into() }, FontSize::System(_) => { @@ -903,12 +994,12 @@ impl FontSize { } #[cfg(feature = "gecko")] { - context.cached_system_font.as_ref().unwrap().font_size.size + context.cached_system_font.as_ref().unwrap().font_size.size.0 } }, }; computed::FontSize { - size: size, + size: NonNegative(size), keyword_info: info, } } @@ -952,7 +1043,7 @@ impl FontSize { } if let Ok(kw) = input.try(KeywordSize::parse) { - return Ok(FontSize::Keyword(kw.into())); + return Ok(FontSize::Keyword(KeywordInfo::new(kw))); } try_match_ident_ignore_ascii_case! { input, diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index 1686b9f424dc..ebc8e8f86ee1 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -90,8 +90,7 @@ impl ToComputedValue for LineHeight { let result = match non_negative_lp.0 { LengthPercentage::Length(NoCalcLength::Absolute(ref abs)) => { context - .maybe_zoom_text(abs.to_computed_value(context).into()) - .0 + .maybe_zoom_text(abs.to_computed_value(context)) }, LengthPercentage::Length(ref length) => length.to_computed_value(context), LengthPercentage::Percentage(ref p) => FontRelativeLength::Em(p.0)