[androidkit] expose SkPath to androidkit

Change-Id: Ibc871459234ba72b0ab948c601e0895c15e21126
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/415797
Commit-Queue: Jorge Betancourt <jmbetancourt@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index f14126b..a6fe5f6 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2526,6 +2526,8 @@
         "modules/androidkit/src/ImageFilter.cpp",
         "modules/androidkit/src/Matrix.cpp",
         "modules/androidkit/src/Paint.cpp",
+        "modules/androidkit/src/Path.cpp",
+        "modules/androidkit/src/PathBuilder.cpp",
         "modules/androidkit/src/RuntimeShaderBuilder.cpp",
         "modules/androidkit/src/Shader.cpp",
         "modules/androidkit/src/SkottieAnimation.cpp",
diff --git a/modules/androidkit/src/AndroidKit.cpp b/modules/androidkit/src/AndroidKit.cpp
index 105821b..855b03d 100644
--- a/modules/androidkit/src/AndroidKit.cpp
+++ b/modules/androidkit/src/AndroidKit.cpp
@@ -28,6 +28,8 @@
     REGISTER_NATIVES(ImageFilter)
     REGISTER_NATIVES(Matrix)
     REGISTER_NATIVES(Paint)
+    REGISTER_NATIVES(Path)
+    REGISTER_NATIVES(PathBuilder)
     REGISTER_NATIVES(RuntimeShaderBuilder)
     REGISTER_NATIVES(Shader)
     REGISTER_NATIVES(SkottieAnimation)
diff --git a/modules/androidkit/src/Canvas.cpp b/modules/androidkit/src/Canvas.cpp
index d0759cf..053b7fc 100644
--- a/modules/androidkit/src/Canvas.cpp
+++ b/modules/androidkit/src/Canvas.cpp
@@ -113,6 +113,16 @@
     }
 }
 
+void Canvas_DrawPath(JNIEnv* env, jobject, jlong native_instance, jlong native_path,
+                     jlong native_paint) {
+    auto* canvas = reinterpret_cast<SkCanvas*>(native_instance);
+    auto* path  = reinterpret_cast<SkPath* >(native_path);
+    auto* paint  = reinterpret_cast<SkPaint* >(native_paint);
+    if (canvas && paint && path) {
+        canvas->drawPath(*path, *paint);
+    }
+}
+
 }  // namespace
 
 int register_androidkit_Canvas(JNIEnv* env) {
@@ -130,6 +140,7 @@
         {"nDrawColor"       , "(JFFFF)V"  , reinterpret_cast<void*>(Canvas_DrawColor)     },
         {"nDrawRect"        , "(JFFFFJ)V" , reinterpret_cast<void*>(Canvas_DrawRect)      },
         {"nDrawImage"       , "(JJFFIFF)V", reinterpret_cast<void*>(Canvas_DrawImage)     },
+        {"nDrawPath"        , "(JJJ)V"    , reinterpret_cast<void*>(Canvas_DrawPath)      },
     };
 
     const auto clazz = env->FindClass("org/skia/androidkit/Canvas");
