diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index 2badbce35fe..7c0b36800c2 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -118,7 +118,7 @@ impl FontContext { let layout_font_group_cache_key = LayoutFontGroupCacheKey { pointer: style.clone(), - size: Au::from(style.font_size), + size: style.font_size.size(), }; if let Some(ref cached_font_group) = self.layout_font_group_cache.get( &layout_font_group_cache_key) { @@ -148,7 +148,7 @@ impl FontContext { Some(ref cached_font_ref) => { let cached_font = (*cached_font_ref).borrow(); if cached_font.descriptor == desc && - cached_font.requested_pt_size == Au::from(style.font_size) && + cached_font.requested_pt_size == style.font_size.size() && cached_font.variant == style.font_variant_caps { fonts.push((*cached_font_ref).clone()); cache_hit = true; @@ -166,7 +166,7 @@ impl FontContext { Some(template_info) => { let layout_font = self.create_layout_font(template_info.font_template, desc.clone(), - Au::from(style.font_size), + style.font_size.size(), style.font_variant_caps, template_info.font_key); let font = match layout_font { @@ -199,7 +199,7 @@ impl FontContext { for cached_font_entry in &self.fallback_font_cache { let cached_font = cached_font_entry.font.borrow(); if cached_font.descriptor == desc && - cached_font.requested_pt_size == Au::from(style.font_size) && + cached_font.requested_pt_size == style.font_size.size() && cached_font.variant == style.font_variant_caps { fonts.push(cached_font_entry.font.clone()); cache_hit = true; @@ -211,7 +211,7 @@ impl FontContext { let template_info = self.font_cache_thread.last_resort_font_template(desc.clone()); let layout_font = self.create_layout_font(template_info.font_template, desc.clone(), - Au::from(style.font_size), + style.font_size.size(), style.font_variant_caps, template_info.font_key); match layout_font { diff --git a/components/layout/multicol.rs b/components/layout/multicol.rs index 8d59092956d..2cb181f1f97 100644 --- a/components/layout/multicol.rs +++ b/components/layout/multicol.rs @@ -97,10 +97,10 @@ impl Flow for MulticolFlow { { let column_style = self.block_flow.fragment.style.get_column(); - let column_gap = Au::from(match column_style.column_gap { - Either::First(len) => len, - Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size, - }); + let column_gap = match column_style.column_gap { + Either::First(len) => len.into(), + Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size.size(), + }; let mut column_count; if let Either::First(column_width) = column_style.column_width { diff --git a/components/layout/text.rs b/components/layout/text.rs index 23cd69a89db..1915b2b878d 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -447,7 +447,7 @@ pub fn font_metrics_for_style(font_context: &mut FontContext, font_style: ::Serv /// Returns the line block-size needed by the given computed style and font size. pub fn line_height_from_style(style: &ComputedValues, metrics: &FontMetrics) -> Au { - let font_size = Au::from(style.get_font().font_size); + let font_size = style.get_font().font_size.size(); match style.get_inheritedtext().line_height { LineHeight::Normal => Au::from(metrics.line_gap), LineHeight::Number(l) => font_size.scale_by(l.0), diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 2765547aaf9..2e298431820 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -78,7 +78,7 @@ impl Device { pres_context: pres_context, default_values: ComputedValues::default_values(unsafe { &*pres_context }), // FIXME(bz): Seems dubious? - root_font_size: AtomicIsize::new(font_size::get_initial_value().0.to_i32_au() as isize), + root_font_size: AtomicIsize::new(font_size::get_initial_value().size().0 as isize), body_text_color: AtomicUsize::new(unsafe { &*pres_context }.mDefaultColor as usize), used_root_font_size: AtomicBool::new(false), used_viewport_size: AtomicBool::new(false), diff --git a/components/style/matching.rs b/components/style/matching.rs index 9018727f996..faa62cae051 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -511,7 +511,6 @@ pub trait MatchMethods : TElement { mut new_styles: ResolvedElementStyles, important_rules_changed: bool, ) -> ChildCascadeRequirement { - use app_units::Au; use dom::TNode; use std::cmp; @@ -553,7 +552,7 @@ pub trait MatchMethods : TElement { if old_styles.primary.as_ref().map_or(true, |s| s.get_font().clone_font_size() != new_font_size) { debug_assert!(self.owner_doc_matches_for_testing(device)); - device.set_root_font_size(Au::from(new_font_size)); + device.set_root_font_size(new_font_size.size()); // If the root font-size changed since last time, and something // in the document did use rem units, ensure we recascade the // entire tree. diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 1606a2dc0df..c5cad20c6ba 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2167,8 +2167,8 @@ fn static_assert() { } pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) { - self.gecko.mSize = v.0.to_i32_au(); - self.gecko.mScriptUnconstrainedSize = v.0.to_i32_au(); + self.gecko.mSize = v.size().0; + self.gecko.mScriptUnconstrainedSize = v.size().0; } /// Set font size, taking into account scriptminsize and scriptlevel @@ -2185,7 +2185,7 @@ fn static_assert() { self.fixup_font_min_size(device); None } else { - self.gecko.mSize = v.0.to_i32_au(); + self.gecko.mSize = v.size().0; self.fixup_font_min_size(device); Some(Au(parent.gecko.mScriptUnconstrainedSize).into()) } @@ -2348,7 +2348,10 @@ fn static_assert() { } pub fn clone_font_size(&self) -> longhands::font_size::computed_value::T { - Au(self.gecko.mSize).into() + longhands::font_size::computed_value::T { + size: Au(self.gecko.mSize).into(), + info: None, // XXXManishearth this is a placeholder + } } pub fn set_font_weight(&mut self, v: longhands::font_weight::computed_value::T) { diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 6092f80289b..d41cd314bb2 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -596,7 +596,7 @@ ${helpers.single_keyword_system("font-variant-caps", } -<%helpers:longhand name="font-size" animation_value_type="NonNegativeLength" +<%helpers:longhand name="font-size" animation_value_type="ComputedValue" flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER" allow_quirks="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size"> use app_units::Au; @@ -648,13 +648,56 @@ ${helpers.single_keyword_system("font-variant-caps", } pub mod computed_value { + use app_units::Au; + use std::fmt; + use style_traits::ToCss; use values::computed::NonNegativeLength; - pub type T = NonNegativeLength; + + #[derive(Copy, Clone, PartialEq, Debug)] + #[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct T { + pub size: NonNegativeLength, + pub info: Option, + } + + #[derive(Copy, Clone, PartialEq, Debug)] + #[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct KeywordInfo { + pub kw: super::KeywordSize, + pub factor: f32, + pub offset: NonNegativeLength, + } + + impl KeywordInfo { + /// 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, + } + } + } + + impl T { + pub fn size(self) -> Au { + self.size.into() + } + } + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.size.to_css(dest) + } + } } /// CSS font keywords #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] + #[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum KeywordSize { XXSmall = 1, // This is to enable the NonZero optimization @@ -727,7 +770,7 @@ ${helpers.single_keyword_system("font-variant-caps", impl ToComputedValue for KeywordSize { type ComputedValue = NonNegativeLength; #[inline] - fn to_computed_value(&self, _: &Context) -> computed_value::T { + fn to_computed_value(&self, _: &Context) -> NonNegativeLength { // https://drafts.csswg.org/css-fonts-3/#font-size-prop use values::FONT_MEDIUM_PX; match *self { @@ -743,7 +786,7 @@ ${helpers.single_keyword_system("font-variant-caps", } #[inline] - fn from_computed_value(_: &computed_value::T) -> Self { + fn from_computed_value(_: &NonNegativeLength) -> Self { unreachable!() } } @@ -751,7 +794,7 @@ ${helpers.single_keyword_system("font-variant-caps", impl ToComputedValue for KeywordSize { type ComputedValue = NonNegativeLength; #[inline] - fn to_computed_value(&self, cx: &Context) -> computed_value::T { + fn to_computed_value(&self, cx: &Context) -> NonNegativeLength { use gecko_bindings::structs::nsIAtom; use values::specified::length::au_to_int_px; // Data from nsRuleNode.cpp in Gecko @@ -792,7 +835,7 @@ ${helpers.single_keyword_system("font-variant-caps", } #[inline] - fn from_computed_value(_: &computed_value::T) -> Self { + fn from_computed_value(_: &NonNegativeLength) -> Self { unreachable!() } } @@ -863,11 +906,18 @@ ${helpers.single_keyword_system("font-variant-caps", &self, context: &Context, base_size: FontBaseSize, - ) -> NonNegativeLength { + ) -> computed_value::T { use values::specified::length::FontRelativeLength; - match *self { + let mut info = None; + let size = match *self { SpecifiedValue::Length(LengthOrPercentage::Length( NoCalcLength::FontRelative(value))) => { + if let FontRelativeLength::Em(em) = value { + // If the parent font was keyword-derived, this is too. + // Tack the em unit onto the factor + info = context.style().get_parent_font() + .clone_font_size().info.map(|i| i.compose(em, Au(0).into())); + } value.to_computed_value(context, base_size).into() } SpecifiedValue::Length(LengthOrPercentage::Length( @@ -876,21 +926,45 @@ ${helpers.single_keyword_system("font-variant-caps", } SpecifiedValue::Length(LengthOrPercentage::Length( NoCalcLength::Absolute(ref l))) => { - context.maybe_zoom_text(l.to_computed_value(context)).into() + context.maybe_zoom_text(l.to_computed_value(context).into()) } SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => { l.to_computed_value(context).into() } SpecifiedValue::Length(LengthOrPercentage::Percentage(pc)) => { + // If the parent font was keyword-derived, this is too. + // Tack the % onto the factor + info = context.style().get_parent_font().clone_font_size().info.map(|i| i.compose(pc.0, Au(0).into())); base_size.resolve(context).scale_by(pc.0).into() } SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => { + let parent = context.style().get_parent_font().clone_font_size(); + // if we contain em/% units and the parent was keyword derived, this is too + // Extract the ratio/offset and compose it + if (calc.em.is_some() || calc.percentage.is_some()) && parent.info.is_some() { + let ratio = calc.em.unwrap_or(0.) + calc.percentage.map_or(0., |pc| pc.0); + // Compute it, but shave off the font-relative part (em, %) + // This will mean that other font-relative units like ex and ch will be computed against + // the old font even when the font changes. There's no particular "right answer" for what + // to do here -- Gecko recascades as if the font had changed, we instead track the changes + // and reapply, which means that we carry over old computed ex/ch values whilst Gecko + // recomputes new ones. This is enough of an edge case to not really matter. + let abs = calc.to_computed_value_zoomed(context, FontBaseSize::Custom(Au(0).into())) + .length_component().into(); + info = parent.info.map(|i| i.compose(ratio, abs)); + } let calc = calc.to_computed_value_zoomed(context, base_size); calc.to_used_value(Some(base_size.resolve(context))).unwrap().into() } - SpecifiedValue::Keyword(ref key, fraction, offset) => { + SpecifiedValue::Keyword(key, fraction, offset) => { + // As a specified keyword, this is keyword derived + info = Some(computed_value::KeywordInfo { + kw: key, + factor: fraction, + offset: offset, + }); let key_len = key.to_computed_value(context).scale_by(fraction) + offset; - context.maybe_zoom_text(key_len.0).into() + context.maybe_zoom_text(key_len).into() } SpecifiedValue::Smaller => { FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO) @@ -903,17 +977,25 @@ ${helpers.single_keyword_system("font-variant-caps", SpecifiedValue::System(_) => { <%self:nongecko_unreachable> - context.cached_system_font.as_ref().unwrap().font_size + context.cached_system_font.as_ref().unwrap().font_size.size } - } + }; + computed_value::T { size, info } } } #[inline] #[allow(missing_docs)] pub fn get_initial_value() -> computed_value::T { - NonNegativeLength::new(FONT_MEDIUM_PX as f32) + computed_value::T { + size: Au::from_px(FONT_MEDIUM_PX).into(), + info: Some(computed_value::KeywordInfo { + kw: KeywordSize::Medium, + factor: 1., + offset: Au(0).into(), + }) + } } #[inline] @@ -933,7 +1015,7 @@ ${helpers.single_keyword_system("font-variant-caps", #[inline] fn from_computed_value(computed: &computed_value::T) -> Self { SpecifiedValue::Length(LengthOrPercentage::Length( - ToComputedValue::from_computed_value(&computed.0) + ToComputedValue::from_computed_value(&computed.size.0) )) } } @@ -980,7 +1062,7 @@ ${helpers.single_keyword_system("font-variant-caps", #[allow(unused_mut)] pub fn cascade_specified_font_size(context: &mut Context, specified_value: &SpecifiedValue, - mut computed: NonNegativeLength) { + mut computed: computed_value::T) { if let SpecifiedValue::Keyword(kw, fraction, offset) = *specified_value { context.builder.font_size_keyword = Some((kw, fraction, offset)); } else if let Some((ratio, abs)) = specified_value.as_font_ratio(context) { @@ -1011,8 +1093,15 @@ ${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, offset)) = context.builder.font_size_keyword { - let len = kw.to_computed_value(context).scale_by(ratio) + offset; - computed = context.maybe_zoom_text(len.0).into(); + let len = context.maybe_zoom_text(kw.to_computed_value(context).scale_by(ratio) + offset); + computed = computed_value::T { + size: len, + info: Some(computed_value::KeywordInfo { + kw: kw, + factor: ratio, + offset: offset + }), + } } } % endif @@ -1031,7 +1120,7 @@ ${helpers.single_keyword_system("font-variant-caps", .to_computed_value_against(context, FontBaseSize::Custom(Au::from(parent))); context.builder .mutate_font() - .apply_unconstrained_font_size(new_unconstrained); + .apply_unconstrained_font_size(new_unconstrained.size); } } @@ -1042,8 +1131,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, offset)| { - let len = SpecifiedValue::Keyword(kw, ratio, offset).to_computed_value(context); - context.maybe_zoom_text(len.0).into() + context.maybe_zoom_text(SpecifiedValue::Keyword(kw, ratio, offset).to_computed_value(context).size) }); let parent_kw; let device = context.builder.device; @@ -1068,10 +1156,9 @@ ${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 = context.maybe_zoom_text( - longhands::font_size::get_initial_specified_value() - .to_computed_value(context).0 - ).into(); + let mut computed = longhands::font_size::get_initial_specified_value() + .to_computed_value(context); + computed.size = context.maybe_zoom_text(computed.size); context.builder.mutate_font().set_font_size(computed); % if product == "gecko": let device = context.builder.device; @@ -2552,7 +2639,7 @@ ${helpers.single_keyword("-moz-math-variant", let weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight); let ret = ComputedSystemFont { font_family: longhands::font_family::computed_value::T(family), - font_size: Au(system.size).into(), + font_size: longhands::font_size::computed_value::T { size: Au(system.size).into(), info: None }, font_weight: weight, font_size_adjust: longhands::font_size_adjust::computed_value ::T::from_gecko_adjust(system.sizeAdjust), diff --git a/components/style/rule_cache.rs b/components/style/rule_cache.rs index 7862414f530..be0bcc43c3b 100644 --- a/components/style/rule_cache.rs +++ b/components/style/rule_cache.rs @@ -52,7 +52,7 @@ impl RuleCacheConditions { } if let Some(fs) = self.font_size { - if style.get_font().clone_font_size() != fs { + if style.get_font().clone_font_size().size != fs { return false; } } diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index f3a8670adcf..bd6b2a1f003 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -67,7 +67,7 @@ impl Device { viewport_size, device_pixel_ratio, // FIXME(bz): Seems dubious? - root_font_size: AtomicIsize::new(font_size::get_initial_value().0.to_i32_au() as isize), + root_font_size: AtomicIsize::new(font_size::get_initial_value().size().0 as isize), used_root_font_size: AtomicBool::new(false), used_viewport_units: AtomicBool::new(false), } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 3e85339f875..a0d70b45a34 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -35,7 +35,7 @@ impl ToComputedValue for specified::NoCalcLength { specified::NoCalcLength::ViewportPercentage(length) => length.to_computed_value(context.viewport_size_for_viewport_unit_resolution()), specified::NoCalcLength::ServoCharacterWidth(length) => - length.to_computed_value(Au::from(context.style().get_font().clone_font_size())), + length.to_computed_value(context.style().get_font().clone_font_size().size()), #[cfg(feature = "gecko")] specified::NoCalcLength::Physical(length) => length.to_computed_value(context), @@ -269,7 +269,7 @@ impl specified::CalcLengthOrPercentage { /// Compute font-size or line-height taking into account text-zoom if necessary. pub fn to_computed_value_zoomed(&self, context: &Context, base_size: FontBaseSize) -> CalcLengthOrPercentage { - self.to_computed_value_with_zoom(context, |abs| context.maybe_zoom_text(abs), base_size) + self.to_computed_value_with_zoom(context, |abs| context.maybe_zoom_text(abs.into()).0, base_size) } } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 5b7f251ff26..1c8a478f205 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -159,7 +159,7 @@ impl<'a> Context<'a> { /// Apply text-zoom if enabled. #[cfg(feature = "gecko")] - pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength { + pub fn maybe_zoom_text(&self, size: NonNegativeLength) -> NonNegativeLength { // We disable zoom for by unsetting the // -x-text-zoom property, which leads to a false value // in mAllowZoom @@ -172,7 +172,7 @@ impl<'a> Context<'a> { /// (Servo doesn't do text-zoom) #[cfg(feature = "servo")] - pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength { + pub fn maybe_zoom_text(&self, size: NonNegativeLength) -> NonNegativeLength { size } } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 3c7c8a722f1..257781f62ae 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -96,8 +96,8 @@ impl FontBaseSize { pub fn resolve(&self, context: &Context) -> Au { match *self { FontBaseSize::Custom(size) => size, - FontBaseSize::CurrentStyle => Au::from(context.style().get_font().clone_font_size()), - FontBaseSize::InheritedStyle => Au::from(context.style().get_parent_font().clone_font_size()), + FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().size(), + FontBaseSize::InheritedStyle => context.style().get_parent_font().clone_font_size().size(), } } } diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index e8f0b899760..2d4cd532f5c 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -100,7 +100,7 @@ impl ToComputedValue for LineHeight { GenericLineHeight::Length(ref non_negative_lop) => { let result = match non_negative_lop.0 { LengthOrPercentage::Length(NoCalcLength::Absolute(ref abs)) => { - context.maybe_zoom_text(abs.to_computed_value(context)) + context.maybe_zoom_text(abs.to_computed_value(context).into()).0 } LengthOrPercentage::Length(ref length) => { length.to_computed_value(context)