Unverified Commit a55a6b09 authored by Oleksandr Karpovich's avatar Oleksandr Karpovich Committed by GitHub

add Canvas methods implementations for nativeJsMain (#323)

* CanvasTest.kt: drawString

* CanvasTest.kt: localToDevice

* CanvasTest.kt: setMatrix

* CanvasTest.kt: drawPatch

* add Matrix44.fromInteropPointer to make it reusable
Co-authored-by: 's avatarOleksandr Karpovich <oleksandr.karpovich@jetbrains.com>
parent d90660e8
...@@ -1126,8 +1126,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -1126,8 +1126,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
val localToDevice: Matrix44 val localToDevice: Matrix44
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
val mat = _nGetLocalToDevice(_ptr) Matrix44.fromInteropPointer { interopPointer -> _nGetLocalToDevice(_ptr, interopPointer) }
Matrix44(*mat)
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -1627,7 +1626,7 @@ private external fun _nDrawPaint(ptr: NativePointer, paintPtr: NativePointer) ...@@ -1627,7 +1626,7 @@ private external fun _nDrawPaint(ptr: NativePointer, paintPtr: NativePointer)
private external fun _nSetMatrix(ptr: NativePointer, matrix: InteropPointer) private external fun _nSetMatrix(ptr: NativePointer, matrix: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nGetLocalToDevice") @ExternalSymbolName("org_jetbrains_skia_Canvas__1nGetLocalToDevice")
private external fun _nGetLocalToDevice(ptr: NativePointer): FloatArray private external fun _nGetLocalToDevice(ptr: NativePointer, resultFloats: InteropPointer): FloatArray
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nResetMatrix") @ExternalSymbolName("org_jetbrains_skia_Canvas__1nResetMatrix")
private external fun _nResetMatrix(ptr: NativePointer) private external fun _nResetMatrix(ptr: NativePointer)
......
package org.jetbrains.skia package org.jetbrains.skia
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.withResult
/** /**
* *
* 4x4 matrix used by SkCanvas and other parts of Skia. * 4x4 matrix used by SkCanvas and other parts of Skia.
...@@ -53,6 +56,11 @@ class Matrix44(vararg mat: Float) { ...@@ -53,6 +56,11 @@ class Matrix44(vararg mat: Float) {
companion object { companion object {
val IDENTITY = Matrix44(1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f) val IDENTITY = Matrix44(1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f)
internal fun fromInteropPointer(block: (InteropPointer) -> Unit): Matrix44 {
val result = withResult(FloatArray(16), block)
return Matrix44(*result)
}
} }
/** /**
...@@ -62,4 +70,4 @@ class Matrix44(vararg mat: Float) { ...@@ -62,4 +70,4 @@ class Matrix44(vararg mat: Float) {
require(mat.size == 16) { "Expected 16 elements, got ${mat.size}" } require(mat.size == 16) { "Expected 16 elements, got ${mat.size}" }
this.mat = mat this.mat = mat
} }
} }
\ No newline at end of file
package org.jetbrains.skia package org.jetbrains.skia
import org.jetbrains.skia.tests.makeFromResource
import org.jetbrains.skia.util.assertContentSame import org.jetbrains.skia.util.assertContentSame
import org.jetbrains.skia.util.imageFromIntArray import org.jetbrains.skia.util.imageFromIntArray
import org.jetbrains.skiko.tests.SkipJsTarget
import org.jetbrains.skiko.tests.SkipNativeTarget
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertTrue
class CanvasTest { class CanvasTest {
@Test @Test
...@@ -83,4 +89,105 @@ class CanvasTest { ...@@ -83,4 +89,105 @@ class CanvasTest {
assertContentSame(expected, surface.makeImageSnapshot(), 0.25) assertContentSame(expected, surface.makeImageSnapshot(), 0.25)
} }
private suspend fun fontInter36() =
Font(Typeface.makeFromResource("./fonts/Inter-Hinted-Regular.ttf"), 36f)
// TODO(karpovich): enable for all platforms
// native and js don't work: resulting image has no changed pixels (typeface implementations required)
@Test @SkipNativeTarget @SkipJsTarget
fun drawString() = runTest {
val surface = Surface.makeRasterN32Premul(100, 100)
val bytes = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
assertTrue {
bytes.isNotEmpty() && bytes.all { it == 0.toByte() }
}
surface.canvas.drawString(
s = "Hello world!",
x = 10f, y = 10f,
font = fontInter36(),
paint = Paint().apply {
color = Color.RED
setStroke(false)
}
)
val bytes2 = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
assertTrue {
bytes2.isNotEmpty() && bytes2.any { it != 0.toByte() }
}
}
@Test
fun testLocalToDevice() = runTest {
val surface = Surface.makeRasterN32Premul(100, 100)
val expectedArray = FloatArray(16) { if (it % 5 == 0) 1f else 0f }
assertContentEquals(expectedArray, surface.canvas.localToDevice.mat)
surface.canvas.scale(2f, 2f)
val expectedAfterScale = floatArrayOf(
2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
)
assertContentEquals(expectedAfterScale, surface.canvas.localToDevice.mat)
surface.canvas.resetMatrix()
assertContentEquals(expectedArray, surface.canvas.localToDevice.mat)
}
@Test
fun testSetMatrix() = runTest {
val surface = Surface.makeRasterN32Premul(100, 100)
val expectedArray = FloatArray(16) { if (it % 5 == 0) 1f else 0f }
assertContentEquals(expectedArray, surface.canvas.localToDevice.mat)
surface.canvas.setMatrix(Matrix33.makeScale(2f, 2f))
val expectedAfterScale = floatArrayOf(
2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
)
assertContentEquals(expectedAfterScale, surface.canvas.localToDevice.mat)
}
@Test
fun drawPatch() = runTest {
// source: https://fiddle.skia.org/c/e96c5f9aa21fb97c25058d9e7b9be3a9
val surface = Surface.makeRasterN32Premul(8, 8)
val points = arrayOf(
3, 1, 4, 2, 5, 1, 7, 3, 6, 4, 7, 5, 5, 7, 4, 6, 3, 7, 1, 5, 2, 4, 1, 3
).toList().chunked(2) {
Point(it[0].toFloat(), it[1].toFloat())
}
surface.canvas.drawPatch(
cubics = points.toTypedArray(),
colors = intArrayOf(Color.RED, Color.BLUE, Color.YELLOW, Color.CYAN),
texCoords = null,
paint = Paint()
)
val expected = imageFromIntArray(
pixArray = intArrayOf(
0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(),
0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0xffcb0634.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(),
0x00000000.toInt(), 0x00000000.toInt(), 0xffb63b49.toInt(), 0xff9b3064.toInt(), 0xff762b8a.toInt(), 0xff4b1cb4.toInt(), 0x00000000.toInt(), 0x00000000.toInt(),
0x00000000.toInt(), 0x00000000.toInt(), 0xff8d6e73.toInt(), 0xff866479.toInt(), 0xff7a6386.toInt(), 0xff675698.toInt(), 0xff3632c9.toInt(), 0x00000000.toInt(),
0x00000000.toInt(), 0xff36cdc9.toInt(), 0xff67a998.toInt(), 0xff7a9c86.toInt(), 0xff869b79.toInt(), 0xff8d9173.toInt(), 0x00000000.toInt(), 0x00000000.toInt(),
0x00000000.toInt(), 0x00000000.toInt(), 0xff4be3b4.toInt(), 0xff76d48a.toInt(), 0xff9bcf64.toInt(), 0xffb6c449.toInt(), 0x00000000.toInt(), 0x00000000.toInt(),
0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0xffcbf934.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(),
0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(), 0x00000000.toInt(),
),
imageWidth = 8
)
assertContentSame(expected = expected, got = surface.makeImageSnapshot(), sensitivity = 0.25)
}
} }
...@@ -229,13 +229,13 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nResetMatri ...@@ -229,13 +229,13 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nResetMatri
canvas->resetMatrix(); canvas->resetMatrix();
} }
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_CanvasKt__1nGetLocalToDevice extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nGetLocalToDevice
(JNIEnv* env, jclass jclass, jlong canvasPtr) { (JNIEnv* env, jclass jclass, jlong canvasPtr, jfloatArray resultingMatrix) {
jfloat *floats = env->GetFloatArrayElements(resultingMatrix, NULL);
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(canvasPtr)); SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(canvasPtr));
SkM44 matrix = canvas->getLocalToDevice(); SkM44 matrix = canvas->getLocalToDevice();
std::vector<float> floats(16); matrix.getRowMajor(floats);
matrix.getRowMajor(floats.data()); env->ReleaseFloatArrayElements(resultingMatrix, floats, 0);
return javaFloatArray(env, floats);
} }
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nClipRect extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nClipRect
......
...@@ -124,23 +124,15 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawRegion ...@@ -124,23 +124,15 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawRegion
canvas->drawRegion(*region, *paint); canvas->drawRegion(*region, *paint);
} }
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawString SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawString
(KNativePointer canvasPtr, KInteropPointer stringObj, KFloat x, KFloat y, KNativePointer skFontPtr, KNativePointer paintPtr) { (KNativePointer canvasPtr, KInteropPointer stringObj, KFloat x, KFloat y, KNativePointer skFontPtr, KNativePointer paintPtr) {
TODO("implement org_jetbrains_skia_Canvas__1nDrawString"); SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasPtr);
} SkString string = skString(stringObj);
SkFont* font = reinterpret_cast<SkFont*>(skFontPtr);
#if 0 SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawString
(KNativePointer canvasPtr, KInteropPointer stringObj, KFloat x, KFloat y, KNativePointer skFontPtr, KNativePointer paintPtr) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*> ((canvasPtr));
SkString string = skString(env, stringObj);
SkFont* font = reinterpret_cast<SkFont*> ((skFontPtr));
SkPaint* paint = reinterpret_cast<SkPaint*> ((paintPtr));
canvas->drawString(string, x, y, *font, *paint); canvas->drawString(string, x, y, *font, *paint);
} }
#endif
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawTextBlob SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawTextBlob
...@@ -183,30 +175,18 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawVertices ...@@ -183,30 +175,18 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawVertices
canvas->drawVertices(vertices, static_cast<SkBlendMode>(blendMode), *paint); canvas->drawVertices(vertices, static_cast<SkBlendMode>(blendMode), *paint);
} }
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch
(KNativePointer ptr, KFloat* cubicsArr, KInt* colorsArr, KFloat* texCoordsArr, KInt blendMode, KNativePointer paintPtr) { (KNativePointer ptr, KFloat* cubicsArr, KInt* colorsArr, KFloat* texCoordsArr, KInt blendMode, KNativePointer paintPtr) {
TODO("implement org_jetbrains_skia_Canvas__1nDrawPatch"); SkCanvas* canvas = reinterpret_cast<SkCanvas*>(ptr);
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch
(KNativePointer ptr, KFloat* cubicsArr, KInt* colorsArr, KFloat* texCoordsArr, KInt blendMode, KNativePointer paintPtr) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*> ((ptr));
KFloat* cubics = env->GetFloatArrayElements(cubicsArr, 0);
KInt* colors = env->GetIntArrayElements(colorsArr, 0);
KFloat* texCoords = texCoordsArr == nullptr ? nullptr : env->GetFloatArrayElements(texCoordsArr, 0);
SkPaint* paint = reinterpret_cast<SkPaint*>((paintPtr)); SkPaint* paint = reinterpret_cast<SkPaint*>((paintPtr));
canvas->drawPatch(
canvas->drawPatch(reinterpret_cast<SkPoint*>(cubics), reinterpret_cast<SkColor*>(colors), reinterpret_cast<SkPoint*>(texCoords), static_cast<SkBlendMode>(blendMode), *paint); reinterpret_cast<SkPoint*>(cubicsArr),
reinterpret_cast<SkColor*>(colorsArr),
if (texCoords != nullptr) reinterpret_cast<SkPoint*>(texCoordsArr),
env->ReleaseFloatArrayElements(texCoordsArr, texCoords, 0); static_cast<SkBlendMode>(blendMode),
env->ReleaseIntArrayElements(colorsArr, colors, 0); *paint
env->ReleaseFloatArrayElements(cubicsArr, cubics, 0); );
} }
#endif
...@@ -238,21 +218,12 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPaint ...@@ -238,21 +218,12 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPaint
canvas->drawPaint(*paint); canvas->drawPaint(*paint);
} }
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nSetMatrix
(KNativePointer canvasPtr, KFloat* matrixArr) {
TODO("implement org_jetbrains_skia_Canvas__1nSetMatrix");
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nSetMatrix SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nSetMatrix
(KNativePointer canvasPtr, KFloat* matrixArr) { (KNativePointer canvasPtr, KFloat* matrixArr) {
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);
canvas->setMatrix(*matrix); canvas->setMatrix(*matrix);
} }
#endif
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nResetMatrix SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nResetMatrix
(KNativePointer canvasPtr) { (KNativePointer canvasPtr) {
...@@ -261,22 +232,12 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nResetMatrix ...@@ -261,22 +232,12 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nResetMatrix
} }
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Canvas__1nGetLocalToDevice SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nGetLocalToDevice
(KNativePointer canvasPtr) { (KNativePointer canvasPtr, KFloat* resultingFloats) {
TODO("implement org_jetbrains_skia_Canvas__1nGetLocalToDevice"); SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasPtr);
} SkM44 matrix = canvas->getLocalToDevice();
matrix.getRowMajor(resultingFloats);
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Canvas__1nGetLocalToDevice
(KNativePointer canvasPtr) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
SkM44 matrix = canvas->getLocalToDevice();
std::vector<float> floats(16);
matrix.getRowMajor(floats.data());
return javaFloatArray(env, floats);
} }
#endif
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nClipRect SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nClipRect
(KNativePointer canvasPtr, KFloat left, KFloat top, KFloat right, KFloat bottom, KInt mode, KBoolean antiAlias) { (KNativePointer canvasPtr, KFloat left, KFloat top, KFloat right, KFloat bottom, KInt mode, KBoolean antiAlias) {
......
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