Change drawText() to generate positions and send to drawPosText()

The idea here is to have a central place that does layout for drawText(), and
then always feed text through drawPosText(). This both makes all of the
GrTextContexts consistent in drawText() output, and does a better job of
stressing drawPosText().

Because of the effect of matrices on hinting and approximation error, the
generated text is not 100% identical to that produced by the raster pipeline.

BUG=skia:2778

Review URL: https://codereview.chromium.org/653133004
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index fa70d32..a1196dc 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -16,7 +16,6 @@
 #include "GrTextStrike_impl.h"
 #include "effects/GrCustomCoordsTextureEffect.h"
 
-#include "SkAutoKern.h"
 #include "SkColorPriv.h"
 #include "SkDraw.h"
 #include "SkDrawProcs.h"
@@ -91,97 +90,6 @@
     fMaxVertices = 0;
 }
 
-void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
-                                   const char text[], size_t byteLength,
-                                   SkScalar x, SkScalar y) {
-    SkASSERT(byteLength == 0 || text != NULL);
-
-    // nothing to draw
-    if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
-        return;
-    }
-
-    this->init(paint, skPaint);
-
-    SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
-
-    SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
-    SkGlyphCache*       cache = autoCache.getCache();
-    GrFontScaler*       fontScaler = GetGrFontScaler(cache);
-
-    // transform our starting point
-    {
-        SkPoint loc;
-        fContext->getMatrix().mapXY(x, y, &loc);
-        x = loc.fX;
-        y = loc.fY;
-    }
-
-    // need to measure first
-    if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
-        SkVector    stop;
-
-        MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
-
-        SkScalar    stopX = stop.fX;
-        SkScalar    stopY = stop.fY;
-
-        if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
-            stopX = SkScalarHalf(stopX);
-            stopY = SkScalarHalf(stopY);
-        }
-        x -= stopX;
-        y -= stopY;
-    }
-
-    const char* stop = text + byteLength;
-
-    SkAutoKern autokern;
-
-    SkFixed fxMask = ~0;
-    SkFixed fyMask = ~0;
-    SkFixed halfSampleX, halfSampleY;
-    if (cache->isSubpixel()) {
-        halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
-        SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
-        if (kX_SkAxisAlignment == baseline) {
-            fyMask = 0;
-            halfSampleY = SK_FixedHalf;
-        } else if (kY_SkAxisAlignment == baseline) {
-            fxMask = 0;
-            halfSampleX = SK_FixedHalf;
-        }
-    } else {
-        halfSampleX = halfSampleY = SK_FixedHalf;
-    }
-
-    SkFixed fx = SkScalarToFixed(x) + halfSampleX;
-    SkFixed fy = SkScalarToFixed(y) + halfSampleY;
-
-    GrContext::AutoMatrix  autoMatrix;
-    autoMatrix.setIdentity(fContext, &fPaint);
-
-    while (text < stop) {
-        const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
-
-        fx += autokern.adjust(glyph);
-
-        if (glyph.fWidth) {
-            this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
-                                            glyph.getSubXFixed(),
-                                            glyph.getSubYFixed()),
-                              SkFixedFloorToFixed(fx),
-                              SkFixedFloorToFixed(fy),
-                              fontScaler);
-        }
-
-        fx += glyph.fAdvanceX;
-        fy += glyph.fAdvanceY;
-    }
-
-    this->finish();
-}
-
 void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
                                       const char text[], size_t byteLength,
                                       const SkScalar pos[], int scalarsPerPosition,
diff --git a/src/gpu/GrBitmapTextContext.h b/src/gpu/GrBitmapTextContext.h
index 7a93820..7a73b7b 100644
--- a/src/gpu/GrBitmapTextContext.h
+++ b/src/gpu/GrBitmapTextContext.h
@@ -45,8 +45,6 @@
 
     virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
 
-    virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
-                            SkScalar x, SkScalar y) SK_OVERRIDE;
     virtual void onDrawPosText(const GrPaint&, const SkPaint&,
                                const char text[], size_t byteLength,
                                const SkScalar pos[], int scalarsPerPosition,
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index 9fa0c1d..ce2b175 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -28,6 +28,9 @@
 #include "SkStrokeRec.h"
 #include "effects/GrDistanceFieldTextureEffect.h"
 
+#include "SkDrawProcs.h"
+#include "SkTextMapStateProc.h"
+
 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
                 "Dump the contents of the font cache before every purge.");
 
@@ -207,81 +210,6 @@
     }
 }
 
