Unverified Commit 54fb2034 authored by Aleksandr Veselov's avatar Aleksandr Veselov Committed by GitHub

Implement Drawable for native (#373)

parent 82342b34
...@@ -81,7 +81,9 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") { ...@@ -81,7 +81,9 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") {
flags.set(listOf( flags.set(listOf(
*skiaPreprocessorFlags(), *skiaPreprocessorFlags(),
"-DSKIKO_WASM" "-DSKIKO_WASM",
"-fno-rtti",
"-fno-exceptions"
)) ))
} }
......
...@@ -2,6 +2,7 @@ package org.jetbrains.skia ...@@ -2,6 +2,7 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.* import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad import org.jetbrains.skia.impl.Library.Companion.staticLoad
import org.jetbrains.skiko.maybeSynchronized
/** /**
* *
...@@ -12,14 +13,15 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad ...@@ -12,14 +13,15 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad
* allow for clients of the drawable that may want to cache the results, the drawable must * allow for clients of the drawable that may want to cache the results, the drawable must
* change its generation id whenever its internal state changes such that it will draw differently. * change its generation id whenever its internal state changes such that it will draw differently.
*/ */
abstract class Drawable : RefCnt(Drawable_nMake()) { abstract class Drawable : Managed(Drawable_nMake(), _FinalizerHolder.PTR) {
companion object { companion object {
init { init {
staticLoad() staticLoad()
} }
} }
internal var _bounds: Rect? = null private var _bounds: Rect? = null
private val boundsLock = Unit
/** /**
* Draws into the specified content. The drawing sequence will be balanced upon return * Draws into the specified content. The drawing sequence will be balanced upon return
...@@ -93,9 +95,11 @@ abstract class Drawable : RefCnt(Drawable_nMake()) { ...@@ -93,9 +95,11 @@ abstract class Drawable : RefCnt(Drawable_nMake()) {
*/ */
val bounds: Rect val bounds: Rect
get() { get() {
if (_bounds == null) _bounds = onGetBounds() maybeSynchronized(boundsLock) {
if (_bounds == null) _bounds = Rect.fromInteropPointer { Drawable_nGetBounds(_ptr, it) }
return _bounds!! return _bounds!!
} }
}
/** /**
* Calling this invalidates the previous generation ID, and causes a new one to be computed * Calling this invalidates the previous generation ID, and causes a new one to be computed
...@@ -103,27 +107,34 @@ abstract class Drawable : RefCnt(Drawable_nMake()) { ...@@ -103,27 +107,34 @@ abstract class Drawable : RefCnt(Drawable_nMake()) {
* in response to its internal state changing. * in response to its internal state changing.
*/ */
fun notifyDrawingChanged(): Drawable { fun notifyDrawingChanged(): Drawable {
maybeSynchronized(boundsLock) {
Stats.onNativeCall() Stats.onNativeCall()
_nNotifyDrawingChanged(_ptr) _nNotifyDrawingChanged(_ptr)
_bounds = null _bounds = null
}
return this return this
} }
abstract fun onDraw(canvas: Canvas?) abstract fun onDraw(canvas: Canvas?)
abstract fun onGetBounds(): Rect abstract fun onGetBounds(): Rect
fun _onDraw(canvasPtr: NativePointer) {
private fun _onDraw(canvasPtr: NativePointer) {
onDraw(Canvas(canvasPtr, false, this)) onDraw(Canvas(canvasPtr, false, this))
} }
private object _FinalizerHolder {
val PTR = Drawable_nGetFinalizer()
}
init { init {
Stats.onNativeCall() doInit(_ptr)
Stats.onNativeCall()
Drawable_nInit(this, _ptr)
} }
} }
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nInit") internal expect fun Drawable.doInit(ptr: NativePointer)
private external fun Drawable_nInit(drawable: Drawable, ptr: NativePointer)
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nGetFinalizer")
private external fun Drawable_nGetFinalizer(): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nMake") @ExternalSymbolName("org_jetbrains_skia_Drawable__1nMake")
private external fun Drawable_nMake(): NativePointer private external fun Drawable_nMake(): NativePointer
...@@ -139,3 +150,17 @@ private external fun _nMakePictureSnapshot(ptr: NativePointer): NativePointer ...@@ -139,3 +150,17 @@ private external fun _nMakePictureSnapshot(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nNotifyDrawingChanged") @ExternalSymbolName("org_jetbrains_skia_Drawable__1nNotifyDrawingChanged")
private external fun _nNotifyDrawingChanged(ptr: NativePointer) private external fun _nNotifyDrawingChanged(ptr: NativePointer)
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nGetBounds")
private external fun Drawable_nGetBounds(ptr: NativePointer, result: InteropPointer)
// For Native/JS usage only
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nInit")
internal external fun Drawable_nInit(ptr: NativePointer, onGetBounds: InteropPointer, onDraw: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nGetOnDrawCanvas")
internal external fun _nGetOnDrawCanvas(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Drawable__1nSetBounds")
internal external fun _nSetBounds(ptr: NativePointer, left: Float, top: Float, right: Float, bottom: Float)
\ No newline at end of file
...@@ -77,7 +77,7 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -77,7 +77,7 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
interopScope { interopScope {
_nPlayback(_ptr, getPtr(canvas), toInterop(abort)) _nPlayback(_ptr, getPtr(canvas), booleanCallback(abort))
} }
this this
} finally { } finally {
......
...@@ -42,7 +42,15 @@ expect class InteropScope() { ...@@ -42,7 +42,15 @@ expect class InteropScope() {
fun InteropPointer.fromInteropNativePointerArray(): NativePointerArray fun InteropPointer.fromInteropNativePointerArray(): NativePointerArray
inline fun <reified T> InteropPointer.fromInterop(decoder: ArrayInteropDecoder<T>): Array<T> inline fun <reified T> InteropPointer.fromInterop(decoder: ArrayInteropDecoder<T>): Array<T>
fun toInteropForArraysOfPointers(interopPointers: Array<InteropPointer>): InteropPointer fun toInteropForArraysOfPointers(interopPointers: Array<InteropPointer>): InteropPointer
fun toInterop(callback: (() -> Boolean)?): InteropPointer
// Callbacks
fun callback(callback: (() -> Unit)?): InteropPointer
fun booleanCallback(callback: (() -> Boolean)?): InteropPointer
// Virtual methods
fun virtual(method: () -> Unit): InteropPointer
fun virtualBoolean(method: () -> Boolean): InteropPointer
fun release() fun release()
} }
......
package org.jetbrains.skia
import org.jetbrains.skia.tests.assertCloseEnough
import kotlin.test.Test
import kotlin.test.assertEquals
class DrawableTest {
@Test
fun canDrawDrawable() {
val cross = object : Drawable() {
override fun onDraw(canvas: Canvas?) {
val paint = Paint().apply { color = Color.RED }
canvas!!.drawRect(Rect(4f, 0f, 12f, 16f), paint)
canvas.drawRect(Rect(0f, 4f, 16f, 12f), paint)
}
override fun onGetBounds() = Rect(0f, 0f, 16f, 16f)
}
val surface = Surface.makeRasterN32Premul(16, 16)
surface.canvas.drawDrawable(cross)
val pixels = Bitmap.makeFromImage(surface.makeImageSnapshot())
assertEquals(Color.RED, pixels.getColor(8, 8))
assertEquals(Color.TRANSPARENT, pixels.getColor(2, 2))
assertCloseEnough(Rect(0f, 0f, 16f, 16f), cross.bounds)
}
}
\ No newline at end of file
...@@ -195,12 +195,28 @@ actual class InteropScope actual constructor() { ...@@ -195,12 +195,28 @@ actual class InteropScope actual constructor() {
return toInterop(interopPointers.toIntArray()) return toInterop(interopPointers.toIntArray())
} }
actual fun toInterop(callback: (() -> Boolean)?): InteropPointer { actual fun booleanCallback(callback: (() -> Boolean)?): InteropPointer {
if (callback == null) { return 0 } if (callback == null) { return 0 }
initCallbacks() initCallbacks()
val data = CallbackData<Boolean>(null) val data = CallbackData<Boolean>(null)
return _registerCallback({ data.value = callback() }, data) return _registerCallback({ data.value = callback() }, data, global = false)
}
actual fun callback(callback: (() -> Unit)?): InteropPointer {
if (callback == null) { return 0 }
initCallbacks()
return _registerCallback({ callback() }, null, global = false)
}
actual fun virtual(method: () -> Unit): InteropPointer {
return _registerCallback({ method() }, null, global = true)
}
actual fun virtualBoolean(method: () -> Boolean): InteropPointer {
val data = CallbackData<Boolean>(null)
return _registerCallback({ data.value = method() }, data, global = true);
} }
actual fun release() { actual fun release() {
...@@ -229,7 +245,7 @@ actual class InteropScope actual constructor() { ...@@ -229,7 +245,7 @@ actual class InteropScope actual constructor() {
private class CallbackData<T>(@JsName("value") var value: T?) private class CallbackData<T>(@JsName("value") var value: T?)
// See `setup.js` // See `setup.js`
private external fun _registerCallback(cb: () -> Unit, data: Any?): Int private external fun _registerCallback(cb: () -> Unit, data: Any?, global: Boolean): Int
private external fun _createLocalCallbackScope() private external fun _createLocalCallbackScope()
private external fun _releaseLocalCallbackScope() private external fun _releaseLocalCallbackScope()
......
...@@ -11,20 +11,23 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco ...@@ -11,20 +11,23 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
class Scope { class Scope {
constructor() { constructor() {
this.callbackMap = [CB_NULL]; this.nextId = 1;
this.callbackMap = new Map();
this.callbackMap.set(0, CB_NULL);
} }
addCallback(callback, data) { addCallback(callback, data) {
this.callbackMap.push({callback, data}); let id = this.nextId++;
return this.callbackMap.length - 1; this.callbackMap.set(id, {callback, data});
return id;
} }
getCallback(id) { getCallback(id) {
return this.callbackMap[id] || CB_UNDEFINED return this.callbackMap.get(id) || CB_UNDEFINED;
} }
deleteCallback(id) { deleteCallback(id) {
this.callbackMap[id] = CB_UNDEFINED this.callbackMap.delete(id);
} }
release() { release() {
...@@ -36,8 +39,8 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco ...@@ -36,8 +39,8 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
let scope = GLOBAL_SCOPE; let scope = GLOBAL_SCOPE;
return { return {
_callCallback(callbackId) { _callCallback(callbackId, global = false) {
let callback = scope.getCallback(callbackId); let callback = (global ? GLOBAL_SCOPE : scope).getCallback(callbackId);
try { try {
callback.callback(); callback.callback();
return callback.data; return callback.data;
...@@ -45,11 +48,11 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco ...@@ -45,11 +48,11 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
console.error(e) console.error(e)
} }
}, },
_registerCallback(callback, data = null) { _registerCallback(callback, data = null, global = false) {
return scope.addCallback(callback, data); return (global ? GLOBAL_SCOPE : scope).addCallback(callback, data);
}, },
_releaseCallback(callbackId) { _releaseCallback(callbackId, global = false) {
scope.deleteCallback(callbackId); (global ? GLOBAL_SCOPE : scope).deleteCallback(callbackId);
}, },
_createLocalCallbackScope() { _createLocalCallbackScope() {
if (scope !== GLOBAL_SCOPE) { if (scope !== GLOBAL_SCOPE) {
......
...@@ -10,14 +10,14 @@ public: ...@@ -10,14 +10,14 @@ public:
~SkijaDrawableImpl() { ~SkijaDrawableImpl() {
JNIEnv* env; JNIEnv* env;
if (fJavaVM->GetEnv(reinterpret_cast<void**>(&env), SKIKO_JNI_VERSION) == JNI_OK) if (fJavaVM->GetEnv(AS_JNI_ENV_PTR(&env), SKIKO_JNI_VERSION) == JNI_OK)
env->DeleteWeakGlobalRef(fObject); env->DeleteGlobalRef(fObject);
} }
void init(JNIEnv* e, jobject o) { void init(JNIEnv* e, jobject o) {
fEnv = e; fEnv = e;
fEnv->GetJavaVM(&fJavaVM); fEnv->GetJavaVM(&fJavaVM);
fObject = fEnv->NewWeakGlobalRef(o); fObject = fEnv->NewGlobalRef(o);
} }
protected: protected:
...@@ -38,13 +38,21 @@ private: ...@@ -38,13 +38,21 @@ private:
jobject fObject; jobject fObject;
}; };
static void deleteDrawable(SkijaDrawableImpl* drawable) {
delete drawable;
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DrawableKt_Drawable_1nGetFinalizer() {
return reinterpret_cast<jlong>(&deleteDrawable);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DrawableKt_Drawable_1nMake extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DrawableKt_Drawable_1nMake
(JNIEnv* env, jclass jclass) { (JNIEnv* env, jclass jclass) {
SkijaDrawableImpl* instance = new SkijaDrawableImpl(); SkijaDrawableImpl* instance = new SkijaDrawableImpl();
return reinterpret_cast<jlong>(instance); return reinterpret_cast<jlong>(instance);
} }
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DrawableKt_Drawable__1nInit extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_Drawable_1jvmKt_Drawable_1nInit
(JNIEnv* env, jclass jclass, jobject jthis, jlong ptr) { (JNIEnv* env, jclass jclass, jobject jthis, jlong ptr) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>(static_cast<uintptr_t>(ptr)); SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>(static_cast<uintptr_t>(ptr));
instance->init(env, jthis); instance->init(env, jthis);
...@@ -75,3 +83,9 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DrawableKt__1nNotifyDr ...@@ -75,3 +83,9 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DrawableKt__1nNotifyDr
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>(static_cast<uintptr_t>(ptr)); SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>(static_cast<uintptr_t>(ptr));
return instance->notifyDrawingChanged(); return instance->notifyDrawingChanged();
} }
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DrawableKt_Drawable_1nGetBounds
(JNIEnv* env, jclass jclass, jlong ptr, jfloatArray result) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>(static_cast<uintptr_t>(ptr));
skija::Rect::copyToInterop(env, instance->getBounds(), result);
}
...@@ -446,8 +446,8 @@ public: ...@@ -446,8 +446,8 @@ public:
} }
T operator()() { T operator()() {
jobject res = env->CallObjectMethod(callback, kotlin::jvm::functions::Function0::invoke); skija::AutoLocal<jobject> res(env, env->CallObjectMethod(callback, kotlin::jvm::functions::Function0::invoke));
return jObjectConvert<T>(env, res); return jObjectConvert<T>(env, res.get());
} }
bool isExceptionThrown() { bool isExceptionThrown() {
......
package org.jetbrains.skia
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.Stats
internal actual fun Drawable.doInit(ptr: NativePointer) {
Stats.onNativeCall()
Drawable_nInit(this, ptr)
}
private external fun Drawable_nInit(thisPtr: Drawable, ptr: NativePointer)
\ No newline at end of file
...@@ -78,7 +78,13 @@ actual open class InteropScope actual constructor() { ...@@ -78,7 +78,13 @@ actual open class InteropScope actual constructor() {
actual inline fun <reified T> InteropPointer.fromInterop(decoder: ArrayInteropDecoder<T>): Array<T> = actual inline fun <reified T> InteropPointer.fromInterop(decoder: ArrayInteropDecoder<T>): Array<T> =
this@fromInterop as Array<T> this@fromInterop as Array<T>
actual fun toInteropForArraysOfPointers(interopPointers: Array<InteropPointer>): InteropPointer = interopPointers actual fun toInteropForArraysOfPointers(interopPointers: Array<InteropPointer>): InteropPointer = interopPointers
actual fun toInterop(callback: (() -> Boolean)?) = callback as Any?
actual fun callback(callback: (() -> Unit)?) = callback as Any?
actual fun booleanCallback(callback: (() -> Boolean)?) = callback as Any?
actual fun virtual(method: () -> Unit) = callback(method)
actual fun virtualBoolean(method: () -> Boolean) = booleanCallback(method)
actual fun release() {} actual fun release() {}
} }
......
...@@ -188,23 +188,13 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch ...@@ -188,23 +188,13 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch
); );
} }
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawDrawable
(KNativePointer ptr, KNativePointer drawablePtr, KFloat* matrixArr) {
TODO("implement org_jetbrains_skia_Canvas__1nDrawDrawable");
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawDrawable SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawDrawable
(KNativePointer ptr, KNativePointer drawablePtr, KFloat* matrixArr) { (KNativePointer ptr, KNativePointer drawablePtr, KFloat* matrixArr) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((ptr)); SkCanvas* canvas = reinterpret_cast<SkCanvas*>((ptr));
SkDrawable* drawable = reinterpret_cast<SkDrawable*>((drawablePtr)); SkDrawable* drawable = reinterpret_cast<SkDrawable*>((drawablePtr));
std::unique_ptr<SkMatrix> matrix = skMatrix(env, matrixArr); std::unique_ptr<SkMatrix> matrix = skMatrix(matrixArr);
canvas->drawDrawable(drawable, matrix.get()); canvas->drawDrawable(drawable, matrix.get());
} }
#endif
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nClear(KNativePointer ptr, KInt color) { SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nClear(KNativePointer ptr, KInt color) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((ptr)); SkCanvas* canvas = reinterpret_cast<SkCanvas*>((ptr));
......
...@@ -5,94 +5,96 @@ ...@@ -5,94 +5,96 @@
#include "SkDrawable.h" #include "SkDrawable.h"
#include "common.h" #include "common.h"
class SkikoDrawable : public SkDrawable {
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMake public:
(){ SkikoDrawable(KInteropPointer onDraw, KInteropPointer onGetBounds) : _onDraw(onDraw), _onGetBounds(onGetBounds) {};
TODO("implement org_jetbrains_skia_Drawable__1nMake");
void init(KInteropPointer onDraw, KInteropPointer onGetBounds) {
_onDraw = KVoidCallback(onDraw);
_onGetBounds = KVoidCallback(onGetBounds);
}
SkRect& bounds() { return _bounds; }
SkCanvas* onDrawCanvas() { return _onDrawCanvas; }
protected:
void onDraw(SkCanvas* canvas) override {
_onDrawCanvas = canvas;
_onDraw();
_onDrawCanvas = nullptr;
};
SkRect onGetBounds() override {
_onGetBounds();
return _bounds;
};
private:
SkRect _bounds;
SkCanvas* _onDrawCanvas;
KVoidCallback _onDraw;
KVoidCallback _onGetBounds;
};
static void deleteSkikoDrawable(SkikoDrawable* drawable) {
delete drawable;
} }
#if 0 SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nGetFinalizer
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMake () {
(){ return reinterpret_cast<KNativePointer>(&deleteSkikoDrawable);
SkijaDrawableImpl* instance = new SkijaDrawableImpl();
return reinterpret_cast<KNativePointer>(instance);
} }
#endif
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nSetBounds
(KNativePointer ptr, KFloat left, KFloat top, KFloat right, KFloat bottom) {
SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>(ptr);
instance->bounds().setLTRB(left, top, right, bottom);
}
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nInit SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nGetBounds
(KInteropPointer kthis, KNativePointer ptr) { (KNativePointer ptr, KInteropPointer result) {
TODO("implement org_jetbrains_skia_Drawable__1nInit"); SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>(ptr);
skija::Rect::copyToInterop(instance->getBounds(), result);
} }
#if 0 SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Drawable__1nGetOnDrawCanvas
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nInit
(KNativePointer ptr) { (KNativePointer ptr) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>((ptr)); SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>(ptr);
instance->init(env, jthis); return reinterpret_cast<KInteropPointer>(instance->onDrawCanvas());
} }
#endif
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMake
(){
SkikoDrawable* instance = new SkikoDrawable(nullptr, nullptr);
return reinterpret_cast<KNativePointer>(instance);
}
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nDraw SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nInit
(KNativePointer ptr, KNativePointer canvasPtr, KFloat* matrixArr) { (KNativePointer ptr, KInteropPointer onGetBounds, KInteropPointer onDraw) {
TODO("implement org_jetbrains_skia_Drawable__1nDraw"); SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>((ptr));
instance->init(onDraw, onGetBounds);
} }
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nDraw SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nDraw
(KNativePointer ptr, KNativePointer canvasPtr, KFloat* matrixArr) { (KNativePointer ptr, KNativePointer canvasPtr, KFloat* matrixArr) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>((ptr)); SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>((ptr));
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr)); SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
std::unique_ptr<SkMatrix> matrix = skMatrix(env, matrixArr); std::unique_ptr<SkMatrix> matrix = skMatrix(matrixArr);
instance->draw(canvas, matrix.get()); instance->draw(canvas, matrix.get());
} }
#endif
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMakePictureSnapshot SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMakePictureSnapshot
(KNativePointer ptr) { (KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Drawable__1nMakePictureSnapshot"); SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>((ptr));
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMakePictureSnapshot
(KNativePointer ptr) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>((ptr));
return reinterpret_cast<KNativePointer>(instance->newPictureSnapshot()); return reinterpret_cast<KNativePointer>(instance->newPictureSnapshot());
} }
#endif
SKIKO_EXPORT KInt org_jetbrains_skia_Drawable__1nGetGenerationId
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Drawable__1nGetGenerationId");
}
#if 0
SKIKO_EXPORT KInt org_jetbrains_skia_Drawable__1nGetGenerationId SKIKO_EXPORT KInt org_jetbrains_skia_Drawable__1nGetGenerationId
(KNativePointer ptr) { (KNativePointer ptr) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>((ptr)); SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>((ptr));
return instance->getGenerationID(); return instance->getGenerationID();
} }
#endif
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nNotifyDrawingChanged
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Drawable__1nNotifyDrawingChanged");
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nNotifyDrawingChanged SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nNotifyDrawingChanged
(KNativePointer ptr) { (KNativePointer ptr) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>((ptr)); SkikoDrawable* instance = reinterpret_cast<SkikoDrawable*>((ptr));
return instance->notifyDrawingChanged(); return instance->notifyDrawingChanged();
} }
#endif
...@@ -160,10 +160,12 @@ static inline KFloat fromBits(KInt i) { ...@@ -160,10 +160,12 @@ static inline KFloat fromBits(KInt i) {
// Callback support // Callback support
typedef void (*SkikoDisposeCallback)(KInteropPointer); typedef void (*SkikoDisposeCallback)(KInteropPointer);
typedef void (*SkikoCallVoidCallback)(KInteropPointer);
typedef KBoolean (*SkikoCallBooleanCallback)(KInteropPointer); typedef KBoolean (*SkikoCallBooleanCallback)(KInteropPointer);
typedef void* KOpaquePointer; typedef void* KOpaquePointer;
void disposeCallback(KInteropPointer cb); void disposeCallback(KInteropPointer cb);
void callVoidCallback(KInteropPointer cb);
KBoolean callBooleanCallback(KInteropPointer cb); KBoolean callBooleanCallback(KInteropPointer cb);
template <typename T, T(*Apply)(KInteropPointer)> template <typename T, T(*Apply)(KInteropPointer)>
...@@ -171,19 +173,35 @@ class KCallback { ...@@ -171,19 +173,35 @@ class KCallback {
public: public:
explicit KCallback(KInteropPointer data) : data(data) {} explicit KCallback(KInteropPointer data) : data(data) {}
virtual ~KCallback() { disposeCallback(data); } virtual ~KCallback() {
if (data != nullptr) {
disposeCallback(data);
}
}
KCallback(const KCallback&) = delete; KCallback(const KCallback&) = delete;
KCallback(KCallback&&) = delete;
KCallback& operator=(const KCallback&) = delete; KCallback& operator=(const KCallback&) = delete;
KCallback& operator=(KCallback&&) = delete;
T operator()() const { return Apply(data); } KCallback(KCallback&& other) noexcept {
KInteropPointer t = data;
data = other.data;
other.data = t;
}
KCallback& operator=(KCallback&& other) {
std::swap(data, other.data);
return *this;
}
T operator()() const {
return Apply(data);
}
private: private:
KInteropPointer data; KInteropPointer data;
}; };
typedef KCallback<KBoolean, callBooleanCallback> KBooleanCallback; typedef KCallback<KBoolean, callBooleanCallback> KBooleanCallback;
typedef KCallback<void, callVoidCallback> KVoidCallback;
#endif /* SKIKO_COMMON_H */ #endif /* SKIKO_COMMON_H */
...@@ -342,13 +342,21 @@ KBoolean callBooleanCallback(KInteropPointer cb) { ...@@ -342,13 +342,21 @@ KBoolean callBooleanCallback(KInteropPointer cb) {
return static_cast<KBoolean>(value); return static_cast<KBoolean>(value);
} }
void callVoidCallback(KInteropPointer cb) {
EM_ASM({
_callCallback($0);
}, cb);
}
#else // __EMSCRIPTEN__ #else // __EMSCRIPTEN__
static SkikoDisposeCallback disposeCallbackImpl = nullptr; static SkikoDisposeCallback disposeCallbackImpl = nullptr;
static SkikoCallBooleanCallback callBooleanCallbackImpl = nullptr; static SkikoCallBooleanCallback callBooleanCallbackImpl = nullptr;
static SkikoCallVoidCallback callVoidCallbackImpl = nullptr;
SKIKO_EXPORT void skiko_initCallbacks(KOpaquePointer callBoolean, KOpaquePointer dispose) { SKIKO_EXPORT void skiko_initCallbacks(KOpaquePointer callBoolean, KOpaquePointer callVoid, KOpaquePointer dispose) {
callBooleanCallbackImpl = reinterpret_cast<SkikoCallBooleanCallback>(callBoolean); callBooleanCallbackImpl = reinterpret_cast<SkikoCallBooleanCallback>(callBoolean);
callVoidCallbackImpl = reinterpret_cast<SkikoCallVoidCallback>(callVoid);
disposeCallbackImpl = reinterpret_cast<SkikoDisposeCallback>(dispose); disposeCallbackImpl = reinterpret_cast<SkikoDisposeCallback>(dispose);
} }
...@@ -360,5 +368,9 @@ KBoolean callBooleanCallback(KInteropPointer cb) { ...@@ -360,5 +368,9 @@ KBoolean callBooleanCallback(KInteropPointer cb) {
return callBooleanCallbackImpl(cb); return callBooleanCallbackImpl(cb);
} }
void callVoidCallback(KInteropPointer cb) {
return callVoidCallbackImpl(cb);
}
#endif // __EMSCRIPTEN__ #endif // __EMSCRIPTEN__
package org.jetbrains.skia
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.interopScope
internal actual fun Drawable.doInit(ptr: NativePointer) {
Stats.onNativeCall()
interopScope {
val onDrawCallback = virtual {
onDraw(Canvas(_nGetOnDrawCanvas(_ptr), false, this))
}
val onGetBoundsCallback = virtual {
val bounds = onGetBounds()
_nSetBounds(_ptr, bounds.left, bounds.top, bounds.right, bounds.bottom)
}
Drawable_nInit(_ptr, onGetBoundsCallback, onDrawCallback)
}
}
...@@ -26,6 +26,7 @@ actual abstract class Native actual constructor(ptr: NativePointer) { ...@@ -26,6 +26,7 @@ actual abstract class Native actual constructor(ptr: NativePointer) {
init { init {
initCallbacks( initCallbacks(
staticCFunction(::callBooleanCallback), staticCFunction(::callBooleanCallback),
staticCFunction(::callVoidCallback),
staticCFunction(::disposeCallback), staticCFunction(::disposeCallback),
) )
} }
...@@ -200,12 +201,21 @@ actual class InteropScope actual constructor() { ...@@ -200,12 +201,21 @@ actual class InteropScope actual constructor() {
return toInterop(interopPointers.map { it.toLong() }.toLongArray()) return toInterop(interopPointers.map { it.toLong() }.toLongArray())
} }
actual fun toInterop(callback: (() -> Boolean)?): InteropPointer actual fun booleanCallback(callback: (() -> Boolean)?): InteropPointer
= callback?.let { = callback?.let {
val ptr = StableRef.create(it).asCPointer() val ptr = StableRef.create(it).asCPointer()
NativePtr.NULL.plus(ptr.toLong()) NativePtr.NULL.plus(ptr.toLong())
} ?: NativePtr.NULL } ?: NativePtr.NULL
actual fun callback(callback: (() -> Unit)?): InteropPointer
= callback?.let {
val ptr = StableRef.create(it).asCPointer()
NativePtr.NULL.plus(ptr.toLong())
} ?: NativePtr.NULL
actual fun virtual(method: () -> Unit) = callback(method)
actual fun virtualBoolean(method: () -> Boolean) = booleanCallback(method)
actual fun release() { actual fun release() {
elements.forEach { elements.forEach {
it.unpin() it.unpin()
...@@ -232,6 +242,10 @@ actual class NativePointerArray actual constructor(size: Int) { ...@@ -232,6 +242,10 @@ actual class NativePointerArray actual constructor(size: Int) {
// Callbacks support // Callbacks support
private fun callVoidCallback(ptr: COpaquePointer) {
ptr.asStableRef<() -> Unit>().get().invoke()
}
private fun callBooleanCallback(ptr: COpaquePointer): Boolean { private fun callBooleanCallback(ptr: COpaquePointer): Boolean {
return ptr.asStableRef<() -> Boolean>().get().invoke() return ptr.asStableRef<() -> Boolean>().get().invoke()
} }
...@@ -241,4 +255,4 @@ private fun disposeCallback(ptr: COpaquePointer) { ...@@ -241,4 +255,4 @@ private fun disposeCallback(ptr: COpaquePointer) {
} }
@ExternalSymbolName("skiko_initCallbacks") @ExternalSymbolName("skiko_initCallbacks")
private external fun initCallbacks(callBoolean: COpaquePointer, dispose: COpaquePointer) private external fun initCallbacks(callBoolean: COpaquePointer, callVoid: COpaquePointer, dispose: COpaquePointer)
\ No newline at end of file \ 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