Bug 691581 - Don't let a zero-sized font result in assertions from FUnitsToDevUnitsFactor(). r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Mon, 02 Nov 2015 08:36:50 +0000
changeset 270853 11486a275847896bf97beff11d6c07ffea3611e9
parent 270817 469fc8555c437105e4bdeea57e1645525bd83cdc
child 270854 b0a8ab5e08568fc92f8f01db5c5cefaa663ed30f
push id18459
push usercbook@mozilla.com
push dateTue, 03 Nov 2015 11:14:32 +0000
treeherderb2g-inbound@09173d8e6694 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs691581
milestone45.0a1
Bug 691581 - Don't let a zero-sized font result in assertions from FUnitsToDevUnitsFactor(). r=jdaggett
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxGDIFont.cpp
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -743,17 +743,17 @@ gfxFont::RunMetrics::CombineWith(const R
 
 gfxFont::gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                  AntialiasOption anAAOption, cairo_scaled_font_t *aScaledFont) :
     mScaledFont(aScaledFont),
     mFontEntry(aFontEntry), mIsValid(true),
     mApplySyntheticBold(false),
     mStyle(*aFontStyle),
     mAdjustedSize(0.0),
-    mFUnitsConvFactor(0.0f),
+    mFUnitsConvFactor(-1.0f), // negative to indicate "not yet initialized"
     mAntialiasOption(anAAOption)
 {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
     ++gFontCount;
 #endif
     mKerningSet = HasFeatureSet(HB_TAG('k','e','r','n'), mKerningEnabled);
 }
 
