diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml index 9773c22..25fa9ac 100644 --- a/.idea/androidTestResultsUserPreferences.xml +++ b/.idea/androidTestResultsUserPreferences.xml @@ -52,6 +52,7 @@ + diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 2ac6b25..678d26c 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -1,17 +1,23 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index fdf8d99..ae3f30a 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index b4b4525..82807bf 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/README.md b/README.md index c087b28..5fbe850 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'dev.romainguy:pathway:0.15.0' + implementation 'dev.romainguy:pathway:0.16.0' } ``` diff --git a/build.gradle b/build.gradle index 1f6fd30..8ccd3b3 100644 --- a/build.gradle +++ b/build.gradle @@ -5,9 +5,9 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:8.0.2" + classpath "com.android.tools.build:gradle:8.2.0" classpath "com.vanniktech:gradle-maven-publish-plugin:0.25.3" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21" classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.8.20" } @@ -29,5 +29,6 @@ buildscript { "-fdata-sections", "-Wl,--gc-sections", "-Wl,-Bsymbolic-functions", + "-nostdlib++" ] } diff --git a/gradle.properties b/gradle.properties index 5e9777a..caf023d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ GROUP=dev.romainguy -VERSION_NAME=0.15.0 +VERSION_NAME=0.16.0 SONATYPE_HOST=S01 RELEASE_SIGNING_ENABLED=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c2a0986..f446e80 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jul 12 13:05:07 PDT 2023 +#Tue Dec 12 17:22:13 PST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/pathway/build.gradle b/pathway/build.gradle index b5964f9..413cddc 100644 --- a/pathway/build.gradle +++ b/pathway/build.gradle @@ -23,6 +23,8 @@ android { } } + consumerProguardFiles "proguard-rules.pro" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/pathway/proguard-rules.pro b/pathway/proguard-rules.pro new file mode 100644 index 0000000..34187b3 --- /dev/null +++ b/pathway/proguard-rules.pro @@ -0,0 +1,3 @@ +-keepclasseswithmembernames,includedescriptorclasses class dev.romainguy.graphics.path.** { + native ; +} diff --git a/pathway/src/main/cpp/Conic.cpp b/pathway/src/main/cpp/Conic.cpp index f6e28f2..56bb9b7 100644 --- a/pathway/src/main/cpp/Conic.cpp +++ b/pathway/src/main/cpp/Conic.cpp @@ -26,8 +26,6 @@ using namespace filament::math; -constexpr int kMaxConicToQuadCount = 5; - constexpr bool isFinite(const Point points[], int count) noexcept { return isFinite(&points[0].x, count << 1); } @@ -53,17 +51,9 @@ const Point* ConicConverter::toQuadratics( Conic conic(points[0], points[1], points[2], weight); int count = conic.computeQuadraticCount(tolerance); - mQuadraticCount = 1 << count; - - int newSize = 1 + 2 * mQuadraticCount; - if (newSize > mStorage.size()) { - mStorage.resize(newSize); - } - - Point* data = mStorage.data(); - mQuadraticCount = conic.splitIntoQuadratics(data, count); + mQuadraticCount = conic.splitIntoQuadratics(mStorage, count); - return data; + return mStorage; } int Conic::computeQuadraticCount(float tolerance) const noexcept { diff --git a/pathway/src/main/cpp/Conic.h b/pathway/src/main/cpp/Conic.h index eeebf3f..0d4a95a 100644 --- a/pathway/src/main/cpp/Conic.h +++ b/pathway/src/main/cpp/Conic.h @@ -19,9 +19,8 @@ #include "Path.h" -#include - -constexpr int kDefaultQuadraticCount = 8; +constexpr int kMaxConicToQuadCount = 5; +constexpr int kMaxQuadraticCount = 1 << kMaxConicToQuadCount; class ConicConverter { public: @@ -32,12 +31,12 @@ class ConicConverter { int quadraticCount() const noexcept { return mQuadraticCount; } const Point* quadratics() const noexcept { - return mQuadraticCount > 0 ? mStorage.data() : nullptr; + return mQuadraticCount > 0 ? mStorage : nullptr; } private: int mQuadraticCount = 0; - std::vector mStorage{1 + 2 * kDefaultQuadraticCount}; + Point mStorage[1 + 2 * kMaxQuadraticCount]; }; struct Conic { diff --git a/pathway/src/main/cpp/pathway.cpp b/pathway/src/main/cpp/pathway.cpp index cb9f617..7700d15 100644 --- a/pathway/src/main/cpp/pathway.cpp +++ b/pathway/src/main/cpp/pathway.cpp @@ -20,6 +20,9 @@ #include +#include +#include + #define JNI_CLASS_NAME "dev/romainguy/graphics/path/Paths" struct { @@ -77,14 +80,17 @@ static jlong createPathIterator(JNIEnv* env, jclass, direction = PathIterator::VerbDirection::Backward; } - return jlong(new PathIterator( + PathIterator* iterator = static_cast(malloc(sizeof(PathIterator))); + return jlong(new(iterator) PathIterator( points, verbs, conicWeights, count, direction, PathIterator::ConicEvaluation(conicEvaluation_), tolerance_ )); } static void destroyPathIterator(JNIEnv*, jclass, jlong pathIterator_) { - delete reinterpret_cast(pathIterator_); + PathIterator* iterator = reinterpret_cast(pathIterator_); + iterator->~PathIterator(); + free(iterator); } static jboolean pathIteratorHasNext(JNIEnv*, jclass, jlong pathIterator_) { diff --git a/pathway/src/main/java/dev/romainguy/graphics/path/Paths.kt b/pathway/src/main/java/dev/romainguy/graphics/path/Paths.kt index b0a3bea..d9022dd 100644 --- a/pathway/src/main/java/dev/romainguy/graphics/path/Paths.kt +++ b/pathway/src/main/java/dev/romainguy/graphics/path/Paths.kt @@ -103,9 +103,7 @@ class PathSegment internal constructor(val type: Type, val points: Array if (type != other.type) return false if (!points.contentEquals(other.points)) return false - if (weight != other.weight) return false - - return true + return weight == other.weight } override fun hashCode(): Int { @@ -130,11 +128,6 @@ val DoneSegment = PathSegment(PathSegment.Type.Done, emptyArray(), 0.0f) */ val CloseSegment = PathSegment(PathSegment.Type.Close, emptyArray(), 0.0f) -/** - * Cache of [PathSegment.Type] values to avoid internal allocation on each use. - */ -private val pathSegmentTypes = PathSegment.Type.values() - /** * Creates a new [PathIterator] for this [path][android.graphics.Path] that evaluates * conics as quadratics. To preserve conics, use [Path.iterator]. @@ -211,7 +204,7 @@ class PathIterator( * Returns the type of the current segment in the iteration, or [Done][PathSegment.Type.Done] * if the iteration is finished. */ - fun peek() = pathSegmentTypes[internalPathIteratorPeek(internalPathIterator)] + fun peek() = PathSegment.Type.entries[internalPathIteratorPeek(internalPathIterator)] /** * Returns the [type][PathSegment.Type] of the next [path segment][PathSegment] in the iteration @@ -236,7 +229,7 @@ class PathIterator( fun next(points: FloatArray, offset: Int = 0): PathSegment.Type { check(points.size - offset >= 8) { "The points array must contain at least 8 floats" } val typeValue = internalPathIteratorNext(internalPathIterator, points, offset) - return pathSegmentTypes[typeValue] + return PathSegment.Type.entries[typeValue] } /** @@ -246,7 +239,7 @@ class PathIterator( */ override fun next(): PathSegment { val typeValue = internalPathIteratorNext(internalPathIterator, pointsData, 0) - val type = pathSegmentTypes[typeValue] + val type = PathSegment.Type.entries[typeValue] if (type == PathSegment.Type.Done) return DoneSegment if (type == PathSegment.Type.Close) return CloseSegment @@ -255,12 +248,14 @@ class PathIterator( PathSegment.Type.Move -> { arrayOf(PointF(pointsData[0], pointsData[1])) } + PathSegment.Type.Line -> { arrayOf( PointF(pointsData[0], pointsData[1]), PointF(pointsData[2], pointsData[3]) ) } + PathSegment.Type.Quadratic, PathSegment.Type.Conic -> { arrayOf( @@ -269,6 +264,7 @@ class PathIterator( PointF(pointsData[4], pointsData[5]) ) } + PathSegment.Type.Cubic -> { arrayOf( PointF(pointsData[0], pointsData[1]), @@ -291,29 +287,22 @@ class PathIterator( } } -@Suppress("KotlinJniMissingFunction") private external fun createInternalPathIterator( path: Path, conicEvaluation: Int, tolerance: Float ): Long -@Suppress("KotlinJniMissingFunction") private external fun destroyInternalPathIterator(internalPathIterator: Long) -@Suppress("KotlinJniMissingFunction") private external fun internalPathIteratorHasNext(internalPathIterator: Long): Boolean -@Suppress("KotlinJniMissingFunction") private external fun internalPathIteratorNext( internalPathIterator: Long, points: FloatArray, offset: Int ): Int -@Suppress("KotlinJniMissingFunction") private external fun internalPathIteratorPeek(internalPathIterator: Long): Int -@Suppress("KotlinJniMissingFunction") private external fun internalPathIteratorRawSize(internalPathIterator: Long): Int -@Suppress("KotlinJniMissingFunction") private external fun internalPathIteratorSize(internalPathIterator: Long): Int