diff --git a/modules/androidkit/src/Path.cpp b/modules/androidkit/src/Path.cpp
new file mode 100644
index 0000000..8ea4bc6
--- /dev/null
+++ b/modules/androidkit/src/Path.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <jni.h>
+
+#include "include/core/SkPath.h"
+
+namespace {
+static void Path_Release(JNIEnv* env, jobject, jlong native_path) {
+    delete reinterpret_cast<SkPath*>(native_path);
+}
+
+}  // namespace
+
+int register_androidkit_Path(JNIEnv* env) {
+    static const JNINativeMethod methods[] = {
+        {"nRelease" , "(J)V"    , reinterpret_cast<void*>(Path_Release)},
+    };
+
+    const auto clazz = env->FindClass("org/skia/androidkit/Path");
+    return clazz
+        ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
+        : JNI_ERR;
+}
diff --git a/modules/androidkit/src/PathBuilder.cpp b/modules/androidkit/src/PathBuilder.cpp
new file mode 100644
index 0000000..a0a8504
--- /dev/null
+++ b/modules/androidkit/src/PathBuilder.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <jni.h>
+
+#include "include/core/SkPathBuilder.h"
+
+namespace {
+
+static jlong PathBuilder_Create(JNIEnv* env, jobject) {
+    return reinterpret_cast<jlong>(new SkPathBuilder());
+}
+
+static void PathBuilder_Release(JNIEnv* env, jobject, jlong native_pathBuilder) {
+    delete reinterpret_cast<SkPathBuilder*>(native_pathBuilder);
+}
+
+static void PathBuilder_MoveTo(JNIEnv* env, jobject, jlong native_pathBuilder, jfloat x, jfloat y) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        pathBuilder->moveTo(x, y);
+    }
+}
+
+static void PathBuilder_LineTo(JNIEnv* env, jobject, jlong native_pathBuilder, jfloat x, jfloat y) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        pathBuilder->lineTo(x, y);
+    }
+}
+
+static void PathBuilder_QuadTo(JNIEnv* env, jobject, jlong native_pathBuilder, jfloat x1, jfloat y1, jfloat x2, jfloat y2) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        pathBuilder->quadTo(x1, y1, x2, y2);
+    }
+}
+
+static void PathBuilder_ConicTo(JNIEnv* env, jobject, jlong native_pathBuilder, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat w) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        pathBuilder->conicTo(x1, y1, x2, y2, w);
+    }
+}
+
+static void PathBuilder_CubicTo(JNIEnv* env, jobject, jlong native_pathBuilder, jfloat x1, jfloat y1,
+                                                                                jfloat x2, jfloat y2,
+                                                                                jfloat x3, jfloat y3) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        pathBuilder->cubicTo(x1, y1, x2, y2, x3, y3);
+    }
+}
+
+static void PathBuilder_Close(JNIEnv* env, jobject, jlong native_pathBuilder) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        pathBuilder->close();
+    }
+}
+
+static void PathBuilder_SetFillType(JNIEnv* env, jobject, jlong native_pathBuilder, jint fill) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        switch(fill) {
+            case 0:
+                pathBuilder->setFillType(SkPathFillType::kWinding);
+                break;
+            case 1:
+                pathBuilder->setFillType(SkPathFillType::kEvenOdd);
+                break;
+            case 2:
+                pathBuilder->setFillType(SkPathFillType::kInverseWinding);
+                break;
+            case 3:
+                pathBuilder->setFillType(SkPathFillType::kInverseEvenOdd);
+                break;
+        }
+    }
+}
+
+static jlong PathBuilder_MakePath(JNIEnv* env, jobject, jlong native_pathBuilder) {
+    if (auto* pathBuilder = reinterpret_cast<SkPathBuilder*>(native_pathBuilder)) {
+        SkPath* path = new SkPath(pathBuilder->detach());
+        return reinterpret_cast<jlong>(path);
+    }
+
+    return 0;
+}
+
+}  // namespace
+
+int register_androidkit_PathBuilder(JNIEnv* env) {
+    static const JNINativeMethod methods[] = {
+        {"nCreate"      , "()J"       , reinterpret_cast<void*>(PathBuilder_Create)},
+        {"nRelease"     , "(J)V"      , reinterpret_cast<void*>(PathBuilder_Release)},
+        {"nMoveTo"      , "(JFF)V"    , reinterpret_cast<void*>(PathBuilder_MoveTo)},
+        {"nLineTo"      , "(JFF)V"    , reinterpret_cast<void*>(PathBuilder_LineTo)},
+        {"nQuadTo"      , "(JFFFF)V"  , reinterpret_cast<void*>(PathBuilder_QuadTo)},
+        {"nConicTo"     , "(JFFFFF)V" , reinterpret_cast<void*>(PathBuilder_ConicTo)},
+        {"nCubicTo"     , "(JFFFFFF)V", reinterpret_cast<void*>(PathBuilder_CubicTo)},
+        {"nClose"       , "(J)V"      , reinterpret_cast<void*>(PathBuilder_Close)},
+        {"nSetFillType" , "(JI)V"     , reinterpret_cast<void*>(PathBuilder_SetFillType)},
+        {"nMake"        , "(J)J"      , reinterpret_cast<void*>(PathBuilder_MakePath)},
+    };
+
+    const auto clazz = env->FindClass("org/skia/androidkit/PathBuilder");
+    return clazz
+        ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
+        : JNI_ERR;
+}
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
index 2cd4da1..356bad1 100644
--- a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
@@ -7,13 +7,6 @@
 
 package org.skia.androidkit;
 
-import org.skia.androidkit.Color;
-import org.skia.androidkit.Image;
-import org.skia.androidkit.Matrix;
-import org.skia.androidkit.Paint;
-import org.skia.androidkit.SamplingOptions;
-import org.skia.androidkit.Surface;
-
 public class Canvas {
     private long mNativeInstance;
     private Surface mSurface;
@@ -101,6 +94,10 @@
                    sampling.getNativeDesc(), sampling.getCubicCoeffB(), sampling.getCubicCoeffC());
     }
 
