servo: Merge #16122 - stylo: Handle font-size keywords correctly (from Manishearth:stylo-font-size); r=heycam

r=heycam https://bugzilla.mozilla.org/show_bug.cgi?id=1341775

Source-Repo: https://github.com/servo/servo
Source-Revision: 1584bbd3ecc2a86339f8fe2ccb88bd30fc462b1c

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 2047c506f34dd7a2ea6e36b24008384212f8f737
This commit is contained in:
Manish Goregaokar 2017-03-24 12:30:10 -07:00
Родитель 8b6b8b09d0
Коммит d5c001e64d
9 изменённых файлов: 238 добавлений и 33 удалений

Просмотреть файл

@ -293,6 +293,7 @@ mod bindings {
"BORDER_STYLE_.*",
"mozilla::SERVO_PREF_.*",
"kNameSpaceID_.*",
"kGenericFont_.*",
];
let whitelist = [
"RawGecko.*",

Просмотреть файл

@ -1012,6 +1012,12 @@ extern "C" {
pub fn Gecko_nsStyleFont_CopyLangFrom(aFont: *mut nsStyleFont,
aSource: *const nsStyleFont);
}
extern "C" {
pub fn Gecko_nsStyleFont_GetBaseSize(font: *const nsStyleFont,
pres_context:
RawGeckoPresContextBorrowed)
-> nscoord;
}
extern "C" {
pub fn Gecko_GetMediaFeatures() -> *const nsMediaFeature;
}

Просмотреть файл

@ -19097,6 +19097,14 @@ pub mod root {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct gfxFontStyle([u8; 0]);
pub const kGenericFont_NONE: u8 = 0;
pub const kGenericFont_moz_variable: u8 = 0;
pub const kGenericFont_moz_fixed: u8 = 1;
pub const kGenericFont_serif: u8 = 2;
pub const kGenericFont_sans_serif: u8 = 4;
pub const kGenericFont_monospace: u8 = 8;
pub const kGenericFont_cursive: u8 = 16;
pub const kGenericFont_fantasy: u8 = 32;
#[repr(C)]
#[derive(Debug)]
pub struct nsFont {

Просмотреть файл

@ -18546,6 +18546,14 @@ pub mod root {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct gfxFontStyle([u8; 0]);
pub const kGenericFont_NONE: u8 = 0;
pub const kGenericFont_moz_variable: u8 = 0;
pub const kGenericFont_moz_fixed: u8 = 1;
pub const kGenericFont_serif: u8 = 2;
pub const kGenericFont_sans_serif: u8 = 4;
pub const kGenericFont_monospace: u8 = 8;
pub const kGenericFont_cursive: u8 = 16;
pub const kGenericFont_fantasy: u8 = 32;
#[repr(C)]
#[derive(Debug)]
pub struct nsFont {

Просмотреть файл

@ -80,6 +80,7 @@ pub struct ComputedValues {
shareable: bool,
pub writing_mode: WritingMode,
pub root_font_size: Au,
pub font_size_keyword: Option<longhands::font_size::KeywordSize>,
}
impl ComputedValues {
@ -89,6 +90,7 @@ impl ComputedValues {
shareable: parent.shareable,
writing_mode: parent.writing_mode,
root_font_size: parent.root_font_size,
font_size_keyword: parent.font_size_keyword,
% for style_struct in data.style_structs:
% if style_struct.inherited:
${style_struct.ident}: parent.${style_struct.ident}.clone(),
@ -103,6 +105,7 @@ impl ComputedValues {
shareable: bool,
writing_mode: WritingMode,
root_font_size: Au,
font_size_keyword: Option<longhands::font_size::KeywordSize>,
% for style_struct in data.style_structs:
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor
@ -112,6 +115,7 @@ impl ComputedValues {
shareable: shareable,
writing_mode: writing_mode,
root_font_size: root_font_size,
font_size_keyword: font_size_keyword,
% for style_struct in data.style_structs:
${style_struct.ident}: ${style_struct.ident},
% endfor
@ -124,6 +128,7 @@ impl ComputedValues {
shareable: true,
writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious
root_font_size: longhands::font_size::get_initial_value(), // FIXME(bz): Also seems dubious?
font_size_keyword: Some(Default::default()),
% for style_struct in data.style_structs:
${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context),
% endfor
@ -194,6 +199,11 @@ impl ComputedValues {
pub struct ${style_struct.gecko_struct_name} {
gecko: ${style_struct.gecko_ffi_name},
}
impl ${style_struct.gecko_struct_name} {
pub fn gecko(&self) -> &${style_struct.gecko_ffi_name} {
&self.gecko
}
}
</%def>
<%def name="impl_simple_setter(ident, gecko_ffi_name)">
@ -1191,14 +1201,31 @@ fn static_assert() {
unsafe { Gecko_FontFamilyList_AppendNamed(list, name.0.as_ptr()); }
}
FontFamily::Generic(ref name) => {
let family_type =
if name == &atom!("serif") { FontFamilyType::eFamily_serif }
else if name == &atom!("sans-serif") { FontFamilyType::eFamily_sans_serif }
else if name == &atom!("cursive") { FontFamilyType::eFamily_cursive }
else if name == &atom!("fantasy") { FontFamilyType::eFamily_fantasy }
else if name == &atom!("monospace") { FontFamilyType::eFamily_monospace }
else if name == &atom!("-moz-fixed") { FontFamilyType::eFamily_moz_fixed }
else { panic!("Unknown generic font family") };
let (family_type, generic) =
if name == &atom!("serif") {
(FontFamilyType::eFamily_serif,
structs::kGenericFont_serif)
} else if name == &atom!("sans-serif") {
(FontFamilyType::eFamily_sans_serif,
structs::kGenericFont_sans_serif)
} else if name == &atom!("cursive") {
(FontFamilyType::eFamily_cursive,
structs::kGenericFont_cursive)
} else if name == &atom!("fantasy") {
(FontFamilyType::eFamily_fantasy,
structs::kGenericFont_fantasy)
} else if name == &atom!("monospace") {
(FontFamilyType::eFamily_monospace,
structs::kGenericFont_monospace)
} else if name == &atom!("-moz-fixed") {
(FontFamilyType::eFamily_moz_fixed,
structs::kGenericFont_moz_fixed)
} else {
panic!("Unknown generic font family")
};
if v.0.len() == 1 {
self.gecko.mGenericID = generic;
}
unsafe { Gecko_FontFamilyList_AppendGeneric(list, family_type); }
}
}

Просмотреть файл

@ -266,6 +266,13 @@
match *value {
DeclaredValue::Value(ref specified_value) => {
let computed = specified_value.to_computed_value(context);
% if property.ident == "font_size":
if let longhands::font_size::SpecifiedValue::Keyword(kw) = **specified_value {
context.mutate_style().font_size_keyword = Some(kw);
} else {
context.mutate_style().font_size_keyword = None;
}
% endif
% if property.has_uncacheable_values:
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
.set_${property.ident}(computed, cacheable ${maybe_wm});
@ -280,12 +287,22 @@
CSSWideKeyword::Unset |
% endif
CSSWideKeyword::Initial => {
// We assume that it's faster to use copy_*_from rather than
// set_*(get_initial_value());
let initial_struct = default_style
.get_${data.current_style_struct.name_lower}();
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
.copy_${property.ident}_from(initial_struct ${maybe_wm});
% if property.ident == "font_size":
// font-size's default ("medium") does not always
// compute to the same value and depends on the font
let computed = longhands::font_size::get_initial_specified_value()
.to_computed_value(context);
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
.set_font_size(computed);
context.mutate_style().font_size_keyword = Some(Default::default());
% else:
// We assume that it's faster to use copy_*_from rather than
// set_*(get_initial_value());
let initial_struct = default_style
.get_${data.current_style_struct.name_lower}();
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
.copy_${property.ident}_from(initial_struct ${maybe_wm});
% endif
},
% if data.current_style_struct.inherited:
CSSWideKeyword::Unset |
@ -300,6 +317,10 @@
inherited_style.get_${data.current_style_struct.name_lower}();
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
.copy_${property.ident}_from(inherited_struct ${maybe_wm});
% if property.ident == "font_size":
context.mutate_style().font_size_keyword =
context.inherited_style.font_size_keyword;
% endif
}
}
}

Просмотреть файл

@ -465,6 +465,12 @@ ${helpers.single_keyword("font-variant-caps",
}
}
impl Default for KeywordSize {
fn default() -> Self {
Medium
}
}
impl ToCss for KeywordSize {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str(match *self {
@ -482,29 +488,79 @@ ${helpers.single_keyword("font-variant-caps",
}
}
impl ToComputedValue for KeywordSize {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, _: &Context) -> computed_value::T {
// https://drafts.csswg.org/css-fonts-3/#font-size-prop
use values::FONT_MEDIUM_PX;
match *self {
XXSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 5,
XSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 4,
Small => Au::from_px(FONT_MEDIUM_PX) * 8 / 9,
Medium => Au::from_px(FONT_MEDIUM_PX),
Large => Au::from_px(FONT_MEDIUM_PX) * 6 / 5,
XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2,
XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2,
XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3,
% if product == "servo":
impl ToComputedValue for KeywordSize {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, _: &Context) -> computed_value::T {
// https://drafts.csswg.org/css-fonts-3/#font-size-prop
use values::FONT_MEDIUM_PX;
match *self {
XXSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 5,
XSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 4,
Small => Au::from_px(FONT_MEDIUM_PX) * 8 / 9,
Medium => Au::from_px(FONT_MEDIUM_PX),
Large => Au::from_px(FONT_MEDIUM_PX) * 6 / 5,
XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2,
XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2,
XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3,
}
}
#[inline]
fn from_computed_value(_: &computed_value::T) -> Self {
unreachable!()
}
}
% else:
impl ToComputedValue for KeywordSize {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, cx: &Context) -> computed_value::T {
use gecko_bindings::bindings::Gecko_nsStyleFont_GetBaseSize;
use values::specified::length::au_to_int_px;
// Data from nsRuleNode.cpp in Gecko
// Mapping from base size and HTML size to pixels
// The first index is (base_size - 9), the second is the
// HTML size. "0" is CSS keyword xx-small, not HTML size 0,
// since HTML size 0 is the same as 1.
//
// xxs xs s m l xl xxl -
// - 0/1 2 3 4 5 6 7
static FONT_SIZE_MAPPING: [[i32; 8]; 8] = [
[9, 9, 9, 9, 11, 14, 18, 27],
[9, 9, 9, 10, 12, 15, 20, 30],
[9, 9, 10, 11, 13, 17, 22, 33],
[9, 9, 10, 12, 14, 18, 24, 36],
[9, 10, 12, 13, 16, 20, 26, 39],
[9, 10, 12, 14, 17, 21, 28, 42],
[9, 10, 13, 15, 18, 23, 30, 45],
[9, 10, 13, 16, 18, 24, 32, 48]
];
#[inline]
fn from_computed_value(_: &computed_value::T) -> Self {
unreachable!()
static FONT_SIZE_FACTORS: [i32; 8] = [60, 75, 89, 100, 120, 150, 200, 300];
// XXXManishearth handle quirks mode
let base_size = unsafe {
Gecko_nsStyleFont_GetBaseSize(cx.style().get_font().gecko(),
&*cx.device.pres_context)
};
let base_size_px = au_to_int_px(base_size as f32);
let html_size = *self as usize;
if base_size_px >= 9 && base_size_px <= 16 {
Au::from_px(FONT_SIZE_MAPPING[(base_size_px - 9) as usize][html_size])
} else {
Au(FONT_SIZE_FACTORS[html_size] * base_size / 100)
}
}
#[inline]
fn from_computed_value(_: &computed_value::T) -> Self {
unreachable!()
}
}
}
% endif
impl SpecifiedValue {
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size

Просмотреть файл

@ -1502,6 +1502,8 @@ pub struct ComputedValues {
pub writing_mode: WritingMode,
/// The root element's computed font size.
pub root_font_size: Au,
/// The keyword behind the current font-size property, if any
pub font_size_keyword: Option<longhands::font_size::KeywordSize>,
}
#[cfg(feature = "servo")]
@ -1511,6 +1513,7 @@ impl ComputedValues {
shareable: bool,
writing_mode: WritingMode,
root_font_size: Au,
font_size_keyword: Option<longhands::font_size::KeywordSize>,
% for style_struct in data.active_style_structs():
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor
@ -1520,6 +1523,7 @@ impl ComputedValues {
shareable: shareable,
writing_mode: writing_mode,
root_font_size: root_font_size,
font_size_keyword: font_size_keyword,
% for style_struct in data.active_style_structs():
${style_struct.ident}: ${style_struct.ident},
% endfor
@ -1843,6 +1847,7 @@ mod lazy_static_module {
shareable: true,
writing_mode: WritingMode::empty(),
root_font_size: longhands::font_size::get_initial_value(),
font_size_keyword: Some(Default::default()),
};
}
}
@ -1985,6 +1990,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
flags.contains(SHAREABLE),
WritingMode::empty(),
inherited_style.root_font_size,
inherited_style.font_size_keyword,
% for style_struct in data.active_style_structs():
% if style_struct.inherited:
inherited_style.clone_${style_struct.name_lower}(),
@ -1998,6 +2004,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
flags.contains(SHAREABLE),
WritingMode::empty(),
inherited_style.root_font_size,
inherited_style.font_size_keyword,
% for style_struct in data.active_style_structs():
inherited_style.clone_${style_struct.name_lower}(),
% endfor
@ -2030,6 +2037,13 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
// To improve i-cache behavior, we outline the individual functions and use
// virtual dispatch instead.
% for category_to_cascade_now in ["early", "other"]:
% if category_to_cascade_now == "early":
// Pull these out so that we can
// compute them in a specific order without
// introducing more iterations
let mut font_size = None;
let mut font_family = None;
% endif
for declaration in iter_declarations() {
let longhand_id = match declaration.id() {
PropertyDeclarationId::Longhand(id) => id,
@ -2076,6 +2090,17 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
}
seen.insert(physical_longhand_id);
% if category_to_cascade_now == "early":
if LonghandId::FontSize == longhand_id {
font_size = Some(declaration);
continue;
}
if LonghandId::FontFamily == longhand_id {
font_family = Some(declaration);
continue;
}
% endif
let discriminant = longhand_id as usize;
(CASCADE_PROPERTY[discriminant])(declaration,
inherited_style,
@ -2088,6 +2113,51 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
% if category_to_cascade_now == "early":
let writing_mode = get_writing_mode(context.style.get_inheritedbox());
context.style.writing_mode = writing_mode;
// It is important that font_size is computed before
// the late properties (for em units), but after font-family
// (for the base-font-size dependence for default and keyword font-sizes)
// Additionally, when we support system fonts they will have to be
// computed early, and *before* font_family, so I'm including
// font_family here preemptively instead of keeping it within
// the early properties.
//
// To avoid an extra iteration, we just pull out the property
// during the early iteration and cascade them in order
// after it.
if let Some(declaration) = font_family {
let discriminant = LonghandId::FontFamily as usize;
(CASCADE_PROPERTY[discriminant])(declaration,
inherited_style,
default_style,
&mut context,
&mut cacheable,
&mut cascade_info,
error_reporter);
}
if let Some(declaration) = font_size {
let discriminant = LonghandId::FontSize as usize;
(CASCADE_PROPERTY[discriminant])(declaration,
inherited_style,
default_style,
&mut context,
&mut cacheable,
&mut cascade_info,
error_reporter);
} else if let Some(kw) = inherited_style.font_size_keyword {
// Font size keywords will inherit as keywords and be recomputed
// each time.
let discriminant = LonghandId::FontSize as usize;
let size = PropertyDeclaration::FontSize(
longhands::font_size::SpecifiedValue::Keyword(kw)
);
(CASCADE_PROPERTY[discriminant])(&size,
inherited_style,
default_style,
&mut context,
&mut cacheable,
&mut cascade_info,
error_reporter);
}
% endif
% endfor

Просмотреть файл

@ -33,6 +33,14 @@ const AU_PER_Q: CSSFloat = AU_PER_MM / 4.;
const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
/// Same as Gecko's AppUnitsToIntCSSPixels
///
/// Converts app units to integer pixel values,
/// rounding during the conversion
pub fn au_to_int_px(au: f32) -> i32 {
(au / AU_PER_PX).round() as i32
}
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A font relative length.