diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 7ca5530e9a3..b485efa48ee 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -293,6 +293,7 @@ mod bindings { "BORDER_STYLE_.*", "mozilla::SERVO_PREF_.*", "kNameSpaceID_.*", + "kGenericFont_.*", ]; let whitelist = [ "RawGecko.*", diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 360766befcc..7efc2252a00 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -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; } diff --git a/components/style/gecko_bindings/structs_debug.rs b/components/style/gecko_bindings/structs_debug.rs index d6be67cdf8a..4dfd92f3dfe 100644 --- a/components/style/gecko_bindings/structs_debug.rs +++ b/components/style/gecko_bindings/structs_debug.rs @@ -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 { diff --git a/components/style/gecko_bindings/structs_release.rs b/components/style/gecko_bindings/structs_release.rs index 53d42fdde00..661b28a18f9 100644 --- a/components/style/gecko_bindings/structs_release.rs +++ b/components/style/gecko_bindings/structs_release.rs @@ -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 { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 82203d96e19..f8f25da8ed5 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -194,6 +194,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 name="impl_simple_setter(ident, gecko_ffi_name)"> @@ -1191,14 +1196,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); } } } diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 49b3557c8cb..7b1e829eaf0 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -482,29 +482,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 diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index bffae92c4ff..7a16ce41d8f 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -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.