Bug 1305977 - Use HarfBuzz ot-math API to parse the OpenType MATH table. r=jfkthame
authorFrédéric Wang <fred.wang@free.fr>
Wed, 02 Nov 2016 11:47:18 -0700
changeset 347406 3898797a6267e6d0f84049258e261e207fafd4e5
parent 347405 773aed2f801b27cbad3c031fc7aa747ea9b2c1ed
child 347407 0cb96d5b5a57709e54e59887d57a36225b0b115e
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1305977
milestone52.0a1
Bug 1305977 - Use HarfBuzz ot-math API to parse the OpenType MATH table. r=jfkthame
gfx/thebes/MathTableStructures.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontEntry.cpp
gfx/thebes/gfxFontEntry.h
gfx/thebes/gfxMathTable.cpp
gfx/thebes/gfxMathTable.h
gfx/thebes/gfxTextRun.cpp
layout/mathml/nsMathMLChar.cpp
layout/mathml/nsMathMLFrame.cpp
layout/mathml/nsMathMLmfracFrame.cpp
layout/mathml/nsMathMLmmultiscriptsFrame.cpp
layout/mathml/nsMathMLmrootFrame.cpp
layout/mathml/nsMathMLmunderoverFrame.cpp
deleted file mode 100644
--- a/gfx/thebes/MathTableStructures.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This file contains the structures described in Microsoft's document
-// "The MATH table and OpenType Features for Math Processing" (not yet public).
-//
-// Arrays of varying size are indicated in comments. Typically, gfxMathTable
-// will read the header of the structure first, verify that there is enough
-// space for the specified arrays and then use a pointer to browse these arrays.
-
-#ifndef MATH_TABLE_STRUCTURE_H
-#define MATH_TABLE_STRUCTURE_H
-
-#include "gfxFontUtils.h"
-
-typedef mozilla::AutoSwap_PRUint16 Count16;
-typedef mozilla::AutoSwap_PRUint16 GlyphID;
-typedef mozilla::AutoSwap_PRUint16 Offset;
-
-struct MathValueRecord {
-  mozilla::AutoSwap_PRInt16  mValue;
-  Offset                     mDeviceTable;
-};
-
-struct RangeRecord {
-  GlyphID                    mStart;
-  GlyphID                    mEnd;
-  mozilla::AutoSwap_PRUint16 mStartCoverageIndex;
-};
-
-struct Coverage {
-  mozilla::AutoSwap_PRUint16 mFormat;
-};
-
-struct CoverageFormat1 {
-  mozilla::AutoSwap_PRUint16 mFormat;
-  Count16                    mGlyphCount;
-  // GlyphID                 mGlyphArray[mGlyphCount]
-};
-
-struct CoverageFormat2 {
-  mozilla::AutoSwap_PRUint16 mFormat;
-  Count16                    mRangeCount;
-  // RangeRecord             mRangeArray[mRangeCount];
-};
-
-struct MATHTableHeader {
-  mozilla::AutoSwap_PRUint32 mVersion;
-  Offset                     mMathConstants;
-  Offset                     mMathGlyphInfo;
-  Offset                     mMathVariants;
-};
-
-struct MathConstants {
-  mozilla::AutoSwap_PRInt16  mInt16[gfxFontEntry::ScriptScriptPercentScaleDown -
-                                    gfxFontEntry::ScriptPercentScaleDown + 1];
-  mozilla::AutoSwap_PRUint16 mUint16[gfxFontEntry::DisplayOperatorMinHeight -
-                                     gfxFontEntry::
-                                     DelimitedSubFormulaMinHeight + 1];
-  MathValueRecord            mMathValues[gfxFontEntry::RadicalKernAfterDegree -
-                                         gfxFontEntry::MathLeading + 1];
-  mozilla::AutoSwap_PRUint16 mRadicalDegreeBottomRaisePercent;
-};
-
-struct MathGlyphInfo {
-  Offset mMathItalicsCorrectionInfo;
-  Offset mMathTopAccentAttachment;
-  Offset mExtendedShapeCoverage;
-  Offset mMathKernInfo;
-};
-
-struct MathItalicsCorrectionInfo {
-  Offset  mCoverage;
-  Count16 mItalicsCorrectionCount;
-  // MathValueRecord mItalicsCorrection[mItalicsCorrectionCount]
-};
-
-struct MathVariants {
-  mozilla::AutoSwap_PRUint16 mMinConnectorOverlap;
-  Offset                     mVertGlyphCoverage;
-  Offset                     mHorizGlyphCoverage;
-  Count16                    mVertGlyphCount;
-  Count16                    mHorizGlyphCount;
-  // Offset                  mVertGlyphConstruction[mVertGlyphCount];
-  // Offset                  mHorizGlyphConstruction[mHorizGlyphCount];
-};
-
-struct MathGlyphVariantRecord {
-  GlyphID                    mVariantGlyph;
-  mozilla::AutoSwap_PRUint16 mAdvanceMeasurement;
-};
-
-struct MathGlyphConstruction {
-  Offset                    mGlyphAssembly;
-  Count16                   mVariantCount;
-  // MathGlyphVariantRecord mMathGlyphVariantRecord[mVariantCount]
-};
-
-struct GlyphPartRecord {
-  GlyphID                    mGlyph;
-  mozilla::AutoSwap_PRUint16 mStartConnectorLength;
-  mozilla::AutoSwap_PRUint16 mEndConnectorLength;
-  mozilla::AutoSwap_PRUint16 mFullAdvance;
-  mozilla::AutoSwap_PRUint16 mPartFlags;
-};
-
-// PartFlags enumeration currently uses only one bit:
-// 0x0001 If set, the part can be skipped or repeated.
-// 0xFFFE Reserved.
-enum {
-  PART_FLAG_EXTENDER = 0x01
-};
-
-struct GlyphAssembly {
-  MathValueRecord    mItalicsCorrection;
-  Count16            mPartCount;
-  // GlyphPartRecord mPartRecords[mPartCount]
-};
-
-#endif
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -32,16 +32,17 @@
 #include "nsUnicodeProperties.h"
 #include "nsStyleConsts.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
+#include "gfxMathTable.h"
 #include "gfxSVGGlyphs.h"
 #include "gfx2DGlue.h"
 
 #include "GreekCasing.h"
 
 #include "cairo.h"
 
 #include "harfbuzz/hb.h"
@@ -836,16 +837,17 @@ gfxFont::RunMetrics::CombineWith(const R
     mAdvanceWidth += aOther.mAdvanceWidth;
 }
 
 gfxFont::gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                  AntialiasOption anAAOption, cairo_scaled_font_t *aScaledFont) :
     mScaledFont(aScaledFont),
     mFontEntry(aFontEntry), mIsValid(true),
     mApplySyntheticBold(false),
+    mMathInitialized(false),
     mStyle(*aFontStyle),
     mAdjustedSize(0.0),
     mFUnitsConvFactor(-1.0f), // negative to indicate "not yet initialized"
     mAntialiasOption(anAAOption)
 {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
     ++gFontCount;
 #endif
@@ -4001,8 +4003,26 @@ gfxFontStyle::AdjustForSubSuperscript(in
                           NS_FONT_SUB_SUPER_SMALL_SIZE);
         size *= (1.0 - t) * NS_FONT_SUB_SUPER_SIZE_RATIO_SMALL +
                     t * NS_FONT_SUB_SUPER_SIZE_RATIO_LARGE;
     }
 
     // clear the variant field
     variantSubSuper = NS_FONT_VARIANT_POSITION_NORMAL;
 }
+
+bool
+gfxFont::TryGetMathTable()
+{
+    if (!mMathInitialized) {
+        mMathInitialized = true;
+
+        hb_face_t *face = GetFontEntry()->GetHBFace();
+        if (face) {
+            if (hb_ot_math_has_data(face)) {
+                mMathTable = MakeUnique<gfxMathTable>(face, GetAdjustedSize());
+            }
+            hb_face_destroy(face);
+        }
+    }
+
+    return !!mMathTable;
+}
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -41,16 +41,17 @@ typedef struct _cairo_scaled_font cairo_
 
 class gfxContext;
 class gfxTextRun;
 class gfxFont;
 class gfxGlyphExtents;
 class gfxShapedText;
 class gfxShapedWord;
 class gfxSkipChars;
+class gfxMathTable;
 
 #define FONT_MAX_SIZE                  2000.0
 
 #define NO_FONT_LANGUAGE_OVERRIDE      0
 
 #define SMALL_CAPS_SCALE_FACTOR        0.8
 
 // The skew factor used for synthetic-italic [oblique] fonts;
@@ -1839,32 +1840,23 @@ public:
         return mFontEntry->TryGetSVGData(this);
     }
 
     static void DestroySingletons() {
         delete sScriptTagToCode;
         delete sDefaultFeatures;
     }
 
-    // Get a font dimension from the MATH table, scaled to appUnits;
-    // may only be called if mFontEntry->TryGetMathTable has succeeded
-    // (i.e. the font is known to be a valid OpenType math font).
-    nscoord GetMathConstant(gfxFontEntry::MathConstant aConstant,
-                            uint32_t aAppUnitsPerDevPixel)
-    {
-        return NSToCoordRound(mFontEntry->GetMathConstant(aConstant) *
-                              GetAdjustedSize() * aAppUnitsPerDevPixel);
-    }
-
-    // Get a dimensionless math constant (e.g. a percentage);
-    // may only be called if mFontEntry->TryGetMathTable has succeeded
-    // (i.e. the font is known to be a valid OpenType math font).
-    float GetMathConstant(gfxFontEntry::MathConstant aConstant)
-    {
-        return mFontEntry->GetMathConstant(aConstant);
+    // Call TryGetMathTable() to try and load the Open Type MATH table.
+    // If (and ONLY if) TryGetMathTable() has returned true, the MathTable()
+    // method may be called to access the gfxMathTable data.
+    bool          TryGetMathTable();
+    gfxMathTable* MathTable() {
+        MOZ_RELEASE_ASSERT(mMathTable, "A successful call to TryGetMathTable() must be performed before calling this function");
+        return mMathTable.get();
     }
 
     // return a cloned font resized and offset to simulate sub/superscript glyphs
     virtual already_AddRefed<gfxFont>
     GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel);
 
     /**
      * Return the reference cairo_t object from aDT.
@@ -2091,16 +2083,18 @@ protected:
 
     // use synthetic bolding for environments where this is not supported
     // by the platform
     bool                       mApplySyntheticBold;
 
     bool                       mKerningSet;     // kerning explicitly set?
     bool                       mKerningEnabled; // if set, on or off?
 
+    bool                       mMathInitialized; // TryGetMathTable() called?
+
     nsExpirationState          mExpirationState;
     gfxFontStyle               mStyle;
     nsTArray<mozilla::UniquePtr<gfxGlyphExtents>> mGlyphExtentsArray;
     mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<GlyphChangeObserver>>>
                                mGlyphChangeObservers;
 
     gfxFloat                   mAdjustedSize;
 
@@ -2126,16 +2120,19 @@ protected:
     // ranges supported by font
     RefPtr<gfxCharacterMap> mUnicodeRangeMap;
 
     RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont;
 
     // For vertical metrics, created on demand.
     mozilla::UniquePtr<const Metrics> mVerticalMetrics;
 
+    // Table used for MathML layout.
+    mozilla::UniquePtr<gfxMathTable> mMathTable;
+
     // Helper for subclasses that want to initialize standard metrics from the
     // tables of sfnt (TrueType/OpenType) fonts.
     // This will use mFUnitsConvFactor if it is already set, else compute it
     // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
     // Returns TRUE and sets mIsValid=TRUE if successful;
     // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
     // Returns FALSE if the font does not appear to be an sfnt at all,
     // and should be handled (if possible) using other APIs.
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -30,17 +30,16 @@
 #include "mozilla/AppUnits.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "gfxSVGGlyphs.h"
-#include "gfxMathTable.h"
 #include "gfx2DGlue.h"
 
 #include "cairo.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "graphite2/Font.h"
 
@@ -68,17 +67,16 @@ gfxFontEntry::gfxFontEntry() :
     mIsUserFontContainer(false),
     mIsDataUserFont(false),
     mIsLocalUserFont(false),
     mStandardFace(false),
     mSymbolFont(false),
     mIgnoreGDEF(false),
     mIgnoreGSUB(false),
     mSVGInitialized(false),
-    mMathInitialized(false),
     mHasSpaceFeaturesInitialized(false),
     mHasSpaceFeatures(false),
     mHasSpaceFeaturesKerning(false),
     mHasSpaceFeaturesNonKerning(false),
     mSkipDefaultFeatureSpaceCheck(false),
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
@@ -108,17 +106,16 @@ gfxFontEntry::gfxFontEntry(const nsAStri
     mIsBadUnderlineFont(false),
     mIsUserFontContainer(false),
     mIsDataUserFont(false),
     mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
     mSymbolFont(false),
     mIgnoreGDEF(false),
     mIgnoreGSUB(false),
     mSVGInitialized(false),
-    mMathInitialized(false),
     mHasSpaceFeaturesInitialized(false),
     mHasSpaceFeatures(false),
     mHasSpaceFeaturesKerning(false),
     mHasSpaceFeaturesNonKerning(false),
     mSkipDefaultFeatureSpaceCheck(false),
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
@@ -402,88 +399,16 @@ gfxFontEntry::NotifyGlyphsChanged()
 {
     for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
         gfxFont* font = mFontsUsingSVGGlyphs[i];
         font->NotifyGlyphsChanged();
     }
 }
 
 bool
-gfxFontEntry::TryGetMathTable()
-{
-    if (!mMathInitialized) {
-        mMathInitialized = true;
-
-        // If UnitsPerEm is not known/valid, we can't use MATH table
-        if (UnitsPerEm() == kInvalidUPEM) {
-            return false;
-        }
-
-        // We don't use AutoTable here because we'll pass ownership of this
-        // blob to the gfxMathTable, once we've confirmed the table exists
-        hb_blob_t *mathTable = GetFontTable(TRUETYPE_TAG('M','A','T','H'));
-        if (!mathTable) {
-            return false;
-        }
-
-        // gfxMathTable will hb_blob_destroy() the table when it is finished
-        // with it.
-        mMathTable = MakeUnique<gfxMathTable>(mathTable);
-        if (!mMathTable->HasValidHeaders()) {
-            mMathTable.reset(nullptr);
-            return false;
-        }
-    }
-
-    return !!mMathTable;
-}
-
-gfxFloat
-gfxFontEntry::GetMathConstant(gfxFontEntry::MathConstant aConstant)
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    gfxFloat value = mMathTable->GetMathConstant(aConstant);
-    if (aConstant == gfxFontEntry::ScriptPercentScaleDown ||
-        aConstant == gfxFontEntry::ScriptScriptPercentScaleDown ||
-        aConstant == gfxFontEntry::RadicalDegreeBottomRaisePercent) {
-        return value / 100.0;
-    }
-    return value / mUnitsPerEm;
-}
-
-bool
-gfxFontEntry::GetMathItalicsCorrection(uint32_t aGlyphID,
-                                       gfxFloat* aItalicCorrection)
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    int16_t italicCorrection;
-    if (!mMathTable->GetMathItalicsCorrection(aGlyphID, &italicCorrection)) {
-        return false;
-    }
-    *aItalicCorrection = gfxFloat(italicCorrection) / mUnitsPerEm;
-    return true;
-}
-
-uint32_t
-gfxFontEntry::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
-                                  uint16_t aSize)
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    return mMathTable->GetMathVariantsSize(aGlyphID, aVertical, aSize);
-}
-
-bool
-gfxFontEntry::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
-                                   uint32_t aGlyphs[4])
-{
-    NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first.");
-    return mMathTable->GetMathVariantsParts(aGlyphID, aVertical, aGlyphs);
-}
-
-bool
 gfxFontEntry::TryGetColorGlyphs()
 {
     if (mCheckedForColorGlyph) {
         return (mCOLR && mCPAL);
     }
 
     mCheckedForColorGlyph = true;
 
@@ -1082,20 +1007,16 @@ gfxFontEntry::AddSizeOfExcludingThis(Mal
     if (mUserFontData) {
         aSizes->mFontTableCacheSize +=
             mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
     }
     if (mSVGGlyphs) {
         aSizes->mFontTableCacheSize +=
             mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
     }
-    if (mMathTable) {
-        aSizes->mFontTableCacheSize +=
-            mMathTable->SizeOfIncludingThis(aMallocSizeOf);
-    }
     if (mSupportedFeatures) {
         aSizes->mFontTableCacheSize +=
             mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
     }
     if (mFeatureInputs) {
         aSizes->mFontTableCacheSize +=
             mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
         for (auto iter = mFeatureInputs->ConstIter(); !iter.Done();
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -28,17 +28,16 @@ typedef struct gr_face gr_face;
 #endif
 
 struct gfxFontStyle;
 class gfxContext;
 class gfxFont;
 class gfxFontFamily;
 class gfxUserFontData;
 class gfxSVGGlyphs;
-class gfxMathTable;
 class FontInfoData;
 struct FontListSizes;
 class nsIAtom;
 
 namespace mozilla {
 class SVGContextPaint;
 };
 
@@ -188,89 +187,16 @@ public:
     bool GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
                             gfxRect *aResult);
     bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
                         mozilla::SVGContextPaint* aContextPaint);
     // Call this when glyph geometry or rendering has changed
     // (e.g. animated SVG glyphs)
     void NotifyGlyphsChanged();
 
-    enum MathConstant {
-        // The order of the constants must match the order of the fields
-        // defined in the MATH table.
-        ScriptPercentScaleDown,
-        ScriptScriptPercentScaleDown,
-        DelimitedSubFormulaMinHeight,
-        DisplayOperatorMinHeight,
-        MathLeading,
-        AxisHeight,
-        AccentBaseHeight,
-        FlattenedAccentBaseHeight,
-        SubscriptShiftDown,
-        SubscriptTopMax,
-        SubscriptBaselineDropMin,
-        SuperscriptShiftUp,
-        SuperscriptShiftUpCramped,
-        SuperscriptBottomMin,
-        SuperscriptBaselineDropMax,
-        SubSuperscriptGapMin,
-        SuperscriptBottomMaxWithSubscript,
-        SpaceAfterScript,
-        UpperLimitGapMin,
-        UpperLimitBaselineRiseMin,
-        LowerLimitGapMin,
-        LowerLimitBaselineDropMin,
-        StackTopShiftUp,
-        StackTopDisplayStyleShiftUp,
-        StackBottomShiftDown,
-        StackBottomDisplayStyleShiftDown,
-        StackGapMin,
-        StackDisplayStyleGapMin,
-        StretchStackTopShiftUp,
-        StretchStackBottomShiftDown,
-        StretchStackGapAboveMin,
-        StretchStackGapBelowMin,
-        FractionNumeratorShiftUp,
-        FractionNumeratorDisplayStyleShiftUp,
-        FractionDenominatorShiftDown,
-        FractionDenominatorDisplayStyleShiftDown,
-        FractionNumeratorGapMin,
-        FractionNumDisplayStyleGapMin,
-        FractionRuleThickness,
-        FractionDenominatorGapMin,
-        FractionDenomDisplayStyleGapMin,
-        SkewedFractionHorizontalGap,
-        SkewedFractionVerticalGap,
-        OverbarVerticalGap,
-        OverbarRuleThickness,
-        OverbarExtraAscender,
-        UnderbarVerticalGap,
-        UnderbarRuleThickness,
-        UnderbarExtraDescender,
-        RadicalVerticalGap,
-        RadicalDisplayStyleVerticalGap,
-        RadicalRuleThickness,
-        RadicalExtraAscender,
-        RadicalKernBeforeDegree,
-        RadicalKernAfterDegree,
-        RadicalDegreeBottomRaisePercent
-    };
-
-    // Call TryGetMathTable to try to load the Open Type MATH table. The other
-    // functions forward the call to the gfxMathTable class. The GetMath...()
-    // functions MUST NOT be called unless TryGetMathTable() has returned true.
-    bool     TryGetMathTable();
-    gfxFloat GetMathConstant(MathConstant aConstant);
-    bool     GetMathItalicsCorrection(uint32_t aGlyphID,
-                                      gfxFloat* aItalicCorrection);
-    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
-                                 uint16_t aSize);
-    bool     GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
-                                  uint32_t aGlyphs[4]);
-
     bool     TryGetColorGlyphs();
     bool     GetColorLayersInfo(uint32_t aGlyphId,
                                 const mozilla::gfx::Color& aDefaultColor,
                                 nsTArray<uint16_t>& layerGlyphs,
                                 nsTArray<mozilla::gfx::Color>& layerColors);
 
     virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
         return true;
@@ -410,17 +336,16 @@ public:
     bool             mIsUserFontContainer : 1; // userfont entry
     bool             mIsDataUserFont : 1;      // platform font entry (data)
     bool             mIsLocalUserFont : 1;     // platform font entry (local)
     bool             mStandardFace : 1;
     bool             mSymbolFont  : 1;
     bool             mIgnoreGDEF  : 1;
     bool             mIgnoreGSUB  : 1;
     bool             mSVGInitialized : 1;
-    bool             mMathInitialized : 1;
     bool             mHasSpaceFeaturesInitialized : 1;
     bool             mHasSpaceFeatures : 1;
     bool             mHasSpaceFeaturesKerning : 1;
     bool             mHasSpaceFeaturesNonKerning : 1;
     bool             mSkipDefaultFeatureSpaceCheck : 1;
     bool             mGraphiteSpaceContextualsInitialized : 1;
     bool             mHasGraphiteSpaceContextuals : 1;
     bool             mSpaceGlyphIsInvisible : 1;
@@ -441,17 +366,16 @@ public:
 
     RefPtr<gfxCharacterMap> mCharacterMap;
     uint32_t         mUVSOffset;
     mozilla::UniquePtr<uint8_t[]> mUVSData;
     mozilla::UniquePtr<gfxUserFontData> mUserFontData;
     mozilla::UniquePtr<gfxSVGGlyphs> mSVGGlyphs;
     // list of gfxFonts that are using SVG glyphs
     nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
-    mozilla::UniquePtr<gfxMathTable> mMathTable;
     nsTArray<gfxFontFeature> mFeatureSettings;
     mozilla::UniquePtr<nsDataHashtable<nsUint32HashKey,bool>> mSupportedFeatures;
     mozilla::UniquePtr<nsDataHashtable<nsUint32HashKey,hb_set_t*>> mFeatureInputs;
     uint32_t         mLanguageOverride;
 
     // Color Layer font support
     hb_blob_t*       mCOLR;
     hb_blob_t*       mCPAL;
--- a/gfx/thebes/gfxMathTable.cpp
+++ b/gfx/thebes/gfxMathTable.cpp
@@ -1,486 +1,210 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxMathTable.h"
 
-#include "MathTableStructures.h"
 #include "harfbuzz/hb.h"
-#include "mozilla/BinarySearch.h"
-#include <algorithm>
+#include "harfbuzz/hb-ot.h"
+
+#define FixedToFloat(f) ((f) * (1.0 / 65536.0))
 
 using namespace mozilla;
 
-gfxMathTable::gfxMathTable(hb_blob_t* aMathTable)
-  : mMathTable(aMathTable)
-  , mGlyphConstruction(nullptr)
-  , mGlyphID(-1)
-  , mVertical(false)
+gfxMathTable::gfxMathTable(hb_face_t *aFace, gfxFloat aSize)
 {
+  mHBFont = hb_font_create(aFace);
+  if (mHBFont) {
+    hb_font_set_ppem(mHBFont, aSize, aSize);
+    uint32_t scale = FloatToFixed(aSize);
+    hb_font_set_scale(mHBFont, scale, scale);
+  }
+
+  mMathVariantCache.glyphID = 0;
+  ClearCache();
 }
 
 gfxMathTable::~gfxMathTable()
 {
-  hb_blob_destroy(mMathTable);
+  if (mHBFont) {
+      hb_font_destroy(mHBFont);
+  }
 }
 
-bool
-gfxMathTable::HasValidHeaders()
+gfxFloat
+gfxMathTable::Constant(MathConstant aConstant) const
 {
-  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
-  // Verify the MATH table header.
-  if (!ValidStructure(mathData, sizeof(MATHTableHeader))) {
-    return false;
+  int32_t value = hb_ot_math_get_constant(mHBFont, static_cast<hb_ot_math_constant_t>(aConstant));
+  if (aConstant == ScriptPercentScaleDown ||
+      aConstant == ScriptScriptPercentScaleDown ||
+      aConstant == RadicalDegreeBottomRaisePercent) {
+    return value / 100.0;
   }
-  const MATHTableHeader* header = GetMATHTableHeader();
-  if (uint32_t(header->mVersion) != 0x00010000 ||
-      !ValidOffset(mathData, uint16_t(header->mMathConstants)) ||
-      !ValidOffset(mathData, uint16_t(header->mMathGlyphInfo)) ||
-      !ValidOffset(mathData, uint16_t(header->mMathVariants))) {
-    return false;
-  }
+  return FixedToFloat(value);
+}
 
-  // Verify the MathConstants header.
-  const MathConstants* mathconstants = GetMathConstants();
-  const char* start = reinterpret_cast<const char*>(mathconstants);
-  if (!ValidStructure(start, sizeof(MathConstants))) {
-    return false;
-  }
+gfxFloat
+gfxMathTable::ItalicsCorrection(uint32_t aGlyphID) const
+{
+  return FixedToFloat(hb_ot_math_get_glyph_italics_correction(mHBFont, aGlyphID));
+}
 
-  // Verify the MathGlyphInfo header.
-  const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo();
-  start = reinterpret_cast<const char*>(mathglyphinfo);
-  if (!ValidStructure(start, sizeof(MathGlyphInfo))) {
-    return false;
+uint32_t
+gfxMathTable::VariantsSize(uint32_t aGlyphID, bool aVertical,
+                           uint16_t aSize) const
+{
+  UpdateMathVariantCache(aGlyphID, aVertical);
+  if (aSize < kMaxCachedSizeCount) {
+    return mMathVariantCache.sizes[aSize];
   }
 
-  // Verify the MathVariants header.
-  const MathVariants* mathvariants = GetMathVariants();
-  start = reinterpret_cast<const char*>(mathvariants);
-  if (!ValidStructure(start, sizeof(MathVariants)) ||
-      !ValidStructure(start,
-                      sizeof(MathVariants) + sizeof(Offset) *
-                      (uint16_t(mathvariants->mVertGlyphCount) +
-                       uint16_t(mathvariants->mHorizGlyphCount))) ||
-      !ValidOffset(start, uint16_t(mathvariants->mVertGlyphCoverage)) ||
-      !ValidOffset(start, uint16_t(mathvariants->mHorizGlyphCoverage))) {
-    return false;
-  }
-
-  return true;
-}
-
-int32_t
-gfxMathTable::GetMathConstant(gfxFontEntry::MathConstant aConstant)
-{
-  const MathConstants* mathconstants = GetMathConstants();
-
-  if (aConstant <= gfxFontEntry::ScriptScriptPercentScaleDown) {
-    return int16_t(mathconstants->mInt16[aConstant]);
-  }
-
-  if (aConstant <= gfxFontEntry::DisplayOperatorMinHeight) {
-    return
-      uint16_t(mathconstants->
-               mUint16[aConstant - gfxFontEntry::DelimitedSubFormulaMinHeight]);
-  }
-
-  if (aConstant <= gfxFontEntry::RadicalKernAfterDegree) {
-    return int16_t(mathconstants->
-                   mMathValues[aConstant - gfxFontEntry::MathLeading].mValue);
-  }
-
-  return uint16_t(mathconstants->mRadicalDegreeBottomRaisePercent);
+  // If the size index exceeds the cache size, we just read the value with
+  // hb_ot_math_get_glyph_variants.
+  hb_direction_t direction = aVertical ? HB_DIRECTION_BTT : HB_DIRECTION_LTR;
+  hb_ot_math_glyph_variant_t variant;
+  unsigned int count = 1;
+  hb_ot_math_get_glyph_variants(mHBFont, aGlyphID, direction, aSize, &count,
+                                &variant);
+  return count > 0 ? variant.glyph : 0;
 }
 
 bool
-gfxMathTable::GetMathItalicsCorrection(uint32_t aGlyphID,
-                                       int16_t* aItalicCorrection)
+gfxMathTable::VariantsParts(uint32_t aGlyphID, bool aVertical,
+                            uint32_t aGlyphs[4]) const
 {
-  const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo();
-
-  // Get the offset of the italic correction and verify whether it is valid.
-  const char* start = reinterpret_cast<const char*>(mathglyphinfo);
-  uint16_t offset = mathglyphinfo->mMathItalicsCorrectionInfo;
-  if (offset == 0 || !ValidOffset(start, offset)) {
-    return false;
-  }
-  start += offset;
-
-  // Verify the validity of the MathItalicsCorrectionInfo and retrieve it.
-  if (!ValidStructure(start, sizeof(MathItalicsCorrectionInfo))) {
-    return false;
-  }
-  const MathItalicsCorrectionInfo* italicsCorrectionInfo =
-    reinterpret_cast<const MathItalicsCorrectionInfo*>(start);
+  UpdateMathVariantCache(aGlyphID, aVertical);
+  memcpy(aGlyphs, mMathVariantCache.parts, sizeof(mMathVariantCache.parts));
+  return mMathVariantCache.arePartsValid;
+}
 
-  // Get the coverage index for the glyph.
-  offset = italicsCorrectionInfo->mCoverage;
-  const Coverage* coverage =
-    reinterpret_cast<const Coverage*>(start + offset);
-  int32_t i = GetCoverageIndex(coverage, aGlyphID);
-
-  // Get the ItalicsCorrection.
-  uint16_t count = italicsCorrectionInfo->mItalicsCorrectionCount;
-  if (i < 0 || i >= count) {
-    return false;
-  }
-  start = reinterpret_cast<const char*>(italicsCorrectionInfo + 1);
-  if (!ValidStructure(start, count * sizeof(MathValueRecord))) {
-    return false;
-  }
-  const MathValueRecord* mathValueRecordArray =
-    reinterpret_cast<const MathValueRecord*>(start);
-
-  *aItalicCorrection = int16_t(mathValueRecordArray[i].mValue);
-  return true;
+void
+gfxMathTable::ClearCache() const
+{
+  memset(mMathVariantCache.sizes, 0, sizeof(mMathVariantCache.sizes));
+  memset(mMathVariantCache.parts, 0, sizeof(mMathVariantCache.parts));
+  mMathVariantCache.arePartsValid = false;
 }
 
-uint32_t
-gfxMathTable::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
-                                  uint16_t aSize)
+void
+gfxMathTable::UpdateMathVariantCache(uint32_t aGlyphID, bool aVertical) const
 {
-  // Select the glyph construction.
-  SelectGlyphConstruction(aGlyphID, aVertical);
-  if (!mGlyphConstruction) {
-    return 0;
-  }
+  if (aGlyphID == mMathVariantCache.glyphID &&
+      aVertical == mMathVariantCache.vertical)
+    return;
+
+  mMathVariantCache.glyphID = aGlyphID;
+  mMathVariantCache.vertical = aVertical;
+  ClearCache();
 
-  // Verify the validity of the array of the MathGlyphVariantRecord's and
-  // whether there is a variant of the requested size.
-  uint16_t count = mGlyphConstruction->mVariantCount;
-  const char* start = reinterpret_cast<const char*>(mGlyphConstruction + 1);
-  if (aSize >= count ||
-      !ValidStructure(start, count * sizeof(MathGlyphVariantRecord))) {
-    return 0;
+  // Cache the first size variants.
+  hb_direction_t direction = aVertical ? HB_DIRECTION_BTT : HB_DIRECTION_LTR;
+  hb_ot_math_glyph_variant_t variant[kMaxCachedSizeCount];
+  unsigned int count = kMaxCachedSizeCount;
+  hb_ot_math_get_glyph_variants(mHBFont, aGlyphID, direction, 0, &count,
+                                variant);
+  for (unsigned int i = 0; i < count; i++) {
+    mMathVariantCache.sizes[i] = variant[i].glyph;
   }
 
-  // Return the glyph index of the requested size variant.
-  const MathGlyphVariantRecord* recordArray =
-    reinterpret_cast<const MathGlyphVariantRecord*>(start);
-  return uint32_t(recordArray[aSize].mVariantGlyph);
-}
-
-bool
-gfxMathTable::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
-                                   uint32_t aGlyphs[4])
-{
-  // Get the glyph assembly corresponding to that (aGlyphID, aVertical) pair.
-  const GlyphAssembly* glyphAssembly = GetGlyphAssembly(aGlyphID, aVertical);
-  if (!glyphAssembly) {
-    return false;
-  }
-
-  // Verify the validity of the array of GlyphPartRecord's and retrieve it.
-  uint16_t count = glyphAssembly->mPartCount;
-  const char* start = reinterpret_cast<const char*>(glyphAssembly + 1);
-  if (!ValidStructure(start, count * sizeof(GlyphPartRecord))) {
-    return false;
-  }
-  const GlyphPartRecord* recordArray =
-    reinterpret_cast<const GlyphPartRecord*>(start);
-
+  // Try and cache the parts of the glyph assembly.
   // XXXfredw The structure of the Open Type Math table is a bit more general
   // than the one currently used by the nsMathMLChar code, so we try to fallback
   // in reasonable way. We use the approach of the copyComponents function in
   // github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py
   //
   // The nsMathMLChar code can use at most 3 non extender pieces (aGlyphs[0],
   // aGlyphs[1] and aGlyphs[2]) and the extenders between these pieces should
   // all be the same (aGlyphs[4]). Also, the parts of vertical assembly are
   // stored from bottom to top in the Open Type MATH table while they are
   // stored from top to bottom in nsMathMLChar.
 
+  hb_ot_math_glyph_part_t parts[5];
+  count = MOZ_ARRAY_LENGTH(parts);
+  unsigned int offset = 0;
+  if (hb_ot_math_get_glyph_assembly(mHBFont, aGlyphID, direction, offset, &count, parts, NULL) > MOZ_ARRAY_LENGTH(parts))
+    return; // Not supported: Too many pieces.
+  if (count <= 0)
+    return; // Not supported: No pieces.
+
   // Count the number of non extender pieces
   uint16_t nonExtenderCount = 0;
   for (uint16_t i = 0; i < count; i++) {
-    if (!(uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER)) {
+    if (!(parts[i].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER)) {
       nonExtenderCount++;
     }
   }
   if (nonExtenderCount > 3) {
     // Not supported: too many pieces
-    return false;
+    return;
   }
 
   // Now browse the list of pieces
 
   // 0 = look for a left/bottom glyph
   // 1 = look for an extender between left/bottom and mid
   // 2 = look for a middle glyph
   // 3 = look for an extender between middle and right/top
   // 4 = look for a right/top glyph
   // 5 = no more piece expected
   uint8_t state = 0;
 
   // First extender char found.
   uint32_t extenderChar = 0;
 
-  // Clear the aGlyphs table.
-  memset(aGlyphs, 0, sizeof(uint32_t) * 4);
-
   for (uint16_t i = 0; i < count; i++) {
 
-    bool isExtender = uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER;
-    uint32_t glyph = recordArray[i].mGlyph;
+    bool isExtender = parts[i].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER;
+    uint32_t glyph = parts[i].glyph;
 
     if ((state == 1 || state == 2) && nonExtenderCount < 3) {
       // do not try to find a middle glyph
       state += 2;
     }
 
     if (isExtender) {
       if (!extenderChar) {
         extenderChar = glyph;
-        aGlyphs[3] = extenderChar;
+        mMathVariantCache.parts[3] = extenderChar;
       } else if (extenderChar != glyph)  {
         // Not supported: different extenders
-        return false;
+        return;
       }
 
       if (state == 0) { // or state == 1
         // ignore left/bottom piece and multiple successive extenders
         state = 1;
       } else if (state == 2) { // or state == 3
         // ignore middle piece and multiple successive extenders
         state = 3;
       } else if (state >= 4) {
         // Not supported: unexpected extender
-        return false;
+        return;
       }
 
       continue;
     }
 
     if (state == 0) {
       // copy left/bottom part
-      aGlyphs[mVertical ? 2 : 0] = glyph;
+      mMathVariantCache.parts[aVertical ? 2 : 0] = glyph;
       state = 1;
       continue;
     }
 
     if (state == 1 || state == 2) {
       // copy middle part
-      aGlyphs[1] = glyph;
+      mMathVariantCache.parts[1] = glyph;
       state = 3;
       continue;
     }
 
     if (state == 3 || state == 4) {
       // copy right/top part
-      aGlyphs[mVertical ? 0 : 2] = glyph;
+      mMathVariantCache.parts[aVertical ? 0 : 2] = glyph;
       state = 5;
     }
 
   }
 
-  return true;
-}
-
-bool
-gfxMathTable::ValidStructure(const char* aStart, uint16_t aSize)
-{
-  unsigned int mathDataLength;
-  const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
-  return (mathData <= aStart &&
-          aStart + aSize <= mathData + mathDataLength);
-}
-
-bool
-gfxMathTable::ValidOffset(const char* aStart, uint16_t aOffset)
-{
-  unsigned int mathDataLength;
-  const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength);
-  return (mathData <= aStart + aOffset &&
-          aStart + aOffset < mathData + mathDataLength);
-}
-
-const MATHTableHeader*
-gfxMathTable::GetMATHTableHeader()
-{
-  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
-  return reinterpret_cast<const MATHTableHeader*>(mathData);
-}
-
-const MathConstants*
-gfxMathTable::GetMathConstants()
-{
-  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
-  return
-    reinterpret_cast<const MathConstants*>(mathData +
-                                           uint16_t(GetMATHTableHeader()->
-                                                    mMathConstants));
-}
-
-const MathGlyphInfo*
-gfxMathTable::GetMathGlyphInfo()
-{
-  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
-  return
-    reinterpret_cast<const MathGlyphInfo*>(mathData +
-                                           uint16_t(GetMATHTableHeader()->
-                                                    mMathGlyphInfo));
-}
-
-const MathVariants*
-gfxMathTable::GetMathVariants()
-{
-  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
-  return
-    reinterpret_cast<const MathVariants*>(mathData +
-                                          uint16_t(GetMATHTableHeader()->
-                                                   mMathVariants));
-}
-
-const GlyphAssembly*
-gfxMathTable::GetGlyphAssembly(uint32_t aGlyphID, bool aVertical)
-{
-  // Select the glyph construction.
-  SelectGlyphConstruction(aGlyphID, aVertical);
-  if (!mGlyphConstruction) {
-    return nullptr;
-  }
-
-  // Get the offset of the glyph assembly and verify whether it is valid.
-  const char* start = reinterpret_cast<const char*>(mGlyphConstruction);
-  uint16_t offset = mGlyphConstruction->mGlyphAssembly;
-  if (offset == 0 || !ValidOffset(start, offset)) {
-    return nullptr;
-  }
-  start += offset;
-
-  // Verify the validity of the GlyphAssembly and return it.
-  if (!ValidStructure(start, sizeof(GlyphAssembly))) {
-    return nullptr;
-  }
-  return reinterpret_cast<const GlyphAssembly*>(start);
+  mMathVariantCache.arePartsValid = true;
 }
-
-namespace {
-
-struct GlyphArrayWrapper
-{
-  const GlyphID* const mGlyphArray;
-  explicit GlyphArrayWrapper(const GlyphID* const aGlyphArray) : mGlyphArray(aGlyphArray)
-  {}
-  uint16_t operator[](size_t index) const {
-    return mGlyphArray[index];
-  }
-};
-
-struct RangeRecordComparator
-{
-  const uint32_t mGlyph;
-  explicit RangeRecordComparator(uint32_t aGlyph) : mGlyph(aGlyph) {}
-  int operator()(const RangeRecord& aRecord) const {
-    if (mGlyph < static_cast<uint16_t>(aRecord.mStart)) {
-      return -1;
-    }
-    if (mGlyph > static_cast<uint16_t>(aRecord.mEnd)) {
-      return 1;
-    }
-    return 0;
-  }
-};
-
-} // namespace
-
-int32_t
-gfxMathTable::GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph)
-{
-  using mozilla::BinarySearch;
-  using mozilla::BinarySearchIf;
-
-  if (uint16_t(aCoverage->mFormat) == 1) {
-    // Coverage Format 1: list of individual glyph indices in the glyph set.
-    const CoverageFormat1* table =
-      reinterpret_cast<const CoverageFormat1*>(aCoverage);
-    const uint16_t count = table->mGlyphCount;
-    const char* start = reinterpret_cast<const char*>(table + 1);
-    if (ValidStructure(start, count * sizeof(GlyphID))) {
-      const GlyphID* glyphArray = reinterpret_cast<const GlyphID*>(start);
-      size_t index;
-
-      if (BinarySearch(GlyphArrayWrapper(glyphArray), 0, count, aGlyph, &index)) {
-        return index;
-      }
-    }
-  } else if (uint16_t(aCoverage->mFormat) == 2) {
-    // Coverage Format 2: ranges of consecutive indices.
-    const CoverageFormat2* table =
-      reinterpret_cast<const CoverageFormat2*>(aCoverage);
-    const uint16_t count = table->mRangeCount;
-    const char* start = reinterpret_cast<const char*>(table + 1);
-    if (ValidStructure(start, count * sizeof(RangeRecord))) {
-      const RangeRecord* rangeArray = reinterpret_cast<const RangeRecord*>(start);
-      size_t index;
-
-      if (BinarySearchIf(rangeArray, 0, count, RangeRecordComparator(aGlyph),
-                         &index)) {
-        uint16_t rStart = rangeArray[index].mStart;
-        uint16_t startCoverageIndex = rangeArray[index].mStartCoverageIndex;
-        return (startCoverageIndex + aGlyph - rStart);
-      }
-    }
-  }
-  return -1;
-}
-
-void
-gfxMathTable::SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical)
-{
-  if (mGlyphID == aGlyphID && mVertical == aVertical) {
-    // The (glyph, direction) pair is already selected: nothing to do.
-    return;
-  }
-
-  // Update our cached values.
-  mVertical = aVertical;
-  mGlyphID = aGlyphID;
-  mGlyphConstruction = nullptr;
-
-  // Get the coverage index for the new values.
-  const MathVariants* mathvariants = GetMathVariants();
-  const char* start = reinterpret_cast<const char*>(mathvariants);
-  uint16_t offset = (aVertical ?
-                     mathvariants->mVertGlyphCoverage :
-                     mathvariants->mHorizGlyphCoverage);
-  const Coverage* coverage =
-    reinterpret_cast<const Coverage*>(start + offset);
-  int32_t i = GetCoverageIndex(coverage, aGlyphID);
-
-  // Get the offset to the glyph construction.
-  uint16_t count = (aVertical ?
-                    mathvariants->mVertGlyphCount :
-                    mathvariants->mHorizGlyphCount);
-  start = reinterpret_cast<const char*>(mathvariants + 1);
-  if (i < 0 || i >= count) {
-    return;
-  }
-  if (!aVertical) {
-    start += uint16_t(mathvariants->mVertGlyphCount) * sizeof(Offset);
-  }
-  if (!ValidStructure(start, count * sizeof(Offset))) {
-    return;
-  }
-  const Offset* offsetArray = reinterpret_cast<const Offset*>(start);
-  offset = uint16_t(offsetArray[i]);
-
-  // Make mGlyphConstruction point to the desired glyph construction.
-  start = reinterpret_cast<const char*>(mathvariants);
-  if (!ValidStructure(start + offset, sizeof(MathGlyphConstruction))) {
-    return;
-  }
-  mGlyphConstruction =
-    reinterpret_cast<const MathGlyphConstruction*>(start + offset);
-}
-
-size_t
-gfxMathTable::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
-{
-  // We don't include the size of mMathTable here, because (depending on the
-  // font backend implementation) it will either wrap a block of data owned
-  // by the system (and potentially shared), or a table that's in our font
-  // table cache and therefore already counted.
-  return aMallocSizeOf(this);
-}
--- a/gfx/thebes/gfxMathTable.h
+++ b/gfx/thebes/gfxMathTable.h
@@ -2,123 +2,154 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_MATH_TABLE_H
 #define GFX_MATH_TABLE_H
 
 #include "gfxFont.h"
 
-struct Coverage;
-struct GlyphAssembly;
-struct MATHTableHeader;
-struct MathConstants;
-struct MathGlyphConstruction;
-struct MathGlyphInfo;
-struct MathVariants;
-
 /**
- * Used by |gfxFontEntry| to represent the MATH table of an OpenType font.
- * Each |gfxFontEntry| owns at most one |gfxMathTable| instance.
+ * Used by |gfxFont| to represent the MATH table of an OpenType font.
+ * Each |gfxFont| owns at most one |gfxMathTable| instance.
  */
 class gfxMathTable
 {
 public:
     /**
-     * @param aMathTable The MATH table from the OpenType font
-     *
-     * The gfxMathTable 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 this reference.
+     * @param aFace The HarfBuzz face containing the math table.
+     * @param aSize The font size to pass to HarfBuzz.
      */
-    explicit gfxMathTable(hb_blob_t* aMathTable);
+    gfxMathTable(hb_face_t *aFace, gfxFloat aSize);
 
     /**
      * Releases our reference to the MATH table and cleans up everything else.
      */
     ~gfxMathTable();
 
+    enum MathConstant {
+        // The order of the constants must match the order of the fields
+        // defined in the MATH table.
+        ScriptPercentScaleDown,
+        ScriptScriptPercentScaleDown,
+        DelimitedSubFormulaMinHeight,
+        DisplayOperatorMinHeight,
+        MathLeading,
+        AxisHeight,
+        AccentBaseHeight,
+        FlattenedAccentBaseHeight,
+        SubscriptShiftDown,
+        SubscriptTopMax,
+        SubscriptBaselineDropMin,
+        SuperscriptShiftUp,
+        SuperscriptShiftUpCramped,
+        SuperscriptBottomMin,
+        SuperscriptBaselineDropMax,
+        SubSuperscriptGapMin,
+        SuperscriptBottomMaxWithSubscript,
+        SpaceAfterScript,
+        UpperLimitGapMin,
+        UpperLimitBaselineRiseMin,
+        LowerLimitGapMin,
+        LowerLimitBaselineDropMin,
+        StackTopShiftUp,
+        StackTopDisplayStyleShiftUp,
+        StackBottomShiftDown,
+        StackBottomDisplayStyleShiftDown,
+        StackGapMin,
+        StackDisplayStyleGapMin,
+        StretchStackTopShiftUp,
+        StretchStackBottomShiftDown,
+        StretchStackGapAboveMin,
+        StretchStackGapBelowMin,
+        FractionNumeratorShiftUp,
+        FractionNumeratorDisplayStyleShiftUp,
+        FractionDenominatorShiftDown,
+        FractionDenominatorDisplayStyleShiftDown,
+        FractionNumeratorGapMin,
+        FractionNumDisplayStyleGapMin,
+        FractionRuleThickness,
+        FractionDenominatorGapMin,
+        FractionDenomDisplayStyleGapMin,
+        SkewedFractionHorizontalGap,
+        SkewedFractionVerticalGap,
+        OverbarVerticalGap,
+        OverbarRuleThickness,
+        OverbarExtraAscender,
+        UnderbarVerticalGap,
+        UnderbarRuleThickness,
+        UnderbarExtraDescender,
+        RadicalVerticalGap,
+        RadicalDisplayStyleVerticalGap,
+        RadicalRuleThickness,
+        RadicalExtraAscender,
+        RadicalKernBeforeDegree,
+        RadicalKernAfterDegree,
+        RadicalDegreeBottomRaisePercent
+    };
+
     /**
      * Returns the value of the specified constant from the MATH table.
      */
-    int32_t GetMathConstant(gfxFontEntry::MathConstant aConstant);
+    gfxFloat Constant(MathConstant aConstant) const;
+
+    /**
+     * Returns the value of the specified constant in app units.
+     */
+    nscoord Constant(MathConstant aConstant,
+                     uint32_t aAppUnitsPerDevPixel) const
+    {
+        return NSToCoordRound(Constant(aConstant) * aAppUnitsPerDevPixel);
+    }
 
     /**
      *  If the MATH table contains an italic correction for that glyph, this
-     *  function gets the value and returns true. Otherwise it returns false.
+     *  function returns the corresponding value. Otherwise it returns 0.
      */
-    bool
-    GetMathItalicsCorrection(uint32_t aGlyphID, int16_t* aItalicCorrection);
+    gfxFloat
+    ItalicsCorrection(uint32_t aGlyphID) const;
 
     /**
      * @param aGlyphID  glyph index of the character we want to stretch
      * @param aVertical direction of the stretching (vertical/horizontal)
      * @param aSize     the desired size variant
      *
      * Returns the glyph index of the desired size variant or 0 if there is not
      * any such size variant.
      */
-    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
-                                 uint16_t aSize);
+    uint32_t VariantsSize(uint32_t aGlyphID, bool aVertical,
+                          uint16_t aSize) const;
 
     /**
      * @param aGlyphID  glyph index of the character we want to stretch
      * @param aVertical direction of the stretching (vertical/horizontal)
      * @param aGlyphs   pre-allocated buffer of 4 elements where the glyph
      * indexes (or 0 for absent parts) will be stored. The parts are stored in
      * the order expected by the nsMathMLChar: Top (or Left), Middle, Bottom
      * (or Right), Glue.
      *
      * Tries to fill-in aGlyphs with the relevant glyph indexes and returns
      * whether the operation was successful. The function returns false if
      * there is not any assembly for the character we want to stretch or if
      * the format is not supported by the nsMathMLChar code.
      *
      */
