bug 847344 - refactor gfxFont/gfxFontEntry and associated classes for more efficient use of HarfBuzz and Graphite shaper APIs. r=roc
authorJonathan Kew <jkew@mozilla.com>
Thu, 16 May 2013 17:32:41 +0100
changeset 144476 0a6d36fc3749bc0161899fe74fb97cb4de66fc4c
parent 144475 ba23d27b9cecfad97be8c38bd51891c6a95bfb5b
child 144477 55620ca9673c267ca3b97b39df9155e8bbe733ac
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs847344
milestone24.0a1
bug 847344 - refactor gfxFont/gfxFontEntry and associated classes for more efficient use of HarfBuzz and Graphite shaper APIs. r=roc
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxDWriteFonts.h
gfx/thebes/gfxFT2FontBase.cpp
gfx/thebes/gfxFT2FontBase.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2FontList.h
gfx/thebes/gfxFT2Utils.cpp
gfx/thebes/gfxFT2Utils.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontUtils.cpp
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxGraphiteShaper.cpp
gfx/thebes/gfxGraphiteShaper.h
gfx/thebes/gfxHarfBuzzShaper.cpp
gfx/thebes/gfxHarfBuzzShaper.h
gfx/thebes/gfxMacFont.cpp
gfx/thebes/gfxMacFont.h
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxPangoFonts.h
gfx/thebes/gfxSVGGlyphs.cpp
gfx/thebes/gfxSVGGlyphs.h
layout/media/symbols.def.in
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -17,16 +17,18 @@
 #include "nsCharSeparatedTokenizer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "gfxGDIFontList.h"
 
 #include "nsIWindowsRegKey.h"
 
+#include "harfbuzz/hb.h"
+
 using namespace mozilla;
 
 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
                                PR_LOG_DEBUG, args)
 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
                                    PR_LOG_DEBUG)
 
@@ -259,18 +261,18 @@ UsingArabicOrHebrewScriptSystemLocale()
     case LANG_HEBREW:
         return true;
     default:
         return false;
     }
 }
 
 nsresult
-gfxDWriteFontEntry::GetFontTable(uint32_t aTableTag,
-                                 FallibleTArray<uint8_t> &aBuffer)
+gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag,
+                                  FallibleTArray<uint8_t> &aBuffer)
 {
     gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList();
 
     // Don't use GDI table loading for symbol fonts or for
     // italic fonts in Arabic-script system locales because of
     // potential cmap discrepancies, see bug 629386.
     // Ditto for Hebrew, bug 837498.
     if (mFont && pFontList->UseGDIFontTableAccess() &&
@@ -296,103 +298,123 @@ gfxDWriteFontEntry::GetFontTable(uint32_
                     return NS_OK;
                 }
                 return NS_ERROR_OUT_OF_MEMORY;
             }
         }
         return NS_ERROR_FAILURE;
     }
 
-    HRESULT hr;
-    nsresult rv;
     nsRefPtr<IDWriteFontFace> fontFace;
-
-    rv = CreateFontFace(getter_AddRefs(fontFace));
-
+    nsresult rv = CreateFontFace(getter_AddRefs(fontFace));
     if (NS_FAILED(rv)) {
         return rv;
     }
 
     uint8_t *tableData;
     uint32_t len;
     void *tableContext = NULL;
     BOOL exists;
-    hr = fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
-                                   (const void**)&tableData,
-                                   &len,
-                                   &tableContext,
-                                   &exists);
-
+    HRESULT hr =
+        fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
+                                  (const void**)&tableData, &len,
+                                  &tableContext, &exists);
     if (FAILED(hr) || !exists) {
         return NS_ERROR_FAILURE;
     }
