Backed out changeset 961a84574836 (bug 1305977) for multiscripts-1.html failures a=backout
authorWes Kocher <wkocher@mozilla.com>
Wed, 02 Nov 2016 11:45:41 -0700
changeset 347405 773aed2f801b27cbad3c031fc7aa747ea9b2c1ed
parent 347404 1633ac89c6ac66367461e9f93dab995bfcf068b4
child 347406 3898797a6267e6d0f84049258e261e207fafd4e5
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)
reviewersbackout
bugs1305977
milestone52.0a1
backs out961a845748368c2d51a4c3fc97c55525e8cb7091
Backed out changeset 961a84574836 (bug 1305977) for multiscripts-1.html failures a=backout
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
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/MathTableStructures.h
@@ -0,0 +1,121 @@
+/* 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,17 +32,16 @@
 #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"
@@ -837,17 +836,16 @@ 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
@@ -4003,26 +4001,8 @@ gfxFontStyle::AdjustForSubSuperscript(in
                           NS_FONT_SUB_SUPER_SMALL_SIZE);
         size *= (1.0 - t) * NS_FONT_SUB_SUPER_SIZE_RATIO_SMALL +
                     t * NS_FONT_SUB_SUPER_SIZE_RATIO_LARGE;
     }
 
     // clear the variant field
     variantSubSuper = NS_FONT_VARIANT_POSITION_NORMAL;
 }
-
-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,17 +41,16 @@ 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;
@@ -1840,23 +1839,32 @@ public:
         return mFontEntry->TryGetSVGData(this);
     }
 
     static void DestroySingletons() {
         delete sScriptTagToCode;
         delete sDefaultFeatures;
     }
 
-    // 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();
+    // 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);
     }
 
     // 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.
@@ -2083,18 +2091,16 @@ 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;
 
@@ -2120,19 +2126,16 @@ 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,16 +30,17 @@
 #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"
 
@@ -67,16 +68,17 @@ 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),
@@ -106,16 +108,17 @@ 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),
@@ -399,16 +402,88 @@ 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;
 
@@ -1007,16 +1082,20 @@ 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,16 +28,17 @@ 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;
 };
 
@@ -187,16 +188,89 @@ 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;
@@ -336,16 +410,17 @@ 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;
@@ -366,16 +441,17 @@ 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,210 +1,486 @@
 /* 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 "harfbuzz/hb-ot.h"
-
-#define FixedToFloat(f) ((f) * (1.0 / 65536.0))
+#include "mozilla/BinarySearch.h"
+#include <algorithm>
 
 using namespace mozilla;
 
-gfxMathTable::gfxMathTable(hb_face_t *aFace, gfxFloat aSize)
+gfxMathTable::gfxMathTable(hb_blob_t* aMathTable)
+  : mMathTable(aMathTable)
+  , mGlyphConstruction(nullptr)
+  , mGlyphID(-1)
+  , mVertical(false)
 {
-  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()
 {
-  if (mHBFont) {
-      hb_font_destroy(mHBFont);
+  hb_blob_destroy(mMathTable);
+}
+
+bool
+gfxMathTable::HasValidHeaders()
+{
+  const char* mathData = hb_blob_get_data(mMathTable, nullptr);
+  // Verify the MATH table header.
+  if (!ValidStructure(mathData, sizeof(MATHTableHeader))) {
+    return false;
+  }
+  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;
   }
+
+  // Verify the MathConstants header.
+  const MathConstants* mathconstants = GetMathConstants();
+  const char* start = reinterpret_cast<const char*>(mathconstants);
+  if (!ValidStructure(start, sizeof(MathConstants))) {
+    return false;
+  }
+
+  // Verify the MathGlyphInfo header.
+  const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo();
+  start = reinterpret_cast<const char*>(mathglyphinfo);
+  if (!ValidStructure(start, sizeof(MathGlyphInfo))) {
+    return false;
+  }
+
+  // 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;
 }
 
-gfxFloat
-gfxMathTable::Constant(MathConstant aConstant) const
+int32_t
+gfxMathTable::GetMathConstant(gfxFontEntry::MathConstant aConstant)
 {
-  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 MathConstants* mathconstants = GetMathConstants();
+
+  if (aConstant <= gfxFontEntry::ScriptScriptPercentScaleDown) {
+    return int16_t(mathconstants->mInt16[aConstant]);
   }
-  return FixedToFloat(value);
+
+  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);
 }
 
-gfxFloat
-gfxMathTable::ItalicsCorrection(uint32_t aGlyphID) const
+bool
+gfxMathTable::GetMathItalicsCorrection(uint32_t aGlyphID,
+                                       int16_t* aItalicCorrection)
 {
-  return FixedToFloat(hb_ot_math_get_glyph_italics_correction(mHBFont, aGlyphID));
+  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);
+
+  // 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;
 }
 
 uint32_t
-gfxMathTable::VariantsSize(uint32_t aGlyphID, bool aVertical,
-                           uint16_t aSize) const
+gfxMathTable::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
+                                  uint16_t aSize)
 {
-  UpdateMathVariantCache(aGlyphID, aVertical);
-  if (aSize < kMaxCachedSizeCount) {
-    return mMathVariantCache.sizes[aSize];
+  // Select the glyph construction.
+  SelectGlyphConstruction(aGlyphID, aVertical);
+  if (!mGlyphConstruction) {
+    return 0;
   }
 
-  // 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;
+  // 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;
+  }
+
+  // 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::VariantsParts(uint32_t aGlyphID, bool aVertical,
-                            uint32_t aGlyphs[4]) const
-{
-  UpdateMathVariantCache(aGlyphID, aVertical);
-  memcpy(aGlyphs, mMathVariantCache.parts, sizeof(mMathVariantCache.parts));
-  return mMathVariantCache.arePartsValid;
-}
-
-void
-gfxMathTable::ClearCache() const
+gfxMathTable::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
+                                   uint32_t aGlyphs[4])
 {
-  memset(mMathVariantCache.sizes, 0, sizeof(mMathVariantCache.sizes));
-  memset(mMathVariantCache.parts, 0, sizeof(mMathVariantCache.parts));
-  mMathVariantCache.arePartsValid = false;
-}
-
-void
-gfxMathTable::UpdateMathVariantCache(uint32_t aGlyphID, bool aVertical) const
-{
-  if (aGlyphID == mMathVariantCache.glyphID &&
-      aVertical == mMathVariantCache.vertical)
-    return;
-
-  mMathVariantCache.glyphID = aGlyphID;
-  mMathVariantCache.vertical = aVertical;
-  ClearCache();
-
-  // 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;
+  // Get the glyph assembly corresponding to that (aGlyphID, aVertical) pair.
+  const GlyphAssembly* glyphAssembly = GetGlyphAssembly(aGlyphID, aVertical);
+  if (!glyphAssembly) {
+    return false;
   }
 
-  // Try and cache the parts of the glyph assembly.
+  // 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);
+
   // 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 (!(parts[i].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER)) {
+    if (!(uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER)) {
       nonExtenderCount++;
     }
   }
   if (nonExtenderCount > 3) {
     // Not supported: too many pieces
-    return;
+    return false;
   }
 
   // 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 = parts[i].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER;
-    uint32_t glyph = parts[i].glyph;
+    bool isExtender = uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER;
+    uint32_t glyph = recordArray[i].mGlyph;
 
     if ((state == 1 || state == 2) && nonExtenderCount < 3) {
       // do not try to find a middle glyph
       state += 2;
     }
 
     if (isExtender) {
       if (!extenderChar) {
         extenderChar = glyph;
-        mMathVariantCache.parts[3] = extenderChar;
+        aGlyphs[3] = extenderChar;
       } else if (extenderChar != glyph)  {
         // Not supported: different extenders
-        return;
+        return false;
       }
 
       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;
+        return false;
       }
 
       continue;
     }
 
     if (state == 0) {
       // copy left/bottom part
-      mMathVariantCache.parts[aVertical ? 2 : 0] = glyph;
+      aGlyphs[mVertical ? 2 : 0] = glyph;
       state = 1;
       continue;
     }
 
     if (state == 1 || state == 2) {
       // copy middle part
-      mMathVariantCache.parts[1] = glyph;
+      aGlyphs[1] = glyph;
       state = 3;
       continue;
     }
 
     if (state == 3 || state == 4) {
       // copy right/top part
-      mMathVariantCache.parts[aVertical ? 0 : 2] = glyph;
+      aGlyphs[mVertical ? 0 : 2] = glyph;
       state = 5;
     }
 
   }
 
-  mMathVariantCache.arePartsValid = true;
+  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);
 }
+
+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,154 +2,123 @@
  * 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 |gfxFont| to represent the MATH table of an OpenType font.
- * Each |gfxFont| owns at most one |gfxMathTable| instance.
+ * Used by |gfxFontEntry| to represent the MATH table of an OpenType font.
+ * Each |gfxFontEntry| owns at most one |gfxMathTable| instance.
  */
 class gfxMathTable
 {
 public:
     /**
-     * @param aFace The HarfBuzz face containing the math table.
-     * @param aSize The font size to pass to HarfBuzz.
+     * @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.
      */
-    gfxMathTable(hb_face_t *aFace, gfxFloat aSize);
+    explicit gfxMathTable(hb_blob_t* aMathTable);
 
     /**
      * 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.
      */
-    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);
-    }
+    int32_t GetMathConstant(gfxFontEntry::MathConstant aConstant);
 
     /**
      *  If the MATH table contains an italic correction for that glyph, this
-     *  function returns the corresponding value. Otherwise it returns 0.
+     *  function gets the value and returns true. Otherwise it returns false.
      */
