Unverified Commit 9372822b authored by Aleksandr Veselov's avatar Aleksandr Veselov Committed by GitHub

Implement Path methods (#322)

parent 73ca2ed4
......@@ -2,6 +2,7 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad
import kotlin.math.min
/**
*
......@@ -29,11 +30,17 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad
*/
class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR), Iterable<PathSegment?> {
companion object {
fun makeFromSVGString(svg: String): Path {
val res = _nMakeFromSVGString(svg)
return if (res == NullPointer) throw IllegalArgumentException("Failed to parse SVG Path string: $svg") else Path(
res
)
fun makeFromSVGString(svg: String): Path {
Stats.onNativeCall()
val result = interopScope {
_nMakeFromSVGString(toInterop(svg))
}
if (result == NullPointer) {
throw IllegalArgumentException("Failed to parse SVG Path string: $svg")
} else {
return Path(result)
}
}
/**
......@@ -140,7 +147,12 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
*/
fun convertConicToQuads(p0: Point, p1: Point, p2: Point, w: Float, pow2: Int): Array<Point> {
Stats.onNativeCall()
return _nConvertConicToQuads(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, w, pow2)
val maxResultPointCount = (1 + 2 * (1 shl pow2)) // See Skia docs
var pointCount = 0
val coords = withResult(FloatArray(maxResultPointCount * 2)) {
pointCount = _nConvertConicToQuads(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, w, pow2, it)
}
return Array(pointCount) { Point(coords[2 * it], coords[2 * it + 1]) }
}
/**
......@@ -190,13 +202,17 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
*
* @see [https://fiddle.skia.org/c/@Path_readFromMemory](https://fiddle.skia.org/c/@Path_readFromMemory)
*/
fun makeFromBytes(data: ByteArray?): Path {
fun makeFromBytes(data: ByteArray): Path {
Stats.onNativeCall()
return Path(
interopScope {
_nMakeFromBytes(toInterop(data))
}
)
val result = interopScope {
_nMakeFromBytes(toInterop(data), data.size)
}
if (result == NullPointer) {
throw IllegalArgumentException("Failed to parse serialized Path")
} else {
return Path(result)
}
}
init {
......@@ -335,10 +351,10 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
*
* @see [https://fiddle.skia.org/c/@Path_isOval](https://fiddle.skia.org/c/@Path_isOval)
*/
val isOval: Rect
val isOval: Rect?
get() = try {
Stats.onNativeCall()
_nIsOval(_ptr)
Rect.fromInteropPointerNullable { _nIsOval(_ptr, it) }
} finally {
reachabilityBarrier(this)
}
......@@ -350,10 +366,10 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
*
* @see [https://fiddle.skia.org/c/@Path_isRRect](https://fiddle.skia.org/c/@Path_isRRect)
*/
val isRRect: RRect
val isRRect: RRect?
get() = try {
Stats.onNativeCall()
_nIsRRect(_ptr)
RRect.fromInteropPointerNullable { _nIsRRect(_ptr, it) }
} finally {
reachabilityBarrier(this)
}
......@@ -444,7 +460,8 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
val isFinite: Boolean
get() = try {
Stats.onNativeCall()
_nIsFinite(_ptr)
// TODO For some reason this method returns 0 instead of false in JS target, investigate
!!_nIsFinite(_ptr)
} finally {
reachabilityBarrier(this)
}
......@@ -521,10 +538,17 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
*
* @see [https://fiddle.skia.org/c/@Path_isLine](https://fiddle.skia.org/c/@Path_isLine)
*/
val asLine: Array<Point>
val asLine: Array<Point>?
get() = try {
Stats.onNativeCall()
_nMaybeGetAsLine(_ptr)
// HACK Use a temporary Rect as a buffer to store two points
val rectBuffer = Rect.fromInteropPointerNullable { _nMaybeGetAsLine(_ptr, it) }
rectBuffer?.run {
arrayOf(
Point(left, top),
Point(right, bottom)
)
}
} finally {
reachabilityBarrier(this)
}
......@@ -561,7 +585,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
fun getPoint(index: Int): Point {
return try {
Stats.onNativeCall()
_nGetPoint(_ptr, index)
Point.fromInteropPointer { _nGetPoint(_ptr, index, it) }
} finally {
reachabilityBarrier(this)
}
......@@ -598,9 +622,22 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
*/
fun getPoints(points: Array<Point?>?, max: Int): Int {
return try {
require(if (points == null) max == 0 else true)
require(if (points == null) max == 0 else max >= 0)
Stats.onNativeCall()
_nGetPoints(_ptr, points, max)
if (points == null) {
interopScope {
_nGetPoints(_ptr, toInterop(null as FloatArray?), max)
}
} else {
var result = 0
val coords = withResult(FloatArray(max * 2)) {
result = _nGetPoints(_ptr, it, max)
}
for (i in 0 until min(max, result)) {
points[i] = Point(coords[2 * i], coords[2 * i + 1])
}
result
}
} finally {
reachabilityBarrier(this)
}
......@@ -643,7 +680,10 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
Stats.onNativeCall()
val out = if (verbs == null) null else ByteArray(max)
val count = interopScope {
_nGetVerbs(_ptr, toInterop(out), max)
val ptr = toInterop(out)
_nGetVerbs(_ptr, ptr, max).also {
out?.let { ptr.fromInterop(it) }
}
}
if (verbs != null) for (i in 0 until minOf(count, max)) verbs[i] = PathVerb.values().get(
out!![i].toInt()
......@@ -705,7 +745,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
val bounds: Rect
get() = try {
Stats.onNativeCall()
_nGetBounds(_ptr)
Rect.fromInteropPointer { _nGetBounds(_ptr, it) }
} finally {
reachabilityBarrier(this)
}
......@@ -753,7 +793,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
fun computeTightBounds(): Rect {
return try {
Stats.onNativeCall()
_nComputeTightBounds(_ptr)
Rect.fromInteropPointer { _nComputeTightBounds(_ptr, it) }
} finally {
reachabilityBarrier(this)
}
......@@ -1440,10 +1480,10 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
*
* @see [https://fiddle.skia.org/c/@Path_isRect](https://fiddle.skia.org/c/@Path_isRect)
*/
val isRect: Rect
val isRect: Rect?
get() = try {
Stats.onNativeCall()
_nIsRect(_ptr)
Rect.fromInteropPointerNullable { _nIsRect(_ptr, it) }
} finally {
reachabilityBarrier(this)
}
......@@ -1673,7 +1713,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
require(pts.size % 2 == 0) { "Expected even amount of pts, got " + pts.size }
Stats.onNativeCall()
interopScope {
_nAddPoly(_ptr, toInterop(pts), close)
_nAddPoly(_ptr, toInterop(pts), pts.size / 2, close)
}
return this
}
......@@ -1920,7 +1960,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
var lastPt: Point
get() = try {
Stats.onNativeCall()
_nGetLastPt(_ptr)
Point.fromInteropPointer { _nGetLastPt(_ptr, it) }
} finally {
reachabilityBarrier(this)
}
......@@ -2068,7 +2108,13 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
fun serializeToBytes(): ByteArray {
return try {
Stats.onNativeCall()
_nSerializeToBytes(_ptr)
val size = interopScope { _nSerializeToBytes(_ptr, toInterop(null as ByteArray?)) }
if (size == -1) {
throw Error("Path is too big")
}
withResult(ByteArray(size)) {
_nSerializeToBytes(_ptr, it)
}
} finally {
reachabilityBarrier(this)
}
......@@ -2142,7 +2188,7 @@ private external fun Path_nSwap(ptr: NativePointer, otherPtr: NativePointer)
private external fun Path_nGetGenerationId(ptr: NativePointer): Int
@ExternalSymbolName("org_jetbrains_skia_Path__1nMakeFromSVGString")
private external fun _nMakeFromSVGString(s: String?): NativePointer
private external fun _nMakeFromSVGString(svg: InteropPointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Path__1nIsInterpolatable")
private external fun _nIsInterpolatable(ptr: NativePointer, comparePtr: NativePointer): Boolean
......@@ -2160,10 +2206,10 @@ private external fun _nSetFillMode(ptr: NativePointer, fillMode: Int)
private external fun _nIsConvex(ptr: NativePointer): Boolean
@ExternalSymbolName("org_jetbrains_skia_Path__1nIsOval")
private external fun _nIsOval(ptr: NativePointer): Rect
private external fun _nIsOval(ptr: NativePointer, rect: InteropPointer): Boolean
@ExternalSymbolName("org_jetbrains_skia_Path__1nIsRRect")
private external fun _nIsRRect(ptr: NativePointer): RRect
private external fun _nIsRRect(ptr: NativePointer, rrect: InteropPointer): Boolean
@ExternalSymbolName("org_jetbrains_skia_Path__1nRewind")
private external fun _nRewind(ptr: NativePointer)
......@@ -2207,16 +2253,16 @@ private external fun _nIsCubicDegenerate(
@ExternalSymbolName("org_jetbrains_skia_Path__1nMaybeGetAsLine")
private external fun _nMaybeGetAsLine(ptr: NativePointer): Array<Point>
private external fun _nMaybeGetAsLine(ptr: NativePointer, rectBuffer: InteropPointer): Boolean
@ExternalSymbolName("org_jetbrains_skia_Path__1nGetPointsCount")
private external fun _nGetPointsCount(ptr: NativePointer): Int
@ExternalSymbolName("org_jetbrains_skia_Path__1nGetPoint")
private external fun _nGetPoint(ptr: NativePointer, index: Int): Point
private external fun _nGetPoint(ptr: NativePointer, index: Int, result: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_Path__1nGetPoints")
private external fun _nGetPoints(ptr: NativePointer, points: Array<Point?>?, max: Int): Int
private external fun _nGetPoints(ptr: NativePointer, points: InteropPointer, max: Int): Int
@ExternalSymbolName("org_jetbrains_skia_Path__1nCountVerbs")
private external fun _nCountVerbs(ptr: NativePointer): Int
......@@ -2228,13 +2274,13 @@ private external fun _nGetVerbs(ptr: NativePointer, verbs: InteropPointer, max:
private external fun _nApproximateBytesUsed(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Path__1nGetBounds")
private external fun _nGetBounds(ptr: NativePointer): Rect
private external fun _nGetBounds(ptr: NativePointer, rect: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_Path__1nUpdateBoundsCache")
private external fun _nUpdateBoundsCache(ptr: NativePointer)
@ExternalSymbolName("org_jetbrains_skia_Path__1nComputeTightBounds")
private external fun _nComputeTightBounds(ptr: NativePointer): Rect
private external fun _nComputeTightBounds(ptr: NativePointer, rect: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_Path__1nConservativelyContainsRect")
private external fun _nConservativelyContainsRect(ptr: NativePointer, l: Float, t: Float, r: Float, b: Float): Boolean
......@@ -2326,12 +2372,13 @@ private external fun _nConvertConicToQuads(
x2: Float,
y2: Float,
w: Float,
pow2: Int
): Array<Point>
pow2: Int,
result: InteropPointer
): Int
@ExternalSymbolName("org_jetbrains_skia_Path__1nIsRect")
private external fun _nIsRect(ptr: NativePointer): Rect
private external fun _nIsRect(ptr: NativePointer, rect: InteropPointer): Boolean
@ExternalSymbolName("org_jetbrains_skia_Path__1nAddRect")
private external fun _nAddRect(ptr: NativePointer, l: Float, t: Float, r: Float, b: Float, dir: Int, start: Int)
......@@ -2360,7 +2407,7 @@ private external fun _nAddRRect(
@ExternalSymbolName("org_jetbrains_skia_Path__1nAddPoly")
private external fun _nAddPoly(ptr: NativePointer, coords: InteropPointer, close: Boolean)
private external fun _nAddPoly(ptr: NativePointer, coords: InteropPointer, count: Int, close: Boolean)
@ExternalSymbolName("org_jetbrains_skia_Path__1nAddPath")
private external fun _nAddPath(ptr: NativePointer, srcPtr: NativePointer, extend: Boolean)
......@@ -2381,7 +2428,7 @@ private external fun _nOffset(ptr: NativePointer, dx: Float, dy: Float, dst: Nat
private external fun _nTransform(ptr: NativePointer, matrix: InteropPointer, dst: NativePointer, applyPerspectiveClip: Boolean)
@ExternalSymbolName("org_jetbrains_skia_Path__1nGetLastPt")
private external fun _nGetLastPt(ptr: NativePointer): Point
private external fun _nGetLastPt(ptr: NativePointer, result: InteropPointer): Boolean
@ExternalSymbolName("org_jetbrains_skia_Path__1nSetLastPt")
private external fun _nSetLastPt(ptr: NativePointer, x: Float, y: Float)
......@@ -2399,13 +2446,13 @@ private external fun _nDump(ptr: NativePointer)
private external fun _nDumpHex(ptr: NativePointer)
@ExternalSymbolName("org_jetbrains_skia_Path__1nSerializeToBytes")
private external fun _nSerializeToBytes(ptr: NativePointer): ByteArray
private external fun _nSerializeToBytes(ptr: NativePointer, dst: InteropPointer): Int
@ExternalSymbolName("org_jetbrains_skia_Path__1nMakeCombining")
private external fun _nMakeCombining(onePtr: NativePointer, twoPtr: NativePointer, op: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Path__1nMakeFromBytes")
private external fun _nMakeFromBytes(data: InteropPointer): NativePointer
private external fun _nMakeFromBytes(data: InteropPointer, size: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Path__1nIsValid")
private external fun _nIsValid(ptr: NativePointer): Boolean
\ No newline at end of file
package org.jetbrains.skia
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.withResult
class Point(val x: Float, val y: Float) {
fun offset(dx: Float, dy: Float): Point {
......@@ -59,5 +62,10 @@ class Point(val x: Float, val y: Float) {
for (i in 0 until pts.size / 2) arr[i] = Point(pts[i * 2], pts[i * 2 + 1])
return arr
}
internal fun fromInteropPointer(block: (InteropPointer) -> Unit): Point {
val result = withResult(FloatArray(2), block)
return Point(result[0], result[1])
}
}
}
\ No newline at end of file
package org.jetbrains.skia
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.withResult
import kotlin.jvm.JvmStatic
import kotlin.math.abs
......@@ -32,14 +34,18 @@ class RRect internal constructor(l: Float, t: Float, r: Float, b: Float, val rad
}
override fun toString(): String {
return "RRect(_left=$left, _top=$top, _right=$right, _bottom=$bottom, _radii=$radii)"
return "RRect(_left=$left, _top=$top, _right=$right, _bottom=$bottom, _radii=${radii.joinToString()})"
}
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is RRect) return false
if (!super.equals(other)) return false
return radii.contentEquals(other.radii)
return if (radii.size == other.radii.size) {
radii.contentEquals(other.radii)
} else {
normalizeRadii(radii).contentEquals(normalizeRadii(other.radii))
}
}
override fun hashCode(): Int {
......@@ -146,5 +152,27 @@ class RRect internal constructor(l: Float, t: Float, r: Float, b: Float, val rad
fun makePillXYWH(l: Float, t: Float, w: Float, h: Float): RRect {
return RRect(l, t, l + w, t + h, floatArrayOf(minOf(w, h) / 2.0f))
}
internal fun fromInteropPointer(block: (InteropPointer) -> Unit): RRect {
val result = withResult(FloatArray(12 /* 4 dimensions + 4 radii * 2 */), block)
return RRect(result[0], result[1], result[2], result[3], result.copyOfRange(4, 12))
}
internal fun fromInteropPointerNullable(block: (InteropPointer) -> Boolean): RRect? {
var result = true
val rect = fromInteropPointer { result = block(it) }
return if (result) { rect } else { null }
}
}
}
private fun normalizeRadii(radii: FloatArray): FloatArray {
return when (radii.size) {
0 -> FloatArray(8) { 0.0f }
1 -> FloatArray(8) { radii[0] } // All are the same
2 -> FloatArray(8) { radii[it % 2] } // Corresponding values are same for each corner
4 -> FloatArray(8) { radii[it / 2] } // Horizontal and vertical are same for each corner
8 -> radii
else -> throw Error("illegal radii array")
}
}
\ No newline at end of file
package org.jetbrains.skia
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.withResult
import kotlin.jvm.JvmStatic
open class Rect constructor(val left: Float, val top: Float, val right: Float, val bottom: Float) {
......@@ -103,5 +105,16 @@ open class Rect constructor(val left: Float, val top: Float, val right: Float, v
require(h >= 0) { "Rect::makeXYWH expected h >= 0, got: $h" }
return Rect(l, t, l + w, t + h)
}
internal fun fromInteropPointer(block: (InteropPointer) -> Unit): Rect {
val result = withResult(FloatArray(4), block)
return Rect(result[0], result[1], result[2], result[3])
}
internal fun fromInteropPointerNullable(block: (InteropPointer) -> Boolean): Rect? {
var result = true
val rect = fromInteropPointer { result = block(it) }
return if (result) { rect } else { null }
}
}
}
\ No newline at end of file
package org.jetbrains.skiko
package org.jetbrains.skia
import org.jetbrains.skia.Path
import org.jetbrains.skia.PathSegmentMask
import org.jetbrains.skia.PathVerb
import org.jetbrains.skia.Point
import org.jetbrains.skia.impl.Native.Companion.NullPointer
import org.jetbrains.skia.tests.assertCloseEnough
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
......@@ -83,9 +81,16 @@ class PathTest {
null
), verbs
)
assertNotEquals(0L, p.approximateBytesUsed)
assertNotEquals(NullPointer, p.approximateBytesUsed)
assertEquals(PathSegmentMask.LINE, p.segmentMasks)
}
}
@Test
fun canGetBounds() {
val path = Path().lineTo(40f, 40f).lineTo(40f, 0f).lineTo(0f, 40f).lineTo(0f, 0f).closePath()
val bounds = Rect(0.0f, 0.0f, 40.0f, 40.0f)
assertCloseEnough(bounds, path.bounds)
assertCloseEnough(bounds, path.computeTightBounds())
}
}
\ No newline at end of file
package org.jetbrains.skia
import org.jetbrains.skia.impl.use
import org.jetbrains.skiko.tests.SkipJsTarget
import org.jetbrains.skiko.tests.SkipNativeTarget
import org.jetbrains.skia.tests.assertContentCloseEnough
import kotlin.test.Test
import kotlin.test.assertTrue
import kotlin.test.assertFalse
......@@ -69,8 +68,6 @@ class PathTests {
@Test
@SkipJsTarget
@SkipNativeTarget
fun isShapeTest() {
for (dir in PathDirection.values()) {
for (start in 0..3) {
......@@ -124,8 +121,6 @@ class PathTests {
}
@Test
@SkipJsTarget
@SkipNativeTarget
fun checksTest() {
Path().lineTo(40f, 40f).lineTo(40f, 0f).lineTo(0f, 40f).lineTo(0f, 0f).closePath().use { p ->
assertFalse(p.isEmpty)
......@@ -174,8 +169,6 @@ class PathTests {
}
@Test
@SkipJsTarget
@SkipNativeTarget
fun swapTest() {
Path().lineTo(40f, 40f).lineTo(40f, 0f).lineTo(0f, 40f).lineTo(0f, 0f).closePath().use { p1 ->
Path().lineTo(0f, 0f).lineTo(20f, 20f).use { p2 ->
......@@ -187,8 +180,6 @@ class PathTests {
}
@Test
@SkipJsTarget
@SkipNativeTarget
fun containsTest() {
Path().addRRect(RRect.makeLTRB(10f, 20f, 54f, 120f, 10f, 20f)).use { p ->
assertTrue(p.conservativelyContainsRect(Rect.makeLTRB(10f, 40f, 54f, 80f)))
......@@ -202,8 +193,6 @@ class PathTests {
}
@Test
@SkipJsTarget
@SkipNativeTarget
fun utilsTest() {
assertFalse(Path.isLineDegenerate(Point(0f, 0f), Point(10f, 0f), false))
assertTrue(Path.isLineDegenerate(Point(0f, 0f), Point(0f, 0f), true))
......@@ -213,11 +202,11 @@ class PathTests {
assertTrue(Path.isQuadDegenerate(Point(0f, 0f), Point(0f, 0f), Point(0f, 0f), false))
assertFalse(Path.isCubicDegenerate(Point(0f, 0f), Point(10f, 0f), Point(0f, 0f), Point(0f, 0f), false))
assertTrue(Path.isCubicDegenerate(Point(0f, 0f), Point(0f, 0f), Point(0f, 0f), Point(0f, 0f), false))
assertContentEquals(
assertContentCloseEnough(
arrayOf(Point(0f, 20f), Point(6.666667f, 13.333334f)),
Path.convertConicToQuads(Point(0f, 20f), Point(20f, 0f), Point(40f, 20f), 0.5f, 1)
)
assertContentEquals(
assertContentCloseEnough(
arrayOf(
Point(0f, 20f),
Point(3.0940108f, 16.905989f),
......@@ -238,12 +227,15 @@ class PathTests {
}
@Test
@SkipJsTarget
@SkipNativeTarget
fun serializeTest() {
Path().lineTo(40f, 40f).lineTo(40f, 0f).lineTo(0f, 40f).lineTo(0f, 0f).closePath().use { p ->
val p2: Path = Path.makeFromBytes(p.serializeToBytes())
assertEquals(p, p2)
}
}
@Test
fun svgTest() {
Path.makeFromSVGString("M0 0 L10 10 Z").use { }
}
}
\ No newline at end of file
......@@ -3,7 +3,9 @@ package org.jetbrains.skia.tests
import org.jetbrains.skia.Color4f
import org.jetbrains.skia.Matrix33
import org.jetbrains.skia.Point
import org.jetbrains.skia.Rect
import kotlin.math.abs
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
private const val EPSILON = 0.00001f
......@@ -21,10 +23,39 @@ internal fun assertCloseEnough(expected: Matrix33, actual: Matrix33?, epsilon: F
expected.mat.zip(actual!!.mat).forEach { (a, b) -> assertCloseEnough(a, b, epsilon) }
}
internal fun assertCloseEnough(expected: Color4f, actual: Color4f?, epsilon: Float = EPSILON) {
assertCloseEnough(expected.r, actual!!.r, epsilon)
assertCloseEnough(expected.g, actual.g, epsilon)
assertCloseEnough(expected.b, actual.b, epsilon)
assertCloseEnough(expected.a, actual.a, epsilon)
}
\ No newline at end of file
}
internal fun assertCloseEnough(expected: Rect, actual: Rect?, epsilon: Float = EPSILON) {
assertCloseEnough(expected.left, actual!!.left, epsilon)
assertCloseEnough(expected.top, actual.top, epsilon)
assertCloseEnough(expected.right, actual.right, epsilon)
assertCloseEnough(expected.bottom, actual.bottom, epsilon)
}
internal fun assertContentCloseEnough(expected: FloatArray, actual: FloatArray?, epsilon: Float = EPSILON) {
if (actual == null) {
throw AssertionError("expected $expected, got null")
}
for (i in expected.indices) {
if (abs(expected[i] - actual[i]) > epsilon) {
throw AssertionError("results differ at index$i, expected ${expected[i]}, got ${actual[i]}")
}
}
}
internal fun assertContentCloseEnough(expected: Array<Point>, actual: Array<Point>?, epsilon: Float = EPSILON) {
assertNotNull(actual)
for (i in expected.indices) {
try {
assertCloseEnough(expected[i], actual[i], epsilon)
} catch (e: AssertionError) {
throw AssertionError("results differ at index $i, ${e.message}")
}
}
}
......@@ -2,6 +2,7 @@
#include <cfloat>
#include <iostream>
#include <vector>
#include <limits>
#include <jni.h>
#include "SkPath.h"
#include "SkPathOps.h"
......@@ -73,22 +74,26 @@ extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_PathKt__1nIsConvex
return instance->isConvex();
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_PathKt__1nIsOval(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_PathKt__1nIsOval(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
SkRect bounds;
if (instance->isOval(&bounds))
return skija::Rect::fromSkRect(env, bounds);
else
return nullptr;
if (instance->isOval(&bounds)) {
skija::Rect::copyToInterop(env, bounds, resultArray);
return true;
} else {
return false;
}
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_PathKt__1nIsRRect(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_PathKt__1nIsRRect(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
SkRRect rrect;
if (instance->isRRect(&rrect))
return skija::RRect::fromSkRRect(env, rrect);
else
return nullptr;
if (instance->isRRect(&rrect)) {
skija::RRect::copyToInterop(env, rrect, resultArray);
return true;
} else {
return false;
}
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt_Path_1nReset(JNIEnv* env, jclass jclass, jlong ptr) {
......@@ -138,16 +143,16 @@ extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_PathKt__1nIsCubicD
return SkPath::IsCubicDegenerate({x0, y0}, {x1, y1}, {x2, y2}, {x3, y3}, exact);
}
extern "C" JNIEXPORT jobjectArray JNICALL Java_org_jetbrains_skia_PathKt__1nMaybeGetAsLine(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_PathKt__1nMaybeGetAsLine(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
SkPoint line[2];
if (instance->isLine(line)) {
jobjectArray res = env->NewObjectArray(2, skija::Point::cls, nullptr);
env->SetObjectArrayElement(res, 0, skija::Point::fromSkPoint(env, line[0]));
env->SetObjectArrayElement(res, 1, skija::Point::fromSkPoint(env, line[1]));
return res;
} else
return nullptr;
SkRect rect = SkRect::MakeLTRB(line[0].x(), line[0].y(), line[1].x(), line[1].y());
skija::Rect::copyToInterop(env, rect, resultArray);
return true;
} else {
return false;
}
}
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_PathKt__1nGetPointsCount(JNIEnv* env, jclass jclass, jlong ptr) {
......@@ -155,18 +160,18 @@ extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_PathKt__1nGetPointsCou
return instance->countPoints();
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_PathKt__1nGetPoint(JNIEnv* env, jclass jclass, jlong ptr, jint index) {
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nGetPoint(JNIEnv* env, jclass jclass, jlong ptr, jint index, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
SkPoint p = instance->getPoint(index);
return skija::Point::fromSkPoint(env, p);
skija::Point::copyToInterop(env, instance->getPoint(index), resultArray);
}
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_PathKt__1nGetPoints(JNIEnv* env, jclass jclass, jlong ptr, jobjectArray pointsArray, jint max) {
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_PathKt__1nGetPoints(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray pointsArray, jint max) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
std::vector<SkPoint> p(std::min<jint>(max, instance->countPoints()));
int count = instance->getPoints(p.data(), max);
for (int i = 0; i < max && i < count; ++ i)
env->SetObjectArrayElement(pointsArray, i, skija::Point::fromSkPoint(env, p[i]));
jfloat* points = pointsArray == nullptr ? nullptr : env->GetFloatArrayElements(pointsArray, 0);
int count = instance->getPoints(reinterpret_cast<SkPoint*>(points), max);
if (pointsArray != nullptr) {
env->ReleaseFloatArrayElements(pointsArray, points, 0);
}
return count;
}
......@@ -195,9 +200,9 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt_Path_1nSwap(JNI
instance->swap(*other);
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_PathKt__1nGetBounds(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nGetBounds(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
return skija::Rect::fromSkRect(env, instance->getBounds());
skija::Rect::copyToInterop(env, instance->getBounds(), resultArray);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nUpdateBoundsCache(JNIEnv* env, jclass jclass, jlong ptr) {
......@@ -205,9 +210,9 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nUpdateBounds
instance->updateBoundsCache();
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_PathKt__1nComputeTightBounds(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nComputeTightBounds(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
return skija::Rect::fromSkRect(env, instance->computeTightBounds());
skija::Rect::copyToInterop(env, instance->computeTightBounds(), resultArray);
}
extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_PathKt__1nConservativelyContainsRect(JNIEnv* env, jclass jclass, jlong ptr, float l, float t, float r, float b) {
......@@ -296,25 +301,24 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nClosePath(JN
instance->close();
}
extern "C" JNIEXPORT jobjectArray Java_org_jetbrains_skia_PathKt__1nConvertConicToQuads
(JNIEnv* env, jclass jclass, jfloat x0, jfloat y0, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat w, jint pow2) {
std::vector<SkPoint> pts(1 + 2 * (1 << pow2));
int count = SkPath::ConvertConicToQuads({x0, y0}, {x1, y1}, {x2, y2}, w, pts.data(), pow2);
jobjectArray res = env->NewObjectArray(count, skija::Point::cls, nullptr);
for (int i = 0; i < count; ++i) {
env->SetObjectArrayElement(res, i, skija::Point::fromSkPoint(env, pts[i]));
}
return res;
extern "C" JNIEXPORT jint Java_org_jetbrains_skia_PathKt__1nConvertConicToQuads
(JNIEnv* env, jclass jclass, jfloat x0, jfloat y0, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat w, jint pow2, jfloatArray resultArray) {
jfloat* points = env->GetFloatArrayElements(resultArray, 0);
int count = SkPath::ConvertConicToQuads({x0, y0}, {x1, y1}, {x2, y2}, w, reinterpret_cast<SkPoint*>(points), pow2);
env->ReleaseFloatArrayElements(resultArray, points, 0);
return count;
}
extern "C" JNIEXPORT jobject Java_org_jetbrains_skia_PathKt__1nIsRect
(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT jboolean Java_org_jetbrains_skia_PathKt__1nIsRect
(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
SkRect rect;
if (instance->isRect(&rect))
return skija::Rect::fromSkRect(env, rect);
else
return nullptr;
if (instance->isRect(&rect)) {
skija::Rect::copyToInterop(env, rect, resultArray);
return true;
} else {
return false;
}
}
extern "C" JNIEXPORT void Java_org_jetbrains_skia_PathKt__1nAddRect
......@@ -353,7 +357,7 @@ extern "C" JNIEXPORT void Java_org_jetbrains_skia_PathKt__1nAddRRect
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nAddPoly
(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray coords, jboolean close) {
(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray coords, jint _count, jboolean close) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
jsize len = env->GetArrayLength(coords);
jfloat* arr = env->GetFloatArrayElements(coords, 0);
......@@ -409,14 +413,16 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nTransform
instance->transform(*matrix, dst, pc);
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_PathKt__1nGetLastPt
(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_PathKt__1nGetLastPt
(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
SkPoint out;
if (instance->getLastPt(&out))
return skija::Point::fromSkPoint(env, out);
else
return nullptr;
if (instance->getLastPt(&out)) {
skija::Point::copyToInterop(env, out, resultArray);
return true;
} else {
return false;
}
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nSetLastPt
......@@ -449,15 +455,20 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PathKt__1nDumpHex
instance->dumpHex();
}
extern "C" JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_skia_PathKt__1nSerializeToBytes
(JNIEnv* env, jclass jclass, jlong ptr) {
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_PathKt__1nSerializeToBytes
(JNIEnv* env, jclass jclass, jlong ptr, jbyteArray dstArray) {
SkPath* instance = reinterpret_cast<SkPath*>(static_cast<uintptr_t>(ptr));
size_t count = instance->writeToMemory(nullptr);
jbyteArray bytesArray = env->NewByteArray((jsize) count);
jbyte* bytes = env->GetByteArrayElements(bytesArray, 0);
instance->writeToMemory(bytes);
env->ReleaseByteArrayElements(bytesArray, bytes, 0);
return bytesArray;
jbyte* dst = dstArray == nullptr ? nullptr : env->GetByteArrayElements(dstArray, 0);
size_t count = instance->writeToMemory(reinterpret_cast<void*>(dst));
if (dst != nullptr) {
env->ReleaseByteArrayElements(dstArray, dst, 0);
}
if (count > std::numeric_limits<jint>::max()) {
return -1;
} else {
return count;
}
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_PathKt__1nMakeCombining
......@@ -473,7 +484,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_PathKt__1nMakeCombini
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_PathKt__1nMakeFromBytes
(JNIEnv* env, jclass jclass, jbyteArray bytesArray) {
(JNIEnv* env, jclass jclass, jbyteArray bytesArray, jint _size) {
SkPath* instance = new SkPath();
int count = env->GetArrayLength(bytesArray);
jbyte* bytes = env->GetByteArrayElements(bytesArray, 0);
......
......@@ -579,6 +579,15 @@ namespace skija {
}
return res;
}
void copyToInterop(JNIEnv* env, const SkPoint& point, jfloatArray pointer) {
jfloat* xy = pointer == nullptr ? nullptr : env->GetFloatArrayElements(pointer, 0);
if (xy != nullptr) {
xy[0] = point.x();
xy[1] = point.y();
env->ReleaseFloatArrayElements(pointer, xy, 0);
}
}
}
namespace PaintFilterCanvas {
......@@ -659,6 +668,17 @@ namespace skija {
jobject fromSkRect(JNIEnv* env, const SkRect& rect) {
return fromLTRB(env, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
}
void copyToInterop(JNIEnv* env, const SkRect& rect, jfloatArray pointer) {
jfloat* ltrb = pointer == nullptr ? nullptr : env->GetFloatArrayElements(pointer, 0);
if (ltrb != nullptr) {
ltrb[0] = rect.left();
ltrb[1] = rect.top();
ltrb[2] = rect.right();
ltrb[3] = rect.bottom();
env->ReleaseFloatArrayElements(pointer, ltrb, 0);
}
}
}
namespace RRect {
......@@ -761,6 +781,27 @@ namespace skija {
return nullptr;
}
void copyToInterop(JNIEnv* env, const SkRRect& rect, jfloatArray pointer) {
jfloat* ltrb = pointer == nullptr ? nullptr : env->GetFloatArrayElements(pointer, 0);
if (ltrb != nullptr) {
ltrb[0] = rect.rect().left();
ltrb[1] = rect.rect().top();
ltrb[2] = rect.rect().right();
ltrb[3] = rect.rect().bottom();
ltrb[4] = rect.radii(SkRRect::kUpperLeft_Corner).x();
ltrb[5] = rect.radii(SkRRect::kUpperLeft_Corner).y();
ltrb[6] = rect.radii(SkRRect::kUpperRight_Corner).x();
ltrb[7] = rect.radii(SkRRect::kUpperRight_Corner).y();
ltrb[8] = rect.radii(SkRRect::kLowerRight_Corner).x();
ltrb[9] = rect.radii(SkRRect::kLowerRight_Corner).y();
ltrb[10] = rect.radii(SkRRect::kLowerLeft_Corner).x();
ltrb[11] = rect.radii(SkRRect::kLowerLeft_Corner).y();
env->ReleaseFloatArrayElements(pointer, ltrb, 0);
}
}
}
namespace RSXform {
......
......@@ -250,6 +250,8 @@ namespace skija {
jobject make(JNIEnv* env, float x, float y);
jobject fromSkPoint(JNIEnv* env, const SkPoint& p);
jobjectArray fromSkPoints(JNIEnv* env, const std::vector<SkPoint>& ps);
void copyToInterop(JNIEnv* env, const SkPoint& point, jfloatArray pointer);
}
namespace PaintFilterCanvas {
......@@ -273,6 +275,8 @@ namespace skija {
std::unique_ptr<SkRect> toSkRect(JNIEnv* env, jobject rect);
jobject fromLTRB(JNIEnv* env, float left, float top, float right, float bottom);
jobject fromSkRect(JNIEnv* env, const SkRect& rect);
void copyToInterop(JNIEnv* env, const SkRect& rect, jfloatArray pointer);
}
namespace RRect {
......@@ -291,6 +295,8 @@ namespace skija {
void onUnload(JNIEnv* env);
SkRRect toSkRRect(JNIEnv* env, jfloat left, jfloat top, jfloat right, jfloat bottom, jfloatArray jradii);
jobject fromSkRRect(JNIEnv* env, const SkRRect& rect);
void copyToInterop(JNIEnv* env, const SkRRect& rect, jfloatArray pointer);
}
namespace RSXform {
......
......@@ -5,6 +5,7 @@
#include <cfloat>
#include <iostream>
#include <vector>
#include <limits>
#include "SkPath.h"
#include "SkPathOps.h"
#include "include/utils/SkParsePath.h"
......@@ -24,16 +25,10 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMake() {
return reinterpret_cast<KNativePointer>(obj);
}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMakeFromSVGString
(KInteropPointer d) {
TODO("implement org_jetbrains_skia_Path__1nMakeFromSVGString");
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMakeFromSVGString
(KInteropPointer d) {
SkPath* obj = new SkPath();
SkString s = skString(env, d);
SkString s = skString(d);
if (SkParsePath::FromSVGString(s.c_str(), obj))
return reinterpret_cast<KNativePointer>(obj);
else {
......@@ -41,8 +36,6 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMakeFromSVGString
return 0;
}
}
#endif
SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nEquals(KNativePointer aPtr, KNativePointer bPtr) {
SkPath* a = reinterpret_cast<SkPath*>((aPtr));
......@@ -84,37 +77,27 @@ SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nIsConvex(KNativePointer ptr) {
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nIsOval(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nIsOval(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nIsOval(KNativePointer ptr) {
SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nIsOval(KNativePointer ptr, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkRect bounds;
if (instance->isOval(&bounds))
return skija::Rect::fromSkRect(env, bounds);
else
return nullptr;
if (instance->isOval(&bounds)) {
skija::Rect::copyToInterop(bounds, resultArray);
return true;
} else {
return false;
}
}
#endif
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nIsRRect(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nIsRRect(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nIsRRect(KNativePointer ptr) {
SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nIsRRect(KNativePointer ptr, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkRRect rrect;
if (instance->isRRect(&rrect))
return skija::RRect::fromSkRRect(env, rrect);
else
return nullptr;
if (instance->isRRect(&rrect)) {
skija::RRect::copyToInterop(rrect, resultArray);
return true;
} else {
return false;
}
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Path__1nReset(KNativePointer ptr) {
......@@ -165,23 +148,17 @@ SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nIsCubicDegenerate(KFloat x0, KF
}
SKIKO_EXPORT KInteropPointerArray org_jetbrains_skia_Path__1nMaybeGetAsLine(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nMaybeGetAsLine(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInteropPointerArray org_jetbrains_skia_Path__1nMaybeGetAsLine(KNativePointer ptr) {
SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nMaybeGetAsLine(KNativePointer ptr, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkPoint line[2];
if (instance->isLine(line)) {
KInteropPointerArray res = env->NewObjectArray(2, skija::Point::cls, nullptr);
env->SetObjectArrayElement(res, 0, skija::Point::fromSkPoint(env, line[0]));
env->SetObjectArrayElement(res, 1, skija::Point::fromSkPoint(env, line[1]));
return res;
} else
return nullptr;
SkRect rect = SkRect::MakeLTRB(line[0].x(), line[0].y(), line[1].x(), line[1].y());
skija::Rect::copyToInterop(rect, resultArray);
return true;
} else {
return false;
}
}
#endif
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetPointsCount(KNativePointer ptr) {
......@@ -189,56 +166,26 @@ SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetPointsCount(KNativePointer ptr)
return instance->countPoints();
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nGetPoint(KNativePointer ptr, KInt index) {
TODO("implement org_jetbrains_skia_Path__1nGetPoint(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nGetPoint(KNativePointer ptr, KInt index) {
SKIKO_EXPORT void org_jetbrains_skia_Path__1nGetPoint(KNativePointer ptr, KInt index, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkPoint p = instance->getPoint(index);
return skija::Point::fromSkPoint(env, p);
skija::Point::copyToInterop(instance->getPoint(index), resultArray);
}
#endif
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetPoints(KNativePointer ptr, KInteropPointerArray pointsArray, KInt max) {
TODO("implement org_jetbrains_skia_Path__1nGetPoints(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetPoints(KNativePointer ptr, KInteropPointerArray pointsArray, KInt max) {
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetPoints(KNativePointer ptr, KInteropPointer pointsArray, KInt max) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
std::vector<SkPoint> p(std::min<KInt>(max, instance->countPoints()));
int count = instance->getPoints(p.data(), max);
for (int i = 0; i < max && i < count; ++ i)
env->SetObjectArrayElement(pointsArray, i, skija::Point::fromSkPoint(env, p[i]));
return count;
SkPoint* points = reinterpret_cast<SkPoint*>(pointsArray);
return instance->getPoints(points, max);
}
#endif
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nCountVerbs(KNativePointer ptr) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
return instance->countVerbs();
}
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetVerbs(KNativePointer ptr, KByte* verbsArray, KInt max) {
TODO("implement org_jetbrains_skia_Path__1nGetVerbs(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetVerbs(KNativePointer ptr, KByte* verbsArray, KInt max) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
KByte* verbs = verbsArray == nullptr ? nullptr : env->GetByteArrayElements(verbsArray, 0);
int count = instance->getVerbs(reinterpret_cast<uint8_t *>(verbs), max);
if (verbsArray != nullptr)
env->ReleaseByteArrayElements(verbsArray, verbs, 0);
return count;
return instance->getVerbs(reinterpret_cast<uint8_t *>(verbsArray), max);
}
#endif
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nApproximateBytesUsed(KNativePointer ptr) {
......@@ -252,36 +199,22 @@ SKIKO_EXPORT void org_jetbrains_skia_Path__1nSwap(KNativePointer ptr, KNativePoi
instance->swap(*other);
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nGetBounds(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nGetBounds(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nGetBounds(KNativePointer ptr) {
SKIKO_EXPORT void org_jetbrains_skia_Path__1nGetBounds(KNativePointer ptr, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
return skija::Rect::fromSkRect(env, instance->getBounds());
SkRect bounds = instance->getBounds();
skija::Rect::copyToInterop(bounds, resultArray);
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Path__1nUpdateBoundsCache(KNativePointer ptr) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
instance->updateBoundsCache();
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nComputeTightBounds(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nComputeTightBounds(KInteropPointer");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nComputeTightBounds(KNativePointer ptr) {
SKIKO_EXPORT void org_jetbrains_skia_Path__1nComputeTightBounds(KNativePointer ptr, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
return skija::Rect::fromSkRect(env, instance->computeTightBounds());
SkRect bounds = instance->computeTightBounds();
skija::Rect::copyToInterop(bounds, resultArray);
}
#endif
SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nConservativelyContainsRect(KNativePointer ptr, float l, float t, float r, float b) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
......@@ -370,42 +303,24 @@ SKIKO_EXPORT void org_jetbrains_skia_Path__1nClosePath(KNativePointer ptr) {
}
SKIKO_EXPORT KInteropPointerArray org_jetbrains_skia_Path__1nConvertConicToQuads
(KFloat x0, KFloat y0, KFloat x1, KFloat y1, KFloat x2, KFloat y2, KFloat w, KInt pow2) {
TODO("implement org_jetbrains_skia_Path__1nConvertConicToQuads");
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nConvertConicToQuads
(KFloat x0, KFloat y0, KFloat x1, KFloat y1, KFloat x2, KFloat y2, KFloat w, KInt pow2, KInteropPointer resultArray) {
SkPoint* result = reinterpret_cast<SkPoint*>(resultArray);
return SkPath::ConvertConicToQuads({x0, y0}, {x1, y1}, {x2, y2}, w, result, pow2);
}
#if 0
SKIKO_EXPORT KInteropPointerArray org_jetbrains_skia_Path__1nConvertConicToQuads
(KFloat x0, KFloat y0, KFloat x1, KFloat y1, KFloat x2, KFloat y2, KFloat w, KInt pow2) {
std::vector<SkPoint> pts(1 + 2 * (1 << pow2));
int count = SkPath::ConvertConicToQuads({x0, y0}, {x1, y1}, {x2, y2}, w, pts.data(), pow2);
KInteropPointerArray res = env->NewObjectArray(count, skija::Point::cls, nullptr);
for (int i = 0; i < count; ++i) {
env->SetObjectArrayElement(res, i, skija::Point::fromSkPoint(env, pts[i]));
}
return res;
}
#endif
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nIsRect
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nIsRect");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nIsRect
(KNativePointer ptr) {
SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nIsRect
(KNativePointer ptr, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkRect rect;
if (instance->isRect(&rect))
return skija::Rect::fromSkRect(env, rect);
else
return nullptr;
if (instance->isRect(&rect)) {
skija::Rect::copyToInterop(rect, resultArray);
return true;
} else {
return false;
}
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddRect
......@@ -444,20 +359,10 @@ SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddRRect
}
SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddPoly
(KNativePointer ptr, KFloat* coords, KBoolean close) {
TODO("implement org_jetbrains_skia_Path__1nAddPoly");
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddPoly
(KNativePointer ptr, KFloat* coords, KBoolean close) {
(KNativePointer ptr, KFloat* coords, KInt count, KBoolean close) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
jsize len = env->GetArrayLength(coords);
KFloat* arr = env->GetFloatArrayElements(coords, 0);
instance->addPoly(reinterpret_cast<SkPoint*>(arr), len / 2, close);
env->ReleaseFloatArrayElements(coords, arr, 0);
instance->addPoly(reinterpret_cast<SkPoint*>(coords), count, close);
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddPath
......@@ -477,21 +382,14 @@ SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddPathOffset
}
SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddPathTransform
(KNativePointer ptr, KNativePointer srcPtr, KFloat* matrixArr, KBoolean extend) {
TODO("implement org_jetbrains_skia_Path__1nAddPathTransform");
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Path__1nAddPathTransform
(KNativePointer ptr, KNativePointer srcPtr, KFloat* matrixArr, KBoolean extend) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkPath* src = reinterpret_cast<SkPath*>((srcPtr));
std::unique_ptr<SkMatrix> matrix = skMatrix(env, matrixArr);
std::unique_ptr<SkMatrix> matrix = skMatrix(matrixArr);
SkPath::AddPathMode mode = extend ? SkPath::AddPathMode::kExtend_AddPathMode : SkPath::AddPathMode::kAppend_AddPathMode;
instance->addPath(*src, *matrix, mode);
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Path__1nReverseAddPath
......@@ -509,40 +407,27 @@ SKIKO_EXPORT void org_jetbrains_skia_Path__1nOffset
}
SKIKO_EXPORT void org_jetbrains_skia_Path__1nTransform
(KNativePointer ptr, KFloat* matrixArr, KNativePointer dstPtr, KBoolean pcBool) {
TODO("implement org_jetbrains_skia_Path__1nTransform");
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Path__1nTransform
(KNativePointer ptr, KFloat* matrixArr, KNativePointer dstPtr, KBoolean pcBool) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkPath* dst = reinterpret_cast<SkPath*>((dstPtr));
std::unique_ptr<SkMatrix> matrix = skMatrix(env, matrixArr);
std::unique_ptr<SkMatrix> matrix = skMatrix(matrixArr);
SkApplyPerspectiveClip pc = pcBool ? SkApplyPerspectiveClip::kYes : SkApplyPerspectiveClip::kNo;
instance->transform(*matrix, dst, pc);
}
#endif
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nGetLastPt
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nGetLastPt");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Path__1nGetLastPt
(KNativePointer ptr) {
SKIKO_EXPORT KBoolean org_jetbrains_skia_Path__1nGetLastPt
(KNativePointer ptr, KInteropPointer resultArray) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
SkPoint out;
if (instance->getLastPt(&out))
return skija::Point::fromSkPoint(env, out);
else
return nullptr;
if (instance->getLastPt(&out)) {
skija::Point::copyToInterop(out, resultArray);
return true;
} else {
return false;
}
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Path__1nSetLastPt
......@@ -576,23 +461,16 @@ SKIKO_EXPORT void org_jetbrains_skia_Path__1nDumpHex
}
SKIKO_EXPORT KByte* org_jetbrains_skia_Path__1nSerializeToBytes
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Path__1nSerializeToBytes");
}
#if 0
SKIKO_EXPORT KByte* org_jetbrains_skia_Path__1nSerializeToBytes
(KNativePointer ptr) {
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nSerializeToBytes
(KNativePointer ptr, KInteropPointer dst) {
SkPath* instance = reinterpret_cast<SkPath*>((ptr));
size_t count = instance->writeToMemory(nullptr);
KByte* bytesArray = env->NewByteArray((jsize) count);
KByte* bytes = env->GetByteArrayElements(bytesArray, 0);
instance->writeToMemory(bytes);
env->ReleaseByteArrayElements(bytesArray, bytes, 0);
return bytesArray;
size_t count = instance->writeToMemory(reinterpret_cast<void*>(dst));
if (count > std::numeric_limits<KInt>::max()) {
return -1;
} else {
return count;
}
}
#endif
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMakeCombining
......@@ -609,26 +487,16 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMakeCombining
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMakeFromBytes
(KByte* bytesArray) {
TODO("implement org_jetbrains_skia_Path__1nMakeFromBytes");
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Path__1nMakeFromBytes
(KByte* bytesArray) {
(KByte* bytesArray, KInt size) {
SkPath* instance = new SkPath();
int count = env->GetArrayLength(bytesArray);
KByte* bytes = env->GetByteArrayElements(bytesArray, 0);
if (instance->readFromMemory(bytes, count)) {
env->ReleaseByteArrayElements(bytesArray, bytes, 0);
void* bytes = reinterpret_cast<void*>(bytesArray);
if (instance->readFromMemory(bytes, size)) {
return reinterpret_cast<KNativePointer>(instance);
} else {
env->ReleaseByteArrayElements(bytesArray, bytes, 0);
delete instance;
return 0;
}
}
#endif
SKIKO_EXPORT KInt org_jetbrains_skia_Path__1nGetGenerationId
......
......@@ -49,6 +49,18 @@ namespace skija {
uint32_t from8To16(size_t i8);
};
namespace Rect {
void copyToInterop(const SkRect& rect, KInteropPointer pointer);
}
namespace RRect {
void copyToInterop(const SkRRect& rect, KInteropPointer pointer);
}
namespace Point {
void copyToInterop(const SkPoint& rect, KInteropPointer pointer);
}
namespace RRect {
SkRRect toSkRRect(KFloat left, KFloat top, KFloat right, KFloat bottom, KFloat* jradii, KInt size);
}
......
......@@ -175,6 +175,48 @@ std::vector<SkString> skStringVector(KInteropPointerArray arr, KInt len) {
}
namespace skija {
namespace Rect {
void copyToInterop(const SkRect& rect, KInteropPointer pointer) {
float* ltrb = reinterpret_cast<float*>(pointer);
if (ltrb != nullptr) {
ltrb[0] = rect.left();
ltrb[1] = rect.top();
ltrb[2] = rect.right();
ltrb[3] = rect.bottom();
}
}
}
namespace RRect {
void copyToInterop(const SkRRect& rect, KInteropPointer pointer) {
float* ltrb = reinterpret_cast<float*>(pointer);
if (ltrb != nullptr) {
ltrb[0] = rect.rect().left();
ltrb[1] = rect.rect().top();
ltrb[2] = rect.rect().right();
ltrb[3] = rect.rect().bottom();
ltrb[4] = rect.radii(SkRRect::kUpperLeft_Corner).x();
ltrb[5] = rect.radii(SkRRect::kUpperLeft_Corner).y();
ltrb[6] = rect.radii(SkRRect::kUpperRight_Corner).x();
ltrb[7] = rect.radii(SkRRect::kUpperRight_Corner).y();
ltrb[8] = rect.radii(SkRRect::kLowerRight_Corner).x();
ltrb[9] = rect.radii(SkRRect::kLowerRight_Corner).y();
ltrb[10] = rect.radii(SkRRect::kLowerLeft_Corner).x();
ltrb[11] = rect.radii(SkRRect::kLowerLeft_Corner).y();
}
}
}
namespace Point {
void copyToInterop(const SkPoint& point, KInteropPointer pointer) {
float* xy = reinterpret_cast<float*>(pointer);
if (xy != nullptr) {
xy[0] = point.x();
xy[1] = point.y();
}
}
}
namespace RRect {
SkRRect toSkRRect(KFloat left, KFloat top, KFloat right, KFloat bottom, KFloat* radii, KInt radiiSize) {
SkRect rect {left, top, right, bottom};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment