Merge "Add conic support for Path#approximate" into oc-dev
am: ebd44d0076

Change-Id: I68f5924aef7526de1c801f529dd5a304a1a1d287
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 292454b..d3d6882 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -26,6 +26,7 @@
 
 #include "SkPath.h"
 #include "SkPathOps.h"
+#include "SkGeometry.h" // WARNING: Internal Skia Header
 
 #include <Caches.h>
 #include <vector>
@@ -355,8 +356,9 @@
         }
     }
 
-    static void createVerbSegments(SkPath::Verb verb, const SkPoint* points,
-        std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, float errorSquared) {
+    static void createVerbSegments(const SkPath::Iter& pathIter, SkPath::Verb verb,
+            const SkPoint* points, std::vector<SkPoint>& segmentPoints,
+            std::vector<float>& lengths, float errorSquared, float errorConic) {
         switch (verb) {
             case SkPath::kMove_Verb:
                 addMove(segmentPoints, lengths, points[0]);
@@ -375,8 +377,27 @@
                 addBezier(points, cubicBezierCalculation, segmentPoints, lengths,
                     errorSquared, true);
                 break;
+            case SkPath::kConic_Verb: {
+                SkAutoConicToQuads converter;
+                const SkPoint* quads = converter.computeQuads(
+                        points, pathIter.conicWeight(), errorConic);
+                for (int i = 0; i < converter.countQuads(); i++) {
+                    // Note: offset each subsequent quad by 2, since end points are shared
+                    const SkPoint* quad = quads + i * 2;
+                    addBezier(quad, quadraticBezierCalculation, segmentPoints, lengths,
+                        errorConic, false);
+                }
+                break;
+            }
             default:
-                // Leave element as NULL, Conic sections are not supported.
+                static_assert(SkPath::kMove_Verb == 0
+                                && SkPath::kLine_Verb == 1
+                                && SkPath::kQuad_Verb == 2
+                                && SkPath::kConic_Verb == 3
+                                && SkPath::kCubic_Verb == 4
+                                && SkPath::kClose_Verb == 5
+                                && SkPath::kDone_Verb == 6,
+                        "Path enum changed, new types may have been added.");
                 break;
         }
     }
@@ -398,9 +419,11 @@
         std::vector<SkPoint> segmentPoints;
         std::vector<float> lengths;
         float errorSquared = acceptableError * acceptableError;
+        float errorConic = acceptableError / 2; // somewhat arbitrary
 
         while ((verb = pathIter.next(points, false)) != SkPath::kDone_Verb) {
-            createVerbSegments(verb, points, segmentPoints, lengths, errorSquared);
+            createVerbSegments(pathIter, verb, points, segmentPoints, lengths,
+                    errorSquared, errorConic);
         }
 
         if (segmentPoints.empty()) {
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 3631373..098cdc6 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -16,8 +16,10 @@
 
 package android.graphics;
 
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
@@ -805,7 +807,12 @@
      *                        the error is less than half a pixel.
      * @return An array of components for points approximating the Path.
      */
-    public float[] approximate(float acceptableError) {
+    @NonNull
+    @Size(min = 6, multiple = 3)
+    public float[] approximate(@FloatRange(from = 0) float acceptableError) {
+        if (acceptableError < 0) {
+            throw new IllegalArgumentException("AcceptableError must be greater than or equal to 0");
+        }
         return nApproximate(mNativePath, acceptableError);
     }
 
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 9246237..64b2c45 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -1005,6 +1005,14 @@
                 break;
             }
             default:
+                static_assert(SkPath::kMove_Verb == 0
+                                && SkPath::kLine_Verb == 1
+                                && SkPath::kQuad_Verb == 2
+                                && SkPath::kConic_Verb == 3
+                                && SkPath::kCubic_Verb == 4
+                                && SkPath::kClose_Verb == 5
+                                && SkPath::kDone_Verb == 6,
+                        "Path enum changed, new types may have been added");
                 break;
             }
     }