-    gfxFloat
-    ItalicsCorrection(uint32_t aGlyphID) const;
+    bool
+    GetMathItalicsCorrection(uint32_t aGlyphID, int16_t* aItalicCorrection);
 
     /**
      * @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 VariantsSize(uint32_t aGlyphID, bool aVertical,
-                          uint16_t aSize) const;
+    uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
+                                 uint16_t aSize);
 
     /**
      * @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 VariantsParts(uint32_t aGlyphID, bool aVertical,
-                       uint32_t aGlyphs[4]) const;
+    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();
 
 private:
-    // size-specific font object, owned by the gfxMathTable
-    hb_font_t *mHBFont;
+    // 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);
 
-    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;
+    // 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);
 };
 
 #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->TryGetMathTable()) {
+        if (font && font->GetFontEntry()->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->TryGetMathTable()) {
+    if (!aFont->GetFontEntry()->TryGetMathTable()) {
       return nullptr;
     }
-    return new nsOpenTypeTable(aFont);
+    return new nsOpenTypeTable(aFont->GetFontEntry());
   }
 
 private:
-  RefPtr<gfxFont> mFont;
+  RefPtr<gfxFontEntry> mFontEntry;
   FontFamilyName mFontFamilyName;
   uint32_t mGlyphID;
 
-  explicit nsOpenTypeTable(gfxFont* aFont)
-    : mFont(aFont),
-    mFontFamilyName(aFont->GetFontEntry()->FamilyName(), eUnquotedName) {
+  explicit nsOpenTypeTable(gfxFontEntry* aFontEntry)
+    : mFontEntry(aFontEntry),
+      mFontFamilyName(aFontEntry->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 (!mFont->MathTable()->VariantsParts(mGlyphID, aVertical, parts)) {
+  if (!mFontEntry->GetMathVariantsParts(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 =
-    mFont->MathTable()->VariantsSize(mGlyphID, aVertical, aSize);
+    mFontEntry->GetMathVariantsSize(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 (!mFont->MathTable()->VariantsParts(mGlyphID, aVertical, parts)) {
+  if (!mFontEntry->GetMathVariantsParts(mGlyphID, aVertical, parts)) {
     return false;
   }
 
   return parts[0] || parts[1] || parts[2] || parts[3];
 }
 
 /* virtual */
 already_AddRefed<gfxTextRun>
