Bug 1261552 - Introduce StaticPresData and hoist some shared functionality into it. r=heycam
authorBobby Holley <bobbyholley@gmail.com>
Thu, 31 Mar 2016 12:47:20 -0700
changeset 291715 74a65e4f87f0dc77bd550c117442173420fbe2a0
parent 291714 f3c202b18fa268a30d4782653f4d2a76ccfeda74
child 291716 767a3ddd89e46554e84b51ee9f80ff1cbd2b91ad
push id30144
push usercbook@mozilla.com
push dateTue, 05 Apr 2016 14:52:26 +0000
treeherdermozilla-central@17a0ded9bb99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1261552
milestone48.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
Bug 1261552 - Introduce StaticPresData and hoist some shared functionality into it. r=heycam The complexity around the font pref cache stuff is really annoying. If we think it's unnecessary, we could remove it in a followup.
layout/base/StaticPresData.cpp
layout/base/StaticPresData.h
layout/base/moz.build
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/build/nsLayoutStatics.cpp
layout/style/nsStyleStruct.cpp
new file mode 100644
--- /dev/null
+++ b/layout/base/StaticPresData.cpp
@@ -0,0 +1,311 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/StaticPresData.h"
+
+#include "mozilla/Preferences.h"
+#include "nsPresContext.h"
+
+namespace mozilla {
+
+static StaticPresData* sSingleton = nullptr;
+
+void
+StaticPresData::Init()
+{
+  MOZ_ASSERT(!sSingleton);
+  sSingleton = new StaticPresData();
+}
+
+void
+StaticPresData::Shutdown()
+{
+  MOZ_ASSERT(sSingleton);
+  delete sSingleton;
+  sSingleton = nullptr;
+}
+
+StaticPresData*
+StaticPresData::Get()
+{
+  MOZ_ASSERT(sSingleton);
+  return sSingleton;
+}
+
+StaticPresData::StaticPresData()
+{
+  mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
+
+  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] = nsPresContext::CSSPixelsToAppUnits(1);
+  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] = nsPresContext::CSSPixelsToAppUnits(3);
+  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] = nsPresContext::CSSPixelsToAppUnits(5);
+}
+
+#define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
+ _pref.Assign(_s0); \
+ _pref.Append(_s1);
+
+static const char* const kGenericFont[] = {
+  ".variable.",
+  ".fixed.",
+  ".serif.",
+  ".sans-serif.",
+  ".monospace.",
+  ".cursive.",
+  ".fantasy."
+};
+
+// These are private, use the list in nsFont.h if you want a public list.
+enum {
+  eDefaultFont_Variable,
+  eDefaultFont_Fixed,
+  eDefaultFont_Serif,
+  eDefaultFont_SansSerif,
+  eDefaultFont_Monospace,
+  eDefaultFont_Cursive,
+  eDefaultFont_Fantasy,
+  eDefaultFont_COUNT
+};
+
+const LangGroupFontPrefs*
+StaticPresData::GetFontPrefsForLangHelper(nsIAtom *aLanguage,
+                                          const LangGroupFontPrefs* aPrefs) const
+{
+  // Get language group for aLanguage:
+  MOZ_ASSERT(aLanguage);
+  MOZ_ASSERT(mLangService);
+  MOZ_ASSERT(aPrefs);
+
+  nsresult rv = NS_OK;
+  nsIAtom *langGroupAtom = nullptr;
+  langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
+  if (NS_FAILED(rv) || !langGroupAtom) {
+    langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
+  }
+
+  LangGroupFontPrefs *prefs = const_cast<LangGroupFontPrefs*>(aPrefs);
+  if (prefs->mLangGroup) { // if initialized
+    DebugOnly<uint32_t> count = 0;
+    for (;;) {
+      NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
+      if (prefs->mLangGroup == langGroupAtom) {
+        return prefs;
+      }
+      if (!prefs->mNext) {
+        break;
+      }
+      prefs = prefs->mNext;
+    }
+
+    // nothing cached, so go on and fetch the prefs for this lang group:
+    prefs = prefs->mNext = new LangGroupFontPrefs;
+  }
+
+  prefs->mLangGroup = langGroupAtom;
+
+  /* Fetch the font prefs to be used -- see bug 61883 for details.
+     Not all prefs are needed upfront. Some are fallback prefs intended
+     for the GFX font sub-system...
+
+  1) unit : assumed to be the same for all language groups -------------
+  font.size.unit = px | pt    XXX could be folded in the size... bug 90440
+
+  2) attributes for generic fonts --------------------------------------
+  font.default.[langGroup] = serif | sans-serif - fallback generic font
+  font.name.[generic].[langGroup] = current user' selected font on the pref dialog
+  font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
+  font.size.[generic].[langGroup] = integer - settable by the user
+  font.size-adjust.[generic].[langGroup] = "float" - settable by the user
+  font.minimum-size.[langGroup] = integer - settable by the user
+  */
+
+  nsAutoCString langGroup;
+  langGroupAtom->ToUTF8String(langGroup);
+
+  prefs->mDefaultVariableFont.size = nsPresContext::CSSPixelsToAppUnits(16);
+  prefs->mDefaultFixedFont.size = nsPresContext::CSSPixelsToAppUnits(13);
+
+  nsAutoCString pref;
+
+  // get the current applicable font-size unit
+  enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
+  int32_t unit = eUnit_px;
+
+  nsAdoptingCString cvalue =
+    Preferences::GetCString("font.size.unit");
+
+  if (!cvalue.IsEmpty()) {
+    if (cvalue.EqualsLiteral("px")) {
+      unit = eUnit_px;
+    }
+    else if (cvalue.EqualsLiteral("pt")) {
+      unit = eUnit_pt;
+    }
+    else {
+      // XXX should really send this warning to the user (Error Console?).
+      // And just default to unit = eUnit_px?
+      NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
+      unit = eUnit_unknown;
+    }
+  }
+
+  // get font.minimum-size.[langGroup]
+
+  MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
+
+  int32_t size = Preferences::GetInt(pref.get());
+  if (unit == eUnit_px) {
+    prefs->mMinimumFontSize = nsPresContext::CSSPixelsToAppUnits(size);
+  }
+  else if (unit == eUnit_pt) {
+    prefs->mMinimumFontSize = nsPresContext::CSSPointsToAppUnits(size);
+  }
+
+  nsFont* fontTypes[] = {
+    &prefs->mDefaultVariableFont,
+    &prefs->mDefaultFixedFont,
+    &prefs->mDefaultSerifFont,
+    &prefs->mDefaultSansSerifFont,
+    &prefs->mDefaultMonospaceFont,
+    &prefs->mDefaultCursiveFont,
+    &prefs->mDefaultFantasyFont
+  };
+  static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
+                "FontTypes array count is not correct");
+
+  // Get attributes specific to each generic font. We do not get the user's
+  // generic-font-name-to-specific-family-name preferences because its the
+  // generic name that should be fed into the cascade. It is up to the GFX
+  // code to look up the font prefs to convert generic names to specific
+  // family names as necessary.
+  nsAutoCString generic_dot_langGroup;
+  for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
+    generic_dot_langGroup.Assign(kGenericFont[eType]);
+    generic_dot_langGroup.Append(langGroup);
+
+    nsFont* font = fontTypes[eType];
+
+    // set the default variable font (the other fonts are seen as 'generic' fonts
+    // in GFX and will be queried there when hunting for alternative fonts)
+    if (eType == eDefaultFont_Variable) {
+      MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
+
+      nsAdoptingString value = Preferences::GetString(pref.get());
+      if (!value.IsEmpty()) {
+        FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
+        FontFamilyType defaultType = defaultVariableName.mType;
+        NS_ASSERTION(defaultType == eFamily_serif ||
+                     defaultType == eFamily_sans_serif,
+                     "default type must be serif or sans-serif");
+        prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
+      }
+      else {
+        MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
+        value = Preferences::GetString(pref.get());
+        if (!value.IsEmpty()) {
+          FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
+          FontFamilyType defaultType = defaultVariableName.mType;
+          NS_ASSERTION(defaultType == eFamily_serif ||
+                       defaultType == eFamily_sans_serif,
+                       "default type must be serif or sans-serif");
+          prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
+        }
+      }
+    }
+    else {
+      if (eType == eDefaultFont_Monospace) {
+        // This takes care of the confusion whereby people often expect "monospace"
+        // to have the same default font-size as "-moz-fixed" (this tentative
+        // size may be overwritten with the specific value for "monospace" when
+        // "font.size.monospace.[langGroup]" is read -- see below)
+        prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
+      }
+      else if (eType != eDefaultFont_Fixed) {
+        // all the other generic fonts are initialized with the size of the
+        // variable font, but their specific size can supersede later -- see below
+        font->size = prefs->mDefaultVariableFont.size;
+      }
+    }
+
+    // Bug 84398: for spec purists, a different font-size only applies to the
+    // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
+    // The problem is that only GfxWin has the support for |font-size-adjust|. So for
+    // parity, we enable the ability to set a different font-size on all platforms.
+
+    // get font.size.[generic].[langGroup]
+    // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
+    MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
+    size = Preferences::GetInt(pref.get());
+    if (size > 0) {
+      if (unit == eUnit_px) {
+        font->size = nsPresContext::CSSPixelsToAppUnits(size);
+      }
+      else if (unit == eUnit_pt) {
+        font->size = nsPresContext::CSSPointsToAppUnits(size);
+      }
+    }
+
+    // get font.size-adjust.[generic].[langGroup]
+    // XXX only applicable on GFX ports that handle |font-size-adjust|
+    MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
+    cvalue = Preferences::GetCString(pref.get());
+    if (!cvalue.IsEmpty()) {
+      font->sizeAdjust = (float)atof(cvalue.get());
+    }
+
+#ifdef DEBUG_rbs
+    printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
+           generic_dot_langGroup.get(),
+           NS_ConvertUTF16toUTF8(font->name).get(), font->size,
+           font->sizeAdjust);
+#endif
+  }
+
+  return prefs;
+}
+
+const nsFont*
+StaticPresData::GetDefaultFontHelper(uint8_t aFontID, nsIAtom *aLanguage,
+                                     const LangGroupFontPrefs* aPrefs) const
+{
+  MOZ_ASSERT(aLanguage);
+  MOZ_ASSERT(aPrefs);
+
+  const nsFont *font;
+  switch (aFontID) {
+    // Special (our default variable width font and fixed width font)
+    case kPresContext_DefaultVariableFont_ID:
+      font = &aPrefs->mDefaultVariableFont;
+      break;
+    case kPresContext_DefaultFixedFont_ID:
+      font = &aPrefs->mDefaultFixedFont;
+      break;
+    // CSS
+    case kGenericFont_serif:
+      font = &aPrefs->mDefaultSerifFont;
+      break;
+    case kGenericFont_sans_serif:
+      font = &aPrefs->mDefaultSansSerifFont;
+      break;
+    case kGenericFont_monospace:
+      font = &aPrefs->mDefaultMonospaceFont;
+      break;
+    case kGenericFont_cursive:
+      font = &aPrefs->mDefaultCursiveFont;
+      break;
+    case kGenericFont_fantasy:
+      font = &aPrefs->mDefaultFantasyFont;
+      break;
+    default:
+      font = nullptr;
+      NS_ERROR("invalid arg");
+      break;
+  }
+  return font;
+}
+
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/base/StaticPresData.h
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_StaticPresData_h
+#define mozilla_StaticPresData_h
+
+#include "nsAutoPtr.h"
+#include "nsCoord.h"
+#include "nsCOMPtr.h"
+#include "nsFont.h"
+#include "nsIAtom.h"
+#include "nsILanguageAtomService.h"
+
+namespace mozilla {
+
+struct LangGroupFontPrefs {
+  // Font sizes default to zero; they will be set in GetFontPreferences
+  LangGroupFontPrefs()
+    : mLangGroup(nullptr)
+    , mMinimumFontSize(0)
+    , mDefaultVariableFont(mozilla::eFamily_serif, 0)
+    , mDefaultFixedFont(mozilla::eFamily_monospace, 0)
+    , mDefaultSerifFont(mozilla::eFamily_serif, 0)
+    , mDefaultSansSerifFont(mozilla::eFamily_sans_serif, 0)
+    , mDefaultMonospaceFont(mozilla::eFamily_monospace, 0)
+    , mDefaultCursiveFont(mozilla::eFamily_cursive, 0)
+    , mDefaultFantasyFont(mozilla::eFamily_fantasy, 0)
+  {}
+
+  void Reset()
+  {
+    // Throw away any other LangGroupFontPrefs objects:
+    mNext = nullptr;
+
+    // Make GetFontPreferences reinitialize mLangGroupFontPrefs:
+    mLangGroup = nullptr;
+  }
+
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
+    size_t n = 0;
+    LangGroupFontPrefs* curr = mNext;
+    while (curr) {
+      n += aMallocSizeOf(curr);
+
+      // Measurement of the following members may be added later if DMD finds
+      // it is worthwhile:
+      // - mLangGroup
+      // - mDefault*Font
+
+      curr = curr->mNext;
+    }
+    return n;
+  }
+
+  nsCOMPtr<nsIAtom> mLangGroup;
+  nscoord mMinimumFontSize;
+  nsFont mDefaultVariableFont;
+  nsFont mDefaultFixedFont;
+  nsFont mDefaultSerifFont;
+  nsFont mDefaultSansSerifFont;
+  nsFont mDefaultMonospaceFont;
+  nsFont mDefaultCursiveFont;
+  nsFont mDefaultFantasyFont;
+  nsAutoPtr<LangGroupFontPrefs> mNext;
+};
+
+/**
+ * Some functionality that has historically lived on nsPresContext does not
+ * actually need to be per-document. This singleton class serves as a host
+ * for that functionality. We delegate to it from nsPresContext where
+ * appropriate, and use it standalone in some cases as well.
+ */
+class StaticPresData
+{
+public:
+  // Initialization and shutdown of the singleton. Called exactly once.
+  static void Init();
+  static void Shutdown();
+
+  // Gets an instance of the singleton. Infallible between the calls to Init
+  // and Shutdown.
+  static StaticPresData* Get();
+
+  /**
+   * This table maps border-width enums 'thin', 'medium', 'thick'
+   * to actual nscoord values.
+   */
+  const nscoord* GetBorderWidthTable() { return mBorderWidthTable; }
+
+  /**
+   * 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.
+   *
+   * Storing this per-session rather than per-document would almost certainly
+   * be fine. But just to be on the safe side, we leave the old mechanism as-is,
+   * with an additional per-session cache that new callers can use if they don't
+   * have a PresContext.
+   */
+  const LangGroupFontPrefs* GetFontPrefsForLangHelper(nsIAtom* aLanguage,
+                                                      const LangGroupFontPrefs* aPrefs) const;
+  /**
+   * Get the default font for the given language and generic font ID.
+   * aLanguage may not be nullptr.
+   *
+   * This object is read-only, you must copy the font to modify it.
+   *
+   * When aFontID is kPresContext_DefaultVariableFontID or
+   * kPresContext_DefaultFixedFontID (which equals
+   * kGenericFont_moz_fixed, which is used for the -moz-fixed generic),
+   * the nsFont returned has its name as a CSS generic family (serif or
+   * sans-serif for the former, monospace for the latter), and its size
+   * as the default font size for variable or fixed fonts for the
+   * language group.
+   *
+   * For aFontID corresponding to a CSS Generic, the nsFont returned has
+   * its name set to that generic font's name, and its size set to
+   * the user's preference for font size for that generic and the
+   * given language.
+   */
+  const nsFont* GetDefaultFontHelper(uint8_t aFontID,
+                                     nsIAtom* aLanguage,
+                                     const LangGroupFontPrefs* aPrefs) const;
+
+  /*
+   * These versions operate on the font pref cache on StaticPresData.
+   */
+
+  const nsFont* GetDefaultFont(uint8_t aFontID, nsIAtom* aLanguage) const
+  {
+    MOZ_ASSERT(aLanguage);
+    return GetDefaultFontHelper(aFontID, aLanguage, GetFontPrefsForLang(aLanguage));
+  }
+  const LangGroupFontPrefs* GetFontPrefsForLang(nsIAtom* aLanguage) const
+  {
+    MOZ_ASSERT(aLanguage);
+    return GetFontPrefsForLangHelper(aLanguage, &mStaticLangGroupFontPrefs);
+  }
+
+  void ResetCachedFontPrefs() { mStaticLangGroupFontPrefs.Reset(); }
+
+private:
+  StaticPresData();
+  ~StaticPresData() {}
+
+  nsCOMPtr<nsILanguageAtomService> mLangService;
+  nscoord mBorderWidthTable[3];
+  LangGroupFontPrefs mStaticLangGroupFontPrefs;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_StaticPresData_h
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -104,16 +104,17 @@ EXPORTS.mozilla += [
     'ArenaRefPtrInlines.h',
     'GeometryUtils.h',
     'PaintTracker.h',
     'RestyleLogging.h',
     'RestyleManager.h',
     'RestyleManagerHandle.h',
     'RestyleManagerHandleInlines.h',
     'ServoRestyleManager.h',
+    'StaticPresData.h',
 ]
 
 UNIFIED_SOURCES += [
     'AccessibleCaret.cpp',
     'AccessibleCaretEventHub.cpp',
     'AccessibleCaretManager.cpp',
     'ActiveLayerTracker.cpp',
     'DisplayItemClip.cpp',
@@ -149,16 +150,17 @@ UNIFIED_SOURCES += [
     'nsStyleSheetService.cpp',
     'PaintTracker.cpp',
     'PositionedEventTargeting.cpp',
     'RestyleManager.cpp',
     'RestyleTracker.cpp',
     'ScrollbarStyles.cpp',
     'ServoRestyleManager.cpp',
     'StackArena.cpp',
+    'StaticPresData.cpp',
     'TouchManager.cpp',
     'ZoomConstraintsClient.cpp',
 ]
 
 # nsPresArena.cpp needs to be built separately because it uses plarena.h.
 # nsRefreshDriver.cpp needs to be built separately because of name clashes in the OS X headers
 SOURCES += [
     'nsPresArena.cpp',
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -392,251 +392,30 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   // NS_RELEASE(tmp->mLanguage); // an atom
   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
 
   tmp->Destroy();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-
-#define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
- _pref.Assign(_s0); \
- _pref.Append(_s1);
-
-static const char* const kGenericFont[] = {
-  ".variable.",
-  ".fixed.",
-  ".serif.",
-  ".sans-serif.",
-  ".monospace.",
-  ".cursive.",
-  ".fantasy."
-};
-
 // whether no native theme service exists;
 // if this gets set to true, we'll stop asking for it.
 static bool sNoTheme = false;
 
 // Set to true when LookAndFeelChanged needs to be called.  This is used
 // because the look and feel is a service, so there's no need to notify it from
 // more than one prescontext.
 static bool sLookAndFeelChanged;
 
 // Set to true when ThemeChanged needs to be called on mTheme.  This is used
 // because mTheme is a service, so there's no need to notify it from more than
 // one prescontext.
 static bool sThemeChanged;
 
-const nsPresContext::LangGroupFontPrefs*
-nsPresContext::GetFontPrefsForLang(nsIAtom *aLanguage) const
-{
-  // Get language group for aLanguage:
-
-  nsresult rv = NS_OK;
-  nsIAtom *langGroupAtom = nullptr;
-  if (!aLanguage) {
-    aLanguage = mLanguage;
-  }
-  if (aLanguage && mLangService) {
-    langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
-  }
-  if (NS_FAILED(rv) || !langGroupAtom) {
-    langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
-  }
-
-  // Look for cached prefs for this lang group.
-  // Most documents will only use one (or very few) language groups. Rather
-  // than have the overhead of a hash lookup, we simply look along what will
-  // typically be a very short (usually of length 1) linked list. There are 31
-  // language groups, so in the worst case scenario we'll need to traverse 31
-  // link items.
-
-  LangGroupFontPrefs *prefs =
-    const_cast<LangGroupFontPrefs*>(&mLangGroupFontPrefs);
-  if (prefs->mLangGroup) { // if initialized
-    DebugOnly<uint32_t> count = 0;
-    for (;;) {
-      NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
-      if (prefs->mLangGroup == langGroupAtom) {
-        return prefs;
-      }
-      if (!prefs->mNext) {
-        break;
-      }
-      prefs = prefs->mNext;
-    }
-
-    // nothing cached, so go on and fetch the prefs for this lang group:
-    prefs = prefs->mNext = new LangGroupFontPrefs;
-  }
-
-  prefs->mLangGroup = langGroupAtom;
-
-  /* Fetch the font prefs to be used -- see bug 61883 for details.
-     Not all prefs are needed upfront. Some are fallback prefs intended
-     for the GFX font sub-system...
-
-  1) unit : assumed to be the same for all language groups -------------
-  font.size.unit = px | pt    XXX could be folded in the size... bug 90440
-
-  2) attributes for generic fonts --------------------------------------
-  font.default.[langGroup] = serif | sans-serif - fallback generic font
-  font.name.[generic].[langGroup] = current user' selected font on the pref dialog
-  font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
-  font.size.[generic].[langGroup] = integer - settable by the user
-  font.size-adjust.[generic].[langGroup] = "float" - settable by the user
-  font.minimum-size.[langGroup] = integer - settable by the user
-  */
-
-  nsAutoCString langGroup;
-  langGroupAtom->ToUTF8String(langGroup);
-
-  prefs->mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
-  prefs->mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
-
-  nsAutoCString pref;
-
-  // get the current applicable font-size unit
-  enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
-  int32_t unit = eUnit_px;
-
-  nsAdoptingCString cvalue =
-    Preferences::GetCString("font.size.unit");
-
-  if (!cvalue.IsEmpty()) {
-    if (cvalue.EqualsLiteral("px")) {
-      unit = eUnit_px;
-    }
-    else if (cvalue.EqualsLiteral("pt")) {
-      unit = eUnit_pt;
-    }
-    else {
-      // XXX should really send this warning to the user (Error Console?).
-      // And just default to unit = eUnit_px?
-      NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
-      unit = eUnit_unknown;
-    }
-  }
-
-  // get font.minimum-size.[langGroup]
-
-  MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
-
-  int32_t size = Preferences::GetInt(pref.get());
-  if (unit == eUnit_px) {
-    prefs->mMinimumFontSize = CSSPixelsToAppUnits(size);
-  }
-  else if (unit == eUnit_pt) {
-    prefs->mMinimumFontSize = CSSPointsToAppUnits(size);
-  }
-
-  nsFont* fontTypes[] = {
-    &prefs->mDefaultVariableFont,
-    &prefs->mDefaultFixedFont,
-    &prefs->mDefaultSerifFont,
-    &prefs->mDefaultSansSerifFont,
-    &prefs->mDefaultMonospaceFont,
-    &prefs->mDefaultCursiveFont,
-    &prefs->mDefaultFantasyFont
-  };
-  static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
-                "FontTypes array count is not correct");
-
-  // Get attributes specific to each generic font. We do not get the user's
-  // generic-font-name-to-specific-family-name preferences because its the
-  // generic name that should be fed into the cascade. It is up to the GFX
-  // code to look up the font prefs to convert generic names to specific
-  // family names as necessary.
-  nsAutoCString generic_dot_langGroup;
-  for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
-    generic_dot_langGroup.Assign(kGenericFont[eType]);
-    generic_dot_langGroup.Append(langGroup);
-
-    nsFont* font = fontTypes[eType];
-
-    // set the default variable font (the other fonts are seen as 'generic' fonts
-    // in GFX and will be queried there when hunting for alternative fonts)
-    if (eType == eDefaultFont_Variable) {
-      MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
-
-      nsAdoptingString value = Preferences::GetString(pref.get());
-      if (!value.IsEmpty()) {
-        FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
-        FontFamilyType defaultType = defaultVariableName.mType;
-        NS_ASSERTION(defaultType == eFamily_serif ||
-                     defaultType == eFamily_sans_serif,
-                     "default type must be serif or sans-serif");
-        prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
-      }
-      else {
-        MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
-        value = Preferences::GetString(pref.get());
-        if (!value.IsEmpty()) {
-          FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
-          FontFamilyType defaultType = defaultVariableName.mType;
-          NS_ASSERTION(defaultType == eFamily_serif ||
-                       defaultType == eFamily_sans_serif,
-                       "default type must be serif or sans-serif");
-          prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
-        }
-      }
-    }
-    else {
-      if (eType == eDefaultFont_Monospace) {
-        // This takes care of the confusion whereby people often expect "monospace"
-        // to have the same default font-size as "-moz-fixed" (this tentative
-        // size may be overwritten with the specific value for "monospace" when
-        // "font.size.monospace.[langGroup]" is read -- see below)
-        prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
-      }
-      else if (eType != eDefaultFont_Fixed) {
-        // all the other generic fonts are initialized with the size of the
-        // variable font, but their specific size can supersede later -- see below
-        font->size = prefs->mDefaultVariableFont.size;
-      }
-    }
-
-    // Bug 84398: for spec purists, a different font-size only applies to the
-    // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
-    // The problem is that only GfxWin has the support for |font-size-adjust|. So for
-    // parity, we enable the ability to set a different font-size on all platforms.
-
-    // get font.size.[generic].[langGroup]
-    // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
-    MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
-    size = Preferences::GetInt(pref.get());
-    if (size > 0) {
-      if (unit == eUnit_px) {
-        font->size = CSSPixelsToAppUnits(size);
-      }
-      else if (unit == eUnit_pt) {
-        font->size = CSSPointsToAppUnits(size);
-      }
-    }
-
-    // get font.size-adjust.[generic].[langGroup]
-    // XXX only applicable on GFX ports that handle |font-size-adjust|
-    MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
-    cvalue = Preferences::GetCString(pref.get());
-    if (!cvalue.IsEmpty()) {
-      font->sizeAdjust = (float)atof(cvalue.get());
-    }
-
-#ifdef DEBUG_rbs
-    printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
-           generic_dot_langGroup.get(),
-           NS_ConvertUTF16toUTF8(font->name).get(), font->size,
-           font->sizeAdjust);
-#endif
-  }
-
-  return prefs;
-}
-
 void
 nsPresContext::GetDocumentColorPreferences()
 {
   // Make sure the preferences are initialized.  In the normal run,
   // they would already be, because gfxPlatform would have been created,
   // but in some reference tests, that is not the case.
   gfxPrefs::GetSingleton();
 
@@ -795,17 +574,18 @@ nsPresContext::GetUserPreferences()
   mBodyTextColor = mDefaultColor;
 
   // * use fonts?
   mUseDocumentFonts =
     Preferences::GetInt("browser.display.use_document_fonts") != 0;
 
   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
 
-  ResetCachedFontPrefs();
+  mLangGroupFontPrefs.Reset();
+  StaticPresData::Get()->ResetCachedFontPrefs();
 
   // * image animation
   const nsAdoptingCString& animatePref =
     Preferences::GetCString("image.animation_mode");
   if (animatePref.EqualsLiteral("normal"))
     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   else if (animatePref.EqualsLiteral("none"))
     mImageAnimationModePref = imgIContainer::kDontAnimMode;
@@ -1231,17 +1011,17 @@ nsPresContext::UpdateCharSet(const nsCSt
   if (mLangService) {
     mLanguage = mLangService->LookupCharSet(aCharSet);
     // this will be a language group (or script) code rather than a true language code
 
     // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
     if (mLanguage == nsGkAtoms::Unicode) {
       mLanguage = mLangService->GetLocaleLanguage();
     }
-    ResetCachedFontPrefs();
+    mLangGroupFontPrefs.Reset();
   }
 
   switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
 
     case IBMBIDI_TEXTTYPE_LOGICAL:
       SetVisualMode(false);
       break;
 
@@ -1470,54 +1250,16 @@ nsPresContext::SetImageAnimationModeInte
 }
 
 void
 nsPresContext::SetImageAnimationModeExternal(uint16_t aMode)
 {
   SetImageAnimationModeInternal(aMode);
 }
 
-const nsFont*
-nsPresContext::GetDefaultFont(uint8_t aFontID, nsIAtom *aLanguage) const
-{
-  const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
-
-  const nsFont *font;
-  switch (aFontID) {
-    // Special (our default variable width font and fixed width font)
-    case kPresContext_DefaultVariableFont_ID:
-      font = &prefs->mDefaultVariableFont;
-      break;
-    case kPresContext_DefaultFixedFont_ID:
-      font = &prefs->mDefaultFixedFont;
-      break;
-    // CSS
-    case kGenericFont_serif:
-      font = &prefs->mDefaultSerifFont;
-      break;
-    case kGenericFont_sans_serif:
-      font = &prefs->mDefaultSansSerifFont;
-      break;
-    case kGenericFont_monospace:
-      font = &prefs->mDefaultMonospaceFont;
-      break;
-    case kGenericFont_cursive:
-      font = &prefs->mDefaultCursiveFont;
-      break;
-    case kGenericFont_fantasy:
-      font = &prefs->mDefaultFantasyFont;
-      break;
-    default:
-      font = nullptr;
-      NS_ERROR("invalid arg");
-      break;
-  }
-  return font;
-}
-
 already_AddRefed<nsIAtom>
 nsPresContext::GetContentLanguage() const
 {
   nsAutoString language;
   Document()->GetContentLanguage(language);
   language.StripWhitespace();
 
   // Content-Language may be a comma-separated list of language codes,
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -37,16 +37,17 @@
 #include "prclist.h"
 #include "nsThreadUtils.h"
 #include "ScrollbarStyles.h"
 #include "nsIMessageManager.h"
 #include "mozilla/RestyleLogging.h"
 #include "Units.h"
 #include "mozilla/RestyleManagerHandle.h"
 #include "prenv.h"
+#include "mozilla/StaticPresData.h"
 
 class nsAString;
 class nsIPrintSettings;
 class nsDocShell;
 class nsIDocShell;
 class nsIDocument;
 class nsILanguageAtomService;
 class nsITheme;
@@ -130,17 +131,19 @@ public:
 class nsRootPresContext;
 
 // An interface for presentation contexts. Presentation contexts are
 // objects that provide an outer context for a presentation shell.
 
 class nsPresContext : public nsIObserver {
 public:
   typedef mozilla::FramePropertyTable FramePropertyTable;
+  typedef mozilla::LangGroupFontPrefs LangGroupFontPrefs;
   typedef mozilla::ScrollbarStyles ScrollbarStyles;
+  typedef mozilla::StaticPresData StaticPresData;
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
   NS_DECL_CYCLE_COLLECTION_CLASS(nsPresContext)
 
   enum nsPresContextType {
     eContext_Galley,       // unpaginated screen presentation
@@ -360,33 +363,25 @@ public:
     if (mShell)
       mShell->FreeMisc(aSize, aFreeChunk);
   }
 
   /**
    * Get the default font for the given language and generic font ID.
    * If aLanguage is nullptr, the document's language is used.
    *
-   * This object is read-only, you must copy the font to modify it.
-   *
-   * When aFontID is kPresContext_DefaultVariableFontID or
-   * kPresContext_DefaultFixedFontID (which equals
-   * kGenericFont_moz_fixed, which is used for the -moz-fixed generic),
-   * the nsFont returned has its name as a CSS generic family (serif or
-   * sans-serif for the former, monospace for the latter), and its size
-   * as the default font size for variable or fixed fonts for the
-   * language group.
-   *
-   * For aFontID corresponding to a CSS Generic, the nsFont returned has
-   * its name set to that generic font's name, and its size set to
-   * the user's preference for font size for that generic and the
-   * given language.
+   * See the comment in StaticPresData::GetDefaultFont.
    */
   const nsFont* GetDefaultFont(uint8_t aFontID,
-                                           nsIAtom *aLanguage) const;
+                               nsIAtom *aLanguage) const
+  {
+    nsIAtom* lang = aLanguage ? aLanguage : mLanguage.get();
+    return StaticPresData::Get()->GetDefaultFontHelper(aFontID, lang,
+                                                       GetFontPrefsForLang(lang));
+  }
 
   /** Get a cached boolean pref, by its type */
   // *  - initially created for bugs 31816, 20760, 22963
   bool GetCachedBoolPref(nsPresContext_CachedBoolPrefType aPrefType) const
   {
     // If called with a constant parameter, the compiler should optimize
     // this switch statement away.
     switch (aPrefType) {
@@ -1120,74 +1115,24 @@ protected:
   void PreferenceChanged(const char* aPrefName);
   static void PrefChangedCallback(const char*, void*);
 
   void UpdateAfterPreferencesChanged();
   static void PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure);
 
   void GetUserPreferences();
 
-  // Allow nsAutoPtr<LangGroupFontPrefs> dtor to access this protected struct's
-  // dtor:
-  struct LangGroupFontPrefs;
-  friend class nsAutoPtr<LangGroupFontPrefs>;
-  struct LangGroupFontPrefs {
-    // Font sizes default to zero; they will be set in GetFontPreferences
-    LangGroupFontPrefs()
-      : mLangGroup(nullptr)
-      , mMinimumFontSize(0)
-      , mDefaultVariableFont(mozilla::eFamily_serif, 0)
-      , mDefaultFixedFont(mozilla::eFamily_monospace, 0)
-      , mDefaultSerifFont(mozilla::eFamily_serif, 0)
-      , mDefaultSansSerifFont(mozilla::eFamily_sans_serif, 0)
-      , mDefaultMonospaceFont(mozilla::eFamily_monospace, 0)
-      , mDefaultCursiveFont(mozilla::eFamily_cursive, 0)
-      , mDefaultFantasyFont(mozilla::eFamily_fantasy, 0)
-    {}
-
-    size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
-      size_t n = 0;
-      LangGroupFontPrefs *curr = mNext;
-      while (curr) {
-        n += aMallocSizeOf(curr);
-
-        // Measurement of the following members may be added later if DMD finds
-        // it is worthwhile:
-        // - mLangGroup
-        // - mDefault*Font
-
-        curr = curr->mNext;
-      }
-      return n;
-    }
-
-    nsCOMPtr<nsIAtom> mLangGroup;
-    nscoord mMinimumFontSize;
-    nsFont mDefaultVariableFont;
-    nsFont mDefaultFixedFont;
-    nsFont mDefaultSerifFont;
-    nsFont mDefaultSansSerifFont;
-    nsFont mDefaultMonospaceFont;
-    nsFont mDefaultCursiveFont;
-    nsFont mDefaultFantasyFont;
-    nsAutoPtr<LangGroupFontPrefs> mNext;
-  };
-
   /**
    * Fetch the user's font preferences for the given aLanguage's
    * langugage group.
    */
-  const LangGroupFontPrefs* GetFontPrefsForLang(nsIAtom *aLanguage) const;
-
-  void ResetCachedFontPrefs() {
-    // Throw away any other LangGroupFontPrefs objects:
-    mLangGroupFontPrefs.mNext = nullptr;
-
-    // Make GetFontPreferences reinitialize mLangGroupFontPrefs:
-    mLangGroupFontPrefs.mLangGroup = nullptr;
+  const LangGroupFontPrefs* GetFontPrefsForLang(nsIAtom *aLanguage) const
+  {
+    nsIAtom* lang = aLanguage ? aLanguage : mLanguage.get();
+    return StaticPresData::Get()->GetFontPrefsForLangHelper(lang, &mLangGroupFontPrefs);
   }
 
   void UpdateCharSet(const nsCString& aCharSet);
 
 public:
   void DoChangeCharSet(const nsCString& aCharSet);
 
   /**
@@ -1327,16 +1272,21 @@ protected:
   ScrollbarStyles       mViewportStyleScrollbar;
   uint8_t               mFocusRingWidth;
 
   bool mExistThrottledUpdates;
 
   uint16_t              mImageAnimationMode;
   uint16_t              mImageAnimationModePref;
 
+  // Most documents will only use one (or very few) language groups. Rather
+  // than have the overhead of a hash lookup, we simply look along what will
+  // typically be a very short (usually of length 1) linked list. There are 31
+  // language groups, so in the worst case scenario we'll need to traverse 31
+  // link items.
   LangGroupFontPrefs    mLangGroupFontPrefs;
 
   nscoord               mBorderWidthTable[3];
 
   uint32_t              mInterruptChecksToSkip;
 
   // Counters for tests and tools that want to detect frame construction
   // or reflow.
@@ -1428,28 +1378,16 @@ protected:
   bool                  mInitialized;
 #endif
 
 
 protected:
 
   virtual ~nsPresContext();
 
-  // these are private, use the list in nsFont.h if you want a public list
-  enum {
-    eDefaultFont_Variable,
-    eDefaultFont_Fixed,
-    eDefaultFont_Serif,
-    eDefaultFont_SansSerif,
-    eDefaultFont_Monospace,
-    eDefaultFont_Cursive,
-    eDefaultFont_Fantasy,
-    eDefaultFont_COUNT
-  };
-
   nscolor MakeColorPref(const nsString& aColor);
 
   void LastRelease();
 
 #ifdef DEBUG
 private:
   friend struct nsAutoLayoutPhase;
   uint32_t mLayoutPhaseCount[eLayoutPhase_COUNT];
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -126,16 +126,17 @@ using namespace mozilla::system;
 #include "mozilla/IMEStateManager.h"
 #include "nsDocument.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CameraPreferences.h"
 #include "TouchManager.h"
 #include "MediaDecoder.h"
 #include "mozilla/layers/CompositorLRU.h"
 #include "mozilla/dom/devicestorage/DeviceStorageStatics.h"
+#include "mozilla/StaticPresData.h"
 
 #ifdef MOZ_B2G_BT
 #include "mozilla/dom/BluetoothUUID.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::net;
 using namespace mozilla::dom;
@@ -192,16 +193,17 @@ nsLayoutStatics::Initialize()
   rv = nsTextFragment::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsTextFragment");
     return rv;
   }
 
   nsCellMap::Init();
 
+  StaticPresData::Init();
   nsCSSRendering::Init();
 
   nsTextFrameTextRunCache::Init();
 
   rv = nsHTMLDNSPrefetch::Initialize();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize HTML DNS prefetch");
     return rv;
@@ -342,16 +344,17 @@ nsLayoutStatics::Shutdown()
   Attr::Shutdown();
   EventListenerManager::Shutdown();
   IMEStateManager::Shutdown();
   nsCSSParser::Shutdown();
   nsCSSRuleProcessor::Shutdown();
   nsTextFrameTextRunCache::Shutdown();
   nsHTMLDNSPrefetch::Shutdown();
   nsCSSRendering::Shutdown();
+  StaticPresData::Shutdown();
 #ifdef DEBUG
   nsFrame::DisplayReflowShutdown();
 #endif
   nsCellMap::Shutdown();
   ActiveLayerTracker::Shutdown();
 
   // Release all of our atoms
   nsColorNames::ReleaseTable();
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -104,17 +104,17 @@ nsStyleFont::nsStyleFont(const nsFont& a
   , mGenericID(kGenericFont_NONE)
   , mScriptLevel(0)
   , mMathVariant(NS_MATHML_MATHVARIANT_NONE)
   , mMathDisplay(NS_MATHML_DISPLAYSTYLE_INLINE)
   , mMinFontSizeRatio(100) // 100%
   , mExplicitLanguage(false)
   , mAllowZoom(true)
   , mScriptUnconstrainedSize(mSize)
-  , mScriptMinSize(aPresContext->CSSTwipsToAppUnits(
+  , mScriptMinSize(nsPresContext::CSSTwipsToAppUnits(
       NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT)))
   , mScriptSizeMultiplier(NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER)
   , mLanguage(GetLanguage(aPresContext))
 {
   MOZ_COUNT_CTOR(nsStyleFont);
   mFont.size = mSize;
 }
 
@@ -368,17 +368,17 @@ nsStyleBorder::nsStyleBorder(nsPresConte
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
   NS_FOR_CSS_HALF_CORNERS (corner) {
     mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
   }
 
   nscoord medium =
-    (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
+    (StaticPresData::Get()->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
   NS_FOR_CSS_SIDES(side) {
     mBorderImageSlice.Set(side, nsStyleCoord(1.0f, eStyleUnit_Percent));
     mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
     mBorderImageOutset.Set(side, nsStyleCoord(0.0f, eStyleUnit_Factor));
 
     mBorder.Side(side) = medium;
     mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
     mBorderColor[side] = NS_RGB(0, 0, 0);
@@ -755,17 +755,18 @@ nsChangeHint nsStyleXUL::CalcDifference(
 nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
 {
   MOZ_COUNT_CTOR(nsStyleColumn);
   mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
   mColumnWidth.SetAutoValue();
   mColumnGap.SetNormalValue();
   mColumnFill = NS_STYLE_COLUMN_FILL_BALANCE;
 
-  mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
+  mColumnRuleWidth =
+    (StaticPresData::Get()->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
   mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
   mColumnRuleColor = NS_RGB(0, 0, 0);
   mColumnRuleColorIsForeground = true;
 
   mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel();
 }
 
 nsStyleColumn::~nsStyleColumn()