Bug 1370734 - Part 2: stylo: Prefill default font when a single generic is set; r?heycam draft
authorManish Goregaokar <manishearth@gmail.com>
Tue, 06 Jun 2017 17:09:08 -0700
changeset 590306 c42d29a3d38f56bc73590e9f5f2423ea774a8d14
parent 590305 13a78924fddd24337c0c2118bfa3af566c6b47b6
child 591207 2298bd841a2656225affb0566289ddb4ba293418
push id62692
push userbmo:manishearth@gmail.com
push dateWed, 07 Jun 2017 15:39:26 +0000
reviewersheycam
bugs1370734
milestone55.0a1
Bug 1370734 - Part 2: stylo: Prefill default font when a single generic is set; r?heycam MozReview-Commit-ID: LooD1QCqrct
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/gecko/generated/bindings.rs
servo/components/style/properties/properties.mako.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -84,33 +84,32 @@ using namespace mozilla::dom;
 
 
 static Mutex* sServoFontMetricsLock = nullptr;
 static RWLock* sServoLangFontPrefsLock = nullptr;
 
 
 static
 const nsFont*
-ThreadSafeGetDefaultFontHelper(const nsPresContext* aPresContext, nsIAtom* aLanguage)
+ThreadSafeGetDefaultFontHelper(const nsPresContext* aPresContext,
+                               nsIAtom* aLanguage, uint8_t aGenericId)
 {
   bool needsCache = false;
   const nsFont* retval;
 
   {
     AutoReadLock guard(*sServoLangFontPrefsLock);
-    retval = aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
-                                          aLanguage, &needsCache);
+    retval = aPresContext->GetDefaultFont(aGenericId, aLanguage, &needsCache);
   }
   if (!needsCache) {
     return retval;
   }
   {
     AutoWriteLock guard(*sServoLangFontPrefsLock);
-  retval = aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
-                                        aLanguage, nullptr);
+  retval = aPresContext->GetDefaultFont(aGenericId, aLanguage, nullptr);
   }
   return retval;
 }
 
 void
 AssertIsMainThreadOrServoLangFontPrefsCacheLocked()
 {
   MOZ_ASSERT(NS_IsMainThread() || sServoLangFontPrefsLock->LockedForWritingByCurrentThread());
@@ -1156,17 +1155,18 @@ Gecko_CopyFontFamilyFrom(nsFont* dst, co
   dst->fontlist = src->fontlist;
 }
 
 void
 Gecko_nsFont_InitSystem(nsFont* aDest, int32_t aFontId,
                         const nsStyleFont* aFont, RawGeckoPresContextBorrowed aPresContext)
 {
   MutexAutoLock lock(*sServoFontMetricsLock);
-  const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage);
+  const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
+                                                                     kPresContext_DefaultVariableFont_ID);
 
   // We have passed uninitialized memory to this function,
   // initialize it. We can't simply return an nsFont because then
   // we need to know its size beforehand. Servo cannot initialize nsFont
   // itself, so this will do.
   nsFont* system = new (aDest) nsFont(*defaultVariableFont);
 
   MOZ_RELEASE_ASSERT(system);
@@ -2058,22 +2058,33 @@ Gecko_nsStyleFont_CopyLangFrom(nsStyleFo
 {
   aFont->mLanguage = aSource->mLanguage;
 }
 
 void
 Gecko_nsStyleFont_FixupNoneGeneric(nsStyleFont* aFont,
                                    RawGeckoPresContextBorrowed aPresContext)
 {
-  const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage);
+  const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
+                                                                     kPresContext_DefaultVariableFont_ID);
   nsRuleNode::FixupNoneGeneric(&aFont->mFont, aPresContext,
                                aFont->mGenericID, defaultVariableFont);
 }
 
 void
+Gecko_nsStyleFont_PrefillDefaultForGeneric(nsStyleFont* aFont,
+                                           RawGeckoPresContextBorrowed aPresContext,
+                                           uint8_t aGenericId)
+{
+  const nsFont* defaultFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
+                                                             aGenericId);
+   aFont->mFont.fontlist = defaultFont->fontlist;
+}
+
+void
 Gecko_nsStyleFont_FixupMinFontSize(nsStyleFont* aFont,
                                    RawGeckoPresContextBorrowed aPresContext)
 {
   nscoord minFontSize;
   bool needsCache = false;
 
   {
     AutoReadLock guard(*sServoLangFontPrefsLock);
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -511,16 +511,19 @@ void Gecko_CSSValue_SetPairList(nsCSSVal
 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);
 void Gecko_nsStyleFont_FixupNoneGeneric(nsStyleFont* font,
                                         RawGeckoPresContextBorrowed pres_context);
+void Gecko_nsStyleFont_PrefillDefaultForGeneric(nsStyleFont* font,
+                                                RawGeckoPresContextBorrowed pres_context,
+                                                uint8_t generic_id);
 void Gecko_nsStyleFont_FixupMinFontSize(nsStyleFont* font,
                                         RawGeckoPresContextBorrowed pres_context);
 FontSizePrefs Gecko_GetBaseSize(nsIAtom* lang);
 
 struct GeckoFontMetrics
 {
   nscoord mChSize;
   nscoord mXSize;
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -1333,16 +1333,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/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2741,39 +2741,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,