servo: Merge #17211 - stylo: Prefill default font when a single generic is set (from Manishearth:stylo-single-generic); r=heycam
authorManish Goregaokar <manishearth@gmail.com>
Wed, 07 Jun 2017 10:53:25 -0700
changeset 410958 43589b5d25c16bfd9b029a9e3fb40f9df2d64ac4
parent 410957 0d5ae200e069f348555b175c339ea0f1443eec7c
child 410959 9c914937a358e1dac731194071f4be5c90741790
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs17211, 1370734
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #17211 - stylo: Prefill default font when a single generic is set (from Manishearth:stylo-single-generic); r=heycam r=heycam https://bugzilla.mozilla.org/show_bug.cgi?id=1370734 Source-Repo: https://github.com/servo/servo Source-Revision: eaefcbe55186b874b96c6dffc7e8dd2b6283634d
servo/components/style/gecko/generated/bindings.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/font.mako.rs
servo/components/style/properties/properties.mako.rs
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -1342,16 +1342,22 @@ extern "C" {
                                           aSource: *const nsStyleFont);
 }
 extern "C" {
     pub fn Gecko_nsStyleFont_FixupNoneGeneric(font: *mut nsStyleFont,
                                               pres_context:
                                                   RawGeckoPresContextBorrowed);
 }
 extern "C" {
+    pub fn Gecko_nsStyleFont_PrefillDefaultForGeneric(font: *mut nsStyleFont,
+                                                      pres_context:
+                                                          RawGeckoPresContextBorrowed,
+                                                      generic_id: u8);
+}
+extern "C" {
     pub fn Gecko_nsStyleFont_FixupMinFontSize(font: *mut nsStyleFont,
                                               pres_context:
                                                   RawGeckoPresContextBorrowed);
 }
 extern "C" {
     pub fn Gecko_GetBaseSize(lang: *mut nsIAtom) -> FontSizePrefs;
 }
 extern "C" {
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -216,16 +216,19 @@ 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
     }
+    pub fn gecko_mut(&mut self) -> &mut ${style_struct.gecko_ffi_name} {
+        &mut 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")}
     }
@@ -1582,51 +1585,29 @@ fn static_assert() {
     pub fn fixup_none_generic(&mut self, device: &Device) {
         unsafe {
             bindings::Gecko_nsStyleFont_FixupNoneGeneric(&mut self.gecko, &*device.pres_context)
         }
     }
 
     pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) {
         use properties::longhands::font_family::computed_value::FontFamily;
-        use gecko_bindings::structs::FontFamilyType;
 
         let list = &mut self.gecko.mFont.fontlist;
         unsafe { Gecko_FontFamilyList_Clear(list); }
 
         self.gecko.mGenericID = structs::kGenericFont_NONE;
 
         for family in &v.0 {
             match *family {
                 FontFamily::FamilyName(ref f) => {
                     unsafe { Gecko_FontFamilyList_AppendNamed(list, f.name.as_ptr(), f.quoted); }
                 }
                 FontFamily::Generic(ref name) => {
-                    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")
-                        };
+                    let (family_type, generic) = FontFamily::generic(name);
                     if v.0.len() == 1 {
                         self.gecko.mGenericID = generic;
                     }
                     unsafe { Gecko_FontFamilyList_AppendGeneric(list, family_type); }
                 }
             }
         }
     }
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -186,16 +186,43 @@
                     value.push_str(" ");
                     value.push_str(&ident);
                 }
                 Ok(FontFamily::FamilyName(FamilyName {
                     name: Atom::from(value),
                     quoted: false,
                 }))
             }
