mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
stylo: Use gecko's font metrics
This commit is contained in:
parent
1154600dd4
commit
25667d0321
10 changed files with 72 additions and 58 deletions
|
@ -9,7 +9,9 @@
|
||||||
use Atom;
|
use Atom;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use context::SharedStyleContext;
|
use context::SharedStyleContext;
|
||||||
use euclid::Size2D;
|
use logical_geometry::WritingMode;
|
||||||
|
use media_queries::Device;
|
||||||
|
use properties::style_structs::Font;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// Represents the font metrics that style needs from a font to compute the
|
/// Represents the font metrics that style needs from a font to compute the
|
||||||
|
@ -18,8 +20,8 @@ use std::fmt;
|
||||||
pub struct FontMetrics {
|
pub struct FontMetrics {
|
||||||
/// The x-height of the font.
|
/// The x-height of the font.
|
||||||
pub x_height: Au,
|
pub x_height: Au,
|
||||||
/// The zero advance.
|
/// The zero advance. This is usually writing mode dependent
|
||||||
pub zero_advance_measure: Size2D<Au>,
|
pub zero_advance_measure: Au,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result for querying font metrics for a given font family.
|
/// The result for querying font metrics for a given font family.
|
||||||
|
@ -27,11 +29,30 @@ pub struct FontMetrics {
|
||||||
pub enum FontMetricsQueryResult {
|
pub enum FontMetricsQueryResult {
|
||||||
/// The font is available, but we may or may not have found any font metrics
|
/// The font is available, but we may or may not have found any font metrics
|
||||||
/// for it.
|
/// for it.
|
||||||
Available(Option<FontMetrics>),
|
Available(FontMetrics),
|
||||||
/// The font is not available.
|
/// The font is not available.
|
||||||
NotAvailable,
|
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
|
// 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)
|
// have to be replaced with something else (perhaps a trait method on TElement)
|
||||||
// when we get there
|
// 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 {
|
pub fn get_metrics_provider_for_product() -> ServoMetricsProvider {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -513,6 +513,7 @@ impl Expression {
|
||||||
// insists on having an actual ComputedValues inside itself.
|
// insists on having an actual ComputedValues inside itself.
|
||||||
style: default_values.clone(),
|
style: default_values.clone(),
|
||||||
font_metrics_provider: &provider,
|
font_metrics_provider: &provider,
|
||||||
|
in_media_query: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let required_value = match self.value {
|
let required_value = match self.value {
|
||||||
|
|
|
@ -22,7 +22,7 @@ use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TEleme
|
||||||
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
|
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use error_reporting::StdoutErrorReporter;
|
use error_reporting::StdoutErrorReporter;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
|
||||||
use gecko::global_style_data::GLOBAL_STYLE_DATA;
|
use gecko::global_style_data::GLOBAL_STYLE_DATA;
|
||||||
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
|
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
|
||||||
use gecko::snapshot_helpers;
|
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_IN_NATIVE_ANONYMOUS_SUBTREE;
|
||||||
use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
|
use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
|
||||||
use gecko_bindings::sugar::ownership::HasArcFFI;
|
use gecko_bindings::sugar::ownership::HasArcFFI;
|
||||||
|
use logical_geometry::WritingMode;
|
||||||
|
use media_queries::Device;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use properties::{ComputedValues, parse_style_attribute};
|
use properties::{ComputedValues, parse_style_attribute};
|
||||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
||||||
use properties::animated_properties::AnimationValueMap;
|
use properties::animated_properties::AnimationValueMap;
|
||||||
|
use properties::style_structs::Font;
|
||||||
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||||
use selector_parser::{ElementExt, Snapshot};
|
use selector_parser::{ElementExt, Snapshot};
|
||||||
use selectors::Element;
|
use selectors::Element;
|
||||||
|
@ -468,6 +471,24 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
|
||||||
cache.push((font_name.clone(), sizes));
|
cache.push((font_name.clone(), sizes));
|
||||||
sizes.size_for_generic(font_family)
|
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 {
|
impl structs::FontSizePrefs {
|
||||||
|
|
|
@ -2072,6 +2072,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
|
||||||
layout_parent_style: layout_parent_style,
|
layout_parent_style: layout_parent_style,
|
||||||
style: starting_style,
|
style: starting_style,
|
||||||
font_metrics_provider: font_metrics_provider,
|
font_metrics_provider: font_metrics_provider,
|
||||||
|
in_media_query: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set computed values, overwriting earlier declarations for the same
|
// Set computed values, overwriting earlier declarations for the same
|
||||||
|
|
|
@ -190,6 +190,7 @@ impl Range<specified::Length> {
|
||||||
// A real provider will be needed here once we do; since
|
// A real provider will be needed here once we do; since
|
||||||
// ch units can exist in media queries.
|
// ch units can exist in media queries.
|
||||||
font_metrics_provider: &ServoMetricsProvider,
|
font_metrics_provider: &ServoMetricsProvider,
|
||||||
|
in_media_query: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -58,6 +58,9 @@ pub struct Context<'a> {
|
||||||
/// A font metrics provider, used to access font metrics to implement
|
/// A font metrics provider, used to access font metrics to implement
|
||||||
/// font-relative units.
|
/// font-relative units.
|
||||||
pub font_metrics_provider: &'a FontMetricsProvider,
|
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> {
|
impl<'a> Context<'a> {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use font_metrics::FontMetrics;
|
use font_metrics::FontMetricsQueryResult;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::{cmp, fmt, mem};
|
use std::{cmp, fmt, mem};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
|
@ -69,22 +69,17 @@ impl ToCss for FontRelativeLength {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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<FontMetrics> {
|
|
||||||
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
|
/// Computes the font-relative length. We use the use_inherited flag to
|
||||||
/// special-case the computation of font-size.
|
/// special-case the computation of font-size.
|
||||||
pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au {
|
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 {
|
let reference_font_size = if use_inherited {
|
||||||
context.inherited_style().get_font().clone_font_size()
|
context.inherited_style().get_font().clone_font_size()
|
||||||
} else {
|
} else {
|
||||||
|
@ -95,33 +90,20 @@ impl FontRelativeLength {
|
||||||
match *self {
|
match *self {
|
||||||
FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
|
FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
|
||||||
FontRelativeLength::Ex(length) => {
|
FontRelativeLength::Ex(length) => {
|
||||||
match Self::find_first_available_font_metrics(context) {
|
match query_font_metrics(context, reference_font_size) {
|
||||||
Some(metrics) => metrics.x_height,
|
FontMetricsQueryResult::Available(metrics) => metrics.x_height.scale_by(length),
|
||||||
// https://drafts.csswg.org/css-values/#ex
|
// https://drafts.csswg.org/css-values/#ex
|
||||||
//
|
//
|
||||||
// In the cases where it is impossible or impractical to
|
// In the cases where it is impossible or impractical to
|
||||||
// determine the x-height, a value of 0.5em must be
|
// determine the x-height, a value of 0.5em must be
|
||||||
// assumed.
|
// assumed.
|
||||||
//
|
//
|
||||||
None => reference_font_size.scale_by(0.5 * length),
|
FontMetricsQueryResult::NotAvailable => reference_font_size.scale_by(0.5 * length),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FontRelativeLength::Ch(length) => {
|
FontRelativeLength::Ch(length) => {
|
||||||
let wm = context.style().writing_mode;
|
match query_font_metrics(context, reference_font_size) {
|
||||||
|
FontMetricsQueryResult::Available(metrics) => metrics.zero_advance_measure.scale_by(length),
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// https://drafts.csswg.org/css-values/#ch
|
// https://drafts.csswg.org/css-values/#ch
|
||||||
//
|
//
|
||||||
// In the cases where it is impossible or impractical to
|
// 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
|
// writing-mode is vertical-rl or vertical-lr and
|
||||||
// text-orientation is upright).
|
// text-orientation is upright).
|
||||||
//
|
//
|
||||||
None => {
|
FontMetricsQueryResult::NotAvailable => {
|
||||||
if vertical {
|
if context.style().writing_mode.is_vertical() {
|
||||||
reference_font_size.scale_by(length)
|
reference_font_size.scale_by(length)
|
||||||
} else {
|
} else {
|
||||||
reference_font_size.scale_by(0.5 * length)
|
reference_font_size.scale_by(0.5 * length)
|
||||||
|
|
|
@ -683,6 +683,7 @@ impl MaybeNew for ViewportConstraints {
|
||||||
layout_parent_style: device.default_computed_values(),
|
layout_parent_style: device.default_computed_values(),
|
||||||
style: device.default_computed_values().clone(),
|
style: device.default_computed_values().clone(),
|
||||||
font_metrics_provider: &provider,
|
font_metrics_provider: &provider,
|
||||||
|
in_media_query: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
|
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
|
||||||
|
|
|
@ -1709,6 +1709,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
|
||||||
layout_parent_style: parent_style.unwrap_or(default_values),
|
layout_parent_style: parent_style.unwrap_or(default_values),
|
||||||
style: (**style).clone(),
|
style: (**style).clone(),
|
||||||
font_metrics_provider: &metrics,
|
font_metrics_provider: &metrics,
|
||||||
|
in_media_query: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (index, keyframe) in keyframes.iter().enumerate() {
|
for (index, keyframe) in keyframes.iter().enumerate() {
|
||||||
|
|
|
@ -53,6 +53,7 @@ fn test_linear_gradient() {
|
||||||
layout_parent_style: initial_style,
|
layout_parent_style: initial_style,
|
||||||
style: initial_style.clone(),
|
style: initial_style.clone(),
|
||||||
font_metrics_provider: &ServoMetricsProvider,
|
font_metrics_provider: &ServoMetricsProvider,
|
||||||
|
in_media_query: false,
|
||||||
};
|
};
|
||||||
assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
|
assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
|
||||||
computed::AngleOrCorner::Angle(Angle::from_radians(PI)));
|
computed::AngleOrCorner::Angle(Angle::from_radians(PI)));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue