Bug 1418899 - Part 2: Move some font-related static methods out of nsRuleNode. r=TYLin draft
authorCameron McCormack <cam@mcc.id.au>
Mon, 20 Nov 2017 12:43:21 +0800
changeset 701032 26031748b63044676a2e8620053bfb7dc6c52b18
parent 701031 2a007a693f125d383d2e5b66c53132d2903c7865
child 701033 2b7d7ff48c4d8cc06e82f8b5d76c65376d26d767
push id90037
push userbmo:cam@mcc.id.au
push dateTue, 21 Nov 2017 04:39:57 +0000
reviewersTYLin
bugs1418899
milestone59.0a1
Bug 1418899 - Part 2: Move some font-related static methods out of nsRuleNode. r=TYLin MozReview-Commit-ID: 3l9L6bHr0PJ
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/style/FontFaceSet.cpp
layout/style/ServoBindings.cpp
layout/style/nsRuleNode.cpp
layout/style/nsRuleNode.h
layout/style/nsStyleUtil.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -10068,8 +10068,234 @@ nsLayoutUtils::ComputeOffsetToUserSpace(
 
 /* static */ uint8_t
 nsLayoutUtils::ControlCharVisibilityDefault()
 {
   return StylePrefs::sControlCharVisibility
     ? NS_STYLE_CONTROL_CHARACTER_VISIBILITY_VISIBLE
     : NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
 }
+
+/* static */
+already_AddRefed<nsFontMetrics>
+nsLayoutUtils::GetMetricsFor(nsPresContext* aPresContext,
+                             bool aIsVertical,
+                             const nsStyleFont* aStyleFont,
+                             nscoord aFontSize,
+                             bool aUseUserFontSet,
+                             FlushUserFontSet aFlushUserFontSet)
+{
+  nsFont font = aStyleFont->mFont;
+  font.size = aFontSize;
+  gfxFont::Orientation orientation
+    = aIsVertical ? gfxFont::eVertical : gfxFont::eHorizontal;
+  nsFontMetrics::Params params;
+  params.language = aStyleFont->mLanguage;
+  params.explicitLanguage = aStyleFont->mExplicitLanguage;
+  params.orientation = orientation;
+  params.userFontSet = aUseUserFontSet
+    ? aPresContext->GetUserFontSet(aFlushUserFontSet == FlushUserFontSet::Yes)
+    : nullptr;
+  params.textPerf = aPresContext->GetTextPerfMetrics();
+  return aPresContext->DeviceContext()->GetMetricsFor(font, params);
+}
+
+/* static */ void
+nsLayoutUtils::FixupNoneGeneric(nsFont* aFont,
+                                const nsPresContext* aPresContext,
+                                uint8_t aGenericFontID,
+                                const nsFont* aDefaultVariableFont)
+{
+  bool useDocumentFonts =
+    aPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
+  if (aGenericFontID == kGenericFont_NONE ||
+      (!useDocumentFonts && (aGenericFontID == kGenericFont_cursive ||
+                             aGenericFontID == kGenericFont_fantasy))) {
+    FontFamilyType defaultGeneric =
+      aDefaultVariableFont->fontlist.GetDefaultFontType();
+    MOZ_ASSERT(aDefaultVariableFont->fontlist.IsEmpty() &&
+               (defaultGeneric == eFamily_serif ||
+                defaultGeneric == eFamily_sans_serif));
+    if (defaultGeneric != eFamily_none) {
+      if (useDocumentFonts) {
+        aFont->fontlist.SetDefaultFontType(defaultGeneric);
+      } else {
+        // Either prioritize the first generic in the list,
+        // or (if there isn't one) prepend the default variable font.
+        if (!aFont->fontlist.PrioritizeFirstGeneric()) {
+          aFont->fontlist.PrependGeneric(defaultGeneric);
+        }
+      }
+    }
+  } else {
+    aFont->fontlist.SetDefaultFontType(eFamily_none);
+  }
+}
+
+/* static */ void
+nsLayoutUtils::ApplyMinFontSize(nsStyleFont* aFont,
+                                const nsPresContext* aPresContext,
+                                nscoord aMinFontSize)
+{
+  nscoord fontSize = aFont->mSize;
+
+  // enforce the user' specified minimum font-size on the value that we expose
+  // (but don't change font-size:0, since that would unhide hidden text)
+  if (fontSize > 0) {
+    if (aMinFontSize < 0) {
+      aMinFontSize = 0;
+    } else {
+      aMinFontSize = (aMinFontSize * aFont->mMinFontSizeRatio) / 100;
+    }
+    if (fontSize < aMinFontSize && !aPresContext->IsChrome()) {
+      // override the minimum font-size constraint
+      fontSize = aMinFontSize;
+    }
+  }
+  aFont->mFont.size = fontSize;
+}
+
+/* static */ void
+nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, LookAndFeel::FontID aFontID,
+                                 const nsPresContext* aPresContext,
+                                 const nsFont* aDefaultVariableFont)
+{
+  gfxFontStyle fontStyle;
+  float devPerCSS =
+    (float)nsPresContext::AppUnitsPerCSSPixel() /
+    aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
+  nsAutoString systemFontName;
+  if (LookAndFeel::GetFont(aFontID, systemFontName, fontStyle, devPerCSS)) {
+    systemFontName.Trim("\"'");
+    aSystemFont->fontlist = FontFamilyList(systemFontName, eUnquotedName);
+    aSystemFont->fontlist.SetDefaultFontType(eFamily_none);
+    aSystemFont->style = fontStyle.style;
+    aSystemFont->systemFont = fontStyle.systemFont;
+    aSystemFont->weight = fontStyle.weight;
+    aSystemFont->stretch = fontStyle.stretch;
+    aSystemFont->size =
+      NSFloatPixelsToAppUnits(fontStyle.size,
+                              aPresContext->DeviceContext()->
+                                AppUnitsPerDevPixelAtUnitFullZoom());
+    //aSystemFont->langGroup = fontStyle.langGroup;
+    aSystemFont->sizeAdjust = fontStyle.sizeAdjust;
+
+#ifdef XP_WIN
+    // XXXldb This platform-specific stuff should be in the
+    // LookAndFeel implementation, not here.
+    // XXXzw Should we even still *have* this code?  It looks to be making
+    // old, probably obsolete assumptions.
+
+    if (aFontID == LookAndFeel::eFont_Field ||
+        aFontID == LookAndFeel::eFont_Button ||
+        aFontID == LookAndFeel::eFont_List) {
+      // As far as I can tell the system default fonts and sizes
+      // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
+      // all pre-determined and cannot be changed by either the control panel
+      // or programmatically.
+      // Fields (text fields)
+      // Button and Selects (listboxes/comboboxes)
+      //    We use whatever font is defined by the system. Which it appears
+      //    (and the assumption is) it is always a proportional font. Then we
+      //    always use 2 points smaller than what the browser has defined as
+      //    the default proportional font.
+      // Assumption: system defined font is proportional
+      aSystemFont->size =
+        std::max(aDefaultVariableFont->size -
+                 nsPresContext::CSSPointsToAppUnits(2), 0);
+    }
+#endif
+  }
+}
+
+static inline void
+AssertValidFontTag(const nsString& aString)
+{
+  // To be valid as a font feature tag, a string MUST be:
+  MOZ_ASSERT(aString.Length() == 4 &&              // (1) exactly 4 chars long
+             NS_IsAscii(aString.BeginReading()) && // (2) entirely ASCII
+             isprint(aString[0]) &&                // (3) all printable chars
+             isprint(aString[1]) &&
+             isprint(aString[2]) &&
+             isprint(aString[3]));
+}
+
+/* static */ void
+nsLayoutUtils::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
+                                   nsTArray<gfxFontFeature>& aFeatureSettings)
+{
+  aFeatureSettings.Clear();
+  for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
+    gfxFontFeature feat;
+
+    MOZ_ASSERT(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
+               "unexpected value unit");
+
+    // tag is a 4-byte ASCII sequence
+    nsAutoString tag;
+    p->mXValue.GetStringValue(tag);
+    AssertValidFontTag(tag);
+    if (tag.Length() != 4) {
+      continue;
+    }
+    // parsing validates that these are ASCII chars
+    // tags are always big-endian
+    feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
+
+    // value
+    NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
+                 "should have found an integer unit");
+    feat.mValue = p->mYValue.GetIntValue();
+
+    aFeatureSettings.AppendElement(feat);
+  }
+}
+
+/* static */ void
+nsLayoutUtils::ComputeFontVariations(const nsCSSValuePairList* aVariationsList,
+                                     nsTArray<gfxFontVariation>& aVariationSettings)
+{
+  aVariationSettings.Clear();
+  for (const nsCSSValuePairList* p = aVariationsList; p; p = p->mNext) {
+    gfxFontVariation var;
+
+    MOZ_ASSERT(aVariationsList->mXValue.GetUnit() == eCSSUnit_String,
+               "unexpected value unit");
+
+    // tag is a 4-byte ASCII sequence
+    nsAutoString tag;
+    p->mXValue.GetStringValue(tag);
+    AssertValidFontTag(tag);
+    if (tag.Length() != 4) {
+      continue;
+    }
+    // parsing validates that these are ASCII chars
+    // tags are always big-endian
+    var.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
+
+    // value
+    NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Number,
+                 "should have found a number unit");
+    var.mValue = p->mYValue.GetFloatValue();
+
+    aVariationSettings.AppendElement(var);
+  }
+}
+
+/* static */ uint32_t
+nsLayoutUtils::ParseFontLanguageOverride(const nsAString& aLangTag)
+{
+  if (!aLangTag.Length() || aLangTag.Length() > 4) {
+    return NO_FONT_LANGUAGE_OVERRIDE;
+  }
+  uint32_t index, result = 0;
+  for (index = 0; index < aLangTag.Length(); ++index) {
+    char16_t ch = aLangTag[index];
+    if (!nsCRT::IsAscii(ch)) { // valid tags are pure ASCII
+      return NO_FONT_LANGUAGE_OVERRIDE;
+    }
+    result = (result << 8) + ch;
+  }
+  while (index++ < 4) {
+    result = (result << 8) + 0x20;
+  }
+  return result;
+}
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -3050,16 +3050,58 @@ public:
 
   static nsPoint ComputeOffsetToUserSpace(nsDisplayListBuilder* aBuilder,
                                           nsIFrame* aFrame);
 
   // Return the default value to be used for -moz-control-character-visibility,
   // from preferences.
   static uint8_t ControlCharVisibilityDefault();
 
+  enum class FlushUserFontSet {
+    Yes,
+    No,
+  };
+
+  static already_AddRefed<nsFontMetrics> GetMetricsFor(nsPresContext* aPresContext,
+                                                       bool aIsVertical,
+                                                       const nsStyleFont* aStyleFont,
+                                                       nscoord aFontSize,
+                                                       bool aUseUserFontSet,
+                                                       FlushUserFontSet aFlushUserFontSet);
+
+  /**
+   * Appropriately add the correct font if we are using DocumentFonts or
+   * overriding for XUL
+   */
+  static void FixupNoneGeneric(nsFont* aFont,
+                               const nsPresContext* aPresContext,
+                               uint8_t aGenericFontID,
+                               const nsFont* aDefaultVariableFont);
+
+  /**
+   * For an nsStyleFont with mSize set, apply minimum font size constraints
+   * from preferences, as well as -moz-min-font-size-ratio.
+   */
+  static void ApplyMinFontSize(nsStyleFont* aFont,
+                               const nsPresContext* aPresContext,
+                               nscoord aMinFontSize);
+
+  static void ComputeSystemFont(nsFont* aSystemFont,
+                                mozilla::LookAndFeel::FontID aFontID,
+                                const nsPresContext* aPresContext,
+                                const nsFont* aDefaultVariableFont);
+
+  static void ComputeFontFeatures(const nsCSSValuePairList* aFeaturesList,
+                                  nsTArray<gfxFontFeature>& aFeatureSettings);
+
+  static void ComputeFontVariations(const nsCSSValuePairList* aVariationsList,
+                                    nsTArray<gfxFontVariation>& aVariationSettings);
+
+  static uint32_t ParseFontLanguageOverride(const nsAString& aLangTag);
+
 private:
   static uint32_t sFontSizeInflationEmPerLine;
   static uint32_t sFontSizeInflationMinTwips;
   static uint32_t sFontSizeInflationLineThreshold;
   static int32_t  sFontSizeInflationMappingIntercept;
   static uint32_t sFontSizeInflationMaxRatio;
   static bool sFontSizeInflationForceEnabled;
   static bool sFontSizeInflationDisabledInMasterProcess;
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -38,16 +38,17 @@
 #include "nsINetworkPredictor.h"
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
 #include "nsISupportsPriority.h"
 #include "nsIWebNavigation.h"
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 #include "nsIInputStream.h"
+#include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsPrintfCString.h"
 #include "nsStyleSet.h"
 #include "nsUTF8Utils.h"
 #include "nsDOMNavigationTiming.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
@@ -1062,31 +1063,31 @@ FontFaceSet::FindOrCreateUserFontEntryFr
 
   // set up font features
   nsTArray<gfxFontFeature> featureSettings;
   aFontFace->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
   unit = val.GetUnit();
   if (unit == eCSSUnit_Normal) {
     // empty list of features
   } else if (unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep) {
-    nsRuleNode::ComputeFontFeatures(val.GetPairListValue(), featureSettings);
+    nsLayoutUtils::ComputeFontFeatures(val.GetPairListValue(), featureSettings);
   } else {
     NS_ASSERTION(unit == eCSSUnit_Null,
                  "@font-face font-feature-settings has unexpected unit");
   }
 
   // set up font language override
   aFontFace->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
   unit = val.GetUnit();
   if (unit == eCSSUnit_Normal) {
     // empty feature string
   } else if (unit == eCSSUnit_String) {
     nsString stringValue;
     val.GetStringValue(stringValue);
-    languageOverride = nsRuleNode::ParseFontLanguageOverride(stringValue);
+    languageOverride = nsLayoutUtils::ParseFontLanguageOverride(stringValue);
   } else {
     NS_ASSERTION(unit == eCSSUnit_Null,
                  "@font-face font-language-override has unexpected unit");
   }
 
   // set up unicode-range
   gfxCharacterMap* unicodeRanges = aFontFace->GetUnicodeRangeAsCharacterMap();
 
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1335,17 +1335,18 @@ Gecko_nsFont_InitSystem(nsFont* aDest, i
   nsFont* system = new (aDest) nsFont(*defaultVariableFont);
 
   MOZ_RELEASE_ASSERT(system);
 
   *aDest = *defaultVariableFont;
   LookAndFeel::FontID fontID = static_cast<LookAndFeel::FontID>(aFontId);
 
   AutoWriteLock guard(*sServoFFILock);
-  nsRuleNode::ComputeSystemFont(aDest, fontID, aPresContext, defaultVariableFont);
+  nsLayoutUtils::ComputeSystemFont(aDest, fontID, aPresContext,
+                                   defaultVariableFont);
 }
 
 void
 Gecko_nsFont_Destroy(nsFont* aDest)
 {
   aDest->~nsFont();
 }
 
@@ -2352,20 +2353,21 @@ Gecko_nsStyleFont_CopyLangFrom(nsStyleFo
 {
   aFont->mLanguage = aSource->mLanguage;
 }
 
 void
 Gecko_nsStyleFont_FixupNoneGeneric(nsStyleFont* aFont,
                                    RawGeckoPresContextBorrowed aPresContext)
 {
-  const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
-                                                                     kPresContext_DefaultVariableFont_ID);
-  nsRuleNode::FixupNoneGeneric(&aFont->mFont, aPresContext,
-                               aFont->mGenericID, defaultVariableFont);
+  const nsFont* defaultVariableFont =
+    ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
+                                   kPresContext_DefaultVariableFont_ID);
+  nsLayoutUtils::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,
@@ -2392,17 +2394,17 @@ Gecko_nsStyleFont_FixupMinFontSize(nsSty
     minFontSize = aPresContext->MinFontSize(aFont->mLanguage, &needsCache);
   }
 
   if (needsCache) {
     AutoWriteLock guard(*sServoFFILock);
     minFontSize = aPresContext->MinFontSize(aFont->mLanguage, nullptr);
   }
 
-  nsRuleNode::ApplyMinFontSize(aFont, aPresContext, minFontSize);
+  nsLayoutUtils::ApplyMinFontSize(aFont, aPresContext, minFontSize);
 }
 
 void
 FontSizePrefs::CopyFrom(const LangGroupFontPrefs& prefs)
 {
   mDefaultVariableSize = prefs.mDefaultVariableFont.size;
   mDefaultFixedSize = prefs.mDefaultFixedFont.size;
   mDefaultSerifSize = prefs.mDefaultSerifFont.size;
@@ -2508,19 +2510,19 @@ Gecko_GetFontMetrics(RawGeckoPresContext
   // and if so, appends PostTraversalTasks to the current ServoStyleSet
   // to be performed immediately after the traversal is finished.  This
   // works well for starting downloadable font loads, since we don't have
   // those fonts available to get metrics for anyway.  Platform fonts and
   // ArrayBuffer-backed FontFace objects are handled synchronously.
 
   nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
   presContext->SetUsesExChUnits(true);
-  RefPtr<nsFontMetrics> fm = nsRuleNode::GetMetricsFor(
+  RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
       presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet,
-      nsRuleNode::FlushUserFontSet::No);
+      nsLayoutUtils::FlushUserFontSet::No);
 
   ret.mXSize = fm->XHeight();
   gfxFloat zeroWidth = fm->GetThebesFontGroup()->GetFirstValidFont()->
                            GetMetrics(fm->Orientation()).zeroOrAveCharWidth;
   ret.mChSize = ceil(aPresContext->AppUnitsPerDevPixel() * zeroWidth);
   return ret;
 }
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -369,112 +369,31 @@ static inline nscoord ScaleViewportCoord
   // to avoid introducing error.
   return NSToCoordTruncClamped(aValue.GetFloatValue() *
                                aViewportSize / 100.0f);
 }
 
 /* static */
 already_AddRefed<nsFontMetrics>
 nsRuleNode::GetMetricsFor(nsPresContext* aPresContext,
-                          bool aIsVertical,
-                          const nsStyleFont* aStyleFont,
-                          nscoord aFontSize,
-                          bool aUseUserFontSet,
-                          FlushUserFontSet aFlushUserFontSet)
-{
-  nsFont font = aStyleFont->mFont;
-  font.size = aFontSize;
-  gfxFont::Orientation orientation
-    = aIsVertical ? gfxFont::eVertical : gfxFont::eHorizontal;
-  nsFontMetrics::Params params;
-  params.language = aStyleFont->mLanguage;
-  params.explicitLanguage = aStyleFont->mExplicitLanguage;
-  params.orientation = orientation;
-  params.userFontSet = aUseUserFontSet
-    ? aPresContext->GetUserFontSet(aFlushUserFontSet == FlushUserFontSet::Yes)
-    : nullptr;
-  params.textPerf = aPresContext->GetTextPerfMetrics();
-  return aPresContext->DeviceContext()->GetMetricsFor(font, params);
-}
-
-/* static */
-already_AddRefed<nsFontMetrics>
-nsRuleNode::GetMetricsFor(nsPresContext* aPresContext,
                           nsStyleContext* aStyleContext,
                           const nsStyleFont* aStyleFont,
                           nscoord aFontSize, // overrides value from aStyleFont
                           bool aUseUserFontSet)
 {
   bool isVertical = false;
   if (aStyleContext) {
     WritingMode wm(aStyleContext);
     if (wm.IsVertical() && !wm.IsSideways()) {
       isVertical = true;
     }
   }
-  return nsRuleNode::GetMetricsFor(
+  return nsLayoutUtils::GetMetricsFor(
       aPresContext, isVertical, aStyleFont, aFontSize, aUseUserFontSet,
-      FlushUserFontSet::Yes);
-}
-
-/* static */
-void
-nsRuleNode::FixupNoneGeneric(nsFont* aFont,
-                             const nsPresContext* aPresContext,
-                             uint8_t aGenericFontID,
-                             const nsFont* aDefaultVariableFont)
-{
-  bool useDocumentFonts =
-    aPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
-  if (aGenericFontID == kGenericFont_NONE ||
-      (!useDocumentFonts && (aGenericFontID == kGenericFont_cursive ||
-                             aGenericFontID == kGenericFont_fantasy))) {
-    FontFamilyType defaultGeneric =
-      aDefaultVariableFont->fontlist.GetDefaultFontType();
-    MOZ_ASSERT(aDefaultVariableFont->fontlist.IsEmpty() &&
-               (defaultGeneric == eFamily_serif ||
-                defaultGeneric == eFamily_sans_serif));
-    if (defaultGeneric != eFamily_none) {
-      if (useDocumentFonts) {
-        aFont->fontlist.SetDefaultFontType(defaultGeneric);
-      } else {
-        // Either prioritize the first generic in the list,
-        // or (if there isn't one) prepend the default variable font.
-        if (!aFont->fontlist.PrioritizeFirstGeneric()) {
-          aFont->fontlist.PrependGeneric(defaultGeneric);
-        }
-      }
-    }
-  } else {
-    aFont->fontlist.SetDefaultFontType(eFamily_none);
-  }
-}
-
-/* static */
-void
-nsRuleNode::ApplyMinFontSize(nsStyleFont* aFont,
-                             const nsPresContext* aPresContext,
-                             nscoord aMinFontSize)
-{
-  nscoord fontSize = aFont->mSize;
-
-  // enforce the user' specified minimum font-size on the value that we expose
-  // (but don't change font-size:0, since that would unhide hidden text)
-  if (fontSize > 0) {
-    if (aMinFontSize < 0) {
-      aMinFontSize = 0;
-    } else {
-      aMinFontSize = (aMinFontSize * aFont->mMinFontSizeRatio) / 100;
-    }
-    if (fontSize < aMinFontSize && !aPresContext->IsChrome()) {
-      // override the minimum font-size constraint
-      fontSize = aMinFontSize;
-    }
-  }
-  aFont->mFont.size = fontSize;
+      nsLayoutUtils::FlushUserFontSet::Yes);
 }
 
 static nsSize CalcViewportUnitsScale(nsPresContext* aPresContext)
 {
   // The caller is making use of viewport units, so notify the style set
   // that it will need to rebuild the rule tree if the size of the viewport
   // changes.
   // It is possible for this to be called on a Servo-styled document,from
@@ -3561,69 +3480,16 @@ static int8_t ClampTo8Bit(int32_t aValue
   if (aValue < -128)
     return -128;
   if (aValue > 127)
     return 127;
   return int8_t(aValue);
 }
 
 /* static */ void
-nsRuleNode::ComputeSystemFont(nsFont* aSystemFont, LookAndFeel::FontID aFontID,
-                              const nsPresContext* aPresContext,
-                              const nsFont* aDefaultVariableFont)
-{
-  gfxFontStyle fontStyle;
-  float devPerCSS =
-    (float)nsPresContext::AppUnitsPerCSSPixel() /
-    aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
-  nsAutoString systemFontName;
-  if (LookAndFeel::GetFont(aFontID, systemFontName, fontStyle, devPerCSS)) {
-    systemFontName.Trim("\"'");
-    aSystemFont->fontlist = FontFamilyList(systemFontName, eUnquotedName);
-    aSystemFont->fontlist.SetDefaultFontType(eFamily_none);
-    aSystemFont->style = fontStyle.style;
-    aSystemFont->systemFont = fontStyle.systemFont;
-    aSystemFont->weight = fontStyle.weight;
-    aSystemFont->stretch = fontStyle.stretch;
-    aSystemFont->size =
-      NSFloatPixelsToAppUnits(fontStyle.size,
-                              aPresContext->DeviceContext()->
-                                AppUnitsPerDevPixelAtUnitFullZoom());
-    //aSystemFont->langGroup = fontStyle.langGroup;
-    aSystemFont->sizeAdjust = fontStyle.sizeAdjust;
-
-#ifdef XP_WIN
-    // XXXldb This platform-specific stuff should be in the
-    // LookAndFeel implementation, not here.
-    // XXXzw Should we even still *have* this code?  It looks to be making
-    // old, probably obsolete assumptions.
-
-    if (aFontID == LookAndFeel::eFont_Field ||
-        aFontID == LookAndFeel::eFont_Button ||
-        aFontID == LookAndFeel::eFont_List) {
-      // As far as I can tell the system default fonts and sizes
-      // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
-      // all pre-determined and cannot be changed by either the control panel
-      // or programmatically.
-      // Fields (text fields)
-      // Button and Selects (listboxes/comboboxes)
-      //    We use whatever font is defined by the system. Which it appears
-      //    (and the assumption is) it is always a proportional font. Then we
-      //    always use 2 points smaller than what the browser has defined as
-      //    the default proportional font.
-      // Assumption: system defined font is proportional
-      aSystemFont->size =
-        std::max(aDefaultVariableFont->size -
-                 nsPresContext::CSSPointsToAppUnits(2), 0);
-    }
-#endif
-  }
-}
-
-/* static */ void
 nsRuleNode::SetFont(nsPresContext* aPresContext, GeckoStyleContext* aContext,
                     uint8_t aGenericFontID, const nsRuleData* aRuleData,
                     const nsStyleFont* aParentFont,
                     nsStyleFont* aFont, bool aUsedStartStruct,
                     RuleNodeCacheConditions& aConditions)
 {
   bool atRoot = !aContext->GetParent();
 
@@ -3681,28 +3547,28 @@ nsRuleNode::SetFont(nsPresContext* aPres
 
   // Fall back to defaultVariableFont.
   Maybe<nsFont> lazySystemFont;
   const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
   if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
     lazySystemFont.emplace(*defaultVariableFont);
     LookAndFeel::FontID fontID =
       (LookAndFeel::FontID)systemFontValue->GetIntValue();
-    ComputeSystemFont(lazySystemFont.ptr(), fontID, aPresContext,
-                      defaultVariableFont);
+    nsLayoutUtils::ComputeSystemFont(lazySystemFont.ptr(), fontID, aPresContext,
+                                     defaultVariableFont);
   }
   const nsFont& systemFont = lazySystemFont.refOr(*defaultVariableFont);
 
   // font-family: font family list, enum, inherit
   switch (aRuleData->ValueForFontFamily()->GetUnit()) {
     case eCSSUnit_FontFamilyList:
       // set the correct font if we are using DocumentFonts OR we are overriding
       // for XUL - MJA: bug 31816
-      nsRuleNode::FixupNoneGeneric(&aFont->mFont, aPresContext,
-                                   aGenericFontID, defaultVariableFont);
+      nsLayoutUtils::FixupNoneGeneric(&aFont->mFont, aPresContext,
+                                      aGenericFontID, defaultVariableFont);
 
       aFont->mFont.systemFont = false;
       // Technically this is redundant with the code below, but it's good
       // to have since we'll still want it once we get rid of
       // SetGenericFont (bug 380915).
       aFont->mGenericID = aGenericFontID;
       break;
     case eCSSUnit_System_Font:
@@ -3719,18 +3585,18 @@ nsRuleNode::SetFont(nsPresContext* aPres
       MOZ_FALLTHROUGH;  // Fall through here to check for a lang change.
     case eCSSUnit_Null:
       // If we have inheritance (cases eCSSUnit_Inherit, eCSSUnit_Unset, and
       // eCSSUnit_Null) and a (potentially different) language is explicitly
       // specified, then we need to overwrite the inherited default generic font
       // with the default generic from defaultVariableFont, which is computed
       // using aFont->mLanguage above.
       if (aRuleData->ValueForLang()->GetUnit() != eCSSUnit_Null) {
-        FixupNoneGeneric(&aFont->mFont, aPresContext, aGenericFontID,
-                         defaultVariableFont);
+        nsLayoutUtils::FixupNoneGeneric(&aFont->mFont, aPresContext,
+                                        aGenericFontID, defaultVariableFont);
       }
       break;
     case eCSSUnit_Initial:
       aFont->mFont.fontlist = defaultVariableFont->fontlist;
       aFont->mFont.systemFont = defaultVariableFont->systemFont;
       aFont->mGenericID = kGenericFont_NONE;
       break;
     default:
@@ -4022,18 +3888,19 @@ nsRuleNode::SetFont(nsPresContext* aPres
       break;
 
     case eCSSUnit_System_Font:
       aFont->mFont.fontFeatureSettings = systemFont.fontFeatureSettings;
       break;
 
     case eCSSUnit_PairList:
     case eCSSUnit_PairListDep:
-      ComputeFontFeatures(featureSettingsValue->GetPairListValue(),
-                          aFont->mFont.fontFeatureSettings);
+      nsLayoutUtils::ComputeFontFeatures(
+        featureSettingsValue->GetPairListValue(),
+        aFont->mFont.fontFeatureSettings);
       break;
 
     default:
       MOZ_ASSERT(false, "unexpected value unit");
       break;
   }
 
   // font-variation-settings
@@ -4057,18 +3924,19 @@ nsRuleNode::SetFont(nsPresContext* aPres
       break;
 
     case eCSSUnit_System_Font:
       aFont->mFont.fontVariationSettings = systemFont.fontVariationSettings;
       break;
 
     case eCSSUnit_PairList:
     case eCSSUnit_PairListDep:
-      ComputeFontVariations(variationSettingsValue->GetPairListValue(),
-                            aFont->mFont.fontVariationSettings);
+      nsLayoutUtils::ComputeFontVariations(
+        variationSettingsValue->GetPairListValue(),
+        aFont->mFont.fontVariationSettings);
       break;
 
     default:
       MOZ_ASSERT(false, "unexpected value unit");
       break;
   }
 
   // font-language-override
@@ -4081,17 +3949,18 @@ nsRuleNode::SetFont(nsPresContext* aPres
   } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
              eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
     aFont->mFont.languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
   } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
     aFont->mFont.languageOverride = systemFont.languageOverride;
   } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
     nsAutoString lang;
     languageOverrideValue->GetStringValue(lang);
-    aFont->mFont.languageOverride = ParseFontLanguageOverride(lang);
+    aFont->mFont.languageOverride =
+      nsLayoutUtils::ParseFontLanguageOverride(lang);
   }
 
   // -moz-min-font-size-ratio: percent, inherit
   const nsCSSValue* minFontSizeRatio = aRuleData->ValueForMinFontSizeRatio();
   switch (minFontSizeRatio->GetUnit()) {
     case eCSSUnit_Null:
       break;
     case eCSSUnit_Unset:
@@ -4172,103 +4041,29 @@ nsRuleNode::SetFont(nsPresContext* aPres
                 &aFont->mScriptUnconstrainedSize,
                 systemFont, aParentFont->mScriptUnconstrainedSize,
                 scriptLevelAdjustedUnconstrainedParentSize,
                 aUsedStartStruct, atRoot, unconstrainedConditions);
   }
   NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
                "scriptminsize should never be making things bigger");
 
