Skip to content
Permalink
Browse files

style: Refactor and add infrastructure for font metrics in style.

This commit itself only moves things around and adds an extra parameter to the
`apply_declarations` function to eventually handle #14079 correctly.

Probably needs a more granular API to query fonts, á la nsFontMetrics, but
that's trivial to do once this is landed.

Then we should make the font provider mandatory, and implement the missing stylo
bits.
  • Loading branch information
emilio committed Nov 13, 2016
1 parent 9fd6f0a commit 6c3458767bd2f37d1d8130fe0841fc877729ad60
@@ -403,6 +403,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
previous_style,
/* cascade_info = */ None,
context.error_reporter.clone(),
/* Metrics provider */ None,
CascadeFlags::empty());
computed
}
@@ -0,0 +1,35 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use Atom;
use app_units::Au;
use euclid::Size2D;
use std::fmt;

/// Represents the font metrics that style needs from a font to compute the
/// value of certain CSS units like `ex`.
#[derive(Debug, PartialEq, Clone)]
pub struct FontMetrics {
pub x_height: Au,
pub zero_advance_measure: Size2D<Au>,
}

#[derive(Debug, PartialEq, Clone)]
pub enum FontMetricsQueryResult {
Available(Option<FontMetrics>),
NotAvailable,
}

/// A trait used to represent something capable of providing us font metrics.
pub trait FontMetricsProvider: Send + Sync + 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.
///
/// This is not too common in practice though.
fn query(&self, _font_name: &Atom) -> FontMetricsQueryResult {
FontMetricsQueryResult::NotAvailable
}
}
@@ -38,7 +38,7 @@ impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
let has_percentage = other.percentage.is_some();
nsStyleCoord_CalcValue {
mLength: other.length.map_or(0, |l| l.0),
mLength: other.length.0,
mPercent: other.percentage.unwrap_or(0.0),
mHasPercent: has_percentage,
}
@@ -53,7 +53,7 @@ impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
None
};
CalcLengthOrPercentage {
length: Some(Au(other.mLength)),
length: Au(other.mLength),
percentage: percentage,
}
}
@@ -103,6 +103,7 @@ pub mod dom;
pub mod element_state;
pub mod error_reporting;
pub mod font_face;
pub mod font_metrics;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
pub mod keyframes;
@@ -10,10 +10,10 @@ use Atom;
use app_units::Au;
use cssparser::{Delimiter, Parser, Token};
use euclid::size::{Size2D, TypedSize2D};
use properties::longhands;
use serialize_comma_separated_list;
use std::fmt::{self, Write};
use style_traits::{ToCss, ViewportPx};
use values::computed::{self, ToComputedValue};
use values::specified;


@@ -49,28 +49,11 @@ impl Range<specified::Length> {
fn to_computed_range(&self, viewport_size: Size2D<Au>) -> Range<Au> {
// http://dev.w3.org/csswg/mediaqueries3/#units
// em units are relative to the initial font-size.
let initial_font_size = longhands::font_size::get_initial_value();
let compute_width = |&width| {
match width {
specified::Length::Absolute(value) => value,
specified::Length::FontRelative(value)
=> value.to_computed_value(initial_font_size, initial_font_size),
specified::Length::ViewportPercentage(value)
=> value.to_computed_value(viewport_size),
specified::Length::Calc(val, range)
=> range.clamp(
val.compute_from_viewport_and_font_size(viewport_size,
initial_font_size,
initial_font_size)
.length()),
specified::Length::ServoCharacterWidth(..)
=> unreachable!(),
}
};
let context = computed::Context::initial(viewport_size, false);

match *self {
Range::Min(ref width) => Range::Min(compute_width(width)),
Range::Max(ref width) => Range::Max(compute_width(width)),
Range::Min(ref width) => Range::Min(width.to_computed_value(&context)),
Range::Max(ref width) => Range::Max(width.to_computed_value(&context)),
//Range::Eq(ref width) => Range::Eq(compute_width(width))
}
}
@@ -916,6 +916,14 @@ fn static_assert() {
}
}

pub fn font_family_count(&self) -> usize {
0
}

pub fn font_family_at(&self, _: usize) -> longhands::font_family::computed_value::FontFamily {
unimplemented!()
}