-    if (!aBuffer.SetLength(len)) {
-        return NS_ERROR_OUT_OF_MEMORY;
+
+    if (aBuffer.SetLength(len)) {
+        memcpy(aBuffer.Elements(), tableData, len);
+        rv = NS_OK;
+    } else {
+        rv = NS_ERROR_OUT_OF_MEMORY;
     }
-    memcpy(aBuffer.Elements(), tableData, len);
+
     if (tableContext) {
         fontFace->ReleaseFontTable(&tableContext);
     }
-    return NS_OK;
+
+    return rv;
+}
+
+// Access to font tables packaged in hb_blob_t form
+
+// object attached to the Harfbuzz blob, used to release
+// the table when the blob is destroyed
+class FontTableRec {
+public:
+    FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
+        : mFontFace(aFontFace), mContext(aContext)
+    { }
+
+    ~FontTableRec() {
+        mFontFace->ReleaseFontTable(mContext);
+    }
+
+private:
+    IDWriteFontFace *mFontFace;
+    void            *mContext;
+};
+
+static void
+DestroyBlobFunc(void* aUserData)
+{
+    FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
+    delete ftr;
+}
+
+hb_blob_t *
+gfxDWriteFontEntry::GetFontTable(uint32_t aTag)
+{
+    // try to avoid potentially expensive DWrite call if we haven't actually
+    // created the font face yet, by using the gfxFontEntry method that will
+    // use CopyFontTable and then cache the data
+    if (!mFontFace) {
+        return gfxFontEntry::GetFontTable(aTag);
+    }
+
+    const void *data;
+    UINT32      size;
+    void       *context;
+    BOOL        exists;
+    HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
+                                            &data, &size, &context, &exists);
+    if (SUCCEEDED(hr) && exists) {
+        FontTableRec *ftr = new FontTableRec(mFontFace, context);
+        return hb_blob_create(static_cast<const char*>(data), size,
+                              HB_MEMORY_MODE_READONLY,
+                              ftr, DestroyBlobFunc);
+    }
+
+    return nullptr;
 }
 
 nsresult
 gfxDWriteFontEntry::ReadCMAP()
 {
-    HRESULT hr;
     nsresult rv;
 
     // attempt this once, if errors occur leave a blank cmap
     if (mCharacterMap) {
         return NS_OK;
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
-    // if loading via GDI, just use GetFontTable
-    if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) {
-        uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
-    
-        AutoFallibleTArray<uint8_t,16384> cmap;
-        rv = GetFontTable(kCMAP, cmap);
-    
+    uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
+    AutoTable cmapTable(this, kCMAP);
+    if (cmapTable) {
         bool unicodeFont = false, symbolFont = false; // currently ignored
-    
-        if (NS_SUCCEEDED(rv)) {
-            rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
-                                        *charmap, mUVSOffset,
-                                        unicodeFont, symbolFont);
-        }
-    } else {
-        // loading using dwrite, don't use GetFontTable to avoid copy
-        nsRefPtr<IDWriteFontFace> fontFace;
-        rv = CreateFontFace(getter_AddRefs(fontFace));
-    
-        if (NS_SUCCEEDED(rv)) {
-            const uint32_t kCmapTag = DWRITE_MAKE_OPENTYPE_TAG('c', 'm', 'a', 'p');
-            uint8_t *tableData;
-            uint32_t len;
-            void *tableContext = NULL;
-            BOOL exists;
-            hr = fontFace->TryGetFontTable(kCmapTag, (const void**)&tableData,
-                                           &len, &tableContext, &exists);
-
-            if (SUCCEEDED(hr)) {
-                bool isSymbol = fontFace->IsSymbolFont();
-                bool isUnicode = true;
-                if (exists) {
-                    rv = gfxFontUtils::ReadCMAP(tableData, len, *charmap,
-                                                mUVSOffset, isUnicode, 
-                                                isSymbol);
-                }
-                fontFace->ReleaseFontTable(tableContext);
-            } else {
-                rv = NS_ERROR_FAILURE;
-            }
-        }
+        uint32_t cmapLen;
+        const uint8_t* cmapData =
+            reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
+                                                              &cmapLen));
+        rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
+                                    *charmap, mUVSOffset,
+                                    unicodeFont, symbolFont);
     }
 
     mHasCmapTable = NS_SUCCEEDED(rv);
     if (mHasCmapTable) {
         gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
         mCharacterMap = pfl->FindCharMap(charmap);
     } else {
         // if error occurred, initialize to null cmap
@@ -421,62 +443,70 @@ gfxDWriteFontEntry::CreateFontInstance(c
 {
     return new gfxDWriteFont(this, aFontStyle, aNeedsBold);
 }
 
 nsresult
 gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
                                    DWRITE_FONT_SIMULATIONS aSimulations)
 {
-    HRESULT hr;
-    if (mFont) {
-        hr = mFont->CreateFontFace(aFontFace);
-        if (SUCCEEDED(hr) && (aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
-            !((*aFontFace)->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
-            // need to replace aFontFace with a version that has the Bold
-            // simulation - unfortunately, DWrite doesn't provide a simple API
-            // for this
-            nsRefPtr<IDWriteFontFace> origFace = (*aFontFace);
-            (*aFontFace)->Release();
-            *aFontFace = NULL;
-            UINT32 numberOfFiles = 0;
-            hr = origFace->GetFiles(&numberOfFiles, NULL);
-            if (FAILED(hr)) {
-                return NS_ERROR_FAILURE;
-            }
-            nsAutoTArray<IDWriteFontFile*,1> files;
-            files.AppendElements(numberOfFiles);
-            hr = origFace->GetFiles(&numberOfFiles, files.Elements());
-            if (FAILED(hr)) {
-                return NS_ERROR_FAILURE;
-            }
+    // initialize mFontFace if this hasn't been done before
+    if (!mFontFace) {
+        HRESULT hr;
+        if (mFont) {
+            hr = mFont->CreateFontFace(getter_AddRefs(mFontFace));
+        } else if (mFontFile) {
+            IDWriteFontFile *fontFile = mFontFile.get();
             hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
-                CreateFontFace(origFace->GetType(),
-                               numberOfFiles,
-                               files.Elements(),
-                               origFace->GetIndex(),
-                               aSimulations,
-                               aFontFace);
-            for (UINT32 i = 0; i < numberOfFiles; ++i) {
-                files[i]->Release();
-            }
+                CreateFontFace(mFaceType,
+                               1,
+                               &fontFile,
+                               0,
+                               DWRITE_FONT_SIMULATIONS_NONE,
+                               getter_AddRefs(mFontFace));
+        } else {
+            NS_NOTREACHED("invalid font entry");
+            return NS_ERROR_FAILURE;
+        }
+        if (FAILED(hr)) {
+            return NS_ERROR_FAILURE;
         }
-    } else if (mFontFile) {
-        IDWriteFontFile *fontFile = mFontFile.get();
-        hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
-            CreateFontFace(mFaceType,
-                           1,
-                           &fontFile,
-                           0,
+    }
+
+    // check whether we need to add a DWrite simulated style
+    if ((aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
+        !(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
+        // if so, we need to return not mFontFace itself but a version that
+        // has the Bold simulation - unfortunately, DWrite doesn't provide
+        // a simple API for this
+        UINT32 numberOfFiles = 0;
+        if (FAILED(mFontFace->GetFiles(&numberOfFiles, NULL))) {
+            return NS_ERROR_FAILURE;
+        }
+        nsAutoTArray<IDWriteFontFile*,1> files;
+        files.AppendElements(numberOfFiles);
+        if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) {
+            return NS_ERROR_FAILURE;
+        }
+        HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
+            CreateFontFace(mFontFace->GetType(),
+                           numberOfFiles,
+                           files.Elements(),
+                           mFontFace->GetIndex(),
                            aSimulations,
                            aFontFace);
+        for (UINT32 i = 0; i < numberOfFiles; ++i) {
+            files[i]->Release();
+        }
+        return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
     }
-    if (FAILED(hr)) {
-        return NS_ERROR_FAILURE;
-    }
+
+    // no simulation: we can just add a reference to mFontFace and return that
+    *aFontFace = mFontFace;
+    (*aFontFace)->AddRef();
     return NS_OK;
 }
 
 bool
 gfxDWriteFontEntry::InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont)
 {
     HRESULT hr;
 
@@ -493,17 +523,17 @@ gfxDWriteFontEntry::IsCJKFont()
     if (mIsCJK != UNINITIALIZED_VALUE) {
         return mIsCJK;
     }
 
     mIsCJK = false;
 
     const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
     AutoFallibleTArray<uint8_t,128> buffer;
-    if (GetFontTable(kOS2Tag, buffer) != NS_OK) {
+    if (CopyFontTable(kOS2Tag, buffer) != NS_OK) {
         return mIsCJK;
     }
 
     // ulCodePageRange bit definitions for the CJK codepages,
     // from http://www.microsoft.com/typography/otspec/os2.htm#cpr
     const uint32_t CJK_CODEPAGE_BITS =
         (1 << 17) | // codepage 932 - JIS/Japan
         (1 << 18) | // codepage 936 - Chinese (simplified)
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -138,18 +138,17 @@ public:
         mIsUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     virtual ~gfxDWriteFontEntry();
 
     virtual bool IsSymbolFont();
 
-    virtual nsresult GetFontTable(uint32_t aTableTag,
-                                  FallibleTArray<uint8_t>& aBuffer);
+    virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
 
     nsresult ReadCMAP();
 
     bool IsCJKFont();
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
     bool GetForceGDIClassic() { return mForceGDIClassic; }
 
@@ -157,31 +156,39 @@ public:
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
 protected:
     friend class gfxDWriteFont;
     friend class gfxDWriteFontList;
 
+    virtual nsresult CopyFontTable(uint32_t aTableTag,
+                                   FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
+
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         bool aNeedsBold);
     
     nsresult CreateFontFace(
         IDWriteFontFace **aFontFace,
         DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE);
 
     static bool InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont);
 
     /**
      * A fontentry only needs to have either of these. If it has both only
      * the IDWriteFont will be used.
      */
     nsRefPtr<IDWriteFont> mFont;
     nsRefPtr<IDWriteFontFile> mFontFile;
+
+    // font face corresponding to the mFont/mFontFile *without* any DWrite
+    // style simulations applied
+    nsRefPtr<IDWriteFontFace> mFontFace;
+
     DWRITE_FONT_FACE_TYPE mFaceType;
 
     int8_t mIsCJK;
     bool mForceGDIClassic;
 };
 
 // custom text renderer used to determine the fallback font for a given char
 class FontFallbackRenderer MOZ_FINAL : public IDWriteTextRenderer
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -14,16 +14,17 @@
 
 #include "gfxDWriteTextAnalysis.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;
 using namespace mozilla::gfx;
 
 // This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common,
 // but we can't declare it in the gfxFont.h or gfxFontUtils.h headers
 // because those are exported, and the cairo headers aren't.
 static inline cairo_antialias_t
 GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption)
 {
@@ -224,62 +225,51 @@ gfxDWriteFont::ComputeMetrics(AntialiasO
     mMetrics->emHeight = mAdjustedSize;
     mMetrics->emAscent = mMetrics->emHeight *
         mMetrics->maxAscent / mMetrics->maxHeight;
     mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
 
     mMetrics->maxAdvance = mAdjustedSize;
 
     // try to get the true maxAdvance value from 'hhea'
-    uint8_t *tableData;
-    uint32_t len;
-    void *tableContext = NULL;
-    BOOL exists;
-    HRESULT hr =
-        mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('h', 'h', 'e', 'a'),
-                                   (const void**)&tableData,
-                                   &len,
-                                   &tableContext,
-                                   &exists);
-    if (SUCCEEDED(hr)) {
-        if (exists && len >= sizeof(mozilla::HheaTable)) {
-            const mozilla::HheaTable* hhea =
-                reinterpret_cast<const mozilla::HheaTable*>(tableData);
+    gfxFontEntry::AutoTable hheaTable(GetFontEntry(),
+                                      TRUETYPE_TAG('h','h','e','a'));
+    if (hheaTable) {
+        uint32_t len;
+        const HheaTable* hhea =
+            reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
+        if (len >= sizeof(HheaTable)) {
             mMetrics->maxAdvance =
                 uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
         }
-        mFontFace->ReleaseFontTable(tableContext);
     }
 
     mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
     mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
 
     UINT16 glyph = (uint16_t)GetSpaceGlyph();
     mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
 
     // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
     // if the table is not available or if using hinted/pixel-snapped widths
     if (mUseSubpixelPositions) {
         mMetrics->aveCharWidth = 0;
-        hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
-                                        (const void**)&tableData,
-                                        &len,
-                                        &tableContext,
-                                        &exists);
-        if (SUCCEEDED(hr)) {
-            if (exists && len >= 4) {
+        gfxFontEntry::AutoTable os2Table(GetFontEntry(),
+                                         TRUETYPE_TAG('O','S','/','2'));
+        if (os2Table) {
+            uint32_t len;
+            const OS2Table* os2 =
+                reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
+            if (len >= 4) {
                 // Not checking against sizeof(mozilla::OS2Table) here because older
                 // versions of the table have different sizes; we only need the first
                 // two 16-bit fields here.
-                const mozilla::OS2Table* os2 =
-                    reinterpret_cast<const mozilla::OS2Table*>(tableData);
                 mMetrics->aveCharWidth =
                     int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
             }
-            mFontFace->ReleaseFontTable(tableContext);
         }
     }
 
     UINT32 ucs;
     if (mMetrics->aveCharWidth < 1) {
         ucs = L'x';
         if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
             mMetrics->aveCharWidth = MeasureGlyphWidth(glyph);
@@ -596,70 +586,16 @@ gfxDWriteFont::Measure(gfxTextRun *aText
         metrics.mBoundingBox.width > 0) {
         metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
         metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3;
     }
 
     return metrics;
 }
 
-// Access to font tables packaged in hb_blob_t form
-
-// object attached to the Harfbuzz blob, used to release
-// the table when the blob is destroyed
-class FontTableRec {
-public:
-    FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
-        : mFontFace(aFontFace), mContext(aContext)
-    { }
-
-    ~FontTableRec() {
-        mFontFace->ReleaseFontTable(mContext);
-    }
-
-private:
-    IDWriteFontFace *mFontFace;
-    void            *mContext;
-};
-
-/*static*/ void
-gfxDWriteFont::DestroyBlobFunc(void* aUserData)
-{
-    FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
-    delete ftr;
-}
-
-hb_blob_t *
-gfxDWriteFont::GetFontTable(uint32_t aTag)
-{
-    const void *data;
-    UINT32      size;
-    void       *context;
-    BOOL        exists;
-    HRESULT hr = mFontFace->TryGetFontTable(mozilla::NativeEndian::swapToBigEndian(aTag),
-                                            &data, &size, &context, &exists);
-    if (SUCCEEDED(hr) && exists) {
-        FontTableRec *ftr = new FontTableRec(mFontFace, context);
-        return hb_blob_create(static_cast<const char*>(data), size,
-                              HB_MEMORY_MODE_READONLY,
-                              ftr, DestroyBlobFunc);
-    }
-
-    if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
-        // for downloaded fonts, there may be layout tables cached in the entry
-        // even though they're absent from the sanitized platform font
-        hb_blob_t *blob;
-        if (mFontEntry->GetExistingFontTable(aTag, &blob)) {
-            return blob;
-        }
-    }
-
-    return nullptr;
-}
-
 bool
 gfxDWriteFont::ProvidesGlyphWidths()
 {
     return !mUseSubpixelPositions ||
            (mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
 }
 
 int32_t
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -47,20 +47,16 @@ public:
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                gfxContext *aContextForTightBoundingBox,
                                Spacing *aSpacing);
 
-    // override gfxFont table access function to bypass gfxFontEntry cache,
-    // use DWrite API to get direct access to system font data
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
-
     virtual bool ProvidesGlyphWidths();
 
     virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
 
     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions();
 
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontCacheSizes*   aSizes) const;
@@ -83,18 +79,16 @@ protected:
     void ComputeMetrics(AntialiasOption anAAOption);
 
     bool HasBitmapStrikeForSize(uint32_t aSize);
 
     cairo_font_face_t *CairoFontFace();
 
     gfxFloat MeasureGlyphWidth(uint16_t aGlyph);
 
-    static void DestroyBlobFunc(void* userArg);
-
     DWRITE_MEASURING_MODE GetMeasuringMode();
     bool GetForceGDIClassic();
 
     nsRefPtr<IDWriteFontFace> mFontFace;
     cairo_font_face_t *mCairoFontFace;
 
     gfxFont::Metrics          *mMetrics;
 
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -141,32 +141,16 @@ uint32_t
 gfxFT2FontBase::GetSpaceGlyph()
 {
     NS_ASSERTION(GetStyle()->size != 0,
                  "forgot to short-circuit a text run with zero-sized font?");
     GetMetrics();
     return mSpaceGlyph;
 }
 
-hb_blob_t *
-gfxFT2FontBase::GetFontTable(uint32_t aTag)
-{
-    hb_blob_t *blob;
-    if (mFontEntry->GetExistingFontTable(aTag, &blob))
-        return blob;
-
-    FallibleTArray<uint8_t> buffer;
-    bool haveTable = gfxFT2LockedFace(this).GetFontTable(aTag, buffer);
-
-    // Cache even when there is no table to save having to open the FT_Face
-    // again.
-    return mFontEntry->ShareFontTableAndGetBlob(aTag,
-                                                haveTable ? &buffer : nullptr);
-}
-
 uint32_t
 gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
 {
     if (variation_selector) {
         uint32_t id =
             gfxFT2LockedFace(this).GetUVSGlyph(unicode, variation_selector);
         if (id)
             return id;
--- a/gfx/thebes/gfxFT2FontBase.h
+++ b/gfx/thebes/gfxFT2FontBase.h
@@ -18,17 +18,16 @@ public:
                    const gfxFontStyle *aFontStyle);
     virtual ~gfxFT2FontBase();
 
     uint32_t GetGlyph(uint32_t aCharCode);
     void GetGlyphExtents(uint32_t aGlyph,
                          cairo_text_extents_t* aExtents);
     virtual const gfxFont::Metrics& GetMetrics();
     virtual uint32_t GetSpaceGlyph();
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
     virtual bool ProvidesGetGlyph() const { return true; }
     virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector);
     virtual bool ProvidesGlyphWidths() { return true; }
     virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
 
     cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
     virtual bool SetupCairoFont(gfxContext *aContext);
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -411,17 +411,17 @@ FT2FontEntry::ReadCMAP()
 {
     if (mCharacterMap) {
         return NS_OK;
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
     AutoFallibleTArray<uint8_t,16384> buffer;
-    nsresult rv = GetFontTable(TTAG_cmap, buffer);
+    nsresult rv = CopyFontTable(TTAG_cmap, buffer);
     
     if (NS_SUCCEEDED(rv)) {
         bool unicodeFont;
         bool symbolFont;
         rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(),
                                     *charmap, mUVSOffset,
                                     unicodeFont, symbolFont);
     }
@@ -433,18 +433,18 @@ FT2FontEntry::ReadCMAP()
     } else {
         // if error occurred, initialize to null cmap
         mCharacterMap = new gfxCharacterMap();
     }
     return rv;
 }
 
 nsresult
-FT2FontEntry::GetFontTable(uint32_t aTableTag,
-                           FallibleTArray<uint8_t>& aBuffer)
+FT2FontEntry::CopyFontTable(uint32_t aTableTag,
+                            FallibleTArray<uint8_t>& aBuffer)
 {
     AutoFTFace face(this);
     if (!face) {
         return NS_ERROR_FAILURE;
     }
 
     FT_Error status;
     FT_ULong len = 0;
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -61,17 +61,19 @@ public:
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         bool aNeedsBold);
 
     cairo_font_face_t *CairoFontFace();
     cairo_scaled_font_t *CreateScaledFont(const gfxFontStyle *aStyle);
 
     nsresult ReadCMAP();
-    nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer);
+
+    virtual nsresult CopyFontTable(uint32_t aTableTag,
+                                   FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
     // Check for various kinds of brokenness, and set flags on the entry
     // accordingly so that we avoid using bad font tables
     void CheckForBrokenFont(gfxFontFamily *aFamily);
 
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -313,41 +313,16 @@ gfxFT2LockedFace::GetUVSGlyph(uint32_t a
     if (!mFace->charmap || mFace->charmap->encoding != FT_ENCODING_UNICODE) {
         FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
     }
 #endif
 
     return (*sGetCharVariantPtr)(mFace, aCharCode, aVariantSelector);
 }
 
-bool
-gfxFT2LockedFace::GetFontTable(uint32_t aTag, FallibleTArray<uint8_t>& aBuffer)
-{
-    if (!mFace || !FT_IS_SFNT(mFace))
-        return false;
-
-    FT_ULong length = 0;
-    // TRUETYPE_TAG is defined equivalent to FT_MAKE_TAG
-    FT_Error error = FT_Load_Sfnt_Table(mFace, aTag, 0, NULL, &length);
-    if (error != 0)
-        return false;
-
-    if (MOZ_UNLIKELY(length > static_cast<FallibleTArray<uint8_t>::size_type>(-1))
-        || MOZ_UNLIKELY(!aBuffer.SetLength(length)))
-        return false;
-        
-    error = FT_Load_Sfnt_Table(mFace, aTag, 0, aBuffer.Elements(), &length);
-    if (MOZ_UNLIKELY(error != 0)) {
-        aBuffer.Clear();
-        return false;
-    }
-
-    return true;
-}
-
 uint32_t
 gfxFT2LockedFace::GetCharExtents(char aChar, cairo_text_extents_t* aExtents)
 {
     NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
 
     if (!mFace)
         return 0;
 
--- a/gfx/thebes/gfxFT2Utils.h
+++ b/gfx/thebes/gfxFT2Utils.h
@@ -43,18 +43,16 @@ public:
     uint32_t GetGlyph(uint32_t aCharCode);
     /**
      * Returns 0 if there is no variation selector cmap subtable.
      */
     uint32_t GetUVSGlyph(uint32_t aCharCode, uint32_t aVariantSelector);
 
     void GetMetrics(gfxFont::Metrics* aMetrics, uint32_t* aSpaceGlyph);
 
-    bool GetFontTable(uint32_t aTag, FallibleTArray<uint8_t>& aBuffer);
-
     // A scale factor for use in converting horizontal metrics from font units
     // to pixels.
     gfxFloat XScale()
     {
         if (MOZ_UNLIKELY(!mFace))
             return 0.0;
 
         const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -40,16 +40,17 @@
 #include "mozilla/Telemetry.h"
 #include "gfxSVGGlyphs.h"
 
 #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 <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
@@ -90,16 +91,22 @@ gfxCharacterMap::NotifyReleased()
 gfxFontEntry::~gfxFontEntry()
 {
     // For downloaded fonts, we need to tell the user font cache that this
     // entry is being deleted.
     if (!mIsProxy && IsUserFont() && !IsLocalUserFont()) {
         gfxUserFontSet::UserFontCache::ForgetFont(this);
     }
 
+    // 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);
+
     if (mSVGGlyphs) {
         delete mSVGGlyphs;
     }
     delete mUserFontData;
 }
 
 bool gfxFontEntry::IsSymbolFont() 
 {
@@ -125,27 +132,29 @@ nsresult gfxFontEntry::InitializeUVSMap(
     }
 
     if (!mUVSOffset) {
         return NS_ERROR_FAILURE;
     }
 
     if (!mUVSData) {
         const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
-        AutoFallibleTArray<uint8_t,16384> buffer;
-        if (GetFontTable(kCmapTag, buffer) != NS_OK) {
+        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(
-                          buffer.Elements() + mUVSOffset,
-                          buffer.Length() - mUVSOffset,
-                          uvsData);
+                          (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;
     }
 
@@ -168,21 +177,20 @@ nsresult gfxFontEntry::ReadCMAP()
     NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
     mCharacterMap = new gfxCharacterMap();
     return NS_OK;
 }
 
 nsString
 gfxFontEntry::RealFaceName()
 {
-    FallibleTArray<uint8_t> nameTable;
-    nsresult rv = GetFontTable(TRUETYPE_TAG('n','a','m','e'), nameTable);
-    if (NS_SUCCEEDED(rv)) {
+    AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
+    if (nameTable) {
         nsAutoString name;
-        rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
+        nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
         if (NS_SUCCEEDED(rv)) {
             return name;
         }
     }
     return Name();
 }
 
 already_AddRefed<gfxFont>
@@ -243,26 +251,32 @@ gfxFontEntry::TryGetSVGData()
 {
     if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
         return false;
     }
 
     if (!mSVGInitialized) {
         mSVGInitialized = true;
 
-        FallibleTArray<uint8_t> svgTable;
-        nsresult rv = GetFontTable(TRUETYPE_TAG('S', 'V', 'G', ' '), svgTable);
-        if (NS_FAILED(rv)) {
+        // We don't use AutoTable here because we'll pass ownership of these
+        // blobs to the gfxSVGGlyphs, once we've confirmed the tables exist
+        hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
+        if (!svgTable) {
             return false;
         }
 
-        FallibleTArray<uint8_t> cmapTable;
-        rv = GetFontTable(TRUETYPE_TAG('c', 'm', 'a', 'p'), cmapTable);
-        NS_ENSURE_SUCCESS(rv, false);
-
+        hb_blob_t *cmapTable = GetFontTable(TRUETYPE_TAG('c','m','a','p'));
+        if (!cmapTable) {
+            NS_NOTREACHED("using a font with no cmap!");
+            hb_blob_destroy(svgTable);
+            return false;
+        }
+
+        // gfxSVGGlyphs will hb_blob_destroy() the tables when it is finished
+        // with them.
         mSVGGlyphs = new gfxSVGGlyphs(svgTable, cmapTable);
     }
 
     return !!mSVGGlyphs;
 }
 
 /**
  * FontTableBlobData
@@ -422,22 +436,146 @@ gfxFontEntry::ShareFontTableAndGetBlob(u
         // ensure the entry is null
         entry->Clear();
         return nullptr;
     }
 
     return entry->ShareTableAndGetBlob(*aBuffer, &mFontTableCache);
 }
 
+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*>;
+        mGrTableMap->Init();
+        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::CheckForGraphiteTables()
 {
-    AutoFallibleTArray<uint8_t,16384> buffer;
-    mHasGraphiteTables =
-        NS_SUCCEEDED(GetFontTable(TRUETYPE_TAG('S','i','l','f'), buffer));
+    AutoTable silfTable(this, TRUETYPE_TAG('S','i','l','f'));
+    mHasGraphiteTables = silfTable && hb_blob_get_length(silfTable) > 0;
 }
 
 /* static */ size_t
 gfxFontEntry::FontTableHashEntry::SizeOfEntryExcludingThis
     (FontTableHashEntry *aEntry,
      nsMallocSizeOfFun   aMallocSizeOf,
      void*               aUserArg)
 {
@@ -879,21 +1017,21 @@ gfxFontFamily::SearchAllFontsForChar(Glo
             }
         }
     }
 }
 
 // returns true if other names were found, false otherwise
 bool
 gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
-                                           FallibleTArray<uint8_t>& aNameTable,
-                                           bool useFullName)
-{
-    const uint8_t *nameData = aNameTable.Elements();
-    uint32_t dataLength = aNameTable.Length();
+                                           hb_blob_t           *aNameTable,
+                                           bool                 useFullName)
+{
+    uint32_t dataLength;
+    const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
     const gfxFontUtils::NameHeader *nameHeader =
         reinterpret_cast<const gfxFontUtils::NameHeader*>(nameData);
 
     uint32_t nameCount = nameHeader->count;
     if (nameCount * sizeof(gfxFontUtils::NameRecord) > dataLength) {
         NS_WARNING("invalid font (name records)");
         return false;
     }
@@ -942,106 +1080,108 @@ gfxFontFamily::ReadOtherFamilyNames(gfxP
         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');
-    AutoFallibleTArray<uint8_t,8192> buffer;
 
     for (i = 0; i < numFonts; ++i) {
         gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe)
+        if (!fe) {
             continue;
-
-        if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+        }
+        gfxFontEntry::AutoTable nameTable(fe, kNAME);
+        if (!nameTable) {
             continue;
-
+        }
         mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                           buffer);
+                                                           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)
+        if (!fe) {
             continue;
-
-        if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+        }
+        gfxFontEntry::AutoTable nameTable(fe, kNAME);
+        if (!nameTable) {
             continue;
-
-        ReadOtherFamilyNamesForFace(aPlatformFontList, buffer);
+        }
+        ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
     }
 }
 
 void
 gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, 
                              bool aNeedFullnamePostscriptNames)
 {
     // if all needed names have already been read, skip
     if (mOtherFamilyNamesInitialized &&
         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
         return;
 
     FindStyleVariations();
 
     uint32_t i, numFonts = mAvailableFonts.Length();
     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
-    AutoFallibleTArray<uint8_t,8192> buffer;
     nsAutoString fullname, psname;
 
     bool firstTime = true, readAllFaces = false;
     for (i = 0; i < numFonts; ++i) {
         gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe)
+        if (!fe) {
             continue;
-
-        if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+        }
+        gfxFontEntry::AutoTable nameTable(fe, kNAME);
+        if (!nameTable) {
             continue;
-
+        }
         if (aNeedFullnamePostscriptNames) {
             if (gfxFontUtils::ReadCanonicalName(
-                    buffer, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
+                    nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
             {
                 aPlatformFontList->AddFullname(fe, fullname);
             }
 
             if (gfxFontUtils::ReadCanonicalName(
-                    buffer, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
+                    nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
             {
                 aPlatformFontList->AddPostscriptName(fe, psname);
             }
         }
 
-       if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
-           bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                               buffer);
-
-           // 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;
+        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*
@@ -1569,36 +1709,16 @@ gfxFont::AgeCacheEntry(CacheHashEntry *a
         return PL_DHASH_REMOVE;
     }
     if (aEntry->mShapedWord->IncrementAge() == kShapedWordCacheMaxAge) {
         return PL_DHASH_REMOVE;
     }
     return PL_DHASH_NEXT;
 }
 
-hb_blob_t *
-gfxFont::GetFontTable(uint32_t aTag) {
-    hb_blob_t *blob;
-    if (mFontEntry->GetExistingFontTable(aTag, &blob))
-        return blob;
-
-    FallibleTArray<uint8_t> buffer;
-    bool haveTable = NS_SUCCEEDED(mFontEntry->GetFontTable(aTag, buffer));
-
-    return mFontEntry->ShareFontTableAndGetBlob(aTag,
-                                                haveTable ? &buffer : nullptr);
-}
-
-static hb_blob_t *
-HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData)
-{
-    gfxFont* font = static_cast<gfxFont*>(aUserData);
-    return font->GetFontTable(aTag);
-}
-
 static bool
 HasLookupRuleWithGlyphByScript(hb_face_t *aFace, hb_tag_t aTableTag,
                                hb_tag_t aScript, uint16_t aGlyph)
 {
     hb_set_t *lookups = hb_set_create();
     hb_set_t *glyphs = hb_set_create();
     hb_tag_t scripts[2] = {0};
     scripts[0] = aScript;
@@ -1752,17 +1872,17 @@ nsDataHashtable<nsUint32HashKey, int32_t
 
 void
 gfxFont::CheckForFeaturesInvolvingSpace()
 {
     mFontEntry->mHasSpaceFeaturesInitialized = true;
 
     bool result = false;
 
-    hb_face_t *face = hb_face_create_for_tables(HBGetTable, this, nullptr);
+    hb_face_t *face = GetFontEntry()->GetHBFace();
 
     uint32_t i, len, offset;
     uint32_t spaceGlyph = GetSpaceGlyph();
     int32_t s;
 
     mFontEntry->mHasSpaceFeaturesSubDefault = false;
 
     // GSUB lookups - examine per script
@@ -3287,90 +3407,98 @@ gfxFont::SetupGlyphExtents(gfxContext *a
     aExtents->SetTightGlyphExtents(aGlyphID, bounds);
 }
 
 // Try to initialize font metrics by reading sfnt tables directly;
 // set mIsValid=TRUE and return TRUE on success.
 // Return FALSE if the gfxFontEntry subclass does not
 // implement GetFontTable(), or for non-sfnt fonts where tables are
 // not available.
+// If this returns TRUE without setting the mIsValid flag, then we -did-
+// apparently find an sfnt, but it was too broken to be used.
 bool
 gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
 {
     mIsValid = false; // font is NOT valid in case of early return
 
     const uint32_t kHeadTableTag = TRUETYPE_TAG('h','e','a','d');
     const uint32_t kHheaTableTag = TRUETYPE_TAG('h','h','e','a');
     const uint32_t kPostTableTag = TRUETYPE_TAG('p','o','s','t');
     const uint32_t kOS_2TableTag = TRUETYPE_TAG('O','S','/','2');
 
+    uint32_t len;
+
     if (mFUnitsConvFactor == 0.0) {
         // If the conversion factor from FUnits is not yet set,
         // 'head' table is required; otherwise we cannot read any metrics
         // because we don't know unitsPerEm
-        AutoFallibleTArray<uint8_t,sizeof(HeadTable)> headData;
-        if (NS_FAILED(mFontEntry->GetFontTable(kHeadTableTag, headData)) ||
-            headData.Length() < sizeof(HeadTable)) {
-            return false; // no 'head' table -> not an sfnt
-        }
-        HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements());
+        gfxFontEntry::AutoTable headTable(mFontEntry, kHeadTableTag);
+        if (!headTable) {
+            return false;
+        }
+        const HeadTable* head =
+            reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len));
+        if (len < sizeof(HeadTable)) {
+            return false;
+        }
         uint32_t unitsPerEm = head->unitsPerEm;
         if (!unitsPerEm) {
             return true; // is an sfnt, but not valid
         }
         mFUnitsConvFactor = mAdjustedSize / unitsPerEm;
     }
 
     // 'hhea' table is required to get vertical extents
-    AutoFallibleTArray<uint8_t,sizeof(HheaTable)> hheaData;
-    if (NS_FAILED(mFontEntry->GetFontTable(kHheaTableTag, hheaData)) ||
-        hheaData.Length() < sizeof(HheaTable)) {
+    gfxFontEntry::AutoTable hheaTable(mFontEntry, kHheaTableTag);
+    if (!hheaTable) {
         return false; // no 'hhea' table -> not an sfnt
     }
-    HheaTable *hhea = reinterpret_cast<HheaTable*>(hheaData.Elements());
+    const HheaTable* hhea =
+        reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
+    if (len < sizeof(HheaTable)) {
+        return false;
+    }
 
 #define SET_UNSIGNED(field,src) aMetrics.field = uint16_t(src) * mFUnitsConvFactor
 #define SET_SIGNED(field,src)   aMetrics.field = int16_t(src) * mFUnitsConvFactor
 
     SET_UNSIGNED(maxAdvance, hhea->advanceWidthMax);
     SET_SIGNED(maxAscent, hhea->ascender);
     SET_SIGNED(maxDescent, -int16_t(hhea->descender));
     SET_SIGNED(externalLeading, hhea->lineGap);
 
     // 'post' table is required for underline metrics
-    AutoFallibleTArray<uint8_t,sizeof(PostTable)> postData;
-    if (NS_FAILED(mFontEntry->GetFontTable(kPostTableTag, postData))) {
+    gfxFontEntry::AutoTable postTable(mFontEntry, kPostTableTag);
+    if (!postTable) {
         return true; // no 'post' table -> sfnt is not valid
     }
-    if (postData.Length() <
-        offsetof(PostTable, underlineThickness) + sizeof(uint16_t)) {
+    const PostTable *post =
+        reinterpret_cast<const PostTable*>(hb_blob_get_data(postTable, &len));
+    if (len < offsetof(PostTable, underlineThickness) + sizeof(uint16_t)) {
         return true; // bad post table -> sfnt is not valid
     }
-    PostTable *post = reinterpret_cast<PostTable*>(postData.Elements());
 
     SET_SIGNED(underlineOffset, post->underlinePosition);
     SET_UNSIGNED(underlineSize, post->underlineThickness);
 
     // 'OS/2' table is optional, if not found we'll estimate xHeight
     // and aveCharWidth by measuring glyphs
-    AutoFallibleTArray<uint8_t,sizeof(OS2Table)> os2data;
-    if (NS_SUCCEEDED(mFontEntry->GetFontTable(kOS_2TableTag, os2data))) {
-        OS2Table *os2 = reinterpret_cast<OS2Table*>(os2data.Elements());
-
-        if (os2data.Length() >= offsetof(OS2Table, sxHeight) +
-                                sizeof(int16_t) &&
+    gfxFontEntry::AutoTable os2Table(mFontEntry, kOS_2TableTag);
+    if (os2Table) {
+        const OS2Table *os2 =
+            reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
+        if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
             uint16_t(os2->version) >= 2) {
             // version 2 and later includes the x-height field
             SET_SIGNED(xHeight, os2->sxHeight);
             // Abs because of negative xHeight seen in Kokonor (Tibetan) font
             aMetrics.xHeight = Abs(aMetrics.xHeight);
         }
         // this should always be present
-        if (os2data.Length() >= offsetof(OS2Table, yStrikeoutPosition) +
-                                sizeof(int16_t)) {
+        if (len >= offsetof(OS2Table, yStrikeoutPosition) + sizeof(int16_t)) {
             SET_SIGNED(aveCharWidth, os2->xAvgCharWidth);
             SET_SIGNED(subscriptOffset, os2->ySubscriptYOffset);
             SET_SIGNED(superscriptOffset, os2->ySuperscriptYOffset);
             SET_SIGNED(strikeoutSize, os2->yStrikeoutSize);
             SET_SIGNED(strikeoutOffset, os2->yStrikeoutPosition);
         }
     }
 
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -24,18 +24,20 @@
 #include "gfxPattern.h"
 #include "mozilla/HashFunctions.h"
 #include "nsIMemoryReporter.h"
 #include "gfxFontFeatures.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/Attributes.h"
 #include <algorithm>
 #include "nsUnicodeProperties.h"
+#include "harfbuzz/hb.h"
 
 typedef struct _cairo_scaled_font cairo_scaled_font_t;
+typedef struct gr_face            gr_face;
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 class gfxContext;
 class gfxTextRun;
 class gfxFont;
@@ -45,18 +47,16 @@ class gfxUserFontSet;
 class gfxUserFontData;
 class gfxShapedText;
 class gfxShapedWord;
 class gfxSVGGlyphs;
 class gfxTextObjectPaint;
 
 class nsILanguageAtomService;
 
-typedef struct hb_blob_t hb_blob_t;
-
 #define FONT_MAX_SIZE                  2000.0
 
 #define NO_FONT_LANGUAGE_OVERRIDE      0
 
 struct FontListSizes;
 struct gfxTextRunDrawCallbacks;
 
 struct THEBES_API gfxFontStyle {
@@ -232,23 +232,27 @@ public:
         mIgnoreGDEF(false),
         mIgnoreGSUB(false),
         mSVGInitialized(false),
         mHasSpaceFeaturesInitialized(false),
         mHasSpaceFeatures(false),
         mHasSpaceFeaturesKerning(false),
         mHasSpaceFeaturesNonKerning(false),
         mHasSpaceFeaturesSubDefault(false),
-        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mCheckedForGraphiteTables(false),
         mHasCmapTable(false),
+        mGrFaceInitialized(false),
+        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
-        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
+        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
+        mHBFace(nullptr),
+        mGrFace(nullptr),
+        mGrFaceRefCnt(0)
     {
         memset(&mHasSpaceFeaturesSub, 0, sizeof(mHasSpaceFeaturesSub));
     }
 
     virtual ~gfxFontEntry();
 
     // unique name for the face, *not* the family; not necessarily the
     // "real" or user-friendly name, may be an internal identifier
@@ -317,19 +321,56 @@ public:
 
     virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
         return true;
     }
     virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
         return true;
     }
 
-    virtual nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) {
-        return NS_ERROR_FAILURE; // all platform subclasses should reimplement this!
-    }
+    // 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 NULL if
+    // the table doesn't exist in the font.
+    //
+    // Caller is responsible to call hb_blob_destroy() on the returned blob
+    // (if non-NULL) 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.
     //
@@ -342,16 +383,31 @@ public:
     // reference is owned by the caller.  Removing the last reference
     // unregisters the table from the font entry.
     //
     // Pass NULL for aBuffer to indicate that the table is not present and
     // NULL will be returned.  Also returns NULL on OOM.
     hb_blob_t *ShareFontTableAndGetBlob(uint32_t aTag,
                                         FallibleTArray<uint8_t>* aTable);
 
+    // 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);
+    
     // For memory reporting
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
     nsString         mName;
     nsString         mFamilyName;
@@ -368,26 +424,27 @@ public:
     bool             mIgnoreGDEF  : 1;
     bool             mIgnoreGSUB  : 1;
     bool             mSVGInitialized : 1;
     bool             mHasSpaceFeaturesInitialized : 1;
     bool             mHasSpaceFeatures : 1;
     bool             mHasSpaceFeaturesKerning : 1;
     bool             mHasSpaceFeaturesNonKerning : 1;
     bool             mHasSpaceFeaturesSubDefault : 1;
+    bool             mHasGraphiteTables : 1;
+    bool             mCheckedForGraphiteTables : 1;
+    bool             mHasCmapTable : 1;
+    bool             mGrFaceInitialized : 1;
 
     // bitvector of substitution space features per script
     uint32_t         mHasSpaceFeaturesSub[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
 
     uint16_t         mWeight;
     int16_t          mStretch;
 
-    bool             mHasGraphiteTables;
-    bool             mCheckedForGraphiteTables;
-    bool             mHasCmapTable;
     nsRefPtr<gfxCharacterMap> mCharacterMap;
     uint32_t         mUVSOffset;
     nsAutoArrayPtr<uint8_t> mUVSData;
     gfxUserFontData* mUserFontData;
     gfxSVGGlyphs    *mSVGGlyphs;
 
     nsTArray<gfxFontFeature> mFeatureSettings;
     uint32_t         mLanguageOverride;
@@ -410,34 +467,82 @@ protected:
         mIgnoreGDEF(false),
         mIgnoreGSUB(false),
         mSVGInitialized(false),
         mHasSpaceFeaturesInitialized(false),
         mHasSpaceFeatures(false),
         mHasSpaceFeaturesKerning(false),
         mHasSpaceFeaturesNonKerning(false),
         mHasSpaceFeaturesSubDefault(false),
-        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mCheckedForGraphiteTables(false),
         mHasCmapTable(false),
+        mGrFaceInitialized(false),
+        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
-        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
+        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
+        mHBFace(nullptr),
+        mGrFace(nullptr),
+        mGrFaceRefCnt(0)
     { }
 
     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;
+    }
+
+protected:
+    // 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.
@@ -687,18 +792,18 @@ public:
 
 protected:
     // 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,
-                                       FallibleTArray<uint8_t>& aNameTable,
-                                       bool useFullName = false);
+                                     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;
             }
@@ -1302,31 +1407,16 @@ public:
         return mFontEntry->HasCmapTable();
     }
 
     // check whether this is an sfnt we can potentially use with Graphite
     bool FontCanSupportGraphite() {
         return mFontEntry->HasGraphiteTables();
     }
 
-    // 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 released.
-    //
-    // Default implementations forward to the font entry,
-    // and maintain a shared table.
-    //
-    // Subclasses should override this if they can provide more efficient
-    // access than getting tables with mFontEntry->GetFontTable() and sharing
-    // them via the entry.
-    //
-    // Get pointer to a specific font table, or NULL if
-    // the table doesn't exist in the font
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
-
     // Subclasses may choose to look up glyph ids for characters.
     // If they do not override this, gfxHarfBuzzShaper will fetch the cmap
     // table and use that.
     virtual bool ProvidesGetGlyph() const {
         return false;
     }
     // Map unicode character to glyph ID.
     // Only used if ProvidesGetGlyph() returns true.
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -15,16 +15,18 @@
 #include "nsServiceManagerUtils.h"
 
 #include "mozilla/Preferences.h"
 
 #include "nsIUUIDGenerator.h"
 #include "nsMemory.h"
 #include "nsICharsetConverterManager.h"
 
+#include "harfbuzz/hb.h"
+
 #include "plbase64.h"
 #include "prlog.h"
 
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #ifdef PR_LOGGING
@@ -1210,27 +1212,28 @@ gfxFontUtils::GetFullNameFromSFNT(const 
     }
     
     // should never fail, as we're only called after font validation succeeded
     NS_ENSURE_TRUE(foundName, NS_ERROR_NOT_AVAILABLE);
 
     uint32_t len = dirEntry->length;
     NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
                    NS_ERROR_UNEXPECTED);
-    FallibleTArray<uint8_t> nameTable;
-    if (!nameTable.SetLength(len)) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-    memcpy(nameTable.Elements(), aFontData + dirEntry->offset, len);
 
-    return GetFullNameFromTable(nameTable, aFullName);
+    hb_blob_t *nameBlob =
+        hb_blob_create((const char*)aFontData + dirEntry->offset, len,
+                       HB_MEMORY_MODE_READONLY, nullptr, nullptr);
+    nsresult rv = GetFullNameFromTable(nameBlob, aFullName);
+    hb_blob_destroy(nameBlob);
+
+    return rv;
 }
 
 nsresult
-gfxFontUtils::GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+gfxFontUtils::GetFullNameFromTable(hb_blob_t *aNameTable,
                                    nsAString& aFullName)
 {
     nsAutoString name;
     nsresult rv =
         gfxFontUtils::ReadCanonicalName(aNameTable,
                                         gfxFontUtils::NAME_ID_FULL,
                                         name);
     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
@@ -1252,17 +1255,17 @@ gfxFontUtils::GetFullNameFromTable(Falli
         }
         return NS_OK;
     }
 
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsresult
-gfxFontUtils::GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+gfxFontUtils::GetFamilyNameFromTable(hb_blob_t *aNameTable,
                                      nsAString& aFullName)
 {
     nsAutoString name;
     nsresult rv =
         gfxFontUtils::ReadCanonicalName(aNameTable,
                                         gfxFontUtils::NAME_ID_FAMILY,
                                         name);
     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
@@ -1278,24 +1281,24 @@ enum {
     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
 #else
     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
 #endif
 };    
 
 nsresult
-gfxFontUtils::ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+gfxFontUtils::ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
                         int32_t aPlatformID, nsTArray<nsString>& aNames)
 {
     return ReadNames(aNameTable, aNameID, LANG_ALL, aPlatformID, aNames);
 }
 
 nsresult
-gfxFontUtils::ReadCanonicalName(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+gfxFontUtils::ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID, 
                                 nsString& aName)
 {
     nsresult rv;
     
     nsTArray<nsString> names;
     
     // first, look for the English name (this will succeed 99% of the time)
     rv = ReadNames(aNameTable, aNameID, CANONICAL_LANG_ID, PLATFORM_ID, names);
@@ -1453,17 +1456,17 @@ gfxFontUtils::GetCharsetForFontName(uint
     }
 
     return nullptr;
 }
 
 // convert a raw name from the name table to an nsString, if possible;
 // return value indicates whether conversion succeeded
 bool
-gfxFontUtils::DecodeFontName(const uint8_t *aNameData, int32_t aByteLen, 
+gfxFontUtils::DecodeFontName(const char *aNameData, int32_t aByteLen, 
                              uint32_t aPlatformCode, uint32_t aScriptCode,
                              uint32_t aLangCode, nsAString& aName)
 {
     NS_ASSERTION(aByteLen > 0, "bad length for font name data");
 
     const char *csName = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
 
     if (!csName) {
@@ -1503,47 +1506,47 @@ gfxFontUtils::DecodeFontName(const uint8
     nsCOMPtr<nsIUnicodeDecoder> decoder;
     rv = ccm->GetUnicodeDecoderRaw(csName, getter_AddRefs(decoder));
     if (NS_FAILED(rv)) {
         NS_WARNING("failed to get the decoder for a font name string");
         return false;
     }
 
     int32_t destLength;
-    rv = decoder->GetMaxLength(reinterpret_cast<const char*>(aNameData), aByteLen, &destLength);
+    rv = decoder->GetMaxLength(aNameData, aByteLen, &destLength);
     if (NS_FAILED(rv)) {
         NS_WARNING("decoder->GetMaxLength failed, invalid font name?");
         return false;
     }
 
     // make space for the converted string
     aName.SetLength(destLength);
-    rv = decoder->Convert(reinterpret_cast<const char*>(aNameData), &aByteLen,
+    rv = decoder->Convert(aNameData, &aByteLen,
                           aName.BeginWriting(), &destLength);
     if (NS_FAILED(rv)) {
         NS_WARNING("decoder->Convert failed, invalid font name?");
         return false;
     }
     aName.Truncate(destLength); // set the actual length
 
     return true;
 }
 
 nsresult
-gfxFontUtils::ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+gfxFontUtils::ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
                         int32_t aLangID, int32_t aPlatformID,
                         nsTArray<nsString>& aNames)
 {
-    uint32_t nameTableLen = aNameTable.Length();
+    uint32_t nameTableLen;
+    const char *nameTable = hb_blob_get_data(aNameTable, &nameTableLen);
     NS_ASSERTION(nameTableLen != 0, "null name table");
 
-    if (nameTableLen == 0)
+    if (!nameTableLen) {
         return NS_ERROR_FAILURE;
-
-    uint8_t *nameTable = aNameTable.Elements();
+    }
 
     // -- name table data
     const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(nameTable);
 
     uint32_t nameCount = nameHeader->count;
 
     // -- sanity check the number of name records
     if (uint64_t(nameCount) * sizeof(NameRecord) > nameTableLen) {
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -28,16 +28,18 @@
 #include <algorithm>
 
 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
 #ifdef __MINGW32__
 #undef min
 #undef max
 #endif
 
+typedef struct hb_blob_t hb_blob_t;
+
 class gfxSparseBitSet {
 private:
     enum { BLOCK_SIZE = 32 };   // ==> 256 codepoints per block
     enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
     enum { BLOCK_INDEX_SHIFT = 8 };
 
     struct Block {
         Block(const Block& aBlock) { memcpy(mBits, aBlock.mBits, sizeof(mBits)); }
@@ -824,46 +826,46 @@ public:
     // so it should always succeed in finding the name table.
     static nsresult
     GetFullNameFromSFNT(const uint8_t* aFontData, uint32_t aLength,
                         nsAString& aFullName);
 
     // helper to get fullname from name table, constructing from family+style
     // if no explicit fullname is present
     static nsresult
-    GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+    GetFullNameFromTable(hb_blob_t *aNameTable,
                          nsAString& aFullName);
 
     // helper to get family name from name table
     static nsresult
-    GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+    GetFamilyNameFromTable(hb_blob_t *aNameTable,
                            nsAString& aFamilyName);
 
     // create a new name table and build a new font with that name table
     // appended on the end, returns true on success
     static nsresult
     RenameFont(const nsAString& aName, const uint8_t *aFontData, 
                uint32_t aFontDataLength, FallibleTArray<uint8_t> *aNewFont);
     
     // read all names matching aNameID, returning in aNames array
     static nsresult
-    ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+    ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
               int32_t aPlatformID, nsTArray<nsString>& aNames);
       
     // reads English or first name matching aNameID, returning in aName
     // platform based on OS
     static nsresult
-    ReadCanonicalName(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+    ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID, 
                       nsString& aName);
       
     // convert a name from the raw name table data into an nsString,
     // provided we know how; return true if successful, or false
     // if we can't handle the encoding
     static bool
-    DecodeFontName(const uint8_t *aBuf, int32_t aLength, 
+    DecodeFontName(const char *aBuf, int32_t aLength, 
                    uint32_t aPlatformCode, uint32_t aScriptCode,
                    uint32_t aLangCode, nsAString& dest);
 
     static inline bool IsJoinCauser(uint32_t ch) {
         return (ch == 0x200D);
     }
 
     static inline bool IsJoinControl(uint32_t ch) {
@@ -929,17 +931,17 @@ public:
     static void GetPrefsFontList(const char *aPrefName, 
                                  nsTArray<nsString>& aFontList);
 
     // generate a unique font name
     static nsresult MakeUniqueUserFontName(nsAString& aName);
 
 protected:
     static nsresult
-    ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+    ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
               int32_t aLangID, int32_t aPlatformID, nsTArray<nsString>& aNames);
 
     // convert opentype name-table platform/encoding/language values to a charset name
     // we can use to convert the name data to unicode, or "" if data is UTF16BE
     static const char*
     GetCharsetForFontName(uint16_t aPlatform, uint16_t aScript, uint16_t aLanguage);
 
     struct MacFontNameCharsetMapping {
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -194,17 +194,17 @@ GDIFontEntry::ReadCMAP()
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
     uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
     nsresult rv;
 
     AutoFallibleTArray<uint8_t,16384> cmap;
-    rv = GetFontTable(kCMAP, cmap);
+    rv = CopyFontTable(kCMAP, cmap);
 
     bool unicodeFont = false, symbolFont = false; // currently ignored
 
     if (NS_SUCCEEDED(rv)) {
         rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
                                     *charmap, mUVSOffset,
                                     unicodeFont, symbolFont);
     }
@@ -258,18 +258,18 @@ GDIFontEntry::CreateFontInstance(const g
           gfxWindowsPlatform::GetPlatform()->UseClearTypeForDownloadableFonts()));
 
     return new gfxGDIFont(this, aFontStyle, aNeedsBold, 
                           (useClearType ? gfxFont::kAntialiasSubpixel
                                         : gfxFont::kAntialiasDefault));
 }
 
 nsresult
-GDIFontEntry::GetFontTable(uint32_t aTableTag,
-                           FallibleTArray<uint8_t>& aBuffer)
+GDIFontEntry::CopyFontTable(uint32_t aTableTag,
+                            FallibleTArray<uint8_t>& aBuffer)
 {
     if (!IsTrueType()) {
         return NS_ERROR_FAILURE;
     }
 
     AutoDC dc;
     AutoSelectFont font(dc.GetDC(), &mLogFont);
     if (font.IsValid()) {
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -275,18 +275,18 @@ protected:
     GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
                  bool aItalic, uint16_t aWeight, int16_t aStretch,
                  gfxUserFontData *aUserFontData, bool aFamilyHasItalicFace);
 
     void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
 
-    virtual nsresult GetFontTable(uint32_t aTableTag,
-                                  FallibleTArray<uint8_t>& aBuffer);
+    virtual nsresult CopyFontTable(uint32_t aTableTag,
+                                   FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
     LOGFONTW mLogFont;
 };
 
 // a single font family, referencing one or more faces
 class GDIFontFamily : public gfxFontFamily
 {
 public:
--- a/gfx/thebes/gfxGraphiteShaper.cpp
+++ b/gfx/thebes/gfxGraphiteShaper.cpp
@@ -35,79 +35,36 @@
 using namespace mozilla; // for AutoSwap_* types
 
 /*
  * Creation and destruction; on deletion, release any font tables we're holding
  */
 
 gfxGraphiteShaper::gfxGraphiteShaper(gfxFont *aFont)
     : gfxFontShaper(aFont),
-      mGrFace(nullptr),
+      mGrFace(mFont->GetFontEntry()->GetGrFace()),
       mGrFont(nullptr)
 {
-    mTables.Init();
     mCallbackData.mFont = aFont;
     mCallbackData.mShaper = this;
 }
 
-PLDHashOperator
-ReleaseTableFunc(const uint32_t& /* aKey */,
-                 gfxGraphiteShaper::TableRec& aData,
-                 void* /* aUserArg */)
-{
-    hb_blob_destroy(aData.mBlob);
-    return PL_DHASH_REMOVE;
-}
-
 gfxGraphiteShaper::~gfxGraphiteShaper()
 {
     if (mGrFont) {
         gr_font_destroy(mGrFont);
     }
-    if (mGrFace) {
-        gr_face_destroy(mGrFace);
-    }
-    mTables.Enumerate(ReleaseTableFunc, nullptr);
-}
-
-static const void*
-GrGetTable(const void* appFaceHandle, unsigned int name, size_t *len)
-{
-    const gfxGraphiteShaper::CallbackData *cb =
-        static_cast<const gfxGraphiteShaper::CallbackData*>(appFaceHandle);
-    return cb->mShaper->GetTable(name, len);
+    mFont->GetFontEntry()->ReleaseGrFace(mGrFace);
 }
 
-const void*
-gfxGraphiteShaper::GetTable(uint32_t aTag, size_t *aLength)
+/*static*/ float
+gfxGraphiteShaper::GrGetAdvance(const void* appFontHandle, uint16_t glyphid)
 {
-    TableRec tableRec;
-
-    if (!mTables.Get(aTag, &tableRec)) {
-        hb_blob_t *blob = mFont->GetFontTable(aTag);
-        if (blob) {
-            // mFont->GetFontTable() gives us a reference to the blob.
-            // We will destroy (release) it in our destructor.
-            tableRec.mBlob = blob;
-            tableRec.mData = hb_blob_get_data(blob, &tableRec.mLength);
-            mTables.Put(aTag, tableRec);
-        } else {
-            return nullptr;
-        }
-    }
-
-    *aLength = tableRec.mLength;
-    return tableRec.mData;
-}
-
-static float
-GrGetAdvance(const void* appFontHandle, gr_uint16 glyphid)
-{
-    const gfxGraphiteShaper::CallbackData *cb =
-        static_cast<const gfxGraphiteShaper::CallbackData*>(appFontHandle);
+    const CallbackData *cb =
+        static_cast<const CallbackData*>(appFontHandle);
     return FixedToFloat(cb->mFont->GetGlyphWidth(cb->mContext, glyphid));
 }
 
 static inline uint32_t
 MakeGraphiteLangTag(uint32_t aTag)
 {
     uint32_t grLangTag = aTag;
     // replace trailing space-padding with NULs for graphite
@@ -147,17 +104,16 @@ gfxGraphiteShaper::ShapeText(gfxContext 
     // some font back-ends require this in order to get proper hinted metrics
     if (!mFont->SetupCairoFont(aContext)) {
         return false;
     }
 
     mCallbackData.mContext = aContext;
 
     if (!mGrFont) {
-        mGrFace = gr_make_face(&mCallbackData, GrGetTable, gr_face_default);
         if (!mGrFace) {
             return false;
         }
 
         if (mFont->ProvidesGlyphWidths()) {
             gr_font_ops ops = {
                 sizeof(gr_font_ops),
                 &GrGetAdvance,
@@ -165,18 +121,16 @@ gfxGraphiteShaper::ShapeText(gfxContext 
             };
             mGrFont = gr_make_font_with_ops(mFont->GetAdjustedSize(),
                                             &mCallbackData, &ops, mGrFace);
         } else {
             mGrFont = gr_make_font(mFont->GetAdjustedSize(), mGrFace);
         }
 
         if (!mGrFont) {
-            gr_face_destroy(mGrFace);
-            mGrFace = nullptr;
             return false;
         }
     }
 
     gfxFontEntry *entry = mFont->GetFontEntry();
     const gfxFontStyle *style = mFont->GetStyle();
     uint32_t grLang = 0;
     if (style->languageOverride) {
--- a/gfx/thebes/gfxGraphiteShaper.h
+++ b/gfx/thebes/gfxGraphiteShaper.h
@@ -22,45 +22,38 @@ public:
 
     virtual bool ShapeText(gfxContext      *aContext,
                            const PRUnichar *aText,
                            uint32_t         aOffset,
                            uint32_t         aLength,
                            int32_t          aScript,
                            gfxShapedText   *aShapedText);
 
-    const void* GetTable(uint32_t aTag, size_t *aLength);
-
     static void Shutdown();
 
-    struct CallbackData {
-        gfxFont           *mFont;
-        gfxGraphiteShaper *mShaper;
-        gfxContext        *mContext;
-    };
-
-    struct TableRec {
-        hb_blob_t  *mBlob;
-        const void *mData;
-        uint32_t    mLength;
-    };
-
 protected:
     nsresult SetGlyphsFromSegment(gfxContext      *aContext,
                                   gfxShapedText   *aShapedText,
                                   uint32_t         aOffset,
                                   uint32_t         aLength,
                                   const PRUnichar *aText,
                                   gr_segment      *aSegment);
 
-    gr_face *mGrFace;
-    gr_font *mGrFont;
+    static float GrGetAdvance(const void* appFontHandle, uint16_t glyphid);
+
+    gr_face *mGrFace; // owned by the font entry; shaper must call
+                      // gfxFontEntry::ReleaseGrFace when finished with it
+    gr_font *mGrFont; // owned by the shaper itself
+
+    struct CallbackData {
+        gfxFont           *mFont;
+        gfxGraphiteShaper *mShaper;
+        gfxContext        *mContext;
+    };
 
     CallbackData mCallbackData;
 
-    nsDataHashtable<nsUint32HashKey,TableRec> mTables;
-
     // Convert HTML 'lang' (BCP47) to Graphite language code
     static uint32_t GetGraphiteTagForLang(const nsCString& aLang);
     static nsTHashtable<nsUint32HashKey> sLanguageTags;
 };
 
 #endif /* GFX_GRAPHITESHAPER_H */
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -38,82 +38,50 @@ using namespace mozilla; // for AutoSwap
 using namespace mozilla::unicode; // for Unicode property lookup
 
 /*
  * Creation and destruction; on deletion, release any font tables we're holding
  */
 
 gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont)
     : gfxFontShaper(aFont),
-      mHBFace(nullptr),
+      mHBFace(aFont->GetFontEntry()->GetHBFace()),
+      mHBFont(nullptr),
       mKernTable(nullptr),
       mHmtxTable(nullptr),
       mNumLongMetrics(0),
       mCmapTable(nullptr),
       mCmapFormat(-1),
       mSubtableOffset(0),
       mUVSTableOffset(0),
       mUseFontGetGlyph(aFont->ProvidesGetGlyph()),
-      mUseFontGlyphWidths(false)
+      mUseFontGlyphWidths(false),
+      mInitialized(false)
 {
 }
 
 gfxHarfBuzzShaper::~gfxHarfBuzzShaper()
 {
-    hb_blob_destroy(mCmapTable);
-    hb_blob_destroy(mHmtxTable);
-    hb_blob_destroy(mKernTable);
-    hb_face_destroy(mHBFace);
-}
-
-/*
- * HarfBuzz callback access to font table data
- */
-
-// callback for HarfBuzz to get a font table (in hb_blob_t form)
-// from the shaper (passed as aUserData)
-static hb_blob_t *
-HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData)
-{
-    gfxHarfBuzzShaper *shaper = static_cast<gfxHarfBuzzShaper*>(aUserData);
-    gfxFont *font = shaper->GetFont();
-
-    // 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') &&
-        font->GetFontEntry()->IgnoreGDEF()) {
-        return nullptr;
+    if (mCmapTable) {
+        hb_blob_destroy(mCmapTable);
+    }
+    if (mHmtxTable) {
+        hb_blob_destroy(mHmtxTable);
     }
-
-    // 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') &&
-        font->GetFontEntry()->IgnoreGSUB()) {
-        return nullptr;
+    if (mKernTable) {
+        hb_blob_destroy(mKernTable);
     }
-
-    return font->GetFontTable(aTag);
+    if (mHBFont) {
+        hb_font_destroy(mHBFont);
+    }
+    if (mHBFace) {
+        hb_face_destroy(mHBFace);
+    }
 }
 
-/*
- * HarfBuzz font callback functions; font_data is a ptr to a
- * FontCallbackData struct
- */
-
-struct FontCallbackData {
-    FontCallbackData(gfxHarfBuzzShaper *aShaper, gfxContext *aContext,
-                     bool aKerning)
-        : mShaper(aShaper), mContext(aContext), mKerning(aKerning)
-    { }
-
-    gfxHarfBuzzShaper *mShaper;
-    gfxContext        *mContext;
-    bool               mKerning;
-};
-
 #define UNICODE_BMP_LIMIT 0x10000
 
 hb_codepoint_t
 gfxHarfBuzzShaper::GetGlyph(hb_codepoint_t unicode,
                             hb_codepoint_t variation_selector) const
 {
     hb_codepoint_t gid;
 
@@ -170,18 +138,18 @@ gfxHarfBuzzShaper::GetGlyph(hb_codepoint
 }
 
 static hb_bool_t
 HBGetGlyph(hb_font_t *font, void *font_data,
            hb_codepoint_t unicode, hb_codepoint_t variation_selector,
            hb_codepoint_t *glyph,
            void *user_data)
 {
-    const FontCallbackData *fcd =
-        static_cast<const FontCallbackData*>(font_data);
+    const gfxHarfBuzzShaper::FontCallbackData *fcd =
+        static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
     *glyph = fcd->mShaper->GetGlyph(unicode, variation_selector);
     return *glyph != 0;
 }
 
 struct HMetricsHeader {
     AutoSwap_PRUint32    tableVersionNumber;
     AutoSwap_PRInt16     ascender;
     AutoSwap_PRInt16     descender;
@@ -235,18 +203,18 @@ gfxHarfBuzzShaper::GetGlyphHAdvance(gfxC
     return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
                         uint16_t(hmtx->metrics[glyph].advanceWidth));
 }
 
 static hb_position_t
 HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
                    hb_codepoint_t glyph, void *user_data)
 {
-    const FontCallbackData *fcd =
-        static_cast<const FontCallbackData*>(font_data);
+    const gfxHarfBuzzShaper::FontCallbackData *fcd =
+        static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
     return fcd->mShaper->GetGlyphHAdvance(fcd->mContext, glyph);
 }
 
 static hb_bool_t
 HBGetContourPoint(hb_font_t *font, void *font_data,
                   unsigned int point_index, hb_codepoint_t glyph,
                   hb_position_t *x, hb_position_t *y,
                   void *user_data)
@@ -495,17 +463,17 @@ gfxHarfBuzzShaper::GetHKerning(uint16_t 
     // handling words in isolation, the only space characters seen here are
     // the ones artificially added by the textRun code.
     uint32_t spaceGlyph = mFont->GetSpaceGlyph();
     if (aFirstGlyph == spaceGlyph || aSecondGlyph == spaceGlyph) {
         return 0;
     }
 
     if (!mKernTable) {
-        mKernTable = mFont->GetFontTable(TRUETYPE_TAG('k','e','r','n'));
+        mKernTable = mFont->GetFontEntry()->GetFontTable(TRUETYPE_TAG('k','e','r','n'));
         if (!mKernTable) {
             mKernTable = hb_blob_get_empty();
         }
     }
 
     uint32_t len;
     const char* base = hb_blob_get_data(mKernTable, &len);
     if (len < sizeof(KernTableVersion0)) {
@@ -639,25 +607,19 @@ gfxHarfBuzzShaper::GetHKerning(uint16_t 
     return 0;
 }
 
 static hb_position_t
 HBGetHKerning(hb_font_t *font, void *font_data,
               hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
               void *user_data)
 {
-    const FontCallbackData *fcd =
-        static_cast<const FontCallbackData*>(font_data);
-
-    // return 0 if kerning is explicitly disabled
-    if (fcd->mKerning) {
-        return fcd->mShaper->GetHKerning(first_glyph, second_glyph);
-    } else {
-        return 0.0;
-    }
+    const gfxHarfBuzzShaper::FontCallbackData *fcd =
+        static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
+    return fcd->mShaper->GetHKerning(first_glyph, second_glyph);
 }
 
 /*
  * HarfBuzz unicode property callbacks
  */
 
 static hb_codepoint_t
 HBGetMirroring(hb_unicode_funcs_t *ufuncs, hb_codepoint_t aCh,
@@ -854,22 +816,25 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
                              int32_t          aScript,
                              gfxShapedText   *aShapedText)
 {
     // some font back-ends require this in order to get proper hinted metrics
     if (!mFont->SetupCairoFont(aContext)) {
         return false;
     }
 
-    if (!mHBFace) {
+    mCallbackData.mContext = aContext;
+    gfxFontEntry *entry = mFont->GetFontEntry();
+
+    if (!mInitialized) {
+        mInitialized = true;
+        mCallbackData.mShaper = this;
 
         mUseFontGlyphWidths = mFont->ProvidesGlyphWidths();
 
-        // set up the harfbuzz face etc the first time we use the font
-
         if (!sHBFontFuncs) {
             // static function callback pointers, initialized by the first
             // harfbuzz shaper used
             sHBFontFuncs = hb_font_funcs_create();
             hb_font_funcs_set_glyph_func(sHBFontFuncs, HBGetGlyph,
                                          nullptr, nullptr);
             hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs,
                                                    HBGetGlyphHAdvance,
@@ -900,21 +865,19 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
             hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs,
                                               HBUnicodeCompose,
                                               nullptr, nullptr);
             hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs,
                                                 HBUnicodeDecompose,
                                                 nullptr, nullptr);
         }
 
-        mHBFace = hb_face_create_for_tables(HBGetTable, this, nullptr);
-
         if (!mUseFontGetGlyph) {
             // get the cmap table and find offset to our subtable
-            mCmapTable = mFont->GetFontTable(TRUETYPE_TAG('c','m','a','p'));
+            mCmapTable = entry->GetFontTable(TRUETYPE_TAG('c','m','a','p'));
             if (!mCmapTable) {
                 NS_WARNING("failed to load cmap, glyphs will be missing");
                 return false;
             }
             uint32_t len;
             const uint8_t* data = (const uint8_t*)hb_blob_get_data(mCmapTable, &len);
             bool symbol;
             mCmapFormat = gfxFontUtils::
@@ -923,71 +886,65 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
                                       &symbol);
         }
 
         if (!mUseFontGlyphWidths) {
             // if font doesn't implement GetGlyphWidth, we will be reading
             // the hmtx table directly;
             // read mNumLongMetrics from hhea table without caching its blob,
             // and preload/cache the hmtx table
-            hb_blob_t *hheaTable =
-                mFont->GetFontTable(TRUETYPE_TAG('h','h','e','a'));
+            gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a'));
             if (hheaTable) {
                 uint32_t len;
                 const HMetricsHeader* hhea =
                     reinterpret_cast<const HMetricsHeader*>
                         (hb_blob_get_data(hheaTable, &len));
                 if (len >= sizeof(HMetricsHeader)) {
                     mNumLongMetrics = hhea->numberOfHMetrics;
                     if (mNumLongMetrics > 0 &&
                         int16_t(hhea->metricDataFormat) == 0) {
                         // no point reading hmtx if number of entries is zero!
                         // in that case, we won't be able to use this font
                         // (this method will return FALSE below if mHmtx is null)
                         mHmtxTable =
-                            mFont->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
+                            entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
                         if (hb_blob_get_length(mHmtxTable) <
                             mNumLongMetrics * sizeof(HLongMetric)) {
                             // hmtx table is not large enough for the claimed
                             // number of entries: invalid, do not use.
                             hb_blob_destroy(mHmtxTable);
                             mHmtxTable = nullptr;
                         }
                     }
                 }
             }
-            hb_blob_destroy(hheaTable);
         }
+
+        mHBFont = hb_font_create(mHBFace);
+        hb_font_set_funcs(mHBFont, sHBFontFuncs, &mCallbackData, nullptr);
+        hb_font_set_ppem(mHBFont, mFont->GetAdjustedSize(), mFont->GetAdjustedSize());
+        uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point
+        hb_font_set_scale(mHBFont, scale, scale);
     }
 
     if ((!mUseFontGetGlyph && mCmapFormat <= 0) ||
         (!mUseFontGlyphWidths && !mHmtxTable)) {
         // unable to shape with this font
         return false;
     }
 
     const gfxFontStyle *style = mFont->GetStyle();
-    // kerning is enabled *except* when explicitly disabled (font-kerning: none)
-    FontCallbackData fcd(this, aContext, !mFont->KerningDisabled());
-    hb_font_t *font = hb_font_create(mHBFace);
-    hb_font_set_funcs(font, sHBFontFuncs, &fcd, nullptr);
-    hb_font_set_ppem(font, mFont->GetAdjustedSize(), mFont->GetAdjustedSize());
-    uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point
-    hb_font_set_scale(font, scale, scale);
 
     nsAutoTArray<hb_feature_t,20> features;
-
-    gfxFontEntry *entry = mFont->GetFontEntry();
-
     nsDataHashtable<nsUint32HashKey,uint32_t> mergedFeatures;
 
     if (MergeFontFeatures(style,
-                          mFont->GetFontEntry()->mFeatureSettings,
+                          entry->mFeatureSettings,
                           aShapedText->DisableLigatures(),
-                          mFont->GetFontEntry()->FamilyName(),
+                          entry->FamilyName(),
                           mergedFeatures))
     {
         // enumerate result and insert into hb_feature array
         mergedFeatures.Enumerate(AddFeature, &features);
     }
 
     bool isRightToLeft = aShapedText->IsRightToLeft();
     hb_buffer_t *buffer = hb_buffer_create();
@@ -1015,28 +972,27 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
     }
     hb_buffer_set_language(buffer, language);
 
     uint32_t length = aLength;
     hb_buffer_add_utf16(buffer,
                         reinterpret_cast<const uint16_t*>(aText),
                         length, 0, length);
 
-    hb_shape(font, buffer, features.Elements(), features.Length());
+    hb_shape(mHBFont, buffer, features.Elements(), features.Length());
 
     if (isRightToLeft) {
         hb_buffer_reverse(buffer);
     }
 
     nsresult rv = SetGlyphsFromRun(aContext, aShapedText, aOffset, aLength,
                                    aText, buffer);
 
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store glyphs into gfxShapedWord");
     hb_buffer_destroy(buffer);
-    hb_font_destroy(font);
 
     return NS_SUCCEEDED(rv);
 }
 
 #define SMALL_GLYPH_RUN 128 // some testing indicates that 90%+ of text runs
                             // will fit without requiring separate allocation
                             // for charToGlyphArray
 
--- a/gfx/thebes/gfxHarfBuzzShaper.h
+++ b/gfx/thebes/gfxHarfBuzzShaper.h
@@ -13,16 +13,25 @@
 
 #include "harfbuzz/hb.h"
 
 class gfxHarfBuzzShaper : public gfxFontShaper {
 public:
     gfxHarfBuzzShaper(gfxFont *aFont);
     virtual ~gfxHarfBuzzShaper();
 
+    /*
+     * For HarfBuzz font callback functions, font_data is a ptr to a
+     * FontCallbackData struct
+     */
+    struct FontCallbackData {
+        gfxHarfBuzzShaper *mShaper;
+        gfxContext        *mContext;
+    };
+
     virtual bool ShapeText(gfxContext      *aContext,
                            const PRUnichar *aText,
                            uint32_t         aOffset,
                            uint32_t         aLength,
                            int32_t          aScript,
                            gfxShapedText   *aShapedText);
 
     // get a given font table in harfbuzz blob form
@@ -49,19 +58,25 @@ protected:
 
     // retrieve glyph positions, applying advance adjustments and attachments
     // returns results in appUnits
     nscoord GetGlyphPositions(gfxContext *aContext,
                               hb_buffer_t *aBuffer,
                               nsTArray<nsPoint>& aPositions,
                               uint32_t aAppUnitsPerDevUnit);
 
-    // harfbuzz face object, created on first use (caches font tables)
+    // harfbuzz face object: we acquire a reference from the font entry
+    // on shaper creation, and release it in our destructor
     hb_face_t         *mHBFace;
 
+    // size-specific font object, owned by the gfxHarfBuzzShaper
+    hb_font_t         *mHBFont;
+
+    FontCallbackData   mCallbackData;
+
     // Following table references etc are declared "mutable" because the
     // harfbuzz callback functions take a const ptr to the shaper, but
     // wish to cache tables here to avoid repeatedly looking them up
     // in the font.
 
     // Old-style TrueType kern table, if we're not doing GPOS kerning
     mutable hb_blob_t *mKernTable;
 
@@ -82,11 +97,13 @@ protected:
     mutable uint32_t   mUVSTableOffset;
 
     // Whether the font implements GetGlyph, or we should read tables
     // directly
     bool mUseFontGetGlyph;
     // Whether the font implements GetGlyphWidth, or we should read tables
     // directly to get ideal widths
     bool mUseFontGlyphWidths;
+
+    bool mInitialized;
 };
 
 #endif /* GFX_HARFBUZZSHAPER_H */
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -184,23 +184,27 @@ gfxMacFont::InitMetrics()
 
     uint32_t upem = 0;
 
     // try to get unitsPerEm from sfnt head table, to avoid calling CGFont
     // if possible (bug 574368) and because CGFontGetUnitsPerEm does not
     // return the true value for OpenType/CFF fonts (it normalizes to 1000,
     // which then leads to metrics errors when we read the 'hmtx' table to
     // get glyph advances for HarfBuzz, see bug 580863)
-    const uint32_t kHeadTableTag = TRUETYPE_TAG('h','e','a','d');
-    AutoFallibleTArray<uint8_t,sizeof(HeadTable)> headData;
-    if (NS_SUCCEEDED(mFontEntry->GetFontTable(kHeadTableTag, headData)) &&
-        headData.Length() >= sizeof(HeadTable)) {
-        HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements());
-        upem = head->unitsPerEm;
-    } else {
+    CFDataRef headData =
+        ::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('h','e','a','d'));
+    if (headData) {
+        if (size_t(::CFDataGetLength(headData)) >= sizeof(HeadTable)) {
+            const HeadTable *head =
+                reinterpret_cast<const HeadTable*>(::CFDataGetBytePtr(headData));
+            upem = head->unitsPerEm;
+        }
+        ::CFRelease(headData);
+    }
+    if (!upem) {
         upem = ::CGFontGetUnitsPerEm(mCGFont);
     }
 
     if (upem < 16 || upem > 16384) {
         // See http://www.microsoft.com/typography/otspec/head.htm
 #ifdef DEBUG
         char warnBuf[1024];
         sprintf(warnBuf, "Bad font metrics for: %s (invalid unitsPerEm value)",
@@ -343,45 +347,16 @@ gfxMacFont::GetCharWidth(CFDataRef aCmap
         if (::CGFontGetGlyphAdvances(mCGFont, &glyph, 1, &advance)) {
             return advance * aConvFactor;
         }
     }
 
     return 0;
 }
 
-/*static*/ void
-gfxMacFont::DestroyBlobFunc(void* aUserData)
-{
-    ::CFRelease((CFDataRef)aUserData);
-}
-
-hb_blob_t *
-gfxMacFont::GetFontTable(uint32_t aTag)
-{
-    CFDataRef dataRef = ::CGFontCopyTableForTag(mCGFont, aTag);
-    if (dataRef) {
-        return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
-                              ::CFDataGetLength(dataRef),
-                              HB_MEMORY_MODE_READONLY,
-                              (void*)dataRef, DestroyBlobFunc);
-    }
-
-    if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
-        // for downloaded fonts, there may be layout tables cached in the entry
-        // even though they're absent from the sanitized platform font
-        hb_blob_t *blob;
-        if (mFontEntry->GetExistingFontTable(aTag, &blob)) {
-            return blob;
-        }
-    }
-
-    return nullptr;
-}
-
 // Try to initialize font metrics via platform APIs (CG/CT),
 // and set mIsValid = TRUE on success.
 // We ONLY call this for local (platform) fonts that are not sfnt format;
 // for sfnts, including ALL downloadable fonts, we prefer to use
 // InitMetricsFromSfntTables and avoid platform APIs.
 void
 gfxMacFont::InitMetricsFromPlatform()
 {
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -35,20 +35,16 @@ public:
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                gfxContext *aContextForTightBoundingBox,
                                Spacing *aSpacing);
 
-    // override gfxFont table access function to bypass gfxFontEntry cache,
-    // use CGFontRef API to get direct access to system font data
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
-
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget);
 
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontCacheSizes*   aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontCacheSizes*   aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_MAC; }
@@ -68,18 +64,16 @@ protected:
     void InitMetrics();
     void InitMetricsFromPlatform();
 
     // Get width and glyph ID for a character; uses aConvFactor
     // to convert font units as returned by CG to actual dimensions
     gfxFloat GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar,
                           uint32_t *aGlyphID, gfxFloat aConvFactor);
 
-    static void DestroyBlobFunc(void* aUserData);
-
     // a weak reference to the CoreGraphics font: this is owned by the
     // MacOSFontEntry, it is not retained or released by gfxMacFont
     CGFontRef             mCGFont;
 
     cairo_font_face_t    *mFontFace;
 
     Metrics               mMetrics;
     uint32_t              mSpaceGlyph;
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -35,33 +35,36 @@ public:
                    bool aIsUserFont, bool aIsLocal);
 
     virtual ~MacOSFontEntry() {
         ::CGFontRelease(mFontRef);
     }
 
     virtual CGFontRef GetFontRef();
 
-    virtual nsresult GetFontTable(uint32_t aTableTag,
-                                  FallibleTArray<uint8_t>& aBuffer);
+    // override gfxFontEntry table access function to bypass table cache,
+    // use CGFontRef API to get direct access to system font data
+    virtual hb_blob_t *GetFontTable(uint32_t aTag) MOZ_OVERRIDE;
 
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
     nsresult ReadCMAP();
 
     bool RequiresAATLayout() const { return mRequiresAAT; }
 
     bool IsCFF();
 
 protected:
     virtual gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
 
     virtual bool HasFontTable(uint32_t aTableTag);
 
+    static void DestroyBlobFunc(void* aUserData);
+
     CGFontRef mFontRef; // owning reference to the CGFont, released on destruction
 
     bool mFontRefInitialized;
     bool mRequiresAAT;
     bool mIsCFF;
     bool mIsCFFInitialized;
 };
 
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -196,77 +196,58 @@ static const ScriptRange sComplexScripts
                         TRUETYPE_TAG('m','y','m','2'), 0 } },
     { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } },
     // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
     { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'),
                         TRUETYPE_TAG('m','y','m','2'), 0 } },
     // Thai seems to be "renderable" without AAT morphing tables
 };
 
-static void
-DestroyBlobFunc(void* aUserData)
-{
-    FallibleTArray<uint8_t>* data = static_cast<FallibleTArray<uint8_t>*>(aUserData);
-    delete data;
-}
-
-// This is only used via MacOSFontEntry::ReadCMAP when checking for layout
-// support; it does not respect the mIgnore* flags on font entries, as those
-// are not relevant here at present.
-static hb_blob_t *
-GetTableForHarfBuzz(hb_face_t *aFace, hb_tag_t aTag, void *aUserData)
-{
-    gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
-    FallibleTArray<uint8_t>* table = new FallibleTArray<uint8_t>;
-    nsresult rv = fe->GetFontTable(aTag, *table);
-    if (NS_SUCCEEDED(rv)) {
-        return hb_blob_create((const char*)table->Elements(), table->Length(),
-                              HB_MEMORY_MODE_READONLY, table, DestroyBlobFunc);
-    }
-    delete table;
-    return hb_blob_get_empty();
-}
-
 static bool
 SupportsScriptInGSUB(gfxFontEntry* aFontEntry, const hb_tag_t* aScriptTags)
 {
-    hb_face_t *face = hb_face_create_for_tables(GetTableForHarfBuzz,
-                                                aFontEntry, nullptr);
+    hb_face_t *face = aFontEntry->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
 MacOSFontEntry::ReadCMAP()
 {
     // attempt this once, if errors occur leave a blank cmap
     if (mCharacterMap) {
         return NS_OK;
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
     uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
-    nsresult rv;
 
-    AutoFallibleTArray<uint8_t,16384> cmap;
-    rv = GetFontTable(kCMAP, cmap);
+    AutoTable cmapTable(this, kCMAP);
+    if (!cmapTable) {
+        return NS_OK; // leave it empty
+    }
 
     bool unicodeFont = false, symbolFont = false; // currently ignored
 
-    if (NS_SUCCEEDED(rv)) {
-        rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
-                                    *charmap, mUVSOffset,
-                                    unicodeFont, symbolFont);
-    }
+    uint32_t cmapLen;
+    const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
+    nsresult rv = gfxFontUtils::ReadCMAP((const uint8_t*)cmapData, cmapLen,
+                                         *charmap, mUVSOffset,
+                                         unicodeFont, symbolFont);
   
     if (NS_SUCCEEDED(rv) && !HasGraphiteTables()) {
         // We assume a Graphite font knows what it's doing,
         // and provides whatever shaping is needed for the
         // characters it supports, so only check/clear the
         // complex-script ranges for non-Graphite fonts
 
         // for layout support, check for the presence of mort/morx and/or
@@ -390,43 +371,39 @@ MacOSFontEntry::GetFontRef()
     if (!mFontRefInitialized) {
         mFontRefInitialized = true;
         NSString *psname = GetNSStringForString(mName);
         mFontRef = ::CGFontCreateWithFontName(CFStringRef(psname));
     }
     return mFontRef;
 }
 
-nsresult
-MacOSFontEntry::GetFontTable(uint32_t aTableTag,
-                             FallibleTArray<uint8_t>& aBuffer)
+/*static*/ void
+MacOSFontEntry::DestroyBlobFunc(void* aUserData)
 {
-    nsAutoreleasePool localPool;
+    ::CFRelease((CFDataRef)aUserData);
+}
 
+hb_blob_t *
+MacOSFontEntry::GetFontTable(uint32_t aTag)
+{
     CGFontRef fontRef = GetFontRef();
     if (!fontRef) {
-        return NS_ERROR_FAILURE;
+        return nullptr;
     }
 
-    CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag);
-    if (!tableData) {
-        return NS_ERROR_FAILURE;
+    CFDataRef dataRef = ::CGFontCopyTableForTag(fontRef, aTag);
+    if (dataRef) {
+        return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
+                              ::CFDataGetLength(dataRef),
+                              HB_MEMORY_MODE_READONLY,
+                              (void*)dataRef, DestroyBlobFunc);
     }
 
-    nsresult rval = NS_OK;
-    CFIndex dataLength = ::CFDataGetLength(tableData);
-    if (aBuffer.AppendElements(dataLength)) {
-        ::CFDataGetBytes(tableData, ::CFRangeMake(0, dataLength),
-                         aBuffer.Elements());
-    } else {
-        rval = NS_ERROR_OUT_OF_MEMORY;
-    }
-    ::CFRelease(tableData);
-
-    return rval;
+    return nullptr;
 }
 
 bool
 MacOSFontEntry::HasFontTable(uint32_t aTableTag)
 {
     nsAutoreleasePool localPool;
 
     CGFontRef fontRef = GetFontRef();
@@ -635,32 +612,36 @@ gfxSingleFaceMacFontFamily::LocalizedNam
 
     // failed to get localized name, just use the canonical one
     aLocalizedName = mName;
 }
 
 void
 gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
 {
-    if (mOtherFamilyNamesInitialized)
+    if (mOtherFamilyNamesInitialized) {
         return;
+    }
 
     gfxFontEntry *fe = mAvailableFonts[0];
-    if (!fe)
+    if (!fe) {
         return;
+    }
 
     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
-    AutoFallibleTArray<uint8_t,8192> buffer;
 
-    if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+    gfxFontEntry::AutoTable nameTable(fe, kNAME);
+    if (!nameTable) {
         return;
+    }
 
     mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                       buffer,
+                                                       nameTable,
                                                        true);
+
     mOtherFamilyNamesInitialized = true;
 }
 
 
 /* gfxMacPlatformFontList */
 #pragma mark-
 
 gfxMacPlatformFontList::gfxMacPlatformFontList() :
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -310,17 +310,18 @@ gfxFcFontEntry::ShouldUseHarfBuzz(int32_
 
 class gfxSystemFcFontEntry : public gfxFcFontEntry {
 public:
     // For memory efficiency, aFontPattern should be a font pattern,
     // not a fully resolved pattern.
     gfxSystemFcFontEntry(cairo_font_face_t *aFontFace,
                          FcPattern *aFontPattern,
                          const nsAString& aName)
-        : gfxFcFontEntry(aName), mFontFace(aFontFace)
+        : gfxFcFontEntry(aName), mFontFace(aFontFace),
+          mFTFace(nullptr), mFTFaceInitialized(false)
     {
         cairo_font_face_reference(mFontFace);
         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, NULL);
         mPatterns.AppendElement();
         // mPatterns is an nsAutoTArray with 1 space always available, so the
         // AppendElement always succeeds.
         mPatterns[0] = aFontPattern;
 
@@ -331,20 +332,99 @@ public:
         }
     }
 
     ~gfxSystemFcFontEntry()
     {
         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, NULL, NULL);
         cairo_font_face_destroy(mFontFace);
     }
+
+    virtual void ForgetHBFace();
+    virtual void ReleaseGrFace(gr_face* aFace);
+
+protected:
+    virtual nsresult
+    CopyFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
+
+    void MaybeReleaseFTFace();
+
 private:
     cairo_font_face_t *mFontFace;
+    FT_Face            mFTFace;
+    bool               mFTFaceInitialized;
 };
 
+nsresult
+gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag,
+                                    FallibleTArray<uint8_t>& aBuffer)
+{
+    if (!mFTFaceInitialized) {
+        mFTFaceInitialized = true;
+        FcChar8 *filename;
+        if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) {
+            return NS_ERROR_FAILURE;
+        }
+        int index;
+        if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) {
+            index = 0; // default to 0 if not found in pattern
+        }
+        if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(),
+                        (const char*)filename, index, &mFTFace) != 0) {
+            return NS_ERROR_FAILURE;
+        }
+    }
+
+    if (!mFTFace) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    FT_ULong length = 0;
+    if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+    if (!aBuffer.SetLength(length)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+    if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
+        aBuffer.Clear();
+        return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+}
+
+void
+gfxSystemFcFontEntry::MaybeReleaseFTFace()
+{
+    // don't release if either HB or Gr face still exists
+    if (mHBFace || mGrFace) {
+        return;
+    }
+    if (mFTFace) {
+        FT_Done_Face(mFTFace);
+        mFTFace = nullptr;
+    }
+    mFTFaceInitialized = false;
+}
+
+void
+gfxSystemFcFontEntry::ForgetHBFace()
+{
+    gfxFontEntry::ForgetHBFace();
+    MaybeReleaseFTFace();        
+}
+
+void
+gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace)
+{
+    gfxFontEntry::ReleaseGrFace(aFace);
+    MaybeReleaseFTFace();        
+}
+
 // A namespace for @font-face family names in FcPatterns so that fontconfig
 // aliases do not pick up families from @font-face rules and so that
 // fontconfig rules can distinguish between web fonts and platform fonts.
 // http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
 #define FONT_FACE_FAMILY_PREFIX "@font-face:"
 
 /**
  * gfxUserFcFontEntry:
@@ -509,18 +589,17 @@ public:
     // Returns true on success
     bool SetCairoFace(cairo_font_face_t *aFace);
 
     // Returns a PangoCoverage owned by the FontEntry.  The caller must add a
     // reference if it wishes to keep the PangoCoverage longer than the
     // lifetime of the FontEntry.
     PangoCoverage *GetPangoCoverage();
 
-    virtual nsresult
-    GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
+    virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
 
 protected:
     void InitPattern();
 
     // mFontData holds the data used to instantiate the FT_Face;
     // this has to persist until we are finished with the face,
     // then be released with NS_Free().
     const uint8_t* mFontData;
@@ -727,37 +806,43 @@ gfxDownloadedFcFontEntry::GetPangoCovera
     NS_ASSERTION(mPatterns.Length() != 0,
                  "Can't get coverage without a pattern!");
     if (!mPangoCoverage) {
         mPangoCoverage.own(NewPangoCoverage(mPatterns[0]));
     }
     return mPangoCoverage;
 }
 
-nsresult
-gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag,
-                                       FallibleTArray<uint8_t>& aBuffer)
+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 *
+gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag)
 {
-    FT_ULong length = 0;
-    FT_Error error = FT_Load_Sfnt_Table(mFace, aTableTag, 0, nullptr, &length);
-    if (error) {
-        return NS_ERROR_NOT_AVAILABLE;
+    // The entry already owns the (sanitized) sfnt data in mFontData,
+    // so we can just return a blob that "wraps" the appropriate chunk of it.
+    // The blob should not attempt to free its data, as the entire sfnt data
+    // will be freed when the font entry is deleted.
+    const SFNTHeader* header = reinterpret_cast<const SFNTHeader*>(mFontData);
+    const TableDirEntry* dir = reinterpret_cast<const TableDirEntry*>(header + 1);
+    dir = static_cast<const TableDirEntry*>
+        (bsearch(&aTableTag, dir, header->numTables, sizeof(TableDirEntry),
+                 DirEntryCmp));
+    if (dir) {
+        return hb_blob_create(reinterpret_cast<const char*>(mFontData) +
+                                  dir->offset, dir->length,
+                              HB_MEMORY_MODE_READONLY, nullptr, nullptr);
+
     }
-
-    if (!aBuffer.SetLength(length)) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    error = FT_Load_Sfnt_Table(mFace, aTableTag, 0, aBuffer.Elements(), &length);
-    if (error) {
-        aBuffer.Clear();
-        return NS_ERROR_FAILURE;
-    }
-
-    return NS_OK;
+    return nullptr;
 }
 
 /*
  * gfxFcFont
  *
  * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
  * cairo_scaled_font created from an FcPattern.
  */
