Duplicate drawDFPosText into drawDFGlyphRun

This CL has duplicate code, but this should be a small CL to
judge how glyphRuns will change the code.

Change-Id: Ib4700aa9d19ae3811090796a2c59bbe746361202
Reviewed-on: https://skia-review.googlesource.com/144022
Auto-Submit: Herb Derby <herb@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h
index 1456e6c..fc85c3e 100644
--- a/src/core/SkGlyphRun.h
+++ b/src/core/SkGlyphRun.h
@@ -209,6 +209,7 @@
     const uint32_t* clusters() const { return fList[fIndex].clusters().data(); }
     uint32_t textSize() const { return fList[fIndex].text().size(); }
     const char* text() const { return fList[fIndex].text().data(); }
+    const SkGlyphRun& glyphRun() const { return fList[fIndex]; }
 
     bool isLCD() const { return fList[fIndex].paint().isLCDRenderText(); }
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 39704e5..0686d61 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1628,6 +1628,8 @@
 void SkGpuDevice::drawPosText(const void* text, size_t byteLength,
                               const SkScalar pos[], int scalarsPerPos,
                               const SkPoint& offset, const SkPaint& paint) {
+
+    SK_ABORT("Oh no!!! There is not drawPosText for GPU device anymore!");
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext.get());
     SkDEBUGCODE(this->validate();)
diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp
index d57055a..4631991 100644
--- a/src/gpu/text/GrTextContext.cpp
+++ b/src/gpu/text/GrTextContext.cpp
@@ -196,12 +196,10 @@
         }
         cacheBlob->setRunPaintFlags(run, runPaint.skPaint().getFlags());
 
-        SkASSERT(it.positioning() == SkTextBlobRunIterator::kFull_Positioning);
         if (CanDrawAsDistanceFields(runPaint, viewMatrix, props,
                                     shaderCaps.supportsDistanceFieldText(), fOptions)) {
-            this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
-                                scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
-                                textLen, it.pos(), 2, origin);
+            this->drawDFGlyphRun(cacheBlob, run, glyphCache, props, runPaint,
+                                scalerContextFlags, viewMatrix, it.glyphRun(), origin);
         } else {
             DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
                            viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2,
@@ -577,6 +575,50 @@
     fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, paint, scalerContextFlags);
 }
 
+void GrTextContext::drawDFGlyphRun(GrTextBlob* blob, int runIndex,
+                                  GrGlyphCache* glyphCache, const SkSurfaceProps& props,
+                                  const GrTextUtils::Paint& paint,
+                                  SkScalerContextFlags scalerContextFlags,
+                                  const SkMatrix& viewMatrix, const SkGlyphRun& glyphRun,
+                                  const SkPoint& offset) const {
+    bool hasWCoord = viewMatrix.hasPerspective() || fOptions.fDistanceFieldVerticesAlwaysHaveW;
+
+    // Setup distance field paint and text ratio
+    SkScalar textRatio;
+    SkPaint dfPaint(paint);
+    SkScalerContextFlags flags;
+    InitDistanceFieldPaint(blob, &dfPaint, viewMatrix, fOptions, &textRatio, &flags);
+    blob->setHasDistanceField();
+    blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText(),
+                                     paint.skPaint().isAntiAlias(), hasWCoord);
+
+    FallbackGlyphRunHelper fallbackTextHelper(viewMatrix, paint, glyphCache->getGlyphSizeLimit(),
+                                          textRatio);
+
+    sk_sp<GrTextStrike> currStrike;
+
+    {
+        auto cache = blob->setupCache(runIndex, props, flags, dfPaint, nullptr);
+
+        const SkPoint* positionCursor = glyphRun.positions().data();
+        for (auto glyphID : glyphRun.shuntGlyphsIDs()) {
+            const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphID);
+            SkPoint glyphPos = offset + *positionCursor++;
+            if (glyph.fWidth > 0) {
+                if (glyph.fMaskFormat == SkMask::kSDF_Format) {
+                    DfAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, glyphPos.fX,
+                                  glyphPos.fY, paint.filteredPremulColor(), cache.get(), textRatio);
+                } else {
+                    // can't append non-SDF glyph to SDF batch, send to fallback
+                    fallbackTextHelper.appendText(glyph, glyphID, glyphPos);
+                }
+            }
+        }
+    }
+
+    fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, paint, scalerContextFlags);
+}
+
 // TODO: merge with BmpAppendGlyph
 void GrTextContext::DfAppendGlyph(GrTextBlob* blob, int runIndex,
                                   GrGlyphCache* grGlyphCache, sk_sp<GrTextStrike>* strike,
@@ -689,6 +731,77 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+void GrTextContext::FallbackGlyphRunHelper::appendText(
+        const SkGlyph& glyph, SkGlyphID glyphID, SkPoint glyphPos) {
+    SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*fTextRatio;
+    if (SkScalarNearlyZero(maxDim)) return;
+
+    if (!fUseTransformedFallback) {
+        if (!fViewMatrix.isScaleTranslate() || maxDim*fMaxScale > fMaxTextSize) {
+            fUseTransformedFallback = true;
+            fMaxTextSize -= 2;    // Subtract 2 to account for the bilerp pad around the glyph
+        }
+    }
+
+    fFallbackTxt.push_back(glyphID);
+    if (fUseTransformedFallback) {
+        // If there's a glyph in the font that's particularly large, it's possible
+        // that fScaledFallbackTextSize may end up minimizing too much. We'd rather skip
+        // that glyph than make the others blurry, so we set a minimum size of half the
+        // maximum text size to avoid this case.
+        SkScalar glyphTextSize =
+                SkTMax(SkScalarFloorToScalar(fTextSize * fMaxTextSize/maxDim), 0.5f*fMaxTextSize);
+        fTransformedFallbackTextSize = SkTMin(glyphTextSize, fTransformedFallbackTextSize);
+    }
+    fFallbackPos.push_back(glyphPos);
+}
+
+void GrTextContext::FallbackGlyphRunHelper::drawText(
+        GrTextBlob* blob, int runIndex, GrGlyphCache* glyphCache, const SkSurfaceProps& props,
+        const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags) {
+    if (!fFallbackTxt.empty()) {
+        blob->initOverride(runIndex);
+        blob->setHasBitmap();
+        blob->setSubRunHasW(runIndex, fViewMatrix.hasPerspective());
+        const SkPaint& skPaint = paint.skPaint();
+        SkColor textColor = paint.filteredPremulColor();
+
+        SkScalar textRatio = SK_Scalar1;
+        SkPaint fallbackPaint(skPaint);
+        SkMatrix matrix = fViewMatrix;
+        this->initializeForDraw(&fallbackPaint, &textRatio, &matrix);
+        SkExclusiveStrikePtr cache =
+                blob->setupCache(runIndex, props, scalerContextFlags, fallbackPaint, &matrix);
+
+        sk_sp<GrTextStrike> currStrike;
+        auto glyphPos = fFallbackPos.begin();
+        for (auto glyphID : fFallbackTxt) {
+            const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphID);
+            if (!fUseTransformedFallback) {
+                fViewMatrix.mapPoints(&*glyphPos, 1);
+                glyphPos->fX = SkScalarFloorToScalar(glyphPos->fX);
+                glyphPos->fY = SkScalarFloorToScalar(glyphPos->fY);
+            }
+            GrTextContext::BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph,
+                                          glyphPos->fX, glyphPos->fY, textColor,
+                                          cache.get(), textRatio, fUseTransformedFallback);
+            glyphPos++;
+        }
+    }
+}
+
+void GrTextContext::FallbackGlyphRunHelper::initializeForDraw(
+        SkPaint* paint, SkScalar* textRatio, SkMatrix* matrix) const {
+    if (!fUseTransformedFallback) return;
+
+    paint->setTextSize(fTransformedFallbackTextSize);
+    *textRatio = fTextSize / fTransformedFallbackTextSize;
+    *matrix = SkMatrix::I();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
 #if GR_TEST_UTILS
 
 #include "GrRenderTargetContext.h"
diff --git a/src/gpu/text/GrTextContext.h b/src/gpu/text/GrTextContext.h
index 0093f84..7c8c576 100644
--- a/src/gpu/text/GrTextContext.h
+++ b/src/gpu/text/GrTextContext.h
@@ -107,6 +107,41 @@
         bool fUseTransformedFallback;
     };
 
