Bug 1137588 - patch 1 - Read the second array in 'vmtx' correctly to get glyph vertical origins. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Thu, 26 Mar 2015 12:23:45 +0000
changeset 264672 44625300e0108465a7f9d5a6394594eb705d1d78
parent 264671 c309c399dfad6d8ef09be2098b88cba96b4ff63b
child 264673 986f5faf4655b9d02aa217db2612e4d3c2d16a9f
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs1137588
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1137588 - patch 1 - Read the second array in 'vmtx' correctly to get glyph vertical origins. r=jdaggett
gfx/thebes/gfxHarfBuzzShaper.cpp
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -350,25 +350,32 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_co
         bool emptyGlyf;
         const Glyf *glyf = FindGlyf(aGlyph, &emptyGlyf);
         if (glyf) {
             if (emptyGlyf) {
                 *aY = 0;
                 return;
             }
 
-            if (aGlyph >= uint32_t(mNumLongVMetrics)) {
-                aGlyph = mNumLongVMetrics - 1;
-            }
             const GlyphMetrics* metrics =
                 reinterpret_cast<const GlyphMetrics*>
                     (hb_blob_get_data(mVmtxTable, nullptr));
+            int16_t lsb;
+            if (aGlyph < hb_codepoint_t(mNumLongVMetrics)) {
+                // Glyph is covered by the first (advance & sidebearing) array
+                lsb = int16_t(metrics->metrics[aGlyph].lsb);
+            } else {
+                // Glyph is covered by the second (sidebearing-only) array
+                const AutoSwap_PRInt16* sidebearings =
+                    reinterpret_cast<const AutoSwap_PRInt16*>
+                        (&metrics->metrics[mNumLongVMetrics]);
+                lsb = int16_t(sidebearings[aGlyph - mNumLongVMetrics]);
+            }
             *aY = -FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
-                                (int16_t(metrics->metrics[aGlyph].lsb) +
-                                 int16_t(glyf->yMax)));
+                                (lsb + int16_t(glyf->yMax)));
             return;
         } else {
             // XXX TODO: not a truetype font; need to get glyph extents
             // via some other API?
             // For now, fall through to default code below.
         }
     }
 
@@ -1266,21 +1273,32 @@ gfxHarfBuzzShaper::InitializeVertical()
     gfxFontEntry::AutoTable vheaTable(entry, TRUETYPE_TAG('v','h','e','a'));
     if (vheaTable) {
         uint32_t len;
         const MetricsHeader* vhea =
             reinterpret_cast<const MetricsHeader*>
             (hb_blob_get_data(vheaTable, &len));
         if (len >= sizeof(MetricsHeader)) {
             mNumLongVMetrics = vhea->numOfLongMetrics;
-            if (mNumLongVMetrics > 0 &&
+            gfxFontEntry::AutoTable
+                maxpTable(entry, TRUETYPE_TAG('m','a','x','p'));
+            int numGlyphs = -1; // invalid if we fail to read 'maxp'
+            if (maxpTable &&
+                hb_blob_get_length(maxpTable) >= sizeof(MaxpTableHeader)) {
+                const MaxpTableHeader* maxp =
+                    reinterpret_cast<const MaxpTableHeader*>
+                    (hb_blob_get_data(maxpTable, nullptr));
+                numGlyphs = uint16_t(maxp->numGlyphs);
+            }
+            if (mNumLongVMetrics > 0 && mNumLongVMetrics <= numGlyphs &&
                 int16_t(vhea->metricDataFormat) == 0) {
                 mVmtxTable = entry->GetFontTable(TRUETYPE_TAG('v','m','t','x'));
                 if (mVmtxTable && hb_blob_get_length(mVmtxTable) <
-                    mNumLongVMetrics * sizeof(LongMetric)) {
+                    mNumLongVMetrics * sizeof(LongMetric) +
+                    (numGlyphs - mNumLongVMetrics) * sizeof(int16_t)) {
                     // metrics table is not large enough for the claimed
                     // number of entries: invalid, do not use.
                     hb_blob_destroy(mVmtxTable);
                     mVmtxTable = nullptr;
                 }
             }
         }
     }