--- a/gfx/thebes/gfxPangoFonts.h
+++ b/gfx/thebes/gfxPangoFonts.h
@@ -90,12 +90,13 @@ private:
 
     gfxFloat GetSizeAdjustFactor()
     {
         if (mFontSets.Length() == 0)
             GetBaseFontSet();
         return mSizeAdjustFactor;
     }
 
+    friend class gfxSystemFcFontEntry;
     static FT_Library GetFTLibrary();
 };
 
 #endif /* GFX_PANGOFONTS_H */
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -55,54 +55,46 @@
 #include "nsXMLContentSink.h"
 #include "nsNetUtil.h"
 #include "nsIInputStream.h"
 #include "nsStringStream.h"
 #include "nsStreamUtils.h"
 #include "nsIPrincipal.h"
 #include "Element.h"
 #include "nsSVGUtils.h"
+#include "harfbuzz/hb.h"
 
 #define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml")
 #define UTF8_CHARSET NS_LITERAL_CSTRING("utf-8")
 
 typedef mozilla::dom::Element Element;
 
 mozilla::gfx::UserDataKey gfxTextObjectPaint::sUserDataKey;
 
 const float gfxSVGGlyphs::SVG_UNITS_PER_EM = 1000.0f;
 
 const gfxRGBA SimpleTextObjectPaint::sZero = gfxRGBA(0.0f, 0.0f, 0.0f, 0.0f);
 
