diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index 292454bd0875f..d3d68826affed 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 #include @@ -355,8 +356,9 @@ public: } } - static void createVerbSegments(SkPath::Verb verb, const SkPoint* points, - std::vector& segmentPoints, std::vector& lengths, float errorSquared) { + static void createVerbSegments(const SkPath::Iter& pathIter, SkPath::Verb verb, + const SkPoint* points, std::vector& segmentPoints, + std::vector& lengths, float errorSquared, float errorConic) { switch (verb) { case SkPath::kMove_Verb: addMove(segmentPoints, lengths, points[0]); @@ -375,8 +377,27 @@ public: 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 @@ public: std::vector segmentPoints; std::vector 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 363137321f5ff..098cdc67555d0 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 @@ public class Path { * 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 9246237aeffbe..64b2c4564d7b9 100644 --- a/libs/hwui/PathTessellator.cpp +++ b/libs/hwui/PathTessellator.cpp @@ -1005,6 +1005,14 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo 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; } }