Clean up bitmap path

Change-Id: If149194fd86f14bea289ad68262ea99cbbc398b6
Reviewed-on: https://skia-review.googlesource.com/142817
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index cb169dc..94a4ddc 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -572,7 +572,7 @@
 }
 
 void SkBitmapDevice::drawGlyphRunList(SkGlyphRunList* glyphRunList) {
-#ifdef SK_SUPPORT_LEGACY_TEXT_BLOB
+#if defined(SK_SUPPORT_LEGACY_TEXT_BLOB)
     auto blob = glyphRunList->blob();
 
     if (blob == nullptr) {
@@ -583,7 +583,8 @@
         this->drawTextBlob(blob, origin.x(), origin.y(), paint);
     }
 #else
-    glyphRunList->temporaryShuntToDrawPosText(this, glyphRunList->origin());
+    SkBitmapDeviceFilteredSurfaceProps props(fBitmap, glyphRunList->paint(), fSurfaceProps);
+    LOOP_TILER( drawGlyphRunList(glyphRunList, &props()), nullptr )
 #endif
 }
 
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h
index 890f7e1..379d42d 100644
--- a/src/core/SkBitmapDevice.h
+++ b/src/core/SkBitmapDevice.h
@@ -112,7 +112,6 @@
      */
     void drawPosText(const void* text, size_t len, const SkScalar pos[],
                      int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override;
-
     void drawGlyphRunList(SkGlyphRunList* glyphRunList) override;
     void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
                       const SkPaint& paint) override;
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index ae1a873..4c9dddf 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -1598,6 +1598,140 @@
         offset, *fMatrix, pos, scalarsPerPosition, cache.get(), drawOneGlyph);
 }
 