-gfxSVGGlyphs::gfxSVGGlyphs(FallibleTArray<uint8_t>& aSVGTable,
-                           const FallibleTArray<uint8_t>& aCmapTable)
+gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable, hb_blob_t *aCmapTable)
 {
-    mSVGData.SwapElements(aSVGTable);
+    mSVGData = aSVGTable;
 
-    mHeader = reinterpret_cast<Header*>(mSVGData.Elements());
-    UnmangleHeaders();
+    const char* svgData = hb_blob_get_data(mSVGData, nullptr);
+    mHeader = reinterpret_cast<const Header*>(svgData);
+    mIndex = reinterpret_cast<const IndexEntry*>(svgData + sizeof(Header));
 
     mGlyphDocs.Init();
     mGlyphIdMap.Init();
     mCmapData = aCmapTable;
 }
 
-void
-gfxSVGGlyphs::UnmangleHeaders()
+gfxSVGGlyphs::~gfxSVGGlyphs()
 {
-    mHeader->mIndexLength = mozilla::NativeEndian::swapFromBigEndian(mHeader->mIndexLength);
-
-    mIndex = reinterpret_cast<IndexEntry*>(mSVGData.Elements() + sizeof(Header));
-
-    for (uint16_t i = 0; i < mHeader->mIndexLength; i++) {
-        mIndex[i].mStartGlyph = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mStartGlyph);
-        mIndex[i].mEndGlyph = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mEndGlyph);
-        mIndex[i].mDocOffset = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mDocOffset);
-        mIndex[i].mDocLength = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mDocLength);
-    }
+    hb_blob_destroy(mSVGData);
+    hb_blob_destroy(mCmapData);
 }
 
 /*
  * Comparison operator for finding a range containing a given glyph ID. Simply
  *   checks whether |key| is less (greater) than every element of |range|, in
  *   which case return |key| < |range| (|key| > |range|). Otherwise |key| is in
  *   |range|, in which case return equality.
  * The total ordering here is guaranteed by
@@ -112,36 +104,37 @@ gfxSVGGlyphs::UnmangleHeaders()
  *        sets intersecting of size > 1 -- so... don't do that)
  */
 /* static */ int
 gfxSVGGlyphs::CompareIndexEntries(const void *_key, const void *_entry)
 {
     const uint32_t key = *(uint32_t*)_key;
     const IndexEntry *entry = (const IndexEntry*)_entry;
 
-    if (key < entry->mStartGlyph) return -1;
-    if (key >= entry->mEndGlyph) return 1;
+    if (key < uint16_t(entry->mStartGlyph)) return -1;
+    if (key >= uint16_t(entry->mEndGlyph)) return 1;
     return 0;
 }
 
 gfxSVGGlyphsDocument *
 gfxSVGGlyphs::FindOrCreateGlyphsDocument(uint32_t aGlyphId)
 {
     IndexEntry *entry = (IndexEntry*)bsearch(&aGlyphId, mIndex,
-                                             mHeader->mIndexLength,
+                                             uint16_t(mHeader->mIndexLength),
                                              sizeof(IndexEntry),
                                              CompareIndexEntries);
     if (!entry) {
         return nullptr;
     }
 
     gfxSVGGlyphsDocument *result = mGlyphDocs.Get(entry->mDocOffset);
 
     if (!result) {
-        result = new gfxSVGGlyphsDocument(mSVGData.Elements() + entry->mDocOffset,
+        const uint8_t *data = (const uint8_t*)hb_blob_get_data(mSVGData, nullptr);
+        result = new gfxSVGGlyphsDocument(data + entry->mDocOffset,
                                           entry->mDocLength, mCmapData);
         mGlyphDocs.Put(entry->mDocOffset, result);
     }
 
     return result;
 }
 
 nsresult
@@ -188,18 +181,17 @@ gfxSVGGlyphsDocument::SetupPresentation(
 
 /**
  * Walk the DOM tree to find all glyph elements and insert them into the lookup
  * table
  * @param aElem The element to search from
  * @param aCmapTable Buffer containing the raw cmap table data
  */
 void
-gfxSVGGlyphsDocument::FindGlyphElements(Element *aElem,
-                                        const FallibleTArray<uint8_t> &aCmapTable)
+gfxSVGGlyphsDocument::FindGlyphElements(Element *aElem, hb_blob_t *aCmapTable)
 {
     for (nsIContent *child = aElem->GetLastChild(); child;
             child = child->GetPreviousSibling()) {
         if (!child->IsElement()) {
             continue;
         }
         FindGlyphElements(child->AsElement(), aCmapTable);
     }
@@ -265,18 +257,18 @@ gfxSVGGlyphs::HasSVGGlyph(uint32_t aGlyp
 }
 
 Element *
 gfxSVGGlyphsDocument::GetGlyphElement(uint32_t aGlyphId)
 {
     return mGlyphIdMap.Get(aGlyphId);
 }
 
-gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(uint8_t *aBuffer, uint32_t aBufLen,
-                                           const FallibleTArray<uint8_t>& aCmapTable)
+gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen,
+                                           hb_blob_t *aCmapTable)
 {
     mGlyphIdMap.Init();
     ParseDocument(aBuffer, aBufLen);
     if (!mDocument) {
         NS_WARNING("Could not parse SVG glyphs document");
         return;
     }
 
@@ -291,17 +283,17 @@ gfxSVGGlyphsDocument::gfxSVGGlyphsDocume
         NS_WARNING("Couldn't setup presentation for SVG glyphs document");
         return;
     }
 
     FindGlyphElements(root, aCmapTable);
 }
 
 static nsresult
-CreateBufferedStream(uint8_t *aBuffer, uint32_t aBufLen,
+CreateBufferedStream(const uint8_t *aBuffer, uint32_t aBufLen,
                      nsCOMPtr<nsIInputStream> &aResult)
 {
     nsCOMPtr<nsIInputStream> stream;
     nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
                                         reinterpret_cast<const char *>(aBuffer),
                                         aBufLen, NS_ASSIGNMENT_DEPEND);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -313,17 +305,17 @@ CreateBufferedStream(uint8_t *aBuffer, u
     }
 
     aResult = stream;
 
     return NS_OK;
 }
 
 nsresult
-gfxSVGGlyphsDocument::ParseDocument(uint8_t *aBuffer, uint32_t aBufLen)
+gfxSVGGlyphsDocument::ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen)
 {
     // Mostly pulled from nsDOMParser::ParseFromStream
 
     nsCOMPtr<nsIInputStream> stream;
     nsresult rv = CreateBufferedStream(aBuffer, aBufLen, stream);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIPrincipal> principal =
@@ -407,26 +399,27 @@ gfxSVGGlyphsDocument::InsertGlyphId(Elem
     if (NS_FAILED(rv)) {
         return;
     }
 
     mGlyphIdMap.Put(glyphId, aGlyphElement);
 }
 
 void
-gfxSVGGlyphsDocument::InsertGlyphChar(Element *aGlyphElement,
-                                      const FallibleTArray<uint8_t> &aCmapTable)
+gfxSVGGlyphsDocument::InsertGlyphChar(Element *aGlyphElement, hb_blob_t *aCmapTable)
 {
     nsAutoString glyphChar;
     if (!aGlyphElement->GetAttr(kNameSpaceID_None, nsGkAtoms::glyphchar, glyphChar)) {
         return;
     }
 
     uint32_t varSelector;
 
+    // XXX jfkthame
+    // This will not handle surrogate pairs properly!
     switch (glyphChar.Length()) {
         case 0:
             NS_WARNING("glyphchar is empty");
             return;
         case 1:
             varSelector = 0;
             break;
         case 2:
@@ -434,18 +427,19 @@ gfxSVGGlyphsDocument::InsertGlyphChar(El
                 varSelector = glyphChar.CharAt(1);
                 break;
             }
         default:
             NS_WARNING("glyphchar contains more than one character");
             return;
     }
 
-    uint32_t glyphId = gfxFontUtils::MapCharToGlyph(aCmapTable.Elements(),
-                                                    aCmapTable.Length(),
+    uint32_t len;
+    const uint8_t *data = (const uint8_t*)hb_blob_get_data(aCmapTable, &len);
+    uint32_t glyphId = gfxFontUtils::MapCharToGlyph(data, len,
                                                     glyphChar.CharAt(0),
                                                     varSelector);
 
     if (glyphId) {
         mGlyphIdMap.Put(glyphId, aGlyphElement);
     }
 }
 
--- a/gfx/thebes/gfxSVGGlyphs.h
+++ b/gfx/thebes/gfxSVGGlyphs.h
@@ -60,38 +60,36 @@
  *   mappings to be drawn by gfxSVGGlyphs
  */
 class gfxSVGGlyphsDocument
 {
     typedef mozilla::dom::Element Element;
     typedef gfxFont::DrawMode DrawMode;
 
 public:
-    gfxSVGGlyphsDocument(uint8_t *aBuffer, uint32_t aBufLen,
-                         const FallibleTArray<uint8_t>& aCmapTable);
+    gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen,
+                         hb_blob_t *aCmapTable);
 
     Element *GetGlyphElement(uint32_t aGlyphId);
 
     ~gfxSVGGlyphsDocument() {
         if (mViewer) {
             mViewer->Destroy();
         }
     }
 
 private:
-    nsresult ParseDocument(uint8_t *aBuffer, uint32_t aBufLen);
+    nsresult ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen);
 
     nsresult SetupPresentation();
 
-    void FindGlyphElements(Element *aElement,
-                           const FallibleTArray<uint8_t> &aCmapTable);
+    void FindGlyphElements(Element *aElement, hb_blob_t *aCmapTable);
 
     void InsertGlyphId(Element *aGlyphElement);
-    void InsertGlyphChar(Element *aGlyphElement,
-                         const FallibleTArray<uint8_t> &aCmapTable);
+    void InsertGlyphChar(Element *aGlyphElement, hb_blob_t *aCmapTable);
 
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsIContentViewer> mViewer;
     nsCOMPtr<nsIPresShell> mPresShell;
 
     nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
 };
 
