Skip to content

Commit

Permalink
stylo: Add support for calcs in base size calculation
Browse files Browse the repository at this point in the history
This tracks an offset along with the ratio for the keyword font size
data. The offset gets used when a calc is involved whilst inheriting
font-size (it is the computed value of that calc ignoring em/percentage
portions, which go into the ratio). If the family or language changes,
the new font size can be computed by taking the keyword's size in the context
of that family/language, multiplying it by the ratio, and adding the
offset.
  • Loading branch information
Manishearth committed Sep 11, 2017
1 parent 1ad9463 commit 6318969
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 29 deletions.
71 changes: 44 additions & 27 deletions components/style/properties/longhand/font.mako.rs
Expand Up @@ -605,7 +605,7 @@ ${helpers.single_keyword_system("font-variant-caps",
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::Keyword(kw, _, _) => kw.to_css(dest),
SpecifiedValue::Smaller => dest.write_str("smaller"),
SpecifiedValue::Larger => dest.write_str("larger"),
SpecifiedValue::System(sys) => sys.to_css(dest),
Expand All @@ -617,13 +617,17 @@ ${helpers.single_keyword_system("font-variant-caps",
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SpecifiedValue {
Length(specified::LengthOrPercentage),
/// A keyword value, along with a ratio.
/// A keyword value, along with a ratio and absolute offset.
/// The ratio in any specified keyword value
/// will be 1, but we cascade keywordness even
/// will be 1 (with offset 0), but we cascade keywordness even
/// after font-relative (percent and em) values
/// have been applied, which is where the keyword
/// comes in. See bug 1355707
Keyword(KeywordSize, f32),
/// have been applied, which is where the ratio
/// comes in. The offset comes in if we cascaded a calc value,
/// where the font-relative portion (em and percentage) will
/// go into the ratio, and the remaining units all computed together
/// will go into the offset.
/// See bug 1355707.
Keyword(KeywordSize, f32, NonNegativeAu),
Smaller,
Larger,
System(SystemFont)
Expand Down Expand Up @@ -802,32 +806,45 @@ ${helpers.single_keyword_system("font-variant-caps",
6 => XXLarge,
// If value is greater than 7, let it be 7.
_ => XXXLarge,
}, 1.)
}, 1., Au(0).into())
}

/// If this value is specified as a ratio of the parent font (em units
/// or percent) return the ratio
pub fn as_font_ratio(&self) -> Option<f32> {
pub fn as_font_ratio(&self, context: &Context) -> Option<(f32, NonNegativeAu)> {
match *self {
SpecifiedValue::Length(ref lop) => {
match *lop {
LengthOrPercentage::Percentage(pc) => {
Some(pc.0)
Some((pc.0, Au(0).into()))
}
LengthOrPercentage::Length(ref nocalc) => {
match *nocalc {
NoCalcLength::FontRelative(FontRelativeLength::Em(em)) => {
Some(em)
Some((em, Au(0).into()))
}
_ => None,
}
}
// FIXME(emilio): This looks super fishy!
LengthOrPercentage::Calc(..) => None,
LengthOrPercentage::Calc(ref calc) => {
if calc.em.is_none() && calc.percentage.is_none() {
return None;
}
let ratio = calc.em.unwrap_or(0.) + calc.percentage.map_or(0., |pc| pc.0);
// Compute it, but shave off the font-relative part (em, %)
// This will mean that other font-relative units like ex and ch will be computed against
// the old font even when the font changes. There's no particular "right answer" for what
// to do here -- Gecko recascades as if the font had changed, we instead track the changes
// and reapply, which means that we carry over old computed ex/ch values whilst Gecko
// recomputes new ones. This is enough of an edge case to not really matter.
let abs = calc.to_computed_value_zoomed(context, FontBaseSize::Custom(Au(0).into()))
.length_component().into();
Some((ratio, abs))
}
}
}
SpecifiedValue::Larger => Some(LARGER_FONT_SIZE_RATIO),
SpecifiedValue::Smaller => Some(1. / LARGER_FONT_SIZE_RATIO),
SpecifiedValue::Larger => Some((LARGER_FONT_SIZE_RATIO, Au(0).into())),
SpecifiedValue::Smaller => Some((1. / LARGER_FONT_SIZE_RATIO, Au(0).into())),
_ => None,
}
}
Expand Down Expand Up @@ -862,8 +879,8 @@ ${helpers.single_keyword_system("font-variant-caps",
let calc = calc.to_computed_value_zoomed(context, base_size);
calc.to_used_value(Some(base_size.resolve(context))).unwrap().into()
}
SpecifiedValue::Keyword(ref key, fraction) => {
context.maybe_zoom_text(key.to_computed_value(context).scale_by(fraction))
SpecifiedValue::Keyword(ref key, fraction, offset) => {
context.maybe_zoom_text(key.to_computed_value(context).scale_by(fraction) + offset)
}
SpecifiedValue::Smaller => {
FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO)
Expand Down Expand Up @@ -891,7 +908,7 @@ ${helpers.single_keyword_system("font-variant-caps",

#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue::Keyword(Medium, 1.)
SpecifiedValue::Keyword(Medium, 1., Au(0).into())
}


Expand Down Expand Up @@ -928,7 +945,7 @@ ${helpers.single_keyword_system("font-variant-caps",
}

if let Ok(kw) = input.try(KeywordSize::parse) {
return Ok(SpecifiedValue::Keyword(kw, 1.))
return Ok(SpecifiedValue::Keyword(kw, 1., Au(0).into()))
}

try_match_ident_ignore_ascii_case! { input.expect_ident()?,
Expand All @@ -954,17 +971,17 @@ ${helpers.single_keyword_system("font-variant-caps",
pub fn cascade_specified_font_size(context: &mut Context,
specified_value: &SpecifiedValue,
mut computed: NonNegativeAu) {
if let SpecifiedValue::Keyword(kw, fraction) = *specified_value {
context.builder.font_size_keyword = Some((kw, fraction, Au(0).into()));
} else if let Some(ratio) = specified_value.as_font_ratio() {
if let SpecifiedValue::Keyword(kw, fraction, offset) = *specified_value {
context.builder.font_size_keyword = Some((kw, fraction, offset));
} else if let Some((ratio, abs)) = specified_value.as_font_ratio(context) {
// In case a font-size-relative value was applied to a keyword
// value, we must preserve this fact in case the generic font family
// changes. relative values (em and %) applied to keywords must be
// recomputed from the base size for the keyword and the relative size.
//
// See bug 1355707
if let Some((kw, fraction, _)) = context.builder.inherited_font_computation_data().font_size_keyword {
context.builder.font_size_keyword = Some((kw, fraction * ratio, Au(0).into()));
if let Some((kw, fraction, old_abs)) = context.builder.inherited_font_computation_data().font_size_keyword {
context.builder.font_size_keyword = Some((kw, fraction * ratio, abs + old_abs.0.scale_by(ratio).into()));
} else {
context.builder.font_size_keyword = None;
}
Expand All @@ -982,8 +999,8 @@ ${helpers.single_keyword_system("font-variant-caps",
context.builder.get_parent_font().gecko().mLanguage.raw::<nsIAtom>() ||
context.builder.get_font().gecko().mGenericID !=
context.builder.get_parent_font().gecko().mGenericID {
if let Some((kw, ratio, _)) = context.builder.font_size_keyword {
computed = context.maybe_zoom_text(kw.to_computed_value(context).scale_by(ratio));
if let Some((kw, ratio, offset)) = context.builder.font_size_keyword {
computed = context.maybe_zoom_text(kw.to_computed_value(context).scale_by(ratio) + offset);
}
}
% endif
Expand Down Expand Up @@ -1012,8 +1029,8 @@ ${helpers.single_keyword_system("font-variant-caps",
// If inheriting, we must recompute font-size in case of language
// changes using the font_size_keyword. We also need to do this to
// handle mathml scriptlevel changes
let kw_inherited_size = context.builder.font_size_keyword.map(|(kw, ratio, _)| {
context.maybe_zoom_text(SpecifiedValue::Keyword(kw, ratio).to_computed_value(context))
let kw_inherited_size = context.builder.font_size_keyword.map(|(kw, ratio, offset)| {
context.maybe_zoom_text(SpecifiedValue::Keyword(kw, ratio, offset).to_computed_value(context))
});
let parent_kw;
let device = context.builder.device;
Expand Down
6 changes: 6 additions & 0 deletions components/style/values/computed/length.rs
Expand Up @@ -113,6 +113,12 @@ impl CalcLengthOrPercentage {
#[inline]
pub fn length(&self) -> Au {
debug_assert!(self.percentage.is_none());
self.length_component()
}

/// Returns the length component of this `calc()`
#[inline]
pub fn length_component(&self) -> Au {
self.clamping_mode.clamp(self.length)
}

Expand Down
10 changes: 8 additions & 2 deletions components/style/values/computed/mod.rs
Expand Up @@ -14,8 +14,7 @@ use properties;
use properties::{ComputedValues, StyleBuilder};
#[cfg(feature = "servo")]
use servo_url::ServoUrl;
use std::f32;
use std::fmt;
use std::{f32, fmt, ops};
#[cfg(feature = "servo")]
use std::sync::Arc;
use style_traits::ToCss;
Expand Down Expand Up @@ -558,6 +557,13 @@ impl NonNegativeAu {
}
}

impl ops::Add<NonNegativeAu> for NonNegativeAu {
type Output = NonNegativeAu;
fn add(self, other: Self) -> Self {
(self.0 + other.0).into()
}
}

impl From<Au> for NonNegativeAu {
#[inline]
fn from(au: Au) -> NonNegativeAu {
Expand Down

0 comments on commit 6318969

Please sign in to comment.