+    class FallbackGlyphRunHelper {
+    public:
+        FallbackGlyphRunHelper(const SkMatrix& viewMatrix,
+                           const SkPaint& pathPaint,
+                           SkScalar maxTextSize,
+                           SkScalar textRatio)
+                : fViewMatrix(viewMatrix)
+                , fTextSize(pathPaint.getTextSize())
+                , fMaxTextSize(maxTextSize)
+                , fTextRatio(textRatio)
+                , fTransformedFallbackTextSize(fMaxTextSize)
+                , fUseTransformedFallback(false) {
+            fMaxScale = viewMatrix.getMaxScale();
+        }
+
+        void appendText(const SkGlyph& glyph, SkGlyphID, SkPoint glyphPos);
+        void drawText(GrTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&,
+                      const GrTextUtils::Paint&, SkScalerContextFlags);
+
+        void initializeForDraw(SkPaint* paint, SkScalar* textRatio, SkMatrix* matrix) const;
+        const std::vector<SkGlyphID>& fallbackText() const { return fFallbackTxt; }
+
+    private:
+        std::vector<SkGlyphID> fFallbackTxt;
+        std::vector<SkPoint> fFallbackPos;
+
+        const SkMatrix& fViewMatrix;
+        SkScalar fTextSize;
+        SkScalar fMaxTextSize;
+        SkScalar fTextRatio;
+        SkScalar fTransformedFallbackTextSize;
+        SkScalar fMaxScale;
+        bool fUseTransformedFallback;
+    };
+
 private:
     GrTextContext(const Options& options);
 
@@ -158,6 +193,12 @@
                        size_t byteLength, const SkScalar pos[], int scalarsPerPosition,
                        const SkPoint& offset) const;
 
+    void drawDFGlyphRun(GrTextBlob* blob, int runIndex, GrGlyphCache*,
+                       const SkSurfaceProps&, const GrTextUtils::Paint& paint,
+                       SkScalerContextFlags scalerContextFlags,
+                       const SkMatrix& viewMatrix, const SkGlyphRun& glyphRun,
+                       const SkPoint& offset) const;
+
     static void BmpAppendGlyph(GrTextBlob*, int runIndex, GrGlyphCache*,
                                sk_sp<GrTextStrike>*, const SkGlyph&, SkScalar sx, SkScalar sy,
                                GrColor color, SkGlyphCache*, SkScalar textRatio, bool needsXform);