@@ -108,24 +106,27 @@ private:
     typedef gfxFont::DrawMode DrawMode;
 
 public:
     static const float SVG_UNITS_PER_EM;
 
     /**
      * @param aSVGTable The SVG table from the OpenType font
      * @param aCmapTable The CMAP table from the OpenType font
+     *
+     * The gfxSVGGlyphs object takes over ownership of the blob references
+     * that are passed in, and will hb_blob_destroy() them when finished;
+     * the caller should -not- destroy these references.
      */
-    gfxSVGGlyphs(FallibleTArray<uint8_t>& aSVGTable,
-                 const FallibleTArray<uint8_t>& aCmapTable);
+    gfxSVGGlyphs(hb_blob_t *aSVGTable, hb_blob_t *aCmapTable);
 
     /**
-     * Big- to little-endian conversion for headers
+     * Releases our references to the SVG and cmap tables.
      */
-    void UnmangleHeaders();
+    ~gfxSVGGlyphs();
 
     /**
      * Find the |gfxSVGGlyphsDocument| containing an SVG glyph for |aGlyphId|.
      * If |aGlyphId| does not map to an SVG document, return null.
      * If a |gfxSVGGlyphsDocument| has not been created for the document, create one.
      */
     gfxSVGGlyphsDocument *FindOrCreateGlyphsDocument(uint32_t aGlyphId);
 