pub fn copy_font_family_from(&mut self, other: &Self) {
unsafe { Gecko_CopyFontFamilyFrom(&mut self.gecko.mFont, &other.gecko.mFont); }
}
@@ -418,7 +418,7 @@ impl Interpolate for CalcLengthOrPercentage {
}

Ok(CalcLengthOrPercentage {
length: try!(interpolate_half(self.length, other.length, progress)),
length: try!(self.length.interpolate(&other.length, progress)),
percentage: try!(interpolate_half(self.percentage, other.percentage, progress)),
})
}
@@ -8,7 +8,7 @@
<% data.new_style_struct("Font",
inherited=True,
additional_methods=[Method("compute_font_hash", is_mut=True)]) %>
<%helpers:longhand name="font-family" animatable="False">
<%helpers:longhand name="font-family" animatable="False" need_index="True">
use self::computed_value::FontFamily;
use values::NoViewportPercentage;
use values::computed::ComputedValueAsSpecified;
@@ -21,15 +21,16 @@
use std::fmt;
use Atom;
use style_traits::ToCss;
pub use self::FontFamily as SingleComputedValue;

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum FontFamily {
FamilyName(Atom),
Generic(Atom),
}
impl FontFamily {

impl FontFamily {
#[inline]
pub fn atom(&self) -> &Atom {
match *self {
@@ -67,11 +68,13 @@
FontFamily::FamilyName(input)
}
}

impl ToCss for FontFamily {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.atom().with_str(|s| dest.write_str(s))
}
}

impl ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut iter = self.0.iter();
@@ -83,6 +86,7 @@
Ok(())
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<FontFamily>);
@@ -307,8 +311,7 @@ ${helpers.single_keyword("font-variant",
fn to_computed_value(&self, context: &Context) -> computed_value::T {
match self.0 {
LengthOrPercentage::Length(Length::FontRelative(value)) => {
value.to_computed_value(context.inherited_style().get_font().clone_font_size(),
context.style().root_font_size())
value.to_computed_value(context, /* use inherited */ true)
}
LengthOrPercentage::Length(Length::ServoCharacterWidth(value)) => {
value.to_computed_value(context.inherited_style().get_font().clone_font_size())
@@ -25,6 +25,7 @@ use url::Url;
#[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
use euclid::size::Size2D;
use computed_values;
use font_metrics::FontMetricsProvider;
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
use logical_geometry::WritingMode;
use parser::{Parse, ParserContext, ParserContextExtraData};
@@ -1464,6 +1465,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
inherited_style,
cascade_info,
error_reporter,
None,
flags)
}

@@ -1475,6 +1477,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
inherited_style: &ComputedValues,
mut cascade_info: Option<<&mut CascadeInfo>,
mut error_reporter: StdBox<ParseErrorReporter + Send>,
font_metrics_provider: Option<<&FontMetricsProvider>,
flags: CascadeFlags)
-> ComputedValues
where F: Fn() -> I, I: Iterator<Item = &'a PropertyDeclaration>
@@ -1528,6 +1531,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
viewport_size: viewport_size,
inherited_style: inherited_style,
style: starting_style,
font_metrics_provider: font_metrics_provider,
};

// Set computed values, overwriting earlier declarations for the same
@@ -1562,6 +1566,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
// classification is correct.
let is_early_property = matches!(*declaration,
PropertyDeclaration::FontSize(_) |
PropertyDeclaration::FontFamily(_) |
PropertyDeclaration::Color(_) |
PropertyDeclaration::Position(_) |
PropertyDeclaration::Float(_) |
@@ -17,14 +17,14 @@ pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct CalcLengthOrPercentage {
pub length: Option<Au>,
pub length: Au,
pub percentage: Option<CSSFloat>,
}

impl CalcLengthOrPercentage {
#[inline]
pub fn length(&self) -> Au {
self.length.unwrap_or(Au(0))
self.length
}

#[inline]
@@ -38,13 +38,13 @@ impl From<LengthOrPercentage> for CalcLengthOrPercentage {
match len {
LengthOrPercentage::Percentage(this) => {
CalcLengthOrPercentage {
length: None,
length: Au(0),
percentage: Some(this),
}
}
LengthOrPercentage::Length(this) => {
CalcLengthOrPercentage {
length: Some(this),
length: this,
percentage: None,
}
}
@@ -60,13 +60,13 @@ impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
match len {
LengthOrPercentageOrAuto::Percentage(this) => {
Some(CalcLengthOrPercentage {
length: None,
length: Au(0),
percentage: Some(this),
})
}
LengthOrPercentageOrAuto::Length(this) => {
Some(CalcLengthOrPercentage {
length: Some(this),
length: this,
percentage: None,
})
}
@@ -83,10 +83,9 @@ impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
impl ToCss for CalcLengthOrPercentage {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match (self.length, self.percentage) {
(None, Some(p)) => write!(dest, "{}%", p * 100.),
(Some(l), None) => write!(dest, "{}px", Au::to_px(l)),
(Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
_ => unreachable!()
(l, Some(p)) if l == Au(0) => write!(dest, "{}%", p * 100.),
(l, Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
(l, None) => write!(dest, "{}px", Au::to_px(l)),
}
}
}
@@ -95,16 +94,34 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
type ComputedValue = CalcLengthOrPercentage;

fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
self.compute_from_viewport_and_font_size(context.viewport_size(),
context.style().get_font().clone_font_size(),
context.style().root_font_size())
let mut length = Au(0);

if let Some(absolute) = self.absolute {
length += absolute;
}

for val in &[self.vw, self.vh, self.vmin, self.vmax] {
if let Some(val) = *val {
length += val.to_computed_value(context.viewport_size());
}
}

for val in &[self.ch, self.em, self.ex, self.rem] {
if let Some(val) = *val {
length += val.to_computed_value(context, /* use inherited */ false);
}
}

CalcLengthOrPercentage {
length: length,
percentage: self.percentage.map(|p| p.0),
}
}

#[inline]
fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self {
specified::CalcLengthOrPercentage {
absolute: computed.length,
absolute: Some(computed.length),
percentage: computed.percentage.map(specified::Percentage),
..Default::default()
}
@@ -4,6 +4,7 @@

use app_units::Au;
use euclid::size::Size2D;
use font_metrics::FontMetricsProvider;
use properties::ComputedValues;
use std::fmt;
use style_traits::ToCss;
@@ -28,9 +29,11 @@ pub struct Context<'a> {
pub viewport_size: Size2D<Au>,
pub inherited_style: &'a ComputedValues,

/// Values access through this need to be in the properties "computed early":
/// color, text-decoration, font-size, display, position, float, border-*-style, outline-style
/// Values access through this need to be in the properties "computed
/// early": color, text-decoration, font-size, display, position, float,
/// border-*-style, outline-style, font-family, writing-mode...
pub style: ComputedValues,
pub font_metrics_provider: Option<&'a FontMetricsProvider>,
}

impl<'a> Context<'a> {
@@ -39,6 +42,20 @@ impl<'a> Context<'a> {
pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style }
pub fn style(&self) -> &ComputedValues { &self.style }
pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style }

/// Creates a dummy computed context for use in multiple places, like
/// evaluating media queries.
pub fn initial(viewport_size: Size2D<Au>, is_root_element: bool) -> Self {
let initial_style = ComputedValues::initial_values();
// FIXME: Enforce a font metrics provider.
Context {
is_root_element: is_root_element,
viewport_size: viewport_size,
inherited_style: initial_style,
style: initial_style.clone(),
font_metrics_provider: None,
}
}
}

pub trait ToComputedValue {
@@ -99,8 +116,7 @@ impl ToComputedValue for specified::Length {
specified::Length::Absolute(length) => length,
specified::Length::Calc(calc, range) => range.clamp(calc.to_computed_value(context).length()),
specified::Length::FontRelative(length) =>
length.to_computed_value(context.style().get_font().clone_font_size(),
context.style().root_font_size()),
length.to_computed_value(context, /* use inherited */ false),
specified::Length::ViewportPercentage(length) =>
length.to_computed_value(context.viewport_size()),
specified::Length::ServoCharacterWidth(length) =>

0 comments on commit 6c34587

Please sign in to comment.
You can’t perform that action at this time.