Redo GrTextBlob path flush

Change-Id: I4cd27b5367983d70d5c18383e21ae918b0dd8f45
Reviewed-on: https://skia-review.googlesource.com/156981
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index 3e6b327..659a545 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -290,54 +290,88 @@
     // GrTextBlob::makeOp only takes uint16_t values for run and subRun indices.
     // Encountering something larger than this is highly unlikely, so we'll just not draw it.
     int lastRun = SkTMin(fRunCount, (1 << 16)) - 1;
-    SkPaint runPaint{paint};
+    // For each run in the GrTextBlob we're going to churn through all the glyphs.
+    // Each run is broken into a path part and a Mask / DFT / ARGB part.
     for (int runIndex = 0; runIndex <= lastRun; runIndex++) {
+
         Run& run = fRuns[runIndex];
 
         // first flush any path glyphs
         if (run.fPathGlyphs.count()) {
-            SkScalar transX, transY;
-            uint16_t paintFlags = run.fPaintFlags;
-            runPaint.setFlags((runPaint.getFlags() & ~Run::kPaintFlagsMask) | paintFlags);
+            SkPaint runPaint{paint};
+            runPaint.setFlags((runPaint.getFlags() & ~Run::kPaintFlagsMask) | run.fPaintFlags);
 
             for (int i = 0; i < run.fPathGlyphs.count(); i++) {
                 GrTextBlob::Run::PathGlyph& pathGlyph = run.fPathGlyphs[i];
-                calculate_translation(pathGlyph.fPreTransformed, viewMatrix, x, y,
-                                      fInitialViewMatrix, fInitialX, fInitialY, &transX, &transY);
 
-                const SkMatrix* ctm = pathGlyph.fPreTransformed ? &SkMatrix::I() : &viewMatrix;
-                SkMatrix pathMatrix;
-                pathMatrix.setScale(pathGlyph.fScale, pathGlyph.fScale);
-                pathMatrix.postTranslate(pathGlyph.fX + transX, pathGlyph.fY + transY);
-
+                SkMatrix ctm;
                 const SkPath* path = &pathGlyph.fPath;
+
+                // TmpPath must be in the same scope as GrShape shape below.
                 SkTLazy<SkPath> tmpPath;
 
-                GrStyle style(runPaint);
+                // The glyph positions and glyph outlines are either in device space or in source
+                // space based on fPreTransformed.
+                if (!pathGlyph.fPreTransformed) {
+                    // Positions and outlines are in source space.
 
-                SkMaskFilter* mf = runPaint.getMaskFilter();
+                    ctm = viewMatrix;
 
-                // Styling, blurs, and shading are supposed to be applied *after* the pathMatrix.
-                // However, if the mask filter is a blur and the pathMatrix contains no scale, then
-                // we can still fold the path matrix into the CTM
-                bool needToApply = runPaint.getShader() || style.applies() ||
-                                   (mf && (!as_MFB(mf)->asABlur(nullptr) ||
-                                           !SkScalarNearlyEqual(pathGlyph.fScale, 1.0f)));
+                    SkMatrix pathMatrix = SkMatrix::MakeScale(pathGlyph.fScale, pathGlyph.fScale);
 
-                if (needToApply) {
-                    SkPath* result = tmpPath.init();
-                    path->transform(pathMatrix, result);
-                    result->setIsVolatile(true);
-                    path = result;
+                    // The origin for the blob may have changed, so figure out the delta.
+                    SkVector originShift = SkPoint{x, y} - SkPoint{fInitialX, fInitialY};
+
+                    // Shift the original glyph location in source space to the position of the new
+                    // blob.
+                    pathMatrix.postTranslate(originShift.x() + pathGlyph.fX,
+                                             originShift.y() + pathGlyph.fY);
+
+                    // If there are shaders, blurs or styles, the path must be scaled into source
+                    // space independently of the CTM. This allows the CTM to be correct for the
+                    // different effects.
+                    GrStyle style(runPaint);
+                    bool scalePath = runPaint.getShader()
+                                     || style.applies()
+                                     || runPaint.getMaskFilter();
+                    if (!scalePath) {
+                        // Scale can be applied to CTM -- no effects.
+
+                        ctm.preConcat(pathMatrix);
+                    } else {
+                        // Scale the outline into source space.
+
+                        // Transform the path form the normalized outline to source space. This
+                        // way the CTM will remain the same so it can be used by the effects.
+                        SkPath* sourceOutline = tmpPath.init();
+                        path->transform(pathMatrix, sourceOutline);
+                        sourceOutline->setIsVolatile(true);
+                        path = sourceOutline;
+                    }
+
+
                 } else {
-                    pathMatrix.postConcat(*ctm);
-                    ctm = &pathMatrix;
+                    // Positions and outlines are in device space.
+
+                    SkPoint originalOrigin = {fInitialX, fInitialY};
+                    fInitialViewMatrix.mapPoints(&originalOrigin, 1);
+
+                    SkPoint newOrigin = {x, y};
+                    viewMatrix.mapPoints(&newOrigin, 1);
+
+                    // The origin shift in device space.
+                    SkPoint originShift = newOrigin - originalOrigin;
+
+                    // Shift the original glyph location in device space to the position of the
+                    // new blob.
+                    ctm = SkMatrix::MakeTrans(originShift.x() + pathGlyph.fX,
+                                              originShift.y() + pathGlyph.fY);
                 }
 
                 // TODO: we are losing the mutability of the path here
                 GrShape shape(*path, paint);
 
-                target->drawShape(clip, runPaint, *ctm, shape);
+                target->drawShape(clip, runPaint, ctm, shape);
             }
         }
 
@@ -345,6 +379,7 @@
         if (!run.fInitialized) {
             continue;
         }
+
         int lastSubRun = SkTMin(run.fSubRunInfo.count(), 1 << 16) - 1;
         for (int subRun = 0; subRun <= lastSubRun; subRun++) {
             const Run::SubRunInfo& info = run.fSubRunInfo[subRun];