Bug 1351200 - Part 3: stylo: Bypass cache when fetching font size prefs from Stylo; r?bholley draft
authorManish Goregaokar <manishearth@gmail.com>
Tue, 04 Apr 2017 11:11:27 -0700
changeset 557490 7b022f16c9320eebaded1fd15c98c5077e3fae45
parent 557489 8c1249e4db89ede3066e7e36a54249325a8ab43c
child 557491 125c876459666b5cde9a50ed1753ace721519720
push id52748
push userbmo:manishearth@gmail.com
push dateThu, 06 Apr 2017 23:02:15 +0000
reviewersbholley
bugs1351200
milestone55.0a1
Bug 1351200 - Part 3: stylo: Bypass cache when fetching font size prefs from Stylo; r?bholley MozReview-Commit-ID: 7WBduQ6lBTC
intl/locale/nsILanguageAtomService.h
intl/locale/nsLanguageAtomService.cpp
intl/locale/nsLanguageAtomService.h
layout/base/StaticPresData.cpp
layout/base/StaticPresData.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/build_gecko.rs
servo/components/style/gecko_bindings/bindings.rs
servo/components/style/gecko_bindings/structs_debug.rs
servo/components/style/gecko_bindings/structs_release.rs
servo/components/style/properties/longhand/font.mako.rs
--- a/intl/locale/nsILanguageAtomService.h
+++ b/intl/locale/nsILanguageAtomService.h
@@ -32,14 +32,19 @@ class nsILanguageAtomService : public ns
                                   nsresult *aError = nullptr) = 0;
   virtual already_AddRefed<nsIAtom>
   LookupCharSet(const nsACString& aCharSet) = 0;
 
   virtual nsIAtom* GetLocaleLanguage() = 0;
 
   virtual nsIAtom* GetLanguageGroup(nsIAtom *aLanguage,
                                     nsresult *aError = nullptr) = 0;
+
+  // Same as GetLanguageGroup, but will not cache anything
+  // and can be used from a different thread
+  virtual nsIAtom* GetUncachedLanguageGroup(nsIAtom *aLanguage,
+                                            nsresult *aError = nullptr) const = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsILanguageAtomService,
                               NS_ILANGUAGEATOMSERVICE_IID)
 
 #endif
--- a/intl/locale/nsLanguageAtomService.cpp
+++ b/intl/locale/nsLanguageAtomService.cpp
@@ -61,45 +61,57 @@ nsLanguageAtomService::GetLocaleLanguage
   return mLocaleLanguage;
 }
 
 nsIAtom*
 nsLanguageAtomService::GetLanguageGroup(nsIAtom *aLanguage,
                                         nsresult *aError)
 {
   nsIAtom *retVal;
-  nsresult res = NS_OK;
 
   retVal = mLangToGroup.GetWeak(aLanguage);
 
   if (!retVal) {
-    nsAutoCString langStr;
-    aLanguage->ToUTF8String(langStr);
+    retVal = GetUncachedLanguageGroup(aLanguage, aError);
+
+    // The hashtable will keep an owning reference to the atom
+    mLangToGroup.Put(aLanguage, retVal);
+  }
+
+  return retVal;
+}
 
-    nsAutoCString langGroupStr;
+nsIAtom*
+nsLanguageAtomService::GetUncachedLanguageGroup(nsIAtom *aLanguage,
+                                                nsresult *aError) const
+{
+  nsIAtom *retVal;
+  nsresult res = NS_OK;
+
+  nsAutoCString langStr;
+  aLanguage->ToUTF8String(langStr);
+
+  nsAutoCString langGroupStr;
+  res = nsUConvPropertySearch::SearchPropertyValue(kLangGroups,
+                                                   ArrayLength(kLangGroups),
+                                                   langStr, langGroupStr);
+  while (NS_FAILED(res)) {
+    int32_t hyphen = langStr.RFindChar('-');
+    if (hyphen <= 0) {
+      langGroupStr.AssignLiteral("x-unicode");
+      break;
+    }
+    langStr.Truncate(hyphen);
     res = nsUConvPropertySearch::SearchPropertyValue(kLangGroups,
                                                      ArrayLength(kLangGroups),
                                                      langStr, langGroupStr);
-    while (NS_FAILED(res)) {
-      int32_t hyphen = langStr.RFindChar('-');
-      if (hyphen <= 0) {
-        langGroupStr.AssignLiteral("x-unicode");
-        break;
-      }
-      langStr.Truncate(hyphen);
-      res = nsUConvPropertySearch::SearchPropertyValue(kLangGroups,
-                                                       ArrayLength(kLangGroups),
-                                                       langStr, langGroupStr);
-    }
+  }
 
-    nsCOMPtr<nsIAtom> langGroup = NS_Atomize(langGroupStr);
+  nsCOMPtr<nsIAtom> langGroup = NS_Atomize(langGroupStr);
 
-    // The hashtable will keep an owning reference to the atom
-    mLangToGroup.Put(aLanguage, langGroup);
-    retVal = langGroup.get();
-  }
+  retVal = langGroup.get();
 
   if (aError) {
     *aError = res;
   }
 
   return retVal;
 }
