diff --git a/skiko/src/commonMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.kt b/skiko/src/commonMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.kt index 23b3bfbb3..5fe39fbf7 100644 --- a/skiko/src/commonMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.kt +++ b/skiko/src/commonMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.kt @@ -8,7 +8,7 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad */ abstract class PaintFilterCanvas(private val canvas: Canvas, unrollDrawable: Boolean) : Canvas(makePaintFilterCanvas(canvas, unrollDrawable), true, canvas) { - companion object { + private companion object { init { staticLoad() } @@ -23,7 +23,9 @@ abstract class PaintFilterCanvas(private val canvas: Canvas, unrollDrawable: Boo * * Note: The base implementation calls onFilter() for top-level/explicit paints only. */ - abstract fun onFilter(paint: Paint): Boolean + protected abstract fun onFilter(paint: Paint): Boolean + + // For JNI call fun onFilter(paintPtr: NativePointer): Boolean { val paint = Paint(paintPtr, false) return onFilter(paint) @@ -56,13 +58,3 @@ internal expect fun PaintFilterCanvas.doInit(ptr: NativePointer) @ExternalSymbolName("org_jetbrains_skia_PaintFilterCanvas__1nMake") @ModuleImport("./skiko.mjs", "org_jetbrains_skia_PaintFilterCanvas__1nMake") private external fun PaintFilterCanvas_nMake(canvasPtr: NativePointer, unrollDrawable: Boolean): NativePointer - -// Native/JS only - -@ExternalSymbolName("org_jetbrains_skia_PaintFilterCanvas__1nInit") -@ModuleImport("./skiko.mjs", "org_jetbrains_skia_PaintFilterCanvas__1nInit") -internal external fun PaintFilterCanvas_nInit(ptr: NativePointer, onFilter: InteropPointer) - -@ExternalSymbolName("org_jetbrains_skia_PaintFilterCanvas__1nGetOnFilterPaint") -@ModuleImport("./skiko.mjs", "org_jetbrains_skia_PaintFilterCanvas__1nGetOnFilterPaint") -internal external fun PaintFilterCanvas_nGetOnFilterPaint(ptr: NativePointer): NativePointer diff --git a/skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt b/skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt index 57206331d..d98ffa356 100644 --- a/skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt +++ b/skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt @@ -3,7 +3,7 @@ package org.jetbrains.skia import org.jetbrains.skia.impl.* import org.jetbrains.skia.impl.Library.Companion.staticLoad -class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) { +class Picture internal constructor(ptr: NativePointer, managed: Boolean = true) : RefCnt(ptr, managed) { companion object { /** * Recreates Picture that was serialized into data. Returns constructed Picture diff --git a/skiko/src/commonMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.kt b/skiko/src/commonMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.kt new file mode 100644 index 000000000..8c1fabf0e --- /dev/null +++ b/skiko/src/commonMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.kt @@ -0,0 +1,48 @@ +package org.jetbrains.skia + +import org.jetbrains.skia.impl.Library.Companion.staticLoad +import org.jetbrains.skia.impl.NativePointer +import org.jetbrains.skia.impl.Stats +import org.jetbrains.skia.impl.getPtr +import org.jetbrains.skia.impl.reachabilityBarrier + +abstract class PictureFilterCanvas(canvas: Canvas) : + Canvas(makePictureFilterCanvas(canvas), true, this) { + private companion object { + init { + staticLoad() + } + } + init { + Stats.onNativeCall() + try { + doInit(_ptr) + } finally { + reachabilityBarrier(this) + } + } + + protected abstract fun onDrawPicture(picture: Picture, matrix: Matrix33? = null, paint: Paint? = null): Boolean + + fun onDrawPicture(picturePtr: NativePointer, matrixPtr: NativePointer, paintPtr: NativePointer): Boolean { + val picture = Picture(picturePtr, managed = false) + // TODO: Provide mapping for matrix arg + val paint = if (paintPtr == NullPointer) null else Paint(paintPtr, managed = false) + return onDrawPicture(picture, null, paint) + } +} + +private fun makePictureFilterCanvas(canvas: Canvas): NativePointer { + Stats.onNativeCall() + return try { + PictureFilterCanvas_nMake(getPtr(canvas)) + } finally { + reachabilityBarrier(canvas) + } +} + +internal expect fun PictureFilterCanvas.doInit(ptr: NativePointer) + +@ExternalSymbolName("org_jetbrains_skia_PictureFilterCanvas__1nMake") +@ModuleImport("./skiko.mjs", "org_jetbrains_skia_PictureFilterCanvas__1nMake") +private external fun PictureFilterCanvas_nMake(canvasPtr: NativePointer): NativePointer diff --git a/skiko/src/jvmMain/cpp/common/PaintFilterCanvas.cc b/skiko/src/jvmMain/cpp/common/PaintFilterCanvas.cc index fd729ad61..2138be1c7 100644 --- a/skiko/src/jvmMain/cpp/common/PaintFilterCanvas.cc +++ b/skiko/src/jvmMain/cpp/common/PaintFilterCanvas.cc @@ -5,14 +5,14 @@ #include "SkPaintFilterCanvas.h" #include "interop.hh" -class SkijaPaintFilterCanvas : public SkPaintFilterCanvas { +class SkikoPaintFilterCanvas : public SkPaintFilterCanvas { public: - SkijaPaintFilterCanvas( + SkikoPaintFilterCanvas( SkCanvas* canvas, bool unrollDrawable ) : SkPaintFilterCanvas(canvas), unrollDrawable(unrollDrawable) {} - virtual ~SkijaPaintFilterCanvas() { + virtual ~SkikoPaintFilterCanvas() { skija::PaintFilterCanvas::detach(jobj); } @@ -37,13 +37,13 @@ class SkijaPaintFilterCanvas : public SkPaintFilterCanvas { extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PaintFilterCanvas_1jvmKt_PaintFilterCanvas_1nInit (JNIEnv* env, jclass jclass, jobject jobj, jlong canvasPtr) { - SkijaPaintFilterCanvas* canvas = reinterpret_cast(static_cast(canvasPtr)); + SkikoPaintFilterCanvas* canvas = reinterpret_cast(static_cast(canvasPtr)); canvas->jobj = skija::PaintFilterCanvas::attach(env, jobj); } extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_PaintFilterCanvasKt_PaintFilterCanvas_1nMake (JNIEnv* env, jclass jclass, jlong canvasPtr, jboolean unrollDrawable) { SkCanvas* canvas = reinterpret_cast(static_cast(canvasPtr)); - SkijaPaintFilterCanvas* filterCanvas = new SkijaPaintFilterCanvas(canvas, unrollDrawable); + SkikoPaintFilterCanvas* filterCanvas = new SkikoPaintFilterCanvas(canvas, unrollDrawable); return reinterpret_cast(filterCanvas); } \ No newline at end of file diff --git a/skiko/src/jvmMain/cpp/common/PictureFilterCanvas.cc b/skiko/src/jvmMain/cpp/common/PictureFilterCanvas.cc new file mode 100644 index 000000000..7f642c3ad --- /dev/null +++ b/skiko/src/jvmMain/cpp/common/PictureFilterCanvas.cc @@ -0,0 +1,38 @@ +#include +#include "SkNWayCanvas.h" +#include "interop.hh" + +class SkikoPictureFilterCanvas : public SkNWayCanvas { +public: + SkikoPictureFilterCanvas(SkCanvas* canvas) : + SkNWayCanvas(canvas->imageInfo().width(), canvas->imageInfo().height()), + _jobject(nullptr) { + this->addCanvas(canvas); + } + + virtual ~SkikoPictureFilterCanvas() { + skija::PictureFilterCanvas::detach(_jobject); + } + + jobject _jobject; + +protected: + void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) override { + jboolean handled = skija::PictureFilterCanvas::onDrawPicture(_jobject, picture, matrix, paint); + if (!handled) { + SkCanvas::onDrawPicture(picture, matrix, paint); + } + } +}; + +extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PictureFilterCanvas_1jvmKt_PictureFilterCanvas_1nInit + (JNIEnv* env, jclass jclass, jobject pictureFilterCanvas, jlong canvasPtr) { + SkikoPictureFilterCanvas* canvas = reinterpret_cast(static_cast(canvasPtr)); + canvas->_jobject = skija::PictureFilterCanvas::attach(env, pictureFilterCanvas); +} + +extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_PictureFilterCanvasKt_PictureFilterCanvas_1nMake + (JNIEnv* env, jclass jclass, SkCanvas* canvas) { + SkikoPictureFilterCanvas* filterCanvas = new SkikoPictureFilterCanvas(canvas); + return reinterpret_cast(filterCanvas); +} diff --git a/skiko/src/jvmMain/cpp/common/interop.cc b/skiko/src/jvmMain/cpp/common/interop.cc index 5b7317731..7244e64c3 100644 --- a/skiko/src/jvmMain/cpp/common/interop.cc +++ b/skiko/src/jvmMain/cpp/common/interop.cc @@ -653,6 +653,39 @@ namespace skija { } } + namespace PictureFilterCanvas { + JavaVM* _vm; + jmethodID onDrawPictureId; + + void onLoad(JNIEnv* env) { + env->GetJavaVM(&_vm); + jclass local = env->FindClass("org/jetbrains/skia/PictureFilterCanvas"); + onDrawPictureId = env->GetMethodID(local, "onDrawPicture", "(JJJ)Z"); + } + + void onUnload(JNIEnv* env) { + } + + bool onDrawPicture(jobject obj, const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { + JNIEnv *env; + _vm->AttachCurrentThread(AS_JNI_ENV_PTR(&env), NULL); + jboolean result = env->CallBooleanMethod(obj, onDrawPictureId, reinterpret_cast(picture), reinterpret_cast(matrix), reinterpret_cast(paint)); + _vm->DetachCurrentThread(); + return result; + } + + jobject attach(JNIEnv* env, jobject obj) { + return env->NewGlobalRef(obj); + } + + void detach(jobject obj) { + JNIEnv *env; + _vm->AttachCurrentThread(AS_JNI_ENV_PTR(&env), NULL); + env->DeleteGlobalRef(obj); + _vm->DetachCurrentThread(); + } + } + namespace Rect { jclass cls; jmethodID makeLTRB; @@ -897,6 +930,7 @@ namespace skija { PathSegment::onLoad(env); Point::onLoad(env); PaintFilterCanvas::onLoad(env); + PictureFilterCanvas::onLoad(env); Rect::onLoad(env); RRect::onLoad(env); RSXform::onLoad(env); @@ -909,6 +943,7 @@ namespace skija { RRect::onUnload(env); Rect::onUnload(env); PaintFilterCanvas::onUnload(env); + PictureFilterCanvas::onUnload(env); Point::onUnload(env); PathSegment::onUnload(env); Path::onUnload(env); diff --git a/skiko/src/jvmMain/cpp/common/interop.hh b/skiko/src/jvmMain/cpp/common/interop.hh index 96e030236..80a660512 100644 --- a/skiko/src/jvmMain/cpp/common/interop.hh +++ b/skiko/src/jvmMain/cpp/common/interop.hh @@ -10,6 +10,7 @@ #include "SkMatrix.h" #include "SkM44.h" #include "SkPaint.h" +#include "SkPicture.h" #include "SkRefCnt.h" #include "SkRect.h" #include "SkRRect.h" @@ -271,6 +272,15 @@ namespace skija { void detach(jobject obj); } + namespace PictureFilterCanvas { + extern jmethodID onDrawPictureId; + void onLoad(JNIEnv* env); + void onUnload(JNIEnv* env); + bool onDrawPicture(jobject obj, const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint); + jobject attach(JNIEnv* env, jobject obj); + void detach(jobject obj); + } + namespace Rect { extern jclass cls; extern jmethodID makeLTRB; diff --git a/skiko/src/jvmMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.jvm.kt b/skiko/src/jvmMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.jvm.kt new file mode 100644 index 000000000..05a6b600a --- /dev/null +++ b/skiko/src/jvmMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.jvm.kt @@ -0,0 +1,9 @@ +package org.jetbrains.skia + +import org.jetbrains.skia.impl.NativePointer + +internal actual fun PictureFilterCanvas.doInit(ptr: NativePointer) { + PictureFilterCanvas_nInit(this, ptr) +} + +private external fun PictureFilterCanvas_nInit(thisPtr: PictureFilterCanvas, canvasPtr: NativePointer) diff --git a/skiko/src/nativeJsMain/cpp/PaintFilterCanvas.cc b/skiko/src/nativeJsMain/cpp/PaintFilterCanvas.cc index 1bae6d98e..93b101722 100644 --- a/skiko/src/nativeJsMain/cpp/PaintFilterCanvas.cc +++ b/skiko/src/nativeJsMain/cpp/PaintFilterCanvas.cc @@ -1,28 +1,28 @@ -#include #include "SkCanvas.h" #include "SkDrawable.h" #include "SkPaintFilterCanvas.h" #include "common.h" -class SkijaPaintFilterCanvas : public SkPaintFilterCanvas { +class SkikoPaintFilterCanvas : public SkPaintFilterCanvas { public: - SkijaPaintFilterCanvas( + SkikoPaintFilterCanvas( SkCanvas* canvas, bool unrollDrawable - ) : SkPaintFilterCanvas(canvas), unrollDrawable(unrollDrawable), _onFilter(nullptr), _onFilterPaint(nullptr) {} + ) : SkPaintFilterCanvas(canvas), unrollDrawable(unrollDrawable), _onFilter(nullptr), _onFilter_paint(nullptr) {} SkPaint* onFilterPaint() const { - return _onFilterPaint; + return _onFilter_paint; } void init(KInteropPointer onFilter) { _onFilter = KBooleanCallback(onFilter); } + protected: bool onFilter(SkPaint& paint) const override { - _onFilterPaint = &paint; + _onFilter_paint = &paint; KBoolean result = _onFilter(); - _onFilterPaint = nullptr; + _onFilter_paint = nullptr; return static_cast(result); } @@ -36,26 +36,29 @@ class SkijaPaintFilterCanvas : public SkPaintFilterCanvas { private: KBooleanCallback _onFilter; - mutable SkPaint* _onFilterPaint; + + // TODO: Support callback with parameters properly + mutable SkPaint* _onFilter_paint; + bool unrollDrawable; }; SKIKO_EXPORT void org_jetbrains_skia_PaintFilterCanvas__1nInit (KNativePointer canvasPtr, KInteropPointer onFilter) { - SkijaPaintFilterCanvas* canvas = reinterpret_cast((canvasPtr)); + SkikoPaintFilterCanvas* canvas = reinterpret_cast((canvasPtr)); canvas->init(onFilter); } SKIKO_EXPORT KNativePointer org_jetbrains_skia_PaintFilterCanvas__1nMake (KNativePointer canvasPtr, KBoolean unrollDrawable) { SkCanvas* canvas = reinterpret_cast((canvasPtr)); - SkijaPaintFilterCanvas* filterCanvas = new SkijaPaintFilterCanvas(canvas, unrollDrawable); + SkikoPaintFilterCanvas* filterCanvas = new SkikoPaintFilterCanvas(canvas, unrollDrawable); return reinterpret_cast(filterCanvas); } SKIKO_EXPORT KNativePointer org_jetbrains_skia_PaintFilterCanvas__1nGetOnFilterPaint (KNativePointer canvasPtr) { - SkijaPaintFilterCanvas* canvas = reinterpret_cast((canvasPtr)); + SkikoPaintFilterCanvas* canvas = reinterpret_cast((canvasPtr)); return reinterpret_cast(canvas->onFilterPaint()); } diff --git a/skiko/src/nativeJsMain/cpp/PictureFilterCanvas.cc b/skiko/src/nativeJsMain/cpp/PictureFilterCanvas.cc new file mode 100644 index 000000000..7b1fc7712 --- /dev/null +++ b/skiko/src/nativeJsMain/cpp/PictureFilterCanvas.cc @@ -0,0 +1,68 @@ +#include "SkNWayCanvas.h" +#include "common.h" + +class SkikoPictureFilterCanvas : public SkNWayCanvas { +public: + SkikoPictureFilterCanvas(SkCanvas* canvas) : + SkNWayCanvas(canvas->imageInfo().width(), canvas->imageInfo().height()), + _onDrawPicture(nullptr), + _onDrawPicture_picture(nullptr), + _onDrawPicture_matrix(nullptr), + _onDrawPicture_paint(nullptr) { + this->addCanvas(canvas); + } + + KBooleanCallback _onDrawPicture; + + // TODO: Support callback with parameters properly + const SkPicture* _onDrawPicture_picture; + const SkMatrix* _onDrawPicture_matrix; + const SkPaint* _onDrawPicture_paint; + +protected: + void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) override { + _onDrawPicture_picture = picture; + _onDrawPicture_matrix = matrix; + _onDrawPicture_paint = paint; + + KBoolean handled = _onDrawPicture(); + + _onDrawPicture_picture = nullptr; + _onDrawPicture_matrix = nullptr; + _onDrawPicture_paint = nullptr; + + if (!handled) { + SkCanvas::onDrawPicture(picture, matrix, paint); + } + } +}; + +SKIKO_EXPORT KNativePointer org_jetbrains_skia_SkikoPictureFilterCanvas__1nMake + (SkCanvas* canvas) { + SkikoPictureFilterCanvas* filterCanvas = new SkikoPictureFilterCanvas(canvas); + return reinterpret_cast(filterCanvas); +} + +SKIKO_EXPORT void org_jetbrains_skia_SkikoPictureFilterCanvas__1nInit + (KNativePointer canvasPtr, KInteropPointer onDrawPicture) { + SkikoPictureFilterCanvas* canvas = reinterpret_cast(canvasPtr); + canvas->_onDrawPicture = KBooleanCallback(onDrawPicture); +} + +SKIKO_EXPORT KNativePointer org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_picture + (KNativePointer canvasPtr) { + SkikoPictureFilterCanvas* canvas = reinterpret_cast(canvasPtr); + return reinterpret_cast(const_cast(canvas->_onDrawPicture_picture)); +} + +SKIKO_EXPORT KNativePointer org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_matrix + (KNativePointer canvasPtr) { + SkikoPictureFilterCanvas* canvas = reinterpret_cast(canvasPtr); + return reinterpret_cast(const_cast(canvas->_onDrawPicture_matrix)); +} + +SKIKO_EXPORT KNativePointer org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_paint + (KNativePointer canvasPtr) { + SkikoPictureFilterCanvas* canvas = reinterpret_cast(canvasPtr); + return reinterpret_cast(const_cast(canvas->_onDrawPicture_paint)); +} diff --git a/skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.nativejs.kt b/skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.nativejs.kt index 018563a96..9da043f81 100644 --- a/skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.nativejs.kt +++ b/skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/PaintFilterCanvas.nativejs.kt @@ -1,14 +1,22 @@ package org.jetbrains.skia +import org.jetbrains.skia.impl.InteropPointer import org.jetbrains.skia.impl.NativePointer import org.jetbrains.skia.impl.interopScope internal actual fun PaintFilterCanvas.doInit(ptr: NativePointer) { interopScope { val onFilter = virtualBoolean { - val paint = Paint(PaintFilterCanvas_nGetOnFilterPaint(ptr), false) - onFilter(paint) + onFilter(PaintFilterCanvas_nGetOnFilterPaint(ptr)) } PaintFilterCanvas_nInit(ptr, onFilter) } } + +@ExternalSymbolName("org_jetbrains_skia_PaintFilterCanvas__1nInit") +@ModuleImport("./skiko.mjs", "org_jetbrains_skia_PaintFilterCanvas__1nInit") +internal external fun PaintFilterCanvas_nInit(ptr: NativePointer, onFilter: InteropPointer) + +@ExternalSymbolName("org_jetbrains_skia_PaintFilterCanvas__1nGetOnFilterPaint") +@ModuleImport("./skiko.mjs", "org_jetbrains_skia_PaintFilterCanvas__1nGetOnFilterPaint") +internal external fun PaintFilterCanvas_nGetOnFilterPaint(ptr: NativePointer): NativePointer diff --git a/skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.nativeJs.kt b/skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.nativeJs.kt new file mode 100644 index 000000000..6d845b8bb --- /dev/null +++ b/skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/PictureFilterCanvas.nativeJs.kt @@ -0,0 +1,34 @@ +package org.jetbrains.skia + +import org.jetbrains.skia.impl.InteropPointer +import org.jetbrains.skia.impl.NativePointer +import org.jetbrains.skia.impl.interopScope + +internal actual fun PictureFilterCanvas.doInit(ptr: NativePointer) { + interopScope { + val onFilter = virtualBoolean { + onDrawPicture( + picturePtr = PictureFilterCanvas_nGetOnDrawPicture_picture(ptr), + matrixPtr = PictureFilterCanvas_nGetOnDrawPicture_matrix(ptr), + paintPtr = PictureFilterCanvas_nGetOnDrawPicture_paint(ptr) + ) + } + PictureFilterCanvas_nInit(ptr, onFilter) + } +} + +@ExternalSymbolName("org_jetbrains_skia_PictureFilterCanvas__1nInit") +@ModuleImport("./skiko.mjs", "org_jetbrains_skia_PictureFilterCanvas__1nInit") +internal external fun PictureFilterCanvas_nInit(ptr: NativePointer, onFilter: InteropPointer) + +@ExternalSymbolName("org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_picture") +@ModuleImport("./skiko.mjs", "org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_picture") +internal external fun PictureFilterCanvas_nGetOnDrawPicture_picture(ptr: NativePointer): NativePointer + +@ExternalSymbolName("org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_matrix") +@ModuleImport("./skiko.mjs", "org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_matrix") +internal external fun PictureFilterCanvas_nGetOnDrawPicture_matrix(ptr: NativePointer): NativePointer + +@ExternalSymbolName("org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_paint") +@ModuleImport("./skiko.mjs", "org_jetbrains_skia_SkikoPictureFilterCanvas__1nGetOnDrawPicture_paint") +internal external fun PictureFilterCanvas_nGetOnDrawPicture_paint(ptr: NativePointer): NativePointer