bug 1066043 - split gfxFont.cpp and .h into more manageably-sized pieces. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Tue, 16 Sep 2014 10:58:12 +0100
changeset 221057 9528e6149978daae6258705dbcc255906c1dc8dc
parent 221056 f4600dbbe4ed42d63365746acbc37dc944c8670a
child 221058 b2b116db2740c162b2be2a024fc3152cd09e45f7
push id7107
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 17:43:31 +0000
treeherdermozilla-aurora@b4b34e0acc75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs1066043
milestone35.0a1
bug 1066043 - split gfxFont.cpp and .h into more manageably-sized pieces. r=jdaggett
content/base/src/nsLineBreaker.cpp
dom/canvas/CanvasRenderingContext2D.h
gfx/src/nsFontMetrics.h
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxCoreTextShaper.cpp
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxFT2Fonts.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontEntry.cpp
gfx/thebes/gfxFontEntry.h
gfx/thebes/gfxGDIFont.cpp
gfx/thebes/gfxGlyphExtents.cpp
gfx/thebes/gfxGlyphExtents.h
gfx/thebes/gfxGraphiteShaper.cpp
gfx/thebes/gfxHarfBuzzShaper.cpp
gfx/thebes/gfxMacFont.cpp
gfx/thebes/gfxPangoFonts.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxTextRun.cpp
gfx/thebes/gfxTextRun.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/moz.build
gfx/thebes/nsUnicodeRange.h
layout/generic/nsTextFrame.cpp
layout/generic/nsTextFrame.h
layout/generic/nsTextRunTransformations.h
layout/inspector/nsFontFace.cpp
layout/inspector/nsFontFaceList.cpp
--- a/content/base/src/nsLineBreaker.cpp
+++ b/content/base/src/nsLineBreaker.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsLineBreaker.h"
 #include "nsContentUtils.h"
 #include "nsILineBreaker.h"
-#include "gfxFont.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values
+#include "gfxTextRun.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values
 #include "nsHyphenationManager.h"
 #include "nsHyphenator.h"
 #include "mozilla/gfx/2D.h"
 
 nsLineBreaker::nsLineBreaker()
   : mCurrentWordLanguage(nullptr),
     mCurrentWordContainsMixedLang(false),
     mCurrentWordContainsComplexChar(false),
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -9,17 +9,17 @@
 #include <vector>
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "mozilla/RefPtr.h"
 #include "nsColor.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CanvasUtils.h"
-#include "gfxFont.h"
+#include "gfxTextRun.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/CanvasGradient.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasPattern.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
 #include "imgIEncoder.h"
--- a/gfx/src/nsFontMetrics.h
+++ b/gfx/src/nsFontMetrics.h
@@ -3,17 +3,17 @@
  * 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 NSFONTMETRICS__H__
 #define NSFONTMETRICS__H__
 
 #include <stdint.h>                     // for uint32_t
 #include <sys/types.h>                  // for int32_t
-#include "gfxFont.h"                    // for gfxFont, gfxFontGroup
+#include "gfxTextRun.h"                 // for gfxFont, gfxFontGroup
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsCoord.h"                    // for nscoord
 #include "nsError.h"                    // for nsresult
 #include "nsFont.h"                     // for nsFont
 #include "nsISupports.h"                // for NS_INLINE_DECL_REFCOUNTING
 #include "nscore.h"                     // for char16_t
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -9,16 +9,17 @@
 #include "gfxAndroidPlatform.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/CountingAllocatorBase.h"
 #include "mozilla/Preferences.h"
 
 #include "gfx2DGlue.h"
 #include "gfxFT2FontList.h"
 #include "gfxImageSurface.h"
+#include "gfxTextRun.h"
 #include "mozilla/dom/ContentChild.h"
 #include "nsXULAppAPI.h"
 #include "nsIScreen.h"
 #include "nsIScreenManager.h"
 #include "nsILocaleService.h"
 #include "nsServiceManagerUtils.h"
 #include "gfxPrefs.h"
 #include "cairo.h"
--- a/gfx/thebes/gfxCoreTextShaper.cpp
+++ b/gfx/thebes/gfxCoreTextShaper.cpp
@@ -2,16 +2,17 @@
  * 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/ArrayUtils.h"
 #include "gfxCoreTextShaper.h"
 #include "gfxMacFont.h"
 #include "gfxFontUtils.h"
+#include "gfxTextRun.h"
 #include "mozilla/gfx/2D.h"
 
 #include <algorithm>
 
 using namespace mozilla;
 
 // standard font descriptors that we construct the first time they're needed
 CTFontDescriptorRef gfxCoreTextShaper::sDefaultFeaturesDescriptor = nullptr;
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -5,16 +5,17 @@
 
 #include "gfxDWriteFonts.h"
 
 #include "mozilla/MemoryReporting.h"
 
 #include <algorithm>
 #include "gfxDWriteFontList.h"
 #include "gfxContext.h"
+#include "gfxTextRun.h"
 #include <dwrite.h>
 
 #include "harfbuzz/hb.h"
 
 // Chosen this as to resemble DWrite's own oblique face style.
 #define OBLIQUE_SKEW_FACTOR 0.3
 
 using namespace mozilla;
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -18,16 +18,17 @@
 #define gfxToolkitPlatform gfxAndroidPlatform
 #endif
 
 #include "gfxTypes.h"
 #include "gfxFT2Fonts.h"
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include "gfxFT2FontList.h"
+#include "gfxTextRun.h"
 #include <locale.h>
 #include "nsGkAtoms.h"
 #include "nsTArray.h"
 #include "nsUnicodeRange.h"
 #include "nsCRT.h"
 #include "nsXULAppAPI.h"
 
 #include "prlog.h"
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -6,1862 +6,85 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MathAlgorithms.h"
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 #include "prlog.h"
 
-#include "nsServiceManagerUtils.h"
 #include "nsExpirationTracker.h"
-#include "nsILanguageAtomService.h"
 #include "nsITimer.h"
 
 #include "gfxFont.h"
+#include "gfxGlyphExtents.h"
 #include "gfxPlatform.h"
+#include "gfxTextRun.h"
 #include "nsGkAtoms.h"
 
 #include "gfxTypes.h"
 #include "gfxContext.h"
 #include "gfxFontMissingGlyphs.h"
 #include "gfxGraphiteShaper.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxUserFontSet.h"
-#include "gfxPlatformFontList.h"
-#include "gfxScriptItemizer.h"
 #include "nsSpecialCasingData.h"
 #include "nsTextRunTransformations.h"
 #include "nsUnicodeProperties.h"
-#include "nsMathUtils.h"
-#include "nsBidiUtils.h"
-#include "nsUnicodeRange.h"
 #include "nsStyleConsts.h"
 #include "mozilla/AppUnits.h"
-#include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "gfxSVGGlyphs.h"
-#include "gfxMathTable.h"
 #include "gfx2DGlue.h"
 
 #include "GreekCasing.h"
 
-#if defined(XP_MACOSX)
-#include "nsCocoaFeatures.h"
-#endif
-
 #include "cairo.h"
-#include "gfxFontTest.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "graphite2/Font.h"
 
-#include "nsCRT.h"
-#include "GeckoProfiler.h"
-#include "gfxFontConstants.h"
-
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 using mozilla::services::GetObserverService;
 
 gfxFontCache *gfxFontCache::gGlobalCache = nullptr;
 
-static const char16_t kEllipsisChar[] = { 0x2026, 0x0 };
-static const char16_t kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 };
-
 #ifdef DEBUG_roc
 #define DEBUG_TEXT_RUN_STORAGE_METRICS
 #endif
 
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-static uint32_t gTextRunStorageHighWaterMark = 0;
-static uint32_t gTextRunStorage = 0;
-static uint32_t gFontCount = 0;
-static uint32_t gGlyphExtentsCount = 0;
-static uint32_t gGlyphExtentsWidthsTotalSize = 0;
-static uint32_t gGlyphExtentsSetupEagerSimple = 0;
-static uint32_t gGlyphExtentsSetupEagerTight = 0;
-static uint32_t gGlyphExtentsSetupLazyTight = 0;
-static uint32_t gGlyphExtentsSetupFallBackToTight = 0;
+uint32_t gTextRunStorageHighWaterMark = 0;
+uint32_t gTextRunStorage = 0;
+uint32_t gFontCount = 0;
+uint32_t gGlyphExtentsCount = 0;
+uint32_t gGlyphExtentsWidthsTotalSize = 0;
+uint32_t gGlyphExtentsSetupEagerSimple = 0;
+uint32_t gGlyphExtentsSetupEagerTight = 0;
+uint32_t gGlyphExtentsSetupLazyTight = 0;
+uint32_t gGlyphExtentsSetupFallBackToTight = 0;
 #endif
 
 #ifdef PR_LOGGING
 #define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
                                   PR_LOG_DEBUG, args)
 #define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
                                         gfxPlatform::GetLog(eGfxLog_fontinit), \
                                         PR_LOG_DEBUG)
 #endif // PR_LOGGING
 
-void
-gfxCharacterMap::NotifyReleased()
-{
-    gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
-    if (mShared) {
-        fontlist->RemoveCmap(this);
-    }
-    delete this;
-}
-
-gfxFontEntry::gfxFontEntry() :
-    mItalic(false), mFixedPitch(false),
-    mIsValid(true),
-    mIsBadUnderlineFont(false),
-    mIsUserFontContainer(false),
-    mIsDataUserFont(false),
-    mIsLocalUserFont(false),
-    mStandardFace(false),
-    mSymbolFont(false),
-    mIgnoreGDEF(false),
-    mIgnoreGSUB(false),
-    mSVGInitialized(false),
-    mMathInitialized(false),
-    mHasSpaceFeaturesInitialized(false),
-    mHasSpaceFeatures(false),
-    mHasSpaceFeaturesKerning(false),
-    mHasSpaceFeaturesNonKerning(false),
-    mSkipDefaultFeatureSpaceCheck(false),
-    mCheckedForGraphiteTables(false),
-    mHasCmapTable(false),
-    mGrFaceInitialized(false),
-    mCheckedForColorGlyph(false),
-    mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
-    mUVSOffset(0), mUVSData(nullptr),
-    mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
-    mCOLR(nullptr),
-    mCPAL(nullptr),
-    mUnitsPerEm(0),
-    mHBFace(nullptr),
-    mGrFace(nullptr),
-    mGrFaceRefCnt(0)
-{
-    memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
-    memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
-}
-
-gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
-    mName(aName), mItalic(false), mFixedPitch(false),
-    mIsValid(true),
-    mIsBadUnderlineFont(false),
-    mIsUserFontContainer(false),
-    mIsDataUserFont(false),
-    mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
-    mSymbolFont(false),
-    mIgnoreGDEF(false),
-    mIgnoreGSUB(false),
-    mSVGInitialized(false),
-    mMathInitialized(false),
-    mHasSpaceFeaturesInitialized(false),
-    mHasSpaceFeatures(false),
-    mHasSpaceFeaturesKerning(false),
-    mHasSpaceFeaturesNonKerning(false),
-    mSkipDefaultFeatureSpaceCheck(false),
-    mCheckedForGraphiteTables(false),
-    mHasCmapTable(false),
-    mGrFaceInitialized(false),
-    mCheckedForColorGlyph(false),
-    mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
-    mUVSOffset(0), mUVSData(nullptr),
-    mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
-    mCOLR(nullptr),
-    mCPAL(nullptr),
-    mUnitsPerEm(0),
-    mHBFace(nullptr),
-    mGrFace(nullptr),
-    mGrFaceRefCnt(0)
-{
-    memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
-    memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
-}
-
-static PLDHashOperator
-DestroyHBSet(const uint32_t& aTag, hb_set_t*& aSet, void *aUserArg)
-{
-    hb_set_destroy(aSet);
-    return PL_DHASH_NEXT;
-}
-
-gfxFontEntry::~gfxFontEntry()
-{
-    if (mCOLR) {
-        hb_blob_destroy(mCOLR);
-    }
-
-    if (mCPAL) {
-        hb_blob_destroy(mCPAL);
-    }
-
-    // For downloaded fonts, we need to tell the user font cache that this
-    // entry is being deleted.
-    if (mIsDataUserFont) {
-        gfxUserFontSet::UserFontCache::ForgetFont(this);
-    }
-
-    if (mFeatureInputs) {
-        mFeatureInputs->Enumerate(DestroyHBSet, nullptr);
-    }
-
-    // By the time the entry is destroyed, all font instances that were
-    // using it should already have been deleted, and so the HB and/or Gr
-    // face objects should have been released.
-    MOZ_ASSERT(!mHBFace);
-    MOZ_ASSERT(!mGrFaceInitialized);
-}
-
-bool gfxFontEntry::IsSymbolFont() 
-{
-    return mSymbolFont;
-}
-
-bool gfxFontEntry::TestCharacterMap(uint32_t aCh)
-{
-    if (!mCharacterMap) {
-        ReadCMAP();
-        NS_ASSERTION(mCharacterMap, "failed to initialize character map");
-    }
-    return mCharacterMap->test(aCh);
-}
-
-nsresult gfxFontEntry::InitializeUVSMap()
-{
-    // mUVSOffset will not be initialized
-    // until cmap is initialized.
-    if (!mCharacterMap) {
-        ReadCMAP();
-        NS_ASSERTION(mCharacterMap, "failed to initialize character map");
-    }
-
-    if (!mUVSOffset) {
-        return NS_ERROR_FAILURE;
-    }
-
-    if (!mUVSData) {
-        const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
-        AutoTable cmapTable(this, kCmapTag);
-        if (!cmapTable) {
-            mUVSOffset = 0; // don't bother to read the table again
-            return NS_ERROR_FAILURE;
-        }
-
-        uint8_t* uvsData;
-        unsigned int cmapLen;
-        const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
-        nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
-                          (const uint8_t*)cmapData + mUVSOffset,
-                          cmapLen - mUVSOffset, uvsData);
-
-        if (NS_FAILED(rv)) {
-            mUVSOffset = 0; // don't bother to read the table again
-            return rv;
-        }
-
-        mUVSData = uvsData;
-    }
-
-    return NS_OK;
-}
-
-uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS)
-{
-    InitializeUVSMap();
-
-    if (mUVSData) {
-        return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData, aCh, aVS);
-    }
-
-    return 0;
-}
-
-bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags)
-{
-    hb_face_t *face = GetHBFace();
-    if (!face) {
-        return false;
-    }
-
-    unsigned int index;
-    hb_tag_t     chosenScript;
-    bool found =
-        hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'),
-                                         aScriptTags, &index, &chosenScript);
-    hb_face_destroy(face);
-
-    return found && chosenScript != TRUETYPE_TAG('D','F','L','T');
-}
-
-nsresult gfxFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
-{
-    NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
-    mCharacterMap = new gfxCharacterMap();
-    return NS_OK;
-}
-
-nsString
-gfxFontEntry::RealFaceName()
-{
-    AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
-    if (nameTable) {
-        nsAutoString name;
-        nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
-        if (NS_SUCCEEDED(rv)) {
-            return name;
-        }
-    }
-    return Name();
-}
-
-already_AddRefed<gfxFont>
-gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle, bool aNeedsBold)
-{
-    // the font entry name is the psname, not the family name
-    nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(this, aStyle);
-
-    if (!font) {
-        gfxFont *newFont = CreateFontInstance(aStyle, aNeedsBold);
-        if (!newFont)
-            return nullptr;
-        if (!newFont->Valid()) {
-            delete newFont;
-            return nullptr;
-        }
-        font = newFont;
-        gfxFontCache::GetCache()->AddNew(font);
-    }
-    return font.forget();
-}
-
-uint16_t
-gfxFontEntry::UnitsPerEm()
-{
-    if (!mUnitsPerEm) {
-        AutoTable headTable(this, TRUETYPE_TAG('h','e','a','d'));
-        if (headTable) {
-            uint32_t len;
-            const HeadTable* head =
-                reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable,
-                                                                    &len));
-            if (len >= sizeof(HeadTable)) {
-                mUnitsPerEm = head->unitsPerEm;
-            }
-        }
-
-        // if we didn't find a usable 'head' table, or if the value was
-        // outside the valid range, record it as invalid
-        if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
-            mUnitsPerEm = kInvalidUPEM;
-        }
-    }
-    return mUnitsPerEm;
-}
-
-bool
-gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId)
-{
-    NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
-    return mSVGGlyphs->HasSVGGlyph(aGlyphId);
-}
-
-bool
-gfxFontEntry::GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
-                                 gfxRect *aResult)
-{
-    NS_ABORT_IF_FALSE(mSVGInitialized,
-                      "SVG data has not yet been loaded. TryGetSVGData() first.");
-    NS_ABORT_IF_FALSE(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
-                      "font has invalid unitsPerEm");
-
-    gfxContextAutoSaveRestore matrixRestore(aContext);
-    cairo_matrix_t fontMatrix;
-    cairo_get_font_matrix(aContext->GetCairo(), &fontMatrix);
-
-    gfxMatrix svgToAppSpace = *reinterpret_cast<gfxMatrix*>(&fontMatrix);
-    svgToAppSpace.Scale(1.0f / mUnitsPerEm, 1.0f / mUnitsPerEm);
-
-    return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToAppSpace, aResult);
-}
-
-bool
-gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
-                             int aDrawMode, gfxTextContextPaint *aContextPaint)
-{
-    NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
-    return mSVGGlyphs->RenderGlyph(aContext, aGlyphId, DrawMode(aDrawMode),
-                                   aContextPaint);
-}
-
-bool
-gfxFontEntry::TryGetSVGData(gfxFont* aFont)
-{
-    if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
-        return false;
-    }
-
-    if (!mSVGInitialized) {
-        mSVGInitialized = true;
-
-        // If UnitsPerEm is not known/valid, we can't use SVG glyphs
-        if (UnitsPerEm() == kInvalidUPEM) {
-            return false;
-        }
-
-        // We don't use AutoTable here because we'll pass ownership of this
-        // blob to the gfxSVGGlyphs, once we've confirmed the table exists
-        hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
-        if (!svgTable) {
-            return false;
-        }
-
-        // gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
-        // with it.
-        mSVGGlyphs = new gfxSVGGlyphs(svgTable, this);
-    }
-
-    if (!mFontsUsingSVGGlyphs.Contains(aFont)) {
-        mFontsUsingSVGGlyphs.AppendElement(aFont);
-    }
-
-    return !!mSVGGlyphs;
-}
-
-void
-gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont)
-{
-    mFontsUsingSVGGlyphs.RemoveElement(aFont);
-}
-
-void
-gfxFontEntry::NotifyGlyphsChanged()
-{
-    for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
-        gfxFont* font = mFontsUsingSVGGlyphs[i];
-        font->NotifyGlyphsChanged();
-    }
-}
-
-bool
-gfxFontEntry::TryGetMathTable()
-{
-    if (!mMathInitialized) {
-        mMathInitialized = true;
-
-        // If UnitsPerEm is not known/valid, we can't use MATH table
-        if (UnitsPerEm() == kInvalidUPEM) {
-            return false;
-        }
-
-        // We don't use AutoTable here because we'll pass ownership of this
-        // blob to the gfxMathTable, once we've confirmed the table exists
-        hb_blob_t *mathTable = GetFontTable(TRUETYPE_TAG('M','A','T','H'));
-        if (!mathTable) {
-            return false;
-        }
-
-        // gfxMathTable will hb_blob_destroy() the table when it is finished
-        // with it.
-        mMathTable = new gfxMathTable(mathTable);
-        if (!mMathTable->HasValidHeaders()) {
-            mMathTable = nullptr;
-            return false;
-        }
-    }
-
-    return !!mMathTable;
-}
-
-gfxFloat
-gfxFontEntry::GetMathConstant(gfxFontEntry::MathConstant aConstant)
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    gfxFloat value = mMathTable->GetMathConstant(aConstant);
-    if (aConstant == gfxFontEntry::ScriptPercentScaleDown ||
-        aConstant == gfxFontEntry::ScriptScriptPercentScaleDown ||
-        aConstant == gfxFontEntry::RadicalDegreeBottomRaisePercent) {
-        return value / 100.0;
-    }
-    return value / mUnitsPerEm;
-}
-
-bool
-gfxFontEntry::GetMathItalicsCorrection(uint32_t aGlyphID,
-                                       gfxFloat* aItalicCorrection)
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    int16_t italicCorrection;
-    if (!mMathTable->GetMathItalicsCorrection(aGlyphID, &italicCorrection)) {
-        return false;
-    }
-    *aItalicCorrection = gfxFloat(italicCorrection) / mUnitsPerEm;
-    return true;
-}
-
-uint32_t
-gfxFontEntry::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
-                                  uint16_t aSize)
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    return mMathTable->GetMathVariantsSize(aGlyphID, aVertical, aSize);
-}
-
-bool
-gfxFontEntry::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
-                                   uint32_t aGlyphs[4])
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    return mMathTable->GetMathVariantsParts(aGlyphID, aVertical, aGlyphs);
-}
-
-bool
-gfxFontEntry::TryGetColorGlyphs()
-{
-    if (mCheckedForColorGlyph) {
-        return (mCOLR && mCPAL);
-    }
-
-    mCheckedForColorGlyph = true;
-
-    mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
-    if (!mCOLR) {
-        return false;
-    }
-
-    mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
-    if (!mCPAL) {
-        hb_blob_destroy(mCOLR);
-        mCOLR = nullptr;
-        return false;
-    }
-
-    // validation COLR and CPAL table
-    if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
-        return true;
-    }
-
-    hb_blob_destroy(mCOLR);
-    hb_blob_destroy(mCPAL);
-    mCOLR = nullptr;
-    mCPAL = nullptr;
-    return false;
-}
-
-/**
- * FontTableBlobData
- *
- * See FontTableHashEntry for the general strategy.
- */
-
-class gfxFontEntry::FontTableBlobData {
-public:
-    // Adopts the content of aBuffer.
-    explicit FontTableBlobData(FallibleTArray<uint8_t>& aBuffer)
-        : mHashtable(nullptr), mHashKey(0)
-    {
-        MOZ_COUNT_CTOR(FontTableBlobData);
-        mTableData.SwapElements(aBuffer);
-    }
-
-    ~FontTableBlobData() {
-        MOZ_COUNT_DTOR(FontTableBlobData);
-        if (mHashtable && mHashKey) {
-            mHashtable->RemoveEntry(mHashKey);
-        }
-    }
-
-    // Useful for creating blobs
-    const char *GetTable() const
-    {
-        return reinterpret_cast<const char*>(mTableData.Elements());
-    }
-    uint32_t GetTableLength() const { return mTableData.Length(); }
-
-    // Tell this FontTableBlobData to remove the HashEntry when this is
-    // destroyed.
-    void ManageHashEntry(nsTHashtable<FontTableHashEntry> *aHashtable,
-                         uint32_t aHashKey)
-    {
-        mHashtable = aHashtable;
-        mHashKey = aHashKey;
-    }
-
-    // Disconnect from the HashEntry (because the blob has already been
-    // removed from the hashtable).
-    void ForgetHashEntry()
-    {
-        mHashtable = nullptr;
-        mHashKey = 0;
-    }
-
-    size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
-        return mTableData.SizeOfExcludingThis(aMallocSizeOf);
-    }
-    size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
-        return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
-    }
-
-private:
-    // The font table data block, owned (via adoption)
-    FallibleTArray<uint8_t> mTableData;
-
-    // The blob destroy function needs to know the owning hashtable
-    // and the hashtable key, so that it can remove the entry.
-    nsTHashtable<FontTableHashEntry> *mHashtable;
-    uint32_t                          mHashKey;
-
-    // not implemented
-    FontTableBlobData(const FontTableBlobData&);
-};
-
-hb_blob_t *
-gfxFontEntry::FontTableHashEntry::
-ShareTableAndGetBlob(FallibleTArray<uint8_t>& aTable,
-                     nsTHashtable<FontTableHashEntry> *aHashtable)
-{
-    Clear();
-    // adopts elements of aTable
-    mSharedBlobData = new FontTableBlobData(aTable);
-    mBlob = hb_blob_create(mSharedBlobData->GetTable(),
-                           mSharedBlobData->GetTableLength(),
-                           HB_MEMORY_MODE_READONLY,
-                           mSharedBlobData, DeleteFontTableBlobData);
-    if (!mSharedBlobData) {
-        // The FontTableBlobData was destroyed during hb_blob_create().
-        // The (empty) blob is still be held in the hashtable with a strong
-        // reference.
-        return hb_blob_reference(mBlob);
-    }
-
-    // Tell the FontTableBlobData to remove this hash entry when destroyed.
-    // The hashtable does not keep a strong reference.
-    mSharedBlobData->ManageHashEntry(aHashtable, GetKey());
-    return mBlob;
-}
-
-void
-gfxFontEntry::FontTableHashEntry::Clear()
-{
-    // If the FontTableBlobData is managing the hash entry, then the blob is
-    // not owned by this HashEntry; otherwise there is strong reference to the
-    // blob that must be removed.
-    if (mSharedBlobData) {
-        mSharedBlobData->ForgetHashEntry();
-        mSharedBlobData = nullptr;
-    } else if (mBlob) {
-        hb_blob_destroy(mBlob);
-    }
-    mBlob = nullptr;
-}
-
-// a hb_destroy_func for hb_blob_create
-
-/* static */ void
-gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(void *aBlobData)
-{
-    delete static_cast<FontTableBlobData*>(aBlobData);
-}
-
-hb_blob_t *
-gfxFontEntry::FontTableHashEntry::GetBlob() const
-{
-    return hb_blob_reference(mBlob);
-}
-
-bool
-gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t **aBlob)
-{
-    if (!mFontTableCache) {
-        // we do this here rather than on fontEntry construction
-        // because not all shapers will access the table cache at all
-        mFontTableCache = new nsTHashtable<FontTableHashEntry>(8);
-    }
-
-    FontTableHashEntry *entry = mFontTableCache->GetEntry(aTag);
-    if (!entry) {
-        return false;
-    }
-
-    *aBlob = entry->GetBlob();
-    return true;
-}
-
-hb_blob_t *
-gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
-                                       FallibleTArray<uint8_t>* aBuffer)
-{
-    if (MOZ_UNLIKELY(!mFontTableCache)) {
-        // we do this here rather than on fontEntry construction
-        // because not all shapers will access the table cache at all
-      mFontTableCache = new nsTHashtable<FontTableHashEntry>(8);
-    }
-
-    FontTableHashEntry *entry = mFontTableCache->PutEntry(aTag);
-    if (MOZ_UNLIKELY(!entry)) { // OOM
-        return nullptr;
-    }
-
-    if (!aBuffer) {
-        // ensure the entry is null
-        entry->Clear();
-        return nullptr;
-    }
-
-    return entry->ShareTableAndGetBlob(*aBuffer, mFontTableCache);
-}
-
-static int
-DirEntryCmp(const void* aKey, const void* aItem)
-{
-    int32_t tag = *static_cast<const int32_t*>(aKey);
-    const TableDirEntry* entry = static_cast<const TableDirEntry*>(aItem);
-    return tag - int32_t(entry->tag);
-}
-
-hb_blob_t*
-gfxFontEntry::GetTableFromFontData(const void* aFontData, uint32_t aTableTag)
-{
-    const SFNTHeader* header =
-        reinterpret_cast<const SFNTHeader*>(aFontData);
-    const TableDirEntry* dir =
-        reinterpret_cast<const TableDirEntry*>(header + 1);
-    dir = static_cast<const TableDirEntry*>
-        (bsearch(&aTableTag, dir, uint16_t(header->numTables),
-                 sizeof(TableDirEntry), DirEntryCmp));
-    if (dir) {
-        return hb_blob_create(reinterpret_cast<const char*>(aFontData) +
-                                  dir->offset, dir->length,
-                              HB_MEMORY_MODE_READONLY, nullptr, nullptr);
-
-    }
-    return nullptr;
-}
-
-already_AddRefed<gfxCharacterMap>
-gfxFontEntry::GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
-                                  uint32_t& aUVSOffset,
-                                  bool& aSymbolFont)
-{
-    if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
-        return nullptr;
-    }
-
-    return aFontInfoData->GetCMAP(mName, aUVSOffset, aSymbolFont);
-}
-
-hb_blob_t *
-gfxFontEntry::GetFontTable(uint32_t aTag)
-{
-    hb_blob_t *blob;
-    if (GetExistingFontTable(aTag, &blob)) {
-        return blob;
-    }
-
-    FallibleTArray<uint8_t> buffer;
-    bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
-
-    return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
-}
-
-// callback for HarfBuzz to get a font table (in hb_blob_t form)
-// from the font entry (passed as aUserData)
-/*static*/ hb_blob_t *
-gfxFontEntry::HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData)
-{
-    gfxFontEntry *fontEntry = static_cast<gfxFontEntry*>(aUserData);
-
-    // bug 589682 - ignore the GDEF table in buggy fonts (applies to
-    // Italic and BoldItalic faces of Times New Roman)
-    if (aTag == TRUETYPE_TAG('G','D','E','F') &&
-        fontEntry->IgnoreGDEF()) {
-        return nullptr;
-    }
-
-    // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
-    // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
-    if (aTag == TRUETYPE_TAG('G','S','U','B') &&
-        fontEntry->IgnoreGSUB()) {
-        return nullptr;
-    }
-
-    return fontEntry->GetFontTable(aTag);
-}
-
-/*static*/ void
-gfxFontEntry::HBFaceDeletedCallback(void *aUserData)
-{
-    gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
-    fe->ForgetHBFace();
-}
-
-void
-gfxFontEntry::ForgetHBFace()
-{
-    mHBFace = nullptr;
-}
-
-hb_face_t*
-gfxFontEntry::GetHBFace()
-{
-    if (!mHBFace) {
-        mHBFace = hb_face_create_for_tables(HBGetTable, this,
-                                            HBFaceDeletedCallback);
-        return mHBFace;
-    }
-    return hb_face_reference(mHBFace);
-}
-
-/*static*/ const void*
-gfxFontEntry::GrGetTable(const void *aAppFaceHandle, unsigned int aName,
-                         size_t *aLen)
-{
-    gfxFontEntry *fontEntry =
-        static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
-    hb_blob_t *blob = fontEntry->GetFontTable(aName);
-    if (blob) {
-        unsigned int blobLength;
-        const void *tableData = hb_blob_get_data(blob, &blobLength);
-        fontEntry->mGrTableMap->Put(tableData, blob);
-        *aLen = blobLength;
-        return tableData;
-    }
-    *aLen = 0;
-    return nullptr;
-}
-
-/*static*/ void
-gfxFontEntry::GrReleaseTable(const void *aAppFaceHandle,
-                             const void *aTableBuffer)
-{
-    gfxFontEntry *fontEntry =
-        static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
-    void *data;
-    if (fontEntry->mGrTableMap->Get(aTableBuffer, &data)) {
-        fontEntry->mGrTableMap->Remove(aTableBuffer);
-        hb_blob_destroy(static_cast<hb_blob_t*>(data));
-    }
-}
-
-gr_face*
-gfxFontEntry::GetGrFace()
-{
-    if (!mGrFaceInitialized) {
-        gr_face_ops faceOps = {
-            sizeof(gr_face_ops),
-            GrGetTable,
-            GrReleaseTable
-        };
-        mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>,void*>;
-        mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
-        mGrFaceInitialized = true;
-    }
-    ++mGrFaceRefCnt;
-    return mGrFace;
-}
-
-void
-gfxFontEntry::ReleaseGrFace(gr_face *aFace)
-{
-    MOZ_ASSERT(aFace == mGrFace); // sanity-check
-    MOZ_ASSERT(mGrFaceRefCnt > 0);
-    if (--mGrFaceRefCnt == 0) {
-        gr_face_destroy(mGrFace);
-        mGrFace = nullptr;
-        mGrFaceInitialized = false;
-        delete mGrTableMap;
-        mGrTableMap = nullptr;
-    }
-}
-
-void
-gfxFontEntry::DisconnectSVG()
-{
-    if (mSVGInitialized && mSVGGlyphs) {
-        mSVGGlyphs = nullptr;
-        mSVGInitialized = false;
-    }
-}
-
-bool
-gfxFontEntry::HasFontTable(uint32_t aTableTag)
-{
-    AutoTable table(this, aTableTag);
-    return table && hb_blob_get_length(table) > 0;
-}
-
-void
-gfxFontEntry::CheckForGraphiteTables()
-{
-    mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S','i','l','f'));
-}
-
-
-#define FEATURE_SCRIPT_MASK 0x000000ff // script index replaces low byte of tag
-
-// check for too many script codes
-PR_STATIC_ASSERT(MOZ_NUM_SCRIPT_CODES <= FEATURE_SCRIPT_MASK);
-
-// high-order three bytes of tag with script in low-order byte
-#define SCRIPT_FEATURE(s,tag) (((~FEATURE_SCRIPT_MASK) & (tag)) | \
-                               ((FEATURE_SCRIPT_MASK) & (s)))
-
-bool
-gfxFontEntry::SupportsOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag)
-{
-    if (!mSupportedFeatures) {
-        mSupportedFeatures = new nsDataHashtable<nsUint32HashKey,bool>();
-    }
-
-    // note: high-order three bytes *must* be unique for each feature
-    // listed below (see SCRIPT_FEATURE macro def'n)
-    NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
-                 aFeatureTag == HB_TAG('c','2','s','c') ||
-                 aFeatureTag == HB_TAG('p','c','a','p') ||
-                 aFeatureTag == HB_TAG('c','2','p','c') ||
-                 aFeatureTag == HB_TAG('s','u','p','s') ||
-                 aFeatureTag == HB_TAG('s','u','b','s'),
-                 "use of unknown feature tag");
-
-    // note: graphite feature support uses the last script index
-    NS_ASSERTION(aScript < FEATURE_SCRIPT_MASK - 1,
-                 "need to bump the size of the feature shift");
-
-    uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
-    bool result;
-    if (mSupportedFeatures->Get(scriptFeature, &result)) {
-        return result;
-    }
-
-    result = false;
-
-    hb_face_t *face = GetHBFace();
-
-    if (hb_ot_layout_has_substitution(face)) {
-        hb_script_t hbScript =
-            gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
-
-        // Get the OpenType tag(s) that match this script code
-        hb_tag_t scriptTags[4] = {
-            HB_TAG_NONE,
-            HB_TAG_NONE,
-            HB_TAG_NONE,
-            HB_TAG_NONE
-        };
-        hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
-
-        // Replace the first remaining NONE with DEFAULT
-        hb_tag_t* scriptTag = &scriptTags[0];
-        while (*scriptTag != HB_TAG_NONE) {
-            ++scriptTag;
-        }
-        *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
-
-        // Now check for 'smcp' under the first of those scripts that is present
-        const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
-        scriptTag = &scriptTags[0];
-        while (*scriptTag != HB_TAG_NONE) {
-            unsigned int scriptIndex;
-            if (hb_ot_layout_table_find_script(face, kGSUB, *scriptTag,
-                                               &scriptIndex)) {
-                if (hb_ot_layout_language_find_feature(face, kGSUB,
-                                                       scriptIndex,
-                                           HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
-                                                       aFeatureTag, nullptr)) {
-                    result = true;
-                }
-                break;
-            }
-            ++scriptTag;
-        }
-    }
-
-    hb_face_destroy(face);
-
-    mSupportedFeatures->Put(scriptFeature, result);
-
-    return result;
-}
-
-const hb_set_t*
-gfxFontEntry::InputsForOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag)
-{
-    if (!mFeatureInputs) {
-        mFeatureInputs = new nsDataHashtable<nsUint32HashKey,hb_set_t*>();
-    }
-
-    NS_ASSERTION(aFeatureTag == HB_TAG('s','u','p','s') ||
-                 aFeatureTag == HB_TAG('s','u','b','s'),
-                 "use of unknown feature tag");
-
-    uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
-    hb_set_t *inputGlyphs;
-    if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
-        return inputGlyphs;
-    }
-
-    inputGlyphs = hb_set_create();
-
-    hb_face_t *face = GetHBFace();
-
-    if (hb_ot_layout_has_substitution(face)) {
-        hb_script_t hbScript =
-            gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
-
-        // Get the OpenType tag(s) that match this script code
-        hb_tag_t scriptTags[4] = {
-            HB_TAG_NONE,
-            HB_TAG_NONE,
-            HB_TAG_NONE,
-            HB_TAG_NONE
-        };
-        hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
-
-        // Replace the first remaining NONE with DEFAULT
-        hb_tag_t* scriptTag = &scriptTags[0];
-        while (*scriptTag != HB_TAG_NONE) {
-            ++scriptTag;
-        }
-        *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
-
-        const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
-        hb_tag_t features[2] = { aFeatureTag, HB_TAG_NONE };
-        hb_set_t *featurelookups = hb_set_create();
-        hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
-                                     features, featurelookups);
-        hb_codepoint_t index = -1;
-        while (hb_set_next(featurelookups, &index)) {
-            hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
-                                               nullptr, inputGlyphs,
-                                               nullptr, nullptr);
-        }
-    }
-
-    hb_face_destroy(face);
-
-    mFeatureInputs->Put(scriptFeature, inputGlyphs);
-    return inputGlyphs;
-}
-
-bool
-gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag)
-{
-    if (!mSupportedFeatures) {
-        mSupportedFeatures = new nsDataHashtable<nsUint32HashKey,bool>();
-    }
-
-    // note: high-order three bytes *must* be unique for each feature
-    // listed below (see SCRIPT_FEATURE macro def'n)
-    NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
-                 aFeatureTag == HB_TAG('c','2','s','c') ||
-                 aFeatureTag == HB_TAG('p','c','a','p') ||
-                 aFeatureTag == HB_TAG('c','2','p','c') ||
-                 aFeatureTag == HB_TAG('s','u','p','s') ||
-                 aFeatureTag == HB_TAG('s','u','b','s'),
-                 "use of unknown feature tag");
-
-    // graphite feature check uses the last script slot
-    uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
-    bool result;
-    if (mSupportedFeatures->Get(scriptFeature, &result)) {
-        return result;
-    }
-
-    gr_face* face = GetGrFace();
-    result = gr_face_find_fref(face, aFeatureTag) != nullptr;
-    ReleaseGrFace(face);
-
-    mSupportedFeatures->Put(scriptFeature, result);
-
-    return result;
-}
-
-bool
-gfxFontEntry::GetColorLayersInfo(uint32_t aGlyphId,
-                            nsTArray<uint16_t>& aLayerGlyphs,
-                            nsTArray<mozilla::gfx::Color>& aLayerColors)
-{
-    return gfxFontUtils::GetColorGlyphLayers(mCOLR,
-                                             mCPAL,
-                                             aGlyphId,
-                                             aLayerGlyphs,
-                                             aLayerColors);
-}
-
-size_t
-gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
-{
-    size_t n = 0;
-    if (mBlob) {
-        n += aMallocSizeOf(mBlob);
-    }
-    if (mSharedBlobData) {
-        n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
-    }
-    return n;
-}
-
-void
-gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                     FontListSizes* aSizes) const
-{
-    aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-
-    // cmaps are shared so only non-shared cmaps are included here
-    if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
-        aSizes->mCharMapsSize +=
-            mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
-    }
-    if (mFontTableCache) {
-        aSizes->mFontTableCacheSize +=
-            mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
-    }
-}
-
-void
-gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                     FontListSizes* aSizes) const
-{
-    aSizes->mFontListSize += aMallocSizeOf(this);
-    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// class gfxFontFamily
-//
-//////////////////////////////////////////////////////////////////////////////
-
-// we consider faces with mStandardFace == true to be "greater than" those with false,
-// because during style matching, later entries will replace earlier ones
-class FontEntryStandardFaceComparator {
-  public:
-    bool Equals(const nsRefPtr<gfxFontEntry>& a, const nsRefPtr<gfxFontEntry>& b) const {
-        return a->mStandardFace == b->mStandardFace;
-    }
-    bool LessThan(const nsRefPtr<gfxFontEntry>& a, const nsRefPtr<gfxFontEntry>& b) const {
-        return (a->mStandardFace == false && b->mStandardFace == true);
-    }
-};
-
-void
-gfxFontFamily::SortAvailableFonts()
-{
-    mAvailableFonts.Sort(FontEntryStandardFaceComparator());
-}
-
-bool
-gfxFontFamily::HasOtherFamilyNames()
-{
-    // need to read in other family names to determine this
-    if (!mOtherFamilyNamesInitialized) {
-        ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());  // sets mHasOtherFamilyNames
-    }
-    return mHasOtherFamilyNames;
-}
-
-gfxFontEntry*
-gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle, 
-                                bool& aNeedsSyntheticBold)
-{
-    if (!mHasStyles)
-        FindStyleVariations(); // collect faces for the family, if not already done
-
-    NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
-
-    aNeedsSyntheticBold = false;
-
-    int8_t baseWeight = aFontStyle.ComputeWeight();
-    bool wantBold = baseWeight >= 6;
-
-    // If the family has only one face, we simply return it; no further checking needed
-    if (mAvailableFonts.Length() == 1) {
-        gfxFontEntry *fe = mAvailableFonts[0];
-        aNeedsSyntheticBold =
-            wantBold && !fe->IsBold() && aFontStyle.allowSyntheticWeight;
-        return fe;
-    }
-
-    bool wantItalic = (aFontStyle.style &
-                       (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
-
-    // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
-    // or some subset of these. In this case, we have exactly 4 entries in mAvailableFonts,
-    // stored in the above order; note that some of the entries may be nullptr.
-    // We can then pick the required entry based on whether the request is for
-    // bold or non-bold, italic or non-italic, without running the more complex
-    // matching algorithm used for larger families with many weights and/or widths.
-
-    if (mIsSimpleFamily) {
-        // Family has no more than the "standard" 4 faces, at fixed indexes;
-        // calculate which one we want.
-        // Note that we cannot simply return it as not all 4 faces are necessarily present.
-        uint8_t faceIndex = (wantItalic ? kItalicMask : 0) |
-                            (wantBold ? kBoldMask : 0);
-
-        // if the desired style is available, return it directly
-        gfxFontEntry *fe = mAvailableFonts[faceIndex];
-        if (fe) {
-            // no need to set aNeedsSyntheticBold here as we matched the boldness request
-            return fe;
-        }
-
-        // order to check fallback faces in a simple family, depending on requested style
-        static const uint8_t simpleFallbacks[4][3] = {
-            { kBoldFaceIndex, kItalicFaceIndex, kBoldItalicFaceIndex },   // fallbacks for Regular
-            { kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex },// Bold
-            { kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex },  // Italic
-            { kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex }       // BoldItalic
-        };
-        const uint8_t *order = simpleFallbacks[faceIndex];
-
-        for (uint8_t trial = 0; trial < 3; ++trial) {
-            // check remaining faces in order of preference to find the first that actually exists
-            fe = mAvailableFonts[order[trial]];
-            if (fe) {
-                aNeedsSyntheticBold =
-                    wantBold && !fe->IsBold() &&
-                    aFontStyle.allowSyntheticWeight;
-                return fe;
-            }
-        }
-
-        // this can't happen unless we have totally broken the font-list manager!
-        NS_NOTREACHED("no face found in simple font family!");
-        return nullptr;
-    }
-
-    // This is a large/rich font family, so we do full style- and weight-matching:
-    // first collect a list of weights that are the best match for the requested
-    // font-stretch and font-style, then pick the best weight match among those
-    // available.
-
-    gfxFontEntry *weightList[10] = { 0 };
-    bool foundWeights = FindWeightsForStyle(weightList, wantItalic, aFontStyle.stretch);
-    if (!foundWeights) {
-        return nullptr;
-    }
-
-    // First find a match for the best weight
-    int8_t matchBaseWeight = 0;
-    int8_t i = baseWeight;
-
-    // Need to special case when normal face doesn't exist but medium does.
-    // In that case, use medium otherwise weights < 400
-    if (baseWeight == 4 && !weightList[4]) {
-        i = 5; // medium
-    }
-
-    // Loop through weights, since one exists loop will terminate
-    int8_t direction = (baseWeight > 5) ? 1 : -1;
-    for (; ; i += direction) {
-        if (weightList[i]) {
-            matchBaseWeight = i;
-            break;
-        }
-
-        // If we've reached one side without finding a font,
-        // start over and go the other direction until we find a match
-        if (i == 1 || i == 9) {
-            i = baseWeight;
-            direction = -direction;
-        }
-    }
-
-    NS_ASSERTION(matchBaseWeight != 0, 
-                 "weight mapping should always find at least one font in a family");
-
-    gfxFontEntry *matchFE = weightList[matchBaseWeight];
-
-    NS_ASSERTION(matchFE,
-                 "weight mapping should always find at least one font in a family");
-
-    if (!matchFE->IsBold() && baseWeight >= 6 &&
-        aFontStyle.allowSyntheticWeight)
-    {
-        aNeedsSyntheticBold = true;
-    }
-
-    return matchFE;
-}
-
-void
-gfxFontFamily::CheckForSimpleFamily()
-{
-    // already checked this family
-    if (mIsSimpleFamily) {
-        return;
-    };
-
-    uint32_t count = mAvailableFonts.Length();
-    if (count > 4 || count == 0) {
-        return; // can't be "simple" if there are >4 faces;
-                // if none then the family is unusable anyway
-    }
-
-    if (count == 1) {
-        mIsSimpleFamily = true;
-        return;
-    }
-
-    int16_t firstStretch = mAvailableFonts[0]->Stretch();
-
-    gfxFontEntry *faces[4] = { 0 };
-    for (uint8_t i = 0; i < count; ++i) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-        if (fe->Stretch() != firstStretch) {
-            return; // font-stretch doesn't match, don't treat as simple family
-        }
-        uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
-                            (fe->Weight() >= 600 ? kBoldMask : 0);
-        if (faces[faceIndex]) {
-            return; // two faces resolve to the same slot; family isn't "simple"
-        }
-        faces[faceIndex] = fe;
-    }
-
-    // we have successfully slotted the available faces into the standard
-    // 4-face framework
-    mAvailableFonts.SetLength(4);
-    for (uint8_t i = 0; i < 4; ++i) {
-        if (mAvailableFonts[i].get() != faces[i]) {
-            mAvailableFonts[i].swap(faces[i]);
-        }
-    }
-
-    mIsSimpleFamily = true;
-}
-
-#ifdef DEBUG
-bool
-gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
-    uint32_t i, numFonts = mAvailableFonts.Length();
-    for (i = 0; i < numFonts; i++) {
-        if (mAvailableFonts[i] == aFontEntry) {
-            return true;
-        }
-        // userfonts contain the actual real font entry
-        if (mAvailableFonts[i]->mIsUserFontContainer) {
-            gfxUserFontEntry* ufe =
-                static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
-            if (ufe->GetPlatformFontEntry() == aFontEntry) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-#endif
-
-static inline uint32_t
-StyleDistance(gfxFontEntry *aFontEntry,
-              bool anItalic, int16_t aStretch)
-{
-    // Compute a measure of the "distance" between the requested style
-    // and the given fontEntry,
-    // considering italicness and font-stretch but not weight.
-
-    int32_t distance = 0;
-    if (aStretch != aFontEntry->mStretch) {
-        // stretch values are in the range -4 .. +4
-        // if aStretch is positive, we prefer more-positive values;
-        // if zero or negative, prefer more-negative
-        if (aStretch > 0) {
-            distance = (aFontEntry->mStretch - aStretch) * 2;
-        } else {
-            distance = (aStretch - aFontEntry->mStretch) * 2;
-        }
-        // if the computed "distance" here is negative, it means that
-        // aFontEntry lies in the "non-preferred" direction from aStretch,
-        // so we treat that as larger than any preferred-direction distance
-        // (max possible is 8) by adding an extra 10 to the absolute value
-        if (distance < 0) {
-            distance = -distance + 10;
-        }
-    }
-    if (aFontEntry->IsItalic() != anItalic) {
-        distance += 1;
-    }
-    return uint32_t(distance);
-}
-
-bool
-gfxFontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
-                                   bool anItalic, int16_t aStretch)
-{
-    uint32_t foundWeights = 0;
-    uint32_t bestMatchDistance = 0xffffffff;
-
-    uint32_t count = mAvailableFonts.Length();
-    for (uint32_t i = 0; i < count; i++) {
-        // this is not called for "simple" families, and therefore it does not
-        // need to check the mAvailableFonts entries for nullptr.
-        gfxFontEntry *fe = mAvailableFonts[i];
-        uint32_t distance = StyleDistance(fe, anItalic, aStretch);
-        if (distance <= bestMatchDistance) {
-            int8_t wt = fe->mWeight / 100;
-            NS_ASSERTION(wt >= 1 && wt < 10, "invalid weight in fontEntry");
-            if (!aFontsForWeights[wt]) {
-                // record this as a possible candidate for weight matching
-                aFontsForWeights[wt] = fe;
-                ++foundWeights;
-            } else {
-                uint32_t prevDistance =
-                    StyleDistance(aFontsForWeights[wt], anItalic, aStretch);
-                if (prevDistance >= distance) {
-                    // replacing a weight we already found,
-                    // so don't increment foundWeights
-                    aFontsForWeights[wt] = fe;
-                }
-            }
-            bestMatchDistance = distance;
-        }
-    }
-
-    NS_ASSERTION(foundWeights > 0, "Font family containing no faces?");
-
-    if (foundWeights == 1) {
-        // no need to cull entries if we only found one weight
-        return true;
-    }
-
-    // we might have recorded some faces that were a partial style match, but later found
-    // others that were closer; in this case, we need to cull the poorer matches from the
-    // weight list we'll return
-    for (uint32_t i = 0; i < 10; ++i) {
-        if (aFontsForWeights[i] &&
-            StyleDistance(aFontsForWeights[i], anItalic, aStretch) > bestMatchDistance)
-        {
-            aFontsForWeights[i] = 0;
-        }
-    }
-
-    return (foundWeights > 0);
-}
-
-
-void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
-{
-    // just return the primary name; subclasses should override
-    aLocalizedName = mName;
-}
-
-// metric for how close a given font matches a style
-static int32_t
-CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
-{
-    int32_t rank = 0;
-    if (aStyle) {
-         // italics
-         bool wantItalic =
-             (aStyle->style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
-         if (aFontEntry->IsItalic() == wantItalic) {
-             rank += 10;
-         }
-
-        // measure of closeness of weight to the desired value
-        rank += 9 - DeprecatedAbs(aFontEntry->Weight() / 100 - aStyle->ComputeWeight());
-    } else {
-        // if no font to match, prefer non-bold, non-italic fonts
-        if (!aFontEntry->IsItalic()) {
-            rank += 3;
-        }
-        if (!aFontEntry->IsBold()) {
-            rank += 2;
-        }
-    }
-
-    return rank;
-}
-
-#define RANK_MATCHED_CMAP   20
-
-void
-gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
-{
-    if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
-        // none of the faces in the family support the required char,
-        // so bail out immediately
-        return;
-    }
-
-    bool needsBold;
-    gfxFontStyle normal;
-    gfxFontEntry *fe = FindFontForStyle(
-                  (aMatchData->mStyle == nullptr) ? *aMatchData->mStyle : normal,
-                  needsBold);
-
-    if (fe && !fe->SkipDuringSystemFallback()) {
-        int32_t rank = 0;
-
-        if (fe->TestCharacterMap(aMatchData->mCh)) {
-            rank += RANK_MATCHED_CMAP;
-            aMatchData->mCount++;
-#ifdef PR_LOGGING
-            PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
-
-            if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_DEBUG))) {
-                uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
-                uint32_t script = GetScriptCode(aMatchData->mCh);
-                PR_LOG(log, PR_LOG_DEBUG,\
-                       ("(textrun-systemfallback-fonts) char: u+%6.6x "
-                        "unicode-range: %d script: %d match: [%s]\n",
-                        aMatchData->mCh,
-                        unicodeRange, script,
-                        NS_ConvertUTF16toUTF8(fe->Name()).get()));
-            }
-#endif
-        }
-
-        aMatchData->mCmapsTested++;
-        if (rank == 0) {
-            return;
-        }
-
-         // omitting from original windows code -- family name, lang group, pitch
-         // not available in current FontEntry implementation
-        rank += CalcStyleMatch(fe, aMatchData->mStyle);
-
-        // xxx - add whether AAT font with morphing info for specific lang groups
-
-        if (rank > aMatchData->mMatchRank
-            || (rank == aMatchData->mMatchRank &&
-                Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
-        {
-            aMatchData->mBestMatch = fe;
-            aMatchData->mMatchedFamily = this;
-            aMatchData->mMatchRank = rank;
-        }
-    }
-}
-
-void
-gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
-{
-    uint32_t i, numFonts = mAvailableFonts.Length();
-    for (i = 0; i < numFonts; i++) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-        if (fe && fe->TestCharacterMap(aMatchData->mCh)) {
-            int32_t rank = RANK_MATCHED_CMAP;
-            rank += CalcStyleMatch(fe, aMatchData->mStyle);
-            if (rank > aMatchData->mMatchRank
-                || (rank == aMatchData->mMatchRank &&
-                    Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
-            {
-                aMatchData->mBestMatch = fe;
-                aMatchData->mMatchedFamily = this;
-                aMatchData->mMatchRank = rank;
-            }
-        }
-    }
-}
-
-/*static*/ void
-gfxFontFamily::ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
-                                           const char *aNameData,
-                                           uint32_t aDataLength,
-                                           nsTArray<nsString>& aOtherFamilyNames,
-                                           bool useFullName)
-{
-    const gfxFontUtils::NameHeader *nameHeader =
-        reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
-
-    uint32_t nameCount = nameHeader->count;
-    if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
-        NS_WARNING("invalid font (name records)");
-        return;
-    }
-    
-    const gfxFontUtils::NameRecord *nameRecord =
-        reinterpret_cast<const gfxFontUtils::NameRecord*>(aNameData + sizeof(gfxFontUtils::NameHeader));
-    uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
-
-    for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
-        uint32_t nameLen = nameRecord->length;
-        uint32_t nameOff = nameRecord->offset;  // offset from base of string storage
-
-        if (stringsBase + nameOff + nameLen > aDataLength) {
-            NS_WARNING("invalid font (name table strings)");
-            return;
-        }
-
-        uint16_t nameID = nameRecord->nameID;
-        if ((useFullName && nameID == gfxFontUtils::NAME_ID_FULL) ||
-            (!useFullName && (nameID == gfxFontUtils::NAME_ID_FAMILY ||
-                              nameID == gfxFontUtils::NAME_ID_PREFERRED_FAMILY))) {
-            nsAutoString otherFamilyName;
-            bool ok = gfxFontUtils::DecodeFontName(aNameData + stringsBase + nameOff,
-                                                     nameLen,
-                                                     uint32_t(nameRecord->platformID),
-                                                     uint32_t(nameRecord->encodingID),
-                                                     uint32_t(nameRecord->languageID),
-                                                     otherFamilyName);
-            // add if not same as canonical family name
-            if (ok && otherFamilyName != aFamilyName) {
-                aOtherFamilyNames.AppendElement(otherFamilyName);
-            }
-        }
-    }
-}
-
-// returns true if other names were found, false otherwise
-bool
-gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
-                                           hb_blob_t           *aNameTable,
-                                           bool                 useFullName)
-{
-    uint32_t dataLength;
-    const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
-    nsAutoTArray<nsString,4> otherFamilyNames;
-
-    ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
-                                otherFamilyNames, useFullName);
-
-    uint32_t n = otherFamilyNames.Length();
-    for (uint32_t i = 0; i < n; i++) {
-        aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
-    }
-
-    return n != 0;
-}
-
-void
-gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
-{
-    if (mOtherFamilyNamesInitialized) 
-        return;
-    mOtherFamilyNamesInitialized = true;
-
-    FindStyleVariations();
-
-    // read in other family names for the first face in the list
-    uint32_t i, numFonts = mAvailableFonts.Length();
-    const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
-
-    for (i = 0; i < numFonts; ++i) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe) {
-            continue;
-        }
-        gfxFontEntry::AutoTable nameTable(fe, kNAME);
-        if (!nameTable) {
-            continue;
-        }
-        mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                           nameTable);
-        break;
-    }
-
-    // read in other names for the first face in the list with the assumption
-    // that if extra names don't exist in that face then they don't exist in
-    // other faces for the same font
-    if (!mHasOtherFamilyNames) 
-        return;
-
-    // read in names for all faces, needed to catch cases where fonts have
-    // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
-    for ( ; i < numFonts; i++) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe) {
-            continue;
-        }
-        gfxFontEntry::AutoTable nameTable(fe, kNAME);
-        if (!nameTable) {
-            continue;
-        }
-        ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
-    }
-}
-
-void
-gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, 
-                             bool aNeedFullnamePostscriptNames,
-                             FontInfoData *aFontInfoData)
-{
-    // if all needed names have already been read, skip
-    if (mOtherFamilyNamesInitialized &&
-        (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
-        return;
-
-    bool asyncFontLoaderDisabled = false;
-
-#if defined(XP_MACOSX)
-    // bug 975460 - async font loader crashes sometimes under 10.6, disable
-    if (!nsCocoaFeatures::OnLionOrLater()) {
-        asyncFontLoaderDisabled = true;
-    }
-#endif
-
-    if (!mOtherFamilyNamesInitialized &&
-        aFontInfoData &&
-        aFontInfoData->mLoadOtherNames &&
-        !asyncFontLoaderDisabled)
-    {
-        nsAutoTArray<nsString,4> otherFamilyNames;
-        bool foundOtherNames =
-            aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
-        if (foundOtherNames) {
-            uint32_t i, n = otherFamilyNames.Length();
-            for (i = 0; i < n; i++) {
-                aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
-            }
-        }
-        mOtherFamilyNamesInitialized = true;
-    }
-
-    // if all needed data has been initialized, return
-    if (mOtherFamilyNamesInitialized &&
-        (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
-        return;
-    }
-
-    FindStyleVariations(aFontInfoData);
-
-    // check again, as style enumeration code may have loaded names
-    if (mOtherFamilyNamesInitialized &&
-        (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
-        return;
-    }
-
-    uint32_t i, numFonts = mAvailableFonts.Length();
-    const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
-
-    bool firstTime = true, readAllFaces = false;
-    for (i = 0; i < numFonts; ++i) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe) {
-            continue;
-        }
-
-        nsAutoString fullname, psname;
-        bool foundFaceNames = false;
-        if (!mFaceNamesInitialized &&
-            aNeedFullnamePostscriptNames &&
-            aFontInfoData &&
-            aFontInfoData->mLoadFaceNames) {
-            aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
-            if (!fullname.IsEmpty()) {
-                aPlatformFontList->AddFullname(fe, fullname);
-            }
-            if (!psname.IsEmpty()) {
-                aPlatformFontList->AddPostscriptName(fe, psname);
-            }
-            foundFaceNames = true;
-
-            // found everything needed? skip to next font
-            if (mOtherFamilyNamesInitialized) {
-                continue;
-            }
-        }
-
-        // load directly from the name table
-        gfxFontEntry::AutoTable nameTable(fe, kNAME);
-        if (!nameTable) {
-            continue;
-        }
-
-        if (aNeedFullnamePostscriptNames && !foundFaceNames) {
-            if (gfxFontUtils::ReadCanonicalName(
-                    nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
-            {
-                aPlatformFontList->AddFullname(fe, fullname);
-            }
-
-            if (gfxFontUtils::ReadCanonicalName(
-                    nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
-            {
-                aPlatformFontList->AddPostscriptName(fe, psname);
-            }
-        }
-
-        if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
-            bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                              nameTable);
-
-            // if the first face has a different name, scan all faces, otherwise
-            // assume the family doesn't have other names
-            if (firstTime && foundOtherName) {
-                mHasOtherFamilyNames = true;
-                readAllFaces = true;
-            }
-            firstTime = false;
-        }
-
-        // if not reading in any more names, skip other faces
-        if (!readAllFaces && !aNeedFullnamePostscriptNames) {
-            break;
-        }
-    }
-
-    mFaceNamesInitialized = true;
-    mOtherFamilyNamesInitialized = true;
-}
-
-
-gfxFontEntry*
-gfxFontFamily::FindFont(const nsAString& aPostscriptName)
-{
-    // find the font using a simple linear search
-    uint32_t numFonts = mAvailableFonts.Length();
-    for (uint32_t i = 0; i < numFonts; i++) {
-        gfxFontEntry *fe = mAvailableFonts[i].get();
-        if (fe && fe->Name() == aPostscriptName)
-            return fe;
-    }
-    return nullptr;
-}
-
-void
-gfxFontFamily::ReadAllCMAPs(FontInfoData *aFontInfoData)
-{
-    FindStyleVariations(aFontInfoData);
-
-    uint32_t i, numFonts = mAvailableFonts.Length();
-    for (i = 0; i < numFonts; i++) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-        // don't try to load cmaps for downloadable fonts not yet loaded
-        if (!fe || fe->mIsUserFontContainer) {
-            continue;
-        }
-        fe->ReadCMAP(aFontInfoData);
-        mFamilyCharacterMap.Union(*(fe->mCharacterMap));
-    }
-    mFamilyCharacterMap.Compact();
-    mFamilyCharacterMapInitialized = true;
-}
-
-void
-gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                      FontListSizes* aSizes) const
-{
-    aSizes->mFontListSize +=
-        mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-    aSizes->mCharMapsSize +=
-        mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
-
-    aSizes->mFontListSize +=
-        mAvailableFonts.SizeOfExcludingThis(aMallocSizeOf);
-    for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-        if (fe) {
-            fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
-        }
-    }
-}
-
-void
-gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                      FontListSizes* aSizes) const
-{
-    aSizes->mFontListSize += aMallocSizeOf(this);
-    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
-}
 
 /*
  * gfxFontCache - global cache of gfxFont instances.
  * Expires unused fonts after a short interval;
  * notifies fonts to age their cached shaped-word records;
  * observes memory-pressure notification and tells fonts to clear their
  * shaped-word caches to free up memory.
  */
@@ -2316,16 +539,194 @@ gfxFontShaper::MergeFontFeatures(
         const gfxFontFeature& feature = styleRuleFeatures.ElementAt(i);
         aMergedFeatures.Put(feature.mTag, feature.mValue);
     }
 
     return aMergedFeatures.Count() != 0;
 }
 
 void
+gfxShapedText::SetupClusterBoundaries(uint32_t         aOffset,
+                                      const char16_t *aString,
+                                      uint32_t         aLength)
+{
+    CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
+
+    gfxTextRun::CompressedGlyph extendCluster;
+    extendCluster.SetComplex(false, true, 0);
+
+    ClusterIterator iter(aString, aLength);
+
+    // the ClusterIterator won't be able to tell us if the string
+    // _begins_ with a cluster-extender, so we handle that here
+    if (aLength && IsClusterExtender(*aString)) {
+        *glyphs = extendCluster;
+    }
+
+    while (!iter.AtEnd()) {
+        if (*iter == char16_t(' ')) {
+            glyphs->SetIsSpace();
+        }
+        // advance iter to the next cluster-start (or end of text)
+        iter.Next();
+        // step past the first char of the cluster
+        aString++;
+        glyphs++;
+        // mark all the rest as cluster-continuations
+        while (aString < iter) {
+            *glyphs = extendCluster;
+            if (NS_IS_LOW_SURROGATE(*aString)) {
+                glyphs->SetIsLowSurrogate();
+            }
+            glyphs++;
+            aString++;
+        }
+    }
+}
+
+void
+gfxShapedText::SetupClusterBoundaries(uint32_t       aOffset,
+                                      const uint8_t *aString,
+                                      uint32_t       aLength)
+{
+    CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
+    const uint8_t *limit = aString + aLength;
+
+    while (aString < limit) {
+        if (*aString == uint8_t(' ')) {
+            glyphs->SetIsSpace();
+        }
+        aString++;
+        glyphs++;
+    }
+}
+
+gfxShapedText::DetailedGlyph *
+gfxShapedText::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
+{
+    NS_ASSERTION(aIndex < GetLength(), "Index out of range");
+
+    if (!mDetailedGlyphs) {
+        mDetailedGlyphs = new DetailedGlyphStore();
+    }
+
+    return mDetailedGlyphs->Allocate(aIndex, aCount);
+}
+
+void
+gfxShapedText::SetGlyphs(uint32_t aIndex, CompressedGlyph aGlyph,
+                         const DetailedGlyph *aGlyphs)
+{
+    NS_ASSERTION(!aGlyph.IsSimpleGlyph(), "Simple glyphs not handled here");
+    NS_ASSERTION(aIndex > 0 || aGlyph.IsLigatureGroupStart(),
+                 "First character can't be a ligature continuation!");
+
+    uint32_t glyphCount = aGlyph.GetGlyphCount();
+    if (glyphCount > 0) {
+        DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, glyphCount);
+        memcpy(details, aGlyphs, sizeof(DetailedGlyph)*glyphCount);
+    }
+    GetCharacterGlyphs()[aIndex] = aGlyph;
+}
+
+#define ZWNJ 0x200C
+#define ZWJ  0x200D
+// U+061C ARABIC LETTER MARK is expected to be added to XIDMOD_DEFAULT_IGNORABLE
+// in a future Unicode update. Add it manually for now
+#define ALM  0x061C
+static inline bool
+IsDefaultIgnorable(uint32_t aChar)
+{
+    return GetIdentifierModification(aChar) == XIDMOD_DEFAULT_IGNORABLE ||
+           aChar == ZWNJ || aChar == ZWJ || aChar == ALM;
+}
+
+void
+gfxShapedText::SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont)
+{
+    uint8_t category = GetGeneralCategory(aChar);
+    if (category >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
+        category <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    {
+        GetCharacterGlyphs()[aIndex].SetComplex(false, true, 0);
+    }
+
+    DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
+
+    details->mGlyphID = aChar;
+    if (IsDefaultIgnorable(aChar)) {
+        // Setting advance width to zero will prevent drawing the hexbox
+        details->mAdvance = 0;
+    } else {
+        gfxFloat width =
+            std::max(aFont->GetMetrics().aveCharWidth,
+                     gfxFontMissingGlyphs::GetDesiredMinWidth(aChar,
+                         mAppUnitsPerDevUnit));
+        details->mAdvance = uint32_t(width * mAppUnitsPerDevUnit);
+    }
+    details->mXOffset = 0;
+    details->mYOffset = 0;
+    GetCharacterGlyphs()[aIndex].SetMissing(1);
+}
+
+bool
+gfxShapedText::FilterIfIgnorable(uint32_t aIndex, uint32_t aCh)
+{
+    if (IsDefaultIgnorable(aCh)) {
+        DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
+        details->mGlyphID = aCh;
+        details->mAdvance = 0;
+        details->mXOffset = 0;
+        details->mYOffset = 0;
+        GetCharacterGlyphs()[aIndex].SetMissing(1);
+        return true;
+    }
+    return false;
+}
+
+void
+gfxShapedText::AdjustAdvancesForSyntheticBold(float aSynBoldOffset,
+                                              uint32_t aOffset,
+                                              uint32_t aLength)
+{
+    uint32_t synAppUnitOffset = aSynBoldOffset * mAppUnitsPerDevUnit;
+    CompressedGlyph *charGlyphs = GetCharacterGlyphs();
+    for (uint32_t i = aOffset; i < aOffset + aLength; ++i) {
+         CompressedGlyph *glyphData = charGlyphs + i;
+         if (glyphData->IsSimpleGlyph()) {
+             // simple glyphs ==> just add the advance
+             int32_t advance = glyphData->GetSimpleAdvance() + synAppUnitOffset;
+             if (CompressedGlyph::IsSimpleAdvance(advance)) {
+                 glyphData->SetSimpleGlyph(advance, glyphData->GetSimpleGlyph());
+             } else {
+                 // rare case, tested by making this the default
+                 uint32_t glyphIndex = glyphData->GetSimpleGlyph();
+                 glyphData->SetComplex(true, true, 1);
+                 DetailedGlyph detail = {glyphIndex, advance, 0, 0};
+                 SetGlyphs(i, *glyphData, &detail);
+             }
+         } else {
+             // complex glyphs ==> add offset at cluster/ligature boundaries
+             uint32_t detailedLength = glyphData->GetGlyphCount();
+             if (detailedLength) {
+                 DetailedGlyph *details = GetDetailedGlyphs(i);
+                 if (!details) {
+                     continue;
+                 }
+                 if (IsRightToLeft()) {
+                     details[0].mAdvance += synAppUnitOffset;
+                 } else {
+                     details[detailedLength - 1].mAdvance += synAppUnitOffset;
+                 }
+             }
+         }
+    }
+}
+
+void
 gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft)
 {
     mAscent = std::max(mAscent, aOther.mAscent);
     mDescent = std::max(mDescent, aOther.mDescent);
     if (aOtherIsOnLeft) {
         mBoundingBox =
             (mBoundingBox + gfxPoint(aOther.mAdvanceWidth, 0)).Union(aOther.mBoundingBox);
     } else {
@@ -3071,46 +1472,16 @@ static AntialiasMode Get2DAAMode(gfxFont
     return AntialiasMode::GRAY;
   case gfxFont::kAntialiasNone:
     return AntialiasMode::NONE;
   default:
     return AntialiasMode::DEFAULT;
   }
 }
 
-// Parameters passed to gfxFont methods for drawing glyphs from a textrun.
-// The TextRunDrawParams are set up once per textrun; the FontDrawParams
-// are dependent on the specific font, so they are set per GlyphRun.
-
-struct TextRunDrawParams {
-    RefPtr<DrawTarget>             dt;
-    gfxContext                    *context;
-    gfxFont::Spacing              *spacing;
-    gfxTextRunDrawCallbacks       *callbacks;
-    gfxTextContextPaint           *runContextPaint;
-    gfxFloat                       direction;
-    double                         devPerApp;
-    DrawMode                       drawMode;
-    bool                           isRTL;
-    bool                           paintSVGGlyphs;
-};
-
-struct FontDrawParams {
-    RefPtr<ScaledFont>             scaledFont;
-    RefPtr<GlyphRenderingOptions>  renderingOptions;
-    gfxTextContextPaint           *contextPaint;
-    Matrix                        *passedInvMatrix;
-    Matrix                         matInv;
-    double                         synBoldOnePixelOffset;
-    int32_t                        extraStrikes;
-    DrawOptions                    drawOptions;
-    bool                           haveSVGGlyphs;
-    bool                           haveColorGlyphs;
-};
-
 class GlyphBufferAzure
 {
 public:
     GlyphBufferAzure(const TextRunDrawParams& aRunParams,
                      const FontDrawParams&    aFontParams)
         : mRunParams(aRunParams)
         , mFontParams(aFontParams)
         , mNumGlyphs(0)
@@ -3653,30 +2024,16 @@ UnionRange(gfxFloat aX, gfxFloat* aDestM
 // on overflowing glyphs.
 static bool
 NeedsGlyphExtents(gfxFont *aFont, gfxTextRun *aTextRun)
 {
     return (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX) ||
         aFont->GetFontEntry()->IsUserFont();
 }
 
-static bool
-NeedsGlyphExtents(gfxTextRun *aTextRun)
-{
-    if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX)
-        return true;
-    uint32_t numRuns;
-    const gfxTextRun::GlyphRun *glyphRuns = aTextRun->GetGlyphRuns(&numRuns);
-    for (uint32_t i = 0; i < numRuns; ++i) {
-        if (glyphRuns[i].mFont->GetFontEntry()->IsUserFont())
-            return true;
-    }
-    return false;
-}
-
 gfxFont::RunMetrics
 gfxFont::Measure(gfxTextRun *aTextRun,
                  uint32_t aStart, uint32_t aEnd,
                  BoundingBoxType aBoundingBoxType,
                  gfxContext *aRefContext,
                  Spacing *aSpacing)
 {
     // If aBoundingBoxType is TIGHT_HINTED_OUTLINE_EXTENTS
@@ -3832,22 +2189,16 @@ gfxFont::NotifyGlyphsChanged()
 }
 
 static bool
 IsBoundarySpace(char16_t aChar, char16_t aNextChar)
 {
     return (aChar == ' ' || aChar == 0x00A0) && !IsClusterExtender(aNextChar);
 }
 
-static inline uint32_t
-HashMix(uint32_t aHash, char16_t aCh)
-{
-    return (aHash >> 28) ^ (aHash << 4) ^ aCh;
-}
-
 #ifdef __GNUC__
 #define GFX_MAYBE_UNUSED __attribute__((unused))
 #else
 #define GFX_MAYBE_UNUSED
 #endif
 
 template<typename T>
 gfxShapedWord*
@@ -3925,17 +2276,17 @@ gfxFont::GetShapedWord(gfxContext *aCont
 bool
 gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
 {
     const gfxShapedWord *sw = mShapedWord;
     if (!sw) {
         return false;
     }
     if (sw->GetLength() != aKey->mLength ||
-        sw->Flags() != aKey->mFlags ||
+        sw->GetFlags() != aKey->mFlags ||
         sw->GetAppUnitsPerDevUnit() != aKey->mAppUnitsPerDevUnit ||
         sw->Script() != aKey->mScript) {
         return false;
     }
     if (sw->TextIs8Bit()) {
         if (aKey->mTextIs8Bit) {
             return (0 == memcmp(sw->Text8Bit(), aKey->mText.mSingle,
                                 aKey->mLength * sizeof(uint8_t)));
@@ -4243,17 +2594,17 @@ gfxFont::SplitAndInitTextRun(gfxContext 
         // break into separate ShapedWords when we hit an invalid char,
         // or a boundary space (always handled individually),
         // or the first non-space after a space
         if (!boundary && !invalid) {
             if (!IsChar8Bit(ch)) {
                 wordIs8Bit = false;
             }
             // include this character in the hash, and move on to next
-            hash = HashMix(hash, ch);
+            hash = gfxShapedWord::HashMix(hash, ch);
             continue;
         }
 
         // We've decided to break here (i.e. we're at the end of a "word");
         // shape the word and add it to the textrun.
         // For words longer than the limit, we don't use the
         // font's word cache but just shape directly into the textrun.
         if (length > wordCacheCharLimit) {
@@ -4293,17 +2644,17 @@ gfxFont::SplitAndInitTextRun(gfxContext 
             // word was terminated by a space: add that to the textrun
             if (!aTextRun->SetSpaceGlyphIfSimple(this, aContext,
                                                  aRunStart + i, ch))
             {
                 static const uint8_t space = ' ';
                 gfxShapedWord *sw =
                     GetShapedWord(aContext,
                                   &space, 1,
-                                  HashMix(0, ' '), aRunScript,
+                                  gfxShapedWord::HashMix(0, ' '), aRunScript,
                                   appUnitsPerDevUnit,
                                   flags | gfxTextRunFactory::TEXT_IS_8BIT, tp);
                 if (sw) {
                     aTextRun->CopyGlyphDataFrom(sw, aRunStart + i);
                 } else {
                     return false;
                 }
             }
@@ -4335,16 +2686,230 @@ gfxFont::SplitAndInitTextRun(gfxContext 
         hash = 0;
         wordStart = i + 1;
         wordIs8Bit = true;
     }
 
     return true;
 }
 
+// Explicit instantiations of SplitAndInitTextRun, to avoid libxul link failure
+template bool
+gfxFont::SplitAndInitTextRun(gfxContext *aContext,
+                             gfxTextRun *aTextRun,
+                             const uint8_t *aString,
+                             uint32_t aRunStart,
+                             uint32_t aRunLength,
+                             int32_t aRunScript);
+template bool
+gfxFont::SplitAndInitTextRun(gfxContext *aContext,
+                             gfxTextRun *aTextRun,
+                             const char16_t *aString,
+                             uint32_t aRunStart,
+                             uint32_t aRunLength,
+                             int32_t aRunScript);
+ 
+bool
+gfxFont::InitFakeSmallCapsRun(gfxContext     *aContext,
+                              gfxTextRun     *aTextRun,
+                              const uint8_t  *aText,
+                              uint32_t        aOffset,
+                              uint32_t        aLength,
+                              uint8_t         aMatchType,
+                              int32_t         aScript,
+                              bool            aSyntheticLower,
+                              bool            aSyntheticUpper)
+{
+    NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aText),
+                                         aLength);
+    return InitFakeSmallCapsRun(aContext, aTextRun, unicodeString.get(),
+                                aOffset, aLength, aMatchType, aScript,
+                                aSyntheticLower, aSyntheticUpper);
+}
+
+bool
+gfxFont::InitFakeSmallCapsRun(gfxContext     *aContext,
+                              gfxTextRun     *aTextRun,
+                              const char16_t *aText,
+                              uint32_t        aOffset,
+                              uint32_t        aLength,
+                              uint8_t         aMatchType,
+                              int32_t         aScript,
+                              bool            aSyntheticLower,
+                              bool            aSyntheticUpper)
+{
+    bool ok = true;
+
+    nsRefPtr<gfxFont> smallCapsFont = GetSmallCapsFont();
+
+    enum RunCaseAction {
+        kNoChange,
+        kUppercaseReduce,
+        kUppercase
+    };
+
+    RunCaseAction runAction = kNoChange;
+    uint32_t runStart = 0;
+
+    for (uint32_t i = 0; i <= aLength; ++i) {
+        uint32_t extraCodeUnits = 0; // Will be set to 1 if we need to consume
+                                     // a trailing surrogate as well as the
+                                     // current code unit.
+        RunCaseAction chAction = kNoChange;
+        // Unless we're at the end, figure out what treatment the current
+        // character will need.
+        if (i < aLength) {
+            uint32_t ch = aText[i];
+            if (NS_IS_HIGH_SURROGATE(ch) && i < aLength - 1 &&
+                NS_IS_LOW_SURROGATE(aText[i + 1])) {
+                ch = SURROGATE_TO_UCS4(ch, aText[i + 1]);
+                extraCodeUnits = 1;
+            }
+            // Characters that aren't the start of a cluster are ignored here.
+            // They get added to whatever lowercase/non-lowercase run we're in.
+            if (IsClusterExtender(ch)) {
+                chAction = runAction;
+            } else {
+                if (ch != ToUpperCase(ch) || mozilla::unicode::SpecialUpper(ch)) {
+                    // ch is lower case
+                    chAction = (aSyntheticLower ? kUppercaseReduce : kNoChange);
+                } else if (ch != ToLowerCase(ch)) {
+                    // ch is upper case
+                    chAction = (aSyntheticUpper ? kUppercaseReduce : kNoChange);
+                    if (mStyle.language == nsGkAtoms::el) {
+                        // In Greek, check for characters that will be modified by
+                        // the GreekUpperCase mapping - this catches accented
+                        // capitals where the accent is to be removed (bug 307039).
+                        // These are handled by using the full-size font with the
+                        // uppercasing transform.
+                        mozilla::GreekCasing::State state;
+                        uint32_t ch2 = mozilla::GreekCasing::UpperCase(ch, state);
+                        if (ch != ch2 && !aSyntheticUpper) {
+                            chAction = kUppercase;
+                        }
+                    }
+                }
+            }
+        }
+
+        // At the end of the text or when the current character needs different
+        // casing treatment from the current run, finish the run-in-progress
+        // and prepare to accumulate a new run.
+        // Note that we do not look at any source data for offset [i] here,
+        // as that would be invalid in the case where i==length.
+        if ((i == aLength || runAction != chAction) && runStart < i) {
+            uint32_t runLength = i - runStart;
+            gfxFont* f = this;
+            switch (runAction) {
+            case kNoChange:
+                // just use the current font and the existing string
+                aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, true);
+                if (!f->SplitAndInitTextRun(aContext, aTextRun,
+                                            aText + runStart,
+                                            aOffset + runStart, runLength,
+                                            aScript)) {
+                    ok = false;
+                }
+                break;
+
+            case kUppercaseReduce:
+                // use reduced-size font, then fall through to uppercase the text
+                f = smallCapsFont;
+
+            case kUppercase:
+                // apply uppercase transform to the string
+                nsDependentSubstring origString(aText + runStart, runLength);
+                nsAutoString convertedString;
+                nsAutoTArray<bool,50> charsToMergeArray;
+                nsAutoTArray<bool,50> deletedCharsArray;
+
+                bool mergeNeeded = nsCaseTransformTextRunFactory::
+                    TransformString(origString,
+                                    convertedString,
+                                    true,
+                                    mStyle.language,
+                                    charsToMergeArray,
+                                    deletedCharsArray);
+
+                if (mergeNeeded) {
+                    // This is the hard case: the transformation caused chars
+                    // to be inserted or deleted, so we can't shape directly
+                    // into the destination textrun but have to handle the
+                    // mismatch of character positions.
+                    gfxTextRunFactory::Parameters params = {
+                        aContext, nullptr, nullptr, nullptr, 0,
+                        aTextRun->GetAppUnitsPerDevUnit()
+                    };
+                    nsAutoPtr<gfxTextRun> tempRun;
+                    tempRun =
+                        gfxTextRun::Create(&params, convertedString.Length(),
+                                           aTextRun->GetFontGroup(), 0);
+                    tempRun->AddGlyphRun(f, aMatchType, 0, true);
+                    if (!f->SplitAndInitTextRun(aContext, tempRun,
+                                                convertedString.BeginReading(),
+                                                0, convertedString.Length(),
+                                                aScript)) {
+                        ok = false;
+                    } else {
+                        nsAutoPtr<gfxTextRun> mergedRun;
+                        mergedRun =
+                            gfxTextRun::Create(&params, runLength,
+                                               aTextRun->GetFontGroup(), 0);
+                        MergeCharactersInTextRun(mergedRun, tempRun,
+                                                 charsToMergeArray.Elements(),
+                                                 deletedCharsArray.Elements());
+                        aTextRun->CopyGlyphDataFrom(mergedRun, 0, runLength,
+                                                    aOffset + runStart);
+                    }
+                } else {
+                    aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart,
+                                          true);
+                    if (!f->SplitAndInitTextRun(aContext, aTextRun,
+                                                convertedString.BeginReading(),
+                                                aOffset + runStart, runLength,
+                                                aScript)) {
+                        ok = false;
+                    }
+                }
+                break;
+            }
+
+            runStart = i;
+        }
+
+        i += extraCodeUnits;
+        if (i < aLength) {
+            runAction = chAction;
+        }
+    }
+
+    return ok;
+}
+
+already_AddRefed<gfxFont>
+gfxFont::GetSmallCapsFont()
+{
+    gfxFontStyle style(*GetStyle());
+    style.size *= SMALL_CAPS_SCALE_FACTOR;
+    style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
+    gfxFontEntry* fe = GetFontEntry();
+    bool needsBold = style.weight >= 600 && !fe->IsBold();
+    return fe->FindOrMakeFont(&style, needsBold);
+}
+
+already_AddRefed<gfxFont>
+gfxFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel)
+{
+    gfxFontStyle style(*GetStyle());
+    style.AdjustForSubSuperscript(aAppUnitsPerDevPixel);
+    gfxFontEntry* fe = GetFontEntry();
+    bool needsBold = style.weight >= 600 && !fe->IsBold();
+    return fe->FindOrMakeFont(&style, needsBold);
+}
+
 gfxGlyphExtents *
 gfxFont::GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit) {
     uint32_t i, count = mGlyphExtentsArray.Length();
     for (i = 0; i < count; ++i) {
         if (mGlyphExtentsArray[i]->GetAppUnitsPerDevUnit() == aAppUnitsPerDevUnit)
             return mGlyphExtentsArray[i];
     }
     gfxGlyphExtents *glyphExtents = new gfxGlyphExtents(aAppUnitsPerDevUnit);
@@ -4682,1623 +3247,16 @@ gfxFont::AddGlyphChangeObserver(GlyphCha
 void
 gfxFont::RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver)
 {
     NS_ASSERTION(mGlyphChangeObservers, "No observers registered");
     NS_ASSERTION(mGlyphChangeObservers->Contains(aObserver), "Observer not registered");
     mGlyphChangeObservers->RemoveEntry(aObserver);
 }
 
-gfxGlyphExtents::~gfxGlyphExtents()
-{
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-    gGlyphExtentsWidthsTotalSize +=
-        mContainedGlyphWidths.SizeOfExcludingThis(&FontCacheMallocSizeOf);
-    gGlyphExtentsCount++;
-#endif
-    MOZ_COUNT_DTOR(gfxGlyphExtents);
-}
-
-bool
-gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
-    gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents)
-{
-    HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
-    if (!entry) {
-        if (!aContext) {
-            NS_WARNING("Could not get glyph extents (no aContext)");
-            return false;
-        }
-
-        if (aFont->SetupCairoFont(aContext)) {
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-            ++gGlyphExtentsSetupLazyTight;
-#endif
-            aFont->SetupGlyphExtents(aContext, aGlyphID, true, this);
-            entry = mTightGlyphExtents.GetEntry(aGlyphID);
-        }
-        if (!entry) {
-            NS_WARNING("Could not get glyph extents");
-            return false;
-        }
-    }
-
-    *aExtents = gfxRect(entry->x, entry->y, entry->width, entry->height);
-    return true;
-}
-
-gfxGlyphExtents::GlyphWidths::~GlyphWidths()
-{
-    uint32_t i, count = mBlocks.Length();
-    for (i = 0; i < count; ++i) {
-        uintptr_t bits = mBlocks[i];
-        if (bits && !(bits & 0x1)) {
-            delete[] reinterpret_cast<uint16_t *>(bits);
-        }
-    }
-}
-
-uint32_t
-gfxGlyphExtents::GlyphWidths::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
-{
-    uint32_t i;
-    uint32_t size = mBlocks.SizeOfExcludingThis(aMallocSizeOf);
-    for (i = 0; i < mBlocks.Length(); ++i) {
-        uintptr_t bits = mBlocks[i];
-        if (bits && !(bits & 0x1)) {
-            size += aMallocSizeOf(reinterpret_cast<void*>(bits));
-        }
-    }
-    return size;
-}
-
-void
-gfxGlyphExtents::GlyphWidths::Set(uint32_t aGlyphID, uint16_t aWidth)
-{
-    uint32_t block = aGlyphID >> BLOCK_SIZE_BITS;
-    uint32_t len = mBlocks.Length();
-    if (block >= len) {
-        uintptr_t *elems = mBlocks.AppendElements(block + 1 - len);
-        if (!elems)
-            return;
-        memset(elems, 0, sizeof(uintptr_t)*(block + 1 - len));
-    }
-
-    uintptr_t bits = mBlocks[block];
-    uint32_t glyphOffset = aGlyphID & (BLOCK_SIZE - 1);
-    if (!bits) {
-        mBlocks[block] = MakeSingle(glyphOffset, aWidth);
-        return;
-    }
-
-    uint16_t *newBlock;
-    if (bits & 0x1) {
-        // Expand the block to a real block. We could avoid this by checking
-        // glyphOffset == GetGlyphOffset(bits), but that never happens so don't bother
-        newBlock = new uint16_t[BLOCK_SIZE];
-        if (!newBlock)
-            return;
-        uint32_t i;
-        for (i = 0; i < BLOCK_SIZE; ++i) {
-            newBlock[i] = INVALID_WIDTH;
-        }
-        newBlock[GetGlyphOffset(bits)] = GetWidth(bits);
-        mBlocks[block] = reinterpret_cast<uintptr_t>(newBlock);
-    } else {
-        newBlock = reinterpret_cast<uint16_t *>(bits);
-    }
-    newBlock[glyphOffset] = aWidth;
-}
-
-void
-gfxGlyphExtents::SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits)
-{
-    HashEntry *entry = mTightGlyphExtents.PutEntry(aGlyphID);
-    if (!entry)
-        return;
-    entry->x = aExtentsAppUnits.X();
-    entry->y = aExtentsAppUnits.Y();
-    entry->width = aExtentsAppUnits.Width();
-    entry->height = aExtentsAppUnits.Height();
-}
-
-size_t
-gfxGlyphExtents::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
-{
-    return mContainedGlyphWidths.SizeOfExcludingThis(aMallocSizeOf) +
-        mTightGlyphExtents.SizeOfExcludingThis(nullptr, aMallocSizeOf);
-}
-
-size_t
-gfxGlyphExtents::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
-{
-    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
-}
-
-gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList,
-                           const gfxFontStyle *aStyle,
-                           gfxUserFontSet *aUserFontSet)
-    : mFamilyList(aFontFamilyList)
-    , mStyle(*aStyle)
-    , mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
-    , mHyphenWidth(-1)
-    , mUserFontSet(aUserFontSet)
-    , mTextPerf(nullptr)
-    , mPageLang(gfxPlatform::GetFontPrefLangFor(aStyle->language))
-    , mSkipDrawing(false)
-{
-    // We don't use SetUserFontSet() here, as we want to unconditionally call
-    // BuildFontList() rather than only do UpdateFontList() if it changed.
-    mCurrGeneration = GetGeneration();
-    BuildFontList();
-}
-
-void
-gfxFontGroup::FindGenericFonts(FontFamilyType aGenericType,
-                               nsIAtom *aLanguage,
-                               void *aClosure)
-{
-    nsAutoTArray<nsString, 5> resolvedGenerics;
-    ResolveGenericFontNames(aGenericType, aLanguage, resolvedGenerics);
-    uint32_t g = 0, numGenerics = resolvedGenerics.Length();
-    for (g = 0; g < numGenerics; g++) {
-        FindPlatformFont(resolvedGenerics[g], false, aClosure);
-    }
-}
-
-/* static */ void
-gfxFontGroup::ResolveGenericFontNames(FontFamilyType aGenericType,
-                                      nsIAtom *aLanguage,
-                                      nsTArray<nsString>& aGenericFamilies)
-{
-    static const char kGeneric_serif[] = "serif";
-    static const char kGeneric_sans_serif[] = "sans-serif";
-    static const char kGeneric_monospace[] = "monospace";
-    static const char kGeneric_cursive[] = "cursive";
-    static const char kGeneric_fantasy[] = "fantasy";
-
-    // treat -moz-fixed as monospace
-    if (aGenericType == eFamily_moz_fixed) {
-        aGenericType = eFamily_monospace;
-    }
-
-    // type should be standard generic type at this point
-    NS_ASSERTION(aGenericType >= eFamily_serif &&
-                 aGenericType <= eFamily_fantasy,
-                 "standard generic font family type required");
-
-    // create the lang string
-    nsIAtom *langGroupAtom = nullptr;
-    nsAutoCString langGroupString;
-    if (aLanguage) {
-        if (!gLangService) {
-            CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
-        }
-        if (gLangService) {
-            nsresult rv;
-            langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv);
-        }
-    }
-    if (!langGroupAtom) {
-        langGroupAtom = nsGkAtoms::Unicode;
-    }
-    langGroupAtom->ToUTF8String(langGroupString);
-
-    // map generic type to string
-    const char *generic = nullptr;
-    switch (aGenericType) {
-        case eFamily_serif:
-            generic = kGeneric_serif;
-            break;
-        case eFamily_sans_serif:
-            generic = kGeneric_sans_serif;
-            break;
-        case eFamily_monospace:
-            generic = kGeneric_monospace;
-            break;
-        case eFamily_cursive:
-            generic = kGeneric_cursive;
-            break;
-        case eFamily_fantasy:
-            generic = kGeneric_fantasy;
-            break;
-        default:
-            break;
-    }
-
-    if (!generic) {
-        return;
-    }
-
-    aGenericFamilies.Clear();
-
-    // load family for "font.name.generic.lang"
-    nsAutoCString prefFontName("font.name.");
-    prefFontName.Append(generic);
-    prefFontName.Append('.');
-    prefFontName.Append(langGroupString);
-    gfxFontUtils::AppendPrefsFontList(prefFontName.get(),
-                                      aGenericFamilies);
-
-    // if lang has pref fonts, also load fonts for "font.name-list.generic.lang"
-    if (!aGenericFamilies.IsEmpty()) {
-        nsAutoCString prefFontListName("font.name-list.");
-        prefFontListName.Append(generic);
-        prefFontListName.Append('.');
-        prefFontListName.Append(langGroupString);
-        gfxFontUtils::AppendPrefsFontList(prefFontListName.get(),
-                                          aGenericFamilies);
-    }
-
-#if 0  // dump out generic mappings
-    printf("%s ===> ", prefFontName.get());
-    for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) {
-        if (k > 0) printf(", ");
-        printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get());
-    }
-    printf("\n");
-#endif
-}
-
-void gfxFontGroup::EnumerateFontList(nsIAtom *aLanguage, void *aClosure)
-{
-    // initialize fonts in the font family list
-    const nsTArray<FontFamilyName>& fontlist = mFamilyList.GetFontlist();
-
-    // lookup fonts in the fontlist
-    uint32_t i, numFonts = fontlist.Length();
-    for (i = 0; i < numFonts; i++) {
-        const FontFamilyName& name = fontlist[i];
-        if (name.IsNamed()) {
-            FindPlatformFont(name.mName, true, aClosure);
-        } else {
-            FindGenericFonts(name.mType, aLanguage, aClosure);
-        }
-    }
-
-    // if necessary, append default generic onto the end
-    if (mFamilyList.GetDefaultFontType() != eFamily_none &&
-        !mFamilyList.HasDefaultGeneric()) {
-        FindGenericFonts(mFamilyList.GetDefaultFontType(),
-                         aLanguage,
-                         aClosure);
-    }
-}
-
-void
-gfxFontGroup::BuildFontList()
-{
-// gfxPangoFontGroup behaves differently, so this method is a no-op on that platform
-#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
-
-    EnumerateFontList(mStyle.language);
-
-    // at this point, fontlist should have been filled in
-    // get a default font if none exists
-    if (mFonts.Length() == 0) {
-        bool needsBold;
-        gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
-        gfxFontFamily *defaultFamily = pfl->GetDefaultFont(&mStyle);
-        NS_ASSERTION(defaultFamily,
-                     "invalid default font returned by GetDefaultFont");
-
-        if (defaultFamily) {
-            gfxFontEntry *fe = defaultFamily->FindFontForStyle(mStyle,
-                                                               needsBold);
-            if (fe) {
-                nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
-                                                            needsBold);
-                if (font) {
-                    mFonts.AppendElement(FamilyFace(defaultFamily, font));
-                }
-            }
-        }
-
-        if (mFonts.Length() == 0) {
-            // Try for a "font of last resort...."
-            // Because an empty font list would be Really Bad for later code
-            // that assumes it will be able to get valid metrics for layout,
-            // just look for the first usable font and put in the list.
-            // (see bug 554544)
-            nsAutoTArray<nsRefPtr<gfxFontFamily>,200> families;
-            pfl->GetFontFamilyList(families);
-            uint32_t count = families.Length();
-            for (uint32_t i = 0; i < count; ++i) {
-                gfxFontEntry *fe = families[i]->FindFontForStyle(mStyle,
-                                                                 needsBold);
-                if (fe) {
-                    nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
-                                                                needsBold);
-                    if (font) {
-                        mFonts.AppendElement(FamilyFace(families[i], font));
-                        break;
-                    }
-                }
-            }
-        }
-
-        if (mFonts.Length() == 0) {
-            // an empty font list at this point is fatal; we're not going to
-            // be able to do even the most basic layout operations
-            char msg[256]; // CHECK buffer length if revising message below
-            nsAutoString families;
-            mFamilyList.ToString(families);
-            sprintf(msg, "unable to find a usable font (%.220s)",
-                    NS_ConvertUTF16toUTF8(families).get());
-            NS_RUNTIMEABORT(msg);
-        }
-    }
-
-    if (!mStyle.systemFont) {
-        uint32_t count = mFonts.Length();
-        for (uint32_t i = 0; i < count; ++i) {
-            gfxFont* font = mFonts[i].Font();
-            if (font->GetFontEntry()->mIsBadUnderlineFont) {
-                gfxFloat first = mFonts[0].Font()->GetMetrics().underlineOffset;
-                gfxFloat bad = font->GetMetrics().underlineOffset;
-                mUnderlineOffset = std::min(first, bad);
-                break;
-            }
-        }
-    }
-#endif
-}
-
-void
-gfxFontGroup::FindPlatformFont(const nsAString& aName,
-                               bool aUseFontSet,
-                               void *aClosure)
-{
-    bool needsBold;
-    gfxFontFamily *family = nullptr;
-    gfxFontEntry *fe = nullptr;
-
-    if (aUseFontSet) {
-        // First, look up in the user font set...
-        // If the fontSet matches the family, we must not look for a platform
-        // font of the same name, even if we fail to actually get a fontEntry
-        // here; we'll fall back to the next name in the CSS font-family list.
-        if (mUserFontSet) {
-            // If the fontSet matches the family, but the font has not yet finished
-            // loading (nor has its load timeout fired), the fontGroup should wait
-            // for the download, and not actually draw its text yet.
-            family = mUserFontSet->LookupFamily(aName);
-            if (family) {
-                bool waitForUserFont = false;
-                gfxUserFontEntry* userFontEntry = nullptr;
-                userFontEntry = mUserFontSet->FindUserFontEntry(family, mStyle,
-                                                                needsBold,
-                                                                waitForUserFont);
-                if (userFontEntry) {
-                    fe = userFontEntry->GetPlatformFontEntry();
-                }
-                if (!fe && waitForUserFont) {
-                    mSkipDrawing = true;
-                }
-            }
-        }
-    }
-
-    // Not known in the user font set ==> check system fonts
-    if (!family) {
-        gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList();
-        family = fontList->FindFamily(aName, mStyle.systemFont);
-        if (family) {
-            fe = family->FindFontForStyle(mStyle, needsBold);
-        }
-    }
-
-    // add to the font group, unless it's already there
-    if (fe && !HasFont(fe)) {
-        nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
-        if (font) {
-            mFonts.AppendElement(FamilyFace(family, font));
-        }
-    }
-}
-
-bool
-gfxFontGroup::HasFont(const gfxFontEntry *aFontEntry)
-{
-    uint32_t count = mFonts.Length();
-    for (uint32_t i = 0; i < count; ++i) {
-        if (mFonts[i].Font()->GetFontEntry() == aFontEntry)
-            return true;
-    }
-    return false;
-}
-
-gfxFontGroup::~gfxFontGroup()
-{
-    mFonts.Clear();
-}
-
-gfxFont *
-gfxFontGroup::GetFirstMathFont()
-{
-    uint32_t count = mFonts.Length();
-    for (uint32_t i = 0; i < count; ++i) {
-        gfxFont* font = GetFontAt(i);
-        if (font->GetFontEntry()->TryGetMathTable()) {
-            return font;
-        }
-    }
-    return nullptr;
-}
-
-gfxFontGroup *
-gfxFontGroup::Copy(const gfxFontStyle *aStyle)
-{
-    gfxFontGroup *fg = new gfxFontGroup(mFamilyList, aStyle, mUserFontSet);
-    fg->SetTextPerfMetrics(mTextPerf);
-    return fg;
-}
-
-bool 
-gfxFontGroup::IsInvalidChar(uint8_t ch)
-{
-    return ((ch & 0x7f) < 0x20 || ch == 0x7f);
-}
-
-bool 
-gfxFontGroup::IsInvalidChar(char16_t ch)
-{
-    // All printable 7-bit ASCII values are OK
-    if (ch >= ' ' && ch < 0x7f) {
-        return false;
-    }
-    // No point in sending non-printing control chars through font shaping
-    if (ch <= 0x9f) {
-        return true;
-    }
-    return (((ch & 0xFF00) == 0x2000 /* Unicode control character */ &&
-             (ch == 0x200B/*ZWSP*/ || ch == 0x2028/*LSEP*/ || ch == 0x2029/*PSEP*/)) ||
-            IsBidiControl(ch));
-}
-
-gfxTextRun *
-gfxFontGroup::MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags)
-{
-    aFlags |= TEXT_IS_8BIT | TEXT_IS_ASCII | TEXT_IS_PERSISTENT;
-    return gfxTextRun::Create(aParams, 0, this, aFlags);
-}
-
-gfxTextRun *
-gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags)
-{
-    aFlags |= TEXT_IS_8BIT | TEXT_IS_ASCII | TEXT_IS_PERSISTENT;
-
-    gfxTextRun *textRun = gfxTextRun::Create(aParams, 1, this, aFlags);
-    if (!textRun) {
-        return nullptr;
-    }
-
-    gfxFont *font = GetFontAt(0);
-    if (MOZ_UNLIKELY(GetStyle()->size == 0)) {
-        // Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
-        // them, and always create at least size 1 fonts, i.e. they still
-        // render something for size 0 fonts.
-        textRun->AddGlyphRun(font, gfxTextRange::kFontGroup, 0, false);
-    }
-    else {
-        if (font->GetSpaceGlyph()) {
-            // Normally, the font has a cached space glyph, so we can avoid
-            // the cost of calling FindFontForChar.
-            textRun->SetSpaceGlyph(font, aParams->mContext, 0);
-        } else {
-            // In case the primary font doesn't have <space> (bug 970891),
-            // find one that does.
-            uint8_t matchType;
-            nsRefPtr<gfxFont> spaceFont =
-                FindFontForChar(' ', 0, MOZ_SCRIPT_LATIN, nullptr, &matchType);
-            if (spaceFont) {
-                textRun->SetSpaceGlyph(spaceFont, aParams->mContext, 0);
-            }
-        }
-    }
-
-    // Note that the gfxGlyphExtents glyph bounds storage for the font will
-    // always contain an entry for the font's space glyph, so we don't have
-    // to call FetchGlyphExtents here.
-    return textRun;
-}
-
-gfxTextRun *
-gfxFontGroup::MakeBlankTextRun(uint32_t aLength,
-                               const Parameters *aParams, uint32_t aFlags)
-{
-    gfxTextRun *textRun =
-        gfxTextRun::Create(aParams, aLength, this, aFlags);
-    if (!textRun) {
-        return nullptr;
-    }
-
-    textRun->AddGlyphRun(GetFontAt(0), gfxTextRange::kFontGroup, 0, false);
-    return textRun;
-}
-
-gfxTextRun *
-gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
-{
-    // only use U+2010 if it is supported by the first font in the group;
-    // it's better to use ASCII '-' from the primary font than to fall back to
-    // U+2010 from some other, possibly poorly-matching face
-    static const char16_t hyphen = 0x2010;
-    gfxFont *font = GetFontAt(0);
-    if (font && font->HasCharacter(hyphen)) {
-        return MakeTextRun(&hyphen, 1, aCtx, aAppUnitsPerDevUnit,
-                           gfxFontGroup::TEXT_IS_PERSISTENT);
-    }
-
-    static const uint8_t dash = '-';
-    return MakeTextRun(&dash, 1, aCtx, aAppUnitsPerDevUnit,
-                       gfxFontGroup::TEXT_IS_PERSISTENT);
-}
-
-gfxFloat
-gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider)
-{
-    if (mHyphenWidth < 0) {
-        nsRefPtr<gfxContext> ctx(aProvider->GetContext());
-        if (ctx) {
-            nsAutoPtr<gfxTextRun>
-                hyphRun(MakeHyphenTextRun(ctx,
-                                          aProvider->GetAppUnitsPerDevUnit()));
-            mHyphenWidth = hyphRun.get() ?
-                hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
-        }
-    }
-    return mHyphenWidth;
-}
-
-gfxTextRun *
-gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength,
-                          const Parameters *aParams, uint32_t aFlags)
-{
-    if (aLength == 0) {
-        return MakeEmptyTextRun(aParams, aFlags);
-    }
-    if (aLength == 1 && aString[0] == ' ') {
-        return MakeSpaceTextRun(aParams, aFlags);
-    }
-
-    aFlags |= TEXT_IS_8BIT;
-
-    if (GetStyle()->size == 0) {
-        // Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
-        // them, and always create at least size 1 fonts, i.e. they still
-        // render something for size 0 fonts.
-        return MakeBlankTextRun(aLength, aParams, aFlags);
-    }
-
-    gfxTextRun *textRun = gfxTextRun::Create(aParams, aLength,
-                                             this, aFlags);
-    if (!textRun) {
-        return nullptr;
-    }
-
-    InitTextRun(aParams->mContext, textRun, aString, aLength);
-
-    textRun->FetchGlyphExtents(aParams->mContext);
-
-    return textRun;
-}
-
-gfxTextRun *
-gfxFontGroup::MakeTextRun(const char16_t *aString, uint32_t aLength,
-                          const Parameters *aParams, uint32_t aFlags)
-{
-    if (aLength == 0) {
-        return MakeEmptyTextRun(aParams, aFlags);
-    }
-    if (aLength == 1 && aString[0] == ' ') {
-        return MakeSpaceTextRun(aParams, aFlags);
-    }
-    if (GetStyle()->size == 0) {
-        return MakeBlankTextRun(aLength, aParams, aFlags);
-    }
-
-    gfxTextRun *textRun = gfxTextRun::Create(aParams, aLength,
-                                             this, aFlags);
-    if (!textRun) {
-        return nullptr;
-    }
-
-    InitTextRun(aParams->mContext, textRun, aString, aLength);
-
-    textRun->FetchGlyphExtents(aParams->mContext);
-
-    return textRun;
-}
-
-template<typename T>
-void
-gfxFontGroup::InitTextRun(gfxContext *aContext,
-                          gfxTextRun *aTextRun,
-                          const T *aString,
-                          uint32_t aLength)
-{
-    NS_ASSERTION(aLength > 0, "don't call InitTextRun for a zero-length run");
-
-    // we need to do numeral processing even on 8-bit text,
-    // in case we're converting Western to Hindi/Arabic digits
-    int32_t numOption = gfxPlatform::GetPlatform()->GetBidiNumeralOption();
-    nsAutoArrayPtr<char16_t> transformedString;
-    if (numOption != IBMBIDI_NUMERAL_NOMINAL) {
-        // scan the string for numerals that may need to be transformed;
-        // if we find any, we'll make a local copy here and use that for
-        // font matching and glyph generation/shaping
-        bool prevIsArabic =
-            (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_INCOMING_ARABICCHAR) != 0;
-        for (uint32_t i = 0; i < aLength; ++i) {
-            char16_t origCh = aString[i];
-            char16_t newCh = HandleNumberInChar(origCh, prevIsArabic, numOption);
-            if (newCh != origCh) {
-                if (!transformedString) {
-                    transformedString = new char16_t[aLength];
-                    if (sizeof(T) == sizeof(char16_t)) {
-                        memcpy(transformedString.get(), aString, i * sizeof(char16_t));
-                    } else {
-                        for (uint32_t j = 0; j < i; ++j) {
-                            transformedString[j] = aString[j];
-                        }
-                    }
-                }
-            }
-            if (transformedString) {
-                transformedString[i] = newCh;
-            }
-            prevIsArabic = IS_ARABIC_CHAR(newCh);
-        }
-    }
-
-#ifdef PR_LOGGING
-    PRLogModuleInfo *log = (mStyle.systemFont ?
-                            gfxPlatform::GetLog(eGfxLog_textrunui) :
-                            gfxPlatform::GetLog(eGfxLog_textrun));
-#endif
-
-    // variant fallback handling may end up passing through this twice
-    bool redo;
-    do {
-        redo = false;
-
-        if (sizeof(T) == sizeof(uint8_t) && !transformedString) {
-
-#ifdef PR_LOGGING
-            if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_WARNING))) {
-                nsAutoCString lang;
-                mStyle.language->ToUTF8String(lang);
-                nsAutoString families;
-                mFamilyList.ToString(families);
-                nsAutoCString str((const char*)aString, aLength);
-                PR_LOG(log, PR_LOG_WARNING,\
-                       ("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
-                        "len %d weight: %d width: %d style: %s size: %6.2f %d-byte "
-                        "TEXTRUN [%s] ENDTEXTRUN\n",
-                        (mStyle.systemFont ? "textrunui" : "textrun"),
-                        NS_ConvertUTF16toUTF8(families).get(),
-                        (mFamilyList.GetDefaultFontType() == eFamily_serif ?
-                         "serif" :
-                         (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
-                          "sans-serif" : "none")),
-                        lang.get(), MOZ_SCRIPT_LATIN, aLength,
-                        uint32_t(mStyle.weight), uint32_t(mStyle.stretch),
-                        (mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
-                        (mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
-                                                                "normal")),
-                        mStyle.size,
-                        sizeof(T),
-                        str.get()));
-            }
-#endif
-
-            // the text is still purely 8-bit; bypass the script-run itemizer
-            // and treat it as a single Latin run
-            InitScriptRun(aContext, aTextRun, aString,
-                          0, aLength, MOZ_SCRIPT_LATIN);
-        } else {
-            const char16_t *textPtr;
-            if (transformedString) {
-                textPtr = transformedString.get();
-            } else {
-                // typecast to avoid compilation error for the 8-bit version,
-                // even though this is dead code in that case
-                textPtr = reinterpret_cast<const char16_t*>(aString);
-            }
-
-            // split into script runs so that script can potentially influence
-            // the font matching process below
-            gfxScriptItemizer scriptRuns(textPtr, aLength);
-
-            uint32_t runStart = 0, runLimit = aLength;
-            int32_t runScript = MOZ_SCRIPT_LATIN;
-            while (scriptRuns.Next(runStart, runLimit, runScript)) {
-
-    #ifdef PR_LOGGING
-                if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_WARNING))) {
-                    nsAutoCString lang;
-                    mStyle.language->ToUTF8String(lang);
-                    nsAutoString families;
-                    mFamilyList.ToString(families);
-                    uint32_t runLen = runLimit - runStart;
-                    PR_LOG(log, PR_LOG_WARNING,\
-                           ("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
-                            "len %d weight: %d width: %d style: %s size: %6.2f "
-                            "%d-byte TEXTRUN [%s] ENDTEXTRUN\n",
-                            (mStyle.systemFont ? "textrunui" : "textrun"),
-                            NS_ConvertUTF16toUTF8(families).get(),
-                            (mFamilyList.GetDefaultFontType() == eFamily_serif ?
-                             "serif" :
-                             (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
-                              "sans-serif" : "none")),
-                            lang.get(), runScript, runLen,
-                            uint32_t(mStyle.weight), uint32_t(mStyle.stretch),
-                            (mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
-                            (mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
-                                                                    "normal")),
-                            mStyle.size,
-                            sizeof(T),
-                            NS_ConvertUTF16toUTF8(textPtr + runStart, runLen).get()));
-                }
-    #endif
-
-                InitScriptRun(aContext, aTextRun, textPtr + runStart,
-                              runStart, runLimit - runStart, runScript);
-            }
-        }
-
-        // if shaping was aborted due to lack of feature support, clear out
-        // glyph runs and redo shaping with fallback forced on
-        if (aTextRun->GetShapingState() == gfxTextRun::eShapingState_Aborted) {
-            redo = true;
-            aTextRun->SetShapingState(
-                gfxTextRun::eShapingState_ForceFallbackFeature);
-            aTextRun->ClearGlyphsAndCharacters();
-        }
-
-    } while (redo);
-
-    if (sizeof(T) == sizeof(char16_t) && aLength > 0) {
-        gfxTextRun::CompressedGlyph *glyph = aTextRun->GetCharacterGlyphs();
-        if (!glyph->IsSimpleGlyph()) {
-            glyph->SetClusterStart(true);
-        }
-    }
-
-    // It's possible for CoreText to omit glyph runs if it decides they contain
-    // only invisibles (e.g., U+FEFF, see reftest 474417-1). In this case, we
-    // need to eliminate them from the glyph run array to avoid drawing "partial
-    // ligatures" with the wrong font.
-    // We don't do this during InitScriptRun (or gfxFont::InitTextRun) because
-    // it will iterate back over all glyphruns in the textrun, which leads to
-    // pathologically-bad perf in the case where a textrun contains many script
-    // changes (see bug 680402) - we'd end up re-sanitizing all the earlier runs
-    // every time a new script subrun is processed.
-    aTextRun->SanitizeGlyphRuns();
-
-    aTextRun->SortGlyphRuns();
-}
-
-template<typename T>
-void
-gfxFontGroup::InitScriptRun(gfxContext *aContext,
-                            gfxTextRun *aTextRun,
-                            const T *aString, // text for this script run,
-                                              // not the entire textrun
-                            uint32_t aOffset, // position of the script run
-                                              // within the textrun
-                            uint32_t aLength, // length of the script run
-                            int32_t aRunScript)
-{
-    NS_ASSERTION(aLength > 0, "don't call InitScriptRun for a 0-length run");
-    NS_ASSERTION(aTextRun->GetShapingState() != gfxTextRun::eShapingState_Aborted,
-                 "don't call InitScriptRun with aborted shaping state");
-
-    gfxFont *mainFont = GetFontAt(0);
-
-    uint32_t runStart = 0;
-    nsAutoTArray<gfxTextRange,3> fontRanges;
-    ComputeRanges(fontRanges, aString, aLength, aRunScript);
-    uint32_t numRanges = fontRanges.Length();
-
-    for (uint32_t r = 0; r < numRanges; r++) {
-        const gfxTextRange& range = fontRanges[r];
-        uint32_t matchedLength = range.Length();
-        gfxFont *matchedFont = range.font;
-
-        // create the glyph run for this range
-        if (matchedFont && mStyle.noFallbackVariantFeatures) {
-            // common case - just do glyph layout and record the
-            // resulting positioned glyphs
-            aTextRun->AddGlyphRun(matchedFont, range.matchType,
-                                  aOffset + runStart, (matchedLength > 0));
-            if (!matchedFont->SplitAndInitTextRun(aContext, aTextRun,
-                                                  aString + runStart,
-                                                  aOffset + runStart,
-                                                  matchedLength,
-                                                  aRunScript)) {
-                // glyph layout failed! treat as missing glyphs
-                matchedFont = nullptr;
-            }
-        } else if (matchedFont) {
-            // shape with some variant feature that requires fallback handling
-            bool petiteToSmallCaps = false;
-            bool syntheticLower = false;
-            bool syntheticUpper = false;
-
-            if (mStyle.variantSubSuper != NS_FONT_VARIANT_POSITION_NORMAL &&
-                (aTextRun->GetShapingState() ==
-                     gfxTextRun::eShapingState_ForceFallbackFeature ||
-                 !matchedFont->SupportsSubSuperscript(mStyle.variantSubSuper,
-                                                      aString, aLength,
-                                                      aRunScript)))
-            {
-                // fallback for subscript/superscript variant glyphs
-
-                // if the feature was already used, abort and force
-                // fallback across the entire textrun
-                gfxTextRun::ShapingState ss = aTextRun->GetShapingState();
-
-                if (ss == gfxTextRun::eShapingState_Normal) {
-                    aTextRun->SetShapingState(gfxTextRun::eShapingState_ShapingWithFallback);
-                } else if (ss == gfxTextRun::eShapingState_ShapingWithFeature) {
-                    aTextRun->SetShapingState(gfxTextRun::eShapingState_Aborted);
-                    return;
-                }
-
-                nsRefPtr<gfxFont> subSuperFont =
-                    matchedFont->GetSubSuperscriptFont(aTextRun->GetAppUnitsPerDevUnit());
-                aTextRun->AddGlyphRun(subSuperFont, range.matchType,
-                                      aOffset + runStart, (matchedLength > 0));
-                if (!subSuperFont->SplitAndInitTextRun(aContext, aTextRun,
-                                                       aString + runStart,
-                                                       aOffset + runStart,
-                                                       matchedLength,
-                                                       aRunScript)) {
-                    // glyph layout failed! treat as missing glyphs
-                    matchedFont = nullptr;
-                }
-            } else if (mStyle.variantCaps != NS_FONT_VARIANT_CAPS_NORMAL &&
-                       !matchedFont->SupportsVariantCaps(aRunScript,
-                                                         mStyle.variantCaps,
-                                                         petiteToSmallCaps,
-                                                         syntheticLower,
-                                                         syntheticUpper))
-            {
-                // fallback for small-caps variant glyphs
-                if (!matchedFont->InitFakeSmallCapsRun(aContext, aTextRun,
-                                                       aString + runStart,
-                                                       aOffset + runStart,
-                                                       matchedLength,
-                                                       range.matchType,
-                                                       aRunScript,
-                                                       syntheticLower,
-                                                       syntheticUpper)) {
-                    matchedFont = nullptr;
-                }
-            } else {
-                // shape normally with variant feature enabled
-                gfxTextRun::ShapingState ss = aTextRun->GetShapingState();
-
-                // adjust the shaping state if necessary
-                if (ss == gfxTextRun::eShapingState_Normal) {
-                    aTextRun->SetShapingState(gfxTextRun::eShapingState_ShapingWithFeature);
-                } else if (ss == gfxTextRun::eShapingState_ShapingWithFallback) {
-                    // already have shaping results using fallback, need to redo
-                    aTextRun->SetShapingState(gfxTextRun::eShapingState_Aborted);
-                    return;
-                }
-
-                // do glyph layout and record the resulting positioned glyphs
-                aTextRun->AddGlyphRun(matchedFont, range.matchType,
-                                      aOffset + runStart, (matchedLength > 0));
-                if (!matchedFont->SplitAndInitTextRun(aContext, aTextRun,
-                                                      aString + runStart,
-                                                      aOffset + runStart,
-                                                      matchedLength,
-                                                      aRunScript)) {
-                    // glyph layout failed! treat as missing glyphs
-                    matchedFont = nullptr;
-                }
-            }
-        } else {
-            aTextRun->AddGlyphRun(mainFont, gfxTextRange::kFontGroup,
-                                  aOffset + runStart, (matchedLength > 0));
-        }
-
-        if (!matchedFont) {
-            // We need to set cluster boundaries (and mark spaces) so that
-            // surrogate pairs, combining characters, etc behave properly,
-            // even if we don't have glyphs for them
-            aTextRun->SetupClusterBoundaries(aOffset + runStart, aString + runStart,
-                                             matchedLength);
-
-            // various "missing" characters may need special handling,
-            // so we check for them here
-            uint32_t runLimit = runStart + matchedLength;
-            for (uint32_t index = runStart; index < runLimit; index++) {
-                T ch = aString[index];
-
-                // tab and newline are not to be displayed as hexboxes,
-                // but do need to be recorded in the textrun
-                if (ch == '\n') {
-                    aTextRun->SetIsNewline(aOffset + index);
-                    continue;
-                }
-                if (ch == '\t') {
-                    aTextRun->SetIsTab(aOffset + index);
-                    continue;
-                }
-
-                // for 16-bit textruns only, check for surrogate pairs and
-                // special Unicode spaces; omit these checks in 8-bit runs
-                if (sizeof(T) == sizeof(char16_t)) {
-                    if (NS_IS_HIGH_SURROGATE(ch) &&
-                        index + 1 < aLength &&
-                        NS_IS_LOW_SURROGATE(aString[index + 1]))
-                    {
-                        aTextRun->SetMissingGlyph(aOffset + index,
-                                                  SURROGATE_TO_UCS4(ch,
-                                                                    aString[index + 1]),
-                                                  mainFont);
-                        index++;
-                        continue;
-                    }
-
-                    // check if this is a known Unicode whitespace character that
-                    // we can render using the space glyph with a custom width
-                    gfxFloat wid = mainFont->SynthesizeSpaceWidth(ch);
-                    if (wid >= 0.0) {
-                        nscoord advance =
-                            aTextRun->GetAppUnitsPerDevUnit() * floor(wid + 0.5);
-                        if (gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance)) {
-                            aTextRun->GetCharacterGlyphs()[aOffset + index].
-                                SetSimpleGlyph(advance,
-                                               mainFont->GetSpaceGlyph());
-                        } else {
-                            gfxTextRun::DetailedGlyph detailedGlyph;
-                            detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph();
-                            detailedGlyph.mAdvance = advance;
-                            detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
-                            gfxShapedText::CompressedGlyph g;
-                            g.SetComplex(true, true, 1);
-                            aTextRun->SetGlyphs(aOffset + index,
-                                                g, &detailedGlyph);
-                        }
-                        continue;
-                    }
-                }
-
-                if (IsInvalidChar(ch)) {
-                    // invalid chars are left as zero-width/invisible
-                    continue;
-                }
-
-                // record char code so we can draw a box with the Unicode value
-                aTextRun->SetMissingGlyph(aOffset + index, ch, mainFont);
-            }
-        }
-
-        runStart += matchedLength;
-    }
-}
-
-bool
-gfxFont::InitFakeSmallCapsRun(gfxContext     *aContext,
-                              gfxTextRun     *aTextRun,
-                              const uint8_t  *aText,
-                              uint32_t        aOffset,
-                              uint32_t        aLength,
-                              uint8_t         aMatchType,
-                              int32_t         aScript,
-                              bool            aSyntheticLower,
-                              bool            aSyntheticUpper)
-{
-    NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aText),
-                                         aLength);
-    return InitFakeSmallCapsRun(aContext, aTextRun, unicodeString.get(),
-                                aOffset, aLength, aMatchType, aScript,
-                                aSyntheticLower, aSyntheticUpper);
-}
-
-bool
-gfxFont::InitFakeSmallCapsRun(gfxContext     *aContext,
-                              gfxTextRun     *aTextRun,
-                              const char16_t *aText,
-                              uint32_t        aOffset,
-                              uint32_t        aLength,
-                              uint8_t         aMatchType,
-                              int32_t         aScript,
-                              bool            aSyntheticLower,
-                              bool            aSyntheticUpper)
-{
-    bool ok = true;
-
-    nsRefPtr<gfxFont> smallCapsFont = GetSmallCapsFont();
-
-    enum RunCaseAction {
-        kNoChange,
-        kUppercaseReduce,
-        kUppercase
-    };
-
-    RunCaseAction runAction = kNoChange;
-    uint32_t runStart = 0;
-
-    for (uint32_t i = 0; i <= aLength; ++i) {
-        uint32_t extraCodeUnits = 0; // Will be set to 1 if we need to consume
-                                     // a trailing surrogate as well as the
-                                     // current code unit.
-        RunCaseAction chAction = kNoChange;
-        // Unless we're at the end, figure out what treatment the current
-        // character will need.
-        if (i < aLength) {
-            uint32_t ch = aText[i];
-            if (NS_IS_HIGH_SURROGATE(ch) && i < aLength - 1 &&
-                NS_IS_LOW_SURROGATE(aText[i + 1])) {
-                ch = SURROGATE_TO_UCS4(ch, aText[i + 1]);
-                extraCodeUnits = 1;
-            }
-            // Characters that aren't the start of a cluster are ignored here.
-            // They get added to whatever lowercase/non-lowercase run we're in.
-            if (IsClusterExtender(ch)) {
-                chAction = runAction;
-            } else {
-                if (ch != ToUpperCase(ch) || mozilla::unicode::SpecialUpper(ch)) {
-                    // ch is lower case
-                    chAction = (aSyntheticLower ? kUppercaseReduce : kNoChange);
-                } else if (ch != ToLowerCase(ch)) {
-                    // ch is upper case
-                    chAction = (aSyntheticUpper ? kUppercaseReduce : kNoChange);
-                    if (mStyle.language == nsGkAtoms::el) {
-                        // In Greek, check for characters that will be modified by
-                        // the GreekUpperCase mapping - this catches accented
-                        // capitals where the accent is to be removed (bug 307039).
-                        // These are handled by using the full-size font with the
-                        // uppercasing transform.
-                        mozilla::GreekCasing::State state;
-                        uint32_t ch2 = mozilla::GreekCasing::UpperCase(ch, state);
-                        if (ch != ch2 && !aSyntheticUpper) {
-                            chAction = kUppercase;
-                        }
-                    }
-                }
-            }
-        }
-
-        // At the end of the text or when the current character needs different
-        // casing treatment from the current run, finish the run-in-progress
-        // and prepare to accumulate a new run.
-        // Note that we do not look at any source data for offset [i] here,
-        // as that would be invalid in the case where i==length.
-        if ((i == aLength || runAction != chAction) && runStart < i) {
-            uint32_t runLength = i - runStart;
-            gfxFont* f = this;
-            switch (runAction) {
-            case kNoChange:
-                // just use the current font and the existing string
-                aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, true);
-                if (!f->SplitAndInitTextRun(aContext, aTextRun,
-                                            aText + runStart,
-                                            aOffset + runStart, runLength,
-                                            aScript)) {
-                    ok = false;
-                }
-                break;
-
-            case kUppercaseReduce:
-                // use reduced-size font, then fall through to uppercase the text
-                f = smallCapsFont;
-
-            case kUppercase:
-                // apply uppercase transform to the string
-                nsDependentSubstring origString(aText + runStart, runLength);
-                nsAutoString convertedString;
-                nsAutoTArray<bool,50> charsToMergeArray;
-                nsAutoTArray<bool,50> deletedCharsArray;
-
-                bool mergeNeeded = nsCaseTransformTextRunFactory::
-                    TransformString(origString,
-                                    convertedString,
-                                    true,
-                                    mStyle.language,
-                                    charsToMergeArray,
-                                    deletedCharsArray);
-
-                if (mergeNeeded) {
-                    // This is the hard case: the transformation caused chars
-                    // to be inserted or deleted, so we can't shape directly
-                    // into the destination textrun but have to handle the
-                    // mismatch of character positions.
-                    gfxTextRunFactory::Parameters params = {
-                        aContext, nullptr, nullptr, nullptr, 0,
-                        aTextRun->GetAppUnitsPerDevUnit()
-                    };
-                    nsAutoPtr<gfxTextRun> tempRun;
-                    tempRun =
-                        gfxTextRun::Create(&params, convertedString.Length(),
-                                           aTextRun->GetFontGroup(), 0);
-                    tempRun->AddGlyphRun(f, aMatchType, 0, true);
-                    if (!f->SplitAndInitTextRun(aContext, tempRun,
-                                                convertedString.BeginReading(),
-                                                0, convertedString.Length(),
-                                                aScript)) {
-                        ok = false;
-                    } else {
-                        nsAutoPtr<gfxTextRun> mergedRun;
-                        mergedRun =
-                            gfxTextRun::Create(&params, runLength,
-                                               aTextRun->GetFontGroup(), 0);
-                        MergeCharactersInTextRun(mergedRun, tempRun,
-                                                 charsToMergeArray.Elements(),
-                                                 deletedCharsArray.Elements());
-                        aTextRun->CopyGlyphDataFrom(mergedRun, 0, runLength,
-                                                    aOffset + runStart);
-                    }
-                } else {
-                    aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart,
-                                          true);
-                    if (!f->SplitAndInitTextRun(aContext, aTextRun,
-                                                convertedString.BeginReading(),
-                                                aOffset + runStart, runLength,
-                                                aScript)) {
-                        ok = false;
-                    }
-                }
-                break;
-            }
-
-            runStart = i;
-        }
-
-        i += extraCodeUnits;
-        if (i < aLength) {
-            runAction = chAction;
-        }
-    }
-
-    return ok;
-}
-
-already_AddRefed<gfxFont>
-gfxFont::GetSmallCapsFont()
-{
-    gfxFontStyle style(*GetStyle());
-    style.size *= SMALL_CAPS_SCALE_FACTOR;
-    style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
-    gfxFontEntry* fe = GetFontEntry();
-    bool needsBold = style.weight >= 600 && !fe->IsBold();
-    return fe->FindOrMakeFont(&style, needsBold);
-}
-
-already_AddRefed<gfxFont>
-gfxFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel)
-{
-    gfxFontStyle style(*GetStyle());
-    style.AdjustForSubSuperscript(aAppUnitsPerDevPixel);
-    gfxFontEntry* fe = GetFontEntry();
-    bool needsBold = style.weight >= 600 && !fe->IsBold();
-    return fe->FindOrMakeFont(&style, needsBold);
-}
-
-gfxTextRun *
-gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
-                                 LazyReferenceContextGetter& aRefContextGetter)
-{
-    if (mCachedEllipsisTextRun &&
-        mCachedEllipsisTextRun->GetAppUnitsPerDevUnit() == aAppUnitsPerDevPixel) {
-        return mCachedEllipsisTextRun;
-    }
-
-    // Use a Unicode ellipsis if the font supports it,
-    // otherwise use three ASCII periods as fallback.
-    gfxFont* firstFont = GetFontAt(0);
-    nsString ellipsis = firstFont->HasCharacter(kEllipsisChar[0])
-        ? nsDependentString(kEllipsisChar,
-                            ArrayLength(kEllipsisChar) - 1)
-        : nsDependentString(kASCIIPeriodsChar,
-                            ArrayLength(kASCIIPeriodsChar) - 1);
-
-    nsRefPtr<gfxContext> refCtx = aRefContextGetter.GetRefContext();
-    Parameters params = {
-        refCtx, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel
-    };
-    gfxTextRun* textRun =
-        MakeTextRun(ellipsis.get(), ellipsis.Length(), &params, TEXT_IS_PERSISTENT);
-    if (!textRun) {
-        return nullptr;
-    }
-    mCachedEllipsisTextRun = textRun;
-    textRun->ReleaseFontGroup(); // don't let the presence of a cached ellipsis
-                                 // textrun prolong the fontgroup's life
-    return textRun;
-}
-
-already_AddRefed<gfxFont>
-gfxFontGroup::TryAllFamilyMembers(gfxFontFamily* aFamily, uint32_t aCh)
-{
-    if (!aFamily->TestCharacterMap(aCh)) {
-        return nullptr;
-    }
-
-    // Note that we don't need the actual runScript in matchData for
-    // gfxFontFamily::SearchAllFontsForChar, it's only used for the
-    // system-fallback case. So we can just set it to 0 here.
-    GlobalFontMatch matchData(aCh, 0, &mStyle);
-    aFamily->SearchAllFontsForChar(&matchData);
-    gfxFontEntry *fe = matchData.mBestMatch;
-    if (!fe) {
-        return nullptr;
-    }
-
-    bool needsBold = mStyle.weight >= 600 && !fe->IsBold();
-    nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
-    return font.forget();
-}
-
-already_AddRefed<gfxFont>
-gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
-                              int32_t aRunScript, gfxFont *aPrevMatchedFont,
-                              uint8_t *aMatchType)
-{
-    // To optimize common cases, try the first font in the font-group
-    // before going into the more detailed checks below
-    uint32_t nextIndex = 0;
-    bool isJoinControl = gfxFontUtils::IsJoinControl(aCh);
-    bool wasJoinCauser = gfxFontUtils::IsJoinCauser(aPrevCh);
-    bool isVarSelector = gfxFontUtils::IsVarSelector(aCh);
-
-    if (!isJoinControl && !wasJoinCauser && !isVarSelector) {
-        nsRefPtr<gfxFont> firstFont = mFonts[0].Font();
-        if (firstFont->HasCharacter(aCh)) {
-            *aMatchType = gfxTextRange::kFontGroup;
-            return firstFont.forget();
-        }
-        // It's possible that another font in the family (e.g. regular face,
-        // where the requested style was italic) will support the character
-        nsRefPtr<gfxFont> font = TryAllFamilyMembers(mFonts[0].Family(), aCh);
-        if (font) {
-            *aMatchType = gfxTextRange::kFontGroup;
-            return font.forget();
-        }
-        // we don't need to check the first font again below
-        ++nextIndex;
-    }
-
-    if (aPrevMatchedFont) {
-        // Don't switch fonts for control characters, regardless of
-        // whether they are present in the current font, as they won't
-        // actually be rendered (see bug 716229)
-        if (isJoinControl ||
-            GetGeneralCategory(aCh) == HB_UNICODE_GENERAL_CATEGORY_CONTROL) {
-            nsRefPtr<gfxFont> ret = aPrevMatchedFont;
-            return ret.forget();
-        }
-
-        // if previous character was a join-causer (ZWJ),
-        // use the same font as the previous range if we can
-        if (wasJoinCauser) {
-            if (aPrevMatchedFont->HasCharacter(aCh)) {
-                nsRefPtr<gfxFont> ret = aPrevMatchedFont;
-                return ret.forget();
-            }
-        }
-    }
-
-    // if this character is a variation selector,
-    // use the previous font regardless of whether it supports VS or not.
-    // otherwise the text run will be divided.
-    if (isVarSelector) {
-        if (aPrevMatchedFont) {
-            nsRefPtr<gfxFont> ret = aPrevMatchedFont;
-            return ret.forget();
-        }
-        // VS alone. it's meaningless to search different fonts
-        return nullptr;
-    }
-
-    // 1. check remaining fonts in the font group
-    uint32_t fontListLength = FontListLength();
-    for (uint32_t i = nextIndex; i < fontListLength; i++) {
-        nsRefPtr<gfxFont> font = mFonts[i].Font();
-        if (font->HasCharacter(aCh)) {
-            *aMatchType = gfxTextRange::kFontGroup;
-            return font.forget();
-        }
-
-        font = TryAllFamilyMembers(mFonts[i].Family(), aCh);
-        if (font) {
-            *aMatchType = gfxTextRange::kFontGroup;
-            return font.forget();
-        }
-    }
-
-    // if character is in Private Use Area, don't do matching against pref or system fonts
-    if ((aCh >= 0xE000  && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
-        return nullptr;
-
-    // 2. search pref fonts
-    nsRefPtr<gfxFont> font = WhichPrefFontSupportsChar(aCh);
-    if (font) {
-        *aMatchType = gfxTextRange::kPrefsFallback;
-        return font.forget();
-    }
-
-    // 3. use fallback fonts
-    // -- before searching for something else check the font used for the previous character
-    if (aPrevMatchedFont && aPrevMatchedFont->HasCharacter(aCh)) {
-        *aMatchType = gfxTextRange::kSystemFallback;
-        nsRefPtr<gfxFont> ret = aPrevMatchedFont;
-        return ret.forget();
-    }
-
-    // never fall back for characters from unknown scripts
-    if (aRunScript == HB_SCRIPT_UNKNOWN) {
-        return nullptr;
-    }
-
-    // for known "space" characters, don't do a full system-fallback search;
-    // we'll synthesize appropriate-width spaces instead of missing-glyph boxes
-    if (GetGeneralCategory(aCh) ==
-            HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR &&
-        GetFontAt(0)->SynthesizeSpaceWidth(aCh) >= 0.0)
-    {
-        return nullptr;
-    }
-
-    // -- otherwise look for other stuff
-    *aMatchType = gfxTextRange::kSystemFallback;
-    font = WhichSystemFontSupportsChar(aCh, aRunScript);
-    return font.forget();
-}
-
-template<typename T>
-void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
-                                 const T *aString, uint32_t aLength,
-                                 int32_t aRunScript)
-{
-    NS_ASSERTION(aRanges.Length() == 0, "aRanges must be initially empty");
-    NS_ASSERTION(aLength > 0, "don't call ComputeRanges for zero-length text");
-
-    uint32_t prevCh = 0;
-    int32_t lastRangeIndex = -1;
-
-    // initialize prevFont to the group's primary font, so that this will be
-    // used for string-initial control chars, etc rather than risk hitting font
-    // fallback for these (bug 716229)
-    gfxFont *prevFont = GetFontAt(0);
-
-    // if we use the initial value of prevFont, we treat this as a match from
-    // the font group; fixes bug 978313
-    uint8_t matchType = gfxTextRange::kFontGroup;
-
-    for (uint32_t i = 0; i < aLength; i++) {
-
-        const uint32_t origI = i; // save off in case we increase for surrogate
-
-        // set up current ch
-        uint32_t ch = aString[i];
-
-        // in 16-bit case only, check for surrogate pair
-        if (sizeof(T) == sizeof(char16_t)) {
-            if ((i + 1 < aLength) && NS_IS_HIGH_SURROGATE(ch) &&
-                                 NS_IS_LOW_SURROGATE(aString[i + 1])) {
-                i++;
-                ch = SURROGATE_TO_UCS4(ch, aString[i]);
-            }
-        }
-
-        if (ch == 0xa0) {
-            ch = ' ';
-        }
-
-        // find the font for this char
-        nsRefPtr<gfxFont> font =
-            FindFontForChar(ch, prevCh, aRunScript, prevFont, &matchType);
-
-#ifndef RELEASE_BUILD
-        if (MOZ_UNLIKELY(mTextPerf)) {
-            if (matchType == gfxTextRange::kPrefsFallback) {
-                mTextPerf->current.fallbackPrefs++;
-            } else if (matchType == gfxTextRange::kSystemFallback) {
-                mTextPerf->current.fallbackSystem++;
-            }
-        }
-#endif
-
-        prevCh = ch;
-
-        if (lastRangeIndex == -1) {
-            // first char ==> make a new range
-            aRanges.AppendElement(gfxTextRange(0, 1, font, matchType));
-            lastRangeIndex++;
-            prevFont = font;
-        } else {
-            // if font has changed, make a new range
-            gfxTextRange& prevRange = aRanges[lastRangeIndex];
-            if (prevRange.font != font || prevRange.matchType != matchType) {
-                // close out the previous range
-                prevRange.end = origI;
-                aRanges.AppendElement(gfxTextRange(origI, i + 1,
-                                                   font, matchType));
-                lastRangeIndex++;
-
-                // update prevFont for the next match, *unless* we switched
-                // fonts on a ZWJ, in which case propagating the changed font
-                // is probably not a good idea (see bug 619511)
-                if (sizeof(T) == sizeof(uint8_t) ||
-                    !gfxFontUtils::IsJoinCauser(ch))
-                {
-                    prevFont = font;
-                }
-            }
-        }
-    }
-
-    aRanges[lastRangeIndex].end = aLength;
-}
-
-gfxUserFontSet* 
-gfxFontGroup::GetUserFontSet()
-{
-    return mUserFontSet;
-}
-
-void 
-gfxFontGroup::SetUserFontSet(gfxUserFontSet *aUserFontSet)
-{
-    if (aUserFontSet == mUserFontSet) {
-        return;
-    }
-    mUserFontSet = aUserFontSet;
-    mCurrGeneration = GetGeneration() - 1;
-    UpdateFontList();
-}
-
-uint64_t
-gfxFontGroup::GetGeneration()
-{
-    if (!mUserFontSet)
-        return 0;
-    return mUserFontSet->GetGeneration();
-}
-
-// note: gfxPangoFontGroup overrides UpdateFontList, such that
-//       BuildFontList is never used
-void
-gfxFontGroup::UpdateFontList()
-{
-    if (mCurrGeneration != GetGeneration()) {
-        // xxx - can probably improve this to detect when all fonts were found, so no need to update list
-        mFonts.Clear();
-        mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
-        mSkipDrawing = false;
-        BuildFontList();
-        mCurrGeneration = GetGeneration();
-        mCachedEllipsisTextRun = nullptr;
-    }
-}
-
-struct PrefFontCallbackData {
-    explicit PrefFontCallbackData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamiliesArray)
-        : mPrefFamilies(aFamiliesArray)
-    {}
-
-    nsTArray<nsRefPtr<gfxFontFamily> >& mPrefFamilies;
-
-    static bool AddFontFamilyEntry(eFontPrefLang aLang, const nsAString& aName, void *aClosure)
-    {
-        PrefFontCallbackData *prefFontData = static_cast<PrefFontCallbackData*>(aClosure);
-
-        gfxFontFamily *family = gfxPlatformFontList::PlatformFontList()->FindFamily(aName);
-        if (family) {
-            prefFontData->mPrefFamilies.AppendElement(family);
-        }
-        return true;
-    }
-};
-
-already_AddRefed<gfxFont>
-gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh)
-{
-    nsRefPtr<gfxFont> font;
-
-    // get the pref font list if it hasn't been set up already
-    uint32_t unicodeRange = FindCharUnicodeRange(aCh);
-    eFontPrefLang charLang = gfxPlatform::GetPlatform()->GetFontPrefLangFor(unicodeRange);
-
-    // if the last pref font was the first family in the pref list, no need to recheck through a list of families
-    if (mLastPrefFont && charLang == mLastPrefLang &&
-        mLastPrefFirstFont && mLastPrefFont->HasCharacter(aCh)) {
-        font = mLastPrefFont;
-        return font.forget();
-    }
-
-    // based on char lang and page lang, set up list of pref lang fonts to check
-    eFontPrefLang prefLangs[kMaxLenPrefLangList];
-    uint32_t i, numLangs = 0;
-
-    gfxPlatform::GetPlatform()->GetLangPrefs(prefLangs, numLangs, charLang, mPageLang);
-
-    for (i = 0; i < numLangs; i++) {
-        nsAutoTArray<nsRefPtr<gfxFontFamily>, 5> families;
-        eFontPrefLang currentLang = prefLangs[i];
-
-        gfxPlatformFontList *fontList = gfxPlatformFontList::PlatformFontList();
-
-        // get the pref families for a single pref lang
-        if (!fontList->GetPrefFontFamilyEntries(currentLang, &families)) {
-            eFontPrefLang prefLangsToSearch[1] = { currentLang };
-            PrefFontCallbackData prefFontData(families);
-            gfxPlatform::ForEachPrefFont(prefLangsToSearch, 1, PrefFontCallbackData::AddFontFamilyEntry,
-                                           &prefFontData);
-            fontList->SetPrefFontFamilyEntries(currentLang, families);
-        }
-
-        // find the first pref font that includes the character
-        uint32_t  j, numPrefs;
-        numPrefs = families.Length();
-        for (j = 0; j < numPrefs; j++) {
-            // look up the appropriate face
-            gfxFontFamily *family = families[j];
-            if (!family) continue;
-
-            // if a pref font is used, it's likely to be used again in the same text run.
-            // the style doesn't change so the face lookup can be cached rather than calling
-            // FindOrMakeFont repeatedly.  speeds up FindFontForChar lookup times for subsequent
-            // pref font lookups
-            if (family == mLastPrefFamily && mLastPrefFont->HasCharacter(aCh)) {
-                font = mLastPrefFont;
-                return font.forget();
-            }
-
-            bool needsBold;
-            gfxFontEntry *fe = family->FindFontForStyle(mStyle, needsBold);
-            // if ch in cmap, create and return a gfxFont
-            if (fe && fe->TestCharacterMap(aCh)) {
-                nsRefPtr<gfxFont> prefFont = fe->FindOrMakeFont(&mStyle, needsBold);
-                if (!prefFont) continue;
-                mLastPrefFamily = family;
-                mLastPrefFont = prefFont;
-                mLastPrefLang = charLang;
-                mLastPrefFirstFont = (i == 0 && j == 0);
-                return prefFont.forget();
-            }
-
-        }
-    }
-
-    return nullptr;
-}
-
-already_AddRefed<gfxFont>
-gfxFontGroup::WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript)
-{
-    gfxFontEntry *fe = 
-        gfxPlatformFontList::PlatformFontList()->
-            SystemFindFontForChar(aCh, aRunScript, &mStyle);
-    if (fe) {
-        bool wantBold = mStyle.ComputeWeight() >= 6;
-        nsRefPtr<gfxFont> font =
-            fe->FindOrMakeFont(&mStyle, wantBold && !fe->IsBold());
-        return font.forget();
-    }
-
-    return nullptr;
-}
-
-/*static*/ void
-gfxFontGroup::Shutdown()
-{
-    NS_IF_RELEASE(gLangService);
-}
-
-nsILanguageAtomService* gfxFontGroup::gLangService = nullptr;
-
 
 #define DEFAULT_PIXEL_FONT_SIZE 16.0f
 
 /*static*/ uint32_t
 gfxFontStyle::ParseFontLanguageOverride(const nsString& aLangTag)
 {
   if (!aLangTag.Length() || aLangTag.Length() > 4) {
     return NO_FONT_LANGUAGE_OVERRIDE;
@@ -6432,1568 +3390,8 @@ gfxFontStyle::AdjustForSubSuperscript(in
                           NS_FONT_SUB_SUPER_SMALL_SIZE);
         size *= (1.0 - t) * NS_FONT_SUB_SUPER_SIZE_RATIO_SMALL +
                     t * NS_FONT_SUB_SUPER_SIZE_RATIO_LARGE;
     }
 
     // clear the variant field
     variantSubSuper = NS_FONT_VARIANT_POSITION_NORMAL;
 }
-
-void
-gfxShapedText::SetupClusterBoundaries(uint32_t         aOffset,
-                                      const char16_t *aString,
-                                      uint32_t         aLength)
-{
-    CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
-
-    gfxTextRun::CompressedGlyph extendCluster;
-    extendCluster.SetComplex(false, true, 0);
-
-    ClusterIterator iter(aString, aLength);
-
-    // the ClusterIterator won't be able to tell us if the string
-    // _begins_ with a cluster-extender, so we handle that here
-    if (aLength && IsClusterExtender(*aString)) {
-        *glyphs = extendCluster;
-    }
-
-    while (!iter.AtEnd()) {
-        if (*iter == char16_t(' ')) {
-            glyphs->SetIsSpace();
-        }
-        // advance iter to the next cluster-start (or end of text)
-        iter.Next();
-        // step past the first char of the cluster
-        aString++;
-        glyphs++;
-        // mark all the rest as cluster-continuations
-        while (aString < iter) {
-            *glyphs = extendCluster;
-            if (NS_IS_LOW_SURROGATE(*aString)) {
-                glyphs->SetIsLowSurrogate();
-            }
-            glyphs++;
-            aString++;
-        }
-    }
-}
-
-void
-gfxShapedText::SetupClusterBoundaries(uint32_t       aOffset,
-                                      const uint8_t *aString,
-                                      uint32_t       aLength)
-{
-    CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
-    const uint8_t *limit = aString + aLength;
-
-    while (aString < limit) {
-        if (*aString == uint8_t(' ')) {
-            glyphs->SetIsSpace();
-        }
-        aString++;
-        glyphs++;
-    }
-}
-
-gfxShapedText::DetailedGlyph *
-gfxShapedText::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
-{
-    NS_ASSERTION(aIndex < GetLength(), "Index out of range");
-
-    if (!mDetailedGlyphs) {
-        mDetailedGlyphs = new DetailedGlyphStore();
-    }
-
-    return mDetailedGlyphs->Allocate(aIndex, aCount);
-}
-
-void
-gfxShapedText::SetGlyphs(uint32_t aIndex, CompressedGlyph aGlyph,
-                         const DetailedGlyph *aGlyphs)
-{
-    NS_ASSERTION(!aGlyph.IsSimpleGlyph(), "Simple glyphs not handled here");
-    NS_ASSERTION(aIndex > 0 || aGlyph.IsLigatureGroupStart(),
-                 "First character can't be a ligature continuation!");
-
-    uint32_t glyphCount = aGlyph.GetGlyphCount();
-    if (glyphCount > 0) {
-        DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, glyphCount);
-        memcpy(details, aGlyphs, sizeof(DetailedGlyph)*glyphCount);
-    }
-    GetCharacterGlyphs()[aIndex] = aGlyph;
-}
-
-#define ZWNJ 0x200C
-#define ZWJ  0x200D
-// U+061C ARABIC LETTER MARK is expected to be added to XIDMOD_DEFAULT_IGNORABLE
-// in a future Unicode update. Add it manually for now
-#define ALM  0x061C
-static inline bool
-IsDefaultIgnorable(uint32_t aChar)
-{
-    return GetIdentifierModification(aChar) == XIDMOD_DEFAULT_IGNORABLE ||
-           aChar == ZWNJ || aChar == ZWJ || aChar == ALM;
-}
-
-void
-gfxShapedText::SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont)
-{
-    uint8_t category = GetGeneralCategory(aChar);
-    if (category >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
-        category <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
-    {
-        GetCharacterGlyphs()[aIndex].SetComplex(false, true, 0);
-    }
-
-    DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
-
-    details->mGlyphID = aChar;
-    if (IsDefaultIgnorable(aChar)) {
-        // Setting advance width to zero will prevent drawing the hexbox
-        details->mAdvance = 0;
-    } else {
-        gfxFloat width =
-            std::max(aFont->GetMetrics().aveCharWidth,
-                     gfxFontMissingGlyphs::GetDesiredMinWidth(aChar,
-                         mAppUnitsPerDevUnit));
-        details->mAdvance = uint32_t(width * mAppUnitsPerDevUnit);
-    }
-    details->mXOffset = 0;
-    details->mYOffset = 0;
-    GetCharacterGlyphs()[aIndex].SetMissing(1);
-}
-
-bool
-gfxShapedText::FilterIfIgnorable(uint32_t aIndex, uint32_t aCh)
-{
-    if (IsDefaultIgnorable(aCh)) {
-        DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
-        details->mGlyphID = aCh;
-        details->mAdvance = 0;
-        details->mXOffset = 0;
-        details->mYOffset = 0;
-        GetCharacterGlyphs()[aIndex].SetMissing(1);
-        return true;
-    }
-    return false;
-}
-
-void
-gfxShapedText::AdjustAdvancesForSyntheticBold(float aSynBoldOffset,
-                                              uint32_t aOffset,
-                                              uint32_t aLength)
-{
-    uint32_t synAppUnitOffset = aSynBoldOffset * mAppUnitsPerDevUnit;
-    CompressedGlyph *charGlyphs = GetCharacterGlyphs();
-    for (uint32_t i = aOffset; i < aOffset + aLength; ++i) {
-         CompressedGlyph *glyphData = charGlyphs + i;
-         if (glyphData->IsSimpleGlyph()) {
-             // simple glyphs ==> just add the advance
-             int32_t advance = glyphData->GetSimpleAdvance() + synAppUnitOffset;
-             if (CompressedGlyph::IsSimpleAdvance(advance)) {
-                 glyphData->SetSimpleGlyph(advance, glyphData->GetSimpleGlyph());
-             } else {
-                 // rare case, tested by making this the default
-                 uint32_t glyphIndex = glyphData->GetSimpleGlyph();
-                 glyphData->SetComplex(true, true, 1);
-                 DetailedGlyph detail = {glyphIndex, advance, 0, 0};
-                 SetGlyphs(i, *glyphData, &detail);
-             }
-         } else {
-             // complex glyphs ==> add offset at cluster/ligature boundaries
-             uint32_t detailedLength = glyphData->GetGlyphCount();
-             if (detailedLength) {
-                 DetailedGlyph *details = GetDetailedGlyphs(i);
-                 if (!details) {
-                     continue;
-                 }
-                 if (IsRightToLeft()) {
-                     details[0].mAdvance += synAppUnitOffset;
-                 } else {
-                     details[detailedLength - 1].mAdvance += synAppUnitOffset;
-                 }
-             }
-         }
-    }
-}
-
-bool
-gfxTextRun::GlyphRunIterator::NextRun()  {
-    if (mNextIndex >= mTextRun->mGlyphRuns.Length())
-        return false;
-    mGlyphRun = &mTextRun->mGlyphRuns[mNextIndex];
-    if (mGlyphRun->mCharacterOffset >= mEndOffset)
-        return false;
-
-    mStringStart = std::max(mStartOffset, mGlyphRun->mCharacterOffset);
-    uint32_t last = mNextIndex + 1 < mTextRun->mGlyphRuns.Length()
-        ? mTextRun->mGlyphRuns[mNextIndex + 1].mCharacterOffset : mTextRun->GetLength();
-    mStringEnd = std::min(mEndOffset, last);
-
-    ++mNextIndex;
-    return true;
-}
-
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-static void
-AccountStorageForTextRun(gfxTextRun *aTextRun, int32_t aSign)
-{
-    // Ignores detailed glyphs... we don't know when those have been constructed
-    // Also ignores gfxSkipChars dynamic storage (which won't be anything
-    // for preformatted text)
-    // Also ignores GlyphRun array, again because it hasn't been constructed
-    // by the time this gets called. If there's only one glyphrun that's stored
-    // directly in the textrun anyway so no additional overhead.
-    uint32_t length = aTextRun->GetLength();
-    int32_t bytes = length * sizeof(gfxTextRun::CompressedGlyph);
-    bytes += sizeof(gfxTextRun);
-    gTextRunStorage += bytes*aSign;
-    gTextRunStorageHighWaterMark = std::max(gTextRunStorageHighWaterMark, gTextRunStorage);
-}
-#endif
-
-// Helper for textRun creation to preallocate storage for glyph records;
-// this function returns a pointer to the newly-allocated glyph storage.
-// Returns nullptr if allocation fails.
-void *
-gfxTextRun::AllocateStorageForTextRun(size_t aSize, uint32_t aLength)
-{
-    // Allocate the storage we need, returning nullptr on failure rather than
-    // throwing an exception (because web content can create huge runs).
-    void *storage = moz_malloc(aSize + aLength * sizeof(CompressedGlyph));
-    if (!storage) {
-        NS_WARNING("failed to allocate storage for text run!");
-        return nullptr;
-    }
-
-    // Initialize the glyph storage (beyond aSize) to zero
-    memset(reinterpret_cast<char*>(storage) + aSize, 0,
-           aLength * sizeof(CompressedGlyph));
-
-    return storage;
-}
-
-gfxTextRun *
-gfxTextRun::Create(const gfxTextRunFactory::Parameters *aParams,
-                   uint32_t aLength, gfxFontGroup *aFontGroup, uint32_t aFlags)
-{
-    void *storage = AllocateStorageForTextRun(sizeof(gfxTextRun), aLength);
-    if (!storage) {
-        return nullptr;
-    }
-
-    return new (storage) gfxTextRun(aParams, aLength, aFontGroup, aFlags);
-}
-
-gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams,
-                       uint32_t aLength, gfxFontGroup *aFontGroup, uint32_t aFlags)
-    : gfxShapedText(aLength, aFlags, aParams->mAppUnitsPerDevUnit)
-    , mUserData(aParams->mUserData)
-    , mFontGroup(aFontGroup)
-    , mReleasedFontGroup(false)
-    , mShapingState(eShapingState_Normal)
-{
-    NS_ASSERTION(mAppUnitsPerDevUnit > 0, "Invalid app unit scale");
-    MOZ_COUNT_CTOR(gfxTextRun);
-    NS_ADDREF(mFontGroup);
-
-#ifndef RELEASE_BUILD
-    gfxTextPerfMetrics *tp = aFontGroup->GetTextPerfMetrics();
-    if (tp) {
-        tp->current.textrunConst++;
-    }
-#endif
-
-    mCharacterGlyphs = reinterpret_cast<CompressedGlyph*>(this + 1);
-
-    if (aParams->mSkipChars) {
-        mSkipChars.TakeFrom(aParams->mSkipChars);
-    }
-
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-    AccountStorageForTextRun(this, 1);
-#endif
-
-    mSkipDrawing = mFontGroup->ShouldSkipDrawing();
-}
-
-gfxTextRun::~gfxTextRun()
-{
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-    AccountStorageForTextRun(this, -1);
-#endif
-#ifdef DEBUG
-    // Make it easy to detect a dead text run
-    mFlags = 0xFFFFFFFF;
-#endif
-
-    // The cached ellipsis textrun (if any) in a fontgroup will have already
-    // been told to release its reference to the group, so we mustn't do that
-    // again here.
-    if (!mReleasedFontGroup) {
-#ifndef RELEASE_BUILD
-        gfxTextPerfMetrics *tp = mFontGroup->GetTextPerfMetrics();
-        if (tp) {
-            tp->current.textrunDestr++;
-        }
-#endif
-        NS_RELEASE(mFontGroup);
-    }
-
-    MOZ_COUNT_DTOR(gfxTextRun);
-}
-
-void
-gfxTextRun::ReleaseFontGroup()
-{
-    NS_ASSERTION(!mReleasedFontGroup, "doubly released!");
-    NS_RELEASE(mFontGroup);
-    mReleasedFontGroup = true;
-}
-
-bool
-gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
-                                   uint8_t *aBreakBefore,
-                                   gfxContext *aRefContext)
-{
-    NS_ASSERTION(aStart + aLength <= GetLength(), "Overflow");
-
-    uint32_t changed = 0;
-    uint32_t i;
-    CompressedGlyph *charGlyphs = mCharacterGlyphs + aStart;
-    for (i = 0; i < aLength; ++i) {
-        uint8_t canBreak = aBreakBefore[i];
-        if (canBreak && !charGlyphs[i].IsClusterStart()) {
-            // This can happen ... there is no guarantee that our linebreaking rules
-            // align with the platform's idea of what constitutes a cluster.
-            NS_WARNING("Break suggested inside cluster!");
-            canBreak = CompressedGlyph::FLAG_BREAK_TYPE_NONE;
-        }
-        changed |= charGlyphs[i].SetCanBreakBefore(canBreak);
-    }
-    return changed != 0;
-}
-
-gfxTextRun::LigatureData
-gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
-                                PropertyProvider *aProvider)
-{
-    NS_ASSERTION(aPartStart < aPartEnd, "Computing ligature data for empty range");
-    NS_ASSERTION(aPartEnd <= GetLength(), "Character length overflow");
-  
-    LigatureData result;
-    CompressedGlyph *charGlyphs = mCharacterGlyphs;
-
-    uint32_t i;
-    for (i = aPartStart; !charGlyphs[i].IsLigatureGroupStart(); --i) {
-        NS_ASSERTION(i > 0, "Ligature at the start of the run??");
-    }
-    result.mLigatureStart = i;
-    for (i = aPartStart + 1; i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
-    }
-    result.mLigatureEnd = i;
-
-    int32_t ligatureWidth =
-        GetAdvanceForGlyphs(result.mLigatureStart, result.mLigatureEnd);
-    // Count the number of started clusters we have seen
-    uint32_t totalClusterCount = 0;
-    uint32_t partClusterIndex = 0;
-    uint32_t partClusterCount = 0;
-    for (i = result.mLigatureStart; i < result.mLigatureEnd; ++i) {
-        // Treat the first character of the ligature as the start of a
-        // cluster for our purposes of allocating ligature width to its
-        // characters.
-        if (i == result.mLigatureStart || charGlyphs[i].IsClusterStart()) {
-            ++totalClusterCount;
-            if (i < aPartStart) {
-                ++partClusterIndex;
-            } else if (i < aPartEnd) {
-                ++partClusterCount;
-            }
-        }
-    }
-    NS_ASSERTION(totalClusterCount > 0, "Ligature involving no clusters??");
-    result.mPartAdvance = partClusterIndex * (ligatureWidth / totalClusterCount);
-    result.mPartWidth = partClusterCount * (ligatureWidth / totalClusterCount);
-
-    // Any rounding errors are apportioned to the final part of the ligature,
-    // so that measuring all parts of a ligature and summing them is equal to
-    // the ligature width.
-    if (aPartEnd == result.mLigatureEnd) {
-        gfxFloat allParts = totalClusterCount * (ligatureWidth / totalClusterCount);
-        result.mPartWidth += ligatureWidth - allParts;
-    }
-
-    if (partClusterCount == 0) {
-        // nothing to draw
-        result.mClipBeforePart = result.mClipAfterPart = true;
-    } else {
-        // Determine whether we should clip before or after this part when
-        // drawing its slice of the ligature.
-        // We need to clip before the part if any cluster is drawn before
-        // this part.
-        result.mClipBeforePart = partClusterIndex > 0;
-        // We need to clip after the part if any cluster is drawn after
-        // this part.
-        result.mClipAfterPart = partClusterIndex + partClusterCount < totalClusterCount;
-    }
-
-    if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) {
-        gfxFont::Spacing spacing;
-        if (aPartStart == result.mLigatureStart) {
-            aProvider->GetSpacing(aPartStart, 1, &spacing);
-            result.mPartWidth += spacing.mBefore;
-        }
-        if (aPartEnd == result.mLigatureEnd) {
-            aProvider->GetSpacing(aPartEnd - 1, 1, &spacing);
-            result.mPartWidth += spacing.mAfter;
-        }
-    }
-
-    return result;
-}
-
-gfxFloat
-gfxTextRun::ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd,
-                                        PropertyProvider *aProvider)
-{
-    if (aPartStart >= aPartEnd)
-        return 0;
-    LigatureData data = ComputeLigatureData(aPartStart, aPartEnd, aProvider);
-    return data.mPartWidth;
-}
-
-int32_t
-gfxTextRun::GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd)
-{
-    const CompressedGlyph *glyphData = mCharacterGlyphs + aStart;
-    int32_t advance = 0;
-    uint32_t i;
-    for (i = aStart; i < aEnd; ++i, ++glyphData) {
-        if (glyphData->IsSimpleGlyph()) {
-            advance += glyphData->GetSimpleAdvance();   
-        } else {
-            uint32_t glyphCount = glyphData->GetGlyphCount();
-            if (glyphCount == 0) {
-                continue;
-            }
-            const DetailedGlyph *details = GetDetailedGlyphs(i);
-            if (details) {
-                uint32_t j;
-                for (j = 0; j < glyphCount; ++j, ++details) {
-                    advance += details->mAdvance;
-                }
-            }
-        }
-    }
-    return advance;
-}
-
-static void
-GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
-                   gfxTextRun::PropertyProvider *aProvider,
-                   gfxTextRun::PropertyProvider::Spacing *aSpacing)
-{
-    if (aStart >= aEnd)
-        return;
-
-    aProvider->GetSpacing(aStart, aEnd - aStart, aSpacing);
-
-#ifdef DEBUG
-    // Check to see if we have spacing inside ligatures
-
-    const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
-    uint32_t i;
-
-    for (i = aStart; i < aEnd; ++i) {
-        if (!charGlyphs[i].IsLigatureGroupStart()) {
-            NS_ASSERTION(i == aStart || aSpacing[i - aStart].mBefore == 0,
-                         "Before-spacing inside a ligature!");
-            NS_ASSERTION(i - 1 <= aStart || aSpacing[i - 1 - aStart].mAfter == 0,
-                         "After-spacing inside a ligature!");
-        }
-    }
-#endif
-}
-
-bool
-gfxTextRun::GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd,
-                                    PropertyProvider *aProvider,
-                                    uint32_t aSpacingStart, uint32_t aSpacingEnd,
-                                    nsTArray<PropertyProvider::Spacing> *aSpacing)
-{
-    if (!aProvider || !(mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING))
-        return false;
-    if (!aSpacing->AppendElements(aEnd - aStart))
-        return false;
-    memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing)*(aSpacingStart - aStart));
-    GetAdjustedSpacing(this, aSpacingStart, aSpacingEnd, aProvider,
-                       aSpacing->Elements() + aSpacingStart - aStart);
-    memset(aSpacing->Elements() + aSpacingEnd - aStart, 0, sizeof(gfxFont::Spacing)*(aEnd - aSpacingEnd));
-    return true;
-}
-
-void
-gfxTextRun::ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd)
-{
-    if (*aStart >= *aEnd)
-        return;
-  
-    CompressedGlyph *charGlyphs = mCharacterGlyphs;
-
-    while (*aStart < *aEnd && !charGlyphs[*aStart].IsLigatureGroupStart()) {
-        ++(*aStart);
-    }
-    if (*aEnd < GetLength()) {
-        while (*aEnd > *aStart && !charGlyphs[*aEnd].IsLigatureGroupStart()) {
-            --(*aEnd);
-        }
-    }
-}
-
-void
-gfxTextRun::DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
-                       gfxPoint *aPt, PropertyProvider *aProvider,
-                       uint32_t aSpacingStart, uint32_t aSpacingEnd,
-                       TextRunDrawParams& aParams)
-{
-    nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
-    bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
-        aSpacingStart, aSpacingEnd, &spacingBuffer);
-    aParams.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr;
-    aFont->Draw(this, aStart, aEnd, aPt, aParams);
-}
-
-static void
-ClipPartialLigature(gfxTextRun *aTextRun, gfxFloat *aLeft, gfxFloat *aRight,
-                    gfxFloat aXOrigin, gfxTextRun::LigatureData *aLigature)
-{
-    if (aLigature->mClipBeforePart) {
-        if (aTextRun->IsRightToLeft()) {
-            *aRight = std::min(*aRight, aXOrigin);
-        } else {
-            *aLeft = std::max(*aLeft, aXOrigin);
-        }
-    }
-    if (aLigature->mClipAfterPart) {
-        gfxFloat endEdge = aXOrigin + aTextRun->GetDirection()*aLigature->mPartWidth;
-        if (aTextRun->IsRightToLeft()) {
-            *aLeft = std::max(*aLeft, endEdge);
-        } else {
-            *aRight = std::min(*aRight, endEdge);
-        }
-    }    
-}
-
-void
-gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
-                                gfxPoint *aPt, PropertyProvider *aProvider,
-                                TextRunDrawParams& aParams)
-{
-    if (aStart >= aEnd)
-        return;
-
-    // Draw partial ligature. We hack this by clipping the ligature.
-    LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider);
-    gfxRect clipExtents = aParams.context->GetClipExtents();
-    gfxFloat left = clipExtents.X() * mAppUnitsPerDevUnit;
-    gfxFloat right = clipExtents.XMost() * mAppUnitsPerDevUnit;
-    ClipPartialLigature(this, &left, &right, aPt->x, &data);
-
-    {
-      // Need to preserve the path, otherwise this can break canvas text-on-path;
-      // in general it seems like a good thing, as naive callers probably won't
-      // expect gfxTextRun::Draw to implicitly destroy the current path.
-      gfxContextPathAutoSaveRestore savePath(aParams.context);
-
-      // use division here to ensure that when the rect is aligned on multiples
-      // of mAppUnitsPerDevUnit, we clip to true device unit boundaries.
-      // Also, make sure we snap the rectangle to device pixels.
-      aParams.context->Save();
-      aParams.context->NewPath();
-      aParams.context->Rectangle(gfxRect(left / mAppUnitsPerDevUnit,
-                                         clipExtents.Y(),
-                                         (right - left) / mAppUnitsPerDevUnit,
-                                         clipExtents.Height()), true);
-      aParams.context->Clip();
-    }
-
-    gfxPoint pt(aPt->x - aParams.direction * data.mPartAdvance, aPt->y);
-    DrawGlyphs(aFont, data.mLigatureStart, data.mLigatureEnd, &pt,
-               aProvider, aStart, aEnd, aParams);
-    aParams.context->Restore();
-
-    aPt->x += aParams.direction * data.mPartWidth;
-}
-
-// returns true if a glyph run is using a font with synthetic bolding enabled, false otherwise
-static bool
-HasSyntheticBold(gfxTextRun *aRun, uint32_t aStart, uint32_t aLength)
-{
-    gfxTextRun::GlyphRunIterator iter(aRun, aStart, aLength);
-    while (iter.NextRun()) {
-        gfxFont *font = iter.GetGlyphRun()->mFont;
-        if (font && font->IsSyntheticBold()) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-// returns true if color is non-opaque (i.e. alpha != 1.0) or completely transparent, false otherwise
-// if true, color is set on output
-static bool
-HasNonOpaqueColor(gfxContext *aContext, gfxRGBA& aCurrentColor)
-{
-    if (aContext->GetDeviceColor(aCurrentColor)) {
-        if (aCurrentColor.a < 1.0 && aCurrentColor.a > 0.0) {
-            return true;
-        }
-    }
-        
-    return false;
-}
-
-// helper class for double-buffering drawing with non-opaque color
-struct BufferAlphaColor {
-    explicit BufferAlphaColor(gfxContext *aContext)
-        : mContext(aContext)
-    {
-
-    }
-
-    ~BufferAlphaColor() {}
-
-    void PushSolidColor(const gfxRect& aBounds, const gfxRGBA& aAlphaColor, uint32_t appsPerDevUnit)
-    {
-        mContext->Save();
-        mContext->NewPath();
-        mContext->Rectangle(gfxRect(aBounds.X() / appsPerDevUnit,
-                    aBounds.Y() / appsPerDevUnit,
-                    aBounds.Width() / appsPerDevUnit,
-                    aBounds.Height() / appsPerDevUnit), true);
-        mContext->Clip();
-        mContext->SetColor(gfxRGBA(aAlphaColor.r, aAlphaColor.g, aAlphaColor.b));
-        mContext->PushGroup(gfxContentType::COLOR_ALPHA);
-        mAlpha = aAlphaColor.a;
-    }
-
-    void PopAlpha()
-    {
-        // pop the text, using the color alpha as the opacity
-        mContext->PopGroupToSource();
-        mContext->SetOperator(gfxContext::OPERATOR_OVER);
-        mContext->Paint(mAlpha);
-        mContext->Restore();
-    }
-
-    gfxContext *mContext;
-    gfxFloat mAlpha;
-};
-
-void
-gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
-                 uint32_t aStart, uint32_t aLength,
-                 PropertyProvider *aProvider, gfxFloat *aAdvanceWidth,
-                 gfxTextContextPaint *aContextPaint,
-                 gfxTextRunDrawCallbacks *aCallbacks)
-{
-    NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
-    NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH ||
-                 !(int(aDrawMode) & int(DrawMode::GLYPH_PATH)),
-                 "GLYPH_PATH cannot be used with GLYPH_FILL, GLYPH_STROKE or GLYPH_STROKE_UNDERNEATH");
-    NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH || !aCallbacks,
-                 "callback must not be specified unless using GLYPH_PATH");
-
-    bool skipDrawing = mSkipDrawing;
-    if (aDrawMode == DrawMode::GLYPH_FILL) {
-        gfxRGBA currentColor;
-        if (aContext->GetDeviceColor(currentColor) && currentColor.a == 0) {
-            skipDrawing = true;
-        }
-    }
-
-    gfxFloat direction = GetDirection();
-
-    if (skipDrawing) {
-        // We don't need to draw anything;
-        // but if the caller wants advance width, we need to compute it here
-        if (aAdvanceWidth) {
-            gfxTextRun::Metrics metrics = MeasureText(aStart, aLength,
-                                                      gfxFont::LOOSE_INK_EXTENTS,
-                                                      aContext, aProvider);
-            *aAdvanceWidth = metrics.mAdvanceWidth * direction;
-        }
-
-        // return without drawing
-        return;
-    }
-
-    // Set up parameters that will be constant across all glyph runs we need
-    // to draw, regardless of the font used.
-    TextRunDrawParams params;
-    params.context = aContext;
-    params.devPerApp = 1.0 / double(GetAppUnitsPerDevUnit());
-    params.isRTL = IsRightToLeft();
-    params.direction = direction;
-    params.drawMode = aDrawMode;
-    params.callbacks = aCallbacks;
-    params.runContextPaint = aContextPaint;
-    params.paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs;
-    params.dt = aContext->GetDrawTarget();
-
-    gfxPoint pt = aPt;
-
-    // synthetic bolding draws glyphs twice ==> colors with opacity won't draw
-    // correctly unless first drawn without alpha
-    BufferAlphaColor syntheticBoldBuffer(aContext);
-    gfxRGBA currentColor;
-    bool needToRestore = false;
-
-    if (aDrawMode == DrawMode::GLYPH_FILL &&
-        HasNonOpaqueColor(aContext, currentColor) &&
-        HasSyntheticBold(this, aStart, aLength)) {
-        needToRestore = true;
-        // measure text, use the bounding box
-        gfxTextRun::Metrics metrics = MeasureText(aStart, aLength,
-                                                  gfxFont::LOOSE_INK_EXTENTS,
-                                                  aContext, aProvider);
-        metrics.mBoundingBox.MoveBy(aPt);
-        syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor,
-                                           GetAppUnitsPerDevUnit());
-    }
-
-    GlyphRunIterator iter(this, aStart, aLength);
-    while (iter.NextRun()) {
-        gfxFont *font = iter.GetGlyphRun()->mFont;
-        uint32_t start = iter.GetStringStart();
-        uint32_t end = iter.GetStringEnd();
-        uint32_t ligatureRunStart = start;
-        uint32_t ligatureRunEnd = end;
-        ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
-
-        bool drawPartial = aDrawMode == DrawMode::GLYPH_FILL ||
-                           (aDrawMode == DrawMode::GLYPH_PATH && aCallbacks);
-
-        if (drawPartial) {
-            DrawPartialLigature(font, start, ligatureRunStart, &pt,
-                                aProvider, params);
-        }
-
-        DrawGlyphs(font, ligatureRunStart, ligatureRunEnd, &pt,
-                   aProvider, ligatureRunStart, ligatureRunEnd, params);
-
-        if (drawPartial) {
-            DrawPartialLigature(font, ligatureRunEnd, end, &pt,
-                                aProvider, params);
-        }
-    }
-
-    // composite result when synthetic bolding used
-    if (needToRestore) {
-        syntheticBoldBuffer.PopAlpha();
-    }
-
-    if (aAdvanceWidth) {
-        *aAdvanceWidth = (pt.x - aPt.x)*direction;
-    }
-}
-
-void
-gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont,
-                                    uint32_t aStart, uint32_t aEnd,
-                                    gfxFont::BoundingBoxType aBoundingBoxType,
-                                    gfxContext *aRefContext,
-                                    PropertyProvider *aProvider,
-                                    uint32_t aSpacingStart, uint32_t aSpacingEnd,
-                                    Metrics *aMetrics)
-{
-    nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
-    bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
-        aSpacingStart, aSpacingEnd, &spacingBuffer);
-    Metrics metrics = aFont->Measure(this, aStart, aEnd, aBoundingBoxType, aRefContext,
-                                     haveSpacing ? spacingBuffer.Elements() : nullptr);
-    aMetrics->CombineWith(metrics, IsRightToLeft());
-}
-
-void
-gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
-    uint32_t aStart, uint32_t aEnd,
-    gfxFont::BoundingBoxType aBoundingBoxType, gfxContext *aRefContext,
-    PropertyProvider *aProvider, Metrics *aMetrics)
-{
-    if (aStart >= aEnd)
-        return;
-
-    // Measure partial ligature. We hack this by clipping the metrics in the
-    // same way we clip the drawing.
-    LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider);
-
-    // First measure the complete ligature
-    Metrics metrics;
-    AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd,
-                            aBoundingBoxType, aRefContext,
-                            aProvider, aStart, aEnd, &metrics);
-
-    // Clip the bounding box to the ligature part
-    gfxFloat bboxLeft = metrics.mBoundingBox.X();
-    gfxFloat bboxRight = metrics.mBoundingBox.XMost();
-    // Where we are going to start "drawing" relative to our left baseline origin
-    gfxFloat origin = IsRightToLeft() ? metrics.mAdvanceWidth - data.mPartAdvance : 0;
-    ClipPartialLigature(this, &bboxLeft, &bboxRight, origin, &data);
-    metrics.mBoundingBox.x = bboxLeft;
-    metrics.mBoundingBox.width = bboxRight - bboxLeft;
-
-    // mBoundingBox is now relative to the left baseline origin for the entire
-    // ligature. Shift it left.
-    metrics.mBoundingBox.x -=
-        IsRightToLeft() ? metrics.mAdvanceWidth - (data.mPartAdvance + data.mPartWidth)
-            : data.mPartAdvance;    
-    metrics.mAdvanceWidth = data.mPartWidth;
-
-    aMetrics->CombineWith(metrics, IsRightToLeft());
-}
-
-gfxTextRun::Metrics
-gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength,
-                        gfxFont::BoundingBoxType aBoundingBoxType,
-                        gfxContext *aRefContext,
-                        PropertyProvider *aProvider)
-{
-    NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
-
-    Metrics accumulatedMetrics;
-    GlyphRunIterator iter(this, aStart, aLength);
-    while (iter.NextRun()) {
-        gfxFont *font = iter.GetGlyphRun()->mFont;
-        uint32_t start = iter.GetStringStart();
-        uint32_t end = iter.GetStringEnd();
-        uint32_t ligatureRunStart = start;
-        uint32_t ligatureRunEnd = end;
-        ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
-
-        AccumulatePartialLigatureMetrics(font, start, ligatureRunStart,
-            aBoundingBoxType, aRefContext, aProvider, &accumulatedMetrics);
-
-        // XXX This sucks. We have to get glyph extents just so we can detect
-        // glyphs outside the font box, even when aBoundingBoxType is LOOSE,
-        // even though in almost all cases we could get correct results just
-        // by getting some ascent/descent from the font and using our stored
-        // advance widths.
-        AccumulateMetricsForRun(font,
-            ligatureRunStart, ligatureRunEnd, aBoundingBoxType,
-            aRefContext, aProvider, ligatureRunStart, ligatureRunEnd,
-            &accumulatedMetrics);
-
-        AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end,
-            aBoundingBoxType, aRefContext, aProvider, &accumulatedMetrics);
-    }
-
-    return accumulatedMetrics;
-}
-
-#define MEASUREMENT_BUFFER_SIZE 100
-
-uint32_t
-gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
-                                bool aLineBreakBefore, gfxFloat aWidth,
-                                PropertyProvider *aProvider,
-                                bool aSuppressInitialBreak,
-                                gfxFloat *aTrimWhitespace,
-                                Metrics *aMetrics,
-                                gfxFont::BoundingBoxType aBoundingBoxType,
-                                gfxContext *aRefContext,
-                                bool *aUsedHyphenation,
-                                uint32_t *aLastBreak,
-                                bool aCanWordWrap,
-                                gfxBreakPriority *aBreakPriority)
-{
-    aMaxLength = std::min(aMaxLength, GetLength() - aStart);
-
-    NS_ASSERTION(aStart + aMaxLength <= GetLength(), "Substring out of range");
-
-    uint32_t bufferStart = aStart;
-    uint32_t bufferLength = std::min<uint32_t>(aMaxLength, MEASUREMENT_BUFFER_SIZE);
-    PropertyProvider::Spacing spacingBuffer[MEASUREMENT_BUFFER_SIZE];
-    bool haveSpacing = aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING) != 0;
-    if (haveSpacing) {
-        GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
-                           spacingBuffer);
-    }
-    bool hyphenBuffer[MEASUREMENT_BUFFER_SIZE];
-    bool haveHyphenation = aProvider &&
-        (aProvider->GetHyphensOption() == NS_STYLE_HYPHENS_AUTO ||
-         (aProvider->GetHyphensOption() == NS_STYLE_HYPHENS_MANUAL &&
-          (mFlags & gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS) != 0));
-    if (haveHyphenation) {
-        aProvider->GetHyphenationBreaks(bufferStart, bufferLength,
-                                        hyphenBuffer);
-    }
-
-    gfxFloat width = 0;
-    gfxFloat advance = 0;
-    // The number of space characters that can be trimmed
-    uint32_t trimmableChars = 0;
-    // The amount of space removed by ignoring trimmableChars
-    gfxFloat trimmableAdvance = 0;
-    int32_t lastBreak = -1;
-    int32_t lastBreakTrimmableChars = -1;
-    gfxFloat lastBreakTrimmableAdvance = -1;
-    bool aborted = false;
-    uint32_t end = aStart + aMaxLength;
-    bool lastBreakUsedHyphenation = false;
-
-    uint32_t ligatureRunStart = aStart;
-    uint32_t ligatureRunEnd = end;
-    ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
-
-    uint32_t i;
-    for (i = aStart; i < end; ++i) {
-        if (i >= bufferStart + bufferLength) {
-            // Fetch more spacing and hyphenation data
-            bufferStart = i;
-            bufferLength = std::min(aStart + aMaxLength, i + MEASUREMENT_BUFFER_SIZE) - i;
-            if (haveSpacing) {
-                GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
-                                   spacingBuffer);
-            }
-            if (haveHyphenation) {
-                aProvider->GetHyphenationBreaks(bufferStart, bufferLength,
-                                                hyphenBuffer);
-            }
-        }
-
-        // There can't be a word-wrap break opportunity at the beginning of the
-        // line: if the width is too small for even one character to fit, it 
-        // could be the first and last break opportunity on the line, and that
-        // would trigger an infinite loop.
-        if (!aSuppressInitialBreak || i > aStart) {
-            bool atNaturalBreak = mCharacterGlyphs[i].CanBreakBefore() == 1;
-            bool atHyphenationBreak =
-                !atNaturalBreak && haveHyphenation && hyphenBuffer[i - bufferStart];
-            bool atBreak = atNaturalBreak || atHyphenationBreak;
-            bool wordWrapping =
-                aCanWordWrap && mCharacterGlyphs[i].IsClusterStart() &&
-                *aBreakPriority <= gfxBreakPriority::eWordWrapBreak;
-
-            if (atBreak || wordWrapping) {
-                gfxFloat hyphenatedAdvance = advance;
-                if (atHyphenationBreak) {
-                    hyphenatedAdvance += aProvider->GetHyphenWidth();
-                }
-            
-                if (lastBreak < 0 || width + hyphenatedAdvance - trimmableAdvance <= aWidth) {
-                    // We can break here.
-                    lastBreak = i;
-                    lastBreakTrimmableChars = trimmableChars;
-                    lastBreakTrimmableAdvance = trimmableAdvance;
-                    lastBreakUsedHyphenation = atHyphenationBreak;
-                    *aBreakPriority = atBreak ? gfxBreakPriority::eNormalBreak
-                                              : gfxBreakPriority::eWordWrapBreak;
-                }
-
-                width += advance;
-                advance = 0;
-                if (width - trimmableAdvance > aWidth) {
-                    // No more text fits. Abort
-                    aborted = true;
-                    break;
-                }
-            }
-        }
-        
-        gfxFloat charAdvance;
-        if (i >= ligatureRunStart && i < ligatureRunEnd) {
-            charAdvance = GetAdvanceForGlyphs(i, i + 1);
-            if (haveSpacing) {
-                PropertyProvider::Spacing *space = &spacingBuffer[i - bufferStart];
-                charAdvance += space->mBefore + space->mAfter;
-            }
-        } else {
-            charAdvance = ComputePartialLigatureWidth(i, i + 1, aProvider);
-        }
-        
-        advance += charAdvance;
-        if (aTrimWhitespace) {
-            if (mCharacterGlyphs[i].CharIsSpace()) {
-                ++trimmableChars;
-                trimmableAdvance += charAdvance;
-            } else {
-                trimmableAdvance = 0;
-                trimmableChars = 0;
-            }
-        }
-    }
-
-    if (!aborted) {
-        width += advance;
-    }
-
-    // There are three possibilities:
-    // 1) all the text fit (width <= aWidth)
-    // 2) some of the text fit up to a break opportunity (width > aWidth && lastBreak >= 0)
-    // 3) none of the text fits before a break opportunity (width > aWidth && lastBreak < 0)
-    uint32_t charsFit;
-    bool usedHyphenation = false;
-    if (width - trimmableAdvance <= aWidth) {
-        charsFit = aMaxLength;
-    } else if (lastBreak >= 0) {
-        charsFit = lastBreak - aStart;
-        trimmableChars = lastBreakTrimmableChars;
-        trimmableAdvance = lastBreakTrimmableAdvance;
-        usedHyphenation = lastBreakUsedHyphenation;
-    } else {
-        charsFit = aMaxLength;
-    }
-
-    if (aMetrics) {
-        *aMetrics = MeasureText(aStart, charsFit - trimmableChars,
-            aBoundingBoxType, aRefContext, aProvider);
-    }
-    if (aTrimWhitespace) {
-        *aTrimWhitespace = trimmableAdvance;
-    }
-    if (aUsedHyphenation) {
-        *aUsedHyphenation = usedHyphenation;
-    }
-    if (aLastBreak && charsFit == aMaxLength) {
-        if (lastBreak < 0) {
-            *aLastBreak = UINT32_MAX;
-        } else {
-            *aLastBreak = lastBreak - aStart;
-        }
-    }
-
-    return charsFit;
-}
-
-gfxFloat
-gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
-                            PropertyProvider *aProvider)
-{
-    NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
-
-    uint32_t ligatureRunStart = aStart;
-    uint32_t ligatureRunEnd = aStart + aLength;
-    ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
-
-    gfxFloat result = ComputePartialLigatureWidth(aStart, ligatureRunStart, aProvider) +
-                      ComputePartialLigatureWidth(ligatureRunEnd, aStart + aLength, aProvider);
-
-    // Account for all remaining spacing here. This is more efficient than
-    // processing it along with the glyphs.
-    if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) {
-        uint32_t i;
-        nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
-        if (spacingBuffer.AppendElements(aLength)) {
-            GetAdjustedSpacing(this, ligatureRunStart, ligatureRunEnd, aProvider,
-                               spacingBuffer.Elements());
-            for (i = 0; i < ligatureRunEnd - ligatureRunStart; ++i) {
-                PropertyProvider::Spacing *space = &spacingBuffer[i];
-                result += space->mBefore + space->mAfter;
-            }
-        }
-    }
-
-    return result + GetAdvanceForGlyphs(ligatureRunStart, ligatureRunEnd);
-}
-
-bool
-gfxTextRun::SetLineBreaks(uint32_t aStart, uint32_t aLength,
-                          bool aLineBreakBefore, bool aLineBreakAfter,
-                          gfxFloat *aAdvanceWidthDelta,
-                          gfxContext *aRefContext)
-{
-    // Do nothing because our shaping does not currently take linebreaks into
-    // account. There is no change in advance width.
-    if (aAdvanceWidthDelta) {
-        *aAdvanceWidthDelta = 0;
-    }
-    return false;
-}
-
-uint32_t
-gfxTextRun::FindFirstGlyphRunContaining(uint32_t aOffset)
-{
-    NS_ASSERTION(aOffset <= GetLength(), "Bad offset looking for glyphrun");
-    NS_ASSERTION(GetLength() == 0 || mGlyphRuns.Length() > 0,
-                 "non-empty text but no glyph runs present!");
-    if (aOffset == GetLength())
-        return mGlyphRuns.Length();
-    uint32_t start = 0;
-    uint32_t end = mGlyphRuns.Length();
-    while (end - start > 1) {
-        uint32_t mid = (start + end)/2;
-        if (mGlyphRuns[mid].mCharacterOffset <= aOffset) {
-            start = mid;
-        } else {
-            end = mid;
-        }
-    }
-    NS_ASSERTION(mGlyphRuns[start].mCharacterOffset <= aOffset,
-                 "Hmm, something went wrong, aOffset should have been found");
-    return start;
-}
-
-nsresult
-gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType,
-                        uint32_t aUTF16Offset, bool aForceNewRun)
-{
-    NS_ASSERTION(aFont, "adding glyph run for null font!");
-    if (!aFont) {
-        return NS_OK;
-    }    
-    uint32_t numGlyphRuns = mGlyphRuns.Length();
-    if (!aForceNewRun && numGlyphRuns > 0) {
-        GlyphRun *lastGlyphRun = &mGlyphRuns[numGlyphRuns - 1];
-
-        NS_ASSERTION(lastGlyphRun->mCharacterOffset <= aUTF16Offset,
-                     "Glyph runs out of order (and run not forced)");
-
-        // Don't append a run if the font is already the one we want
-        if (lastGlyphRun->mFont == aFont &&
-            lastGlyphRun->mMatchType == aMatchType)
-        {
-            return NS_OK;
-        }
-
-        // If the offset has not changed, avoid leaving a zero-length run
-        // by overwriting the last entry instead of appending...
-        if (lastGlyphRun->mCharacterOffset == aUTF16Offset) {
-
-            // ...except that if the run before the last entry had the same
-            // font as the new one wants, merge with it instead of creating
-            // adjacent runs with the same font
-            if (numGlyphRuns > 1 &&
-                mGlyphRuns[numGlyphRuns - 2].mFont == aFont &&
-                mGlyphRuns[numGlyphRuns - 2].mMatchType == aMatchType)
-            {
-                mGlyphRuns.TruncateLength(numGlyphRuns - 1);
-                return NS_OK;
-            }
-
-            lastGlyphRun->mFont = aFont;
-            lastGlyphRun->mMatchType = aMatchType;
-            return NS_OK;
-        }
-    }
-
-    NS_ASSERTION(aForceNewRun || numGlyphRuns > 0 || aUTF16Offset == 0,
-                 "First run doesn't cover the first character (and run not forced)?");
-
-    GlyphRun *glyphRun = mGlyphRuns.AppendElement();
-    if (!glyphRun)
-        return NS_ERROR_OUT_OF_MEMORY;
-    glyphRun->mFont = aFont;
-    glyphRun->mCharacterOffset = aUTF16Offset;
-    glyphRun->mMatchType = aMatchType;
-    return NS_OK;
-}
-
-void
-gfxTextRun::SortGlyphRuns()
-{
-    if (mGlyphRuns.Length() <= 1)
-        return;
-
-    nsTArray<GlyphRun> runs(mGlyphRuns);
-    GlyphRunOffsetComparator comp;
-    runs.Sort(comp);
-
-    // Now copy back, coalescing adjacent glyph runs that have the same font
-    mGlyphRuns.Clear();
-    uint32_t i, count = runs.Length();
-    for (i = 0; i < count; ++i) {
-        // a GlyphRun with the same font as the previous GlyphRun can just
-        // be skipped; the last GlyphRun will cover its character range.
-        if (i == 0 || runs[i].mFont != runs[i - 1].mFont) {
-            mGlyphRuns.AppendElement(runs[i]);
-            // If two fonts have the same character offset, Sort() will have
-            // randomized the order.
-            NS_ASSERTION(i == 0 ||
-                         runs[i].mCharacterOffset !=
-                         runs[i - 1].mCharacterOffset,
-                         "Two fonts for the same run, glyph indices may not match the font");
-        }
-    }
-}
-
-// Note that SanitizeGlyphRuns scans all glyph runs in the textrun;
-// therefore we only call it once, at the end of textrun construction,
-// NOT incrementally as each glyph run is added (bug 680402).
-void
-gfxTextRun::SanitizeGlyphRuns()
-{
-    if (mGlyphRuns.Length() <= 1)
-        return;
-
-    // If any glyph run starts with ligature-continuation characters, we need to advance it
-    // to the first "real" character to avoid drawing partial ligature glyphs from wrong font
-    // (seen with U+FEFF in reftest 474417-1, as Core Text eliminates the glyph, which makes
-    // it appear as if a ligature has been formed)
-    int32_t i, lastRunIndex = mGlyphRuns.Length() - 1;
-    const CompressedGlyph *charGlyphs = mCharacterGlyphs;
-    for (i = lastRunIndex; i >= 0; --i) {
-        GlyphRun& run = mGlyphRuns[i];
-        while (charGlyphs[run.mCharacterOffset].IsLigatureContinuation() &&
-               run.mCharacterOffset < GetLength()) {
-            run.mCharacterOffset++;
-        }
-        // if the run has become empty, eliminate it
-        if ((i < lastRunIndex &&
-             run.mCharacterOffset >= mGlyphRuns[i+1].mCharacterOffset) ||
-            (i == lastRunIndex && run.mCharacterOffset == GetLength())) {
-            mGlyphRuns.RemoveElementAt(i);
-            --lastRunIndex;
-        }
-    }
-}
-
-uint32_t
-gfxTextRun::CountMissingGlyphs()
-{
-    uint32_t i;
-    uint32_t count = 0;
-    for (i = 0; i < GetLength(); ++i) {
-        if (mCharacterGlyphs[i].IsMissing()) {
-            ++count;
-        }
-    }
-    return count;
-}
-
-void
-gfxTextRun::CopyGlyphDataFrom(gfxShapedWord *aShapedWord, uint32_t aOffset)
-{
-    uint32_t wordLen = aShapedWord->GetLength();
-    NS_ASSERTION(aOffset + wordLen <= GetLength(),
-                 "word overruns end of textrun!");
-
-    CompressedGlyph *charGlyphs = GetCharacterGlyphs();
-    const CompressedGlyph *wordGlyphs = aShapedWord->GetCharacterGlyphs();
-    if (aShapedWord->HasDetailedGlyphs()) {
-        for (uint32_t i = 0; i < wordLen; ++i, ++aOffset) {
-            const CompressedGlyph& g = wordGlyphs[i];
-            if (g.IsSimpleGlyph()) {
-                charGlyphs[aOffset] = g;
-            } else {
-                const DetailedGlyph *details =
-                    g.GetGlyphCount() > 0 ?
-                        aShapedWord->GetDetailedGlyphs(i) : nullptr;
-                SetGlyphs(aOffset, g, details);
-            }
-        }
-    } else {
-        memcpy(charGlyphs + aOffset, wordGlyphs,
-               wordLen * sizeof(CompressedGlyph));
-    }
-}
-
-void
-gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
-                              uint32_t aLength, uint32_t aDest)
-{
-    NS_ASSERTION(aStart + aLength <= aSource->GetLength(),
-                 "Source substring out of range");
-    NS_ASSERTION(aDest + aLength <= GetLength(),
-                 "Destination substring out of range");
-
-    if (aSource->mSkipDrawing) {
-        mSkipDrawing = true;
-    }
-
-    // Copy base glyph data, and DetailedGlyph data where present
-    const CompressedGlyph *srcGlyphs = aSource->mCharacterGlyphs + aStart;
-    CompressedGlyph *dstGlyphs = mCharacterGlyphs + aDest;
-    for (uint32_t i = 0; i < aLength; ++i) {
-        CompressedGlyph g = srcGlyphs[i];
-        g.SetCanBreakBefore(!g.IsClusterStart() ?
-            CompressedGlyph::FLAG_BREAK_TYPE_NONE :
-            dstGlyphs[i].CanBreakBefore());
-        if (!g.IsSimpleGlyph()) {
-            uint32_t count = g.GetGlyphCount();
-            if (count > 0) {
-                DetailedGlyph *dst = AllocateDetailedGlyphs(i + aDest, count);
-                if (dst) {
-                    DetailedGlyph *src = aSource->GetDetailedGlyphs(i + aStart);
-                    if (src) {
-                        ::memcpy(dst, src, count * sizeof(DetailedGlyph));
-                    } else {
-                        g.SetMissing(0);
-                    }
-                } else {
-                    g.SetMissing(0);
-                }
-            }
-        }
-        dstGlyphs[i] = g;
-    }
-
-    // Copy glyph runs
-    GlyphRunIterator iter(aSource, aStart, aLength);
-#ifdef DEBUG
-    gfxFont *lastFont = nullptr;
-#endif
-    while (iter.NextRun()) {
-        gfxFont *font = iter.GetGlyphRun()->mFont;
-        NS_ASSERTION(font != lastFont, "Glyphruns not coalesced?");
-#ifdef DEBUG
-        lastFont = font;
-        uint32_t end = iter.GetStringEnd();
-#endif
-        uint32_t start = iter.GetStringStart();
-
-        // These used to be NS_ASSERTION()s, but WARNING is more appropriate.
-        // Although it's unusual (and not desirable), it's possible for us to assign
-        // different fonts to a base character and a following diacritic.
-        // Example on OSX 10.5/10.6 with default fonts installed:
-        //     data:text/html,<p style="font-family:helvetica, arial, sans-serif;">
-        //                    &%23x043E;&%23x0486;&%23x20;&%23x043E;&%23x0486;
-        // This means the rendering of the cluster will probably not be very good,
-        // but it's the best we can do for now if the specified font only covered the
-        // initial base character and not its applied marks.
-        NS_WARN_IF_FALSE(aSource->IsClusterStart(start),
-                         "Started font run in the middle of a cluster");
-        NS_WARN_IF_FALSE(end == aSource->GetLength() || aSource->IsClusterStart(end),
-                         "Ended font run in the middle of a cluster");
-
-        nsresult rv = AddGlyphRun(font, iter.GetGlyphRun()->mMatchType,
-                                  start - aStart + aDest, false);
-        if (NS_FAILED(rv))
-            return;
-    }
-}
-
-void
-gfxTextRun::ClearGlyphsAndCharacters()
-{
-    ResetGlyphRuns();
-    memset(reinterpret_cast<char*>(mCharacterGlyphs), 0,
-           mLength * sizeof(CompressedGlyph));
-    mDetailedGlyphs = nullptr;
-}
-
-void
-gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext,
-                          uint32_t aCharIndex)
-{
-    if (SetSpaceGlyphIfSimple(aFont, aContext, aCharIndex, ' ')) {
-        return;
-    }
-
-    aFont->InitWordCache();
-    static const uint8_t space = ' ';
-    gfxShapedWord *sw = aFont->GetShapedWord(aContext,
-                                             &space, 1,
-                                             HashMix(0, ' '), 
-                                             MOZ_SCRIPT_LATIN,
-                                             mAppUnitsPerDevUnit,
-                                             gfxTextRunFactory::TEXT_IS_8BIT |
-                                             gfxTextRunFactory::TEXT_IS_ASCII |
-                                             gfxTextRunFactory::TEXT_IS_PERSISTENT,
-                                             nullptr);
-    if (sw) {
-        AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false);
-        CopyGlyphDataFrom(sw, aCharIndex);
-    }
-}
-
-bool
-gfxTextRun::SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext,
-                                  uint32_t aCharIndex, char16_t aSpaceChar)
-{
-    uint32_t spaceGlyph = aFont->GetSpaceGlyph();
-    if (!spaceGlyph || !CompressedGlyph::IsSimpleGlyphID(spaceGlyph)) {
-        return false;
-    }
-
-    uint32_t spaceWidthAppUnits =
-        NS_lroundf(aFont->GetMetrics().spaceWidth * mAppUnitsPerDevUnit);
-    if (!CompressedGlyph::IsSimpleAdvance(spaceWidthAppUnits)) {
-        return false;
-    }
-
-    AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false);
-    CompressedGlyph g;
-    g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
-    if (aSpaceChar == ' ') {
-        g.SetIsSpace();
-    }
-    GetCharacterGlyphs()[aCharIndex] = g;
-    return true;
-}
-
-void
-gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
-{
-    bool needsGlyphExtents = NeedsGlyphExtents(this);
-    if (!needsGlyphExtents && !mDetailedGlyphs)
-        return;
-
-    uint32_t i, runCount = mGlyphRuns.Length();
-    CompressedGlyph *charGlyphs = mCharacterGlyphs;
-    for (i = 0; i < runCount; ++i) {
-        const GlyphRun& run = mGlyphRuns[i];
-        gfxFont *font = run.mFont;
-        if (MOZ_UNLIKELY(font->GetStyle()->size == 0)) {
-            continue;
-        }
-
-        uint32_t start = run.mCharacterOffset;
-        uint32_t end = i + 1 < runCount ?
-            mGlyphRuns[i + 1].mCharacterOffset : GetLength();
-        bool fontIsSetup = false;
-        uint32_t j;
-        gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit);
-  
-        for (j = start; j < end; ++j) {
-            const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
-            if (glyphData->IsSimpleGlyph()) {
-                // If we're in speed mode, don't set up glyph extents here; we'll
-                // just return "optimistic" glyph bounds later
-                if (needsGlyphExtents) {
-                    uint32_t glyphIndex = glyphData->GetSimpleGlyph();
-                    if (!extents->IsGlyphKnown(glyphIndex)) {
-                        if (!fontIsSetup) {
-                            if (!font->SetupCairoFont(aRefContext)) {
-                                NS_WARNING("failed to set up font for glyph extents");
-                                break;
-                            }
-                            fontIsSetup = true;
-                        }
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-                        ++gGlyphExtentsSetupEagerSimple;
-#endif
-                        font->SetupGlyphExtents(aRefContext, glyphIndex, false, extents);
-                    }
-                }
-            } else if (!glyphData->IsMissing()) {
-                uint32_t glyphCount = glyphData->GetGlyphCount();
-                if (glyphCount == 0) {
-                    continue;
-                }
-                const gfxTextRun::DetailedGlyph *details = GetDetailedGlyphs(j);
-                if (!details) {
-                    continue;
-                }
-                for (uint32_t k = 0; k < glyphCount; ++k, ++details) {
-                    uint32_t glyphIndex = details->mGlyphID;
-                    if (!extents->IsGlyphKnownWithTightExtents(glyphIndex)) {
-                        if (!fontIsSetup) {
-                            if (!font->SetupCairoFont(aRefContext)) {
-                                NS_WARNING("failed to set up font for glyph extents");
-                                break;
-                            }
-                            fontIsSetup = true;
-                        }
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-                        ++gGlyphExtentsSetupEagerTight;
-#endif
-                        font->SetupGlyphExtents(aRefContext, glyphIndex, true, extents);
-                    }
-                }
-            }
-        }
-    }
-}
-
-
-gfxTextRun::ClusterIterator::ClusterIterator(gfxTextRun *aTextRun)
-    : mTextRun(aTextRun), mCurrentChar(uint32_t(-1))
-{
-}
-
-void
-gfxTextRun::ClusterIterator::Reset()
-{
-    mCurrentChar = uint32_t(-1);
-}
-
-bool
-gfxTextRun::ClusterIterator::NextCluster()
-{
-    uint32_t len = mTextRun->GetLength();
-    while (++mCurrentChar < len) {
-        if (mTextRun->IsClusterStart(mCurrentChar)) {
-            return true;
-        }
-    }
-
-    mCurrentChar = uint32_t(-1);
-    return false;
-}
-
-uint32_t
-gfxTextRun::ClusterIterator::ClusterLength() const
-{
-    if (mCurrentChar == uint32_t(-1)) {
-        return 0;
-    }
-
-    uint32_t i = mCurrentChar,
-             len = mTextRun->GetLength();
-    while (++i < len) {
-        if (mTextRun->IsClusterStart(i)) {
-            break;
-        }
-    }
-
-    return i - mCurrentChar;
-}
-
-gfxFloat
-gfxTextRun::ClusterIterator::ClusterAdvance(PropertyProvider *aProvider) const
-{
-    if (mCurrentChar == uint32_t(-1)) {
-        return 0;
-    }
-
-    return mTextRun->GetAdvanceWidth(mCurrentChar, ClusterLength(), aProvider);
-}
-
-size_t
-gfxTextRun::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)
-{
-    // The second arg is how much gfxTextRun::AllocateStorage would have
-    // allocated.
-    size_t total = mGlyphRuns.SizeOfExcludingThis(aMallocSizeOf);
-
-    if (mDetailedGlyphs) {
-        total += mDetailedGlyphs->SizeOfIncludingThis(aMallocSizeOf);
-    }
-
-    return total;
-}
-
-size_t
-gfxTextRun::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
-{
-    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
-}
-
-
-#ifdef DEBUG
-void
-gfxTextRun::Dump(FILE* aOutput) {
-    if (!aOutput) {
-        aOutput = stdout;
-    }
-
-    uint32_t i;
-    fputc('[', aOutput);
-    for (i = 0; i < mGlyphRuns.Length(); ++i) {
-        if (i > 0) {
-            fputc(',', aOutput);
-        }
-        gfxFont* font = mGlyphRuns[i].mFont;
-        const gfxFontStyle* style = font->GetStyle();
-        NS_ConvertUTF16toUTF8 fontName(font->GetName());
-        nsAutoCString lang;
-        style->language->ToUTF8String(lang);
-        fprintf(aOutput, "%d: %s %f/%d/%d/%s", mGlyphRuns[i].mCharacterOffset,
-                fontName.get(), style->size,
-                style->weight, style->style, lang.get());
-    }
-    fputc(']', aOutput);
-}
-#endif
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -2,73 +2,59 @@
  * 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 GFX_FONT_H
 #define GFX_FONT_H
 
 #include "gfxTypes.h"
+#include "gfxFontEntry.h"
 #include "nsString.h"
 #include "gfxPoint.h"
-#include "gfxFontFamilyList.h"
-#include "gfxFontUtils.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
-#include "gfxSkipChars.h"
 #include "gfxRect.h"
 #include "nsExpirationTracker.h"
 #include "gfxPlatform.h"
 #include "nsIAtom.h"
 #include "mozilla/HashFunctions.h"
 #include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
-#include "gfxFontFeatures.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Attributes.h"
 #include <algorithm>
 #include "DrawMode.h"
-#include "nsUnicodeScriptCodes.h"
 #include "nsDataHashtable.h"
 #include "harfbuzz/hb.h"
 #include "mozilla/gfx/2D.h"
 
 typedef struct _cairo_scaled_font cairo_scaled_font_t;
-typedef struct gr_face            gr_face;
+//typedef struct gr_face            gr_face;
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 class gfxContext;
 class gfxTextRun;
 class gfxFont;
-class gfxFontFamily;
-class gfxFontGroup;
-class gfxGraphiteShaper;
-class gfxHarfBuzzShaper;
-class gfxUserFontSet;
-class gfxUserFontData;
+class gfxGlyphExtents;
 class gfxShapedText;
 class gfxShapedWord;
-class gfxSVGGlyphs;
-class gfxMathTable;
+class gfxSkipChars;
 class gfxTextContextPaint;
-class FontInfoData;
-
-class nsILanguageAtomService;
 
 #define FONT_MAX_SIZE                  2000.0
 
 #define NO_FONT_LANGUAGE_OVERRIDE      0
 
 #define SMALL_CAPS_SCALE_FACTOR        0.8
 
-struct FontListSizes;
 struct gfxTextRunDrawCallbacks;
 
 namespace mozilla {
 namespace gfx {
 class GlyphRenderingOptions;
 }
 }
 
@@ -208,794 +194,16 @@ struct gfxFontStyle {
     }
 
     static void ParseFontFeatureSettings(const nsString& aFeatureString,
                                          nsTArray<gfxFontFeature>& aFeatures);
 
     static uint32_t ParseFontLanguageOverride(const nsString& aLangTag);
 };
 
-class gfxCharacterMap : public gfxSparseBitSet {
-public:
-    nsrefcnt AddRef() {
-        NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
-        ++mRefCnt;
-        NS_LOG_ADDREF(this, mRefCnt, "gfxCharacterMap", sizeof(*this));
-        return mRefCnt;
-    }
-
-    nsrefcnt Release() {
-        NS_PRECONDITION(0 != mRefCnt, "dup release");
-        --mRefCnt;
-        NS_LOG_RELEASE(this, mRefCnt, "gfxCharacterMap");
-        if (mRefCnt == 0) {
-            NotifyReleased();
-            // |this| has been deleted.
-            return 0;
-        }
-        return mRefCnt;
-    }
-
-    gfxCharacterMap() :
-        mHash(0), mBuildOnTheFly(false), mShared(false)
-    { }
-
-    void CalcHash() { mHash = GetChecksum(); }
-
-    size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
-        return gfxSparseBitSet::SizeOfExcludingThis(aMallocSizeOf);
-    }
-
-    // hash of the cmap bitvector
-    uint32_t mHash;
-
-    // if cmap is built on the fly it's never shared
-    bool mBuildOnTheFly;
-
-    // cmap is shared globally
-    bool mShared;
-
-protected:
-    void NotifyReleased();
-
-    nsAutoRefCnt mRefCnt;
-
-private:
-    gfxCharacterMap(const gfxCharacterMap&);
-    gfxCharacterMap& operator=(const gfxCharacterMap&);
-};
-
-class gfxFontEntry {
-public:
-    NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
-
-    explicit gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false);
-
-    // unique name for the face, *not* the family; not necessarily the
-    // "real" or user-friendly name, may be an internal identifier
-    const nsString& Name() const { return mName; }
-
-    // family name
-    const nsString& FamilyName() const { return mFamilyName; }
-
-    // The following two methods may be relatively expensive, as they
-    // will (usually, except on Linux) load and parse the 'name' table;
-    // they are intended only for the font-inspection API, not for
-    // perf-critical layout/drawing work.
-
-    // The "real" name of the face, if available from the font resource;
-    // returns Name() if nothing better is available.
-    virtual nsString RealFaceName();
-
-    uint16_t Weight() const { return mWeight; }
-    int16_t Stretch() const { return mStretch; }
-
-    bool IsUserFont() const { return mIsDataUserFont || mIsLocalUserFont; }
-    bool IsLocalUserFont() const { return mIsLocalUserFont; }
-    bool IsFixedPitch() const { return mFixedPitch; }
-    bool IsItalic() const { return mItalic; }
-    bool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above
-    bool IgnoreGDEF() const { return mIgnoreGDEF; }
-    bool IgnoreGSUB() const { return mIgnoreGSUB; }
-
-    // whether a feature is supported by the font (limited to a small set
-    // of features for which some form of fallback needs to be implemented)
-    bool SupportsOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag);
-    bool SupportsGraphiteFeature(uint32_t aFeatureTag);
-
-    // returns a set containing all input glyph ids for a given feature
-    const hb_set_t*
-    InputsForOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag);
-
-    virtual bool IsSymbolFont();
-
-    virtual bool HasFontTable(uint32_t aTableTag);
-
-    inline bool HasGraphiteTables() {
-        if (!mCheckedForGraphiteTables) {
-            CheckForGraphiteTables();
-            mCheckedForGraphiteTables = true;
-        }
-        return mHasGraphiteTables;
-    }
-
-    inline bool HasCmapTable() {
-        if (!mCharacterMap) {
-            ReadCMAP();
-            NS_ASSERTION(mCharacterMap, "failed to initialize character map");
-        }
-        return mHasCmapTable;
-    }
-
-    inline bool HasCharacter(uint32_t ch) {
-        if (mCharacterMap && mCharacterMap->test(ch)) {
-            return true;
-        }
-        return TestCharacterMap(ch);
-    }
-
-    virtual bool SkipDuringSystemFallback() { return false; }
-    virtual bool TestCharacterMap(uint32_t aCh);
-    nsresult InitializeUVSMap();
-    uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS);
-
-    // All concrete gfxFontEntry subclasses (except gfxUserFontEntry) need
-    // to override this, otherwise the font will never be used as it will
-    // be considered to support no characters.
-    // ReadCMAP() must *always* set the mCharacterMap pointer to a valid
-    // gfxCharacterMap, even if empty, as other code assumes this pointer
-    // can be safely dereferenced.
-    virtual nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
-
-    bool TryGetSVGData(gfxFont* aFont);
-    bool HasSVGGlyph(uint32_t aGlyphId);
-    bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
-                            gfxRect *aResult);
-    bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode,
-                        gfxTextContextPaint *aContextPaint);
-    // Call this when glyph geometry or rendering has changed
-    // (e.g. animated SVG glyphs)
-    void NotifyGlyphsChanged();
-
-    enum MathConstant {
-        // The order of the constants must match the order of the fields
-        // defined in the MATH table.
-        ScriptPercentScaleDown,
-        ScriptScriptPercentScaleDown,
-        DelimitedSubFormulaMinHeight,
-        DisplayOperatorMinHeight,
-        MathLeading,
-        AxisHeight,
-        AccentBaseHeight,
-        FlattenedAccentBaseHeight,
-        SubscriptShiftDown,
-        SubscriptTopMax,
-        SubscriptBaselineDropMin,
-        SuperscriptShiftUp,
-        SuperscriptShiftUpCramped,
-        SuperscriptBottomMin,
-        SuperscriptBaselineDropMax,
-        SubSuperscriptGapMin,
-        SuperscriptBottomMaxWithSubscript,
-        SpaceAfterScript,
-        UpperLimitGapMin,
-        UpperLimitBaselineRiseMin,
-        LowerLimitGapMin,
-        LowerLimitBaselineDropMin,
-        StackTopShiftUp,
-        StackTopDisplayStyleShiftUp,
-        StackBottomShiftDown,
-        StackBottomDisplayStyleShiftDown,
-        StackGapMin,
-        StackDisplayStyleGapMin,
-        StretchStackTopShiftUp,
-        StretchStackBottomShiftDown,
-        StretchStackGapAboveMin,
-        StretchStackGapBelowMin,
-        FractionNumeratorShiftUp,
-        FractionNumeratorDisplayStyleShiftUp,
-        FractionDenominatorShiftDown,
-        FractionDenominatorDisplayStyleShiftDown,
-        FractionNumeratorGapMin,
-        FractionNumDisplayStyleGapMin,
-        FractionRuleThickness,
-        FractionDenominatorGapMin,
-        FractionDenomDisplayStyleGapMin,
-        SkewedFractionHorizontalGap,
-        SkewedFractionVerticalGap,
-        OverbarVerticalGap,
-        OverbarRuleThickness,
-        OverbarExtraAscender,
-        UnderbarVerticalGap,
-        UnderbarRuleThickness,
-        UnderbarExtraDescender,
-        RadicalVerticalGap,
-        RadicalDisplayStyleVerticalGap,
-        RadicalRuleThickness,
-        RadicalExtraAscender,
-        RadicalKernBeforeDegree,
-        RadicalKernAfterDegree,
-        RadicalDegreeBottomRaisePercent
-    };
-
-    // Call TryGetMathTable to try to load the Open Type MATH table. The other
-    // functions forward the call to the gfxMathTable class. The GetMath...()
-    // functions MUST NOT be called unless TryGetMathTable() has returned true.
-    bool     TryGetMathTable();
-    gfxFloat GetMathConstant(MathConstant aConstant);
-    bool     GetMathItalicsCorrection(uint32_t aGlyphID,
-                                      gfxFloat* aItalicCorrection);
-    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
-                                 uint16_t aSize);
-    bool     GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
-                                  uint32_t aGlyphs[4]);
-
-    bool     TryGetColorGlyphs();
-    bool     GetColorLayersInfo(uint32_t aGlyphId,
-                                nsTArray<uint16_t>& layerGlyphs,
-                                nsTArray<mozilla::gfx::Color>& layerColors);
-
-    virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
-        return true;
-    }
-    virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
-        return true;
-    }
-
-    // Access to raw font table data (needed for Harfbuzz):
-    // returns a pointer to data owned by the fontEntry or the OS,
-    // which will remain valid until the blob is destroyed.
-    // The data MUST be treated as read-only; we may be getting a
-    // reference to a shared system font cache.
-    //
-    // The default implementation uses CopyFontTable to get the data
-    // into a byte array, and maintains a cache of loaded tables.
-    //
-    // Subclasses should override this if they can provide more efficient
-    // access than copying table data into our own buffers.
-    //
-    // Get blob that encapsulates a specific font table, or nullptr if
-    // the table doesn't exist in the font.
-    //
-    // Caller is responsible to call hb_blob_destroy() on the returned blob
-    // (if non-nullptr) when no longer required. For transient access to a
-    // table, use of AutoTable (below) is generally preferred.
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
-
-    // Stack-based utility to return a specified table, automatically releasing
-    // the blob when the AutoTable goes out of scope.
-    class AutoTable {
-    public:
-        AutoTable(gfxFontEntry* aFontEntry, uint32_t aTag)
-        {
-            mBlob = aFontEntry->GetFontTable(aTag);
-        }
-        ~AutoTable() {
-            if (mBlob) {
-                hb_blob_destroy(mBlob);
-            }
-        }
-        operator hb_blob_t*() const { return mBlob; }
-    private:
-        hb_blob_t* mBlob;
-        // not implemented:
-        AutoTable(const AutoTable&) MOZ_DELETE;
-        AutoTable& operator=(const AutoTable&) MOZ_DELETE;
-    };
-
-    already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
-                                             bool aNeedsBold);
-
-    // Get an existing font table cache entry in aBlob if it has been
-    // registered, or return false if not.  Callers must call
-    // hb_blob_destroy on aBlob if true is returned.
-    //
-    // Note that some gfxFont implementations may not call this at all,
-    // if it is more efficient to get the table from the OS at that level.
-    bool GetExistingFontTable(uint32_t aTag, hb_blob_t** aBlob);
-
-    // Elements of aTable are transferred (not copied) to and returned in a
-    // new hb_blob_t which is registered on the gfxFontEntry, but the initial
-    // reference is owned by the caller.  Removing the last reference
-    // unregisters the table from the font entry.
-    //
-    // Pass nullptr for aBuffer to indicate that the table is not present and
-    // nullptr will be returned.  Also returns nullptr on OOM.
-    hb_blob_t *ShareFontTableAndGetBlob(uint32_t aTag,
-                                        FallibleTArray<uint8_t>* aTable);
-
-    // Get the font's unitsPerEm from the 'head' table, in the case of an
-    // sfnt resource. Will return kInvalidUPEM for non-sfnt fonts,
-    // if present on the platform.
-    uint16_t UnitsPerEm();
-    enum {
-        kMinUPEM = 16,    // Limits on valid unitsPerEm range, from the
-        kMaxUPEM = 16384, // OpenType spec
-        kInvalidUPEM = uint16_t(-1)
-    };
-
-    // Shaper face accessors:
-    // NOTE that harfbuzz and graphite handle ownership/lifetime of the face
-    // object in completely different ways.
-
-    // Get HarfBuzz face corresponding to this font file.
-    // Caller must release with hb_face_destroy() when finished with it,
-    // and the font entry will be notified via ForgetHBFace.
-    hb_face_t* GetHBFace();
-    virtual void ForgetHBFace();
-
-    // Get Graphite face corresponding to this font file.
-    // Caller must call gfxFontEntry::ReleaseGrFace when finished with it.
-    gr_face* GetGrFace();
-    virtual void ReleaseGrFace(gr_face* aFace);
-
-    // Release any SVG-glyphs document this font may have loaded.
-    void DisconnectSVG();
-
-    // Called to notify that aFont is being destroyed. Needed when we're tracking
-    // the fonts belonging to this font entry.
-    void NotifyFontDestroyed(gfxFont* aFont);
-
-    // For memory reporting
-    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontListSizes* aSizes) const;
-    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontListSizes* aSizes) const;
-
-    // Used when checking for complex script support, to mask off cmap ranges
-    struct ScriptRange {
-        uint32_t         rangeStart;
-        uint32_t         rangeEnd;
-        hb_tag_t         tags[3]; // one or two OpenType script tags to check,
-                                  // plus a NULL terminator
-    };
-
-    bool SupportsScriptInGSUB(const hb_tag_t* aScriptTags);
-
-    nsString         mName;
-    nsString         mFamilyName;
-
-    bool             mItalic      : 1;
-    bool             mFixedPitch  : 1;
-    bool             mIsValid     : 1;
-    bool             mIsBadUnderlineFont : 1;
-    bool             mIsUserFontContainer : 1; // userfont entry
-    bool             mIsDataUserFont : 1;      // platform font entry (data)
-    bool             mIsLocalUserFont : 1;     // platform font entry (local)
-    bool             mStandardFace : 1;
-    bool             mSymbolFont  : 1;
-    bool             mIgnoreGDEF  : 1;
-    bool             mIgnoreGSUB  : 1;
-    bool             mSVGInitialized : 1;
-    bool             mMathInitialized : 1;
-    bool             mHasSpaceFeaturesInitialized : 1;
-    bool             mHasSpaceFeatures : 1;
-    bool             mHasSpaceFeaturesKerning : 1;
-    bool             mHasSpaceFeaturesNonKerning : 1;
-    bool             mSkipDefaultFeatureSpaceCheck : 1;
-    bool             mHasGraphiteTables : 1;
-    bool             mCheckedForGraphiteTables : 1;
-    bool             mHasCmapTable : 1;
-    bool             mGrFaceInitialized : 1;
-    bool             mCheckedForColorGlyph : 1;
-
-    // bitvector of substitution space features per script, one each
-    // for default and non-default features
-    uint32_t         mDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
-    uint32_t         mNonDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
-
-    uint16_t         mWeight;
-    int16_t          mStretch;
-
-    nsRefPtr<gfxCharacterMap> mCharacterMap;
-    uint32_t         mUVSOffset;
-    nsAutoArrayPtr<uint8_t> mUVSData;
-    nsAutoPtr<gfxUserFontData> mUserFontData;
-    nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
-    // list of gfxFonts that are using SVG glyphs
-    nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
-    nsAutoPtr<gfxMathTable> mMathTable;
-    nsTArray<gfxFontFeature> mFeatureSettings;
-    nsAutoPtr<nsDataHashtable<nsUint32HashKey,bool>> mSupportedFeatures;
-    nsAutoPtr<nsDataHashtable<nsUint32HashKey,hb_set_t*>> mFeatureInputs;
-    uint32_t         mLanguageOverride;
-
-    // Color Layer font support
-    hb_blob_t*       mCOLR;
-    hb_blob_t*       mCPAL;
-
-protected:
-    friend class gfxPlatformFontList;
-    friend class gfxMacPlatformFontList;
-    friend class gfxUserFcFontEntry;
-    friend class gfxFontFamily;
-    friend class gfxSingleFaceMacFontFamily;
-
-    gfxFontEntry();
-
-    // Protected destructor, to discourage deletion outside of Release():
-    virtual ~gfxFontEntry();
-
-    virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) {
-        NS_NOTREACHED("oops, somebody didn't override CreateFontInstance");
-        return nullptr;
-    }
-
-    virtual void CheckForGraphiteTables();
-
-    // Copy a font table into aBuffer.
-    // The caller will be responsible for ownership of the data.
-    virtual nsresult CopyFontTable(uint32_t aTableTag,
-                                   FallibleTArray<uint8_t>& aBuffer) {
-        NS_NOTREACHED("forgot to override either GetFontTable or CopyFontTable?");
-        return NS_ERROR_FAILURE;
-    }
-
-    // Return a blob that wraps a table found within a buffer of font data.
-    // The blob does NOT own its data; caller guarantees that the buffer
-    // will remain valid at least as long as the blob.
-    // Returns null if the specified table is not found.
-    // This method assumes aFontData is valid 'sfnt' data; before using this,
-    // caller is responsible to do any sanitization/validation necessary.
-    hb_blob_t* GetTableFromFontData(const void* aFontData, uint32_t aTableTag);
-
-    // lookup the cmap in cached font data
-    virtual already_AddRefed<gfxCharacterMap>
-    GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
-                        uint32_t& aUVSOffset,
-                        bool& aSymbolFont);
-
-    // Font's unitsPerEm from the 'head' table, if available (will be set to
-    // kInvalidUPEM for non-sfnt font formats)
-    uint16_t mUnitsPerEm;
-
-    // Shaper-specific face objects, shared by all instantiations of the same
-    // physical font, regardless of size.
-    // Usually, only one of these will actually be created for any given font
-    // entry, depending on the font tables that are present.
-
-    // hb_face_t is refcounted internally, so each shaper that's using it will
-    // bump the ref count when it acquires the face, and "destroy" (release) it
-    // in its destructor. The font entry has only this non-owning reference to
-    // the face; when the face is deleted, it will tell the font entry to forget
-    // it, so that a new face will be created next time it is needed.
-    hb_face_t* mHBFace;
-
-    static hb_blob_t* HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData);
-
-    // Callback that the hb_face will use to tell us when it is being deleted.
-    static void HBFaceDeletedCallback(void *aUserData);
-
-    // gr_face is -not- refcounted, so it will be owned directly by the font
-    // entry, and we'll keep a count of how many references we've handed out;
-    // each shaper is responsible to call ReleaseGrFace on its entry when
-    // finished with it, so that we know when it can be deleted.
-    gr_face*   mGrFace;
-
-    // hashtable to map raw table data ptr back to its owning blob, for use by
-    // graphite table-release callback
-    nsDataHashtable<nsPtrHashKey<const void>,void*>* mGrTableMap;
-
-    // number of current users of this entry's mGrFace
-    nsrefcnt mGrFaceRefCnt;
-
-    static const void* GrGetTable(const void *aAppFaceHandle,
-                                  unsigned int aName,
-                                  size_t *aLen);
-    static void GrReleaseTable(const void *aAppFaceHandle,
-                               const void *aTableBuffer);
-
-private:
-    /**
-     * Font table hashtable, to support GetFontTable for harfbuzz.
-     *
-     * The harfbuzz shaper (and potentially other clients) needs access to raw
-     * font table data. This needs to be cached so that it can be used
-     * repeatedly (each time we construct a text run; in some cases, for
-     * each character/glyph within the run) without re-fetching large tables
-     * every time.
-     * 
-     * Because we may instantiate many gfxFonts for the same physical font
-     * file (at different sizes), we should ensure that they can share a
-     * single cached copy of the font tables. To do this, we implement table
-     * access and sharing on the fontEntry rather than the font itself.
-     *
-     * The default implementation uses GetFontTable() to read font table
-     * data into byte arrays, and wraps them in blobs which are registered in
-     * a hashtable.  The hashtable can then return pre-existing blobs to
-     * harfbuzz.
-     *
-     * Harfbuzz will "destroy" the blobs when it is finished with them.  When
-     * the last blob reference is removed, the FontTableBlobData user data
-     * will remove the blob from the hashtable if still registered.
-     */
-
-    class FontTableBlobData;
-
-    /**
-     * FontTableHashEntry manages the entries of hb_blob_t's containing font
-     * table data.
-     *
-     * This is used to share font tables across fonts with the same
-     * font entry (but different sizes) for use by HarfBuzz.  The hashtable
-     * does not own a strong reference to the blob, but keeps a weak pointer,
-     * managed by FontTableBlobData.  Similarly FontTableBlobData keeps only a
-     * weak pointer to the hashtable, managed by FontTableHashEntry.
-     */
-
-    class FontTableHashEntry : public nsUint32HashKey
-    {
-    public:
-        // Declarations for nsTHashtable
-
-        typedef nsUint32HashKey KeyClass;
-        typedef KeyClass::KeyType KeyType;
-        typedef KeyClass::KeyTypePointer KeyTypePointer;
-
-        explicit FontTableHashEntry(KeyTypePointer aTag)
-            : KeyClass(aTag)
-            , mSharedBlobData(nullptr)
-            , mBlob(nullptr)
-        { }
-
-        // NOTE: This assumes the new entry belongs to the same hashtable as
-        // the old, because the mHashtable pointer in mSharedBlobData (if
-        // present) will not be updated.
-        FontTableHashEntry(FontTableHashEntry&& toMove)
-            : KeyClass(mozilla::Move(toMove))
-            , mSharedBlobData(mozilla::Move(toMove.mSharedBlobData))
-            , mBlob(mozilla::Move(toMove.mBlob))
-        {
-            toMove.mSharedBlobData = nullptr;
-            toMove.mBlob = nullptr;
-        }
-
-        ~FontTableHashEntry() { Clear(); }
-
-        // FontTable/Blob API
-
-        // Transfer (not copy) elements of aTable to a new hb_blob_t and
-        // return ownership to the caller.  A weak reference to the blob is
-        // recorded in the hashtable entry so that others may use the same
-        // table.
-        hb_blob_t *
-        ShareTableAndGetBlob(FallibleTArray<uint8_t>& aTable,
-                             nsTHashtable<FontTableHashEntry> *aHashtable);
-
-        // Return a strong reference to the blob.
-        // Callers must hb_blob_destroy the returned blob.
-        hb_blob_t *GetBlob() const;
-
-        void Clear();
-
-        size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-
-    private:
-        static void DeleteFontTableBlobData(void *aBlobData);
-        // not implemented
-        FontTableHashEntry& operator=(FontTableHashEntry& toCopy);
-
-        FontTableBlobData *mSharedBlobData;
-        hb_blob_t *mBlob;
-    };
-
-    nsAutoPtr<nsTHashtable<FontTableHashEntry> > mFontTableCache;
-
-    gfxFontEntry(const gfxFontEntry&);
-    gfxFontEntry& operator=(const gfxFontEntry&);
-};
-
-
-// used when iterating over all fonts looking for a match for a given character
-struct GlobalFontMatch {
-    GlobalFontMatch(const uint32_t aCharacter,
-                    int32_t aRunScript,
-                    const gfxFontStyle *aStyle) :
-        mCh(aCharacter), mRunScript(aRunScript), mStyle(aStyle),
-        mMatchRank(0), mCount(0), mCmapsTested(0)
-        {
-
-        }
-
-    const uint32_t         mCh;          // codepoint to be matched
-    int32_t                mRunScript;   // Unicode script for the codepoint
-    const gfxFontStyle*    mStyle;       // style to match
-    int32_t                mMatchRank;   // metric indicating closest match
-    nsRefPtr<gfxFontEntry> mBestMatch;   // current best match
-    nsRefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
-    uint32_t               mCount;       // number of fonts matched
-    uint32_t               mCmapsTested; // number of cmaps tested
-};
-
-class gfxFontFamily {
-public:
-    NS_INLINE_DECL_REFCOUNTING(gfxFontFamily)
-
-    explicit gfxFontFamily(const nsAString& aName) :
-        mName(aName),
-        mOtherFamilyNamesInitialized(false),
-        mHasOtherFamilyNames(false),
-        mFaceNamesInitialized(false),
-        mHasStyles(false),
-        mIsSimpleFamily(false),
-        mIsBadUnderlineFamily(false),
-        mFamilyCharacterMapInitialized(false),
-        mSkipDefaultFeatureSpaceCheck(false)
-        { }
-
-    const nsString& Name() { return mName; }
-
-    virtual void LocalizedName(nsAString& aLocalizedName);
-    virtual bool HasOtherFamilyNames();
-    
-    nsTArray<nsRefPtr<gfxFontEntry> >& GetFontList() { return mAvailableFonts; }
-    
-    void AddFontEntry(nsRefPtr<gfxFontEntry> aFontEntry) {
-        // bug 589682 - set the IgnoreGDEF flag on entries for Italic faces
-        // of Times New Roman, because of buggy table in those fonts
-        if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() &&
-            Name().EqualsLiteral("Times New Roman"))
-        {
-            aFontEntry->mIgnoreGDEF = true;
-        }
-        if (aFontEntry->mFamilyName.IsEmpty()) {
-            aFontEntry->mFamilyName = Name();
-        } else {
-            MOZ_ASSERT(aFontEntry->mFamilyName.Equals(Name()));
-        }
-        aFontEntry->mSkipDefaultFeatureSpaceCheck = mSkipDefaultFeatureSpaceCheck;
-        mAvailableFonts.AppendElement(aFontEntry);
-    }
-
-    // note that the styles for this family have been added
-    bool HasStyles() { return mHasStyles; }
-    void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; }
-
-    // choose a specific face to match a style using CSS font matching
-    // rules (weight matching occurs here).  may return a face that doesn't
-    // precisely match (e.g. normal face when no italic face exists).
-    // aNeedsSyntheticBold is set to true when synthetic bolding is
-    // needed, false otherwise
-    gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, 
-                                   bool& aNeedsSyntheticBold);
-
-    // checks for a matching font within the family
-    // used as part of the font fallback process
-    void FindFontForChar(GlobalFontMatch *aMatchData);
-
-    // checks all fonts for a matching font within the family
-    void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
-
-    // read in other family names, if any, and use functor to add each into cache
-    virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
-
-    // helper method for reading localized family names from the name table
-    // of a single face
-    static void ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
-                                            const char *aNameData,
-                                            uint32_t aDataLength,
-                                            nsTArray<nsString>& aOtherFamilyNames,
-                                            bool useFullName);
-
-    // set when other family names have been read in
-    void SetOtherFamilyNamesInitialized() {
-        mOtherFamilyNamesInitialized = true;
-    }
-
-    // read in other localized family names, fullnames and Postscript names
-    // for all faces and append to lookup tables
-    virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
-                               bool aNeedFullnamePostscriptNames,
-                               FontInfoData *aFontInfoData = nullptr);
-
-    // find faces belonging to this family (platform implementations override this;
-    // should be made pure virtual once all subclasses have been updated)
-    virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) { }
-
-    // search for a specific face using the Postscript name
-    gfxFontEntry* FindFont(const nsAString& aPostscriptName);
-
-    // read in cmaps for all the faces
-    void ReadAllCMAPs(FontInfoData *aFontInfoData = nullptr);
-
-    bool TestCharacterMap(uint32_t aCh) {
-        if (!mFamilyCharacterMapInitialized) {
-            ReadAllCMAPs();
-        }
-        return mFamilyCharacterMap.test(aCh);
-    }
-
-    void ResetCharacterMap() {
-        mFamilyCharacterMap.reset();
-        mFamilyCharacterMapInitialized = false;
-    }
-
-    // mark this family as being in the "bad" underline offset blacklist
-    void SetBadUnderlineFamily() {
-        mIsBadUnderlineFamily = true;
-        if (mHasStyles) {
-            SetBadUnderlineFonts();
-        }
-    }
-
-    bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; }
-
-    // sort available fonts to put preferred (standard) faces towards the end
-    void SortAvailableFonts();
-
-    // check whether the family fits into the simple 4-face model,
-    // so we can use simplified style-matching;
-    // if so set the mIsSimpleFamily flag (defaults to False before we've checked)
-    void CheckForSimpleFamily();
-
-    // For memory reporter
-    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontListSizes* aSizes) const;
-    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontListSizes* aSizes) const;
-
-#ifdef DEBUG
-    // Only used for debugging checks - does a linear search
-    bool ContainsFace(gfxFontEntry* aFontEntry);
-#endif
-
-    void SetSkipSpaceFeatureCheck(bool aSkipCheck) {
-        mSkipDefaultFeatureSpaceCheck = aSkipCheck;
-    }
-
-protected:
-    // Protected destructor, to discourage deletion outside of Release():
-    virtual ~gfxFontFamily()
-    {
-    }
-
-    // fills in an array with weights of faces that match style,
-    // returns whether any matching entries found
-    virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
-                                       bool anItalic, int16_t aStretch);
-
-    bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
-                                     hb_blob_t           *aNameTable,
-                                     bool                 useFullName = false);
-
-    // set whether this font family is in "bad" underline offset blacklist.
-    void SetBadUnderlineFonts() {
-        uint32_t i, numFonts = mAvailableFonts.Length();
-        for (i = 0; i < numFonts; i++) {
-            if (mAvailableFonts[i]) {
-                mAvailableFonts[i]->mIsBadUnderlineFont = true;
-            }
-        }
-    }
-
-    nsString mName;
-    nsTArray<nsRefPtr<gfxFontEntry> >  mAvailableFonts;
-    gfxSparseBitSet mFamilyCharacterMap;
-    bool mOtherFamilyNamesInitialized : 1;
-    bool mHasOtherFamilyNames : 1;
-    bool mFaceNamesInitialized : 1;
-    bool mHasStyles : 1;
-    bool mIsSimpleFamily : 1;
-    bool mIsBadUnderlineFamily : 1;
-    bool mFamilyCharacterMapInitialized : 1;
-    bool mSkipDefaultFeatureSpaceCheck : 1;
-
-    enum {
-        // for "simple" families, the faces are stored in mAvailableFonts
-        // with fixed positions:
-        kRegularFaceIndex    = 0,
-        kBoldFaceIndex       = 1,
-        kItalicFaceIndex     = 2,
-        kBoldItalicFaceIndex = 3,
-        // mask values for selecting face with bold and/or italic attributes
-        kBoldMask   = 0x01,
-        kItalicMask = 0x02
-    };
-};
-
 struct gfxTextRange {
     enum {
         // flags for recording the kind of font-matching that was used
         kFontGroup      = 0x0001,
         kPrefsFallback  = 0x0002,
         kSystemFallback = 0x0004
     };
     gfxTextRange(uint32_t aStart, uint32_t aEnd,
@@ -1335,141 +543,16 @@ public:
     };
 
 protected:
     // Protected destructor, to discourage deletion outside of Release():
     virtual ~gfxTextRunFactory() {}
 };
 
 /**
- * This stores glyph bounds information for a particular gfxFont, at
- * a particular appunits-per-dev-pixel ratio (because the compressed glyph
- * width array is stored in appunits).
- * 
- * We store a hashtable from glyph IDs to float bounding rects. For the
- * common case where the glyph has no horizontal left bearing, and no
- * y overflow above the font ascent or below the font descent, and tight
- * bounding boxes are not required, we avoid storing the glyph ID in the hashtable
- * and instead consult an array of 16-bit glyph XMost values (in appunits).
- * This array always has an entry for the font's space glyph --- the width is
- * assumed to be zero.
- */
-class gfxGlyphExtents {
-public:
-    explicit gfxGlyphExtents(int32_t aAppUnitsPerDevUnit) :
-        mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {
-        MOZ_COUNT_CTOR(gfxGlyphExtents);
-    }
-    ~gfxGlyphExtents();
-
-    enum { INVALID_WIDTH = 0xFFFF };
-
-    void NotifyGlyphsChanged() {
-        mTightGlyphExtents.Clear();
-    }
-
-    // returns INVALID_WIDTH => not a contained glyph
-    // Otherwise the glyph has no before-bearing or vertical bearings,
-    // and the result is its width measured from the baseline origin, in
-    // appunits.
-    uint16_t GetContainedGlyphWidthAppUnits(uint32_t aGlyphID) const {
-        return mContainedGlyphWidths.Get(aGlyphID);
-    }
-
-    bool IsGlyphKnown(uint32_t aGlyphID) const {
-        return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
-            mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
-    }
-
-    bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID) const {
-        return mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
-    }
-
-    // Get glyph extents; a rectangle relative to the left baseline origin
-    // Returns true on success. Can fail on OOM or when aContext is null
-    // and extents were not (successfully) prefetched.
-    bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext,
-            uint32_t aGlyphID, gfxRect *aExtents);
-
-    void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) {
-        mContainedGlyphWidths.Set(aGlyphID, aWidth);
-    }
-    void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits);
-
-    int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
-
-    size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-
-private:
-    class HashEntry : public nsUint32HashKey {
-    public:
-        // When constructing a new entry in the hashtable, we'll leave this
-        // blank. The caller of Put() will fill this in.
-        explicit HashEntry(KeyTypePointer aPtr) : nsUint32HashKey(aPtr) {}
-        HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) {
-          x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.height;
-        }
-
-        float x, y, width, height;
-    };
-
-    enum { BLOCK_SIZE_BITS = 7, BLOCK_SIZE = 1 << BLOCK_SIZE_BITS }; // 128-glyph blocks
-
-    class GlyphWidths {
-    public:
-        void Set(uint32_t aIndex, uint16_t aValue);
-        uint16_t Get(uint32_t aIndex) const {
-            uint32_t block = aIndex >> BLOCK_SIZE_BITS;
-            if (block >= mBlocks.Length())
-                return INVALID_WIDTH;
-            uintptr_t bits = mBlocks[block];
-            if (!bits)
-                return INVALID_WIDTH;
-            uint32_t indexInBlock = aIndex & (BLOCK_SIZE - 1);
-            if (bits & 0x1) {
-                if (GetGlyphOffset(bits) != indexInBlock)
-                    return INVALID_WIDTH;
-                return GetWidth(bits);
-            }
-            uint16_t *widths = reinterpret_cast<uint16_t *>(bits);
-            return widths[indexInBlock];
-        }
-
-        uint32_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-        
-        ~GlyphWidths();
-
-    private:
-        static uint32_t GetGlyphOffset(uintptr_t aBits) {
-            NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
-            return (aBits >> 1) & ((1 << BLOCK_SIZE_BITS) - 1);
-        }
-        static uint32_t GetWidth(uintptr_t aBits) {
-            NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
-            return aBits >> (1 + BLOCK_SIZE_BITS);
-        }
-        static uintptr_t MakeSingle(uint32_t aGlyphOffset, uint16_t aWidth) {
-            return (aWidth << (1 + BLOCK_SIZE_BITS)) + (aGlyphOffset << 1) + 1;
-        }
-
-        nsTArray<uintptr_t> mBlocks;
-    };
-
-    GlyphWidths             mContainedGlyphWidths;
-    nsTHashtable<HashEntry> mTightGlyphExtents;
-    int32_t                 mAppUnitsPerDevUnit;
-
-private:
-    // not implemented:
-    gfxGlyphExtents(const gfxGlyphExtents& aOther) MOZ_DELETE;
-    gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) MOZ_DELETE;
-};
-
-/**
  * gfxFontShaper
  *
  * This class implements text shaping (character to glyph mapping and
  * glyph layout). There is a gfxFontShaper subclass for each text layout
  * technology (uniscribe, core text, harfbuzz,....) we support.
  *
  * The shaper is responsible for setting up glyph data in gfxTextRuns.
  *
@@ -1514,16 +597,631 @@ public:
                       nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures);
 
 protected:
     // the font this shaper is working with
     gfxFont * mFont;
 };
 
 
+/*
+ * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun.
+ * These are objects that store a list of zero or more glyphs for each character.
+ * For each glyph we store the glyph ID, the advance, and possibly x/y-offsets.
+ * The idea is that a string is rendered by a loop that draws each glyph
+ * at its designated offset from the current point, then advances the current
+ * point by the glyph's advance in the direction of the textrun (LTR or RTL).
+ * Each glyph advance is always rounded to the nearest appunit; this ensures
+ * consistent results when dividing the text in a textrun into multiple text
+ * frames (frame boundaries are always aligned to appunits). We optimize
+ * for the case where a character has a single glyph and zero xoffset and yoffset,
+ * and the glyph ID and advance are in a reasonable range so we can pack all
+ * necessary data into 32 bits.
+ *
+ * gfxFontShaper can shape text into either a gfxShapedWord (cached by a gfxFont)
+ * or directly into a gfxTextRun (for cases where we want to shape textruns in
+ * their entirety rather than using cached words, because there may be layout
+ * features that depend on the inter-word spaces).
+ */
+class gfxShapedText
+{
+public:
+    gfxShapedText(uint32_t aLength, uint32_t aFlags,
+                  int32_t aAppUnitsPerDevUnit)
+        : mLength(aLength)
+        , mFlags(aFlags)
+        , mAppUnitsPerDevUnit(aAppUnitsPerDevUnit)
+    { }
+
+    virtual ~gfxShapedText() { }
+
+    /**
+     * This class records the information associated with a character in the
+     * input string. It's optimized for the case where there is one glyph
+     * representing that character alone.
+     * 
+     * A character can have zero or more associated glyphs. Each glyph
+     * has an advance width and an x and y offset.
+     * A character may be the start of a cluster.
+     * A character may be the start of a ligature group.
+     * A character can be "missing", indicating that the system is unable
+     * to render the character.
+     * 
+     * All characters in a ligature group conceptually share all the glyphs
+     * associated with the characters in a group.
+     */
+    class CompressedGlyph {
+    public:
+        CompressedGlyph() { mValue = 0; }
+
+        enum {
+            // Indicates that a cluster and ligature group starts at this
+            // character; this character has a single glyph with a reasonable
+            // advance and zero offsets. A "reasonable" advance
+            // is one that fits in the available bits (currently 12) (specified
+            // in appunits).
+            FLAG_IS_SIMPLE_GLYPH  = 0x80000000U,
+
+            // Indicates whether a linebreak is allowed before this character;
+            // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value
+            // indicating the kind of linebreak (if any) allowed here.
+            FLAGS_CAN_BREAK_BEFORE = 0x60000000U,
+
+            FLAGS_CAN_BREAK_SHIFT = 29,
+            FLAG_BREAK_TYPE_NONE   = 0,
+            FLAG_BREAK_TYPE_NORMAL = 1,
+            FLAG_BREAK_TYPE_HYPHEN = 2,
+
+            FLAG_CHAR_IS_SPACE     = 0x10000000U,
+
+            // The advance is stored in appunits
+            ADVANCE_MASK  = 0x0FFF0000U,
+            ADVANCE_SHIFT = 16,
+
+            GLYPH_MASK = 0x0000FFFFU,
+
+            // Non-simple glyphs may or may not have glyph data in the
+            // corresponding mDetailedGlyphs entry. They have the following
+            // flag bits:
+
+            // When NOT set, indicates that this character corresponds to a
+            // missing glyph and should be skipped (or possibly, render the character
+            // Unicode value in some special way). If there are glyphs,
+            // the mGlyphID is actually the UTF16 character code. The bit is
+            // inverted so we can memset the array to zero to indicate all missing.
+            FLAG_NOT_MISSING              = 0x01,
+            FLAG_NOT_CLUSTER_START        = 0x02,
+            FLAG_NOT_LIGATURE_GROUP_START = 0x04,
+
+            FLAG_CHAR_IS_TAB              = 0x08,
+            FLAG_CHAR_IS_NEWLINE          = 0x10,
+            FLAG_CHAR_IS_LOW_SURROGATE    = 0x20,
+            CHAR_IDENTITY_FLAGS_MASK      = 0x38,
+
+            GLYPH_COUNT_MASK = 0x00FFFF00U,
+            GLYPH_COUNT_SHIFT = 8
+        };
+
+        // "Simple glyphs" have a simple glyph ID, simple advance and their
+        // x and y offsets are zero. Also the glyph extents do not overflow
+        // the font-box defined by the font ascent, descent and glyph advance width.
+        // These case is optimized to avoid storing DetailedGlyphs.
+
+        // Returns true if the glyph ID aGlyph fits into the compressed representation
+        static bool IsSimpleGlyphID(uint32_t aGlyph) {
+            return (aGlyph & GLYPH_MASK) == aGlyph;
+        }
+        // Returns true if the advance aAdvance fits into the compressed representation.
+        // aAdvance is in appunits.
+        static bool IsSimpleAdvance(uint32_t aAdvance) {
+            return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
+        }
+
+        bool IsSimpleGlyph() const { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; }
+        uint32_t GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
+        uint32_t GetSimpleGlyph() const { return mValue & GLYPH_MASK; }
+
+        bool IsMissing() const { return (mValue & (FLAG_NOT_MISSING|FLAG_IS_SIMPLE_GLYPH)) == 0; }
+        bool IsClusterStart() const {
+            return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_CLUSTER_START);
+        }
+        bool IsLigatureGroupStart() const {
+            return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_LIGATURE_GROUP_START);
+        }
+        bool IsLigatureContinuation() const {
+            return (mValue & FLAG_IS_SIMPLE_GLYPH) == 0 &&
+                (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) ==
+                    (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING);
+        }
+
+        // Return true if the original character was a normal (breakable,
+        // trimmable) space (U+0020). Not true for other characters that
+        // may happen to map to the space glyph (U+00A0).
+        bool CharIsSpace() const {
+            return (mValue & FLAG_CHAR_IS_SPACE) != 0;
+        }
+
+        bool CharIsTab() const {
+            return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB) != 0;
+        }
+        bool CharIsNewline() const {
+            return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE) != 0;
+        }
+        bool CharIsLowSurrogate() const {
+            return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_LOW_SURROGATE) != 0;
+        }
+
+        uint32_t CharIdentityFlags() const {
+            return IsSimpleGlyph() ? 0 : (mValue & CHAR_IDENTITY_FLAGS_MASK);
+        }
+
+        void SetClusterStart(bool aIsClusterStart) {
+            NS_ASSERTION(!IsSimpleGlyph(),
+                         "can't call SetClusterStart on simple glyphs");
+            if (aIsClusterStart) {
+                mValue &= ~FLAG_NOT_CLUSTER_START;
+            } else {
+                mValue |= FLAG_NOT_CLUSTER_START;
+            }
+        }
+
+        uint8_t CanBreakBefore() const {
+            return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT;
+        }
+        // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
+        uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore) {
+            NS_ASSERTION(aCanBreakBefore <= 2,
+                         "Bogus break-before value!");
+            uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT);
+            uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE);
+            mValue ^= toggle;
+            return toggle;
+        }
+
+        CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) {
+            NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow");
+            NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
+            NS_ASSERTION(!CharIdentityFlags(), "Char identity flags lost");
+            mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
+                FLAG_IS_SIMPLE_GLYPH |
+                (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
+            return *this;
+        }
+        CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart,
+                uint32_t aGlyphCount) {
+            mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
+                FLAG_NOT_MISSING |
+                CharIdentityFlags() |
+                (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
+                (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
+                (aGlyphCount << GLYPH_COUNT_SHIFT);
+            return *this;
+        }
+        /**
+         * Missing glyphs are treated as ligature group starts; don't mess with
+         * the cluster-start flag (see bugs 618870 and 619286).
+         */
+        CompressedGlyph& SetMissing(uint32_t aGlyphCount) {
+            mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_NOT_CLUSTER_START |
+                                FLAG_CHAR_IS_SPACE)) |
+                CharIdentityFlags() |
+                (aGlyphCount << GLYPH_COUNT_SHIFT);
+            return *this;
+        }
+        uint32_t GetGlyphCount() const {
+            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
+            return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT;
+        }
+
+        void SetIsSpace() {
+            mValue |= FLAG_CHAR_IS_SPACE;
+        }
+        void SetIsTab() {
+            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
+            mValue |= FLAG_CHAR_IS_TAB;
+        }
+        void SetIsNewline() {
+            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
+            mValue |= FLAG_CHAR_IS_NEWLINE;
+        }
+        void SetIsLowSurrogate() {
+            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
+            mValue |= FLAG_CHAR_IS_LOW_SURROGATE;
+        }
+
+    private:
+        uint32_t mValue;
+    };
+
+    // Accessor for the array of CompressedGlyph records, which will be in
+    // a different place in gfxShapedWord vs gfxTextRun
+    virtual CompressedGlyph *GetCharacterGlyphs() = 0;
+
+    /**
+     * When the glyphs for a character don't fit into a CompressedGlyph record
+     * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
+     */
+    struct DetailedGlyph {
+        /** The glyphID, or the Unicode character
+         * if this is a missing glyph */
+        uint32_t mGlyphID;
+        /** The advance, x-offset and y-offset of the glyph, in appunits
+         *  mAdvance is in the text direction (RTL or LTR)
+         *  mXOffset is always from left to right
+         *  mYOffset is always from top to bottom */   
+        int32_t  mAdvance;
+        float    mXOffset, mYOffset;
+    };
+
+    void SetGlyphs(uint32_t aCharIndex, CompressedGlyph aGlyph,
+                   const DetailedGlyph *aGlyphs);
+
+    void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont);
+
+    void SetIsSpace(uint32_t aIndex) {
+        GetCharacterGlyphs()[aIndex].SetIsSpace();
+    }
+
+    void SetIsLowSurrogate(uint32_t aIndex) {
+        SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr);
+        GetCharacterGlyphs()[aIndex].SetIsLowSurrogate();
+    }
+
+    bool HasDetailedGlyphs() const {
+        return mDetailedGlyphs != nullptr;
+    }
+
+    bool IsLigatureGroupStart(uint32_t aPos) {
+        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
+        return GetCharacterGlyphs()[aPos].IsLigatureGroupStart();
+    }
+
+    // NOTE that this must not be called for a character offset that does
+    // not have any DetailedGlyph records; callers must have verified that
+    // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero.
+    DetailedGlyph *GetDetailedGlyphs(uint32_t aCharIndex) {
+        NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() &&
+                     !GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() &&
+                     GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0,
+                     "invalid use of GetDetailedGlyphs; check the caller!");
+        return mDetailedGlyphs->Get(aCharIndex);
+    }
+
+    void AdjustAdvancesForSyntheticBold(float aSynBoldOffset,
+                                        uint32_t aOffset, uint32_t aLength);
+
+    // Mark clusters in the CompressedGlyph records, starting at aOffset,
+    // based on the Unicode properties of the text in aString.
+    // This is also responsible to set the IsSpace flag for space characters.
+    void SetupClusterBoundaries(uint32_t         aOffset,
+                                const char16_t *aString,
+                                uint32_t         aLength);
+    // In 8-bit text, there won't actually be any clusters, but we still need
+    // the space-marking functionality.
+    void SetupClusterBoundaries(uint32_t       aOffset,
+                                const uint8_t *aString,
+                                uint32_t       aLength);
+
+    uint32_t GetFlags() const {
+        return mFlags;
+    }
+
+    bool IsRightToLeft() const {
+        return (GetFlags() & gfxTextRunFactory::TEXT_IS_RTL) != 0;
+    }
+
+    gfxFloat GetDirection() const {
+        return IsRightToLeft() ? -1.0f : 1.0f;
+    }
+
+    bool DisableLigatures() const {
+        return (GetFlags() &
+                gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) != 0;
+    }
+
+    bool TextIs8Bit() const {
+        return (GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) != 0;
+    }
+
+    int32_t GetAppUnitsPerDevUnit() const {
+        return mAppUnitsPerDevUnit;
+    }
+
+    uint32_t GetLength() const {
+        return mLength;
+    }
+
+    bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh);
+
+protected:
+    // Allocate aCount DetailedGlyphs for the given index
+    DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex,
+                                          uint32_t aCount);
+
+    // For characters whose glyph data does not fit the "simple" glyph criteria
+    // in CompressedGlyph, we use a sorted array to store the association
+    // between the source character offset and an index into an array 
+    // DetailedGlyphs. The CompressedGlyph record includes a count of
+    // the number of DetailedGlyph records that belong to the character,
+    // starting at the given index.
+    class DetailedGlyphStore {
+    public:
+        DetailedGlyphStore()
+            : mLastUsed(0)
+        { }
+
+        // This is optimized for the most common calling patterns:
+        // we rarely need random access to the records, access is most commonly
+        // sequential through the textRun, so we record the last-used index
+        // and check whether the caller wants the same record again, or the
+        // next; if not, it's most likely we're starting over from the start
+        // of the run, so we check the first entry before resorting to binary
+        // search as a last resort.
+        // NOTE that this must not be called for a character offset that does
+        // not have any DetailedGlyph records; callers must have verified that
+        // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero
+        // before calling this, otherwise the assertions here will fire (in a
+        // debug build), and we'll probably crash.
+        DetailedGlyph* Get(uint32_t aOffset) {
+            NS_ASSERTION(mOffsetToIndex.Length() > 0,
+                         "no detailed glyph records!");
+            DetailedGlyph* details = mDetails.Elements();
+            // check common cases (fwd iteration, initial entry, etc) first
+            if (mLastUsed < mOffsetToIndex.Length() - 1 &&
+                aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) {
+                ++mLastUsed;
+            } else if (aOffset == mOffsetToIndex[0].mOffset) {
+                mLastUsed = 0;
+            } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) {
+                // do nothing
+            } else if (mLastUsed > 0 &&
+                       aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) {
+                --mLastUsed;
+            } else {
+                mLastUsed =
+                    mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset());
+            }
+            NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex,
+                         "detailed glyph record missing!");
+            return details + mOffsetToIndex[mLastUsed].mIndex;
+        }
+
+        DetailedGlyph* Allocate(uint32_t aOffset, uint32_t aCount) {
+            uint32_t detailIndex = mDetails.Length();
+            DetailedGlyph *details = mDetails.AppendElements(aCount);
+            // We normally set up glyph records sequentially, so the common case
+            // here is to append new records to the mOffsetToIndex array;
+            // test for that before falling back to the InsertElementSorted
+            // method.
+            if (mOffsetToIndex.Length() == 0 ||
+                aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) {
+                mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex));
+            } else {
+                mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex),
+                                                   CompareRecordOffsets());
+            }
+            return details;
+        }
+
+        size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
+            return aMallocSizeOf(this) +
+                mDetails.SizeOfExcludingThis(aMallocSizeOf) +
+                mOffsetToIndex.SizeOfExcludingThis(aMallocSizeOf);
+        }
+
+    private:
+        struct DGRec {
+            DGRec(const uint32_t& aOffset, const uint32_t& aIndex)
+                : mOffset(aOffset), mIndex(aIndex) { }
+            uint32_t mOffset; // source character offset in the textrun
+            uint32_t mIndex;  // index where this char's DetailedGlyphs begin
+        };
+
+        struct CompareToOffset {
+            bool Equals(const DGRec& a, const uint32_t& b) const {
+                return a.mOffset == b;
+            }
+            bool LessThan(const DGRec& a, const uint32_t& b) const {
+                return a.mOffset < b;
+            }
+        };
+
+        struct CompareRecordOffsets {
+            bool Equals(const DGRec& a, const DGRec& b) const {
+                return a.mOffset == b.mOffset;
+            }
+            bool LessThan(const DGRec& a, const DGRec& b) const {
+                return a.mOffset < b.mOffset;
+            }
+        };
+
+        // Concatenated array of all the DetailedGlyph records needed for the
+        // textRun; individual character offsets are associated with indexes
+        // into this array via the mOffsetToIndex table.
+        nsTArray<DetailedGlyph>     mDetails;
+
+        // For each character offset that needs DetailedGlyphs, we record the
+        // index in mDetails where the list of glyphs begins. This array is
+        // sorted by mOffset.
+        nsTArray<DGRec>             mOffsetToIndex;
+
+        // Records the most recently used index into mOffsetToIndex, so that
+        // we can support sequential access more quickly than just doing
+        // a binary search each time.
+        nsTArray<DGRec>::index_type mLastUsed;
+    };
+
+    nsAutoPtr<DetailedGlyphStore>   mDetailedGlyphs;
+
+    // Number of char16_t characters and CompressedGlyph glyph records
+    uint32_t                        mLength;
+
+    // Shaping flags (direction, ligature-suppression)
+    uint32_t                        mFlags;
+
+    int32_t                         mAppUnitsPerDevUnit;
+};
+
+/*
+ * gfxShapedWord: an individual (space-delimited) run of text shaped with a
+ * particular font, without regard to external context.
+ *
+ * The glyph data is copied into gfxTextRuns as needed from the cache of
+ * ShapedWords associated with each gfxFont instance.
+ */
+class gfxShapedWord : public gfxShapedText
+{
+public:
+    // Create a ShapedWord that can hold glyphs for aLength characters,
+    // with mCharacterGlyphs sized appropriately.
+    //
+    // Returns null on allocation failure (does NOT use infallible alloc)
+    // so caller must check for success.
+    //
+    // This does NOT perform shaping, so the returned word contains no
+    // glyph data; the caller must call gfxFont::ShapeText() with appropriate
+    // parameters to set up the glyphs.
+    static gfxShapedWord* Create(const uint8_t *aText, uint32_t aLength,
+                                 int32_t aRunScript,
+                                 int32_t aAppUnitsPerDevUnit,
+                                 uint32_t aFlags) {
+        NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
+                     "excessive length for gfxShapedWord!");
+
+        // Compute size needed including the mCharacterGlyphs array
+        // and a copy of the original text
+        uint32_t size =
+            offsetof(gfxShapedWord, mCharGlyphsStorage) +
+            aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t));
+        void *storage = moz_malloc(size);
+        if (!storage) {
+            return nullptr;
+        }
+
+        // Construct in the pre-allocated storage, using placement new
+        return new (storage) gfxShapedWord(aText, aLength, aRunScript,
+                                           aAppUnitsPerDevUnit, aFlags);
+    }
+
+    static gfxShapedWord* Create(const char16_t *aText, uint32_t aLength,
+                                 int32_t aRunScript,
+                                 int32_t aAppUnitsPerDevUnit,
+                                 uint32_t aFlags) {
+        NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
+                     "excessive length for gfxShapedWord!");
+
+        // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
+        // then we convert the text to an 8-bit version and call the 8-bit
+        // Create function instead.
+        if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
+            nsAutoCString narrowText;
+            LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength),
+                                    narrowText);
+            return Create((const uint8_t*)(narrowText.BeginReading()),
+                          aLength, aRunScript, aAppUnitsPerDevUnit, aFlags);
+        }
+
+        uint32_t size =
+            offsetof(gfxShapedWord, mCharGlyphsStorage) +
+            aLength * (sizeof(CompressedGlyph) + sizeof(char16_t));
+        void *storage = moz_malloc(size);
+        if (!storage) {
+            return nullptr;
+        }
+
+        return new (storage) gfxShapedWord(aText, aLength, aRunScript,
+                                           aAppUnitsPerDevUnit, aFlags);
+    }
+
+    // Override operator delete to properly free the object that was
+    // allocated via moz_malloc.
+    void operator delete(void* p) {
+        moz_free(p);
+    }
+
+    CompressedGlyph *GetCharacterGlyphs() {
+        return &mCharGlyphsStorage[0];
+    }
+
+    const uint8_t* Text8Bit() const {
+        NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
+        return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength());
+    }
+
+    const char16_t* TextUnicode() const {
+        NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
+        return reinterpret_cast<const char16_t*>(mCharGlyphsStorage + GetLength());
+    }
+
+    char16_t GetCharAt(uint32_t aOffset) const {
+        NS_ASSERTION(aOffset < GetLength(), "aOffset out of range");
+        return TextIs8Bit() ?
+            char16_t(Text8Bit()[aOffset]) : TextUnicode()[aOffset];
+    }
+
+    int32_t Script() const {
+        return mScript;
+    }
+
+    void ResetAge() {
+        mAgeCounter = 0;
+    }
+    uint32_t IncrementAge() {
+        return ++mAgeCounter;
+    }
+
+    // Helper used when hashing a word for the shaped-word caches
+    static uint32_t HashMix(uint32_t aHash, char16_t aCh)
+    {
+        return (aHash >> 28) ^ (aHash << 4) ^ aCh;
+    }
+
+private:
+    // so that gfxTextRun can share our DetailedGlyphStore class
+    friend class gfxTextRun;
+
+    // Construct storage for a ShapedWord, ready to receive glyph data
+    gfxShapedWord(const uint8_t *aText, uint32_t aLength,
+                  int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
+                  uint32_t aFlags)
+        : gfxShapedText(aLength, aFlags | gfxTextRunFactory::TEXT_IS_8BIT,
+                        aAppUnitsPerDevUnit)
+        , mScript(aRunScript)
+        , mAgeCounter(0)
+    {
+        memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
+        uint8_t *text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]);
+        memcpy(text, aText, aLength * sizeof(uint8_t));
+    }
+
+    gfxShapedWord(const char16_t *aText, uint32_t aLength,
+                  int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
+                  uint32_t aFlags)
+        : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit)
+        , mScript(aRunScript)
+        , mAgeCounter(0)
+    {
+        memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
+        char16_t *text = reinterpret_cast<char16_t*>(&mCharGlyphsStorage[aLength]);
+        memcpy(text, aText, aLength * sizeof(char16_t));
+        SetupClusterBoundaries(0, aText, aLength);
+    }
+
+    int32_t          mScript;
+
+    uint32_t         mAgeCounter;
+
+    // The mCharGlyphsStorage array is actually a variable-size member;
+    // when the ShapedWord is created, its size will be increased as necessary
+    // to allow the proper number of glyphs to be stored.
+    // The original text, in either 8-bit or 16-bit form, will be stored
+    // immediately following the CompressedGlyphs.
+    CompressedGlyph  mCharGlyphsStorage[1];
+};
+
 class GlyphBufferAzure;
 struct TextRunDrawParams;
 struct FontDrawParams;
 
 class gfxFont {
 
     friend class gfxHarfBuzzShaper;
     friend class gfxGraphiteShaper;
@@ -2290,1590 +1988,39 @@ protected:
     // This helper calculates the scale factor we need to apply to the
     // synthetic-bold offset.
     static double CalcXScale(gfxContext *aContext);
 };
 
 // proportion of ascent used for x-height, if unable to read value from font
 #define DEFAULT_XHEIGHT_FACTOR 0.56f
 
-/*
- * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun.
- * These are objects that store a list of zero or more glyphs for each character.
- * For each glyph we store the glyph ID, the advance, and possibly x/y-offsets.
- * The idea is that a string is rendered by a loop that draws each glyph
- * at its designated offset from the current point, then advances the current
- * point by the glyph's advance in the direction of the textrun (LTR or RTL).
- * Each glyph advance is always rounded to the nearest appunit; this ensures
- * consistent results when dividing the text in a textrun into multiple text
- * frames (frame boundaries are always aligned to appunits). We optimize
- * for the case where a character has a single glyph and zero xoffset and yoffset,
- * and the glyph ID and advance are in a reasonable range so we can pack all
- * necessary data into 32 bits.
- *
- * gfxFontShaper can shape text into either a gfxShapedWord (cached by a gfxFont)
- * or directly into a gfxTextRun (for cases where we want to shape textruns in
- * their entirety rather than using cached words, because there may be layout
- * features that depend on the inter-word spaces).
- */
-class gfxShapedText
-{
-public:
-    gfxShapedText(uint32_t aLength, uint32_t aFlags,
-                  int32_t aAppUnitsPerDevUnit)
-        : mLength(aLength)
-        , mFlags(aFlags)
-        , mAppUnitsPerDevUnit(aAppUnitsPerDevUnit)
-    { }
-
-    virtual ~gfxShapedText() { }
-
-    /**
-     * This class records the information associated with a character in the
-     * input string. It's optimized for the case where there is one glyph
-     * representing that character alone.
-     * 
-     * A character can have zero or more associated glyphs. Each glyph
-     * has an advance width and an x and y offset.
-     * A character may be the start of a cluster.
-     * A character may be the start of a ligature group.
-     * A character can be "missing", indicating that the system is unable
-     * to render the character.
-     * 
-     * All characters in a ligature group conceptually share all the glyphs
-     * associated with the characters in a group.
-     */
-    class CompressedGlyph {
-    public:
-        CompressedGlyph() { mValue = 0; }
-
-        enum {
-            // Indicates that a cluster and ligature group starts at this
-            // character; this character has a single glyph with a reasonable
-            // advance and zero offsets. A "reasonable" advance
-            // is one that fits in the available bits (currently 12) (specified
-            // in appunits).
-            FLAG_IS_SIMPLE_GLYPH  = 0x80000000U,
-
-            // Indicates whether a linebreak is allowed before this character;
-            // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value
-            // indicating the kind of linebreak (if any) allowed here.
-            FLAGS_CAN_BREAK_BEFORE = 0x60000000U,
-
-            FLAGS_CAN_BREAK_SHIFT = 29,
-            FLAG_BREAK_TYPE_NONE   = 0,
-            FLAG_BREAK_TYPE_NORMAL = 1,
-            FLAG_BREAK_TYPE_HYPHEN = 2,
-
-            FLAG_CHAR_IS_SPACE     = 0x10000000U,
-
-            // The advance is stored in appunits
-            ADVANCE_MASK  = 0x0FFF0000U,
-            ADVANCE_SHIFT = 16,
-
-            GLYPH_MASK = 0x0000FFFFU,
-
-            // Non-simple glyphs may or may not have glyph data in the
-            // corresponding mDetailedGlyphs entry. They have the following
-            // flag bits:
-
-            // When NOT set, indicates that this character corresponds to a
-            // missing glyph and should be skipped (or possibly, render the character
-            // Unicode value in some special way). If there are glyphs,
-            // the mGlyphID is actually the UTF16 character code. The bit is
-            // inverted so we can memset the array to zero to indicate all missing.
-            FLAG_NOT_MISSING              = 0x01,
-            FLAG_NOT_CLUSTER_START        = 0x02,
-            FLAG_NOT_LIGATURE_GROUP_START = 0x04,
-
-            FLAG_CHAR_IS_TAB              = 0x08,
-            FLAG_CHAR_IS_NEWLINE          = 0x10,
-            FLAG_CHAR_IS_LOW_SURROGATE    = 0x20,
-            CHAR_IDENTITY_FLAGS_MASK      = 0x38,
-
-            GLYPH_COUNT_MASK = 0x00FFFF00U,
-            GLYPH_COUNT_SHIFT = 8
-        };
-
-        // "Simple glyphs" have a simple glyph ID, simple advance and their
-        // x and y offsets are zero. Also the glyph extents do not overflow
-        // the font-box defined by the font ascent, descent and glyph advance width.
-        // These case is optimized to avoid storing DetailedGlyphs.
-
-        // Returns true if the glyph ID aGlyph fits into the compressed representation
-        static bool IsSimpleGlyphID(uint32_t aGlyph) {
-            return (aGlyph & GLYPH_MASK) == aGlyph;
-        }
-        // Returns true if the advance aAdvance fits into the compressed representation.
-        // aAdvance is in appunits.
-        static bool IsSimpleAdvance(uint32_t aAdvance) {
-            return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
-        }
-
-        bool IsSimpleGlyph() const { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; }
-        uint32_t GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
-        uint32_t GetSimpleGlyph() const { return mValue & GLYPH_MASK; }
-
-        bool IsMissing() const { return (mValue & (FLAG_NOT_MISSING|FLAG_IS_SIMPLE_GLYPH)) == 0; }
-        bool IsClusterStart() const {
-            return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_CLUSTER_START);
-        }
-        bool IsLigatureGroupStart() const {
-            return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_LIGATURE_GROUP_START);
-        }
-        bool IsLigatureContinuation() const {
-            return (mValue & FLAG_IS_SIMPLE_GLYPH) == 0 &&
-                (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) ==
-                    (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING);
-        }
-
-        // Return true if the original character was a normal (breakable,
-        // trimmable) space (U+0020). Not true for other characters that
-        // may happen to map to the space glyph (U+00A0).
-        bool CharIsSpace() const {
-            return (mValue & FLAG_CHAR_IS_SPACE) != 0;
-        }
-
-        bool CharIsTab() const {
-            return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB) != 0;
-        }
-        bool CharIsNewline() const {
-            return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE) != 0;
-        }
-        bool CharIsLowSurrogate() const {
-            return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_LOW_SURROGATE) != 0;
-        }
-
-        uint32_t CharIdentityFlags() const {
-            return IsSimpleGlyph() ? 0 : (mValue & CHAR_IDENTITY_FLAGS_MASK);
-        }
-
-        void SetClusterStart(bool aIsClusterStart) {
-            NS_ASSERTION(!IsSimpleGlyph(),
-                         "can't call SetClusterStart on simple glyphs");
-            if (aIsClusterStart) {
-                mValue &= ~FLAG_NOT_CLUSTER_START;
-            } else {
-                mValue |= FLAG_NOT_CLUSTER_START;
-            }
-        }
-
-        uint8_t CanBreakBefore() const {
-            return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT;
-        }
-        // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
-        uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore) {
-            NS_ASSERTION(aCanBreakBefore <= 2,
-                         "Bogus break-before value!");
-            uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT);
-            uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE);
-            mValue ^= toggle;
-            return toggle;
-        }
-
-        CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) {
-            NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow");
-            NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
-            NS_ASSERTION(!CharIdentityFlags(), "Char identity flags lost");
-            mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
-                FLAG_IS_SIMPLE_GLYPH |
-                (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
-            return *this;
-        }
-        CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart,
-                uint32_t aGlyphCount) {
-            mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
-                FLAG_NOT_MISSING |
-                CharIdentityFlags() |
-                (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
-                (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
-                (aGlyphCount << GLYPH_COUNT_SHIFT);
-            return *this;
-        }
-        /**
-         * Missing glyphs are treated as ligature group starts; don't mess with
-         * the cluster-start flag (see bugs 618870 and 619286).
-         */
-        CompressedGlyph& SetMissing(uint32_t aGlyphCount) {
-            mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_NOT_CLUSTER_START |
-                                FLAG_CHAR_IS_SPACE)) |
-                CharIdentityFlags() |
-                (aGlyphCount << GLYPH_COUNT_SHIFT);
-            return *this;
-        }
-        uint32_t GetGlyphCount() const {
-            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
-            return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT;
-        }
-
-        void SetIsSpace() {
-            mValue |= FLAG_CHAR_IS_SPACE;
-        }
-        void SetIsTab() {
-            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
-            mValue |= FLAG_CHAR_IS_TAB;
-        }
-        void SetIsNewline() {
-            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
-            mValue |= FLAG_CHAR_IS_NEWLINE;
-        }
-        void SetIsLowSurrogate() {
-            NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
-            mValue |= FLAG_CHAR_IS_LOW_SURROGATE;
-        }
-
-    private:
-        uint32_t mValue;
-    };
-
-    // Accessor for the array of CompressedGlyph records, which will be in
-    // a different place in gfxShapedWord vs gfxTextRun
-    virtual CompressedGlyph *GetCharacterGlyphs() = 0;
-
-    /**
-     * When the glyphs for a character don't fit into a CompressedGlyph record
-     * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
-     */
-    struct DetailedGlyph {
-        /** The glyphID, or the Unicode character
-         * if this is a missing glyph */
-        uint32_t mGlyphID;
-        /** The advance, x-offset and y-offset of the glyph, in appunits
-         *  mAdvance is in the text direction (RTL or LTR)
-         *  mXOffset is always from left to right
-         *  mYOffset is always from top to bottom */   
-        int32_t  mAdvance;
-        float    mXOffset, mYOffset;
-    };
-
-    void SetGlyphs(uint32_t aCharIndex, CompressedGlyph aGlyph,
-                   const DetailedGlyph *aGlyphs);
-
-    void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont);
-
-    void SetIsSpace(uint32_t aIndex) {
-        GetCharacterGlyphs()[aIndex].SetIsSpace();
-    }
-
-    void SetIsLowSurrogate(uint32_t aIndex) {
-        SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr);
-        GetCharacterGlyphs()[aIndex].SetIsLowSurrogate();
-    }
-
-    bool HasDetailedGlyphs() const {
-        return mDetailedGlyphs != nullptr;
-    }
-
-    bool IsClusterStart(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return GetCharacterGlyphs()[aPos].IsClusterStart();
-    }
-
-    bool IsLigatureGroupStart(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return GetCharacterGlyphs()[aPos].IsLigatureGroupStart();
-    }
-
-    // NOTE that this must not be called for a character offset that does
-    // not have any DetailedGlyph records; callers must have verified that
-    // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero.
-    DetailedGlyph *GetDetailedGlyphs(uint32_t aCharIndex) {
-        NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() &&
-                     !GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() &&
-                     GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0,
-                     "invalid use of GetDetailedGlyphs; check the caller!");
-        return mDetailedGlyphs->Get(aCharIndex);
-    }
-
-    void AdjustAdvancesForSyntheticBold(float aSynBoldOffset,
-                                        uint32_t aOffset, uint32_t aLength);
-
-    // Mark clusters in the CompressedGlyph records, starting at aOffset,
-    // based on the Unicode properties of the text in aString.
-    // This is also responsible to set the IsSpace flag for space characters.
-    void SetupClusterBoundaries(uint32_t         aOffset,
-                                const char16_t *aString,
-                                uint32_t         aLength);
-    // In 8-bit text, there won't actually be any clusters, but we still need
-    // the space-marking functionality.
-    void SetupClusterBoundaries(uint32_t       aOffset,
-                                const uint8_t *aString,
-                                uint32_t       aLength);
-
-    uint32_t Flags() const {
-        return mFlags;
-    }
-
-    bool IsRightToLeft() const {
-        return (Flags() & gfxTextRunFactory::TEXT_IS_RTL) != 0;
-    }
-
-    float GetDirection() const {
-        return IsRightToLeft() ? -1.0f : 1.0f;
-    }
-
-    bool DisableLigatures() const {
-        return (Flags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) != 0;
-    }
-
-    bool TextIs8Bit() const {
-        return (Flags() & gfxTextRunFactory::TEXT_IS_8BIT) != 0;
-    }
+// Parameters passed to gfxFont methods for drawing glyphs from a textrun.
+// The TextRunDrawParams are set up once per textrun; the FontDrawParams
+// are dependent on the specific font, so they are set per GlyphRun.
 
-    int32_t GetAppUnitsPerDevUnit() const {
-        return mAppUnitsPerDevUnit;
-    }
-
-    uint32_t GetLength() const {
-        return mLength;
-    }
-
-    bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh);
-
-protected:
-    // Allocate aCount DetailedGlyphs for the given index
-    DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex,
-                                          uint32_t aCount);
-
-    // For characters whose glyph data does not fit the "simple" glyph criteria
-    // in CompressedGlyph, we use a sorted array to store the association
-    // between the source character offset and an index into an array 
-    // DetailedGlyphs. The CompressedGlyph record includes a count of
-    // the number of DetailedGlyph records that belong to the character,
-    // starting at the given index.
-    class DetailedGlyphStore {
-    public:
-        DetailedGlyphStore()
-            : mLastUsed(0)
-        { }
-
-        // This is optimized for the most common calling patterns:
-        // we rarely need random access to the records, access is most commonly
-        // sequential through the textRun, so we record the last-used index
-        // and check whether the caller wants the same record again, or the
-        // next; if not, it's most likely we're starting over from the start
-        // of the run, so we check the first entry before resorting to binary
-        // search as a last resort.
-        // NOTE that this must not be called for a character offset that does
-        // not have any DetailedGlyph records; callers must have verified that
-        // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero
-        // before calling this, otherwise the assertions here will fire (in a
-        // debug build), and we'll probably crash.
-        DetailedGlyph* Get(uint32_t aOffset) {
-            NS_ASSERTION(mOffsetToIndex.Length() > 0,
-                         "no detailed glyph records!");
-            DetailedGlyph* details = mDetails.Elements();
-            // check common cases (fwd iteration, initial entry, etc) first
-            if (mLastUsed < mOffsetToIndex.Length() - 1 &&
-                aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) {
-                ++mLastUsed;
-            } else if (aOffset == mOffsetToIndex[0].mOffset) {
-                mLastUsed = 0;
-            } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) {
-                // do nothing
-            } else if (mLastUsed > 0 &&
-                       aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) {
-                --mLastUsed;
-            } else {
-                mLastUsed =
-                    mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset());
-            }
-            NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex,
-                         "detailed glyph record missing!");
-            return details + mOffsetToIndex[mLastUsed].mIndex;
-        }
-
-        DetailedGlyph* Allocate(uint32_t aOffset, uint32_t aCount) {
-            uint32_t detailIndex = mDetails.Length();
-            DetailedGlyph *details = mDetails.AppendElements(aCount);
-            // We normally set up glyph records sequentially, so the common case
-            // here is to append new records to the mOffsetToIndex array;
-            // test for that before falling back to the InsertElementSorted
-            // method.
-            if (mOffsetToIndex.Length() == 0 ||
-                aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) {
-                mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex));
-            } else {
-                mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex),
-                                                   CompareRecordOffsets());
-            }
-            return details;
-        }
-
-        size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
-            return aMallocSizeOf(this) +
-                mDetails.SizeOfExcludingThis(aMallocSizeOf) +
-                mOffsetToIndex.SizeOfExcludingThis(aMallocSizeOf);
-        }
-
-    private:
-        struct DGRec {
-            DGRec(const uint32_t& aOffset, const uint32_t& aIndex)
-                : mOffset(aOffset), mIndex(aIndex) { }
-            uint32_t mOffset; // source character offset in the textrun
-            uint32_t mIndex;  // index where this char's DetailedGlyphs begin
-        };
-
-        struct CompareToOffset {
-            bool Equals(const DGRec& a, const uint32_t& b) const {
-                return a.mOffset == b;
-            }
-            bool LessThan(const DGRec& a, const uint32_t& b) const {
-                return a.mOffset < b;
-            }
-        };
-
-        struct CompareRecordOffsets {
-            bool Equals(const DGRec& a, const DGRec& b) const {
-                return a.mOffset == b.mOffset;
-            }
-            bool LessThan(const DGRec& a, const DGRec& b) const {
-                return a.mOffset < b.mOffset;
-            }
-        };
-
-        // Concatenated array of all the DetailedGlyph records needed for the
-        // textRun; individual character offsets are associated with indexes
-        // into this array via the mOffsetToIndex table.
-        nsTArray<DetailedGlyph>     mDetails;
-
-        // For each character offset that needs DetailedGlyphs, we record the
-        // index in mDetails where the list of glyphs begins. This array is
-        // sorted by mOffset.
-        nsTArray<DGRec>             mOffsetToIndex;
-
-        // Records the most recently used index into mOffsetToIndex, so that
-        // we can support sequential access more quickly than just doing
-        // a binary search each time.
-        nsTArray<DGRec>::index_type mLastUsed;
-    };
-
-    nsAutoPtr<DetailedGlyphStore>   mDetailedGlyphs;
-
-    // Number of char16_t characters and CompressedGlyph glyph records
-    uint32_t                        mLength;
-
-    // Shaping flags (direction, ligature-suppression)
-    uint32_t                        mFlags;
-
-    int32_t                         mAppUnitsPerDevUnit;
-};
-
-/*
- * gfxShapedWord: an individual (space-delimited) run of text shaped with a
- * particular font, without regard to external context.
- *
- * The glyph data is copied into gfxTextRuns as needed from the cache of
- * ShapedWords associated with each gfxFont instance.
- */
-class gfxShapedWord : public gfxShapedText
-{
-public:
-    // Create a ShapedWord that can hold glyphs for aLength characters,
-    // with mCharacterGlyphs sized appropriately.
-    //
-    // Returns null on allocation failure (does NOT use infallible alloc)
-    // so caller must check for success.
-    //
-    // This does NOT perform shaping, so the returned word contains no
-    // glyph data; the caller must call gfxFont::ShapeText() with appropriate
-    // parameters to set up the glyphs.
-    static gfxShapedWord* Create(const uint8_t *aText, uint32_t aLength,
-                                 int32_t aRunScript,
-                                 int32_t aAppUnitsPerDevUnit,
-                                 uint32_t aFlags) {
-        NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
-                     "excessive length for gfxShapedWord!");
-
-        // Compute size needed including the mCharacterGlyphs array
-        // and a copy of the original text
-        uint32_t size =
-            offsetof(gfxShapedWord, mCharGlyphsStorage) +
-            aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t));
-        void *storage = moz_malloc(size);
-        if (!storage) {
-            return nullptr;
-        }
-
-        // Construct in the pre-allocated storage, using placement new
-        return new (storage) gfxShapedWord(aText, aLength, aRunScript,
-                                           aAppUnitsPerDevUnit, aFlags);
-    }
-
-    static gfxShapedWord* Create(const char16_t *aText, uint32_t aLength,
-                                 int32_t aRunScript,
-                                 int32_t aAppUnitsPerDevUnit,
-                                 uint32_t aFlags) {
-        NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
-                     "excessive length for gfxShapedWord!");
-
-        // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
-        // then we convert the text to an 8-bit version and call the 8-bit
-        // Create function instead.
-        if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
-            nsAutoCString narrowText;
-            LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength),
-                                    narrowText);
-            return Create((const uint8_t*)(narrowText.BeginReading()),
-                          aLength, aRunScript, aAppUnitsPerDevUnit, aFlags);
-        }
-
-        uint32_t size =
-            offsetof(gfxShapedWord, mCharGlyphsStorage) +
-            aLength * (sizeof(CompressedGlyph) + sizeof(char16_t));
-        void *storage = moz_malloc(size);
-        if (!storage) {
-            return nullptr;
-        }
-
-        return new (storage) gfxShapedWord(aText, aLength, aRunScript,
-                                           aAppUnitsPerDevUnit, aFlags);
-    }
-
-    // Override operator delete to properly free the object that was
-    // allocated via moz_malloc.
-    void operator delete(void* p) {
-        moz_free(p);
-    }
-
-    CompressedGlyph *GetCharacterGlyphs() {
-        return &mCharGlyphsStorage[0];
-    }
-
-    const uint8_t* Text8Bit() const {
-        NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
-        return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength());
-    }
-
-    const char16_t* TextUnicode() const {
-        NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
-        return reinterpret_cast<const char16_t*>(mCharGlyphsStorage + GetLength());
-    }
-
-    char16_t GetCharAt(uint32_t aOffset) const {
-        NS_ASSERTION(aOffset < GetLength(), "aOffset out of range");
-        return TextIs8Bit() ?
-            char16_t(Text8Bit()[aOffset]) : TextUnicode()[aOffset];
-    }
-
-    int32_t Script() const {
-        return mScript;
-    }
-
-    void ResetAge() {
-        mAgeCounter = 0;
-    }
-    uint32_t IncrementAge() {
-        return ++mAgeCounter;
-    }
-
-private:
-    // so that gfxTextRun can share our DetailedGlyphStore class
-    friend class gfxTextRun;
-
-    // Construct storage for a ShapedWord, ready to receive glyph data
-    gfxShapedWord(const uint8_t *aText, uint32_t aLength,
-                  int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
-                  uint32_t aFlags)
-        : gfxShapedText(aLength, aFlags | gfxTextRunFactory::TEXT_IS_8BIT,
-                        aAppUnitsPerDevUnit)
-        , mScript(aRunScript)
-        , mAgeCounter(0)
-    {
-        memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
-        uint8_t *text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]);
-        memcpy(text, aText, aLength * sizeof(uint8_t));
-    }
-
-    gfxShapedWord(const char16_t *aText, uint32_t aLength,
-                  int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
-                  uint32_t aFlags)
-        : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit)
-        , mScript(aRunScript)
-        , mAgeCounter(0)
-    {
-        memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
-        char16_t *text = reinterpret_cast<char16_t*>(&mCharGlyphsStorage[aLength]);
-        memcpy(text, aText, aLength * sizeof(char16_t));
-        SetupClusterBoundaries(0, aText, aLength);
-    }
-
-    int32_t          mScript;
-
-    uint32_t         mAgeCounter;
-
-    // The mCharGlyphsStorage array is actually a variable-size member;
-    // when the ShapedWord is created, its size will be increased as necessary
-    // to allow the proper number of glyphs to be stored.
-    // The original text, in either 8-bit or 16-bit form, will be stored
-    // immediately following the CompressedGlyphs.
-    CompressedGlyph  mCharGlyphsStorage[1];
-};
-
-/**
- * Callback for Draw() to use when drawing text with mode
- * DrawMode::GLYPH_PATH.
- */
-struct gfxTextRunDrawCallbacks {
-
-    /**
-     * Constructs a new DrawCallbacks object.
-     *
-     * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be
-     *   painted and the NotifyBeforeSVGGlyphPainted/NotifyAfterSVGGlyphPainted
-     *   callbacks will be invoked for each SVG glyph.  If false, SVG glyphs
-     *   will not be painted; fallback plain glyphs are not emitted either.
-     */
-    explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false)
-      : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs)
-    {
-    }
-
-    /**
-     * Called when a path has been emitted to the gfxContext when
-     * painting a text run.  This can be called any number of times,
-     * due to partial ligatures and intervening SVG glyphs.
-     */
-    virtual void NotifyGlyphPathEmitted() = 0;
-
-    /**
-     * Called just before an SVG glyph has been painted to the gfxContext.
-     */
-    virtual void NotifyBeforeSVGGlyphPainted() { }
-
-    /**
-     * Called just after an SVG glyph has been painted to the gfxContext.
-     */
-    virtual void NotifyAfterSVGGlyphPainted() { }
-
-    bool mShouldPaintSVGGlyphs;
+struct TextRunDrawParams {
+    mozilla::RefPtr<mozilla::gfx::DrawTarget> dt;
+    gfxContext              *context;
+    gfxFont::Spacing        *spacing;
+    gfxTextRunDrawCallbacks *callbacks;
+    gfxTextContextPaint     *runContextPaint;
+    gfxFloat                 direction;
+    double                   devPerApp;
+    DrawMode                 drawMode;
+    bool                     isRTL;
+    bool                     paintSVGGlyphs;
 };
 
-/**
- * gfxTextRun is an abstraction for drawing and measuring substrings of a run
- * of text. It stores runs of positioned glyph data, each run having a single
- * gfxFont. The glyphs are associated with a string of source text, and the
- * gfxTextRun APIs take parameters that are offsets into that source text.
- * 
- * gfxTextRuns are not refcounted. They should be deleted when no longer required.
- * 
- * gfxTextRuns are mostly immutable. The only things that can change are
- * inter-cluster spacing and line break placement. Spacing is always obtained
- * lazily by methods that need it, it is not cached. Line breaks are stored
- * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
- * not actually do anything to explicitly account for line breaks). Initially
- * there are no line breaks. The textrun can record line breaks before or after
- * any given cluster. (Line breaks specified inside clusters are ignored.)
- * 
- * It is important that zero-length substrings are handled correctly. This will
- * be on the test!
- */
-class gfxTextRun : public gfxShapedText {
-public:
-
-    // Override operator delete to properly free the object that was
-    // allocated via moz_malloc.
-    void operator delete(void* p) {
-        moz_free(p);
-    }
-
-    virtual ~gfxTextRun();
-
-    typedef gfxFont::RunMetrics Metrics;
-
-    // Public textrun API for general use
-
-    bool IsClusterStart(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].IsClusterStart();
-    }
-    bool IsLigatureGroupStart(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].IsLigatureGroupStart();
-    }
-    bool CanBreakLineBefore(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].CanBreakBefore() ==
-            CompressedGlyph::FLAG_BREAK_TYPE_NORMAL;
-    }
-    bool CanHyphenateBefore(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].CanBreakBefore() ==
-            CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
-    }
-
-    bool CharIsSpace(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].CharIsSpace();
-    }
-    bool CharIsTab(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].CharIsTab();
-    }
-    bool CharIsNewline(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].CharIsNewline();
-    }
-    bool CharIsLowSurrogate(uint32_t aPos) {
-        NS_ASSERTION(aPos < GetLength(), "aPos out of range");
-        return mCharacterGlyphs[aPos].CharIsLowSurrogate();
-    }
-
-    uint32_t GetLength() { return mLength; }
-
-    // All uint32_t aStart, uint32_t aLength ranges below are restricted to
-    // grapheme cluster boundaries! All offsets are in terms of the string
-    // passed into MakeTextRun.
-    
-    // All coordinates are in layout/app units
-
-    /**
-     * Set the potential linebreaks for a substring of the textrun. These are
-     * the "allow break before" points. Initially, there are no potential
-     * linebreaks.
-     * 
-     * This can change glyphs and/or geometry! Some textruns' shapes
-     * depend on potential line breaks (e.g., title-case-converting textruns).
-     * This function is virtual so that those textruns can reshape themselves.
-     * 
-     * @return true if this changed the linebreaks, false if the new line
-     * breaks are the same as the old
-     */
-    virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
-                                          uint8_t *aBreakBefore,
-                                          gfxContext *aRefContext);
-
-    /**
-     * Layout provides PropertyProvider objects. These allow detection of
-     * potential line break points and computation of spacing. We pass the data
-     * this way to allow lazy data acquisition; for example BreakAndMeasureText
-     * will want to only ask for properties of text it's actually looking at.
-     * 
-     * NOTE that requested spacing may not actually be applied, if the textrun
-     * is unable to apply it in some context. Exception: spacing around a
-     * whitespace character MUST always be applied.
-     */
-    class PropertyProvider {
-    public:
-        // Detect hyphenation break opportunities in the given range; breaks
-        // not at cluster boundaries will be ignored.
-        virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
-                                          bool *aBreakBefore) = 0;
-
-        // Returns the provider's hyphenation setting, so callers can decide
-        // whether it is necessary to call GetHyphenationBreaks.
-        // Result is an NS_STYLE_HYPHENS_* value.
-        virtual int8_t GetHyphensOption() = 0;
-
-        // Returns the extra width that will be consumed by a hyphen. This should
-        // be constant for a given textrun.
-        virtual gfxFloat GetHyphenWidth() = 0;
-
-        typedef gfxFont::Spacing Spacing;
-
-        /**
-         * Get the spacing around the indicated characters. Spacing must be zero
-         * inside clusters. In other words, if character i is not
-         * CLUSTER_START, then character i-1 must have zero after-spacing and
-         * character i must have zero before-spacing.
-         */
-        virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
-                                Spacing *aSpacing) = 0;
-
-        // Returns a gfxContext that can be used to measure the hyphen glyph.
-        // Only called if the hyphen width is requested.
-        virtual already_AddRefed<gfxContext> GetContext() = 0;
-
-        // Return the appUnitsPerDevUnit value to be used when measuring.
-        // Only called if the hyphen width is requested.
-        virtual uint32_t GetAppUnitsPerDevUnit() = 0;
-    };
-
-    class ClusterIterator {
-    public:
-        explicit ClusterIterator(gfxTextRun *aTextRun);
-
-        void Reset();
-
-        bool NextCluster();
-
-        uint32_t Position() const {
-            return mCurrentChar;
-        }
-
-        uint32_t ClusterLength() const;
-
-        gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
-
-    private:
-        gfxTextRun *mTextRun;
-        uint32_t    mCurrentChar;
-    };
-
-    /**
-     * Draws a substring. Uses only GetSpacing from aBreakProvider.
-     * The provided point is the baseline origin on the left of the string
-     * for LTR, on the right of the string for RTL.
-     * @param aAdvanceWidth if non-null, the advance width of the substring
-     * is returned here.
-     * 
-     * Drawing should respect advance widths in the sense that for LTR runs,
-     * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
-     * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
-     *      dirty, &provider, nullptr) should have the same effect as
-     * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
-     * For RTL runs the rule is:
-     * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
-     * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
-     *      dirty, &provider, nullptr) should have the same effect as
-     * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
-     * 
-     * Glyphs should be drawn in logical content order, which can be significant
-     * if they overlap (perhaps due to negative spacing).
-     */
-    void Draw(gfxContext *aContext, gfxPoint aPt,
-              DrawMode aDrawMode,
-              uint32_t aStart, uint32_t aLength,
-              PropertyProvider *aProvider,
-              gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint,
-              gfxTextRunDrawCallbacks *aCallbacks = nullptr);
-
-    /**
-     * Computes the ReflowMetrics for a substring.
-     * Uses GetSpacing from aBreakProvider.
-     * @param aBoundingBoxType which kind of bounding box (loose/tight)
-     */
-    Metrics MeasureText(uint32_t aStart, uint32_t aLength,
-                        gfxFont::BoundingBoxType aBoundingBoxType,
-                        gfxContext *aRefContextForTightBoundingBox,
-                        PropertyProvider *aProvider);
-
-    /**
-     * Computes just the advance width for a substring.
-     * Uses GetSpacing from aBreakProvider.
-     */
-    gfxFloat GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
-                             PropertyProvider *aProvider);
-
-    /**
-     * Clear all stored line breaks for the given range (both before and after),
-     * and then set the line-break state before aStart to aBreakBefore and
-     * after the last cluster to aBreakAfter.
-     * 
-     * We require that before and after line breaks be consistent. For clusters
-     * i and i+1, we require that if there is a break after cluster i, a break
-     * will be specified before cluster i+1. This may be temporarily violated
-     * (e.g. after reflowing line L and before reflowing line L+1); to handle
-     * these temporary violations, we say that there is a break betwen i and i+1
-     * if a break is specified after i OR a break is specified before i+1.
-     * 
-     * This can change textrun geometry! The existence of a linebreak can affect
-     * the advance width of the cluster before the break (when kerning) or the
-     * geometry of one cluster before the break or any number of clusters
-     * after the break. (The one-cluster-before-the-break limit is somewhat
-     * arbitrary; if some scripts require breaking it, then we need to
-     * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
-     * it could affect the layout of frames before it...)
-     * 
-     * We return true if glyphs or geometry changed, false otherwise. This
-     * function is virtual so that gfxTextRun subclasses can reshape
-     * properly.
-     * 
-     * @param aAdvanceWidthDelta if non-null, returns the change in advance
-     * width of the given range.
-     */
-    virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength,
-                                 bool aLineBreakBefore, bool aLineBreakAfter,
-                                 gfxFloat *aAdvanceWidthDelta,
-                                 gfxContext *aRefContext);
-
-    /**
-     * Finds the longest substring that will fit into the given width.
-     * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
-     * Guarantees the following:
-     * -- 0 <= result <= aMaxLength
-     * -- result is the maximal value of N such that either
-     *       N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
-     *   OR  N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
-     *   OR  N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth
-     * where GetAdvanceWidth assumes the effect of
-     * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
-     * -- if no such N exists, then result is the smallest N such that
-     *       N < aMaxLength && line break at N
-     *   OR  N < aMaxLength && hyphen break at N
-     *   OR  N == aMaxLength
-     *
-     * The call has the effect of
-     * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider)
-     * and the returned metrics and the invariants above reflect this.
-     *
-     * @param aMaxLength this can be UINT32_MAX, in which case the length used
-     * is up to the end of the string
-     * @param aLineBreakBefore set to true if and only if there is an actual
-     * line break at the start of this string.
-     * @param aSuppressInitialBreak if true, then we assume there is no possible
-     * linebreak before aStart. If false, then we will check the internal
-     * line break opportunity state before deciding whether to return 0 as the
-     * character to break before.
-     * @param aTrimWhitespace if non-null, then we allow a trailing run of
-     * spaces to be trimmed; the width of the space(s) will not be included in
-     * the measured string width for comparison with the limit aWidth, and
-     * trimmed spaces will not be included in returned metrics. The width
-     * of the trimmed spaces will be returned in aTrimWhitespace.
-     * Trimmed spaces are still counted in the "characters fit" result.
-     * @param aMetrics if non-null, we fill this in for the returned substring.
-     * If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
-     * @param aBoundingBoxType whether to make the bounding box in aMetrics tight
-     * @param aRefContextForTightBoundingBox a reference context to get the
-     * tight bounding box, if requested
-     * @param aUsedHyphenation if non-null, records if we selected a hyphenation break
-     * @param aLastBreak if non-null and result is aMaxLength, we set this to
-     * the maximal N such that
-     *       N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
-     *   OR  N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
-     * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
-     * the effect of
-     * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
-     *
-     * @param aCanWordWrap true if we can break between any two grapheme
-     * clusters. This is set by word-wrap: break-word
-     *
-     * @param aBreakPriority in/out the priority of the break opportunity
-     * saved in the line. If we are prioritizing break opportunities, we will
-     * not set a break with a lower priority. @see gfxBreakPriority.
-     * 
-     * Note that negative advance widths are possible especially if negative
-     * spacing is provided.
-     */
-    uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
-                                 bool aLineBreakBefore, gfxFloat aWidth,
-                                 PropertyProvider *aProvider,
-                                 bool aSuppressInitialBreak,
-                                 gfxFloat *aTrimWhitespace,
-                                 Metrics *aMetrics,
-                                 gfxFont::BoundingBoxType aBoundingBoxType,
-                                 gfxContext *aRefContextForTightBoundingBox,
-                                 bool *aUsedHyphenation,
-                                 uint32_t *aLastBreak,
-                                 bool aCanWordWrap,
-                                 gfxBreakPriority *aBreakPriority);
-
-    /**
-     * Update the reference context.
-     * XXX this is a hack. New text frame does not call this. Use only
-     * temporarily for old text frame.
-     */
-    void SetContext(gfxContext *aContext) {}
-
-    // Utility getters
-
-    gfxFloat GetDirection() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) ? -1.0 : 1.0; }
-    void *GetUserData() const { return mUserData; }
-    void SetUserData(void *aUserData) { mUserData = aUserData; }
-    uint32_t GetFlags() const { return mFlags; }
-    void SetFlagBits(uint32_t aFlags) {
-      NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
-                   "Only user flags should be mutable");
-      mFlags |= aFlags;
-    }
-    void ClearFlagBits(uint32_t aFlags) {
-      NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
-                   "Only user flags should be mutable");
-      mFlags &= ~aFlags;
-    }
-    const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
-    gfxFontGroup *GetFontGroup() const { return mFontGroup; }
-
-
-    // Call this, don't call "new gfxTextRun" directly. This does custom
-    // allocation and initialization
-    static gfxTextRun *Create(const gfxTextRunFactory::Parameters *aParams,
-                              uint32_t aLength, gfxFontGroup *aFontGroup,
-                              uint32_t aFlags);
-
-    // The text is divided into GlyphRuns as necessary
-    struct GlyphRun {
-        nsRefPtr<gfxFont> mFont;   // never null
-        uint32_t          mCharacterOffset; // into original UTF16 string
-        uint8_t           mMatchType;
-    };
-
-    class GlyphRunIterator {
-    public:
-        GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength)
-          : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
-            mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
-        }
-        bool NextRun();
-        GlyphRun *GetGlyphRun() { return mGlyphRun; }
-        uint32_t GetStringStart() { return mStringStart; }
-        uint32_t GetStringEnd() { return mStringEnd; }
-    private:
-        gfxTextRun *mTextRun;
-        GlyphRun   *mGlyphRun;
-        uint32_t    mStringStart;
-        uint32_t    mStringEnd;
-        uint32_t    mNextIndex;
-        uint32_t    mStartOffset;
-        uint32_t    mEndOffset;
-    };
-
-    class GlyphRunOffsetComparator {
-    public:
-        bool Equals(const GlyphRun& a,
-                      const GlyphRun& b) const
-        {
-            return a.mCharacterOffset == b.mCharacterOffset;
-        }
-
-        bool LessThan(const GlyphRun& a,
-                        const GlyphRun& b) const
-        {
-            return a.mCharacterOffset < b.mCharacterOffset;
-        }
-    };
-
-    friend class GlyphRunIterator;
-    friend class FontSelector;
-
-    // API for setting up the textrun glyphs. Should only be called by
-    // things that construct textruns.
-    /**
-     * We've found a run of text that should use a particular font. Call this
-     * only during initialization when font substitution has been computed.
-     * Call it before setting up the glyphs for the characters in this run;
-     * SetMissingGlyph requires that the correct glyphrun be installed.
-     *
-     * If aForceNewRun, a new glyph run will be added, even if the
-     * previously added run uses the same font.  If glyph runs are
-     * added out of strictly increasing aStartCharIndex order (via
-     * force), then SortGlyphRuns must be called after all glyph runs
-     * are added before any further operations are performed with this
-     * TextRun.
-     */
-    nsresult AddGlyphRun(gfxFont *aFont, uint8_t aMatchType,
-                         uint32_t aStartCharIndex, bool aForceNewRun);
-    void ResetGlyphRuns() { mGlyphRuns.Clear(); }
-    void SortGlyphRuns();
-    void SanitizeGlyphRuns();
-
-    CompressedGlyph* GetCharacterGlyphs() {
-        NS_ASSERTION(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
-        return mCharacterGlyphs;
-    }
-
-    // clean out results from shaping in progress, used for fallback scenarios
-    void ClearGlyphsAndCharacters();
-
-    void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex);
-
-    // Set the glyph data for the given character index to the font's
-    // space glyph, IF this can be done as a "simple" glyph record
-    // (not requiring a DetailedGlyph entry). This avoids the need to call
-    // the font shaper and go through the shaped-word cache for most spaces.
-    //
-    // The parameter aSpaceChar is the original character code for which
-    // this space glyph is being used; if this is U+0020, we need to record
-    // that it could be trimmed at a run edge, whereas other kinds of space
-    // (currently just U+00A0) would not be trimmable/breakable.
-    //
-    // Returns true if it was able to set simple glyph data for the space;
-    // if it returns false, the caller needs to fall back to some other
-    // means to create the necessary (detailed) glyph data.
-    bool SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext,
-                               uint32_t aCharIndex, char16_t aSpaceChar);
-
-    // Record the positions of specific characters that layout may need to
-    // detect in the textrun, even though it doesn't have an explicit copy
-    // of the original text. These are recorded using flag bits in the
-    // CompressedGlyph record; if necessary, we convert "simple" glyph records
-    // to "complex" ones as the Tab and Newline flags are not present in
-    // simple CompressedGlyph records.
-    void SetIsTab(uint32_t aIndex) {
-        CompressedGlyph *g = &mCharacterGlyphs[aIndex];
-        if (g->IsSimpleGlyph()) {
-            DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
-            details->mGlyphID = g->GetSimpleGlyph();
-            details->mAdvance = g->GetSimpleAdvance();
-            details->mXOffset = details->mYOffset = 0;
-            SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details);
-        }
-        g->SetIsTab();
-    }
-    void SetIsNewline(uint32_t aIndex) {
-        CompressedGlyph *g = &mCharacterGlyphs[aIndex];
-        if (g->IsSimpleGlyph()) {
-            DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
-            details->mGlyphID = g->GetSimpleGlyph();
-            details->mAdvance = g->GetSimpleAdvance();
-            details->mXOffset = details->mYOffset = 0;
-            SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details);
-        }
-        g->SetIsNewline();
-    }
-    void SetIsLowSurrogate(uint32_t aIndex) {
-        SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr);
-        mCharacterGlyphs[aIndex].SetIsLowSurrogate();
-    }
-
-    /**
-     * Prefetch all the glyph extents needed to ensure that Measure calls
-     * on this textrun not requesting tight boundingBoxes will succeed. Note
-     * that some glyph extents might not be fetched due to OOM or other
-     * errors.
-     */
-    void FetchGlyphExtents(gfxContext *aRefContext);
-
-    uint32_t CountMissingGlyphs();
-    const GlyphRun *GetGlyphRuns(uint32_t *aNumGlyphRuns) {
-        *aNumGlyphRuns = mGlyphRuns.Length();
-        return mGlyphRuns.Elements();
-    }
-    // Returns the index of the GlyphRun containing the given offset.
-    // Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
-    uint32_t FindFirstGlyphRunContaining(uint32_t aOffset);
-
-    // Copy glyph data from a ShapedWord into this textrun.
-    void CopyGlyphDataFrom(gfxShapedWord *aSource, uint32_t aStart);
-
-    // Copy glyph data for a range of characters from aSource to this
-    // textrun.
-    void CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
-                           uint32_t aLength, uint32_t aDest);
-
-    nsExpirationState *GetExpirationState() { return &mExpirationState; }
-
-    // Tell the textrun to release its reference to its creating gfxFontGroup
-    // immediately, rather than on destruction. This is used for textruns
-    // that are actually owned by a gfxFontGroup, so that they don't keep it
-    // permanently alive due to a circular reference. (The caller of this is
-    // taking responsibility for ensuring the textrun will not outlive its
-    // mFontGroup.)
-    void ReleaseFontGroup();
-
-    struct LigatureData {
-        // textrun offsets of the start and end of the containing ligature
-        uint32_t mLigatureStart;
-        uint32_t mLigatureEnd;
-        // appunits advance to the start of the ligature part within the ligature;
-        // never includes any spacing
-        gfxFloat mPartAdvance;
-        // appunits width of the ligature part; includes before-spacing
-        // when the part is at the start of the ligature, and after-spacing
-        // when the part is as the end of the ligature
-        gfxFloat mPartWidth;
-        
-        bool mClipBeforePart;
-        bool mClipAfterPart;
-    };
-    
-    // return storage used by this run, for memory reporter;
-    // nsTransformedTextRun needs to override this as it holds additional data
-    virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
-      MOZ_MUST_OVERRIDE;
-    virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
-      MOZ_MUST_OVERRIDE;
-
-    // Get the size, if it hasn't already been gotten, marking as it goes.
-    size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)  {
-        if (mFlags & gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED) {
-            return 0;
-        }
-        mFlags |= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED;
-        return SizeOfIncludingThis(aMallocSizeOf);
-    }
-    void ResetSizeOfAccountingFlags() {
-        mFlags &= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED;
-    }
-
-    // shaping state - for some font features, fallback is required that
-    // affects the entire run. for example, fallback for one script/font
-    // portion of a textrun requires fallback to be applied to the entire run
-
-    enum ShapingState {
-        eShapingState_Normal,                 // default state
-        eShapingState_ShapingWithFeature,     // have shaped with feature
-        eShapingState_ShapingWithFallback,    // have shaped with fallback
-        eShapingState_Aborted,                // abort initial iteration
-        eShapingState_ForceFallbackFeature    // redo with fallback forced on
-    };
-
-    ShapingState GetShapingState() const { return mShapingState; }
-    void SetShapingState(ShapingState aShapingState) {
-        mShapingState = aShapingState;
-    }
-
-#ifdef DEBUG
-    void Dump(FILE* aOutput);
-#endif
-
-protected:
-    /**
-     * Create a textrun, and set its mCharacterGlyphs to point immediately
-     * after the base object; this is ONLY used in conjunction with placement
-     * new, after allocating a block large enough for the glyph records to
-     * follow the base textrun object.
-     */
-    gfxTextRun(const gfxTextRunFactory::Parameters *aParams,
-               uint32_t aLength, gfxFontGroup *aFontGroup, uint32_t aFlags);
-
-    /**
-     * Helper for the Create() factory method to allocate the required
-     * glyph storage for a textrun object with the basic size aSize,
-     * plus room for aLength glyph records.
-     */
-    static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength);
-
-    // Pointer to the array of CompressedGlyph records; must be initialized
-    // when the object is constructed.
-    CompressedGlyph *mCharacterGlyphs;
-
-private:
-    // **** general helpers **** 
-
-    // Get the total advance for a range of glyphs.
-    int32_t GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd);
-
-    // Spacing for characters outside the range aSpacingStart/aSpacingEnd
-    // is assumed to be zero; such characters are not passed to aProvider.
-    // This is useful to protect aProvider from being passed character indices
-    // it is not currently able to handle.
-    bool GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd,
-                                   PropertyProvider *aProvider,
-                                   uint32_t aSpacingStart, uint32_t aSpacingEnd,
-                                   nsTArray<PropertyProvider::Spacing> *aSpacing);
-
-    //  **** ligature helpers ****
-    // (Platforms do the actual ligaturization, but we need to do a bunch of stuff
-    // to handle requests that begin or end inside a ligature)
-
-    // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
-    LigatureData ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
-                                     PropertyProvider *aProvider);
-    gfxFloat ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd,
-                                         PropertyProvider *aProvider);
-    void DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
-                             gfxPoint *aPt, PropertyProvider *aProvider,
-                             TextRunDrawParams& aParams);
-    // Advance aStart to the start of the nearest ligature; back up aEnd
-    // to the nearest ligature end; may result in *aStart == *aEnd
-    void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd);
-    // result in appunits
-    gfxFloat GetPartialLigatureWidth(uint32_t aStart, uint32_t aEnd, PropertyProvider *aProvider);
-    void AccumulatePartialLigatureMetrics(gfxFont *aFont,
-                                          uint32_t aStart, uint32_t aEnd,
-                                          gfxFont::BoundingBoxType aBoundingBoxType,
-                                          gfxContext *aRefContext,
-                                          PropertyProvider *aProvider,
-                                          Metrics *aMetrics);
-
-    // **** measurement helper ****
-    void AccumulateMetricsForRun(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
-                                 gfxFont::BoundingBoxType aBoundingBoxType,
-                                 gfxContext *aRefContext,
-                                 PropertyProvider *aProvider,
-                                 uint32_t aSpacingStart, uint32_t aSpacingEnd,
-                                 Metrics *aMetrics);
-
-    // **** drawing helper ****
-    void DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
-                    gfxPoint *aPt, PropertyProvider *aProvider,
-                    uint32_t aSpacingStart, uint32_t aSpacingEnd,
-                    TextRunDrawParams& aParams);
-
-    // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
-    // for smaller size especially in the super-common one-glyphrun case
-    nsAutoTArray<GlyphRun,1>        mGlyphRuns;
-
-    void             *mUserData;
-    gfxFontGroup     *mFontGroup; // addrefed on creation, but our reference
-                                  // may be released by ReleaseFontGroup()
-    gfxSkipChars      mSkipChars;
-    nsExpirationState mExpirationState;
-
-    bool              mSkipDrawing; // true if the font group we used had a user font
-                                    // download that's in progress, so we should hide text
-                                    // until the download completes (or timeout fires)
-    bool              mReleasedFontGroup; // we already called NS_RELEASE on
-                                          // mFontGroup, so don't do it again
-
-    // shaping state for handling variant fallback features
-    // such as subscript/superscript variant glyphs
-    ShapingState      mShapingState;
+struct FontDrawParams {
+    mozilla::RefPtr<mozilla::gfx::ScaledFont>            scaledFont;
+    mozilla::RefPtr<mozilla::gfx::GlyphRenderingOptions> renderingOptions;
+    gfxTextContextPaint      *contextPaint;
+    mozilla::gfx::Matrix     *passedInvMatrix;
+    mozilla::gfx::Matrix      matInv;
+    double                    synBoldOnePixelOffset;
+    int32_t                   extraStrikes;
+    mozilla::gfx::DrawOptions drawOptions;
+    bool                      haveSVGGlyphs;
+    bool                      haveColorGlyphs;
 };
 
-class gfxFontGroup : public gfxTextRunFactory {
-public:
-    class FamilyFace {
-    public:
-        FamilyFace() { }
-
-        FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
-            : mFamily(aFamily), mFont(aFont)
-        {
-            NS_ASSERTION(aFont, "font pointer must not be null");
-            NS_ASSERTION(!aFamily ||
-                         aFamily->ContainsFace(aFont->GetFontEntry()),
-                         "font is not a member of the given family");
-        }
-
-        gfxFontFamily* Family() const { return mFamily.get(); }
-        gfxFont* Font() const { return mFont.get(); }
-
-    private:
-        nsRefPtr<gfxFontFamily> mFamily;
-        nsRefPtr<gfxFont>       mFont;
-    };
-
-    static void Shutdown(); // platform must call this to release the languageAtomService
-
-    gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
-                 const gfxFontStyle *aStyle,
-                 gfxUserFontSet *aUserFontSet = nullptr);
-
-    virtual ~gfxFontGroup();
-
-    virtual gfxFont *GetFontAt(int32_t i) {
-        // If it turns out to be hard for all clients that cache font
-        // groups to call UpdateFontList at appropriate times, we could
-        // instead consider just calling UpdateFontList from someplace
-        // more central (such as here).
-        NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
-                     "Whoever was caching this font group should have "
-                     "called UpdateFontList on it");
-        NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(), 
-                     "Requesting a font index that doesn't exist");
-
-        return mFonts[i].Font();
-    }
-
-    // Returns the first font in the font-group that has an OpenType MATH table,
-    // or null if no such font is available. The GetMathConstant methods may be
-    // called on the returned font.
-    gfxFont *GetFirstMathFont();
-
-    uint32_t FontListLength() const {
-        return mFonts.Length();
-    }
-
-    const gfxFontStyle *GetStyle() const { return &mStyle; }
-
-    virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
-
-    /**
-     * The listed characters should be treated as invisible and zero-width
-     * when creating textruns.
-     */
-    static bool IsInvalidChar(uint8_t ch);
-    static bool IsInvalidChar(char16_t ch);
-
-    /**
-     * Make a textrun for a given string.
-     * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
-     * textrun will copy it.
-     * This calls FetchGlyphExtents on the textrun.
-     */
-    virtual gfxTextRun *MakeTextRun(const char16_t *aString, uint32_t aLength,
-                                    const Parameters *aParams, uint32_t aFlags);
-    /**
-     * Make a textrun for a given string.
-     * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
-     * textrun will copy it.
-     * This calls FetchGlyphExtents on the textrun.
-     */
-    virtual gfxTextRun *MakeTextRun(const uint8_t *aString, uint32_t aLength,
-                                    const Parameters *aParams, uint32_t aFlags);
-
-    /**
-     * Textrun creation helper for clients that don't want to pass
-     * a full Parameters record.
-     */
-    template<typename T>
-    gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength,
-                            gfxContext *aRefContext,
-                            int32_t aAppUnitsPerDevUnit,
-                            uint32_t aFlags)
-    {
-        gfxTextRunFactory::Parameters params = {
-            aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit
-        };
-        return MakeTextRun(aString, aLength, &params, aFlags);
-    }
-
-    /**
-     * Get the (possibly-cached) width of the hyphen character.
-     * The aCtx and aAppUnitsPerDevUnit parameters will be used only if
-     * needed to initialize the cached hyphen width; otherwise they are
-     * ignored.
-     */
-    gfxFloat GetHyphenWidth(gfxTextRun::PropertyProvider* aProvider);
-
-    /**
-     * Make a text run representing a single hyphen character.
-     * This will use U+2010 HYPHEN if available in the first font,
-     * otherwise fall back to U+002D HYPHEN-MINUS.
-     * The caller is responsible for deleting the returned text run
-     * when no longer required.
-     */
-    gfxTextRun *MakeHyphenTextRun(gfxContext *aCtx,
-                                  uint32_t aAppUnitsPerDevUnit);
-
-    /**
-     * Check whether a given font (specified by its gfxFontEntry)
-     * is already in the fontgroup's list of actual fonts
-     */
-    bool HasFont(const gfxFontEntry *aFontEntry);
-
-    // This returns the preferred underline for this font group.
-    // Some CJK fonts have wrong underline offset in its metrics.
-    // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset.
-    // The value should be lower value of first font's metrics and the bad font's metrics.
-    // Otherwise, this returns from first font's metrics.
-    enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX };
-    virtual gfxFloat GetUnderlineOffset() {
-        if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET)
-            mUnderlineOffset = GetFontAt(0)->GetMetrics().underlineOffset;
-        return mUnderlineOffset;
-    }
-
-    virtual already_AddRefed<gfxFont>
-        FindFontForChar(uint32_t ch, uint32_t prevCh, int32_t aRunScript,
-                        gfxFont *aPrevMatchedFont,
-                        uint8_t *aMatchType);
-
-    // search through pref fonts for a character, return nullptr if no matching pref font
-    virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
-
-    virtual already_AddRefed<gfxFont>
-        WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript);
-
-    template<typename T>
-    void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
-                       const T *aString, uint32_t aLength,
-                       int32_t aRunScript);
-
-    gfxUserFontSet* GetUserFontSet();
-
-    // With downloadable fonts, the composition of the font group can change as fonts are downloaded
-    // for each change in state of the user font set, the generation value is bumped to avoid picking up
-    // previously created text runs in the text run word cache.  For font groups based on stylesheets
-    // with no @font-face rule, this always returns 0.
-    uint64_t GetGeneration();
-
-    // used when logging text performance
-    gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; }
-    void SetTextPerfMetrics(gfxTextPerfMetrics *aTextPerf) { mTextPerf = aTextPerf; }
-
-    // This will call UpdateFontList() if the user font set is changed.
-    void SetUserFontSet(gfxUserFontSet *aUserFontSet);
-
-    // If there is a user font set, check to see whether the font list or any
-    // caches need updating.
-    virtual void UpdateFontList();
-
-    bool ShouldSkipDrawing() const {
-        return mSkipDrawing;
-    }
-
-    class LazyReferenceContextGetter {
-    public:
-      virtual already_AddRefed<gfxContext> GetRefContext() = 0;
-    };
-    // The gfxFontGroup keeps ownership of this textrun.
-    // It is only guaranteed to exist until the next call to GetEllipsisTextRun
-    // (which might use a different appUnitsPerDev value) for the font group,
-    // or until UpdateFontList is called, or the fontgroup is destroyed.
-    // Get it/use it/forget it :) - don't keep a reference that might go stale.
-    gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
-                                   LazyReferenceContextGetter& aRefContextGetter);
-
-    // helper method for resolving generic font families
-    static void
-    ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
-                            nsIAtom *aLanguage,
-                            nsTArray<nsString>& aGenericFamilies);
-
-protected:
-    mozilla::FontFamilyList mFamilyList;
-    gfxFontStyle mStyle;
-    nsTArray<FamilyFace> mFonts;
-    gfxFloat mUnderlineOffset;
-    gfxFloat mHyphenWidth;
-
-    nsRefPtr<gfxUserFontSet> mUserFontSet;
-    uint64_t mCurrGeneration;  // track the current user font set generation, rebuild font list if needed
-
-    gfxTextPerfMetrics *mTextPerf;
-
-    // Cache a textrun representing an ellipsis (useful for CSS text-overflow)
-    // at a specific appUnitsPerDevPixel size
-    nsAutoPtr<gfxTextRun>   mCachedEllipsisTextRun;
-
-    // cache the most recent pref font to avoid general pref font lookup
-    nsRefPtr<gfxFontFamily> mLastPrefFamily;
-    nsRefPtr<gfxFont>       mLastPrefFont;
-    eFontPrefLang           mLastPrefLang;       // lang group for last pref font
-    eFontPrefLang           mPageLang;
-    bool                    mLastPrefFirstFont;  // is this the first font in the list of pref fonts for this lang group?
-
-    bool                    mSkipDrawing; // hide text while waiting for a font
-                                          // download to complete (or fallback
-                                          // timer to fire)
-
-    /**
-     * Textrun creation short-cuts for special cases where we don't need to
-     * call a font shaper to generate glyphs.
-     */
-    gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags);
-    gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags);
-    gfxTextRun *MakeBlankTextRun(uint32_t aLength,
-                                 const Parameters *aParams, uint32_t aFlags);
-
-    // Initialize the list of fonts
-    void BuildFontList();
-
-    // Init this font group's font metrics. If there no bad fonts, you don't need to call this.
-    // But if there are one or more bad fonts which have bad underline offset,
-    // you should call this with the *first* bad font.
-    void InitMetricsForBadFont(gfxFont* aBadFont);
-
-    // Set up the textrun glyphs for an entire text run:
-    // find script runs, and then call InitScriptRun for each
-    template<typename T>
-    void InitTextRun(gfxContext *aContext,
-                     gfxTextRun *aTextRun,
-                     const T *aString,
-                     uint32_t aLength);
-
-    // InitTextRun helper to handle a single script run, by finding font ranges
-    // and calling each font's InitTextRun() as appropriate
-    template<typename T>
-    void InitScriptRun(gfxContext *aContext,
-                       gfxTextRun *aTextRun,
-                       const T *aString,
-                       uint32_t aScriptRunStart,
-                       uint32_t aScriptRunEnd,
-                       int32_t aRunScript);
-
-    // Helper for font-matching:
-    // see if aCh is supported in any of the faces from aFamily;
-    // if so return the best style match, else return null.
-    already_AddRefed<gfxFont> TryAllFamilyMembers(gfxFontFamily* aFamily,
-                                                  uint32_t aCh);
-
-    // helper methods for looking up fonts
-
-    // iterate over the fontlist, lookup names and expand generics
-    void EnumerateFontList(nsIAtom *aLanguage, void *aClosure = nullptr);
-
-    // expand a generic to a list of specific names based on prefs
-    void FindGenericFonts(mozilla::FontFamilyType aGenericType,
-                          nsIAtom *aLanguage,
-                          void *aClosure);
-
-    // lookup and add a font with a given name (i.e. *not* a generic!)
-    virtual void FindPlatformFont(const nsAString& aName,
-                                  bool aUseFontSet,
-                                  void *aClosure);
-
-    static nsILanguageAtomService* gLangService;
-};
 #endif
copy from gfx/thebes/gfxFont.cpp
copy to gfx/thebes/gfxFontEntry.cpp
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -11,99 +11,60 @@
 #endif
 #include "prlog.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsExpirationTracker.h"
 #include "nsILanguageAtomService.h"
 #include "nsITimer.h"
 
-#include "gfxFont.h"
+#include "gfxFontEntry.h"
+#include "gfxTextRun.h"
 #include "gfxPlatform.h"
 #include "nsGkAtoms.h"
 
 #include "gfxTypes.h"
 #include "gfxContext.h"
-#include "gfxFontMissingGlyphs.h"
-#include "gfxGraphiteShaper.h"
+#include "gfxFontConstants.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxUserFontSet.h"
 #include "gfxPlatformFontList.h"
-#include "gfxScriptItemizer.h"
-#include "nsSpecialCasingData.h"
-#include "nsTextRunTransformations.h"
 #include "nsUnicodeProperties.h"
 #include "nsMathUtils.h"
 #include "nsBidiUtils.h"
 #include "nsUnicodeRange.h"
 #include "nsStyleConsts.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "gfxSVGGlyphs.h"
 #include "gfxMathTable.h"
 #include "gfx2DGlue.h"
 
-#include "GreekCasing.h"
-
 #if defined(XP_MACOSX)
 #include "nsCocoaFeatures.h"
 #endif
 
 #include "cairo.h"
-#include "gfxFontTest.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "graphite2/Font.h"
 
-#include "nsCRT.h"
-#include "GeckoProfiler.h"
-#include "gfxFontConstants.h"
-
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 using mozilla::services::GetObserverService;
 
-gfxFontCache *gfxFontCache::gGlobalCache = nullptr;
-
-static const char16_t kEllipsisChar[] = { 0x2026, 0x0 };
-static const char16_t kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 };
-
-#ifdef DEBUG_roc
-#define DEBUG_TEXT_RUN_STORAGE_METRICS
-#endif
-
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-static uint32_t gTextRunStorageHighWaterMark = 0;
-static uint32_t gTextRunStorage = 0;
-static uint32_t gFontCount = 0;
-static uint32_t gGlyphExtentsCount = 0;
-static uint32_t gGlyphExtentsWidthsTotalSize = 0;
-static uint32_t gGlyphExtentsSetupEagerSimple = 0;
-static uint32_t gGlyphExtentsSetupEagerTight = 0;
-static uint32_t gGlyphExtentsSetupLazyTight = 0;
-static uint32_t gGlyphExtentsSetupFallBackToTight = 0;
-#endif
-
-#ifdef PR_LOGGING
-#define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
-                                  PR_LOG_DEBUG, args)
-#define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
-                                        gfxPlatform::GetLog(eGfxLog_fontinit), \
-                                        PR_LOG_DEBUG)
-#endif // PR_LOGGING
-
 void
 gfxCharacterMap::NotifyReleased()
 {
     gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
     if (mShared) {
         fontlist->RemoveCmap(this);
     }
     delete this;
@@ -1852,6148 +1813,8 @@ gfxFontFamily::AddSizeOfExcludingThis(Ma
 
 void
 gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                       FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
-
-/*
- * gfxFontCache - global cache of gfxFont instances.
- * Expires unused fonts after a short interval;
- * notifies fonts to age their cached shaped-word records;
- * observes memory-pressure notification and tells fonts to clear their
- * shaped-word caches to free up memory.
- */
-
-MOZ_DEFINE_MALLOC_SIZE_OF(FontCacheMallocSizeOf)
-
-NS_IMPL_ISUPPORTS(gfxFontCache::MemoryReporter, nsIMemoryReporter)
-
-NS_IMETHODIMP
-gfxFontCache::MemoryReporter::CollectReports(
-    nsIMemoryReporterCallback* aCb, nsISupports* aClosure, bool aAnonymize)
-{
-    FontCacheSizes sizes;
-
-    gfxFontCache::GetCache()->AddSizeOfIncludingThis(&FontCacheMallocSizeOf,
-                                                     &sizes);
-
-    aCb->Callback(EmptyCString(),
-                  NS_LITERAL_CSTRING("explicit/gfx/font-cache"),
-                  KIND_HEAP, UNITS_BYTES, sizes.mFontInstances,
-                  NS_LITERAL_CSTRING("Memory used for active font instances."),
-                  aClosure);
-
-    aCb->Callback(EmptyCString(),
-                  NS_LITERAL_CSTRING("explicit/gfx/font-shaped-words"),
-                  KIND_HEAP, UNITS_BYTES, sizes.mShapedWords,
-                  NS_LITERAL_CSTRING("Memory used to cache shaped glyph data."),
-                  aClosure);
-
-    return NS_OK;
-}
-
-NS_IMPL_ISUPPORTS(gfxFontCache::Observer, nsIObserver)
-
-NS_IMETHODIMP
-gfxFontCache::Observer::Observe(nsISupports *aSubject,
-                                const char *aTopic,
-                                const char16_t *someData)
-{
-    if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
-        gfxFontCache *fontCache = gfxFontCache::GetCache();
-        if (fontCache) {
-            fontCache->FlushShapedWordCaches();
-        }
-    } else {
-        NS_NOTREACHED("unexpected notification topic");
-    }
-    return NS_OK;
-}
-
-nsresult
-gfxFontCache::Init()
-{
-    NS_ASSERTION(!gGlobalCache, "Where did this come from?");
-    gGlobalCache = new gfxFontCache();
-    if (!gGlobalCache) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-    RegisterStrongMemoryReporter(new MemoryReporter());
-    return NS_OK;
-}
-
-void
-gfxFontCache::Shutdown()
-{
-    delete gGlobalCache;
-    gGlobalCache = nullptr;
-
-#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
-    printf("Textrun storage high water mark=%d\n", gTextRunStorageHighWaterMark);
-    printf("Total number of fonts=%d\n", gFontCount);
-    printf("Total glyph extents allocated=%d (size %d)\n", gGlyphExtentsCount,
-            int(gGlyphExtentsCount*sizeof(gfxGlyphExtents)));
-    printf("Total glyph extents width-storage size allocated=%d\n", gGlyphExtentsWidthsTotalSize);
-    printf("Number of simple glyph extents eagerly requested=%d\n", gGlyphExtentsSetupEagerSimple);
-    printf("Number of tight glyph extents eagerly requested=%d\n", gGlyphExtentsSetupEagerTight);
-    printf("Number of tight glyph extents lazily requested=%d\n", gGlyphExtentsSetupLazyTight);
-    printf("Number of simple glyph extent setups that fell back to tight=%d\n", gGlyphExtentsSetupFallBackToTight);
-#endif
-}
-
-gfxFontCache::gfxFontCache()
-    : nsExpirationTracker<gfxFont,3>(FONT_TIMEOUT_SECONDS * 1000)
-{
-    nsCOMPtr<nsIObserverService> obs = GetObserverService();
-    if (obs) {
-        obs->AddObserver(new Observer, "memory-pressure", false);
-    }
-
-#ifndef RELEASE_BUILD
-    // Currently disabled for release builds, due to unexplained crashes
-    // during expiration; see bug 717175 & 894798.
-    mWordCacheExpirationTimer = do_CreateInstance("@mozilla.org/timer;1");
-    if (mWordCacheExpirationTimer) {
-        mWordCacheExpirationTimer->
-            InitWithFuncCallback(WordCacheExpirationTimerCallback, this,
-                                 SHAPED_WORD_TIMEOUT_SECONDS * 1000,
-                                 nsITimer::TYPE_REPEATING_SLACK);
-    }
-#endif
-}
-
-gfxFontCache::~gfxFontCache()
-{
-    // Ensure the user font cache releases its references to font entries,
-    // so they aren't kept alive after the font instances and font-list
-    // have been shut down.
-    gfxUserFontSet::UserFontCache::Shutdown();
-
-    if (mWordCacheExpirationTimer) {
-        mWordCacheExpirationTimer->Cancel();
-        mWordCacheExpirationTimer = nullptr;
-    }
-
-    // Expire everything that has a zero refcount, so we don't leak them.
-    AgeAllGenerations();
-    // All fonts should be gone.
-    NS_WARN_IF_FALSE(mFonts.Count() == 0,
-                     "Fonts still alive while shutting down gfxFontCache");
-    // Note that we have to delete everything through the expiration
-    // tracker, since there might be fonts not in the hashtable but in
-    // the tracker.
-}
-
-bool
-gfxFontCache::HashEntry::KeyEquals(const KeyTypePointer aKey) const
-{
-    return aKey->mFontEntry == mFont->GetFontEntry() &&
-           aKey->mStyle->Equals(*mFont->GetStyle());
-}
-
-already_AddRefed<gfxFont>
-gfxFontCache::Lookup(const gfxFontEntry *aFontEntry,
-                     const gfxFontStyle *aStyle)
-{
-    Key key(aFontEntry, aStyle);
-    HashEntry *entry = mFonts.GetEntry(key);
-
-    Telemetry::Accumulate(Telemetry::FONT_CACHE_HIT, entry != nullptr);
-    if (!entry)
-        return nullptr;
-
-    nsRefPtr<gfxFont> font = entry->mFont;
-    return font.forget();
-}
-
-void
-gfxFontCache::AddNew(gfxFont *aFont)
-{
-    Key key(aFont->GetFontEntry(), aFont->GetStyle());
-    HashEntry *entry = mFonts.PutEntry(key);
-    if (!entry)
-        return;
-    gfxFont *oldFont = entry->mFont;
-    entry->mFont = aFont;
-    // Assert that we can find the entry we just put in (this fails if the key
-    // has a NaN float value in it, e.g. 'sizeAdjust').
-    MOZ_ASSERT(entry == mFonts.GetEntry(key));
-    // If someone's asked us to replace an existing font entry, then that's a
-    // bit weird, but let it happen, and expire the old font if it's not used.
-    if (oldFont && oldFont->GetExpirationState()->IsTracked()) {
-        // if oldFont == aFont, recount should be > 0,
-        // so we shouldn't be here.
-        NS_ASSERTION(aFont != oldFont, "new font is tracked for expiry!");
-        NotifyExpired(oldFont);
-    }
-}
-
-void