--- a/intl/locale/nsLanguageAtomService.h
+++ b/intl/locale/nsLanguageAtomService.h
@@ -25,16 +25,18 @@ public:
 
   virtual already_AddRefed<nsIAtom>
     LookupCharSet(const nsACString& aCharSet) override;
 
   virtual nsIAtom* GetLocaleLanguage() override;
 
   virtual nsIAtom* GetLanguageGroup(nsIAtom *aLanguage,
                                                 nsresult *aError) override;
+  virtual nsIAtom* GetUncachedLanguageGroup(nsIAtom *aLanguage,
+                                            nsresult *aError) const final;
 
   nsLanguageAtomService();
 
 private:
   ~nsLanguageAtomService() { }
 
 protected:
   nsInterfaceHashtable<nsISupportsHashKey, nsIAtom> mLangToGroup;
--- a/layout/base/StaticPresData.cpp
+++ b/layout/base/StaticPresData.cpp
@@ -242,16 +242,28 @@ StaticPresData::GetLangGroup(nsIAtom* aL
   nsIAtom* langGroupAtom = nullptr;
   langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
   if (NS_FAILED(rv) || !langGroupAtom) {
     langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
   }
   return langGroupAtom;
 }
 
+nsIAtom*
+StaticPresData::GetUncachedLangGroup(nsIAtom* aLanguage) const
+{
+  nsresult rv = NS_OK;
+  nsIAtom* langGroupAtom = nullptr;
+  langGroupAtom = mLangService->GeUncachedtLanguageGroup(aLanguage, &rv);
+  if (NS_FAILED(rv) || !langGroupAtom) {
+    langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
+  }
+  return langGroupAtom;
+}
+
 const LangGroupFontPrefs*
 StaticPresData::GetFontPrefsForLangHelper(nsIAtom* aLanguage,
                                           const LangGroupFontPrefs* aPrefs) const
 {
   // Get language group for aLanguage:
   MOZ_ASSERT(aLanguage);
   MOZ_ASSERT(mLangService);
   MOZ_ASSERT(aPrefs);
--- a/layout/base/StaticPresData.h
+++ b/layout/base/StaticPresData.h
@@ -94,16 +94,23 @@ public:
   const nscoord* GetBorderWidthTable() { return mBorderWidthTable; }
 
   /**
    * Given a language, get the language group name, which can
    * be used as an argument to LangGroupFontPrefs::Initialize()
    *
    */
   nsIAtom* GetLangGroup(nsIAtom* aLanguage) const;
+
+  /**
+   * Same as GetLangGroup, but will not cache the result
+   *
+   */
+  nsIAtom* GetUncachedLangGroup(nsIAtom* aLanguage) const;
+
   /**
    * Fetch the user's font preferences for the given aLanguage's
    * langugage group.
    *
    * The original code here is pretty old, and includes an optimization
    * whereby language-specific prefs are read per-document, and the
    * results are stored in a linked list, which is assumed to be very short
    * since most documents only ever use one language.
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1523,20 +1523,33 @@ 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)
+FontSizePrefs
+Gecko_GetBaseSize(nsIAtom* aLanguage)
 {
-  return aPresContext->GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
+  LangGroupFontPrefs prefs;
+  nsIAtom* langGroupAtom = StaticPresData::Get()->GetUncachedLangGroup(aLanguage);
+
+  prefs.Initialize(langGroupAtom);
+  FontSizePrefs sizes;
+
+  sizes.mDefaultVariableSize = prefs.mDefaultVariableFont.size;
+  sizes.mDefaultFixedSize = prefs.mDefaultFixedFont.size;
+  sizes.mDefaultSerifSize = prefs.mDefaultSerifFont.size;
+  sizes.mDefaultSansSerifSize = prefs.mDefaultSansSerifFont.size;
+  sizes.mDefaultMonospaceSize = prefs.mDefaultMonospaceFont.size;
+  sizes.mDefaultCursiveSize = prefs.mDefaultCursiveFont.size;
+  sizes.mDefaultFantasySize = prefs.mDefaultFantasyFont.size;
+  return sizes;
 }
 
 void
 Gecko_LoadStyleSheet(css::Loader* aLoader,
                      ServoStyleSheet* aParent,
                      RawServoStyleSheetBorrowed aChildSheet,
                      RawGeckoURLExtraData* aBaseURLData,
                      const uint8_t* aURLString,
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -86,16 +86,28 @@ class ServoBundledURI
 {
 public:
   already_AddRefed<mozilla::css::URLValue> IntoCssUrl();
   const uint8_t* mURLString;
   uint32_t mURLStringLength;
   mozilla::css::URLExtraData* mExtraData;
 };
 
+class FontSizePrefs
+{
+public:
+  nscoord mDefaultVariableSize;
+  nscoord mDefaultFixedSize;
+  nscoord mDefaultSerifSize;
+  nscoord mDefaultSansSerifSize;
+  nscoord mDefaultMonospaceSize;
+  nscoord mDefaultCursiveSize;
+  nscoord mDefaultFantasySize;
+};
+
 // DOM Traversal.
 uint32_t Gecko_ChildrenCount(RawGeckoNodeBorrowed node);
 bool Gecko_NodeIsElement(RawGeckoNodeBorrowed node);
 bool Gecko_IsInDocument(RawGeckoNodeBorrowed node);
 bool Gecko_FlattenedTreeParentIsParent(RawGeckoNodeBorrowed node);
 bool Gecko_IsSignificantChild(RawGeckoNodeBorrowed node,
                               bool text_is_significant,
                               bool whitespace_is_significant);
@@ -363,17 +375,17 @@ void Gecko_CSSValue_SetArray(nsCSSValueB
 void Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut css_value, ServoBundledURI uri);
 void Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut css_value, int32_t integer, nsCSSUnit unit);
 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);
+FontSizePrefs Gecko_GetBaseSize(nsIAtom* lang, RawGeckoPresContextBorrowed pres_context);
 
 const nsMediaFeature* Gecko_GetMediaFeatures();
 
 // Font face rule
 // Creates and returns a new (already-addrefed) nsCSSFontFaceRule object.
 nsCSSFontFaceRule* Gecko_CSSFontFaceRule_Create();
 void Gecko_CSSFontFaceRule_GetCssText(const nsCSSFontFaceRule* rule, nsAString* result);
 NS_DECL_FFI_REFCOUNTING(nsCSSFontFaceRule, CSSFontFaceRule);
--- a/servo/components/style/build_gecko.rs
+++ b/servo/components/style/build_gecko.rs
@@ -325,16 +325,17 @@ mod bindings {
             "CapturingContentInfo",
             "DefaultDelete",
             "DOMIntersectionObserverEntry",
             "Element",
             "FontFamilyList",
             "FontFamilyListRefCnt",
             "FontFamilyName",
             "FontFamilyType",
+            "FontSizePrefs",
             "FragmentOrURL",
             "FrameRequestCallback",
             "GeckoParserExtraData",
             "gfxAlternateValue",
             "gfxFontFeature",
             "gfxFontVariation",
             "GridNamedArea",
             "HalfCorner",
@@ -604,16 +605,17 @@ mod bindings {
             "RawGeckoPresContextOwned",
             "RawGeckoStyleAnimationList",
             "RawGeckoURLExtraData",
             "RefPtr",
             "CSSPseudoClassType",
             "TraversalRootBehavior",
             "FontFamilyList",
             "FontFamilyType",
+            "FontSizePrefs",
             "Keyframe",
             "ServoBundledURI",
             "ServoElementSnapshot",
             "SheetParsingMode",
             "StyleBasicShape",
             "StyleBasicShapeType",
             "StyleShapeSource",
             "nsCSSFontFaceRule",
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -18,16 +18,17 @@ use gecko_bindings::structs::RawGeckoPre
 use gecko_bindings::structs::RawGeckoPresContextOwned;
 use gecko_bindings::structs::RawGeckoStyleAnimationList;
 use gecko_bindings::structs::RawGeckoURLExtraData;
 use gecko_bindings::structs::RefPtr;
 use gecko_bindings::structs::CSSPseudoClassType;
 use gecko_bindings::structs::TraversalRootBehavior;
 use gecko_bindings::structs::FontFamilyList;
 use gecko_bindings::structs::FontFamilyType;
+use gecko_bindings::structs::FontSizePrefs;
 use gecko_bindings::structs::Keyframe;
 use gecko_bindings::structs::ServoBundledURI;
 use gecko_bindings::structs::ServoElementSnapshot;
 use gecko_bindings::structs::SheetParsingMode;
 use gecko_bindings::structs::StyleBasicShape;
 use gecko_bindings::structs::StyleBasicShapeType;
 use gecko_bindings::structs::StyleShapeSource;
 use gecko_bindings::structs::nsCSSFontFaceRule;
@@ -1016,20 +1017,19 @@ 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;
+    pub fn Gecko_GetBaseSize(lang: *mut nsIAtom,
+                             pres_context: RawGeckoPresContextBorrowed)
+     -> FontSizePrefs;
 }
 extern "C" {
     pub fn Gecko_GetMediaFeatures() -> *const nsMediaFeature;
 }
 extern "C" {
     pub fn Gecko_CSSFontFaceRule_Create() -> *mut nsCSSFontFaceRule;
 }
 extern "C" {
--- a/servo/components/style/gecko_bindings/structs_debug.rs
+++ b/servo/components/style/gecko_bindings/structs_debug.rs
@@ -26754,16 +26754,77 @@ pub mod root {
                     const _ as usize } , 16usize , concat ! (
                     "Alignment of field: " , stringify ! ( ServoBundledURI ) ,
                     "::" , stringify ! ( mExtraData ) ));
     }
     impl Clone for ServoBundledURI {
         fn clone(&self) -> Self { *self }
     }
     #[repr(C)]
+    #[derive(Debug, Copy)]
+    pub struct FontSizePrefs {
+        pub mDefaultVariableSize: root::nscoord,
+        pub mDefaultFixedSize: root::nscoord,
+        pub mDefaultSerifSize: root::nscoord,
+        pub mDefaultSansSerifSize: root::nscoord,
+        pub mDefaultMonospaceSize: root::nscoord,
+        pub mDefaultCursiveSize: root::nscoord,
+        pub mDefaultFantasySize: root::nscoord,
+    }
+    #[test]
+    fn bindgen_test_layout_FontSizePrefs() {
+        assert_eq!(::std::mem::size_of::<FontSizePrefs>() , 28usize , concat !
+                   ( "Size of: " , stringify ! ( FontSizePrefs ) ));
+        assert_eq! (::std::mem::align_of::<FontSizePrefs>() , 4usize , concat
+                    ! ( "Alignment of " , stringify ! ( FontSizePrefs ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultVariableSize as * const _ as usize } , 0usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultVariableSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultFixedSize
+                    as * const _ as usize } , 4usize , concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultFixedSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultSerifSize
+                    as * const _ as usize } , 8usize , concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultSerifSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultSansSerifSize as * const _ as usize } , 12usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultSansSerifSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultMonospaceSize as * const _ as usize } , 16usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultMonospaceSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultCursiveSize as * const _ as usize } , 20usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultCursiveSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultFantasySize as * const _ as usize } , 24usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultFantasySize ) ));
+    }
+    impl Clone for FontSizePrefs {
+        fn clone(&self) -> Self { *self }
+    }
+    #[repr(C)]
     #[derive(Debug, Copy, Clone)]
     pub struct nsROCSSPrimitiveValue([u8; 0]);
     #[repr(C)]
     #[derive(Debug, Copy)]
     pub struct nsIDOMCSSFontFaceRule {
         pub _base: root::nsISupports,
     }
     #[repr(C)]
--- a/servo/components/style/gecko_bindings/structs_release.rs
+++ b/servo/components/style/gecko_bindings/structs_release.rs
@@ -26141,16 +26141,77 @@ pub mod root {
                     const _ as usize } , 16usize , concat ! (
                     "Alignment of field: " , stringify ! ( ServoBundledURI ) ,
                     "::" , stringify ! ( mExtraData ) ));
     }
     impl Clone for ServoBundledURI {
         fn clone(&self) -> Self { *self }
     }
     #[repr(C)]
+    #[derive(Debug, Copy)]
+    pub struct FontSizePrefs {
+        pub mDefaultVariableSize: root::nscoord,
+        pub mDefaultFixedSize: root::nscoord,
+        pub mDefaultSerifSize: root::nscoord,
+        pub mDefaultSansSerifSize: root::nscoord,
+        pub mDefaultMonospaceSize: root::nscoord,
+        pub mDefaultCursiveSize: root::nscoord,
+        pub mDefaultFantasySize: root::nscoord,
+    }
+    #[test]
+    fn bindgen_test_layout_FontSizePrefs() {
+        assert_eq!(::std::mem::size_of::<FontSizePrefs>() , 28usize , concat !
+                   ( "Size of: " , stringify ! ( FontSizePrefs ) ));
+        assert_eq! (::std::mem::align_of::<FontSizePrefs>() , 4usize , concat
+                    ! ( "Alignment of " , stringify ! ( FontSizePrefs ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultVariableSize as * const _ as usize } , 0usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultVariableSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultFixedSize
+                    as * const _ as usize } , 4usize , concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultFixedSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultSerifSize
+                    as * const _ as usize } , 8usize , concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultSerifSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultSansSerifSize as * const _ as usize } , 12usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultSansSerifSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultMonospaceSize as * const _ as usize } , 16usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultMonospaceSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultCursiveSize as * const _ as usize } , 20usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultCursiveSize ) ));
+        assert_eq! (unsafe {
+                    & ( * ( 0 as * const FontSizePrefs ) ) .
+                    mDefaultFantasySize as * const _ as usize } , 24usize ,
+                    concat ! (
+                    "Alignment of field: " , stringify ! ( FontSizePrefs ) ,
+                    "::" , stringify ! ( mDefaultFantasySize ) ));
+    }
+    impl Clone for FontSizePrefs {
+        fn clone(&self) -> Self { *self }
+    }
+    #[repr(C)]
     #[derive(Debug, Copy, Clone)]
     pub struct nsROCSSPrimitiveValue([u8; 0]);
     #[repr(C)]
     #[derive(Debug, Copy)]
     pub struct nsIDOMCSSFontFaceRule {
         pub _base: root::nsISupports,
     }
     #[repr(C)]
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -531,17 +531,18 @@
                 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 gecko_bindings::bindings::Gecko_GetBaseSize;
+                use gecko_bindings::structs;
                 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   -
@@ -556,20 +557,29 @@
                     [9,   10,    13,    15,    18,    23,    30,    45],
                     [9,   10,    13,    16,    18,    24,    32,    48]
                 ];
 
                 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_sizes = unsafe {
+                    Gecko_GetBaseSize(cx.style().get_font().gecko().mLanguage.raw(),
+                                      &*cx.device.pres_context)
                 };
+                let base_size = match cx.style().get_font().gecko().mGenericID {
+                    structs::kGenericFont_serif => base_sizes.mDefaultSerifSize,
+                    structs::kGenericFont_sans_serif => base_sizes.mDefaultSansSerifSize,
+                    structs::kGenericFont_monospace => base_sizes.mDefaultMonospaceSize,
+                    structs::kGenericFont_cursive => base_sizes.mDefaultCursiveSize,
+                    structs::kGenericFont_fantasy => base_sizes.mDefaultFantasySize,
+                    x => unreachable!("Unknown generic ID {}", x),
+                };
+
                 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)
                 }
             }