Unverified Commit e3c7bea1 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

Cleanup, fix JNI names, add tests. (#180)

parent 111d7f30
......@@ -44,7 +44,7 @@ dependencies {
}
application {
mainClass.set("SkijaInjectSample.AppKt")
mainClass.set("SkiaJvmSample.AppKt")
}
val additionalArguments = mutableMapOf<String, String>()
......
......@@ -8,5 +8,5 @@ pluginManagement {
}
}
rootProject.name = "SkijaInjectSample"
rootProject.name = "SkiaJvmSample"
package SkijaInjectSample
package SkiaJvmSample
import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skia.*
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.ParagraphBuilder
......@@ -30,6 +29,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
var mouseY = 0
val window = SkiaWindow()
window.defaultCloseOperation =
if (exitOnClose) WindowConstants.EXIT_ON_CLOSE else WindowConstants.DISPOSE_ON_CLOSE
window.title = title
......
package SkijaInjectSample
package SkiaJvmSample
import java.awt.BorderLayout
import javax.swing.JFrame
......
package SkijaInjectSample
package SkiaJvmSample
import org.jetbrains.skiko.ClipComponent
import org.jetbrains.skiko.SkiaLayer
......
package SkijaInjectSample
package SkiaJvmSample
import java.awt.BorderLayout
import java.awt.Color
......@@ -32,7 +32,6 @@ fun Button(
}
fun SwingSkia() = SwingUtilities.invokeLater {
val window = JFrame()
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.title = "SwingSkiaWindow"
......
......@@ -2,14 +2,8 @@
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
import org.jetbrains.skia.impl.RefCnt
import org.jetbrains.skia.impl.Native
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.reachabilityBarrier
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.NativePointerArray
import org.jetbrains.skia.impl.getPtr
import org.jetbrains.skia.impl.*
import kotlin.jvm.JvmStatic
class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
......@@ -317,13 +311,15 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
}
fun makeMerge(filters: Array<ImageFilter?>, crop: IRect?): ImageFilter {
return try {
Stats.onNativeCall()
val filterPtrs = NativePointerArray(filters.size)
for (i in filters.indices) filterPtrs[i] = getPtr(filters[i])
ImageFilter(_nMakeMerge(filterPtrs, crop))
} finally {
reachabilityBarrier(filters)
return interopScope {
try {
Stats.onNativeCall()
val filterPtrs = NativePointerArray(filters.size)
for (i in filters.indices) filterPtrs[i] = getPtr(filters[i])
ImageFilter(_nMakeMerge(toInterop(filterPtrs), crop))
} finally {
reachabilityBarrier(filters)
}
}
}
......@@ -729,7 +725,7 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
external fun _nMakeMatrixTransform(matrix: FloatArray?, samplingMode: Long, input: NativePointer): NativePointer
@JvmStatic
@ExternalSymbolName("org_jetbrains_skia_ImageFilter__1nMakeMerge")
external fun _nMakeMerge(filters: NativePointerArray?, crop: IRect?): NativePointer
external fun _nMakeMerge(filters: InteropPointer, crop: IRect?): NativePointer
@JvmStatic
@ExternalSymbolName("org_jetbrains_skia_ImageFilter__1nMakeOffset")
external fun _nMakeOffset(dx: Float, dy: Float, input: NativePointer, crop: IRect?): NativePointer
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad
import org.jetbrains.skia.impl.RefCnt
import org.jetbrains.skia.impl.Native
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.NativePointerArray
import org.jetbrains.skia.impl.getPtr
import kotlin.jvm.JvmStatic
class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
......@@ -26,8 +20,8 @@ class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
@JvmStatic
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1nMakeShader")
external fun _nMakeShader(
runtimeEffectPtr: NativePointer, uniformPtr: NativePointer, childrenPtrs: NativePointerArray?,
localMatrix: FloatArray?, isOpaque: Boolean
runtimeEffectPtr: NativePointer, uniformPtr: NativePointer, childrenPtrs: InteropPointer,
localMatrix: InteropPointer, isOpaque: Boolean
): NativePointer
@JvmStatic
......@@ -51,6 +45,8 @@ class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
val childrenPtrs = NativePointerArray(childCount)
for (i in 0 until childCount) childrenPtrs[i] = getPtr(children!![i])
val matrix = localMatrix?.mat
return Shader(_nMakeShader(_ptr, getPtr(uniforms), childrenPtrs, matrix, isOpaque))
return interopScope {
Shader(_nMakeShader(_ptr, getPtr(uniforms), toInterop(childrenPtrs), toInterop(matrix), isOpaque))
}
}
}
\ No newline at end of file
......@@ -24,6 +24,8 @@ expect class InteropScope() {
fun InteropPointer.fromInterop(result: ByteArray)
fun toInterop(array: FloatArray?): InteropPointer
fun InteropPointer.fromInterop(result: FloatArray)
fun toInterop(array: NativePointerArray?): InteropPointer
fun release()
}
......
......@@ -37,6 +37,7 @@ class FontCollection internal constructor(ptr: NativePointer) : RefCnt(ptr) {
external fun _nGetFallbackManager(ptr: NativePointer): NativePointer
@JvmStatic
@ExternalSymbolName("org_jetbrains_skia_FontCollection__1nFindTypefaces")
// TODO: fix me, must pass value to store result!
external fun _nFindTypefaces(ptr: NativePointer, familyNames: Array<String?>?, fontStyle: Int): NativePointerArray
@JvmStatic
@ExternalSymbolName("org_jetbrains_skia_FontCollection__1nDefaultFallbackChar")
......
......@@ -21,7 +21,7 @@ actual fun reachabilityBarrier(obj: Any?) {
}
actual typealias NativePointer = Int
actual typealias NativePointerArray = IntArray
actual typealias InteropPointer = Int
actual class InteropScope actual constructor() {
......@@ -70,6 +70,17 @@ actual class InteropScope actual constructor() {
fromWasm(this@fromInterop, result)
}
actual fun toInterop(array: NativePointerArray?): InteropPointer {
return if (array != null) {
val data = _malloc(array.size * 4)
elements.add(data)
toWasm(data, array)
data
} else {
0
}
}
actual fun release() {
elements.forEach {
_free(it)
......@@ -100,6 +111,10 @@ private fun toWasm(dest: NativePointer, src: FloatArray) {
js("HEAPU32.set(src, dest)")
}
private fun toWasm(dest: NativePointer, src: IntArray) {
js("HEAPU32.set(src, dest)")
}
private fun fromWasm(src: NativePointer, result: ByteArray) {
js("result.set(HEAPU8.subarray(src, result.size))")
}
......
package org.jetbrains.skia.impl
actual typealias NativePointerArray = IntArray
\ No newline at end of file
......@@ -81,8 +81,17 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorFilter__1nMakeTa
return reinterpret_cast<jlong>(ptr);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorFilter__nMakeTableARGB
(JNIEnv* env, jclass jclass, jbyteArray arrayA, jbyteArray arrayR, jbyteArray arrayG, jbyteArray arrayB) {
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorFilterKt__1nMakeTableARGB(
JNIEnv* env, jclass jclass,
jbyteArray arrayA,
jint arrayASize,
jbyteArray arrayR,
jint arrayRSize,
jbyteArray arrayG,
jint arrayGSize,
jbyteArray arrayB,
jint arrayBSize
) {
jbyte* a = arrayA ? env->GetByteArrayElements(arrayA, 0) : nullptr;
jbyte* r = arrayR ? env->GetByteArrayElements(arrayR, 0) : nullptr;
jbyte* g = arrayG ? env->GetByteArrayElements(arrayG, 0) : nullptr;
......
......@@ -27,7 +27,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorSpace__1nMakeDis
return reinterpret_cast<jlong>(ptr);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_ColorSpaceKt__nConvert
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_ColorSpaceKt__1nConvert
(JNIEnv* env, jobject jclass, jlong fromPtr, jlong toPtr, float r, float g, float b, float a, jfloatArray jresult) {
SkColorSpace* from = reinterpret_cast<SkColorSpace*>(static_cast<uintptr_t>(fromPtr));
SkColorSpace* to = reinterpret_cast<SkColorSpace*>(static_cast<uintptr_t>(toPtr));
......
......@@ -47,6 +47,7 @@ actual fun reachabilityBarrier(obj: Any?) {
}
actual typealias NativePointer = Long
actual typealias NativePointerArray = LongArray
actual typealias InteropPointer = Any?
......@@ -57,5 +58,6 @@ actual class InteropScope actual constructor() {
actual fun InteropPointer.fromInterop(result: ByteArray) {}
actual fun toInterop(array: FloatArray?): InteropPointer = array
actual fun InteropPointer.fromInterop(result: FloatArray) {}
actual fun toInterop(array: NativePointerArray?): InteropPointer = array
actual fun release() {}
}
package org.jetbrains.skia.impl
actual typealias NativePointerArray = LongArray
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skia.Color4f
import org.jetbrains.skia.ColorFilter
import org.jetbrains.skia.ColorSpace
import org.junit.Test
class SkiaTest {
@Test
fun `color conversion`() {
val cs = ColorSpace.sRGB
val color = cs.convert(ColorSpace.sRGBLinear, Color4f(1f, 0f, 0f, 1f))
assert(color.r != 0f)
}
@Test
fun `color table`() {
val array = ByteArray(256)
val table = ColorFilter.makeTableARGB(array, array, array, array)
assert(table._ptr != 0L)
}
}
\ No newline at end of file
......@@ -69,6 +69,18 @@ actual class InteropScope actual constructor() {
}
}
actual fun toInterop(array: NativePointerArray?): InteropPointer {
return if (array != null) {
// We pass it as LongArray via boundary.
val pinned = array.backing.pin()
elements.add(pinned)
val result = pinned.addressOf(0).rawValue
result
} else {
NativePtr.NULL
}
}
actual fun InteropPointer.fromInterop(result: FloatArray) {}
actual fun release() {
......@@ -80,3 +92,17 @@ actual class InteropScope actual constructor() {
private val elements = mutableListOf<Pinned<*>>()
}
// Ugly! NativePtrArray in stdlib is unfortunately internal, don't have ctor and cannot be used.
actual class NativePointerArray actual constructor(size: Int) {
internal val backing = LongArray(size)
actual operator fun get(index: Int): NativePointer {
return NativePtr.NULL + backing[index]
}
actual operator fun set(index: Int, value: NativePointer) {
backing[index] = value.toLong()
}
actual val size: Int
get() = backing.size
}
\ No newline at end of file
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