Bug 761442 - treat substitution and positioning lookups involving <space> differently. r=jkew
authorJohn Daggett <jdaggett@mozilla.com>
Thu, 11 Apr 2013 22:49:58 +0900
changeset 135220 703e4668b5c8dcfd49afa2343566b9175dfde5e6
parent 135219 8a0073ae1a45f4bd2318b84c7dcb37620d42156d
child 135221 53e7c851a6a75bf7c920987799f2075eb9a009d2
push id3752
push userlsblakk@mozilla.com
push dateMon, 13 May 2013 17:21:10 +0000
treeherdermozilla-aurora@1580544aef0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjkew
bugs761442
milestone23.0a1
Bug 761442 - treat substitution and positioning lookups involving <space> differently. r=jkew
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
layout/media/symbols.def.in
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1448,16 +1448,17 @@ gfxFont::gfxFont(gfxFontEntry *aFontEntr
     mStyle(*aFontStyle),
     mAdjustedSize(0.0),
     mFUnitsConvFactor(0.0f),
     mAntialiasOption(anAAOption)
 {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
     ++gFontCount;
 #endif
+    mKerningSet = HasFeatureSet(HB_TAG('k','e','r','n'), mKerningEnabled);
 }
 
 gfxFont::~gfxFont()
 {
     uint32_t i, count = mGlyphExtentsArray.Length();
     // We destroy the contents of mGlyphExtentsArray explicitly instead of
     // using nsAutoPtr because VC++ can't deal with nsTArrays of nsAutoPtrs
     // of classes that lack a proper copy constructor
@@ -1496,54 +1497,299 @@ gfxFont::GetFontTable(uint32_t aTag) {
 static hb_blob_t *
 HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData)
 {
     gfxFont* font = static_cast<gfxFont*>(aUserData);
     return font->GetFontTable(aTag);
 }
 
 static bool
-HasLayoutFeatureInvolving(hb_face_t *aFace, hb_tag_t aTag, uint16_t aGlyph)
+HasLookupRuleWithGlyphByScript(hb_face_t *aFace, hb_tag_t aTableTag,
+                               hb_tag_t aScript, uint16_t aGlyph)
 {
     hb_set_t *lookups = hb_set_create();
     hb_set_t *glyphs = hb_set_create();
-
-    hb_ot_layout_collect_lookups(aFace, aTag, nullptr, nullptr, nullptr,
+    hb_tag_t scripts[2] = {0};
+    scripts[0] = aScript;
+
+    bool result = false;
+    hb_ot_layout_collect_lookups(aFace, aTableTag, scripts, nullptr, nullptr,
                                  lookups);
 
     hb_codepoint_t index = -1;
     while (hb_set_next(lookups, &index)) {
-        hb_ot_layout_lookup_collect_glyphs(aFace, aTag, index,
+        hb_ot_layout_lookup_collect_glyphs(aFace, aTableTag, index,
                                            glyphs, glyphs, glyphs,
                                            glyphs);
-    }
-
-    bool result = hb_set_has(glyphs, aGlyph);
+        if (hb_set_has(glyphs, aGlyph)) {
+            result = true;
+            break;
+        }
+    }
 
     hb_set_destroy(glyphs);
     hb_set_destroy(lookups);
 
     return result;
 }
 
-bool
+static void
+CollectLookupsByFeature(hb_face_t *aFace, hb_tag_t aTableTag,
+                        uint32_t aFeatureIndex, hb_set_t *aLookups)
+{
+    uint32_t lookups[32];
+    uint32_t i, len, offset;
+
+    offset = 0;
+    do {
+        len = ArrayLength(lookups);
+        hb_ot_layout_feature_get_lookups(aFace, aTableTag, aFeatureIndex,
+                                         offset, &len, lookups);
+        for (i = 0; i < len; i++) {
+            hb_set_add(aLookups, lookups[i]);
+        }
+        offset += len;
+    } while (len == ArrayLength(lookups));
+}
+
+static void
+CollectLookupsByLanguage(hb_face_t *aFace, hb_tag_t aTableTag,
+                         hb_tag_t aExcludeFeature,
+                         hb_set_t *aLookups, hb_set_t *aExcludedFeatureLookups,
+                         uint32_t aScriptIndex, uint32_t aLangIndex)
+{
+    uint32_t reqFeatureIndex;
+    if (hb_ot_layout_language_get_required_feature_index(aFace, aTableTag,
+                                                         aScriptIndex,
+                                                         aLangIndex,
+                                                         &reqFeatureIndex)) {
+        CollectLookupsByFeature(aFace, aTableTag, reqFeatureIndex, aLookups);
+    }
+
+    uint32_t featureIndexes[32];
+    uint32_t i, len, offset;
+
+    offset = 0;
+    do {
+        len = ArrayLength(featureIndexes);
+        hb_ot_layout_language_get_feature_indexes(aFace, aTableTag,
+                                                  aScriptIndex, aLangIndex,
+                                                  offset, &len, featureIndexes);
+
+        for (i = 0; i < len; i++) {
+            uint32_t featureIndex = featureIndexes[i];
+
+            // get the feature tag
+            hb_tag_t featureTag;
+            uint32_t tagLen = 1;
+            hb_ot_layout_language_get_feature_tags(aFace, aTableTag,
+                                                   aScriptIndex, aLangIndex,
+                                                   offset + i, &tagLen,
+                                                   &featureTag);
+
+            // collect lookups
+            hb_set_t *lookups = featureTag == aExcludeFeature ?
+                                    aExcludedFeatureLookups : aLookups;
+            CollectLookupsByFeature(aFace, aTableTag, featureIndex, lookups);
+        }
+        offset += len;
+    } while (len == ArrayLength(featureIndexes));
+}
+
+static void
+HasLookupRuleWithGlyph(hb_face_t *aFace, hb_tag_t aTableTag, bool& aHasGlyph,
+                       hb_tag_t aExcludeFeature, bool& aHasGlyphExcluded,
+                       uint16_t aGlyph)
+{
+    // iterate over the scripts in the font
+    uint32_t numScripts, numLangs, script, lang;
+    hb_set_t *lookups = hb_set_create();
+    hb_set_t *excludedFeatureLookups = hb_set_create();
+
+    numScripts = hb_ot_layout_table_get_script_tags(aFace, aTableTag, 0,
+                                                    nullptr, nullptr);
+
+    for (script = 0; script < numScripts; script++) {
+        // default lang
+        CollectLookupsByLanguage(aFace, aTableTag, aExcludeFeature,
+                                 lookups, excludedFeatureLookups,
+                                 script, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+
+        // iterate over langs
+        numLangs = hb_ot_layout_script_get_language_tags(aFace, HB_OT_TAG_GPOS,
+                                                         script, 0,
+                                                         nullptr, nullptr);
+        for (lang = 0; lang < numLangs; lang++) {
+            CollectLookupsByLanguage(aFace, aTableTag, aExcludeFeature,
+                                     lookups, excludedFeatureLookups,
+                                     script, lang);
+        }
+    }
+
+    // look for the glyph among non-excluded lookups
+    hb_set_t *glyphs = hb_set_create();
+    hb_codepoint_t index = -1;
+    while (hb_set_next(lookups, &index)) {
+        hb_ot_layout_lookup_collect_glyphs(aFace, aTableTag, index,
+                                           glyphs, glyphs, glyphs,
+                                           glyphs);
+        if (hb_set_has(glyphs, aGlyph)) {
+            aHasGlyph = true;
+            break;
+        }
+    }
+
+    // look for the glyph among excluded lookups
+    hb_set_clear(glyphs);
+    index = -1;
+    while (hb_set_next(excludedFeatureLookups, &index)) {
+        hb_ot_layout_lookup_collect_glyphs(aFace, aTableTag, index,
+                                           glyphs, glyphs, glyphs,
+                                           glyphs);
+        if (hb_set_has(glyphs, aGlyph)) {
+            aHasGlyphExcluded = true;
+            break;
+        }
+    }
+
+    hb_set_destroy(glyphs);
+    hb_set_destroy(excludedFeatureLookups);
+    hb_set_destroy(lookups);
+}
+
+nsDataHashtable<nsUint32HashKey, int32_t> gfxFont::sScriptTagToCode;
+
+void
 gfxFont::CheckForFeaturesInvolvingSpace()
 {
+    mFontEntry->mHasSpaceFeaturesInitialized = true;
+
+    bool result = false;
+
     hb_face_t *face = hb_face_create_for_tables(HBGetTable, this, nullptr);
 
-    bool result = (hb_ot_layout_has_substitution(face) &&
-                   HasLayoutFeatureInvolving(face, HB_OT_TAG_GSUB,
-                                             GetSpaceGlyph())) ||
-                  (hb_ot_layout_has_positioning(face) &&
-                   HasLayoutFeatureInvolving(face, HB_OT_TAG_GPOS,
-                                             GetSpaceGlyph()));
+    uint32_t i, len, offset;
+    uint32_t spaceGlyph = GetSpaceGlyph();
+    int32_t s;
+
+    mFontEntry->mHasSpaceFeaturesSubDefault = false;
+
+    // GSUB lookups - examine per script
+    if (hb_ot_layout_has_substitution(face)) {
+
+        // set up the script ==> code hashtable if needed
+        if (!sScriptTagToCode.IsInitialized()) {
+            sScriptTagToCode.Init(MOZ_NUM_SCRIPT_CODES);
+            for (s = MOZ_SCRIPT_ARABIC; s < MOZ_NUM_SCRIPT_CODES; s++) {
+                hb_script_t scriptTag = hb_script_t(GetScriptTagForCode(s));
+                hb_tag_t s1, s2;
+                hb_ot_tags_from_script(scriptTag, &s1, &s2);
+                sScriptTagToCode.Put(s1, s);
+                if (s2 != HB_OT_TAG_DEFAULT_SCRIPT) {
+                    sScriptTagToCode.Put(s2, s);
+                }
+            }
+        }
+
+        // iterate over the scripts in the font
+        hb_tag_t scriptTags[8];
+
+        offset = 0;
+        do {
+            len = ArrayLength(scriptTags);
+            hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, offset,
+                                               &len, scriptTags);
+            for (i = 0; i < len; i++) {
+                if (HasLookupRuleWithGlyphByScript(face, HB_OT_TAG_GSUB,
+                                                   scriptTags[i], spaceGlyph))
+                {
+                    result = true;
+                    if (scriptTags[i] == HB_TAG('D','F','L','T')) {
+                        mFontEntry->mHasSpaceFeaturesSubDefault = true;
+                    }
+                    if (sScriptTagToCode.Get(scriptTags[i], &s)) {
+                        uint32_t index = s >> 5;
+                        uint32_t bit = s & 0x1f;
+                        mFontEntry->mHasSpaceFeaturesSub[index] |= (1 << bit);
+                    }
+                }
+            }
+            offset += len;
+        } while (len == ArrayLength(scriptTags));
+    }
+
+    // GPOS lookups - distinguish kerning from non-kerning features
+    mFontEntry->mHasSpaceFeaturesKerning = false;
+    mFontEntry->mHasSpaceFeaturesNonKerning = false;
+
+    if (hb_ot_layout_has_positioning(face)) {
+        bool hasKerning = false, hasNonKerning = false;
+        HasLookupRuleWithGlyph(face, HB_OT_TAG_GPOS, hasNonKerning,
+                               HB_TAG('k','e','r','n'), hasKerning, spaceGlyph);
+        if (hasKerning || hasNonKerning) {
+            result = true;
+        }
+        mFontEntry->mHasSpaceFeaturesKerning = hasKerning;
+        mFontEntry->mHasSpaceFeaturesNonKerning = hasNonKerning;
+    }
 
     hb_face_destroy(face);
-
-    return result;
+    mFontEntry->mHasSpaceFeatures = result;
+
+#ifdef DEBUG_SPACE_LOOKUPS
+    printf("font: %s - subst: %8.8x %8.8x %8.8x %8.8x "
+           "default: %s kerning: %s non-kerning: %s\n",
+           NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(),
+           mFontEntry->mHasSpaceFeaturesSub[0],
+           mFontEntry->mHasSpaceFeaturesSub[1],
+           mFontEntry->mHasSpaceFeaturesSub[2],
+           mFontEntry->mHasSpaceFeaturesSub[3],
+           (mFontEntry->mHasSpaceFeaturesSubDefault ? "true" : "false"),
+           (mFontEntry->mHasSpaceFeaturesKerning ? "true" : "false"),
+           (mFontEntry->mHasSpaceFeaturesNonKerning ? "true" : "false")
+    );
+#endif
+}
+
+bool
+gfxFont::HasFeatureSet(uint32_t aFeature, bool& aFeatureOn)
+{
+    aFeatureOn = false;
+
+    if (mStyle.featureSettings.IsEmpty() &&
+        GetFontEntry()->mFeatureSettings.IsEmpty()) {
+        return false;
+    }
+
+    // add feature values from font
+    bool featureSet = false;
+    uint32_t i, count;
+
+    nsTArray<gfxFontFeature>& fontFeatures = GetFontEntry()->mFeatureSettings;
+    count = fontFeatures.Length();
+    for (i = 0; i < count; i++) {
+        const gfxFontFeature& feature = fontFeatures.ElementAt(i);
+        if (feature.mTag == aFeature) {
+            featureSet = true;
+            aFeatureOn = (feature.mValue != 0);
+        }
+    }
+
+    // add feature values from style rules
+    nsTArray<gfxFontFeature>& styleFeatures = mStyle.featureSettings;
+    count = styleFeatures.Length();
+    for (i = 0; i < count; i++) {
+        const gfxFontFeature& feature = styleFeatures.ElementAt(i);
+        if (feature.mTag == aFeature) {
+            featureSet = true;
+            aFeatureOn = (feature.mValue != 0);
+        }
+    }
+
+    return featureSet;
 }
 
 /**
  * A helper function in case we need to do any rounding or other
  * processing here.
  */
 #define ToDeviceUnits(aAppUnits, aDevUnitsPerAppUnit) \
     (double(aAppUnits)*double(aDevUnitsPerAppUnit))
@@ -2754,26 +3000,26 @@ gfxFont::SplitAndInitTextRun(gfxContext 
                              uint32_t aRunStart,
                              uint32_t aRunLength,
                              int32_t aRunScript)
 {
     if (aRunLength == 0) {
         return true;
     }
 
-    uint32_t flags = aTextRun->GetFlags();
-    if (BypassShapedWordCache(flags)) {
+    if (BypassShapedWordCache(aRunScript)) {
         return ShapeTextWithoutWordCache(aContext, aString + aRunStart,
                                          aRunStart, aRunLength, aRunScript,
                                          aTextRun);
     }
 
     InitWordCache();
 
     // the only flags we care about for ShapedWord construction/caching
+    uint32_t flags = aTextRun->GetFlags();
     flags &= (gfxTextRunFactory::TEXT_IS_RTL |
               gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES);
     if (sizeof(T) == sizeof(uint8_t)) {
         flags |= gfxTextRunFactory::TEXT_IS_8BIT;
     }
 
     const T *text = aString + aRunStart;
     uint32_t wordStart = 0;
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -23,16 +23,17 @@
 #include "nsISupportsImpl.h"
 #include "gfxPattern.h"
 #include "mozilla/HashFunctions.h"
 #include "nsIMemoryReporter.h"
 #include "gfxFontFeatures.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/Attributes.h"
 #include <algorithm>
+#include "nsUnicodeProperties.h"
 
 typedef struct _cairo_scaled_font cairo_scaled_font_t;
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 class gfxContext;
@@ -210,25 +211,31 @@ public:
         mName(aName), mItalic(false), mFixedPitch(false),
         mIsProxy(false), mIsValid(true), 
         mIsBadUnderlineFont(false), mIsUserFont(false),
         mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
         mSymbolFont(false),
         mIgnoreGDEF(false),
         mIgnoreGSUB(false),
         mSVGInitialized(false),
+        mHasSpaceFeaturesInitialized(false),
+        mHasSpaceFeatures(false),
+        mHasSpaceFeaturesKerning(false),
+        mHasSpaceFeaturesNonKerning(false),
+        mHasSpaceFeaturesSubDefault(false),
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
-        mHasSpaceFeaturesInitialized(false),
         mCheckedForGraphiteTables(false),
         mHasCmapTable(false),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
         mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
-    { }
+    {
+        memset(&mHasSpaceFeaturesSub, 0, sizeof(mHasSpaceFeaturesSub));
+    }
 
     virtual ~gfxFontEntry();
 
     // unique name for the face, *not* the family; not necessarily the
     // "real" or user-friendly name, may be an internal identifier
     const nsString& Name() const { return mName; }
 
     // family name
@@ -340,23 +347,28 @@ public:
     bool             mIsBadUnderlineFont : 1;
     bool             mIsUserFont  : 1;
     bool             mIsLocalUserFont  : 1;
     bool             mStandardFace : 1;
     bool             mSymbolFont  : 1;
     bool             mIgnoreGDEF  : 1;
     bool             mIgnoreGSUB  : 1;
     bool             mSVGInitialized : 1;
+    bool             mHasSpaceFeaturesInitialized : 1;
+    bool             mHasSpaceFeatures : 1;
+    bool             mHasSpaceFeaturesKerning : 1;
+    bool             mHasSpaceFeaturesNonKerning : 1;
+    bool             mHasSpaceFeaturesSubDefault : 1;
+
+    // bitvector of substitution space features per script
+    uint32_t         mHasSpaceFeaturesSub[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
 
     uint16_t         mWeight;
     int16_t          mStretch;
 
-    bool             mHasSpaceFeatures;
-    bool             mHasSpaceFeaturesInitialized;
-
     bool             mHasGraphiteTables;
     bool             mCheckedForGraphiteTables;
     bool             mHasCmapTable;
     nsRefPtr<gfxCharacterMap> mCharacterMap;
     uint32_t         mUVSOffset;
     nsAutoArrayPtr<uint8_t> mUVSData;
     gfxUserFontData* mUserFontData;
     gfxSVGGlyphs    *mSVGGlyphs;
@@ -377,18 +389,22 @@ protected:
         mIsBadUnderlineFont(false),
         mIsUserFont(false),
         mIsLocalUserFont(false),
         mStandardFace(false),
         mSymbolFont(false),
         mIgnoreGDEF(false),
         mIgnoreGSUB(false),
         mSVGInitialized(false),
+        mHasSpaceFeaturesInitialized(false),
+        mHasSpaceFeatures(false),
+        mHasSpaceFeaturesKerning(false),
+        mHasSpaceFeaturesNonKerning(false),
+        mHasSpaceFeaturesSubDefault(false),
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
-        mHasSpaceFeaturesInitialized(false),
         mCheckedForGraphiteTables(false),
         mHasCmapTable(false),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
         mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
     { }
 
@@ -1561,34 +1577,59 @@ public:
     } FontType;
 
     virtual FontType GetType() const = 0;
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
     { return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this); }
 
 protected:
-    bool BypassShapedWordCache(uint32_t aRunFlags) {
-        // When creating a textrun in optimizeSpeed mode, we always use the
-        // word cache (which means we do not support features that span
-        // inter-word spaces)
-        if (aRunFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) {
+
+    bool HasSubstitutionRulesWithSpaceLookups(int32_t aRunScript) {
+        NS_ASSERTION(GetFontEntry()->mHasSpaceFeaturesInitialized,
+                     "need to initialize space lookup flags");
+        NS_ASSERTION(aRunScript < MOZ_NUM_SCRIPT_CODES, "weird script code");
+        if (aRunScript == MOZ_SCRIPT_INVALID ||
+            aRunScript >= MOZ_NUM_SCRIPT_CODES) {
             return false;
         }
+        uint32_t index = aRunScript >> 5;
+        uint32_t bit = aRunScript & 0x1f;
+        return (mFontEntry->mHasSpaceFeaturesSub[index] & (1 << bit)) != 0;
+    }
+
+    bool BypassShapedWordCache(int32_t aRunScript) {
         // We record the presence of space-dependent features in the font entry
         // so that subsequent instantiations for the same font face won't
         // require us to re-check the tables; however, the actual check is done
         // by gfxFont because not all font entry subclasses know how to create
         // a harfbuzz face for introspection.
-        gfxFontEntry *fe = GetFontEntry();
-        if (!fe->mHasSpaceFeaturesInitialized) {
-            fe->mHasSpaceFeaturesInitialized = true;
-            fe->mHasSpaceFeatures = CheckForFeaturesInvolvingSpace();
+        if (!mFontEntry->mHasSpaceFeaturesInitialized) {
+            CheckForFeaturesInvolvingSpace();
+        }
+
+        if (!mFontEntry->mHasSpaceFeatures) {
+            return false;
         }
-        return fe->mHasSpaceFeatures;
+
+        // if font has substitution rules or non-kerning positioning rules
+        // that involve spaces, bypass
+        if (HasSubstitutionRulesWithSpaceLookups(aRunScript) ||
+            mFontEntry->mHasSpaceFeaturesNonKerning ||
+            mFontEntry->mHasSpaceFeaturesSubDefault) {
+            return true;
+        }
+
+        // if kerning explicitly enabled/disabled via font-feature-settings or
+        // font-kerning and kerning rules use spaces, only bypass when enabled
+        if (mKerningSet && mFontEntry->mHasSpaceFeaturesKerning) {
+            return mKerningEnabled;
+        }
+
+        return false;
     }
 
     // For 8-bit text, expand to 16-bit and then call the following method.
     bool ShapeText(gfxContext    *aContext,
                    const uint8_t *aText,
                    uint32_t       aOffset, // dest offset in gfxShapedText
                    uint32_t       aLength,
                    int32_t        aScript,
@@ -1637,17 +1678,23 @@ protected:
     template<typename T>
     bool ShapeFragmentWithoutWordCache(gfxContext *aContext,
                                        const T    *aText,
                                        uint32_t    aOffset,
                                        uint32_t    aLength,
                                        int32_t     aScript,
                                        gfxTextRun *aTextRun);
 
-    bool CheckForFeaturesInvolvingSpace();
+    void CheckForFeaturesInvolvingSpace();
+
+    // whether a given feature is included in feature settings from both the
+    // font and the style. aFeatureOn set if resolved feature value is non-zero
+    bool HasFeatureSet(uint32_t aFeature, bool& aFeatureOn);
+
+    static nsDataHashtable<nsUint32HashKey, int32_t> sScriptTagToCode;
 
     nsRefPtr<gfxFontEntry> mFontEntry;
 
     struct CacheHashKey {
         union {
             const uint8_t   *mSingle;
             const PRUnichar *mDouble;
         }                mText;
@@ -1730,16 +1777,19 @@ protected:
     static const uint32_t  kShapedWordCacheMaxAge = 3;
 
     bool                       mIsValid;
 
     // 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?
+
     nsExpirationState          mExpirationState;
     gfxFontStyle               mStyle;
     nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray;
 
     gfxFloat                   mAdjustedSize;
 
     float                      mFUnitsConvFactor; // conversion factor from font units to dev units
 
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -540,23 +540,34 @@ hb_font_funcs_set_glyph_contour_point_fu
 hb_font_funcs_set_glyph_func
 hb_font_funcs_set_glyph_h_advance_func
 hb_font_funcs_set_glyph_h_kerning_func
 hb_font_set_funcs
 hb_font_set_ppem
 hb_font_set_scale
 hb_language_from_string
 hb_ot_layout_collect_lookups
+hb_ot_layout_feature_get_lookups
 hb_ot_layout_has_positioning
 hb_ot_layout_has_substitution
+hb_ot_layout_language_get_feature_indexes
+hb_ot_layout_language_get_feature_tags
+hb_ot_layout_language_get_required_feature_index
 hb_ot_layout_lookup_collect_glyphs
+hb_ot_layout_script_get_language_tags
+hb_ot_layout_table_choose_script
+hb_ot_layout_table_get_script_tags
 hb_ot_tag_to_language
+hb_ot_tags_from_script
+hb_set_add
+hb_set_clear
 hb_set_create
 hb_set_destroy
 hb_set_has
+hb_set_is_empty
 hb_set_next
 hb_shape
 hb_unicode_funcs_create
 hb_unicode_funcs_get_empty
 hb_unicode_funcs_set_combining_class_func
 hb_unicode_funcs_set_compose_func
 hb_unicode_funcs_set_decompose_func
 hb_unicode_funcs_set_eastasian_width_func