-    bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
-                              uint32_t aGlyphs[4]);
-
-    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-
-protected:
-    friend class gfxFontEntry;
-    // This allows gfxFontEntry to verify the validity of the main headers
-    // before starting to use the MATH table.
-    bool HasValidHeaders();
+    bool VariantsParts(uint32_t aGlyphID, bool aVertical,
+                       uint32_t aGlyphs[4]) const;
 
 private:
-    // HarfBuzz blob where the MATH table is stored.
-    hb_blob_t*    mMathTable;
-
-    // Cached values for the latest (mGlyphID, mVertical) pair that has been
-    // accessed and the corresponding glyph construction. These are verified
-    // by SelectGlyphConstruction and updated if necessary.
-    // mGlyphConstruction will be set to nullptr if no construction is defined
-    // for the glyph. If non-null, its mGlyphAssembly and mVariantCount fields
-    // may be safely read, but no further validation will have been done.
-    const MathGlyphConstruction* mGlyphConstruction;
-    uint32_t mGlyphID;
-    bool     mVertical;
-    void     SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical);
+    // size-specific font object, owned by the gfxMathTable
+    hb_font_t *mHBFont;
 
-    // Access to some structures of the MATH table.
-    // These accessors just return a pointer, but do NOT themselves check the
-    // validity of anything. Until we've checked that HasValidHeaders (which
-    // does validate them) returns true, they might return pointers that cannot
-    // even safely be dereferenced. GetGlyphAssembly may return nullptr if the
-    // given glyph has no assembly defined.
-    const MATHTableHeader* GetMATHTableHeader();
-    const MathConstants*   GetMathConstants();
-    const MathGlyphInfo*   GetMathGlyphInfo();
-    const MathVariants*    GetMathVariants();
-    const GlyphAssembly*   GetGlyphAssembly(uint32_t aGlyphID, bool aVertical);
-
-    // Verify whether a structure or an offset belongs to the math data and can
-    // be read safely.
-    bool ValidStructure(const char* aStructStart, uint16_t aStructSize);
-    bool ValidOffset(const char* aOffsetStart, uint16_t aOffset);
-
-    // Get the coverage index of a glyph index from an Open Type coverage table
-    // or -1 if the glyph index is not found.
-    int32_t GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph);
+    static const unsigned int kMaxCachedSizeCount = 10;
+    struct MathVariantCacheEntry {
+      uint32_t glyphID;
+      bool vertical;
+      uint32_t sizes[kMaxCachedSizeCount];
+      uint32_t parts[4];
+      bool arePartsValid;
+    };
+    mutable MathVariantCacheEntry mMathVariantCache;
+    void ClearCache() const;
+    void UpdateMathVariantCache(uint32_t aGlyphID, bool aVertical) const;
 };
 
 #endif
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1893,17 +1893,17 @@ gfxFontGroup::GetFirstValidFont(uint32_t
 }
 
 gfxFont *
 gfxFontGroup::GetFirstMathFont()
 {
     uint32_t count = mFonts.Length();
     for (uint32_t i = 0; i < count; ++i) {
         gfxFont* font = GetFontAt(i);
-        if (font && font->GetFontEntry()->TryGetMathTable()) {
+        if (font && font->TryGetMathTable()) {
             return font;
         }
     }
     return nullptr;
 }
 
 gfxFontGroup *
 gfxFontGroup::Copy(const gfxFontStyle *aStyle)
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -438,30 +438,30 @@ public:
               gfxFontGroup*      aFontGroup,
               const nsGlyphCode& aGlyph) override;
 
   // This returns a new OpenTypeTable instance to give access to OpenType MATH
   // table or nullptr if the font does not have such table. Ownership is passed
   // to the caller.
   static nsOpenTypeTable* Create(gfxFont* aFont)
   {
-    if (!aFont->GetFontEntry()->TryGetMathTable()) {
+    if (!aFont->TryGetMathTable()) {
       return nullptr;
     }
-    return new nsOpenTypeTable(aFont->GetFontEntry());
+    return new nsOpenTypeTable(aFont);
   }
 
 private:
-  RefPtr<gfxFontEntry> mFontEntry;
+  RefPtr<gfxFont> mFont;
   FontFamilyName mFontFamilyName;
   uint32_t mGlyphID;
 
-  explicit nsOpenTypeTable(gfxFontEntry* aFontEntry)
-    : mFontEntry(aFontEntry),
-      mFontFamilyName(aFontEntry->FamilyName(), eUnquotedName) {
+  explicit nsOpenTypeTable(gfxFont* aFont)
+    : mFont(aFont),
+    mFontFamilyName(aFont->GetFontEntry()->FamilyName(), eUnquotedName) {
     MOZ_COUNT_CTOR(nsOpenTypeTable);
   }
 
   void UpdateCache(DrawTarget*   aDrawTarget,
                    int32_t       aAppUnitsPerDevPixel,
                    gfxFontGroup* aFontGroup,
                    char16_t      aChar);
 };
@@ -494,17 +494,17 @@ nsOpenTypeTable::ElementAt(DrawTarget*  
                            gfxFontGroup* aFontGroup,
                            char16_t      aChar,
                            bool          aVertical,
                            uint32_t      aPosition)
 {
   UpdateCache(aDrawTarget, aAppUnitsPerDevPixel, aFontGroup, aChar);
 
   uint32_t parts[4];
-  if (!mFontEntry->GetMathVariantsParts(mGlyphID, aVertical, parts)) {
+  if (!mFont->MathTable()->VariantsParts(mGlyphID, aVertical, parts)) {
     return kNullGlyph;
   }
 
   uint32_t glyphID = parts[aPosition];
   if (!glyphID) {
     return kNullGlyph;
   }
   nsGlyphCode glyph;
@@ -520,17 +520,17 @@ nsOpenTypeTable::BigOf(DrawTarget*   aDr
                        gfxFontGroup* aFontGroup,
                        char16_t      aChar,
                        bool          aVertical,
                        uint32_t      aSize)
 {
   UpdateCache(aDrawTarget, aAppUnitsPerDevPixel, aFontGroup, aChar);
 
   uint32_t glyphID =
-    mFontEntry->GetMathVariantsSize(mGlyphID, aVertical, aSize);
+    mFont->MathTable()->VariantsSize(mGlyphID, aVertical, aSize);
   if (!glyphID) {
     return kNullGlyph;
   }
 
   nsGlyphCode glyph;
   glyph.glyphID = glyphID;
   glyph.font = -1;
   return glyph;
@@ -542,17 +542,17 @@ nsOpenTypeTable::HasPartsOf(DrawTarget* 
                             int32_t       aAppUnitsPerDevPixel,
                             gfxFontGroup* aFontGroup,
                             char16_t      aChar,
                             bool          aVertical)
 {
   UpdateCache(aDrawTarget, aAppUnitsPerDevPixel, aFontGroup, aChar);
 
   uint32_t parts[4];
-  if (!mFontEntry->GetMathVariantsParts(mGlyphID, aVertical, parts)) {
+  if (!mFont->MathTable()->VariantsParts(mGlyphID, aVertical, parts)) {
     return false;
   }
 
   return parts[0] || parts[1] || parts[2] || parts[3];
 }
 
 /* virtual */
 already_AddRefed<gfxTextRun>
@@ -1128,19 +1128,18 @@ StretchEnumContext::TryVariants(nsGlyphT
     ch = aGlyphTable->BigOf(mDrawTarget, oneDevPixel, *aFontGroup, uchar,
                             isVertical, 0);
     if (ch.IsGlyphID()) {
       gfxFont* mathFont = aFontGroup->get()->GetFirstMathFont();
       // For OpenType MATH fonts, we will rely on the DisplayOperatorMinHeight
       // to select the right size variant. Note that the value is sometimes too
       // small so we use kLargeOpFactor/kIntegralFactor as a minimum value.
       if (mathFont) {
-        displayOperatorMinHeight =
-          mathFont->GetMathConstant(gfxFontEntry::DisplayOperatorMinHeight,
-                                    oneDevPixel);
+        displayOperatorMinHeight = mathFont->MathTable()->
+          Constant(gfxMathTable::DisplayOperatorMinHeight, oneDevPixel);
         RefPtr<gfxTextRun> textRun =
           aGlyphTable->MakeTextRun(mDrawTarget, oneDevPixel, *aFontGroup, ch);
         nsBoundingMetrics bm = MeasureTextRun(mDrawTarget, textRun.get());
         float largeopFactor = kLargeOpFactor;
         if (NS_STRETCH_INTEGRAL & mStretchHint) {
           // integrals are drawn taller
           largeopFactor = kIntegralFactor;
         }
@@ -1174,22 +1173,21 @@ StretchEnumContext::TryVariants(nsGlyphT
       if (mathFont) {
         // MeasureTextRun should have set the advance width to the right
         // bearing for OpenType MATH fonts. We now subtract the italic
         // correction, so that nsMathMLmmultiscripts will place the scripts
         // correctly.
         // Note that STIX-Word does not provide italic corrections but its
         // advance widths do not match right bearings.
         // (http://sourceforge.net/p/stixfonts/tracking/50/)
-        gfxFloat italicCorrection;
-        if (mathFont->GetFontEntry()->
-            GetMathItalicsCorrection(ch.glyphID, &italicCorrection)) {
+        gfxFloat italicCorrection =
+          mathFont->MathTable()->ItalicsCorrection(ch.glyphID);
+        if (italicCorrection) {
           bm.width -=
-            NSToCoordRound(italicCorrection *
-                           mathFont->GetAdjustedSize() * oneDevPixel);
+            NSToCoordRound(italicCorrection * oneDevPixel);
           if (bm.width < 0) {
             bm.width = 0;
           }
         }
       }
     }
 
     nscoord charSize =
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -7,16 +7,17 @@
 
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "nsLayoutUtils.h"
 #include "nsNameSpaceManager.h"
 #include "nsMathMLChar.h"
 #include "nsCSSPseudoElements.h"
 #include "nsMathMLElement.h"
+#include "gfxMathTable.h"
 
 // used to map attributes into CSS rules
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "nsDisplayList.h"
 #include "nsRenderingContext.h"
 
 using namespace mozilla;
@@ -188,18 +189,18 @@ nsMathMLFrame::GetRuleThickness(DrawTarg
 /* static */ void
 nsMathMLFrame::GetAxisHeight(DrawTarget*    aDrawTarget,
                              nsFontMetrics* aFontMetrics,
                              nscoord&       aAxisHeight)
 {
   gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
   if (mathFont) {
     aAxisHeight =
-      mathFont->GetMathConstant(gfxFontEntry::AxisHeight,
-                                aFontMetrics->AppUnitsPerDevPixel());
+      mathFont->MathTable()->Constant(gfxMathTable::AxisHeight,
+                                      aFontMetrics->AppUnitsPerDevPixel());
     return;
   }
 
   nscoord xHeight = aFontMetrics->XHeight();
   char16_t minus = 0x2212; // not '-', but official Unicode minus sign
   nsBoundingMetrics bm =
     nsLayoutUtils::AppUnitBoundsOfString(&minus, 1, *aFontMetrics, aDrawTarget);
   aAxisHeight = bm.ascent - (bm.ascent + bm.descent)/2;
@@ -388,41 +389,39 @@ nsMathMLFrame::GetRadicalParameters(nsFo
                                     nscoord& aRadicalExtraAscender,
                                     nscoord& aRadicalVerticalGap)
 {
   nscoord oneDevPixel = aFontMetrics->AppUnitsPerDevPixel();
   gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
 
   // get the radical rulethickness
   if (mathFont) {
-    aRadicalRuleThickness =
-      mathFont->GetMathConstant(gfxFontEntry::RadicalRuleThickness,
-                                oneDevPixel);
+    aRadicalRuleThickness = mathFont->MathTable()->
+      Constant(gfxMathTable::RadicalRuleThickness, oneDevPixel);
   } else {
     GetRuleThickness(aFontMetrics, aRadicalRuleThickness);
   }
 
   // get the leading to be left at the top of the resulting frame
   if (mathFont) {
-    aRadicalExtraAscender =
-      mathFont->GetMathConstant(gfxFontEntry::RadicalExtraAscender,
-                                oneDevPixel);
+    aRadicalExtraAscender = mathFont->MathTable()->
+      Constant(gfxMathTable::RadicalExtraAscender, oneDevPixel);
   } else {
     // This seems more reliable than using aFontMetrics->GetLeading() on
     // suspicious fonts.
     nscoord em;
     GetEmHeight(aFontMetrics, em);
     aRadicalExtraAscender = nscoord(0.2f * em);
   }
 
   // get the clearance between rule and content
   if (mathFont) {
-    aRadicalVerticalGap =
-      mathFont->GetMathConstant(aDisplayStyle ?
-                                gfxFontEntry::RadicalDisplayStyleVerticalGap :
-                                gfxFontEntry::RadicalVerticalGap,
-                                oneDevPixel);
+    aRadicalVerticalGap = mathFont->MathTable()->
+      Constant(aDisplayStyle ?
+               gfxMathTable::RadicalDisplayStyleVerticalGap :
+               gfxMathTable::RadicalVerticalGap,
+               oneDevPixel);
   } else {
     // Rule 11, App. G, TeXbook
     aRadicalVerticalGap = aRadicalRuleThickness +
       (aDisplayStyle ? aFontMetrics->XHeight() : aRadicalRuleThickness) / 4;
   }
 }
--- a/layout/mathml/nsMathMLmfracFrame.cpp
+++ b/layout/mathml/nsMathMLmfracFrame.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/RefPtr.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsDisplayList.h"
 #include "gfxContext.h"
 #include "nsMathMLElement.h"
 #include <algorithm>
+#include "gfxMathTable.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 //
 // <mfrac> -- form a fraction from two subexpressions - implementation
 //
 
@@ -234,19 +235,18 @@ nsMathMLmfracFrame::PlaceInternal(DrawTa
   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
   RefPtr<nsFontMetrics> fm =
     nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
 
   nscoord defaultRuleThickness, axisHeight;
   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
   if (mathFont) {
-    defaultRuleThickness =
-      mathFont->GetMathConstant(gfxFontEntry::FractionRuleThickness,
-                                oneDevPixel);
+    defaultRuleThickness = mathFont->MathTable()->
+      Constant(gfxMathTable::FractionRuleThickness, oneDevPixel);
   } else {
     GetRuleThickness(aDrawTarget, fm, defaultRuleThickness);
   }
   GetAxisHeight(aDrawTarget, fm, axisHeight);
 
   bool outermostEmbellished = false;
   if (mEmbellishData.coreFrame) {
     nsEmbellishData parentData;
@@ -300,56 +300,55 @@ nsMathMLmfracFrame::PlaceInternal(DrawTa
     GetNumeratorShifts(fm, numShift1, numShift2, numShift3);
     GetDenominatorShifts(fm, denShift1, denShift2);
 
     if (0 == actualRuleThickness) {
       numShift = displayStyle ? numShift1 : numShift3;
       denShift = displayStyle ? denShift1 : denShift2;
       if (mathFont) {
         numShift = mathFont->
-          GetMathConstant(displayStyle ?
-                          gfxFontEntry::StackTopDisplayStyleShiftUp :
-                          gfxFontEntry::StackTopShiftUp,
-                          oneDevPixel);
+          MathTable()->Constant(displayStyle ?
+                                gfxMathTable::StackTopDisplayStyleShiftUp :
+                                gfxMathTable::StackTopShiftUp,
+                                oneDevPixel);
         denShift = mathFont->
-          GetMathConstant(displayStyle ?
-                          gfxFontEntry::StackBottomDisplayStyleShiftDown :
-                          gfxFontEntry::StackBottomShiftDown,
-                          oneDevPixel);
+          MathTable()->Constant(displayStyle ?
+                                gfxMathTable::StackBottomDisplayStyleShiftDown :
+                                gfxMathTable::StackBottomShiftDown,
+                                oneDevPixel);
       }
     } else {
       numShift = displayStyle ? numShift1 : numShift2;
       denShift = displayStyle ? denShift1 : denShift2;
       if (mathFont) {
-        numShift = mathFont->
-          GetMathConstant(displayStyle ?
-                          gfxFontEntry::FractionNumeratorDisplayStyleShiftUp :
-                          gfxFontEntry::FractionNumeratorShiftUp,
-                          oneDevPixel);
-        denShift = mathFont->
-          GetMathConstant(
-            displayStyle ?
-            gfxFontEntry::FractionDenominatorDisplayStyleShiftDown :
-            gfxFontEntry::FractionDenominatorShiftDown,
-            oneDevPixel);
+        numShift = mathFont->MathTable()->
+          Constant(displayStyle ?
+                   gfxMathTable::FractionNumeratorDisplayStyleShiftUp :
+                   gfxMathTable::FractionNumeratorShiftUp,
+                   oneDevPixel);
+        denShift = mathFont->MathTable()->
+          Constant(displayStyle ?
+                   gfxMathTable::FractionDenominatorDisplayStyleShiftDown :
+                   gfxMathTable::FractionDenominatorShiftDown,
+                   oneDevPixel);
       }
     }
 
     if (0 == actualRuleThickness) {
       // Rule 15c, App. G, TeXbook
 
       // min clearance between numerator and denominator
       nscoord minClearance = displayStyle ?
         7 * defaultRuleThickness : 3 * defaultRuleThickness;
       if (mathFont) {
-        minClearance =
-          mathFont->GetMathConstant(displayStyle ?
-                                    gfxFontEntry::StackDisplayStyleGapMin :
-                                    gfxFontEntry::StackGapMin,
-                                    oneDevPixel);
+        minClearance = mathFont->MathTable()->
+          Constant(displayStyle ?
+                   gfxMathTable::StackDisplayStyleGapMin :
+                   gfxMathTable::StackGapMin,
+                   oneDevPixel);
       }
       // Factor in axis height
       // http://www.mathml-association.org/MathMLinHTML5/S3.html#SS3.SSS2
       numShift += axisHeight;
       denShift += axisHeight;
 
       nscoord actualClearance =
         (numShift - bmNum.descent) - (bmDen.ascent - denShift);
@@ -374,25 +373,25 @@ nsMathMLmfracFrame::PlaceInternal(DrawTa
     // of the value coming from the linethickness attribute, i.e., we recover what
     // TeX does if the user hasn't set linethickness. But when the linethickness
     // is set, we avoid the wide gap problem.
       nscoord minClearanceNum = displayStyle ?
         3 * defaultRuleThickness : defaultRuleThickness + onePixel;
       nscoord minClearanceDen = minClearanceNum;
       if (mathFont) {
         minClearanceNum = mathFont->
-          GetMathConstant(displayStyle ?
-                          gfxFontEntry::FractionNumDisplayStyleGapMin :
-                          gfxFontEntry::FractionNumeratorGapMin,
-                          oneDevPixel);
+          MathTable()->Constant(displayStyle ?
+                                gfxMathTable::FractionNumDisplayStyleGapMin :
+                                gfxMathTable::FractionNumeratorGapMin,
+                                oneDevPixel);
         minClearanceDen = mathFont->
-          GetMathConstant(displayStyle ?
-                          gfxFontEntry::FractionDenomDisplayStyleGapMin :
-                          gfxFontEntry::FractionDenominatorGapMin,
-                          oneDevPixel);
+          MathTable()->Constant(displayStyle ?
+                                gfxMathTable::FractionDenomDisplayStyleGapMin :
+                                gfxMathTable::FractionDenominatorGapMin,
+                                oneDevPixel);
       }
 
       // adjust numShift to maintain minClearanceNum if needed
       nscoord actualClearanceNum =
         (numShift - bmNum.descent) - (axisHeight + actualRuleThickness/2);
       if (actualClearanceNum < minClearanceNum) {
         numShift += (minClearanceNum - actualClearanceNum);
       }
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "nsMathMLmmultiscriptsFrame.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include <algorithm>
+#include "gfxMathTable.h"
 
 using mozilla::WritingMode;
 
 //
 // <mmultiscripts> -- attach prescripts and tensor indices to a base - implementation
 // <msub> -- attach a subscript to a base - implementation
 // <msubsup> -- attach a subscript-superscript pair to a base - implementation
 // <msup> -- attach a superscript to a base - implementation
@@ -190,44 +191,44 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
 
   nscoord xHeight = fm->XHeight();
 
   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
   // scriptspace from TeX for extra spacing after sup/subscript
   nscoord scriptSpace;
   if (mathFont) {
-    scriptSpace =
-      mathFont->GetMathConstant(gfxFontEntry::SpaceAfterScript, oneDevPixel);
+    scriptSpace = mathFont->MathTable()->
+      Constant(gfxMathTable::SpaceAfterScript, oneDevPixel);
   } else {
     // (0.5pt in plain TeX)
     scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
   }
 
   // Try and read sub and sup drops from the MATH table.
   if (mathFont) {
-    subDrop = mathFont->
-      GetMathConstant(gfxFontEntry::SubscriptBaselineDropMin, oneDevPixel);
-    supDrop = mathFont->
-      GetMathConstant(gfxFontEntry::SuperscriptBaselineDropMax, oneDevPixel);
+    subDrop = mathFont->MathTable()->
+      Constant(gfxMathTable::SubscriptBaselineDropMin, oneDevPixel);
+    supDrop = mathFont->MathTable()->
+      Constant(gfxMathTable::SuperscriptBaselineDropMax, oneDevPixel);
   }
 
   // force the scriptSpace to be at least 1 pixel
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   scriptSpace = std::max(onePixel, scriptSpace);
 
   /////////////////////////////////////
   // first the shift for the subscript
 
   nscoord subScriptShift;
   if (mathFont) {
     // Try and get the sub script shift from the MATH table. Note that contrary
     // to TeX we only have one parameter.
-    subScriptShift =
-      mathFont->GetMathConstant(gfxFontEntry::SubscriptShiftDown, oneDevPixel);
+    subScriptShift = mathFont->MathTable()->
+      Constant(gfxMathTable::SubscriptShiftDown, oneDevPixel);
   } else {
     // subScriptShift{1,2}
     // = minimum amount to shift the subscript down
     // = sub{1,2} in TeXbook
     // subScriptShift1 = subscriptshift attribute * x-height
     nscoord subScriptShift1, subScriptShift2;
     // Get subScriptShift{1,2} default from font
     GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
@@ -248,20 +249,20 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
 
   nscoord supScriptShift;
   nsPresentationData presentationData;
   aFrame->GetPresentationData(presentationData);
   if (mathFont) {
     // Try and get the super script shift from the MATH table. Note that
     // contrary to TeX we only have two parameters.
     supScriptShift = mathFont->
-      GetMathConstant(NS_MATHML_IS_COMPRESSED(presentationData.flags) ?
-                      gfxFontEntry::SuperscriptShiftUpCramped :
-                      gfxFontEntry::SuperscriptShiftUp,
-                      oneDevPixel);
+      MathTable()->Constant(NS_MATHML_IS_COMPRESSED(presentationData.flags) ?
+                            gfxMathTable::SuperscriptShiftUpCramped :
+                            gfxMathTable::SuperscriptShiftUp,
+                            oneDevPixel);
   } else {
     // supScriptShift{1,2,3}
     // = minimum amount to shift the supscript up
     // = sup{1,2,3} in TeX
     // supScriptShift1 = superscriptshift attribute * x-height
     // Note that there are THREE values for supscript shifts depending
     // on the current style
     nscoord supScriptShift1, supScriptShift2, supScriptShift3;
@@ -419,18 +420,18 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
 
         if (tag == nsGkAtoms::msub_) {
           boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
           boundingMetrics.width += width;
 
           nscoord subscriptTopMax;
           if (mathFont) {
             subscriptTopMax =
-              mathFont->GetMathConstant(gfxFontEntry::SubscriptTopMax,
-                                        oneDevPixel);
+              mathFont->MathTable()->Constant(gfxMathTable::SubscriptTopMax,
+                                              oneDevPixel);
           } else {
             // get min subscript shift limit from x-height
             // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
             subscriptTopMax = NSToCoordRound((4.0f/5.0f) * xHeight);
           }
           nscoord minShiftFromXHeight = bmSubScript.ascent - subscriptTopMax;
           maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);
 
@@ -445,18 +446,18 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
           // get the supdrop from the supscript font
           GetSupDropFromChild (supScriptFrame, supDrop, aFontSizeInflation);
         }
         // parameter u, Rule 18a, App. G, TeXbook
         minSupScriptShift = bmBase.ascent - supDrop;
         nscoord superscriptBottomMin;
         if (mathFont) {
           superscriptBottomMin =
-            mathFont->GetMathConstant(gfxFontEntry::SuperscriptBottomMin,
-                                      oneDevPixel);
+            mathFont->MathTable()->Constant(gfxMathTable::SuperscriptBottomMin,
+                                            oneDevPixel);
         } else {
           // get min supscript shift limit from x-height
           // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
           superscriptBottomMin = NSToCoordRound((1.0f / 4.0f) * xHeight);
         }
         minShiftFromXHeight = bmSupScript.descent + superscriptBottomMin;
         trySupScriptShift = std::max(minSupScriptShift,
                                      std::max(minShiftFromXHeight,
@@ -490,19 +491,18 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
 
         // negotiate between the various shifts so that
         // there is enough gap between the sup and subscripts
         // Rule 18e, App. G, TeXbook
         if (tag == nsGkAtoms::mmultiscripts_ || 
             tag == nsGkAtoms::msubsup_) {
           nscoord subSuperscriptGapMin;
           if (mathFont) {
-            subSuperscriptGapMin =
-              mathFont->GetMathConstant(gfxFontEntry::SubSuperscriptGapMin,
-                                        oneDevPixel);
+            subSuperscriptGapMin = mathFont->MathTable()->
+              Constant(gfxMathTable::SubSuperscriptGapMin, oneDevPixel);
           } else {
             nscoord ruleSize;
             GetRuleThickness(aDrawTarget, fm, ruleSize);
             subSuperscriptGapMin = 4 * ruleSize;
           }
           nscoord gap =
             (trySupScriptShift - bmSupScript.descent) -
             (bmSubScript.ascent - trySubScriptShift);
@@ -510,19 +510,19 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
             // adjust trySubScriptShift to get a gap of subSuperscriptGapMin
             trySubScriptShift += subSuperscriptGapMin - gap;
           }
 
           // next we want to ensure that the bottom of the superscript
           // will be > superscriptBottomMaxWithSubscript
           nscoord superscriptBottomMaxWithSubscript;
           if (mathFont) {
-            superscriptBottomMaxWithSubscript = mathFont->
-              GetMathConstant(gfxFontEntry::SuperscriptBottomMaxWithSubscript,
-                              oneDevPixel);
+            superscriptBottomMaxWithSubscript = mathFont->MathTable()->
+              Constant(gfxMathTable::SuperscriptBottomMaxWithSubscript,
+                       oneDevPixel);
           } else {
             superscriptBottomMaxWithSubscript =
               NSToCoordRound((4.0f / 5.0f) * xHeight);
           }
           gap = superscriptBottomMaxWithSubscript -
             (trySupScriptShift - bmSupScript.descent);
           if (gap > 0) {
             trySupScriptShift += gap;
--- a/layout/mathml/nsMathMLmrootFrame.cpp
+++ b/layout/mathml/nsMathMLmrootFrame.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsMathMLmrootFrame.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include <algorithm>
+#include "gfxMathTable.h"
 
 using namespace mozilla;
 
 //
 // <mroot> -- form a radical - implementation
 //
 
 // additional style context to be used by our MathMLChar.
@@ -111,35 +112,35 @@ nsMathMLmrootFrame::GetRadicalXOffsets(n
   // that the kern does not make the index and radical collide
   nscoord dxIndex, dxSqr;
   nscoord xHeight = aFontMetrics->XHeight();
   nscoord indexRadicalKern = NSToCoordRound(1.35f * xHeight);
   nscoord oneDevPixel = aFontMetrics->AppUnitsPerDevPixel();
   gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
   if (mathFont) {
     indexRadicalKern =
-      mathFont->GetMathConstant(gfxFontEntry::RadicalKernAfterDegree,
-                                oneDevPixel);
+      mathFont->MathTable()->Constant(gfxMathTable::RadicalKernAfterDegree,
+                                      oneDevPixel);
     indexRadicalKern = -indexRadicalKern;
   }
   if (indexRadicalKern > aIndexWidth) {
     dxIndex = indexRadicalKern - aIndexWidth;
     dxSqr = 0;
   }
   else {
     dxIndex = 0;
     dxSqr = aIndexWidth - indexRadicalKern;
   }
 
   if (mathFont) {
     // add some kern before the radical index
     nscoord indexRadicalKernBefore = 0;
     indexRadicalKernBefore =
-      mathFont->GetMathConstant(gfxFontEntry::RadicalKernBeforeDegree,
-                                oneDevPixel);
+      mathFont->MathTable()->Constant(gfxMathTable::RadicalKernBeforeDegree,
+                                      oneDevPixel);
     dxIndex += indexRadicalKernBefore;
     dxSqr += indexRadicalKernBefore;
   } else {
     // avoid collision by leaving a minimum space between index and radical
     nscoord minimumClearance = aSqrWidth / 2;
     if (dxIndex + aIndexWidth + minimumClearance > dxSqr + aSqrWidth) {
       if (aIndexWidth + minimumClearance < aSqrWidth) {
         dxIndex = aSqrWidth - (aIndexWidth + minimumClearance);
@@ -290,18 +291,18 @@ nsMathMLmrootFrame::Reflow(nsPresContext
   /////////////
   // Re-adjust the desired size to include the index.
   
   // the index is raised by some fraction of the height
   // of the radical, see \mroot macro in App. B, TexBook
   float raiseIndexPercent = 0.6f;
   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
   if (mathFont) {
-    raiseIndexPercent =
-      mathFont->GetMathConstant(gfxFontEntry::RadicalDegreeBottomRaisePercent);
+    raiseIndexPercent = mathFont->MathTable()->
+      Constant(gfxMathTable::RadicalDegreeBottomRaisePercent);
   }
   nscoord raiseIndexDelta = NSToCoordRound(raiseIndexPercent *
                                            (bmSqr.ascent + bmSqr.descent));
   nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical 
     - (bmSqr.ascent + bmSqr.descent) // to bottom of radical
     + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index
 
   nscoord indexClearance = 0;
--- a/layout/mathml/nsMathMLmunderoverFrame.cpp
+++ b/layout/mathml/nsMathMLmunderoverFrame.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsMathMLmunderoverFrame.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsMathMLmmultiscriptsFrame.h"
 #include <algorithm>
+#include "gfxMathTable.h"
 
 //
 // <munderover> -- attach an underscript-overscript pair to a base - implementation
 // <mover> -- attach an overscript to a base - implementation
 // <munder> -- attach an underscript to a base - implementation
 //
 
 nsIFrame*
@@ -424,21 +425,21 @@ nsMathMLmunderoverFrame::Place(DrawTarge
                       dummy, bigOpSpacing2, 
                       dummy, bigOpSpacing4, 
                       bigOpSpacing5);
     if (mathFont) {
       // XXXfredw The Open Type MATH table has some StretchStack* parameters
       // that we may use when the base is a stretchy horizontal operator. See
       // bug 963131.
       bigOpSpacing2 =
-        mathFont->GetMathConstant(gfxFontEntry::LowerLimitGapMin,
-                                  oneDevPixel);
+        mathFont->MathTable()->Constant(gfxMathTable::LowerLimitGapMin,
+                                        oneDevPixel);
       bigOpSpacing4 =
-        mathFont->GetMathConstant(gfxFontEntry::LowerLimitBaselineDropMin,
-                                  oneDevPixel);
+        mathFont->MathTable()->Constant(gfxMathTable::LowerLimitBaselineDropMin,
+                                        oneDevPixel);
       bigOpSpacing5 = 0;
     }
     underDelta1 = std::max(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent));
     underDelta2 = bigOpSpacing5;
   }
   else {
     // No corresponding rule in TeXbook - we are on our own here
     // XXX tune the gap delta between base and underscript 
@@ -467,21 +468,21 @@ nsMathMLmunderoverFrame::Place(DrawTarge
                       bigOpSpacing1, dummy, 
                       bigOpSpacing3, dummy, 
                       bigOpSpacing5);
     if (mathFont) {
       // XXXfredw The Open Type MATH table has some StretchStack* parameters
       // that we may use when the base is a stretchy horizontal operator. See
       // bug 963131.
       bigOpSpacing1 =
-        mathFont->GetMathConstant(gfxFontEntry::UpperLimitGapMin,
-                                  oneDevPixel);
+        mathFont->MathTable()->Constant(gfxMathTable::UpperLimitGapMin,
+                                        oneDevPixel);
       bigOpSpacing3 =
-        mathFont->GetMathConstant(gfxFontEntry::UpperLimitBaselineRiseMin,
-                                  oneDevPixel);
+        mathFont->MathTable()->Constant(gfxMathTable::UpperLimitBaselineRiseMin,
+                                        oneDevPixel);
       bigOpSpacing5 = 0;
     }
     overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent));
     overDelta2 = bigOpSpacing5;
 
     // XXX This is not a TeX rule... 
     // delta1 (as computed abvove) can become really big when bmOver.descent is
     // negative,  e.g., if the content is &OverBar. In such case, we use the height
@@ -517,18 +518,18 @@ nsMathMLmunderoverFrame::Place(DrawTarge
     // while also allowing accents that do not follow the convention :
     // we try to keep the *bottom* of the accent char atleast x-height 
     // from the baseline of the base char. we also slap on an extra
     // padding between the accent and base chars.
     overDelta1 = ruleThickness + onePixel/2;
     nscoord accentBaseHeight = xHeight;
     if (mathFont) {
       accentBaseHeight =
-        mathFont->GetMathConstant(gfxFontEntry::AccentBaseHeight,
-                                  oneDevPixel);
+        mathFont->MathTable()->Constant(gfxMathTable::AccentBaseHeight,
+                                        oneDevPixel);
     }
     if (bmBase.ascent < accentBaseHeight) {
       // also ensure at least accentBaseHeight above the baseline of the base
       overDelta1 += accentBaseHeight - bmBase.ascent;
     }
     overDelta2 = ruleThickness;
   }
   // empty over?