-  nsRuleNode::ApplyMinFontSize(aFont, aPresContext,
-                               aPresContext->MinFontSize(aFont->mLanguage));
+  nsLayoutUtils::ApplyMinFontSize(aFont, aPresContext,
+                                  aPresContext->MinFontSize(aFont->mLanguage));
 
   // font-size-adjust: number, none, inherit, initial, -moz-system-font
   const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
   if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
     aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
   } else
     SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
               aConditions, aParentFont->mFont.sizeAdjust, -1.0f,
               SETFCT_NONE | SETFCT_UNSET_INHERIT);
 }
 
-static inline void
-AssertValidFontTag(const nsString& aString)
-{
-  // To be valid as a font feature tag, a string MUST be:
-  MOZ_ASSERT(aString.Length() == 4 &&              // (1) exactly 4 chars long
-             NS_IsAscii(aString.BeginReading()) && // (2) entirely ASCII
-             isprint(aString[0]) &&                // (3) all printable chars
-             isprint(aString[1]) &&
-             isprint(aString[2]) &&
-             isprint(aString[3]));
-}
-
-/* static */ void
-nsRuleNode::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
-                                nsTArray<gfxFontFeature>& aFeatureSettings)
-{
-  aFeatureSettings.Clear();
-  for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
-    gfxFontFeature feat;
-
-    MOZ_ASSERT(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
-               "unexpected value unit");
-
-    // tag is a 4-byte ASCII sequence
-    nsAutoString tag;
-    p->mXValue.GetStringValue(tag);
-    AssertValidFontTag(tag);
-    if (tag.Length() != 4) {
-      continue;
-    }
-    // parsing validates that these are ASCII chars
-    // tags are always big-endian
-    feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
-
-    // value
-    NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
-                 "should have found an integer unit");
-    feat.mValue = p->mYValue.GetIntValue();
-
-    aFeatureSettings.AppendElement(feat);
-  }
-}
-
-/* static */ void
-nsRuleNode::ComputeFontVariations(const nsCSSValuePairList* aVariationsList,
-                                  nsTArray<gfxFontVariation>& aVariationSettings)
-{
-  aVariationSettings.Clear();
-  for (const nsCSSValuePairList* p = aVariationsList; p; p = p->mNext) {
-    gfxFontVariation var;
-
-    MOZ_ASSERT(aVariationsList->mXValue.GetUnit() == eCSSUnit_String,
-               "unexpected value unit");
-
-    // tag is a 4-byte ASCII sequence
-    nsAutoString tag;
-    p->mXValue.GetStringValue(tag);
-    AssertValidFontTag(tag);
-    if (tag.Length() != 4) {
-      continue;
-    }
-    // parsing validates that these are ASCII chars
-    // tags are always big-endian
-    var.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
-
-    // value
-    NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Number,
-                 "should have found a number unit");
-    var.mValue = p->mYValue.GetFloatValue();
-
-    aVariationSettings.AppendElement(var);
-  }
-}
-
 // This should die (bug 380915).
 //
 // SetGenericFont:
 //  - backtrack to an ancestor with the same generic font name (possibly
 //    up to the root where default values come from the presentation context)
 //  - re-apply cascading rules from there without caching intermediate values
 /* static */ void
 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