+    public void drawPath(Path path, Paint paint) {
+        nDrawPath(mNativeInstance, path.getNativeInstance(), paint.getNativeInstance());
+    }
+
     // package private
     Canvas(Surface surface, long native_instance) {
         mNativeInstance = native_instance;
@@ -129,4 +126,5 @@
     private static native void nDrawImage(long nativeInstance, long nativeImage, float x, float y,
                                           int samplingDesc,
                                           float samplingCoeffB, float samplingCoeffC);
+    private static native void nDrawPath(long mNativeInstance, long nativePath, long nativePaint);
 }
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Path.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Path.java
new file mode 100644
index 0000000..e026a412
--- /dev/null
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Path.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package org.skia.androidkit;
+
+public class Path {
+    private long mNativeInstance;
+
+    Path(long native_instance) {
+        mNativeInstance = native_instance;
+    }
+
+    /**
+     * Releases any resources associated with this Shader.
+     */
+    public void release() {
+        nRelease(mNativeInstance);
+        mNativeInstance = 0;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        release();
+    }
+
+    // package private
+    long getNativeInstance() { return mNativeInstance; }
+
+    private static native void nRelease(long nativeInstance);
+}
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/PathBuilder.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/PathBuilder.java
new file mode 100644
index 0000000..68bfcbd
--- /dev/null
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/PathBuilder.java
@@ -0,0 +1,79 @@
+package org.skia.androidkit;
+
+public class PathBuilder {
+    private long mNativeInstance;
+
+    public PathBuilder() {
+        mNativeInstance = nCreate();
+    }
+
+    /**
+     * Releases any resources associated with this Path.
+     */
+    public void release() {
+        nRelease(mNativeInstance);
+        mNativeInstance = 0;
+    }
+
+    public void moveTo(float x, float y) {
+        nMoveTo(mNativeInstance, x, y);
+    }
+
+    public void lineTo(float x, float y) {
+        nLineTo(mNativeInstance, x, y);
+    }
+
+    public void quadTo(float x1, float y1, float x2, float y2) {
+        nQuadTo(mNativeInstance, x1, y1, x2, y2);
+    }
+    public void conicTo(float x1, float y1, float x2, float y2, float w) {
+        nConicTo(mNativeInstance, x1, y1, x2, y2, w);
+    }
+    public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) {
+        nCubicTo(mNativeInstance, x1, y1, x2, y2, x3, y3);
+    }
+
+    public void close() {
+        nClose(mNativeInstance);
+    }
+
+    public enum FillType {
+        WINDING           (0),
+        EVEN_ODD          (1),
+        INVERSE_WINDING   (2),
+        INVERSE_EVEN_ODD  (3);
+
+
+        FillType(int nativeInt) {
+            this.nativeInt = nativeInt;
+        }
+        final int nativeInt;
+    }
+    public void setFillType(FillType fillType) {
+        nSetFillType(mNativeInstance, fillType.nativeInt);
+    }
+
+    /*
+     * Returns a path from the builder, resets the builder to empty.
+     * Wrapper for SkPath::detach()
+     */
+    public Path makePath() {
+        return new Path(nMake(mNativeInstance));
+    }
+
+    // package private
+    long getNativeInstance() { return mNativeInstance; }
+
+    private static native long nCreate();
+    private static native void nRelease(long nativeInstance);
+    private static native void nMoveTo(long mNativeInstance, float x, float y);
+    private static native void nLineTo(long mNativeInstance, float x, float y);
+    private static native void nQuadTo(long mNativeInstance, float x1, float y1, float x2, float y2);
+    private static native void nConicTo(long mNativeInstance, float x1, float y1, float x2, float y2, float w);
+    private static native void nCubicTo(long mNativeInstance, float x1, float y1, float x2, float y2, float x3, float y3);
+    private static native void nClose(long mNativeInstance);
+    private static native void nSetFillType(long mNativeInstance, int fillType);
+    private static native long nMake(long mNativeInstance);
+
+
+}
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
index b0b9a44..3ed57a3 100644
--- a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
+++ b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
@@ -9,13 +9,11 @@
 
 import android.app.Activity;
 import android.graphics.Bitmap;
-import android.graphics.SurfaceTexture;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
-import android.view.TextureView;
 import android.widget.ImageView;
 import org.skia.androidkit.*;
 import org.skia.androidkit.util.SurfaceRenderer;
@@ -98,7 +96,14 @@
             p.setColor(new Color(1, 1, 0, 1));
             ImageFilter filter = ImageFilter.distantLitDiffuse(.5f, .5f, .5f, new Color(1, 0, 0, 1), 1, 1, null);
             p.setImageFilter(filter);
-            threadedSurface.getCanvas().drawRect(20, 20, 250, 250, p);
+            PathBuilder pathBuilder = new PathBuilder();
+            pathBuilder.moveTo(20, 20);
+            pathBuilder.quadTo(180, 60, 180, 180);
+            pathBuilder.close();
+            pathBuilder.moveTo(180, 60);
+            pathBuilder.quadTo(180, 180, 60, 180);
+            Path path = pathBuilder.makePath();
+            threadedSurface.getCanvas().drawPath(path, p);
             threadedSurface.flushAndSubmit();
         }