style: Try to bring some more sanity into our font code.

It's not very easy to understand on its current state, and it causes subtle bugs
like bug 1533654.

It could be simpler if we centralized where the interactions between properties
are handled. This patch does this.

This patch also changes how MathML script sizes are tracked when scriptlevel
changes and they have relative fonts in between.

With this patch, any explicitly specified font-size is treated the same (being a
scriptlevel boundary), regardless of whether it's either an absolute size, a
relative size, or a wide keyword.

Relative lengths always resolve relative to the constrained size, which allows
us to avoid the double font-size computation, and not give up on sanity with
keyword font-sizes.

I think given no other browser supports scriptlevel it seems like the right
trade-off.

Differential Revision: https://phabricator.services.mozilla.com/D23070
This commit is contained in:
Emilio Cobos Álvarez 2019-03-18 15:37:03 +00:00
parent 77a75596bb
commit aa5ea337da
8 changed files with 290 additions and 498 deletions

View file

@ -152,49 +152,6 @@ impl FontSize {
keyword_info: Some(KeywordInfo::medium()),
}
}
/// FIXME(emilio): This is very complex. Also, it should move to
/// StyleBuilder.
pub fn cascade_inherit_font_size(context: &mut Context) {
// 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
.get_parent_font()
.clone_font_size()
.keyword_info
.map(|info| {
specified::FontSize::Keyword(info)
.to_computed_value(context)
.size
});
let mut font = context.builder.take_font();
font.inherit_font_size_from(
context.builder.get_parent_font(),
kw_inherited_size,
context.builder.device,
);
context.builder.put_font(font);
}
/// Cascade the initial value for the `font-size` property.
///
/// FIXME(emilio): This is the only function that is outside of the
/// `StyleBuilder`, and should really move inside!
///
/// Can we move the font stuff there?
pub fn cascade_initial_font_size(context: &mut Context) {
// font-size's default ("medium") does not always
// compute to the same value and depends on the font
let computed = specified::FontSize::medium().to_computed_value(context);
context.builder.mutate_font().set_font_size(computed);
#[cfg(feature = "gecko")]
{
let device = context.builder.device;
context.builder.mutate_font().fixup_font_min_size(device);
}
}
}
/// XXXManishearth it might be better to
@ -221,15 +178,23 @@ impl ToAnimatedValue for FontSize {
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
/// Specifies a prioritized list of font family names or generic family names.
pub struct FontFamily(pub FontFamilyList);
pub struct FontFamily {
/// The actual list of family names.
pub families: FontFamilyList,
/// Whether this font-family came from a specified system-font.
pub is_system_font: bool,
}
impl FontFamily {
#[inline]
/// Get default font family as `serif` which is a generic font-family
pub fn serif() -> Self {
FontFamily(FontFamilyList::new(Box::new([SingleFontFamily::Generic(
atom!("serif"),
)])))
FontFamily {
families: FontFamilyList::new(Box::new([SingleFontFamily::Generic(
atom!("serif"),
)])),
is_system_font: false,
}
}
}
@ -239,7 +204,7 @@ impl MallocSizeOf for FontFamily {
// SharedFontList objects are generally shared from the pointer
// stored in the specified value. So only count this if the
// SharedFontList is unshared.
unsafe { bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared((self.0).0.get()) }
unsafe { bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(self.families.0.get()) }
}
}
@ -248,7 +213,7 @@ impl ToCss for FontFamily {
where
W: fmt::Write,
{
let mut iter = self.0.iter();
let mut iter = self.families.iter();
iter.next().unwrap().to_css(dest)?;
for family in iter {
dest.write_str(", ")?;

View file

@ -548,13 +548,16 @@ impl ToComputedValue for FontFamily {
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
FontFamily::Values(ref v) => computed::FontFamily(v.clone()),
FontFamily::Values(ref v) => computed::FontFamily {
families: v.clone(),
is_system_font: false,
},
FontFamily::System(_) => self.compute_system(context),
}
}
fn from_computed_value(other: &computed::FontFamily) -> Self {
FontFamily::Values(other.0.clone())
FontFamily::Values(other.families.clone())
}
}
@ -958,48 +961,6 @@ impl FontSize {
"larger" => Ok(FontSize::Larger),
}
}
#[allow(unused_mut)]
/// Cascade `font-size` with specified value
pub fn cascade_specified_font_size(
context: &mut Context,
specified_value: &FontSize,
mut computed: computed::FontSize,
) {
// we could use clone_language and clone_font_family() here but that's
// expensive. Do it only in gecko mode for now.
#[cfg(feature = "gecko")]
{
// if the language or generic changed, we need to recalculate
// the font size from the stored font-size origin information.
if context.builder.get_font().gecko().mLanguage.mRawPtr !=
context.builder.get_parent_font().gecko().mLanguage.mRawPtr ||
context.builder.get_font().gecko().mGenericID !=
context.builder.get_parent_font().gecko().mGenericID
{
if let Some(info) = computed.keyword_info {
computed.size = info.to_computed_value(context);
}
}
}
let device = context.builder.device;
let mut font = context.builder.take_font();
let parent_unconstrained = {
let parent_font = context.builder.get_parent_font();
font.apply_font_size(computed, parent_font, device)
};
context.builder.put_font(font);
if let Some(parent) = parent_unconstrained {
let new_unconstrained = specified_value
.to_computed_value_against(context, FontBaseSize::Custom(Au::from(parent)));
context
.builder
.mutate_font()
.apply_unconstrained_font_size(new_unconstrained.size);
}
}
}
impl Parse for FontSize {

View file

@ -82,17 +82,12 @@ pub enum FontBaseSize {
///
/// FIXME(emilio): This is very complex, and should go away.
InheritedStyleButStripEmUnits,
/// Use a custom base size.
///
/// FIXME(emilio): This is very dubious, and only used for MathML.
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().size(),
FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle => {
context.style().get_parent_font().clone_font_size().size()