-void GrDistanceFieldTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
-                                          const char text[], size_t byteLength,
-                                          SkScalar x, SkScalar y) {
-    SkASSERT(byteLength == 0 || text != NULL);
-
-    // nothing to draw or can't draw
-    if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
-        || fSkPaint.getRasterizer()) {
-        return;
-    }
-
-    this->init(paint, skPaint);
-
-    SkScalar sizeRatio = fTextRatio;
-
-    SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
-
-    SkAutoGlyphCacheNoGamma    autoCache(fSkPaint, &fDeviceProperties, NULL);
-    SkGlyphCache*              cache = autoCache.getCache();
-    GrFontScaler*              fontScaler = GetGrFontScaler(cache);
-
-    setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
-
-    // need to measure first
-    // TODO - generate positions and pre-load cache as well?
-    const char* stop = text + byteLength;
-    if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
-        SkFixed    stopX = 0;
-        SkFixed    stopY = 0;
-
-        const char* textPtr = text;
-        while (textPtr < stop) {
-            // don't need x, y here, since all subpixel variants will have the
-            // same advance
-            const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
-
-            stopX += glyph.fAdvanceX;
-            stopY += glyph.fAdvanceY;
-        }
-        SkASSERT(textPtr == stop);
-
-        SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
-        SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
-
-        if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
-            alignX = SkScalarHalf(alignX);
-            alignY = SkScalarHalf(alignY);
-        }
-
-        x -= alignX;
-        y -= alignY;
-    }
-
-    SkFixed fx = SkScalarToFixed(x);
-    SkFixed fy = SkScalarToFixed(y);
-    SkFixed fixedScale = SkScalarToFixed(sizeRatio);
-    while (text < stop) {
-        const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
-
-        if (glyph.fWidth) {
-            this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
-                                            glyph.getSubXFixed(),
-                                            glyph.getSubYFixed()),
-                              fx,
-                              fy,
-                              fontScaler);
-        }
-
-        fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
-        fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
-    }
-
-    this->finish();
-}
-
 void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
                                              const char text[], size_t byteLength,
                                              const SkScalar pos[], int scalarsPerPosition,
@@ -326,7 +254,8 @@
             pos += scalarsPerPosition;
         }
     } else {
-        int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
+        SkScalar alignMul = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? SK_ScalarHalf
+                                                                              : SK_Scalar1;
         while (text < stop) {
             // the last 2 parameters are ignored
             const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
@@ -335,11 +264,14 @@
                 SkScalar x = offset.x() + pos[0];
                 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
 
+                SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX)*alignMul*fTextRatio;
+                SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY)*alignMul*fTextRatio;
+
                 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
                                                 glyph.getSubXFixed(),
                                                 glyph.getSubYFixed()),
-                                  SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
-                                  SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
+                                  SkScalarToFixed(x - advanceX),
+                                  SkScalarToFixed(y - advanceY),
                                   fontScaler);
             }
             pos += scalarsPerPosition;
diff --git a/src/gpu/GrDistanceFieldTextContext.h b/src/gpu/GrDistanceFieldTextContext.h
index 6fa2d6f..b1cf559 100644
--- a/src/gpu/GrDistanceFieldTextContext.h
+++ b/src/gpu/GrDistanceFieldTextContext.h
@@ -50,8 +50,6 @@
 
     virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
 
-    virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
-                            SkScalar x, SkScalar y) SK_OVERRIDE;
     virtual void onDrawPosText(const GrPaint&, const SkPaint&,
                                const char text[], size_t byteLength,
                                const SkScalar pos[], int scalarsPerPosition,
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index b53ff79..9b4c4d7 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -11,7 +11,6 @@
 #include "GrGpu.h"
 #include "GrPath.h"
 #include "GrPathRange.h"
-#include "SkAutoKern.h"
 #include "SkDraw.h"
 #include "SkDrawProcs.h"
 #include "SkGlyphCache.h"
@@ -62,96 +61,6 @@
     return rec.getFormat() != SkMask::kARGB32_Format;
 }
 
-void GrStencilAndCoverTextContext::onDrawText(const GrPaint& paint,
-                                            const SkPaint& skPaint,
-                                            const char text[],
-                                            size_t byteLength,
-                                            SkScalar x, SkScalar y) {
-    SkASSERT(byteLength == 0 || text != NULL);
-
-    if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
-        return;
-    }
-
-    // This is the slow path, mainly used by Skia unit tests.  The other
-    // backends (8888, gpu, ...) use device-space dependent glyph caches. In
-    // order to match the glyph positions that the other code paths produce, we
-    // must also use device-space dependent glyph cache. This has the
-    // side-effect that the glyph shape outline will be in device-space,
-    // too. This in turn has the side-effect that NVPR can not stroke the paths,
-    // as the stroke in NVPR is defined in object-space.
-    // NOTE: here we have following coincidence that works at the moment:
-    // - When using the device-space glyphs, the transforms we pass to NVPR
-    // instanced drawing are the global transforms, and the view transform is
-    // identity. NVPR can not use non-affine transforms in the instanced
-    // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it
-    // will turn off the use of device-space glyphs when perspective transforms
-    // are in use.
-
-    this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode, SkPoint::Make(0, 0));
-
-    // Transform our starting point.
-    if (fNeedsDeviceSpaceGlyphs) {
-        SkPoint loc;
-        fContextInitialMatrix.mapXY(x, y, &loc);
-        x = loc.fX;
-        y = loc.fY;
-    }
-
-    SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
-
-    fTransformType = GrPathRendering::kTranslate_PathTransformType;
-
-    const char* stop = text + byteLength;
-
-    // Measure first if needed.
-    if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
-        SkFixed    stopX = 0;
-        SkFixed    stopY = 0;
-
-        const char* textPtr = text;
-        while (textPtr < stop) {
-            // We don't need x, y here, since all subpixel variants will have the
-            // same advance.
-            const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0);
-
-            stopX += glyph.fAdvanceX;
-            stopY += glyph.fAdvanceY;
-        }
-        SkASSERT(textPtr == stop);
-
-        SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
-        SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;
-
-        if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
-            alignX = SkScalarHalf(alignX);
-            alignY = SkScalarHalf(alignY);
-        }
-
-        x -= alignX;
-        y -= alignY;
-    }
-
-    SkAutoKern autokern;
-
-    SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);
-
-    SkFixed fx = SkScalarToFixed(x);
-    SkFixed fy = SkScalarToFixed(y);
-    while (text < stop) {
-        const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
-        fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio);
-        if (glyph.fWidth) {
-            this->appendGlyph(glyph.getGlyphID(), SkFixedToScalar(fx), SkFixedToScalar(fy));
-        }
-
-        fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio);
-        fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio);
-    }
-
-    this->finish();
-}
-
 void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint,
                                                const SkPaint& skPaint,
                                                const char text[],
diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h
index 40d38c2..5985c20 100644
--- a/src/gpu/GrStencilAndCoverTextContext.h
+++ b/src/gpu/GrStencilAndCoverTextContext.h
@@ -68,9 +68,6 @@
 
     virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
 
-    virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[],
-                            size_t byteLength,
-                            SkScalar x, SkScalar y) SK_OVERRIDE;
     virtual void onDrawPosText(const GrPaint&, const SkPaint&,
                                const char text[], size_t byteLength,
                                const SkScalar pos[], int scalarsPerPosition,
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 94c05a7..869706e 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -44,16 +44,63 @@
                              const char text[], size_t byteLength,
                              SkScalar x, SkScalar y) {
 
-    GrTextContext* textContext = this;
-    do {
-        if (textContext->canDraw(skPaint)) {
-            textContext->onDrawText(paint, skPaint, text, byteLength, x, y);
-            return true;
-        }
-        textContext = textContext->fFallbackTextContext;
-    } while (textContext);
+    SkASSERT(byteLength == 0 || text != NULL);
 
-    return false;
+    // nothing to draw
+    if (text == NULL || byteLength == 0) {
+        return true;
+    }
+
+    SkDrawCacheProc          glyphCacheProc = skPaint.getDrawCacheProc();
+    SkAutoGlyphCache         autoCache(skPaint, &fDeviceProperties, NULL);
+    SkGlyphCache*            cache = autoCache.getCache();
+
+    SkTArray<SkScalar> positions;
+
+    const char* textPtr = text;
+    SkFixed stopX = 0;
+    SkFixed stopY = 0;
+    SkFixed origin;
+    switch (skPaint.getTextAlign()) {
+        case SkPaint::kRight_Align: origin = SK_Fixed1; break;
+        case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
+        case SkPaint::kLeft_Align: origin = 0; break;
+        default: SkFAIL("Invalid paint origin"); return false;
+    }
+
+    SkAutoKern autokern;
+    const char* stop = text + byteLength;
+    while (textPtr < stop) {
+        // don't need x, y here, since all subpixel variants will have the
+        // same advance
+        const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
+
+        SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
+        positions.push_back(SkFixedToScalar(stopX + SkFixedMul_portable(origin, width)));
+
+        SkFixed height = glyph.fAdvanceY;
+        positions.push_back(SkFixedToScalar(stopY + SkFixedMul_portable(origin, height)));
+
+        stopX += width;
+        stopY += height;
+    }
+    SkASSERT(textPtr == stop);
+
+    // now adjust starting point depending on alignment
+    SkScalar alignX = SkFixedToScalar(stopX);
+    SkScalar alignY = SkFixedToScalar(stopY);
+    if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
+        alignX = SkScalarHalf(alignX);
+        alignY = SkScalarHalf(alignY);
+    } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
+        alignX = 0;
+        alignY = 0;
+    }
+    x -= alignX;
+    y -= alignY;
+    SkPoint offset = SkPoint::Make(x, y);
+
+    return this->drawPosText(paint, skPaint, text, byteLength, positions.begin(), 2, offset);
 }
 
 bool GrTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
diff --git a/src/gpu/GrTextContext.h b/src/gpu/GrTextContext.h
index 95344dd..ec24fa7 100644
--- a/src/gpu/GrTextContext.h
+++ b/src/gpu/GrTextContext.h
@@ -46,8 +46,6 @@
 
     virtual bool canDraw(const SkPaint& paint) = 0;
 
-    virtual void onDrawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
-                            SkScalar x, SkScalar y) = 0;
     virtual void onDrawPosText(const GrPaint&, const SkPaint&,
                                const char text[], size_t byteLength,
                                const SkScalar pos[], int scalarsPerPosition,