From 25667d032154a65ea08c9b308d306921ca1272a7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 7 Apr 2017 15:49:44 -0700 Subject: [PATCH] stylo: Use gecko's font metrics --- components/style/font_metrics.rs | 48 +++++++++--------- components/style/gecko/media_queries.rs | 1 + components/style/gecko/wrapper.rs | 23 ++++++++- .../style/properties/properties.mako.rs | 1 + components/style/servo/media_queries.rs | 1 + components/style/values/computed/mod.rs | 3 ++ components/style/values/specified/length.rs | 50 ++++++------------- components/style/viewport.rs | 1 + ports/geckolib/glue.rs | 1 + tests/unit/style/parsing/image.rs | 1 + 10 files changed, 72 insertions(+), 58 deletions(-) diff --git a/components/style/font_metrics.rs b/components/style/font_metrics.rs index 5210ded345e..64c12f898c7 100644 --- a/components/style/font_metrics.rs +++ b/components/style/font_metrics.rs @@ -9,7 +9,9 @@ use Atom; use app_units::Au; use context::SharedStyleContext; -use euclid::Size2D; +use logical_geometry::WritingMode; +use media_queries::Device; +use properties::style_structs::Font; use std::fmt; /// Represents the font metrics that style needs from a font to compute the @@ -18,8 +20,8 @@ use std::fmt; pub struct FontMetrics { /// The x-height of the font. pub x_height: Au, - /// The zero advance. - pub zero_advance_measure: Size2D, + /// The zero advance. This is usually writing mode dependent + pub zero_advance_measure: Au, } /// The result for querying font metrics for a given font family. @@ -27,11 +29,30 @@ pub struct FontMetrics { pub enum FontMetricsQueryResult { /// The font is available, but we may or may not have found any font metrics /// for it. - Available(Option), + Available(FontMetrics), /// The font is not available. NotAvailable, } +/// A trait used to represent something capable of providing us font metrics. +pub trait FontMetricsProvider: fmt::Debug { + /// Obtain the metrics for given font family. + /// + /// TODO: We could make this take the full list, I guess, and save a few + /// virtual calls in the case we are repeatedly unable to find font metrics? + /// That is not too common in practice though. + fn query(&self, _font: &Font, _font_size: Au, _wm: WritingMode, + _in_media_query: bool, _device: &Device) -> FontMetricsQueryResult { + FontMetricsQueryResult::NotAvailable + } + + /// Get default size of a given language and generic family + fn get_size(&self, font_name: &Atom, font_family: u8) -> Au; + + /// Construct from a shared style context + fn create_from(context: &SharedStyleContext) -> Self where Self: Sized; +} + // TODO: Servo's font metrics provider will probably not live in this crate, so this will // have to be replaced with something else (perhaps a trait method on TElement) // when we get there @@ -67,22 +88,3 @@ pub fn get_metrics_provider_for_product() -> ::gecko::wrapper::GeckoFontMetricsP pub fn get_metrics_provider_for_product() -> ServoMetricsProvider { ServoMetricsProvider } - -/// A trait used to represent something capable of providing us font metrics. -pub trait FontMetricsProvider: fmt::Debug { - /// Obtain the metrics for given font family. - /// - /// TODO: We could make this take the full list, I guess, and save a few - /// virtual calls in the case we are repeatedly unable to find font metrics? - /// That is not too common in practice though. - fn query(&self, _font_name: &Atom) -> FontMetricsQueryResult { - FontMetricsQueryResult::NotAvailable - } - - /// Get default size of a given language and generic family - fn get_size(&self, font_name: &Atom, font_family: u8) -> Au; - - /// Construct from a shared style context - fn create_from(context: &SharedStyleContext) -> Self where Self: Sized; -} - diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 6ba63e75d8f..53074d9058a 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -513,6 +513,7 @@ impl Expression { // insists on having an actual ComputedValues inside itself. style: default_values.clone(), font_metrics_provider: &provider, + in_media_query: true, }; let required_value = match self.value { diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index e0b1b4af0f0..657ba4de11b 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -22,7 +22,7 @@ use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TEleme use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use element_state::ElementState; use error_reporting::StdoutErrorReporter; -use font_metrics::FontMetricsProvider; +use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult}; use gecko::global_style_data::GLOBAL_STYLE_DATA; use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement}; use gecko::snapshot_helpers; @@ -51,10 +51,13 @@ use gecko_bindings::structs::NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO; use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE; use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS; use gecko_bindings::sugar::ownership::HasArcFFI; +use logical_geometry::WritingMode; +use media_queries::Device; use parking_lot::RwLock; use properties::{ComputedValues, parse_style_attribute}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock}; use properties::animated_properties::AnimationValueMap; +use properties::style_structs::Font; use rule_tree::CascadeLevel as ServoCascadeLevel; use selector_parser::{ElementExt, Snapshot}; use selectors::Element; @@ -468,6 +471,24 @@ impl FontMetricsProvider for GeckoFontMetricsProvider { cache.push((font_name.clone(), sizes)); sizes.size_for_generic(font_family) } + + fn query(&self, font: &Font, font_size: Au, wm: WritingMode, + in_media_query: bool, device: &Device) -> FontMetricsQueryResult { + use gecko_bindings::bindings::Gecko_GetFontMetrics; + let gecko_metrics = unsafe { + Gecko_GetFontMetrics(&*device.pres_context, + wm.is_vertical() && !wm.is_sideways(), + font.gecko(), + font_size.0, + // we don't use the user font set in a media query + !in_media_query) + }; + let metrics = FontMetrics { + x_height: Au(gecko_metrics.mXSize), + zero_advance_measure: Au(gecko_metrics.mChSize), + }; + FontMetricsQueryResult::Available(metrics) + } } impl structs::FontSizePrefs { diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 05dcd7e172d..a483a82b862 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2072,6 +2072,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device, layout_parent_style: layout_parent_style, style: starting_style, font_metrics_provider: font_metrics_provider, + in_media_query: false, }; // Set computed values, overwriting earlier declarations for the same diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index 95a537bfdfb..24dd050fb2b 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -190,6 +190,7 @@ impl Range { // A real provider will be needed here once we do; since // ch units can exist in media queries. font_metrics_provider: &ServoMetricsProvider, + in_media_query: true, }; match *self { diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 47d809c5ebb..474239c56f9 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -58,6 +58,9 @@ pub struct Context<'a> { /// A font metrics provider, used to access font metrics to implement /// font-relative units. pub font_metrics_provider: &'a FontMetricsProvider, + + /// Whether or not we are computing the media list in a media query + pub in_media_query: bool, } impl<'a> Context<'a> { diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index d6dcad04a3b..2060662a0f8 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -9,7 +9,7 @@ use app_units::Au; use cssparser::{Parser, Token}; use euclid::size::Size2D; -use font_metrics::FontMetrics; +use font_metrics::FontMetricsQueryResult; use parser::{Parse, ParserContext}; use std::{cmp, fmt, mem}; use std::ascii::AsciiExt; @@ -69,22 +69,17 @@ impl ToCss for FontRelativeLength { } impl FontRelativeLength { - /// Gets the first available font metrics from the current context's - /// font-family list. - pub fn find_first_available_font_metrics(context: &Context) -> Option { - use font_metrics::FontMetricsQueryResult::*; - for family in context.style().get_font().font_family_iter() { - if let Available(metrics) = context.font_metrics_provider.query(family.atom()) { - return metrics; - } - } - - None - } - /// Computes the font-relative length. We use the use_inherited flag to /// special-case the computation of font-size. pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au { + fn query_font_metrics(context: &Context, reference_font_size: Au) -> FontMetricsQueryResult { + context.font_metrics_provider.query(context.style().get_font(), + reference_font_size, + context.style().writing_mode, + context.in_media_query, + context.device) + } + let reference_font_size = if use_inherited { context.inherited_style().get_font().clone_font_size() } else { @@ -95,33 +90,20 @@ impl FontRelativeLength { match *self { FontRelativeLength::Em(length) => reference_font_size.scale_by(length), FontRelativeLength::Ex(length) => { - match Self::find_first_available_font_metrics(context) { - Some(metrics) => metrics.x_height, + match query_font_metrics(context, reference_font_size) { + FontMetricsQueryResult::Available(metrics) => metrics.x_height.scale_by(length), // https://drafts.csswg.org/css-values/#ex // // In the cases where it is impossible or impractical to // determine the x-height, a value of 0.5em must be // assumed. // - None => reference_font_size.scale_by(0.5 * length), + FontMetricsQueryResult::NotAvailable => reference_font_size.scale_by(0.5 * length), } }, FontRelativeLength::Ch(length) => { - let wm = context.style().writing_mode; - - // TODO(emilio, #14144): Compute this properly once we support - // all the relevant writing-mode related properties, this should - // be equivalent to "is the text in the block direction?". - let vertical = wm.is_vertical(); - - match Self::find_first_available_font_metrics(context) { - Some(metrics) => { - if vertical { - metrics.zero_advance_measure.height - } else { - metrics.zero_advance_measure.width - } - } + match query_font_metrics(context, reference_font_size) { + FontMetricsQueryResult::Available(metrics) => metrics.zero_advance_measure.scale_by(length), // https://drafts.csswg.org/css-values/#ch // // In the cases where it is impossible or impractical to @@ -132,8 +114,8 @@ impl FontRelativeLength { // writing-mode is vertical-rl or vertical-lr and // text-orientation is upright). // - None => { - if vertical { + FontMetricsQueryResult::NotAvailable => { + if context.style().writing_mode.is_vertical() { reference_font_size.scale_by(length) } else { reference_font_size.scale_by(0.5 * length) diff --git a/components/style/viewport.rs b/components/style/viewport.rs index 22426a2fbc6..20266bae5e5 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -683,6 +683,7 @@ impl MaybeNew for ViewportConstraints { layout_parent_style: device.default_computed_values(), style: device.default_computed_values().clone(), font_metrics_provider: &provider, + in_media_query: false, }; // DEVICE-ADAPT ยง 9.3 Resolving 'extend-to-zoom' diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 69393e98ce3..b924227b779 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1709,6 +1709,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis layout_parent_style: parent_style.unwrap_or(default_values), style: (**style).clone(), font_metrics_provider: &metrics, + in_media_query: false, }; for (index, keyframe) in keyframes.iter().enumerate() { diff --git a/tests/unit/style/parsing/image.rs b/tests/unit/style/parsing/image.rs index 3e3bce84f89..68ccec16a5f 100644 --- a/tests/unit/style/parsing/image.rs +++ b/tests/unit/style/parsing/image.rs @@ -53,6 +53,7 @@ fn test_linear_gradient() { layout_parent_style: initial_style, style: initial_style.clone(), font_metrics_provider: &ServoMetricsProvider, + in_media_query: false, }; assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context), computed::AngleOrCorner::Angle(Angle::from_radians(PI)));