From 16d46eaf7a826452934b9ea098fcffbe748f9b9d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 28 Jul 2017 17:32:30 -0700 Subject: [PATCH 1/4] stylo: Handle text-zoom for font-size --- components/style/gecko/media_queries.rs | 5 ++++ components/style/properties/gecko.mako.rs | 3 --- .../style/properties/longhand/font.mako.rs | 16 +++++++------ components/style/values/computed/length.rs | 23 +++++++++++++++---- components/style/values/computed/mod.rs | 20 ++++++++++++++++ 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 27d8a5f6c62..63ccf68a541 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -186,6 +186,11 @@ impl Device { pub fn default_background_color(&self) -> RGBA { convert_nscolor_to_rgba(self.pres_context().mBackgroundColor) } + + /// Applies text zoom to a font-size or line-height value (see nsStyleFont::ZoomText). + pub fn zoom_text(&self, size: Au) -> Au { + size.scale_by(self.pres_context().mEffectiveTextZoom) + } } /// A expression for gecko contains a reference to the media feature, the value diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index be27f6bcdd4..edf160a0a94 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2231,9 +2231,6 @@ fn static_assert() { ) } - // FIXME(bholley): Gecko has two different sizes, one of which (mSize) is the - // 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.mSize = v.0; self.gecko.mScriptUnconstrainedSize = v.0; diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index f6b78a91749..f2f65e2dff0 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -830,17 +830,17 @@ ${helpers.single_keyword_system("font-variant-caps", value.to_computed_value(base_size.resolve(context)) } SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => { - l.to_computed_value(context) + context.maybe_zoom_text(l.to_computed_value(context)) } SpecifiedValue::Length(LengthOrPercentage::Percentage(pc)) => { base_size.resolve(context).scale_by(pc.0) } SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => { - let calc = calc.to_computed_value(context); + let calc = calc.to_computed_value_zoomed(context); calc.to_used_value(Some(base_size.resolve(context))).unwrap() } SpecifiedValue::Keyword(ref key, fraction) => { - key.to_computed_value(context).scale_by(fraction) + context.maybe_zoom_text(key.to_computed_value(context).scale_by(fraction)) } SpecifiedValue::Smaller => { FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO) @@ -960,7 +960,7 @@ ${helpers.single_keyword_system("font-variant-caps", context.builder.get_font().gecko().mGenericID != context.builder.get_parent_font().gecko().mGenericID { if let Some((kw, ratio)) = context.builder.font_size_keyword { - computed = kw.to_computed_value(context).scale_by(ratio); + computed = context.maybe_zoom_text(kw.to_computed_value(context).scale_by(ratio)); } } % endif @@ -990,7 +990,7 @@ ${helpers.single_keyword_system("font-variant-caps", // changes using the font_size_keyword. We also need to do this to // handle mathml scriptlevel changes let kw_inherited_size = context.builder.font_size_keyword.map(|(kw, ratio)| { - SpecifiedValue::Keyword(kw, ratio).to_computed_value(context) + context.maybe_zoom_text(SpecifiedValue::Keyword(kw, ratio).to_computed_value(context)) }); let parent_kw; let device = context.builder.device; @@ -1015,8 +1015,10 @@ ${helpers.single_keyword_system("font-variant-caps", pub fn cascade_initial_font_size(context: &mut Context) { // font-size's default ("medium") does not always // compute to the same value and depends on the font - let computed = longhands::font_size::get_initial_specified_value() - .to_computed_value(context); + let computed = context.maybe_zoom_text( + longhands::font_size::get_initial_specified_value() + .to_computed_value(context) + ); context.builder.mutate_font().set_font_size(computed); % if product == "gecko": let device = context.builder.device; diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 8682487f47d..29117a5cb8d 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -228,14 +228,14 @@ impl ToCss for CalcLengthOrPercentage { } } -impl ToComputedValue for specified::CalcLengthOrPercentage { - type ComputedValue = CalcLengthOrPercentage; - - fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage { +impl specified::CalcLengthOrPercentage { + /// Compute the value, zooming any absolute units by the zoom function. + fn to_computed_value_with_zoom(&self, context: &Context, zoom_fn: F) -> CalcLengthOrPercentage + where F: Fn(Au) -> Au { let mut length = Au(0); if let Some(absolute) = self.absolute { - length += absolute; + length += zoom_fn(absolute); } for val in &[self.vw.map(ViewportPercentageLength::Vw), @@ -263,6 +263,19 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { } } + /// Compute font-size or line-height taking into account text-zoom if necessary. + pub fn to_computed_value_zoomed(&self, context: &Context) -> CalcLengthOrPercentage { + self.to_computed_value_with_zoom(context, |abs| context.maybe_zoom_text(abs)) + } +} + +impl ToComputedValue for specified::CalcLengthOrPercentage { + type ComputedValue = CalcLengthOrPercentage; + + fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage { + self.to_computed_value_with_zoom(context, |abs| abs) + } + #[inline] fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self { specified::CalcLengthOrPercentage { diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 75dea7bf87b..d2b49ef5e22 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -132,6 +132,26 @@ impl<'a> Context<'a> { pub fn style(&self) -> &StyleBuilder { &self.builder } + + + /// Apply text-zoom if enabled + #[cfg(feature = "gecko")] + pub fn maybe_zoom_text(&self, size: Au) -> Au { + // We disable zoom for by unsetting the + // -x-text-zoom property, which leads to a false value + // in mAllowZoom + if self.style().get_font().gecko.mAllowZoom { + self.device().zoom_text(size) + } else { + size + } + } + + /// (Servo doesn't do text-zoom) + #[cfg(feature = "servo")] + pub fn maybe_zoom_text(&self, size: Au) -> Au { + size + } } /// An iterator over a slice of computed values From 613012d9fb08685d3be72519fcb08f157d9492d7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 30 Jul 2017 20:50:05 -0700 Subject: [PATCH 2/4] stylo: Handle text-zoom for scriptminsize --- components/style/properties/gecko.mako.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index edf160a0a94..e97122681ec 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2241,8 +2241,8 @@ fn static_assert() { pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, parent: &Self, device: &Device) -> Option { - let (adjusted_size, adjusted_unconstrained_size) - = self.calculate_script_level_size(parent); + let (adjusted_size, adjusted_unconstrained_size) = + self.calculate_script_level_size(parent, device); // In this case, we have been unaffected by scriptminsize, ignore it if parent.gecko.mSize == parent.gecko.mScriptUnconstrainedSize && adjusted_size == adjusted_unconstrained_size { @@ -2321,7 +2321,7 @@ fn static_assert() { /// will be set to the value of that unit computed against the parent /// unconstrained size, whereas the font size will be set computing against /// the parent font size. - pub fn calculate_script_level_size(&self, parent: &Self) -> (Au, Au) { + pub fn calculate_script_level_size(&self, parent: &Self, device: &Device) -> (Au, Au) { use std::cmp; let delta = self.gecko.mScriptLevel - parent.gecko.mScriptLevel; @@ -2333,8 +2333,11 @@ fn static_assert() { return (parent_size, parent_unconstrained_size) } - /// XXXManishearth this should also handle text zoom - let min = Au(parent.gecko.mScriptMinSize); + + let mut min = Au(parent.gecko.mScriptMinSize); + if self.gecko.mAllowZoom { + min = device.zoom_text(min); + } let scale = (parent.gecko.mScriptSizeMultiplier as f32).powi(delta as i32); @@ -2371,7 +2374,7 @@ fn static_assert() { kw_inherited_size: Option, device: &Device) -> bool { let (adjusted_size, adjusted_unconstrained_size) - = self.calculate_script_level_size(parent); + = self.calculate_script_level_size(parent, device); if adjusted_size.0 != parent.gecko.mSize || adjusted_unconstrained_size.0 != parent.gecko.mScriptUnconstrainedSize { // This is incorrect. When there is both a keyword size being inherited From fb107d8cd544a1aa280803c0cff64e9284cc711b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 30 Jul 2017 20:59:03 -0700 Subject: [PATCH 3/4] stylo: Handle text-zoom for line-height --- components/style/values/specified/text.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index 2c0395128c6..495b3eebd33 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -95,7 +95,7 @@ impl ToComputedValue for LineHeight { GenericLineHeight::Number(number.to_computed_value(context)) }, GenericLineHeight::Length(LengthOrPercentage::Length(ref length)) => { - GenericLineHeight::Length(length.to_computed_value(context)) + GenericLineHeight::Length(context.maybe_zoom_text(length.to_computed_value(context))) }, GenericLineHeight::Length(LengthOrPercentage::Percentage(p)) => { let font_relative_length = @@ -103,7 +103,7 @@ impl ToComputedValue for LineHeight { GenericLineHeight::Length(font_relative_length.to_computed_value(context)) }, GenericLineHeight::Length(LengthOrPercentage::Calc(ref calc)) => { - let computed_calc = calc.to_computed_value(context); + let computed_calc = calc.to_computed_value_zoomed(context); let font_relative_length = Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(computed_calc.percentage()))); let absolute_length = computed_calc.unclamped_length(); From 0e3f7d782bf671f3a7e7b7777fd705e8128b2507 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 30 Jul 2017 21:56:47 -0700 Subject: [PATCH 4/4] stylo: Disable text-zoom for --- components/style/gecko/media_queries.rs | 4 +++ components/style/gecko/wrapper.rs | 15 ++++++++ components/style/properties/gecko.mako.rs | 23 +++++++++++- .../style/properties/longhand/font.mako.rs | 35 +++++++++++++++++++ .../style/properties/properties.mako.rs | 18 ++++++++++ 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 63ccf68a541..070e2698e94 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -191,6 +191,10 @@ impl Device { pub fn zoom_text(&self, size: Au) -> Au { size.scale_by(self.pres_context().mEffectiveTextZoom) } + /// Un-apply text zoom (see nsStyleFont::UnzoomText). + pub fn unzoom_text(&self, size: Au) -> Au { + size.scale_by(1. / self.pres_context().mEffectiveTextZoom) + } } /// A expression for gecko contains a reference to the media feature, the value diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 1c0208c1c40..79c7bb26403 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -1402,6 +1402,7 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> { where V: Push, { use properties::longhands::_x_lang::SpecifiedValue as SpecifiedLang; + use properties::longhands::_x_text_zoom::SpecifiedValue as SpecifiedZoom; use properties::longhands::color::SpecifiedValue as SpecifiedColor; use properties::longhands::text_align::SpecifiedValue as SpecifiedTextAlign; use values::specified::color::Color; @@ -1433,6 +1434,15 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> { let arc = Arc::new(global_style_data.shared_lock.wrap(pdb)); ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints) }; + static ref SVG_TEXT_DISABLE_ZOOM_RULE: ApplicableDeclarationBlock = { + let global_style_data = &*GLOBAL_STYLE_DATA; + let pdb = PropertyDeclarationBlock::with_one( + PropertyDeclaration::XTextZoom(SpecifiedZoom(false)), + Importance::Normal + ); + let arc = Arc::new(global_style_data.shared_lock.wrap(pdb)); + ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints) + }; }; let ns = self.get_namespace(); @@ -1445,6 +1455,11 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> { hints.push(TABLE_COLOR_RULE.clone()); } } + if ns == &*Namespace(atom!("http://www.w3.org/2000/svg")) { + if self.get_local_name().as_ptr() == atom!("text").as_ptr() { + hints.push(SVG_TEXT_DISABLE_ZOOM_RULE.clone()); + } + } let declarations = unsafe { Gecko_GetHTMLPresentationAttrDeclarationBlock(self.0) }; let declarations: Option<&RawOffsetArc>> = declarations.and_then(|s| s.as_arc_opt()); diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index e97122681ec..d35b6bf4b10 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2057,7 +2057,7 @@ fn static_assert() { font-variant-east-asian font-variant-ligatures font-variant-numeric font-language-override font-feature-settings font-variation-settings - -moz-min-font-size-ratio""" + -moz-min-font-size-ratio -x-text-zoom""" %> <%self:impl_trait style_struct_name="Font" skip_longhands="${skip_font_longhands}" @@ -2231,6 +2231,12 @@ fn static_assert() { ) } + pub fn unzoom_fonts(&mut self, device: &Device) { + self.gecko.mSize = device.unzoom_text(Au(self.gecko.mSize)).0; + self.gecko.mScriptUnconstrainedSize = device.unzoom_text(Au(self.gecko.mScriptUnconstrainedSize)).0; + self.gecko.mFont.size = device.unzoom_text(Au(self.gecko.mFont.size)).0; + } + pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) { self.gecko.mSize = v.0; self.gecko.mScriptUnconstrainedSize = v.0; @@ -2465,6 +2471,21 @@ fn static_assert() { } } + #[allow(non_snake_case)] + pub fn set__x_text_zoom(&mut self, v: longhands::_x_text_zoom::computed_value::T) { + self.gecko.mAllowZoom = v.0; + } + + #[allow(non_snake_case)] + pub fn copy__x_text_zoom_from(&mut self, other: &Self) { + self.gecko.mAllowZoom = other.gecko.mAllowZoom; + } + + #[allow(non_snake_case)] + pub fn reset__x_text_zoom(&mut self, other: &Self) { + self.copy__x_text_zoom_from(other) + } + #[allow(non_snake_case)] pub fn reset__x_lang(&mut self, other: &Self) { self.copy__x_lang_from(other) diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index f2f65e2dff0..cbf6df1f44e 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -2383,6 +2383,41 @@ ${helpers.single_keyword("-moz-math-variant", } +<%helpers:longhand name="-x-text-zoom" products="gecko" animation_value_type="none" internal="True" + spec="Internal (not web-exposed)"> + use values::computed::ComputedValueAsSpecified; + pub use self::computed_value::T as SpecifiedValue; + + impl ComputedValueAsSpecified for SpecifiedValue {} + no_viewport_percentage!(SpecifiedValue); + + pub mod computed_value { + use std::fmt; + use style_traits::ToCss; + + impl ToCss for T { + fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { + Ok(()) + } + } + + #[derive(Clone, Debug, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + /// text-zoom. Enable if true, disable if false + pub struct T(pub bool); + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(true) + } + + pub fn parse<'i, 't>(_context: &ParserContext, _input: &mut Parser<'i, 't>) + -> Result> { + debug_assert!(false, "Should be set directly by presentation attributes only."); + Err(StyleParseError::UnspecifiedError.into()) + } + % if product == "gecko": pub mod system_font { diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index d98e173db5b..2a5696628ed 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -608,6 +608,7 @@ impl LonghandId { LonghandId::AnimationName | LonghandId::TransitionProperty | LonghandId::XLang | + LonghandId::XTextZoom | LonghandId::MozScriptLevel | LonghandId::MozMinFontSizeRatio | % endif @@ -3207,6 +3208,23 @@ where let mut _skip_font_family = false; % if product == "gecko": + + // is not affected by text zoom, and it uses a preshint to + // disable it. We fix up the struct when this happens by unzooming + // its contained font values, which will have been zoomed in the parent + if seen.contains(LonghandId::XTextZoom) { + let zoom = context.builder.get_font().gecko().mAllowZoom; + let parent_zoom = context.style().get_parent_font().gecko().mAllowZoom; + if zoom != parent_zoom { + debug_assert!(!zoom, + "We only ever disable text zoom (in svg:text), never enable it"); + // can't borrow both device and font, use the take/put machinery + let mut font = context.builder.take_font(); + font.unzoom_fonts(context.device()); + context.builder.put_font(font); + } + } + // Whenever a single generic value is specified, gecko will do a bunch of // recalculation walking up the rule tree, including handling the font-size stuff. // It basically repopulates the font struct with the default font for a given