diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs index edd90a36ab5..5087124c701 100644 --- a/components/style/gecko/generated/bindings.rs +++ b/components/style/gecko/generated/bindings.rs @@ -1304,6 +1304,11 @@ extern "C" { pres_context: RawGeckoPresContextBorrowed); } +extern "C" { + pub fn Gecko_nsStyleFont_FixupMinFontSize(font: *mut nsStyleFont, + pres_context: + RawGeckoPresContextBorrowed); +} extern "C" { pub fn Gecko_GetBaseSize(lang: *mut nsIAtom) -> FontSizePrefs; } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index a611c1c7f09..b074fe7a837 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1487,7 +1487,8 @@ fn static_assert() { font-synthesis -x-lang font-variant-alternates font-variant-east-asian font-variant-ligatures font-variant-numeric font-language-override - font-feature-settings font-variation-settings""" + font-feature-settings font-variation-settings + -moz-min-font-size-ratio""" %> <%self:impl_trait style_struct_name="Font" skip_longhands="${skip_font_longhands}" @@ -1630,7 +1631,6 @@ fn static_assert() { // actual computed size, and the other of which (mFont.size) is the 'display // size' which takes font zooming into account. We don't handle font zooming yet. pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) { - self.gecko.mFont.size = v.0; self.gecko.mSize = v.0; self.gecko.mScriptUnconstrainedSize = v.0; } @@ -1638,21 +1638,27 @@ fn static_assert() { /// Set font size, taking into account scriptminsize and scriptlevel /// Returns Some(size) if we have to recompute the script unconstrained size pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, - parent: &Self) -> Option { + parent: &Self, + device: &Device) -> Option { let (adjusted_size, adjusted_unconstrained_size) = self.calculate_script_level_size(parent); // In this case, we have been unaffected by scriptminsize, ignore it if parent.gecko.mSize == parent.gecko.mScriptUnconstrainedSize && adjusted_size == adjusted_unconstrained_size { self.set_font_size(v); + self.fixup_font_min_size(device); None } else { - self.gecko.mFont.size = v.0; self.gecko.mSize = v.0; + self.fixup_font_min_size(device); Some(Au(parent.gecko.mScriptUnconstrainedSize)) } } + pub fn fixup_font_min_size(&mut self, device: &Device) { + unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, &*device.pres_context) } + } + pub fn apply_unconstrained_font_size(&mut self, v: Au) { self.gecko.mScriptUnconstrainedSize = v.0; } @@ -1761,7 +1767,8 @@ fn static_assert() { /// /// Returns true if the inherited keyword size was actually used pub fn inherit_font_size_from(&mut self, parent: &Self, - kw_inherited_size: Option) -> bool { + kw_inherited_size: Option, + device: &Device) -> bool { let (adjusted_size, adjusted_unconstrained_size) = self.calculate_script_level_size(parent); if adjusted_size.0 != parent.gecko.mSize || @@ -1780,23 +1787,23 @@ fn static_assert() { // In the case that MathML has given us an adjusted size, apply it. // Keep track of the unconstrained adjusted size. - self.gecko.mFont.size = adjusted_size.0; self.gecko.mSize = adjusted_size.0; self.gecko.mScriptUnconstrainedSize = adjusted_unconstrained_size.0; + self.fixup_font_min_size(device); false } else if let Some(size) = kw_inherited_size { // Parent element was a keyword-derived size. - self.gecko.mFont.size = size.0; self.gecko.mSize = size.0; // MathML constraints didn't apply here, so we can ignore this. self.gecko.mScriptUnconstrainedSize = size.0; + self.fixup_font_min_size(device); true } else { // MathML isn't affecting us, and our parent element does not // have a keyword-derived size. Set things normally. - self.gecko.mFont.size = parent.gecko.mFont.size; self.gecko.mSize = parent.gecko.mSize; self.gecko.mScriptUnconstrainedSize = parent.gecko.mScriptUnconstrainedSize; + self.fixup_font_min_size(device); false } } @@ -1899,6 +1906,21 @@ fn static_assert() { } ${impl_simple_copy('font_variant_numeric', 'mFont.variantNumeric')} + + #[allow(non_snake_case)] + pub fn set__moz_min_font_size_ratio(&mut self, v: longhands::_moz_min_font_size_ratio::computed_value::T) { + let percentage = if v.0 > 255. { + 255. + } else if v.0 < 0. { + 0. + } else { + v.0 + }; + + self.gecko.mMinFontSizeRatio = percentage as u8; + } + + ${impl_simple_copy('_moz_min_font_size_ratio', 'mMinFontSizeRatio')} <%def name="impl_copy_animation_or_transition_value(type, ident, gecko_ffi_name)"> diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index d4e6f1de977..88292db54c8 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -925,10 +925,12 @@ ${helpers.single_keyword_system("font-variant-caps", } % endif - let parent_unconstrained = context.mutate_style() - .mutate_font() - .apply_font_size(computed, - parent); + let parent_unconstrained = { + let (style, device) = context.mutate_style_with_device(); + + style.mutate_font().apply_font_size(computed, parent, device) + }; + if let Some(parent) = parent_unconstrained { let new_unconstrained = specified_value @@ -946,13 +948,14 @@ ${helpers.single_keyword_system("font-variant-caps", let kw_inherited_size = context.style().font_size_keyword.map(|(kw, ratio)| { SpecifiedValue::Keyword(kw, ratio).to_computed_value(context) }); - let used_kw = context.mutate_style().mutate_font() - .inherit_font_size_from(parent, kw_inherited_size); + let parent_kw = context.inherited_style.font_computation_data.font_size_keyword; + let (style, device) = context.mutate_style_with_device(); + let used_kw = style.mutate_font() + .inherit_font_size_from(parent, kw_inherited_size, device); if used_kw { - context.mutate_style().font_size_keyword = - context.inherited_style.font_computation_data.font_size_keyword; + style.font_size_keyword = parent_kw; } else { - context.mutate_style().font_size_keyword = None; + style.font_size_keyword = None; } } @@ -961,9 +964,12 @@ ${helpers.single_keyword_system("font-variant-caps", // compute to the same value and depends on the font let computed = longhands::font_size::get_initial_specified_value() .to_computed_value(context); - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_font_size(computed); - context.mutate_style().font_size_keyword = Some((Default::default(), 1.)); + let (style, _device) = context.mutate_style_with_device(); + style.mutate_font().set_font_size(computed); + % if product == "gecko": + style.mutate_font().fixup_font_min_size(_device); + % endif + style.font_size_keyword = Some((Default::default(), 1.)); } @@ -1813,7 +1819,6 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control- """ %> <%helpers:longhand name="font-variation-settings" products="gecko" animation_value_type="none" - boxed="True" spec="${variation_spec}"> use values::computed::ComputedValueAsSpecified; use values::generics::FontSettings; @@ -2387,3 +2392,11 @@ ${helpers.single_keyword("-moz-osx-font-smoothing", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth)", animation_value_type="none", need_clone=True)} + +${helpers.predefined_type("-moz-min-font-size-ratio", + "Percentage", + "computed::Percentage::hundred()", + animation_value_type="none", + products="gecko", + internal=True, + spec="Nonstandard (Internal-only)")} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 5036055d379..8c396ed25ae 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -656,6 +656,7 @@ impl LonghandId { LonghandId::TransitionProperty | LonghandId::XLang | LonghandId::MozScriptLevel | + LonghandId::MozMinFontSizeRatio | % endif LonghandId::FontSize | LonghandId::FontFamily | @@ -1573,6 +1574,7 @@ pub mod style_structs { use super::longhands; use std::hash::{Hash, Hasher}; use logical_geometry::WritingMode; + use media_queries::Device; % for style_struct in data.active_style_structs(): % if style_struct.name == "Font": @@ -1683,14 +1685,15 @@ pub mod style_structs { /// (Servo does not handle MathML, so this just calls copy_font_size_from) pub fn inherit_font_size_from(&mut self, parent: &Self, - _: Option) -> bool { + _: Option, _: &Device) -> bool { self.copy_font_size_from(parent); false } /// (Servo does not handle MathML, so this just calls set_font_size) pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, - _: &Self) -> Option { + _: &Self, + _: &Device) -> Option { self.set_font_size(v); None } @@ -2668,17 +2671,6 @@ pub fn apply_declarations<'a, F, I>(device: &Device, continue } - // The computed value of some properties depends on the - // (sometimes computed) value of *other* properties. - // - // So we classify properties into "early" and "other", such that - // the only dependencies can be from "other" to "early". - // - // We iterate applicable_declarations twice, first cascading - // "early" properties then "other". - // - // Unfortunately, it’s not easy to check that this - // classification is correct. if % if category_to_cascade_now == "early": ! @@ -2758,6 +2750,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device, // scriptlevel changes. } else if seen.contains(LonghandId::XLang) || seen.contains(LonghandId::MozScriptLevel) || + seen.contains(LonghandId::MozMinFontSizeRatio) || font_family.is_some() { let discriminant = LonghandId::FontSize as usize; let size = PropertyDeclaration::CSSWideKeyword( diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 10b5014483b..f92f2c9eeac 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -104,6 +104,8 @@ impl<'a> Context<'a> { pub fn style(&self) -> &StyleBuilder { &self.style } /// A mutable reference to the current style. pub fn mutate_style(&mut self) -> &mut StyleBuilder<'a> { &mut self.style } + /// Get a mutable reference to the current style as well as the device + pub fn mutate_style_with_device(&mut self) -> (&mut StyleBuilder<'a>, &Device) { (&mut self.style, &self.device) } } /// An iterator over a slice of computed values diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 4c3adfc4d63..1311b7c7404 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -734,6 +734,12 @@ impl Percentage { pub fn parse_non_negative(input: &mut Parser) -> Result { Self::parse_with_clamping_mode(input, AllowedNumericType::NonNegative) } + + /// 100% + #[inline] + pub fn hundred() -> Self { + Percentage(1.) + } } impl Parse for Percentage { diff --git a/tests/unit/style/parsing/font.rs b/tests/unit/style/parsing/font.rs index 607f0ecb967..e092fd88989 100644 --- a/tests/unit/style/parsing/font.rs +++ b/tests/unit/style/parsing/font.rs @@ -5,8 +5,7 @@ use parsing::parse; use style::properties::longhands::{font_feature_settings, font_weight}; use style::properties::longhands::font_feature_settings::SpecifiedValue; -use style::properties::longhands::font_feature_settings::computed_value; -use style::properties::longhands::font_feature_settings::computed_value::FeatureTagValue; +use style::values::generics::{FontSettings, FontSettingTag, FontSettingTagInt}; use style_traits::ToCss; #[test] @@ -15,7 +14,7 @@ fn font_feature_settings_should_parse_properly() { use std::io::Cursor; let normal = parse_longhand!(font_feature_settings, "normal"); - let normal_computed = SpecifiedValue::Value(computed_value::T::Normal); + let normal_computed = SpecifiedValue::Value(FontSettings::Normal); assert_eq!(normal, normal_computed); let mut a_d_bytes = Cursor::new(b"abcd"); @@ -25,33 +24,33 @@ fn font_feature_settings_should_parse_properly() { let efgh = e_h_bytes.read_u32::().unwrap(); let on = parse_longhand!(font_feature_settings, "\"abcd\" on"); - let on_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 1 } + let on_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(1) } ])); assert_eq!(on, on_computed); let off = parse_longhand!(font_feature_settings, "\"abcd\" off"); - let off_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 0 } + let off_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(0) } ])); assert_eq!(off, off_computed); let no_value = parse_longhand!(font_feature_settings, "\"abcd\""); - let no_value_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 1 } + let no_value_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(1) } ])); assert_eq!(no_value, no_value_computed); let pos_integer = parse_longhand!(font_feature_settings, "\"abcd\" 100"); - let pos_integer_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 100 } + let pos_integer_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(100) } ])); assert_eq!(pos_integer, pos_integer_computed); let multiple = parse_longhand!(font_feature_settings, "\"abcd\" off, \"efgh\""); - let multiple_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 0 }, - FeatureTagValue { tag: efgh, value: 1 } + let multiple_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(0) }, + FontSettingTag { tag: efgh, value: FontSettingTagInt(1) } ])); assert_eq!(multiple, multiple_computed); }