Bug 1341775 - Part 3: stylo: Calculate font-size keywords based on base size; r?heycam
MozReview-Commit-ID: Ff6kt8RLChI
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1500,16 +1500,22 @@ Gecko_nsStyleFont_SetLang(nsStyleFont* a
}
void
Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont, const nsStyleFont* aSource)
{
aFont->mLanguage = aSource->mLanguage;
}
+nscoord
+Gecko_nsStyleFont_GetBaseSize(const nsStyleFont* aFont, RawGeckoPresContextBorrowed aPresContext)
+{
+ return aPresContext->GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
+}
+
void
Gecko_LoadStyleSheet(css::Loader* aLoader,
ServoStyleSheet* aParent,
RawServoImportRuleBorrowed aImportRule,
nsIURI* aBaseURI,
const uint8_t* aURLString,
uint32_t aURLStringLength,
const uint8_t* aMediaString,
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -372,16 +372,17 @@ void Gecko_CSSValue_SetURL(nsCSSValueBor
void Gecko_CSSValue_SetLocal(nsCSSValueBorrowedMut css_value, const nsString family);
void Gecko_CSSValue_SetInteger(nsCSSValueBorrowedMut css_value, int32_t integer);
void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut css_value);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
bool Gecko_PropertyId_IsPrefEnabled(nsCSSPropertyID id);
void Gecko_nsStyleFont_SetLang(nsStyleFont* font, nsIAtom* atom);
void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont, const nsStyleFont* aSource);
+nscoord Gecko_nsStyleFont_GetBaseSize(const nsStyleFont* font, RawGeckoPresContextBorrowed pres_context);
const nsMediaFeature* Gecko_GetMediaFeatures();
// We use an int32_t here instead of a LookAndFeel::ColorID
// because forward-declaring a nested enum/struct is impossible
nscolor Gecko_GetLookAndFeelSystemColor(int32_t color_id,
RawGeckoPresContextBorrowed pres_context);
--- a/servo/components/style/build_gecko.rs
+++ b/servo/components/style/build_gecko.rs
@@ -288,16 +288,17 @@ mod bindings {
"NODE_.*",
"NS_FONT_.*",
"NS_STYLE_.*",
"NS_RADIUS_.*",
"BORDER_COLOR_.*",
"BORDER_STYLE_.*",
"mozilla::SERVO_PREF_.*",
"kNameSpaceID_.*",
+ "kGenericFont_.*",
];
let whitelist = [
"RawGecko.*",
"mozilla::ServoStyleSheet",
"mozilla::ServoElementSnapshot.*",
"mozilla::CSSPseudoClassType",
"mozilla::css::SheetParsingMode",
"mozilla::HalfCorner",
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -1008,16 +1008,22 @@ extern "C" {
pub fn Gecko_nsStyleFont_SetLang(font: *mut nsStyleFont,
atom: *mut nsIAtom);
}
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;
}
extern "C" {
pub fn Gecko_GetLookAndFeelSystemColor(color_id: i32,
pres_context:
RawGeckoPresContextBorrowed)
-> nscolor;
}
--- a/servo/components/style/gecko_bindings/structs_debug.rs
+++ b/servo/components/style/gecko_bindings/structs_debug.rs
@@ -19073,16 +19073,24 @@ pub mod root {
, "::" , stringify ! ( mValue ) ));
}
impl Clone for gfxFontVariation {
fn clone(&self) -> Self { *self }
}
#[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 {
pub fontlist: root::mozilla::FontFamilyList,
pub style: u8,
pub systemFont: bool,
pub variantCaps: u8,
pub variantNumeric: u8,
--- a/servo/components/style/gecko_bindings/structs_release.rs
+++ b/servo/components/style/gecko_bindings/structs_release.rs
@@ -18522,16 +18522,24 @@ pub mod root {
, "::" , stringify ! ( mValue ) ));
}
impl Clone for gfxFontVariation {
fn clone(&self) -> Self { *self }
}
#[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 {
pub fontlist: root::mozilla::FontFamilyList,
pub style: u8,
pub systemFont: bool,
pub variantCaps: u8,
pub variantNumeric: u8,
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -189,16 +189,21 @@ impl ComputedValues {
}
}
}
<%def name="declare_style_struct(style_struct)">
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)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
${set_gecko_property(gecko_ffi_name, "v")}
}
</%def>
@@ -1186,24 +1191,41 @@ fn static_assert() {
unsafe { Gecko_FontFamilyList_Clear(list); }
for family in &v.0 {
match *family {
FontFamily::FamilyName(ref name) => {
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); }
}
}
}
}
pub fn font_family_count(&self) -> usize {
0
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -477,39 +477,89 @@
XXLarge => "xx-large",
XXXLarge => unreachable!("We should never serialize \
specified values set via
HTML presentation attributes"),
})
}
}
- 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
pub fn from_html_size(size: u8) -> Self {
SpecifiedValue::Keyword(match size {
// If value is less than 1, let it be 1.
0 | 1 => XSmall,
2 => Small,
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -28,16 +28,24 @@ pub use super::image::{SizeKeyword, Vert
const AU_PER_PX: CSSFloat = 60.;
const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
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.
pub enum FontRelativeLength {
/// A "em" value: https://drafts.csswg.org/css-values/#em
Em(CSSFloat),
/// A "ex" value: https://drafts.csswg.org/css-values/#ex
Ex(CSSFloat),