@@ -152,29 +153,29 @@ public:
                          gfxRect *aResult);
 
 private:
     Element *GetGlyphElement(uint32_t aGlyphId);
 
     nsClassHashtable<nsUint32HashKey, gfxSVGGlyphsDocument> mGlyphDocs;
     nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
 
-    FallibleTArray<uint8_t> mSVGData;
-    FallibleTArray<uint8_t> mCmapData;
+    hb_blob_t *mSVGData;
+    hb_blob_t *mCmapData;
 
-    struct Header {
-        uint16_t mVersion;
-        uint16_t mIndexLength;
+    const struct Header {
+        mozilla::AutoSwap_PRUint16 mVersion;
+        mozilla::AutoSwap_PRUint16 mIndexLength;
     } *mHeader;
 
-    struct IndexEntry {
-        uint16_t mStartGlyph;
-        uint16_t mEndGlyph;
-        uint32_t mDocOffset;
-        uint32_t mDocLength;
+    const struct IndexEntry {
+        mozilla::AutoSwap_PRUint16 mStartGlyph;
+        mozilla::AutoSwap_PRUint16 mEndGlyph;
+        mozilla::AutoSwap_PRUint32 mDocOffset;
+        mozilla::AutoSwap_PRUint32 mDocLength;
     } *mIndex;
 
     static int CompareIndexEntries(const void *_a, const void *_b);
 };
 
 /**
  * Used for trickling down paint information through to SVG glyphs.
  * Will be extended in later patch.
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -528,16 +528,17 @@ hb_buffer_get_glyph_infos
 hb_buffer_get_glyph_positions
 hb_buffer_reverse
 hb_buffer_set_direction
 hb_buffer_set_language
 hb_buffer_set_script
 hb_buffer_set_unicode_funcs
 hb_face_create_for_tables
 hb_face_destroy
+hb_face_reference
 hb_font_create
 hb_font_destroy
 hb_font_funcs_create
 hb_font_funcs_set_glyph_contour_point_func
 hb_font_funcs_set_glyph_func
 hb_font_funcs_set_glyph_h_advance_func
 hb_font_funcs_set_glyph_h_kerning_func
 hb_font_set_funcs