Optimize GPU text regen for full pixel position text

If the GrTextBlob does not contain any subpixel position text,
then any translation is ok. This is because all positions and
SkGlyphCache entries will be aligned to pixel boundaries.

Change-Id: Ie2bfd72710295b98c65052a857b6bd33a4858b65
Reviewed-on: https://skia-review.googlesource.com/c/162860
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp
index 3189743..9ae21c0 100644
--- a/src/core/SkGlyphRun.cpp
+++ b/src/core/SkGlyphRun.cpp
@@ -104,6 +104,15 @@
     return false;
 }
 
+bool SkGlyphRunList::anyRunsSubpixelPositioned() const {
+    for (const auto& r : fGlyphRuns) {
+        if (r.paint().isSubpixelText()) {
+            return true;
+        }
+    }
+    return false;
+}
+
 void SkGlyphRunList::temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const {
     SkASSERT(fOriginalTextBlob != nullptr);
     fOriginalTextBlob->notifyAddedToCache(cacheID);
diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h
index 3f7c26e..2d0d345 100644
--- a/src/core/SkGlyphRun.h
+++ b/src/core/SkGlyphRun.h
@@ -151,6 +151,7 @@
 
     uint64_t uniqueID() const;
     bool anyRunsLCD() const;
+    bool anyRunsSubpixelPositioned() const;
     void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const;
 
     bool canCache() const { return fOriginalTextBlob != nullptr; }
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp
index 1d4d7da..cfaafe3 100644
--- a/src/core/SkGlyphRunPainter.cpp
+++ b/src/core/SkGlyphRunPainter.cpp
@@ -388,7 +388,8 @@
     }
 
     if (cacheBlob) {
-        if (cacheBlob->mustRegenerate(listPaint, blurRec, viewMatrix, origin.x(), origin.y())) {
+        if (cacheBlob->mustRegenerate(listPaint, glyphRunList.anyRunsSubpixelPositioned(),
+                                      blurRec, viewMatrix, origin.x(),origin.y())) {
             // We have to remake the blob because changes may invalidate our masks.
             // TODO we could probably get away reuse most of the time if the pointer is unique,
             // but we'd have to clear the subrun information
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index 659a545..6249c3a 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -144,9 +144,9 @@
     run.fPathGlyphs.push_back(GrTextBlob::Run::PathGlyph(path, x, y, scale, preTransformed));
 }
 
-bool GrTextBlob::mustRegenerate(const SkPaint& paint,
-                                     const SkMaskFilterBase::BlurRec& blurRec,
-                                     const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
+bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosition,
+                                const SkMaskFilterBase::BlurRec& blurRec,
+                                const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
     // If we have LCD text then our canonical color will be set to transparent, in this case we have
     // to regenerate the blob on any color change
     // We use the grPaint to get any color filter effects
@@ -196,20 +196,22 @@
             return true;
         }
 
-        // We can update the positions in the cachedtextblobs without regenerating the whole blob,
-        // but only for integer translations.
-        // This cool bit of math will determine the necessary translation to apply to the already
-        // generated vertex coordinates to move them to the correct position
-        SkScalar transX = viewMatrix.getTranslateX() +
-                          viewMatrix.getScaleX() * (x - fInitialX) +
-                          viewMatrix.getSkewX() * (y - fInitialY) -
-                          fInitialViewMatrix.getTranslateX();
-        SkScalar transY = viewMatrix.getTranslateY() +
-                          viewMatrix.getSkewY() * (x - fInitialX) +
-                          viewMatrix.getScaleY() * (y - fInitialY) -
-                          fInitialViewMatrix.getTranslateY();
-        if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY)) {
-            return true;
+        if (!anyRunHasSubpixelPosition) {
+            // We can update the positions in the cachedtextblobs without regenerating the whole
+            // blob, but only for integer translations.
+            // This cool bit of math will determine the necessary translation to apply to the
+            // already generated vertex coordinates to move them to the correct position.
+            SkScalar transX = viewMatrix.getTranslateX() +
+                              viewMatrix.getScaleX() * (x - fInitialX) +
+                              viewMatrix.getSkewX() * (y - fInitialY) -
+                              fInitialViewMatrix.getTranslateX();
+            SkScalar transY = viewMatrix.getTranslateY() +
+                              viewMatrix.getSkewY() * (x - fInitialX) +
+                              viewMatrix.getScaleY() * (y - fInitialY) -
+                              fInitialViewMatrix.getTranslateY();
+            if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY)) {
+                return true;
+            }
         }
     } else if (this->hasDistanceField()) {
         // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different
diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h
index f8a4565..234039f 100644
--- a/src/gpu/text/GrTextBlob.h
+++ b/src/gpu/text/GrTextBlob.h
@@ -196,7 +196,7 @@
         }
     }
 
-    bool mustRegenerate(const SkPaint&, const SkMaskFilterBase::BlurRec& blurRec,
+    bool mustRegenerate(const SkPaint&, bool, const SkMaskFilterBase::BlurRec& blurRec,
                         const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
 
     void flush(GrTextTarget*, const SkSurfaceProps& props,