@@ -4432,36 +4227,16 @@ nsRuleNode::ComputeFontData(void* aStart
     conditions.SetUncacheable();
     nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
                                font);
   }
 
   COMPUTE_END_INHERITED(Font, font)
 }
 
-/*static*/ uint32_t
-nsRuleNode::ParseFontLanguageOverride(const nsAString& aLangTag)
-{
-  if (!aLangTag.Length() || aLangTag.Length() > 4) {
-    return NO_FONT_LANGUAGE_OVERRIDE;
-  }
-  uint32_t index, result = 0;
-  for (index = 0; index < aLangTag.Length(); ++index) {
-    char16_t ch = aLangTag[index];
-    if (!nsCRT::IsAscii(ch)) { // valid tags are pure ASCII
-      return NO_FONT_LANGUAGE_OVERRIDE;
-    }
-    result = (result << 8) + ch;
-  }
-  while (index++ < 4) {
-    result = (result << 8) + 0x20;
-  }
-  return result;
-}
-
 template <typename T>
 inline uint32_t ListLength(const T* aList)
 {
   uint32_t len = 0;
   while (aList) {
     len++;
     aList = aList->mNext;
   }
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -803,51 +803,22 @@ private:
 public:
   // This is infallible; it will never return nullptr.
   static already_AddRefed<nsRuleNode> CreateRootNode(nsPresContext* aPresContext);
 
   static void EnsureBlockDisplay(mozilla::StyleDisplay& display,
                                  bool aConvertListItem = false);
   static void EnsureInlineDisplay(mozilla::StyleDisplay& display);
 
-  enum class FlushUserFontSet {
-    Yes,
-    No,
-  };
-
-  static already_AddRefed<nsFontMetrics> GetMetricsFor(nsPresContext* aPresContext,
-                                                       bool aIsVertical,
-                                                       const nsStyleFont* aStyleFont,
-                                                       nscoord aFontSize,
-                                                       bool aUseUserFontSet,
-                                                       FlushUserFontSet aFlushUserFontSet);
-
   static already_AddRefed<nsFontMetrics> GetMetricsFor(nsPresContext* aPresContext,
                                                        nsStyleContext* aStyleContext,
                                                        const nsStyleFont* aStyleFont,
                                                        nscoord aFontSize,
                                                        bool aUseUserFontSet);
 
-  /**
-   * Appropriately add the correct font if we are using DocumentFonts or
-   * overriding for XUL
-   */
-  static void FixupNoneGeneric(nsFont* aFont,
-                               const nsPresContext* aPresContext,
-                               uint8_t aGenericFontID,
-                               const nsFont* aDefaultVariableFont);
-
-  /**
-   * For an nsStyleFont with mSize set, apply minimum font size constraints
-   * from preferences, as well as -moz-min-font-size-ratio.
-   */
-  static void ApplyMinFontSize(nsStyleFont* aFont,
-                               const nsPresContext* aPresContext,
-                               nscoord aMinFontSize);
-
   // Transition never returns null; on out of memory it'll just return |this|.
   nsRuleNode* Transition(nsIStyleRule* aRule, mozilla::SheetType aLevel,
                          bool aIsImportantRule);
   nsRuleNode* GetParent() const { return mParent; }
   bool IsRoot() const { return mParent == nullptr; }
 
   // Return the root of the rule tree that this rule node is in.
   nsRuleNode* RuleTree();
@@ -1071,28 +1042,20 @@ public:
   }
 
   // Note that this will return false if we have cached conditional
   // style structs.
   bool NodeHasCachedUnconditionalData(const nsStyleStructID aSID) {
     return !!mStyleData.GetStyleData(aSID);
   }
 