@@ -1128,18 +1128,19 @@ 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->MathTable()->
-          Constant(gfxMathTable::DisplayOperatorMinHeight, oneDevPixel);
+        displayOperatorMinHeight =
+          mathFont->GetMathConstant(gfxFontEntry::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;
         }
@@ -1173,21 +1174,22 @@ 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 =
-          mathFont->MathTable()->ItalicsCorrection(ch.glyphID);
-        if (italicCorrection) {
+        gfxFloat italicCorrection;
+        if (mathFont->GetFontEntry()->
+            GetMathItalicsCorrection(ch.glyphID, &italicCorrection)) {
           bm.width -=
-            NSToCoordRound(italicCorrection * oneDevPixel);
+            NSToCoordRound(italicCorrection *
+                           mathFont->GetAdjustedSize() * oneDevPixel);
           if (bm.width < 0) {
             bm.width = 0;
           }
         }
       }
     }
 
     nscoord charSize =
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -7,17 +7,16 @@
 
 #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;
@@ -189,18 +188,18 @@ nsMathMLFrame::GetRuleThickness(DrawTarg
 /* static */ void
 nsMathMLFrame::GetAxisHeight(DrawTarget*    aDrawTarget,
                              nsFontMetrics* aFontMetrics,
                              nscoord&       aAxisHeight)
 {
   gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
   if (mathFont) {
     aAxisHeight =
-      mathFont->MathTable()->Constant(gfxMathTable::AxisHeight,
-                                      aFontMetrics->AppUnitsPerDevPixel());
+      mathFont->GetMathConstant(gfxFontEntry::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;
@@ -389,39 +388,41 @@ nsMathMLFrame::GetRadicalParameters(nsFo
                                     nscoord& aRadicalExtraAscender,
                                     nscoord& aRadicalVerticalGap)
 {
   nscoord oneDevPixel = aFontMetrics->AppUnitsPerDevPixel();
   gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
 
   // get the radical rulethickness
   if (mathFont) {
-    aRadicalRuleThickness = mathFont->MathTable()->
-      Constant(gfxMathTable::RadicalRuleThickness, oneDevPixel);
+    aRadicalRuleThickness =
+      mathFont->GetMathConstant(gfxFontEntry::RadicalRuleThickness,
+                                oneDevPixel);
   } else {
     GetRuleThickness(aFontMetrics, aRadicalRuleThickness);
   }
 
   // get the leading to be left at the top of the resulting frame
   if (mathFont) {
-    aRadicalExtraAscender = mathFont->MathTable()->
-      Constant(gfxMathTable::RadicalExtraAscender, oneDevPixel);
+    aRadicalExtraAscender =
+      mathFont->GetMathConstant(gfxFontEntry::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->MathTable()->
-      Constant(aDisplayStyle ?
-               gfxMathTable::RadicalDisplayStyleVerticalGap :
-               gfxMathTable::RadicalVerticalGap,
-               oneDevPixel);
+    aRadicalVerticalGap =
+      mathFont->GetMathConstant(aDisplayStyle ?
+                                gfxFontEntry::RadicalDisplayStyleVerticalGap :
+                                gfxFontEntry::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,17 +11,16 @@
 #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
 //
 
@@ -235,18 +234,19 @@ 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->MathTable()->
-      Constant(gfxMathTable::FractionRuleThickness, oneDevPixel);
+    defaultRuleThickness =
+      mathFont->GetMathConstant(gfxFontEntry::FractionRuleThickness,
+                                oneDevPixel);
   } else {
     GetRuleThickness(aDrawTarget, fm, defaultRuleThickness);
   }
   GetAxisHeight(aDrawTarget, fm, axisHeight);
 
   bool outermostEmbellished = false;
   if (mEmbellishData.coreFrame) {
     nsEmbellishData parentData;
@@ -300,55 +300,56 @@ 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->
-          MathTable()->Constant(displayStyle ?
-                                gfxMathTable::StackTopDisplayStyleShiftUp :
-                                gfxMathTable::StackTopShiftUp,
-                                oneDevPixel);
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::StackTopDisplayStyleShiftUp :
+                          gfxFontEntry::StackTopShiftUp,
+                          oneDevPixel);
         denShift = mathFont->
-          MathTable()->Constant(displayStyle ?
-                                gfxMathTable::StackBottomDisplayStyleShiftDown :
-                                gfxMathTable::StackBottomShiftDown,
-                                oneDevPixel);
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::StackBottomDisplayStyleShiftDown :
+                          gfxFontEntry::StackBottomShiftDown,
+                          oneDevPixel);
       }
     } else {
       numShift = displayStyle ? numShift1 : numShift2;
       denShift = displayStyle ? denShift1 : denShift2;
       if (mathFont) {
-        numShift = mathFont->MathTable()->
-          Constant(displayStyle ?
-                   gfxMathTable::FractionNumeratorDisplayStyleShiftUp :
-                   gfxMathTable::FractionNumeratorShiftUp,
-                   oneDevPixel);
-        denShift = mathFont->MathTable()->
-          Constant(displayStyle ?
-                   gfxMathTable::FractionDenominatorDisplayStyleShiftDown :
-                   gfxMathTable::FractionDenominatorShiftDown,
-                   oneDevPixel);
+        numShift = mathFont->
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::FractionNumeratorDisplayStyleShiftUp :
+                          gfxFontEntry::FractionNumeratorShiftUp,
+                          oneDevPixel);
+        denShift = mathFont->
+          GetMathConstant(
+            displayStyle ?
+            gfxFontEntry::FractionDenominatorDisplayStyleShiftDown :
+            gfxFontEntry::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->MathTable()->
-          Constant(displayStyle ?
-                   gfxMathTable::StackDisplayStyleGapMin :
-                   gfxMathTable::StackGapMin,
-                   oneDevPixel);
+        minClearance =
+          mathFont->GetMathConstant(displayStyle ?
+                                    gfxFontEntry::StackDisplayStyleGapMin :
+                                    gfxFontEntry::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);
@@ -373,25 +374,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->
-          MathTable()->Constant(displayStyle ?
-                                gfxMathTable::FractionNumDisplayStyleGapMin :
-                                gfxMathTable::FractionNumeratorGapMin,
-                                oneDevPixel);
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::FractionNumDisplayStyleGapMin :
+                          gfxFontEntry::FractionNumeratorGapMin,
+                          oneDevPixel);
         minClearanceDen = mathFont->
-          MathTable()->Constant(displayStyle ?
-                                gfxMathTable::FractionDenomDisplayStyleGapMin :
-                                gfxMathTable::FractionDenominatorGapMin,
-                                oneDevPixel);
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::FractionDenomDisplayStyleGapMin :
+                          gfxFontEntry::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,17 +3,16 @@
  * 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
@@ -191,44 +190,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->MathTable()->
-      Constant(gfxMathTable::SpaceAfterScript, oneDevPixel);
+    scriptSpace =
+      mathFont->GetMathConstant(gfxFontEntry::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->MathTable()->
-      Constant(gfxMathTable::SubscriptBaselineDropMin, oneDevPixel);
-    supDrop = mathFont->MathTable()->
-      Constant(gfxMathTable::SuperscriptBaselineDropMax, oneDevPixel);
+    subDrop = mathFont->
+      GetMathConstant(gfxFontEntry::SubscriptBaselineDropMin, oneDevPixel);
+    supDrop = mathFont->
+      GetMathConstant(gfxFontEntry::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->MathTable()->
-      Constant(gfxMathTable::SubscriptShiftDown, oneDevPixel);
+    subScriptShift =
+      mathFont->GetMathConstant(gfxFontEntry::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);
@@ -249,20 +248,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->
-      MathTable()->Constant(NS_MATHML_IS_COMPRESSED(presentationData.flags) ?
-                            gfxMathTable::SuperscriptShiftUpCramped :
-                            gfxMathTable::SuperscriptShiftUp,
-                            oneDevPixel);
+      GetMathConstant(NS_MATHML_IS_COMPRESSED(presentationData.flags) ?
+                      gfxFontEntry::SuperscriptShiftUpCramped :
+                      gfxFontEntry::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;
@@ -420,18 +419,18 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
 
         if (tag == nsGkAtoms::msub_) {
           boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
           boundingMetrics.width += width;
 
           nscoord subscriptTopMax;
           if (mathFont) {
             subscriptTopMax =
-              mathFont->MathTable()->Constant(gfxMathTable::SubscriptTopMax,
-                                              oneDevPixel);
+              mathFont->GetMathConstant(gfxFontEntry::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);
 
@@ -446,18 +445,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->MathTable()->Constant(gfxMathTable::SuperscriptBottomMin,
-                                            oneDevPixel);
+            mathFont->GetMathConstant(gfxFontEntry::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,
@@ -491,18 +490,19 @@ 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->MathTable()->
-              Constant(gfxMathTable::SubSuperscriptGapMin, oneDevPixel);
+            subSuperscriptGapMin =
+              mathFont->GetMathConstant(gfxFontEntry::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->MathTable()->
-              Constant(gfxMathTable::SuperscriptBottomMaxWithSubscript,
-                       oneDevPixel);
+            superscriptBottomMaxWithSubscript = mathFont->
+              GetMathConstant(gfxFontEntry::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,17 +2,16 @@
 /* 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.
@@ -112,35 +111,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->MathTable()->Constant(gfxMathTable::RadicalKernAfterDegree,
-                                      oneDevPixel);
+      mathFont->GetMathConstant(gfxFontEntry::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->MathTable()->Constant(gfxMathTable::RadicalKernBeforeDegree,
-                                      oneDevPixel);
+      mathFont->GetMathConstant(gfxFontEntry::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);
@@ -291,18 +290,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->MathTable()->
-      Constant(gfxMathTable::RadicalDegreeBottomRaisePercent);
+    raiseIndexPercent =
+      mathFont->GetMathConstant(gfxFontEntry::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,17 +3,16 @@
  * 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*
@@ -425,21 +424,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->MathTable()->Constant(gfxMathTable::LowerLimitGapMin,
-                                        oneDevPixel);
+        mathFont->GetMathConstant(gfxFontEntry::LowerLimitGapMin,
+                                  oneDevPixel);
       bigOpSpacing4 =
-        mathFont->MathTable()->Constant(gfxMathTable::LowerLimitBaselineDropMin,
-                                        oneDevPixel);
+        mathFont->GetMathConstant(gfxFontEntry::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 
@@ -468,21 +467,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->MathTable()->Constant(gfxMathTable::UpperLimitGapMin,
-                                        oneDevPixel);
+        mathFont->GetMathConstant(gfxFontEntry::UpperLimitGapMin,
+                                  oneDevPixel);
       bigOpSpacing3 =
-        mathFont->MathTable()->Constant(gfxMathTable::UpperLimitBaselineRiseMin,
-                                        oneDevPixel);
+        mathFont->GetMathConstant(gfxFontEntry::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
@@ -518,18 +517,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->MathTable()->Constant(gfxMathTable::AccentBaseHeight,
-                                        oneDevPixel);
+        mathFont->GetMathConstant(gfxFontEntry::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?