Don't try to add large glyphs to the font atlas.

When the glyph data is invalid we can try to allocate a ridiculous amount of memory. This adds a check to cover such cases.

BUG=414581
R=egdaniel@google.com

Author: jvanverth@google.com

Review URL: https://codereview.chromium.org/585853003
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index 9ef8da2..4210517 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -454,30 +454,32 @@
     }
 
     if (NULL == glyph->fPlot) {
-        if (fStrike->addGlyphToAtlas(glyph, scaler)) {
-            goto HAS_ATLAS;
-        }
+        if (!fStrike->glyphTooLargeForAtlas(glyph)) {
+            if (fStrike->addGlyphToAtlas(glyph, scaler)) {
+                goto HAS_ATLAS;
+            }
 
-        // try to clear out an unused plot before we flush
-        if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
-            fStrike->addGlyphToAtlas(glyph, scaler)) {
-            goto HAS_ATLAS;
-        }
+            // try to clear out an unused plot before we flush
+            if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
+                fStrike->addGlyphToAtlas(glyph, scaler)) {
+                goto HAS_ATLAS;
+            }
 
-        if (c_DumpFontCache) {
+            if (c_DumpFontCache) {
 #ifdef SK_DEVELOPER
-            fContext->getFontCache()->dump();
+                fContext->getFontCache()->dump();
 #endif
-        }
+            }
 
-        // flush any accumulated draws to allow us to free up a plot
-        this->flushGlyphs();
-        fContext->flush();
+            // flush any accumulated draws to allow us to free up a plot
+            this->flushGlyphs();
+            fContext->flush();
 
-        // we should have an unused plot now
-        if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
-            fStrike->addGlyphToAtlas(glyph, scaler)) {
-            goto HAS_ATLAS;
+            // we should have an unused plot now
+            if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
+                fStrike->addGlyphToAtlas(glyph, scaler)) {
+                goto HAS_ATLAS;
+            }
         }
 
         if (NULL == glyph->fPath) {
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index 18058be..313c02a 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -273,30 +273,32 @@
     }
 */
     if (NULL == glyph->fPlot) {
-        if (fStrike->addGlyphToAtlas(glyph, scaler)) {
-            goto HAS_ATLAS;
-        }
+        if (!fStrike->glyphTooLargeForAtlas(glyph)) {
+            if (fStrike->addGlyphToAtlas(glyph, scaler)) {
+                goto HAS_ATLAS;
+            }
 
-        // try to clear out an unused plot before we flush
-        if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
-            fStrike->addGlyphToAtlas(glyph, scaler)) {
-            goto HAS_ATLAS;
-        }
+            // try to clear out an unused plot before we flush
+            if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
+                fStrike->addGlyphToAtlas(glyph, scaler)) {
+                goto HAS_ATLAS;
+            }
 
-        if (c_DumpFontCache) {
+            if (c_DumpFontCache) {
 #ifdef SK_DEVELOPER
-            fContext->getFontCache()->dump();
+                fContext->getFontCache()->dump();
 #endif
-        }
+            }
 
-        // before we purge the cache, we must flush any accumulated draws
-        this->flushGlyphs();
-        fContext->flush();
+            // before we purge the cache, we must flush any accumulated draws
+            this->flushGlyphs();
+            fContext->flush();
 
-        // we should have an unused plot now
-        if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
-            fStrike->addGlyphToAtlas(glyph, scaler)) {
-            goto HAS_ATLAS;
+            // we should have an unused plot now
+            if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
+                fStrike->addGlyphToAtlas(glyph, scaler)) {
+                goto HAS_ATLAS;
+            }
         }
 
         if (NULL == glyph->fPath) {
diff --git a/src/gpu/GrTextStrike.cpp b/src/gpu/GrTextStrike.cpp
index 24fa707..fa97f73 100644
--- a/src/gpu/GrTextStrike.cpp
+++ b/src/gpu/GrTextStrike.cpp
@@ -289,6 +289,19 @@
     GrAtlas::RemovePlot(&fPlotUsage, plot);
 }
 
+bool GrTextStrike::glyphTooLargeForAtlas(GrGlyph* glyph) {
+    int width = glyph->fBounds.width();
+    int height = glyph->fBounds.height();
+    int pad = fUseDistanceField ? 2 * SK_DistanceFieldPad : 0;
+    if (width + pad > GR_PLOT_WIDTH) {
+        return true;
+    }
+    if (height + pad > GR_PLOT_HEIGHT) {
+        return true;
+    }
+
+    return false;
+}
 
 bool GrTextStrike::addGlyphToAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
 #if 0   // testing hack to force us to flush our cache often
diff --git a/src/gpu/GrTextStrike.h b/src/gpu/GrTextStrike.h
index a5bb6ae..401bd73 100644
--- a/src/gpu/GrTextStrike.h
+++ b/src/gpu/GrTextStrike.h
@@ -37,6 +37,10 @@
     GrTexture*   getTexture() const { return fAtlas->getTexture(); }
 
     inline GrGlyph* getGlyph(GrGlyph::PackedID, GrFontScaler*);
+    // returns true if glyph (or glyph+padding for distance field)
+    // is too large to ever fit in texture atlas subregions (GrPlots)
+    bool glyphTooLargeForAtlas(GrGlyph*);
+    // returns true if glyph successfully added to texture atlas, false otherwise
     bool addGlyphToAtlas(GrGlyph*, GrFontScaler*);
 
     // testing