Skip to content

Commit

Permalink
style: Refactor and add infrastructure for font metrics in style.
Browse files Browse the repository at this point in the history
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 6c34587
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 94 deletions.
1 change: 1 addition & 0 deletions components/style/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
35 changes: 35 additions & 0 deletions components/style/font_metrics.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
4 changes: 2 additions & 2 deletions components/style/gecko/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -53,7 +53,7 @@ impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
None
};
CalcLengthOrPercentage {
length: Some(Au(other.mLength)),
length: Au(other.mLength),
percentage: percentage,
}
}
Expand Down
1 change: 1 addition & 0 deletions components/style/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
25 changes: 4 additions & 21 deletions components/style/media_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down Expand Up @@ -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))
}
}
Expand Down
8 changes: 8 additions & 0 deletions components/style/properties/gecko.mako.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
})
}
Expand Down
11 changes: 7 additions & 4 deletions components/style/properties/longhand/font.mako.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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();
Expand All @@ -83,6 +86,7 @@
Ok(())
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<FontFamily>);
Expand Down Expand Up @@ -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())
Expand Down
5 changes: 5 additions & 0 deletions components/style/properties/properties.mako.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1464,6 +1465,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
inherited_style,
cascade_info,
error_reporter,
None,
flags)
}

Expand All @@ -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>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(_) |
Expand Down
45 changes: 31 additions & 14 deletions components/style/values/computed/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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,
}
}
Expand All @@ -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,
})
}
Expand All @@ -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)),
}
}
}
Expand All @@ -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()
}
Expand Down
24 changes: 20 additions & 4 deletions components/style/values/computed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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> {
Expand All @@ -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 {
Expand Down Expand Up @@ -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) =>
Expand Down
Loading

0 comments on commit 6c34587

Please sign in to comment.