+
+            #[cfg(feature = "gecko")]
+            /// Return the generic ID for a given generic font name
+            pub fn generic(name: &Atom) -> (::gecko_bindings::structs::FontFamilyType, u8) {
+                use gecko_bindings::structs::{self, FontFamilyType};
+                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 {}", name);
+                }
+            }
         }
 
         impl ToCss for FamilyName {
             fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                 if self.quoted {
                     dest.write_char('"')?;
                     write!(CssStringWriter::new(dest), "{}", self.name)?;
                     dest.write_char('"')
@@ -255,16 +282,31 @@
     }
 
     #[derive(Debug, Clone, PartialEq, Eq, Hash)]
     pub enum SpecifiedValue {
         Values(Vec<FontFamily>),
         System(SystemFont),
     }
 
+    #[cfg(feature = "gecko")]
+    impl SpecifiedValue {
+        /// Return the generic ID if it is a single generic font
+        pub fn single_generic(&self) -> Option<u8> {
+            if let SpecifiedValue::Values(ref values) = *self {
+                if values.len() == 1 {
+                    if let FontFamily::Generic(ref name) = values[0] {
+                        return Some(FontFamily::generic(name).1);
+                    }
+                }
+            }
+            None
+        }
+    }
+
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
         fn to_computed_value(&self, _cx: &Context) -> Self::ComputedValue {
             match *self {
                 SpecifiedValue::Values(ref v) => computed_value::T(v.clone()),
                 SpecifiedValue::System(_) => {
                     <%self:nongecko_unreachable>
                         _cx.cached_system_font.as_ref().unwrap().font_family.clone()
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2727,39 +2727,88 @@ pub fn apply_declarations<'a, F, I>(devi
                                              &mut cacheable,
                                              &mut cascade_info,
                                              error_reporter);
         }
         % if category_to_cascade_now == "early":
             let writing_mode = get_writing_mode(context.style.get_inheritedbox());
             context.style.writing_mode = writing_mode;
 
+            let mut _skip_font_family = false;
+
+            % if product == "gecko":
+                // Whenever a single generic value is specified, gecko will do a bunch of
+                // recalculation walking up the rule tree, including handling the font-size stuff.
+                // It basically repopulates the font struct with the default font for a given
+                // generic and language. We handle the font-size stuff separately, so this boils
+                // down to just copying over the font-family lists (no other aspect of the default
+                // font can be configured).
+
+                if seen.contains(LonghandId::XLang) || font_family.is_some() {
+                    // if just the language changed, the inherited generic is all we need
+                    let mut generic = inherited_style.get_font().gecko().mGenericID;
+                    if let Some(declaration) = font_family {
+                        if let PropertyDeclaration::FontFamily(ref fam) = *declaration {
+                            if let Some(id) = fam.single_generic() {
+                                generic = id;
+                                // In case of a specified font family with a single generic, we will
+                                // end up setting font family below, but its value would get
+                                // overwritten later in the pipeline when cascading.
+                                //
+                                // We instead skip cascading font-family in that case.
+                                //
+                                // In case of the language changing, we wish for a specified font-
+                                // family to override this, so we do not skip cascading then.
+                                _skip_font_family = true;
+                            }
+                        }
+                    }
+
+                    // In case of just the language changing, the parent could have had no generic,
+                    // which Gecko just does regular cascading with. Do the same.
+                    // This can only happen in the case where the language changed but the family did not
+                    if generic != structs::kGenericFont_NONE {
+                        let pres_context = context.device.pres_context;
+                        let gecko_font = context.mutate_style().mutate_font().gecko_mut();
+                        gecko_font.mGenericID = generic;
+                        unsafe {
+                            bindings::Gecko_nsStyleFont_PrefillDefaultForGeneric(gecko_font,
+                                                                                 &*pres_context,
+                                                                                 generic);
+                        }
+                    }
+                }
+            % endif
+
             // 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 product == "gecko":
-                    context.style.mutate_font().fixup_none_generic(context.device);
-                % endif
+            if !_skip_font_family {
+                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 product == "gecko":
+                        context.style.mutate_font().fixup_none_generic(context.device);
+                    % endif
+                }
             }
 
             if let Some(declaration) = font_size {
                 let discriminant = LonghandId::FontSize as usize;
                 (CASCADE_PROPERTY[discriminant])(declaration,
                                                  inherited_style,
                                                  default_style,
                                                  &mut context,