Add bilerp support to scaled emojis

Bug: skia:7562
Change-Id: Ibdf8e71050e909de87ca2beb3fb2b57327011364
Reviewed-on: https://skia-review.googlesource.com/111820
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 8212f71..9e144ed 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -258,8 +258,10 @@
         flushInfo.fGeometryProcessor = this->setupDfProcessor(fullAtlasManager);
         SkDEBUGCODE(dfPerspective = fGeoData[0].fViewMatrix.hasPerspective());
     } else {
+        GrSamplerState samplerState = fHasScaledGlyphs ? GrSamplerState::ClampBilerp()
+                                                       : GrSamplerState::ClampNearest();
         flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
-            this->color(), proxies, atlasPageCount, GrSamplerState::ClampNearest(), maskFormat,
+            this->color(), proxies, atlasPageCount, samplerState, maskFormat,
             localMatrix, this->usesLocalCoords());
     }
 
@@ -349,8 +351,10 @@
                     proxies, numProxies, GrSamplerState::ClampBilerp());
             }
         } else {
-            reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewProxies(
-                proxies, numProxies, GrSamplerState::ClampNearest());
+            GrSamplerState samplerState = fHasScaledGlyphs ? GrSamplerState::ClampBilerp()
+                                                           : GrSamplerState::ClampNearest();
+            reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewProxies(proxies, numProxies,
+                                                                      samplerState);
         }
     }
 
@@ -398,6 +402,10 @@
         if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
             return false;
         }
+
+        if (fHasScaledGlyphs != that->fHasScaledGlyphs) {
+            return false;
+        }
     }
 
     // Keep the batch vertex buffer size below 32K so we don't have to create a special one
diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h
index ae1c95b..9ba6c87 100644
--- a/src/gpu/ops/GrAtlasTextOp.h
+++ b/src/gpu/ops/GrAtlasTextOp.h
@@ -41,8 +41,9 @@
     };
 
     static std::unique_ptr<GrAtlasTextOp> MakeBitmap(
-                                GrPaint&& paint, GrMaskFormat maskFormat,
-                                int glyphCount, GrRestrictedAtlasManager* restrictedAtlasManager) {
+                                GrPaint&& paint, GrMaskFormat maskFormat, int glyphCount,
+                                bool hasScaledGlyphs,
+                                GrRestrictedAtlasManager* restrictedAtlasManager) {
         std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp(restrictedAtlasManager,
                                                             std::move(paint)));
 
@@ -60,6 +61,7 @@
         op->fNumGlyphs = glyphCount;
         op->fGeoCount = 1;
         op->fLuminanceColor = 0;
+        op->fHasScaledGlyphs = hasScaledGlyphs;
         return op;
     }
 
@@ -183,15 +185,18 @@
     int fGeoDataAllocSize;
     uint32_t fSRGBFlags;
     GrProcessorSet fProcessors;
-    bool fUsesLocalCoords;
-    bool fCanCombineOnTouchOrOverlap;
+    struct {
+        uint32_t fUsesLocalCoords : 1;
+        uint32_t fCanCombineOnTouchOrOverlap : 1;
+        uint32_t fUseGammaCorrectDistanceTable : 1;
+        uint32_t fHasScaledGlyphs : 1;
+    };
     int fGeoCount;
     int fNumGlyphs;
     MaskType fMaskType;
     // Distance field properties
     sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
     SkColor fLuminanceColor;
-    bool fUseGammaCorrectDistanceTable;
     uint32_t fDFGPFlags = 0;
 
     typedef GrMeshDrawOp INHERITED;
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index 8470370..bd3d768 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -152,6 +152,7 @@
     subRun->appendVertices(vertexStride);
     fGlyphs[subRun->glyphEndIndex()] = glyph;
     subRun->glyphAppended();
+    subRun->setHasScaledGlyphs(SK_Scalar1 != scale);
 }
 
 void GrAtlasTextBlob::appendPathGlyph(int runIndex, const SkPath& path, SkScalar x, SkScalar y,
@@ -264,8 +265,8 @@
                 target->colorSpaceInfo().isGammaCorrect(), paint.luminanceColor(),
                 info.hasUseLCDText(), useBGR, info.isAntiAliased());
     } else {
-        op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format,
-                                       glyphCount, restrictedAtlasManager);
+        op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, glyphCount,
+                                       info.hasScaledGlyphs(), restrictedAtlasManager);
     }
     GrAtlasTextOp::Geometry& geometry = op->geometry();
     geometry.fViewMatrix = viewMatrix;
@@ -355,9 +356,10 @@
             SkRect rtBounds = SkRect::MakeWH(target->width(), target->height());
             SkRRect clipRRect;
             GrAA aa;
-            // We can clip geometrically if we're not using SDFs,
+            // We can clip geometrically if we're not using SDFs or scaled glyphs,
             // and we have an axis-aligned rectangular non-AA clip
