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
val localToDevice: Matrix44
get() = try {
Stats.onNativeCall()
val mat = _nGetLocalToDevice(_ptr)
Matrix44(*mat)
Matrix44.fromInteropPointer { interopPointer -> _nGetLocalToDevice(_ptr, interopPointer) }
} finally {
reachabilityBarrier(this)
}
......@@ -1627,7 +1626,7 @@ private external fun _nDrawPaint(ptr: NativePointer, paintPtr: NativePointer)
private external fun _nSetMatrix(ptr: NativePointer, matrix: InteropPointer)
@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")
private external fun _nResetMatrix(ptr: NativePointer)
......
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.
......@@ -53,6 +56,11 @@ class Matrix44(vararg mat: Float) {
companion object {
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)
}
}
/**
......
package org.jetbrains.skia
import org.jetbrains.skia.tests.makeFromResource
import org.jetbrains.skia.util.assertContentSame
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.assertContentEquals
import kotlin.test.assertTrue
class CanvasTest {
@Test
......@@ -83,4 +89,105 @@ class CanvasTest {
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
canvas->resetMatrix();
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_CanvasKt__1nGetLocalToDevice
(JNIEnv* env, jclass jclass, jlong canvasPtr) {
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nGetLocalToDevice
(JNIEnv* env, jclass jclass, jlong canvasPtr, jfloatArray resultingMatrix) {
jfloat *floats = env->GetFloatArrayElements(resultingMatrix, NULL);
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(canvasPtr));
SkM44 matrix = canvas->getLocalToDevice();
std::vector<float> floats(16);
matrix.getRowMajor(floats.data());
return javaFloatArray(env, floats);
matrix.getRowMajor(floats);
env->ReleaseFloatArrayElements(resultingMatrix, floats, 0);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nClipRect
......
......@@ -124,23 +124,15 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawRegion
canvas->drawRegion(*region, *paint);
}
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawString
(KNativePointer canvasPtr, KInteropPointer stringObj, KFloat x, KFloat y, KNativePointer skFontPtr, KNativePointer paintPtr) {
TODO("implement org_jetbrains_skia_Canvas__1nDrawString");
}
#if 0
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));
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasPtr);
SkString string = skString(stringObj);
SkFont* font = reinterpret_cast<SkFont*>(skFontPtr);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
canvas->drawString(string, x, y, *font, *paint);
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawTextBlob
......@@ -183,30 +175,18 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawVertices
canvas->drawVertices(vertices, static_cast<SkBlendMode>(blendMode), *paint);
}
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch
(KNativePointer ptr, KFloat* cubicsArr, KInt* colorsArr, KFloat* texCoordsArr, KInt blendMode, KNativePointer paintPtr) {
TODO("implement org_jetbrains_skia_Canvas__1nDrawPatch");
}
#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);
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(ptr);
SkPaint* paint = reinterpret_cast<SkPaint*>((paintPtr));
canvas->drawPatch(reinterpret_cast<SkPoint*>(cubics), reinterpret_cast<SkColor*>(colors), reinterpret_cast<SkPoint*>(texCoords), static_cast<SkBlendMode>(blendMode), *paint);
if (texCoords != nullptr)
env->ReleaseFloatArrayElements(texCoordsArr, texCoords, 0);
env->ReleaseIntArrayElements(colorsArr, colors, 0);
env->ReleaseFloatArrayElements(cubicsArr, cubics, 0);
canvas->drawPatch(
reinterpret_cast<SkPoint*>(cubicsArr),
reinterpret_cast<SkColor*>(colorsArr),
reinterpret_cast<SkPoint*>(texCoordsArr),
static_cast<SkBlendMode>(blendMode),
*paint
);
}
#endif
......@@ -238,21 +218,12 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPaint
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
(KNativePointer canvasPtr, KFloat* matrixArr) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
std::unique_ptr<SkMatrix> matrix = skMatrix(env, matrixArr);
std::unique_ptr<SkMatrix> matrix = skMatrix(matrixArr);
canvas->setMatrix(*matrix);
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nResetMatrix
(KNativePointer canvasPtr) {
......@@ -261,22 +232,12 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nResetMatrix
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Canvas__1nGetLocalToDevice
(KNativePointer canvasPtr) {
TODO("implement org_jetbrains_skia_Canvas__1nGetLocalToDevice");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Canvas__1nGetLocalToDevice
(KNativePointer canvasPtr) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nGetLocalToDevice
(KNativePointer canvasPtr, KFloat* resultingFloats) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasPtr);
SkM44 matrix = canvas->getLocalToDevice();
std::vector<float> floats(16);
matrix.getRowMajor(floats.data());
return javaFloatArray(env, floats);
matrix.getRowMajor(resultingFloats);
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nClipRect
(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