-  static void ComputeFontFeatures(const nsCSSValuePairList* aFeaturesList,
-                                  nsTArray<gfxFontFeature>& aFeatureSettings);
-
-  static void ComputeFontVariations(const nsCSSValuePairList* aVariationsList,
-                                    nsTArray<gfxFontVariation>& aVariationSettings);
-
   static nscoord CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize,
                                    nsPresContext* aPresContext,
                                    nsFontSizeType aFontSizeType = eFontSize_HTML);
 
-  static uint32_t ParseFontLanguageOverride(const nsAString& aLangTag);
-
   /**
    * @param aValue The color value, returned from nsCSSParser::ParseColorString
    * @param aPresContext Presentation context whose preferences are used
    *                     for certain enumerated colors
    * @param aStyleContext Style context whose color is used for 'currentColor'
    *
    * @note aPresContext and aStyleContext may be null, but in that case, fully
    *       opaque black will be returned for the values that rely on these
@@ -1114,21 +1077,16 @@ public:
   // Fill unspecified layers by cycling through their values
   // till they all are of length aMaxItemCount
   static void FillAllBackgroundLists(nsStyleImageLayers& aLayers,
                                      uint32_t aMaxItemCount);
 
   static void FillAllMaskLists(nsStyleImageLayers& aLayers,
                                uint32_t aMaxItemCount);
 
-  static void ComputeSystemFont(nsFont* aSystemFont,
-                                mozilla::LookAndFeel::FontID aFontID,
-                                const nsPresContext* aPresContext,
-                                const nsFont* aDefaultVariableFont);
-
 private:
 #ifdef DEBUG
   // non-inline helper function to allow assertions without incomplete
   // type errors
   bool ContextHasCachedData(mozilla::GeckoStyleContext* aContext, nsStyleStructID aSID);
 #endif
 
   // Store style struct on the style context and tell the style context
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsStyleUtil.h"
 #include "nsStyleConsts.h"
 
 #include "nsIContent.h"
 #include "nsCSSProps.h"
 #include "nsContentUtils.h"
-#include "nsRuleNode.h"
 #include "nsROCSSPrimitiveValue.h"
 #include "nsStyleStruct.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIURI.h"
 #include "nsISupportsPrimitives.h"
 #include "nsPrintfCString.h"
 #include <cctype>
@@ -402,17 +401,17 @@ nsStyleUtil::AppendFontFeatureSettings(c
     aResult.AppendLiteral("normal");
     return;
   }
 
   NS_PRECONDITION(unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep,
                   "improper value unit for font-feature-settings:");
 
   nsTArray<gfxFontFeature> featureSettings;
-  nsRuleNode::ComputeFontFeatures(aSrc.GetPairListValue(), featureSettings);
+  nsLayoutUtils::ComputeFontFeatures(aSrc.GetPairListValue(), featureSettings);
   AppendFontFeatureSettings(featureSettings, aResult);
 }
 
 /* static */ void
 nsStyleUtil::AppendFontVariationSettings(const nsTArray<gfxFontVariation>& aVariations,
                                          nsAString& aResult)
 {
   for (uint32_t i = 0, numVars = aVariations.Length(); i < numVars; i++) {
@@ -441,17 +440,18 @@ nsStyleUtil::AppendFontVariationSettings
     aResult.AppendLiteral("normal");
     return;
   }
 
   NS_PRECONDITION(unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep,
                   "improper value unit for font-variation-settings:");
 
   nsTArray<gfxFontVariation> variationSettings;
-  nsRuleNode::ComputeFontVariations(aSrc.GetPairListValue(), variationSettings);
+  nsLayoutUtils::ComputeFontVariations(aSrc.GetPairListValue(),
+                                       variationSettings);
   AppendFontVariationSettings(variationSettings, aResult);
 }
 
 /* static */ void
 nsStyleUtil::GetFunctionalAlternatesName(int32_t aFeature,
                                          nsAString& aFeatureName)
 {
   aFeatureName.Truncate();