+void SkDraw::drawGlyphRunAsPaths(
+        SkGlyphRun* glyphRun, SkPoint origin, const SkSurfaceProps* props) const {
+    // setup our std paint, in hopes of getting hits in the cache
+    const SkPaint& origPaint = glyphRun->paint();
+    SkPaint paint(glyphRun->paint());
+    SkScalar matrixScale = paint.setupForAsPaths();
+
+    SkMatrix matrix;
+    matrix.setScale(matrixScale, matrixScale);
+
+    // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
+    paint.setStyle(SkPaint::kFill_Style);
+    paint.setPathEffect(nullptr);
+
+    auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(
+            paint, props, this->scalerContextFlags(), nullptr);
+
+    // Now restore the original settings, so we "draw" with whatever style/stroking.
+    paint.setStyle(origPaint.getStyle());
+    paint.setPathEffect(origPaint.refPathEffect());
+
+    auto eachGlyph = [this, origin, &cache, &matrix, &paint](SkGlyphID glyphID, SkPoint position) {
+        const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphID);
+        if (glyph.fWidth > 0) {
+            const SkPath* path = cache->findPath(glyph);
+            if (path != nullptr) {
+                SkPoint loc = position + origin;
+                matrix[SkMatrix::kMTransX] = loc.fX;
+                matrix[SkMatrix::kMTransY] = loc.fY;
+                this->drawPath(*path, paint, &matrix, false);
+            }
+        }
+    };
+    glyphRun->forEachGlyphAndPosition(eachGlyph);
+}
+
+void SkDraw::drawGlyphRunAsSubpixelMask(
+        SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const {
+
+    SkMatrix matrix = *fMatrix;
+    // Add rounding and origin.
+    SkAxisAlignment axisAlignment = cache->getScalerContext()->computeAxisAlignmentForHText();
+    SkPoint rounding = SkFindAndPlaceGlyph::SubpixelPositionRounding(axisAlignment);
+    matrix.preTranslate(origin.x(), origin.y());
+    matrix.postTranslate(rounding.x(), rounding.y());
+
+    glyphRun->mapPositions(matrix);
+
+    auto paint = glyphRun->paint();
+    // The Blitter Choose needs to be live while using the blitter below.
+    SkAutoBlitterChoose    blitterChooser(*this, nullptr, paint);
+    SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
+    DrawOneGlyph           drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
+
+    auto eachGlyph = [cache, &drawOneGlyph, axisAlignment](SkGlyphID glyphID, SkPoint position) {
+        auto subpixelAlignment = [](SkAxisAlignment axisAlignment, SkPoint position) -> SkIPoint {
+
+            if (!SkScalarsAreFinite(position.fX, position.fY)) {
+                return {0, 0};
+            }
+
+            // Only the fractional part of position.fX and position.fY matter, because the result of
+            // this function will just be passed to FixedToSub.
+            switch (axisAlignment) {
+                case kX_SkAxisAlignment:
+                    return {SkScalarToFixed(SkScalarFraction(position.fX)), 0};
+                case kY_SkAxisAlignment:
+                    return {0, SkScalarToFixed(SkScalarFraction(position.fY))};
+                case kNone_SkAxisAlignment:
+                    return {SkScalarToFixed(SkScalarFraction(position.fX)),
+                            SkScalarToFixed(SkScalarFraction(position.fY))};
+            }
+            SK_ABORT("Should not get here.");
+            return {0, 0};
+        };
+
+        SkIPoint lookupPosition = subpixelAlignment(axisAlignment, position);
+        const SkGlyph& glyph = cache->getGlyphIDMetrics(
+                glyphID, lookupPosition.x(), lookupPosition.y());
+        if (glyph.fWidth > 0) {
+            drawOneGlyph(glyph, position, SkPoint::Make(0, 0));
+        }
+    };
+    glyphRun->forEachGlyphAndPosition(eachGlyph);
+}
+
+void SkDraw::drawGlyphRunAsFullpixelMask(
+        SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const {
+    SkMatrix matrix = *fMatrix;
+    // Add rounding and origin.
+    matrix.preTranslate(origin.x(), origin.y());
+    matrix.postTranslate(SK_ScalarHalf, SK_ScalarHalf);
+    glyphRun->mapPositions(matrix);
+
+    auto paint = glyphRun->paint();
+    // The Blitter Choose needs to be live while using the blitter below.
+    SkAutoBlitterChoose    blitterChooser(*this, nullptr, paint);
+    SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
+    DrawOneGlyph           drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
+
+    auto eachGlyph = [cache, &drawOneGlyph](SkGlyphID glyphID, SkPoint position) {
+        const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphID);
+        if (glyph.fWidth > 0) {
+            drawOneGlyph(glyph, position, SkPoint::Make(0, 0));
+        }
+    };
+    glyphRun->forEachGlyphAndPosition(eachGlyph);
+}
+
+void SkDraw::drawGlyphRunList(SkGlyphRunList* glyphRunList, const SkSurfaceProps* props) const {
+
+    SkDEBUGCODE(this->validate();)
+
+    if (fRC->isEmpty()) {
+        return;
+    }
+
+    SkPoint origin = glyphRunList->origin();
+    for (auto& glyphRun : *glyphRunList) {
+        if (ShouldDrawTextAsPaths(glyphRun.paint(), *fMatrix)) {
+            this->drawGlyphRunAsPaths(&glyphRun, origin, props);
+        } else {
+            auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(
+                    glyphRun.paint(), props, this->scalerContextFlags(), fMatrix);
+            if (cache->isSubpixel()) {
+                this->drawGlyphRunAsSubpixelMask(cache.get(), &glyphRun, origin);
+            } else {
+                this->drawGlyphRunAsFullpixelMask(cache.get(), &glyphRun, origin);
+            }
+        }
+    }
+
+}
+
 #if defined _WIN32
 #pragma warning ( pop )
 #endif
diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h
index afd50ea..deb7451 100644
--- a/src/core/SkDraw.h
+++ b/src/core/SkDraw.h
@@ -22,6 +22,8 @@
 class SkClipStack;
 class SkBaseDevice;
 class SkBlitter;
+class SkGlyphRun;
+class SkGlyphRunList;
 class SkMatrix;
 class SkPath;
 class SkRegion;
@@ -65,6 +67,16 @@
     void    drawPosText(const char text[], size_t byteLength,
                         const SkScalar pos[], int scalarsPerPosition,
                         const SkPoint& offset, const SkPaint&, const SkSurfaceProps*) const;
+
+    void drawGlyphRunAsPaths(
+            SkGlyphRun* glyphRun, SkPoint origin, const SkSurfaceProps* props) const;
+
+    void drawGlyphRunAsSubpixelMask(
+            SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const;
+
+    void drawGlyphRunAsFullpixelMask(
+            SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const;
+    void    drawGlyphRunList(SkGlyphRunList* glyphRunList, const SkSurfaceProps*) const;
     void    drawVertices(SkVertices::VertexMode mode, int vertexCount,
                          const SkPoint vertices[], const SkPoint textures[],
                          const SkColor colors[], const SkVertices::BoneIndices boneIndices[],
diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp
index 82dae68..cfe63a8 100644
--- a/src/core/SkGlyphRun.cpp
+++ b/src/core/SkGlyphRun.cpp
@@ -16,6 +16,7 @@
 #include "SkGlyphCache.h"
 #include "SkMSAN.h"
 #include "SkMakeUnique.h"
+#include "SkMatrix.h"
 #include "SkPaint.h"
 #include "SkPaintPriv.h"
 #include "SkStrikeCache.h"
@@ -38,7 +39,7 @@
 // -- SkGlyphRun -----------------------------------------------------------------------------------
 SkGlyphRun::SkGlyphRun(SkPaint&& runPaint,
                        SkSpan<const uint16_t> denseIndices,
-                       SkSpan<const SkPoint> positions,
+                       SkSpan<SkPoint> positions,
                        SkSpan<const SkGlyphID> glyphIDs,
                        SkSpan<const SkGlyphID> uniqueGlyphIDs,
                        SkSpan<const char> text,
@@ -59,7 +60,7 @@
     SkGlyphRun run{
         std::move(paint),
         SkSpan<const uint16_t>{},  // No dense indices for now.
-        SkSpan<const SkPoint>{&point, 1},
+        SkSpan<SkPoint>{&point, 1},
         SkSpan<const SkGlyphID>{&glyphID, 1},
         SkSpan<const SkGlyphID>{},
         SkSpan<const char>{},
@@ -76,6 +77,11 @@
 
 }
 
+void SkGlyphRun::mapPositions(const SkMatrix& matrix) {
+    matrix.mapPoints(fPositions.data(), fPositions.data(), (int)fPositions.size());
+}
+
+
 void SkGlyphRun::temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin) {
 
     auto pos = (const SkScalar*) this->positions().data();
@@ -208,7 +214,7 @@
         this->initialize(glyphIDs.size());
     }
 
-    auto positions = SkSpan<const SkPoint>{fPositions, glyphIDs.size()};
+    auto positions = SkSpan<SkPoint>{fPositions, glyphIDs.size()};
 
     // Every glyph is at the origin.
     sk_bzero((void *)positions.data(), positions.size_bytes());
@@ -254,7 +260,8 @@
     auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength);
     if (!glyphIDs.empty()) {
         this->initialize(glyphIDs.size());
-        this->simplifyDrawPosText(paint, glyphIDs, pos, fUniqueGlyphIDIndices, fUniqueGlyphIDs);
+        this->simplifyDrawPosText(paint, glyphIDs, pos,
+                fUniqueGlyphIDIndices, fUniqueGlyphIDs, fPositions);
     }
 
     this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
@@ -310,7 +317,7 @@
             case SkTextBlob::kFull_Positioning:
                 uniqueGlyphIDsSize = this->simplifyDrawPosText(
                         runPaint, glyphIDs, (const SkPoint*)it.pos(),
-                        currentDenseIndices, currentUniqueGlyphIDs,
+                        currentDenseIndices, currentUniqueGlyphIDs, currentPositions,
                         text, clusters);
                 break;
             default:
@@ -384,7 +391,7 @@
 void SkGlyphRunBuilder::makeGlyphRun(
         const SkPaint& runPaint,
         SkSpan<const SkGlyphID> glyphIDs,
-        SkSpan<const SkPoint> positions,
+        SkSpan<SkPoint> positions,
         SkSpan<const uint16_t> uniqueGlyphIDIndices,
         SkSpan<const SkGlyphID> uniqueGlyphIDs,
         SkSpan<const char> text,
@@ -454,7 +461,7 @@
         this->makeGlyphRun(
                 paint,
                 glyphIDs,
-                SkSpan<const SkPoint>{positions, runSize},
+                SkSpan<SkPoint>{positions, runSize},
                 SkSpan<const uint16_t>{uniqueGlyphIDIndicesBuffer, runSize},
                 unqiueGlyphIDs,
                 text,
@@ -469,21 +476,35 @@
         const SkScalar* xpos, SkScalar constY,
         uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions,
         SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
+    auto runSize = glyphIDs.size();
 
     auto posCursor = positions;
     for (auto x : SkSpan<const SkScalar>{xpos, glyphIDs.size()}) {
         *posCursor++ = SkPoint::Make(x, constY);
     }
 
-    return this->simplifyDrawPosText(
-            paint, glyphIDs, positions,
-            uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer,
-            text, clusters);
+    // The dense indices are not used by the rest of the stack yet.
+    SkSpan<const SkGlyphID> uniqueGlyphIDs;
+    #ifdef SK_DEBUG
+        uniqueGlyphIDs = this->addDenseAndUnique(
+                paint, glyphIDs, uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer);
+    #endif
+
+    this->makeGlyphRun(
+            paint,
+            glyphIDs,
+            SkSpan<SkPoint>{positions, runSize},
+            SkSpan<const SkGlyphID>{uniqueGlyphIDIndicesBuffer, runSize},
+            uniqueGlyphIDs,
+            text,
+            clusters);
+
+    return uniqueGlyphIDs.size();
 }
 
 size_t SkGlyphRunBuilder::simplifyDrawPosText(
         const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos,
-        uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer,
+        uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions,
         SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
     auto runSize = glyphIDs.size();
 
@@ -494,12 +515,15 @@
                 paint, glyphIDs, uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer);
     #endif
 
+    memcpy(positions, pos, runSize * sizeof(SkPoint));
+
+
     // TODO: when using the unique glyph system have a guard that there are actually glyphs like
     // drawText above.
     this->makeGlyphRun(
             paint,
             glyphIDs,
-            SkSpan<const SkPoint>{pos, runSize},
+            SkSpan<SkPoint>{positions, runSize},
             SkSpan<const SkGlyphID>{uniqueGlyphIDIndicesBuffer, runSize},
             uniqueGlyphIDs,
             text,
diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h
index 0146b1d..f3b4ff3 100644
--- a/src/core/SkGlyphRun.h
+++ b/src/core/SkGlyphRun.h
@@ -41,6 +41,7 @@
     size_t size() const { return fSize; }
     bool empty() const { return fSize == 0; }
     size_t size_bytes() const { return fSize * sizeof(T); }
+    SkSpan<const T> toConst() const { return SkSpan<const T>{fPtr, fSize}; }
 
 private:
     T* fPtr;
@@ -52,7 +53,7 @@
     SkGlyphRun() = default;
     SkGlyphRun(SkPaint&& runPaint,
                SkSpan<const uint16_t> denseIndices,
-               SkSpan<const SkPoint> positions,
+               SkSpan<SkPoint> positions,
                SkSpan<const SkGlyphID> glyphIDs,
                SkSpan<const SkGlyphID> uniqueGlyphIDs,
                SkSpan<const char> text,
@@ -61,6 +62,13 @@
     // A function that turns an SkGlyphRun into an SkGlyphRun for each glyph.
     using PerGlyph = std::function<void (SkGlyphRun*, SkPaint*)>;
     void eachGlyphToGlyphRun(PerGlyph perGlyph);
+    void mapPositions(const SkMatrix& matrix);
+
+    // The following made a ~5% speed improvement over not using a template.
+    //using PerGlyphPos = std::function<void (SkGlyphID glyphID, SkPoint positions)>;
+    template <typename PerGlyphPos>
+    void forEachGlyphAndPosition(PerGlyphPos perGlyph) const;
+
 
     // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs
     // are developed.
@@ -70,7 +78,7 @@
     void filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions);
 
     size_t runSize() const { return fGlyphIDs.size(); }
-    SkSpan<const SkPoint> positions() const { return fPositions; }
+    SkSpan<const SkPoint> positions() const { return fPositions.toConst(); }
     SkSpan<const SkGlyphID> shuntGlyphsIDs() const { return fGlyphIDs; }
     const SkPaint& paint() const { return fRunPaint; }
     SkPaint* mutablePaint() { return &fRunPaint; }
@@ -81,7 +89,7 @@
     //
     const SkSpan<const uint16_t> fUniqueGlyphIDIndices;
     //
-    const SkSpan<const SkPoint> fPositions;
+    const SkSpan<SkPoint> fPositions;
     // This is temporary while converting from the old per glyph code to the bulk code.
     const SkSpan<const SkGlyphID> fGlyphIDs;
     // The unique glyphs from fGlyphIDs.
@@ -94,6 +102,14 @@
     SkPaint fRunPaint;
 };
 
+template <typename PerGlyphPos>
+inline void SkGlyphRun::forEachGlyphAndPosition(PerGlyphPos perGlyph) const {
+    SkPoint* ptCursor = fPositions.data();
+    for (auto glyphID : fGlyphIDs) {
+        perGlyph(glyphID, *ptCursor++);
+    }
+}
+
 class SkGlyphRunList {
     const SkPaint* fOriginalPaint{nullptr};  // This should be deleted soon.
     // The text blob is needed to hookup the call back that the SkTextBlob destructor calls. It
@@ -207,7 +223,7 @@
     void makeGlyphRun(
             const SkPaint& runPaint,
             SkSpan<const SkGlyphID> glyphIDs,
-            SkSpan<const SkPoint> positions,
+            SkSpan<SkPoint> positions,
             SkSpan<const uint16_t> uniqueGlyphIDIndices,
             SkSpan<const SkGlyphID> uniqueGlyphIDs,
             SkSpan<const char> text,
@@ -228,7 +244,7 @@
             SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
     size_t simplifyDrawPosText(
             const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos,
-            uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs,
+            uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions,
             SkSpan<const char> text = SkSpan<const char>{},
             SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
 
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index ab34f88..adbfdc7 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -489,12 +489,12 @@
     }
 }
 
-static SkGlyphRun make_run(size_t len, const SkGlyphID* glyphs, const SkPoint* pos,
+static SkGlyphRun make_run(size_t len, const SkGlyphID* glyphs, SkPoint* pos,
                            SkPaint paint, const uint32_t* clusters,
                            size_t utf8TextByteLength, const char* utf8Text) {
     return SkGlyphRun(std::move(paint),
                       SkSpan<const uint16_t>{},  // No dense indices for now.
-                      SkSpan<const SkPoint>{pos, len},
+                      SkSpan<SkPoint>{pos, len},
                       SkSpan<const SkGlyphID>{glyphs, len},
                       SkSpan<const SkGlyphID>{},
                       SkSpan<const char>{utf8Text, utf8TextByteLength},
@@ -508,7 +508,7 @@
         constexpr unsigned len = 11;
         const uint32_t clusters[len] = { 3, 2, 2, 1, 0, 4, 4, 7, 6, 6, 5 };
         const SkGlyphID glyphs[len] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
-        const SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
+        SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
                                   {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
         const char text[] = "abcdefgh";
         SkGlyphRun run = make_run(len, glyphs, pos, paint, clusters, strlen(text), text);
@@ -532,7 +532,7 @@
         constexpr unsigned len = 5;
         const uint32_t clusters[len] = { 0, 1, 4, 5, 6 };
         const SkGlyphID glyphs[len] = { 43, 167, 79, 79, 82, };
-        const SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
+        SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
         const char text[] = "Ha\xCC\x8A" "llo";
         SkGlyphRun run = make_run(len, glyphs, pos, paint, clusters, strlen(text), text);
         SkClusterator clusterator(run);