-            if (!info.drawAsDistanceFields() && clip.isRRect(rtBounds, &clipRRect, &aa) &&
+            if (!info.drawAsDistanceFields() && !info.hasScaledGlyphs() &&
+                clip.isRRect(rtBounds, &clipRRect, &aa) &&
                 clipRRect.isRect() && GrAA::kNo == aa) {
                 skipClip = true;
                 // We only need to do clipping work if the subrun isn't contained by the clip
diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h
index 52771c7..b4a11a4 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -435,13 +435,19 @@
                 fFlags  = hasW ? (fFlags | kHasWCoord_Flag) : fFlags & ~kHasWCoord_Flag;
             }
             bool hasWCoord() const { return SkToBool(fFlags & kHasWCoord_Flag); }
+            void setHasScaledGlyphs(bool hasScaledGlyphs) {
+                fFlags  = hasScaledGlyphs ? (fFlags | kHasScaledGlyphs_Flag)
+                                          : fFlags & ~kHasScaledGlyphs_Flag;
+            }
+            bool hasScaledGlyphs() const { return SkToBool(fFlags & kHasScaledGlyphs_Flag); }
 
         private:
             enum Flag {
-                kDrawAsSDF_Flag = 0x1,
-                kUseLCDText_Flag = 0x2,
-                kAntiAliased_Flag = 0x4,
-                kHasWCoord_Flag = 0x8
+                kDrawAsSDF_Flag = 0x01,
+                kUseLCDText_Flag = 0x02,
+                kAntiAliased_Flag = 0x04,
+                kHasWCoord_Flag = 0x08,
+                kHasScaledGlyphs_Flag = 0x10
             };
 
             GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
diff --git a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
index f574d6f..296df22 100644
--- a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
+++ b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
@@ -280,7 +280,8 @@
             if (!fFullAtlasManager->hasGlyph(glyph) &&
                 !strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache,
                                          fFullAtlasManager, glyph,
-                                         fLazyCache->get(), fSubRun->maskFormat())) {
+                                         fLazyCache->get(), fSubRun->maskFormat(),
+                                         fSubRun->hasScaledGlyphs())) {
                 fBrokenRun = glyphIdx > 0;
                 result.fFinished = false;
                 return result;
diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp
index 5ac683e..4a10e10 100644
--- a/src/gpu/text/GrAtlasTextContext.cpp
+++ b/src/gpu/text/GrAtlasTextContext.cpp
@@ -856,6 +856,7 @@
         SkScalar scaledGlyphSize = maxDim * fMaxScale;
         if (!fViewMatrix.hasPerspective() && scaledGlyphSize > fMaxTextSize) {
             fUseScaledFallback = true;
+            fMaxTextSize -= 2;    // Subtract 2 to account for the bilerp pad around the glyph
         }
     }
 
diff --git a/src/gpu/text/GrGlyphCache.cpp b/src/gpu/text/GrGlyphCache.cpp
index 7d89907..2372af8 100644
--- a/src/gpu/text/GrGlyphCache.cpp
+++ b/src/gpu/text/GrGlyphCache.cpp
@@ -298,35 +298,57 @@
                                    GrAtlasManager* fullAtlasManager,
                                    GrGlyph* glyph,
                                    SkGlyphCache* cache,
-                                   GrMaskFormat expectedMaskFormat) {
+                                   GrMaskFormat expectedMaskFormat,
+                                   bool isScaledGlyph) {
     SkASSERT(glyph);
     SkASSERT(cache);
     SkASSERT(fCache.find(glyph->fPackedID));
 
     int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
+    int width = glyph->width();
+    int height = glyph->height();
+    int rowBytes = width * bytesPerPixel;
 
     size_t size = glyph->fBounds.area() * bytesPerPixel;
+    bool isSDFGlyph = GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID);
+    bool addPad = isScaledGlyph && !isSDFGlyph;
+    if (addPad) {
+        width += 2;
+        rowBytes += 2*bytesPerPixel;
+        size += 2 * rowBytes;
+        height += 2;
+        size += 2 * (height + 2) * bytesPerPixel;
+    }
     SkAutoSMalloc<1024> storage(size);
 
     const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
-    if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) {
-        if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(),
+    if (isSDFGlyph) {
+        if (!get_packed_glyph_df_image(cache, skGlyph, width, height,
                                        storage.get())) {
             return false;
         }
     } else {
+        void* dataPtr = storage.get();
+        if (addPad) {
+            sk_bzero(dataPtr, size);
+            dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
+        }
         if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
-                                    glyph->width() * bytesPerPixel, expectedMaskFormat,
-                                    storage.get())) {
+                                    rowBytes, expectedMaskFormat,
+                                    dataPtr)) {
             return false;
         }
     }
 
     bool success = fullAtlasManager->addToAtlas(resourceProvider, glyphCache, this,
                                                 &glyph->fID, target, expectedMaskFormat,
-                                                glyph->width(), glyph->height(),
+                                                width, height,
                                                 storage.get(), &glyph->fAtlasLocation);
     if (success) {
+        if (addPad) {
+            glyph->fAtlasLocation.fX += 1;
+            glyph->fAtlasLocation.fY += 1;
+        }
         SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
         fAtlasedGlyphs++;
     }
diff --git a/src/gpu/text/GrGlyphCache.h b/src/gpu/text/GrGlyphCache.h
index 8279814..7e6056e 100644
--- a/src/gpu/text/GrGlyphCache.h
+++ b/src/gpu/text/GrGlyphCache.h
@@ -65,7 +65,7 @@
     // get the actual glyph image itself when we get the glyph metrics.
     bool addGlyphToAtlas(GrResourceProvider*, GrDeferredUploadTarget*, GrGlyphCache*,
                          GrAtlasManager*, GrGlyph*,
-                         SkGlyphCache*, GrMaskFormat expectedMaskFormat);
+                         SkGlyphCache*, GrMaskFormat expectedMaskFormat, bool isScaledGlyph);
 
     // testing
     int countGlyphs() const { return fCache.count(); }