Merge "Implement drawTextOnPath with Minikin"
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 95e50b1..68e2146 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -969,22 +969,24 @@
         }
 
         nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
-                paint.mBidiFlags, paint.mNativePaint);
+                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
-            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint);
+            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
+            long typeface);
 
     @Override
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
         if (text.length() == 0) return;
 
         nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
-                paint.mBidiFlags, paint.mNativePaint);
+                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
-            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint);
+            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
+            long typeface);
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 4584c46..69e149e 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -1123,29 +1123,82 @@
         delete[] posPtr;
     }
 
+#ifdef USE_MINIKIN
+    class DrawTextOnPathFunctor {
+    public:
+        DrawTextOnPathFunctor(const Layout& layout, SkCanvas* canvas, float hOffset,
+                    float vOffset, SkPaint* paint, SkPath* path)
+                : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
+                    paint(paint), path(path) {
+        }
+        void operator()(size_t start, size_t end) {
+            uint16_t glyphs[1];
+            for (size_t i = start; i < end; i++) {
+                glyphs[0] = layout.getGlyphId(i);
+                float x = hOffset + layout.getX(i);
+                float y = vOffset + layout.getY(i);
+                canvas->drawTextOnPathHV(glyphs, sizeof(glyphs), *path, x, y, *paint);
+            }
+        }
+    private:
+        const Layout& layout;
+        SkCanvas* canvas;
+        float hOffset;
+        float vOffset;
+        SkPaint* paint;
+        SkPath* path;
+    };
+#endif
+
+    static void doDrawTextOnPath(SkPaint* paint, const jchar* text, int count, int bidiFlags,
+            float hOffset, float vOffset, SkPath* path, SkCanvas* canvas, TypefaceImpl* typeface) {
+#ifdef USE_MINIKIN
+        Layout layout;
+        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
+        layout.doLayout(text, 0, count, count, css);
+        hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path);
+        // Set align to left for drawing, as we don't want individual
+        // glyphs centered or right-aligned; the offset above takes
+        // care of all alignment.
+        SkPaint::Align align = paint->getTextAlign();
+        paint->setTextAlign(SkPaint::kLeft_Align);
+
+        DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paint, path);
+        MinikinUtils::forFontRun(layout, paint, f);
+        paint->setTextAlign(align);
+#else
+        TextLayout::drawTextOnPath(paint, text, count, bidiFlags, hOffset, vOffset, path, canvas);
+#endif
+    }
+
     static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
             jlong canvasHandle, jcharArray text, jint index, jint count,
-            jlong pathHandle, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle) {
+            jlong pathHandle, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle,
+            jlong typefaceHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
 
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
-                                   path, canvas);
+        doDrawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas, typeface);
         env->ReleaseCharArrayElements(text, textArray, 0);
     }
 
     static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
             jlong canvasHandle, jstring text, jlong pathHandle,
-            jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle) {
+            jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle,
+            jlong typefaceHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+
         const jchar* text_ = env->GetStringChars(text, NULL);
         int count = env->GetStringLength(text);
-        TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
-                                   path, canvas);
+        doDrawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas, typeface);
         env->ReleaseStringChars(text, text_);
     }
 
@@ -1271,9 +1324,9 @@
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(JLjava/lang/String;[FJ)V",
         (void*) SkCanvasGlue::drawPosText__String_FPaint},
-    {"native_drawTextOnPath","(J[CIIJFFIJ)V",
+    {"native_drawTextOnPath","(J[CIIJFFIJJ)V",
         (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
-    {"native_drawTextOnPath","(JLjava/lang/String;JFFIJ)V",
+    {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V",
         (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
 
     {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches},
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index a9360ea..fc92d53 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -19,6 +19,7 @@
 #include <string>
 
 #include "SkPaint.h"
+#include "SkPathMeasure.h"
 #include "minikin/Layout.h"
 #include "TypefaceImpl.h"
 #include "MinikinSkia.h"
@@ -76,4 +77,20 @@
     return 0;
 }
 
+float MinikinUtils::hOffsetForTextAlign(SkPaint* paint, const Layout& layout, const SkPath& path) {
+    float align = 0;
+    switch (paint->getTextAlign()) {
+        case SkPaint::kCenter_Align:
+            align = -0.5f;
+            break;
+        case SkPaint::kRight_Align:
+            align = -1;
+            break;
+        default:
+            return 0;
+    }
+    SkPathMeasure measure(path, false);
+    return align * (layout.getAdvance() - measure.getLength());
+}
+
 }
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index a96c6b1..b2662a1 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -36,6 +36,7 @@
 
     static float xOffsetForTextAlign(SkPaint* paint, const Layout& layout);
 
+    static float hOffsetForTextAlign(SkPaint* paint, const Layout& layout, const SkPath& path);
     // f is a functor of type void f(size_t start, size_t end);
     template <typename F>
     static void forFontRun(const Layout& layout, SkPaint* paint, F& f) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 4a6e117..de00e59 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -669,8 +669,48 @@
 #endif
 }
 
+#ifdef USE_MINIKIN
+class RenderTextOnPathFunctor {
+public:
+    RenderTextOnPathFunctor(const Layout& layout, OpenGLRenderer* renderer, float hOffset,
+                float vOffset, SkPaint* paint, SkPath* path)
+            : layout(layout), renderer(renderer), hOffset(hOffset), vOffset(vOffset),
+                paint(paint), path(path) {
+    }
+    void operator()(size_t start, size_t end) {
+        uint16_t glyphs[1];
+        for (size_t i = start; i < end; i++) {
+            glyphs[0] = layout.getGlyphId(i);
+            float x = hOffset + layout.getX(i);
+            float y = vOffset + layout.getY(i);
+            renderer->drawTextOnPath((const char*) glyphs, sizeof(glyphs), 1, path, x, y, paint);
+        }
+    }
+private:
+    const Layout& layout;
+    OpenGLRenderer* renderer;
+    float hOffset;
+    float vOffset;
+    SkPaint* paint;
+    SkPath* path;
+};
+#endif
+
 static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint,
+        TypefaceImpl* typeface) {
+#ifdef USE_MINIKIN
+    Layout layout;
+    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
+    layout.doLayout(text, 0, count, count, css);
+    hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path);
+    SkPaint::Align align = paint->getTextAlign();
+    paint->setTextAlign(SkPaint::kLeft_Align);
+
+    RenderTextOnPathFunctor f(layout, renderer, hOffset, vOffset, paint, path);
+    MinikinUtils::forFontRun(layout, paint, f);
+    paint->setTextAlign(align);
+#else
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
             text, 0, count, count, bidiFlags);
     if (value == NULL) {
@@ -681,6 +721,7 @@
     int bytesCount = glyphsCount * sizeof(jchar);
     renderer->drawTextOnPath((const char*) glyphs, bytesCount, glyphsCount, path,
             hOffset, vOffset, paint);
+#endif
 }
 
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
@@ -739,27 +780,31 @@
 
 static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jcharArray text, jint index, jint count,
-        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
+        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr,
+        jlong typefacePtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
 
     renderTextOnPath(renderer, textArray + index, count, path,
-            hOffset, vOffset, bidiFlags, paint);
+            hOffset, vOffset, bidiFlags, paint, typeface);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jstring text, jint start, jint end,
-        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
+        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr,
+        jlong typefacePtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     const jchar* textArray = env->GetStringChars(text, NULL);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
 
     renderTextOnPath(renderer, textArray + start, end - start, path,
-            hOffset, vOffset, bidiFlags, paint);
+            hOffset, vOffset, bidiFlags, paint, typeface);
     env->ReleaseStringChars(text, textArray);
 }
 
@@ -986,8 +1031,8 @@
     { "nDrawText",          "(JLjava/lang/String;IIFFIJJ)V",
             (void*) android_view_GLES20Canvas_drawText },
 
-    { "nDrawTextOnPath",    "(J[CIIJFFIJ)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
-    { "nDrawTextOnPath",    "(JLjava/lang/String;IIJFFIJ)V",
+    { "nDrawTextOnPath",    "(J[CIIJFFIJJ)V",  (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
+    { "nDrawTextOnPath",    "(JLjava/lang/String;IIJFFIJJ)V",
             (void*) android_view_GLES20Canvas_drawTextOnPath },
 
     { "nDrawTextRun",       "(J[CIIIIFFZJJ)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 158801c..13421aa 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1770,7 +1770,7 @@
         }
         native_drawTextOnPath(mNativeCanvasWrapper, text, index, count,
                 path.ni(), hOffset, vOffset,
-                paint.mBidiFlags, paint.mNativePaint);
+                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1790,7 +1790,7 @@
             float vOffset, @NonNull Paint paint) {
         if (text.length() > 0) {
             native_drawTextOnPath(mNativeCanvasWrapper, text, path.ni(), hOffset, vOffset,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
         }
     }
 
@@ -2021,11 +2021,11 @@
                                                      int count, long nativePath,
                                                      float hOffset,
                                                      float vOffset, int bidiFlags,
-                                                     long nativePaint);
+                                                     long nativePaint, long nativeTypeface);
     private static native void native_drawTextOnPath(long nativeCanvas,
                                                      String text, long nativePath,
                                                      float hOffset,
                                                      float vOffset,
-                                                     int flags, long nativePaint);
+                                                     int flags, long nativePaint, long nativeTypeface);
     private static native void finalizer(long nativeCanvas);
 }