Added drawPosTextOnPath method.

The drawPosTextOnPath method allows for text positioned on
a straight line to be drawn along a path.
This method can be used by layout engines to implement the
Canvas::drawTextOnPath method for complex scripts.

Change-Id: I2f9c22b8c97eeacb61cd6de7429ba875a1e7ade9
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 8fba6cf..f88a8b9 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -581,6 +581,19 @@
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
 
+    /** Draw the text on path, with each character/glyph origin specified by the pos[]
+        array. The origin is interpreted by the Align setting in the paint.
+        @param text The text to be drawn
+        @param byteLength   The number of bytes to read from the text parameter
+        @param pos      Array of positions, used to position each character
+        @param paint    The paint used for the text (e.g. color, size, style)
+        @param path The path to draw on
+        @param matrix The canvas matrix
+        */
+    void drawPosTextOnPath(const void* text, size_t byteLength,
+                           const SkPoint pos[], const SkPaint& paint,
+                           const SkPath& path, const SkMatrix* matrix);
+
     /** Draw the picture into this canvas. This method effective brackets the
         playback of the picture's draw calls with save/restore, so the state
         of this canvas will be unchanged after this call. This contrasts with
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 4d678c6..0d724ba 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -120,6 +120,9 @@
     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
+    virtual void drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
+                                   const SkPoint pos[], const SkPaint& paint,
+                                   const SkPath& path, const SkMatrix* matrix);
     virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
                               const SkPoint verts[], const SkPoint texs[],
                               const SkColor colors[], SkXfermode* xmode,
diff --git a/include/core/SkDraw.h b/include/core/SkDraw.h
index 8214859..a86ef67 100644
--- a/include/core/SkDraw.h
+++ b/include/core/SkDraw.h
@@ -54,6 +54,9 @@
                         int scalarsPerPosition, const SkPaint& paint) const;
     void    drawTextOnPath(const char text[], size_t byteLength,
                         const SkPath&, const SkMatrix*, const SkPaint&) const;
+    void    drawPosTextOnPath(const char text[], size_t byteLength,
+                              const SkPoint pos[], const SkPaint& paint,
+                              const SkPath& path, const SkMatrix* matrix) const;
     void    drawVertices(SkCanvas::VertexMode mode, int count,
                          const SkPoint vertices[], const SkPoint textures[],
                          const SkColor colors[], SkXfermode* xmode,
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 23031c5..c01c343 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1216,6 +1216,20 @@
     ITER_END
 }
 
+void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
+                                 const SkPoint pos[], const SkPaint& paint,
+                                 const SkPath& path, const SkMatrix* matrix) {
+
+    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
+
+    while (iter.next()) {
+        iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
+                                        paint, path, matrix);
+    }
+
+    ITER_END
+}
+
 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
                             const SkPoint verts[], const SkPoint texs[],
                             const SkColor colors[], SkXfermode* xmode,
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 139174d..8ce1bd8 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -92,6 +92,12 @@
     draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
 }
 
+void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
+                                     const SkPoint pos[], const SkPaint& paint,
+                                     const SkPath& path, const SkMatrix* matrix) {
+    draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
+}
+
 void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
                                 int vertexCount,
                                 const SkPoint verts[], const SkPoint textures[],
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 7f0cc15..a47d101 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -1854,6 +1854,68 @@
     }
 }
 
+void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength,
+                               const SkPoint pos[], const SkPaint& paint,
+                               const SkPath& path, const SkMatrix* matrix) const {
+    // nothing to draw
+    if (text == NULL || byteLength == 0 || fClip->isEmpty() ||
+        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+        return;
+    }
+
+    SkMatrix scaledMatrix;
+    SkPathMeasure meas(path, false);
+
+    SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc(
+            SkPaint::kForward_TextBufferDirection, true);
+
+    // Copied (modified) from SkTextToPathIter constructor to setup paint
+    SkPaint tempPaint(paint);
+
+    tempPaint.setLinearText(true);
+    tempPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup
+
+    if (tempPaint.getPathEffect() == NULL && !(tempPaint.getStrokeWidth() > 0
+            && tempPaint.getStyle() != SkPaint::kFill_Style)) {
+        tempPaint.setStyle(SkPaint::kFill_Style);
+        tempPaint.setPathEffect(NULL);
+    }
+    // End copied from SkTextToPathIter constructor
+
+    // detach cache
+    SkGlyphCache* cache = tempPaint.detachCache(NULL);
+
+    // Must set scale, even if 1
+    SkScalar scale = SK_Scalar1;
+    scaledMatrix.setScale(scale, scale);
+
+    // Loop over all glyph ids
+    for (const char* stop = text + byteLength; text < stop; pos++) {
+
+        const SkGlyph& glyph = glyphCacheProc(cache, &text);
+        SkPath tmp;
+
+        const SkPath* glyphPath = cache->findPath(glyph);
+        if (glyphPath == NULL) {
+            continue;
+        }
+
+        SkMatrix m(scaledMatrix);
+        m.postTranslate(pos->fX, 0);
+
+        if (matrix) {
+            m.postConcat(*matrix);
+        }
+
+        morphpath(&tmp, *glyphPath, meas, m);
+        this->drawPath(tmp, tempPaint);
+
+    }
+
+    // re-attach cache
+    SkGlyphCache::AttachCache(cache);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 struct VertState {