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 { ...@@ -44,7 +44,7 @@ dependencies {
} }
application { application {
mainClass.set("SkijaInjectSample.AppKt") mainClass.set("SkiaJvmSample.AppKt")
} }
val additionalArguments = mutableMapOf<String, String>() val additionalArguments = mutableMapOf<String, String>()
......
...@@ -8,5 +8,5 @@ pluginManagement { ...@@ -8,5 +8,5 @@ pluginManagement {
} }
} }
rootProject.name = "SkijaInjectSample" rootProject.name = "SkiaJvmSample"
package SkijaInjectSample package SkiaJvmSample
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skia.paragraph.FontCollection import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.ParagraphBuilder import org.jetbrains.skia.paragraph.ParagraphBuilder
...@@ -30,6 +29,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat ...@@ -30,6 +29,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
var mouseY = 0 var mouseY = 0
val window = SkiaWindow() val window = SkiaWindow()
window.defaultCloseOperation = window.defaultCloseOperation =
if (exitOnClose) WindowConstants.EXIT_ON_CLOSE else WindowConstants.DISPOSE_ON_CLOSE if (exitOnClose) WindowConstants.EXIT_ON_CLOSE else WindowConstants.DISPOSE_ON_CLOSE
window.title = title window.title = title
......
package SkijaInjectSample package SkiaJvmSample
import java.awt.BorderLayout import java.awt.BorderLayout
import javax.swing.JFrame import javax.swing.JFrame
......
package SkijaInjectSample package SkiaJvmSample
import org.jetbrains.skiko.ClipComponent import org.jetbrains.skiko.ClipComponent
import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.SkiaLayer
......
package SkijaInjectSample package SkiaJvmSample
import java.awt.BorderLayout import java.awt.BorderLayout
import java.awt.Color import java.awt.Color
...@@ -32,7 +32,6 @@ fun Button( ...@@ -32,7 +32,6 @@ fun Button(
} }
fun SwingSkia() = SwingUtilities.invokeLater { fun SwingSkia() = SwingUtilities.invokeLater {
val window = JFrame() val window = JFrame()
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.title = "SwingSkiaWindow" window.title = "SwingSkiaWindow"
......
...@@ -2,14 +2,8 @@ ...@@ -2,14 +2,8 @@
package org.jetbrains.skia package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad 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.ExternalSymbolName
import org.jetbrains.skia.impl.NativePointer import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.NativePointerArray
import org.jetbrains.skia.impl.getPtr
import kotlin.jvm.JvmStatic import kotlin.jvm.JvmStatic
class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) { class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
...@@ -317,13 +311,15 @@ 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 { fun makeMerge(filters: Array<ImageFilter?>, crop: IRect?): ImageFilter {
return try { return interopScope {
Stats.onNativeCall() try {
val filterPtrs = NativePointerArray(filters.size) Stats.onNativeCall()
for (i in filters.indices) filterPtrs[i] = getPtr(filters[i]) val filterPtrs = NativePointerArray(filters.size)
ImageFilter(_nMakeMerge(filterPtrs, crop)) for (i in filters.indices) filterPtrs[i] = getPtr(filters[i])
} finally { ImageFilter(_nMakeMerge(toInterop(filterPtrs), crop))
reachabilityBarrier(filters) } finally {
reachabilityBarrier(filters)
}
} }
} }
...@@ -729,7 +725,7 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -729,7 +725,7 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
external fun _nMakeMatrixTransform(matrix: FloatArray?, samplingMode: Long, input: NativePointer): NativePointer external fun _nMakeMatrixTransform(matrix: FloatArray?, samplingMode: Long, input: NativePointer): NativePointer
@JvmStatic @JvmStatic
@ExternalSymbolName("org_jetbrains_skia_ImageFilter__1nMakeMerge") @ExternalSymbolName("org_jetbrains_skia_ImageFilter__1nMakeMerge")
external fun _nMakeMerge(filters: NativePointerArray?, crop: IRect?): NativePointer external fun _nMakeMerge(filters: InteropPointer, crop: IRect?): NativePointer
@JvmStatic @JvmStatic
@ExternalSymbolName("org_jetbrains_skia_ImageFilter__1nMakeOffset") @ExternalSymbolName("org_jetbrains_skia_ImageFilter__1nMakeOffset")
external fun _nMakeOffset(dx: Float, dy: Float, input: NativePointer, crop: IRect?): NativePointer external fun _nMakeOffset(dx: Float, dy: Float, input: NativePointer, crop: IRect?): NativePointer
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION") @file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia package org.jetbrains.skia
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad 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 import kotlin.jvm.JvmStatic
class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) { class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
...@@ -26,8 +20,8 @@ class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -26,8 +20,8 @@ class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
@JvmStatic @JvmStatic
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1nMakeShader") @ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1nMakeShader")
external fun _nMakeShader( external fun _nMakeShader(
runtimeEffectPtr: NativePointer, uniformPtr: NativePointer, childrenPtrs: NativePointerArray?, runtimeEffectPtr: NativePointer, uniformPtr: NativePointer, childrenPtrs: InteropPointer,
localMatrix: FloatArray?, isOpaque: Boolean localMatrix: InteropPointer, isOpaque: Boolean
): NativePointer ): NativePointer
@JvmStatic @JvmStatic
...@@ -51,6 +45,8 @@ class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -51,6 +45,8 @@ class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
val childrenPtrs = NativePointerArray(childCount) val childrenPtrs = NativePointerArray(childCount)
for (i in 0 until childCount) childrenPtrs[i] = getPtr(children!![i]) for (i in 0 until childCount) childrenPtrs[i] = getPtr(children!![i])
val matrix = localMatrix?.mat 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() { ...@@ -24,6 +24,8 @@ expect class InteropScope() {
fun InteropPointer.fromInterop(result: ByteArray) fun InteropPointer.fromInterop(result: ByteArray)
fun toInterop(array: FloatArray?): InteropPointer fun toInterop(array: FloatArray?): InteropPointer
fun InteropPointer.fromInterop(result: FloatArray) fun InteropPointer.fromInterop(result: FloatArray)
fun toInterop(array: NativePointerArray?): InteropPointer
fun release() fun release()
} }
......
...@@ -37,6 +37,7 @@ class FontCollection internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -37,6 +37,7 @@ class FontCollection internal constructor(ptr: NativePointer) : RefCnt(ptr) {
external fun _nGetFallbackManager(ptr: NativePointer): NativePointer external fun _nGetFallbackManager(ptr: NativePointer): NativePointer
@JvmStatic @JvmStatic
@ExternalSymbolName("org_jetbrains_skia_FontCollection__1nFindTypefaces") @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 external fun _nFindTypefaces(ptr: NativePointer, familyNames: Array<String?>?, fontStyle: Int): NativePointerArray
@JvmStatic @JvmStatic
@ExternalSymbolName("org_jetbrains_skia_FontCollection__1nDefaultFallbackChar") @ExternalSymbolName("org_jetbrains_skia_FontCollection__1nDefaultFallbackChar")
......
...@@ -21,7 +21,7 @@ actual fun reachabilityBarrier(obj: Any?) { ...@@ -21,7 +21,7 @@ actual fun reachabilityBarrier(obj: Any?) {
} }
actual typealias NativePointer = Int actual typealias NativePointer = Int
actual typealias NativePointerArray = IntArray
actual typealias InteropPointer = Int actual typealias InteropPointer = Int
actual class InteropScope actual constructor() { actual class InteropScope actual constructor() {
...@@ -70,6 +70,17 @@ actual class InteropScope actual constructor() { ...@@ -70,6 +70,17 @@ actual class InteropScope actual constructor() {
fromWasm(this@fromInterop, result) 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() { actual fun release() {
elements.forEach { elements.forEach {
_free(it) _free(it)
...@@ -100,6 +111,10 @@ private fun toWasm(dest: NativePointer, src: FloatArray) { ...@@ -100,6 +111,10 @@ private fun toWasm(dest: NativePointer, src: FloatArray) {
js("HEAPU32.set(src, dest)") js("HEAPU32.set(src, dest)")
} }
private fun toWasm(dest: NativePointer, src: IntArray) {
js("HEAPU32.set(src, dest)")
}
private fun fromWasm(src: NativePointer, result: ByteArray) { private fun fromWasm(src: NativePointer, result: ByteArray) {
js("result.set(HEAPU8.subarray(src, result.size))") 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 ...@@ -81,8 +81,17 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorFilter__1nMakeTa
return reinterpret_cast<jlong>(ptr); return reinterpret_cast<jlong>(ptr);
} }
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorFilter__nMakeTableARGB extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorFilterKt__1nMakeTableARGB(
(JNIEnv* env, jclass jclass, jbyteArray arrayA, jbyteArray arrayR, jbyteArray arrayG, jbyteArray arrayB) { 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* a = arrayA ? env->GetByteArrayElements(arrayA, 0) : nullptr;
jbyte* r = arrayR ? env->GetByteArrayElements(arrayR, 0) : nullptr; jbyte* r = arrayR ? env->GetByteArrayElements(arrayR, 0) : nullptr;
jbyte* g = arrayG ? env->GetByteArrayElements(arrayG, 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 ...@@ -27,7 +27,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ColorSpace__1nMakeDis
return reinterpret_cast<jlong>(ptr); 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) { (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* from = reinterpret_cast<SkColorSpace*>(static_cast<uintptr_t>(fromPtr));
SkColorSpace* to = reinterpret_cast<SkColorSpace*>(static_cast<uintptr_t>(toPtr)); SkColorSpace* to = reinterpret_cast<SkColorSpace*>(static_cast<uintptr_t>(toPtr));
......
...@@ -47,6 +47,7 @@ actual fun reachabilityBarrier(obj: Any?) { ...@@ -47,6 +47,7 @@ actual fun reachabilityBarrier(obj: Any?) {
} }
actual typealias NativePointer = Long actual typealias NativePointer = Long
actual typealias NativePointerArray = LongArray
actual typealias InteropPointer = Any? actual typealias InteropPointer = Any?
...@@ -57,5 +58,6 @@ actual class InteropScope actual constructor() { ...@@ -57,5 +58,6 @@ actual class InteropScope actual constructor() {
actual fun InteropPointer.fromInterop(result: ByteArray) {} actual fun InteropPointer.fromInterop(result: ByteArray) {}
actual fun toInterop(array: FloatArray?): InteropPointer = array actual fun toInterop(array: FloatArray?): InteropPointer = array
actual fun InteropPointer.fromInterop(result: FloatArray) {} actual fun InteropPointer.fromInterop(result: FloatArray) {}
actual fun toInterop(array: NativePointerArray?): InteropPointer = array
actual fun release() {} 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() { ...@@ -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 InteropPointer.fromInterop(result: FloatArray) {}
actual fun release() { actual fun release() {
...@@ -80,3 +92,17 @@ actual class InteropScope actual constructor() { ...@@ -80,3 +92,17 @@ actual class InteropScope actual constructor() {
private val elements = mutableListOf<Pinned<*>>() 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