Bug 1355427 - Part 1: stylo: Support computing font-size against an arbitrary base size; r?heycam
MozReview-Commit-ID: 4jWcugvXR65
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -413,16 +413,17 @@
<%helpers:longhand name="font-size" need_clone="True" animation_type="normal"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size">
use app_units::Au;
use std::fmt;
use style_traits::ToCss;
use values::{FONT_MEDIUM_PX, HasViewportPercentage};
use values::specified::{FontRelativeLength, LengthOrPercentage, Length};
use values::specified::{NoCalcLength, Percentage};
+ use values::specified::length::FontBaseSize;
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SpecifiedValue::Length(ref lop) => lop.to_css(dest),
SpecifiedValue::Keyword(kw, _) => kw.to_css(dest),
SpecifiedValue::Smaller => dest.write_str("smaller"),
SpecifiedValue::Larger => dest.write_str("larger"),
@@ -622,67 +623,73 @@
} else if let LengthOrPercentage::Length(ref nocalc) = *lop {
if let NoCalcLength::FontRelative(FontRelativeLength::Em(em)) = *nocalc {
return Some(em)
}
}
}
None
}
+
+ /// Compute it against a given base font size
+ pub fn to_computed_value_against(&self, context: &Context, base_size: FontBaseSize) -> Au {
+ use values::specified::length::FontRelativeLength;
+ match *self {
+ SpecifiedValue::Length(LengthOrPercentage::Length(
+ NoCalcLength::FontRelative(value))) => {
+ value.to_computed_value(context, base_size)
+ }
+ SpecifiedValue::Length(LengthOrPercentage::Length(
+ NoCalcLength::ServoCharacterWidth(value))) => {
+ value.to_computed_value(base_size.resolve(context))
+ }
+ SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => {
+ l.to_computed_value(context)
+ }
+ SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => {
+ base_size.resolve(context).scale_by(value)
+ }
+ SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
+ let calc = calc.to_computed_value(context);
+ calc.length() +base_size.resolve(context)
+ .scale_by(calc.percentage())
+ }
+ SpecifiedValue::Keyword(ref key, fraction) => {
+ key.to_computed_value(context).scale_by(fraction)
+ }
+ SpecifiedValue::Smaller => {
+ FontRelativeLength::Em(0.85)
+ .to_computed_value(context, base_size)
+ }
+ SpecifiedValue::Larger => {
+ FontRelativeLength::Em(1.2)
+ .to_computed_value(context, base_size)
+ }
+ }
+ }
}
#[inline]
#[allow(missing_docs)]
pub fn get_initial_value() -> computed_value::T {
Au::from_px(FONT_MEDIUM_PX)
}
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue::Keyword(Medium, 1.)
}
+
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
- use values::specified::length::FontRelativeLength;
- match *self {
- SpecifiedValue::Length(LengthOrPercentage::Length(
- NoCalcLength::FontRelative(value))) => {
- value.to_computed_value(context, /* use inherited */ true)
- }
- SpecifiedValue::Length(LengthOrPercentage::Length(
- NoCalcLength::ServoCharacterWidth(value))) => {
- value.to_computed_value(context.inherited_style().get_font().clone_font_size())
- }
- SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => {
- l.to_computed_value(context)
- }
- SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => {
- context.inherited_style().get_font().clone_font_size().scale_by(value)
- }
- SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
- let calc = calc.to_computed_value(context);
- calc.length() + context.inherited_style().get_font().clone_font_size()
- .scale_by(calc.percentage())
- }
- SpecifiedValue::Keyword(ref key, fraction) => {
- key.to_computed_value(context).scale_by(fraction)
- }
- SpecifiedValue::Smaller => {
- FontRelativeLength::Em(0.85).to_computed_value(context,
- /* use_inherited */ true)
- }
- SpecifiedValue::Larger => {
- FontRelativeLength::Em(1.2).to_computed_value(context,
- /* use_inherited */ true)
- }
- }
+ self.to_computed_value_against(context, FontBaseSize::InheritedStyle)
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue::Length(LengthOrPercentage::Length(
ToComputedValue::from_computed_value(computed)
))
}
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -5,32 +5,32 @@
//! `<length>` computed values, and related ones.
use app_units::{Au, AU_PER_PX};
use ordered_float::NotNaN;
use std::fmt;
use style_traits::ToCss;
use super::{Number, ToComputedValue, Context};
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
-use values::specified::length::{AbsoluteLength, FontRelativeLength, ViewportPercentageLength};
+use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
impl ToComputedValue for specified::NoCalcLength {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, context: &Context) -> Au {
match *self {
specified::NoCalcLength::Absolute(length) =>
length.to_computed_value(context),
specified::NoCalcLength::FontRelative(length) =>
- length.to_computed_value(context, /* use inherited */ false),
+ length.to_computed_value(context, /* base_size */ FontBaseSize::CurrentStyle),
specified::NoCalcLength::ViewportPercentage(length) =>
length.to_computed_value(context.viewport_size()),
specified::NoCalcLength::ServoCharacterWidth(length) =>
length.to_computed_value(context.style().get_font().clone_font_size())
}
}
#[inline]
@@ -134,16 +134,17 @@ impl ToCss for CalcLengthOrPercentage {
}
}
}
impl ToComputedValue for specified::CalcLengthOrPercentage {
type ComputedValue = CalcLengthOrPercentage;
fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
+
let mut length = Au(0);
if let Some(absolute) = self.absolute {
length += absolute;
}
for val in &[self.vw.map(ViewportPercentageLength::Vw),
self.vh.map(ViewportPercentageLength::Vh),
@@ -154,17 +155,17 @@ impl ToComputedValue for specified::Calc
}
}
for val in &[self.ch.map(FontRelativeLength::Ch),
self.em.map(FontRelativeLength::Em),
self.ex.map(FontRelativeLength::Ex),
self.rem.map(FontRelativeLength::Rem)] {
if let Some(val) = *val {
- length += val.to_computed_value(context, /* use inherited */ false);
+ length += val.to_computed_value(context, /* base_size */ FontBaseSize::CurrentStyle);
}
}
CalcLengthOrPercentage {
length: length,
percentage: self.percentage,
}
}
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -71,33 +71,50 @@ impl ToCss for FontRelativeLength {
FontRelativeLength::Em(length) => write!(dest, "{}em", length),
FontRelativeLength::Ex(length) => write!(dest, "{}ex", length),
FontRelativeLength::Ch(length) => write!(dest, "{}ch", length),
FontRelativeLength::Rem(length) => write!(dest, "{}rem", length)
}
}
}
+/// A source to resolve font-relative units against
+pub enum FontBaseSize {
+ /// Use the font-size of the current element
+ CurrentStyle,
+ /// Use the inherited font-size
+ InheritedStyle,
+ /// Use a custom base size
+ Custom(Au),
+}
+
+impl FontBaseSize {
+ /// Calculate the actual size for a given context
+ pub fn resolve(&self, context: &Context) -> Au {
+ match *self {
+ FontBaseSize::Custom(size) => size,
+ FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size(),
+ FontBaseSize::InheritedStyle => context.inherited_style().get_font().clone_font_size(),
+ }
+ }
+}
+
impl FontRelativeLength {
- /// 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 {
+ /// Computes the font-relative length. We use the inherited_size
+ /// flag to pass a different size for computing font-size and unconstrained font-size
+ pub fn to_computed_value(&self, context: &Context, base_size: FontBaseSize) -> 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 {
- context.style().get_font().clone_font_size()
- };
+ let reference_font_size = base_size.resolve(context);
let root_font_size = context.style().root_font_size;
match *self {
FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
FontRelativeLength::Ex(length) => {
match query_font_metrics(context, reference_font_size) {
FontMetricsQueryResult::Available(metrics) => metrics.x_height.scale_by(length),
// https://drafts.csswg.org/css-values/#ex