@@ -780,20 +780,20 @@ gfxFloat
 gfxFont::GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID)
 {
     if (!SetupCairoFont(aCtx)) {
         return 0;
     }
     if (ProvidesGlyphWidths()) {
         return GetGlyphWidth(*aCtx->GetDrawTarget(), aGID) / 65536.0;
     }
-    if (mFUnitsConvFactor == 0.0f) {
+    if (mFUnitsConvFactor < 0.0f) {
         GetMetrics(eHorizontal);
     }
-    NS_ASSERTION(mFUnitsConvFactor > 0.0f,
+    NS_ASSERTION(mFUnitsConvFactor >= 0.0f,
                  "missing font unit conversion factor");
     if (!mHarfBuzzShaper) {
         mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
     }
     gfxHarfBuzzShaper* shaper =
         static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
     if (!shaper->Initialize()) {
         return 0;
@@ -3210,17 +3210,17 @@ gfxFont::InitMetricsFromSfntTables(Metri
     mIsValid = false; // font is NOT valid in case of early return
 
     const uint32_t kHheaTableTag = TRUETYPE_TAG('h','h','e','a');
     const uint32_t kPostTableTag = TRUETYPE_TAG('p','o','s','t');
     const uint32_t kOS_2TableTag = TRUETYPE_TAG('O','S','/','2');
 
     uint32_t len;
 
-    if (mFUnitsConvFactor == 0.0) {
+    if (mFUnitsConvFactor < 0.0) {
         // If the conversion factor from FUnits is not yet set,
         // get the unitsPerEm from the 'head' table via the font entry
         uint16_t unitsPerEm = GetFontEntry()->UnitsPerEm();
         if (unitsPerEm == gfxFontEntry::kInvalidUPEM) {
             return false;
         }
         mFUnitsConvFactor = GetAdjustedSize() / unitsPerEm;
     }
@@ -3446,28 +3446,28 @@ gfxFont::CreateVerticalMetrics()
     metrics->emDescent = metrics->emHeight - metrics->emAscent;
 
     metrics->maxAscent = metrics->emAscent;
     metrics->maxDescent = metrics->emDescent;
 
     const float UNINITIALIZED_LEADING = -10000.0f;
     metrics->externalLeading = UNINITIALIZED_LEADING;
 
-    if (mFUnitsConvFactor == 0.0) {
+    if (mFUnitsConvFactor < 0.0) {
         uint16_t upem = GetFontEntry()->UnitsPerEm();
         if (upem != gfxFontEntry::kInvalidUPEM) {
             mFUnitsConvFactor = GetAdjustedSize() / upem;
         }
     }
 
 #define SET_UNSIGNED(field,src) metrics->field = uint16_t(src) * mFUnitsConvFactor
 #define SET_SIGNED(field,src)   metrics->field = int16_t(src) * mFUnitsConvFactor
 
     gfxFontEntry::AutoTable os2Table(mFontEntry, kOS_2TableTag);
-    if (os2Table && mFUnitsConvFactor > 0.0) {
+    if (os2Table && mFUnitsConvFactor >= 0.0) {
         const OS2Table *os2 =
             reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
         // These fields should always be present in any valid OS/2 table
         if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
             SET_SIGNED(strikeoutSize, os2->yStrikeoutSize);
             // Use ascent+descent from the horizontal metrics as the default
             // advance (aveCharWidth) in vertical mode
             gfxFloat ascentDescent = gfxFloat(mFUnitsConvFactor) *
@@ -3483,33 +3483,33 @@ gfxFont::CreateVerticalMetrics()
             metrics->maxDescent = std::max(metrics->maxDescent, halfCharWidth);
         }
     }
 
     // If we didn't set aveCharWidth from OS/2, try to read 'hhea' metrics
     // and use the line height from its ascent/descent.
     if (!metrics->aveCharWidth) {
         gfxFontEntry::AutoTable hheaTable(mFontEntry, kHheaTableTag);
-        if (hheaTable && mFUnitsConvFactor > 0.0) {
+        if (hheaTable && mFUnitsConvFactor >= 0.0) {
             const MetricsHeader* hhea =
                 reinterpret_cast<const MetricsHeader*>
                     (hb_blob_get_data(hheaTable, &len));
             if (len >= sizeof(MetricsHeader)) {
                 SET_SIGNED(aveCharWidth, int16_t(hhea->ascender) -
                                          int16_t(hhea->descender));
                 metrics->maxAscent = metrics->aveCharWidth / 2;
                 metrics->maxDescent =
                     metrics->aveCharWidth - metrics->maxAscent;
             }
         }
     }
 
     // Read real vertical metrics if available.
     gfxFontEntry::AutoTable vheaTable(mFontEntry, kVheaTableTag);
-    if (vheaTable && mFUnitsConvFactor > 0.0) {
+    if (vheaTable && mFUnitsConvFactor >= 0.0) {
         const MetricsHeader* vhea =
             reinterpret_cast<const MetricsHeader*>
                 (hb_blob_get_data(vheaTable, &len));
         if (len >= sizeof(MetricsHeader)) {
             SET_UNSIGNED(maxAdvance, vhea->advanceWidthMax);
             // Redistribute space between ascent/descent because we want a
             // centered vertical baseline by default.
             gfxFloat halfExtent = 0.5 * gfxFloat(mFUnitsConvFactor) *
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1385,17 +1385,17 @@ public:
     virtual gfxFloat GetAdjustedSize() const {
         return mAdjustedSize > 0.0
                  ? mAdjustedSize
                  : (mStyle.sizeAdjust == 0.0 ? 0.0 : mStyle.size);
     }
 
     float FUnitsToDevUnitsFactor() const {
         // check this was set up during font initialization
-        NS_ASSERTION(mFUnitsConvFactor > 0.0f, "mFUnitsConvFactor not valid");
+        NS_ASSERTION(mFUnitsConvFactor >= 0.0f, "mFUnitsConvFactor not valid");
         return mFUnitsConvFactor;
     }
 
     // check whether this is an sfnt we can potentially use with harfbuzz
     bool FontCanSupportHarfBuzz() {
         return mFontEntry->HasCmapTable();
     }
 
@@ -2027,17 +2027,20 @@ protected:
 
     nsExpirationState          mExpirationState;
     gfxFontStyle               mStyle;
     nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray;
     nsAutoPtr<nsTHashtable<nsPtrHashKey<GlyphChangeObserver> > > mGlyphChangeObservers;
 
     gfxFloat                   mAdjustedSize;
 
-    float                      mFUnitsConvFactor; // conversion factor from font units to dev units
+    // Conversion factor from font units to dev units; note that this may be
+    // zero (in the degenerate case where mAdjustedSize has become zero).
+    // This is OK because we only multiply by this factor, never divide.
+    float                      mFUnitsConvFactor;
 
     // the AA setting requested for this font - may affect glyph bounds
     AntialiasOption            mAntialiasOption;
 
     // a copy of the font without antialiasing, if needed for separate
     // measurement by mathml code
     nsAutoPtr<gfxFont>         mNonAAFont;
 
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -355,16 +355,18 @@ gfxGDIFont::Initialize()
         if (ret != GDI_ERROR && glyph != 0xFFFF) {
             GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size);
             mMetrics->zeroOrAveCharWidth = ROUND(size.cx);
         } else {
             mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
         }
 
         SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
+    } else {
+        mFUnitsConvFactor = 0.0; // zero-sized font: all values scale to zero
     }
 
     if (IsSyntheticBold()) {
         mMetrics->aveCharWidth += GetSyntheticBoldOffset();
         mMetrics->maxAdvance += GetSyntheticBoldOffset();
     }
 
     mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont,