Unverified Commit 1c901241 authored by Alexander Maryanovsky's avatar Alexander Maryanovsky Committed by GitHub

Reimplement the Canvas transformation functions via the corresponding Skia...

Reimplement the Canvas transformation functions via the corresponding Skia functions, rather than by concatenating with a transformation matrix. (#724)
parent 697d4896
......@@ -1080,11 +1080,19 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
}
fun translate(dx: Float, dy: Float): Canvas {
return concat(Matrix33.makeTranslate(dx, dy))
interopScope {
Stats.onNativeCall()
_nTranslate(_ptr, dx, dy)
}
return this
}
fun scale(sx: Float, sy: Float): Canvas {
return concat(Matrix33.makeScale(sx, sy))
interopScope {
Stats.onNativeCall()
_nScale(_ptr, sx, sy)
}
return this
}
/**
......@@ -1092,15 +1100,27 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
* @return this
*/
fun rotate(deg: Float): Canvas {
return concat(Matrix33.makeRotate(deg))
interopScope {
Stats.onNativeCall()
_nRotate(_ptr, deg, 0f, 0f)
}
return this
}
fun rotate(deg: Float, x: Float, y: Float): Canvas {
return concat(Matrix33.makeRotate(deg, x, y))
interopScope {
Stats.onNativeCall()
_nRotate(_ptr, deg, x, y)
}
return this
}
fun skew(sx: Float, sy: Float): Canvas {
return concat(Matrix33.makeSkew(sx, sy))
interopScope {
Stats.onNativeCall()
_nSkew(_ptr, sx, sy)
}
return this
}
fun concat(matrix: Matrix33): Canvas {
......@@ -1542,14 +1562,24 @@ private external fun _nClipPath(ptr: NativePointer, nativePath: NativePointer, m
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nClipRegion")
private external fun _nClipRegion(ptr: NativePointer, nativeRegion: NativePointer, mode: Int)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nTranslate")
private external fun _nTranslate(ptr: NativePointer, dx: Float, dy: Float)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nScale")
private external fun _nScale(ptr: NativePointer, sx: Float, sy: Float)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nRotate")
private external fun _nRotate(ptr: NativePointer, deg: Float, x: Float, y: Float)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nSkew")
private external fun _nSkew(ptr: NativePointer, sx: Float, sy: Float)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nConcat")
private external fun _nConcat(ptr: NativePointer, matrix: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nConcat44")
private external fun _nConcat44(ptr: NativePointer, matrix: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nReadPixels")
private external fun _nReadPixels(ptr: NativePointer, bitmapPtr: NativePointer, srcX: Int, srcY: Int): Boolean
......
@file:Suppress("RemoveRedundantCallsOfConversionMethods")
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
fun drawVertices() {
val surface = Surface.makeRasterN32Premul(8, 8)
......@@ -189,4 +191,104 @@ class CanvasTest {
assertContentSame(expected = expected, got = surface.makeImageSnapshot(), sensitivity = 0.25)
}
@Test
fun testTranslate() {
val surface = whiteSurface(4, 4)
surface.canvas.translate(2f, 2f)
surface.canvas.drawBlackPixel(0, 0)
surface.assertSingleBlackPixelAt(2, 2)
}
@Test
fun testScale() {
val surface = whiteSurface(4, 4)
surface.canvas.scale(2f, 2f)
surface.canvas.drawBlackPixel(1, 1)
surface.assertPixelsMatch(
IntArray(16){ index ->
when (index) {
10, 11, 14, 15 -> 0xff000000.toInt()
else -> 0xffffffff.toInt()
}
}
)
}
@Test
fun testRotate() {
val surface = whiteSurface(4, 4)
surface.canvas.rotate(deg = 90f)
surface.canvas.drawBlackPixel(3, -1)
surface.assertSingleBlackPixelAt(0, 3)
}
@Test
fun testRotateXY() {
val surface = whiteSurface(4, 4)
surface.canvas.rotate(deg = 90f, x = 2f, y=2f)
surface.canvas.drawBlackPixel(0, 0)
surface.assertSingleBlackPixelAt(3, 0)
}
@Test
fun testSkew() {
val surface = whiteSurface(4, 4)
surface.canvas.skew(sx = 0.5f, sy = 0f)
surface.canvas.drawBlackPixel(0, 2)
surface.assertPixelsMatch(
IntArray(16){ index ->
when (index) {
// Skewing skews the shape of the pixel itself, so it becomes a parallelogram
9 -> 0xff3f3f3f.toInt()
10 -> 0xffbfbfbf.toInt()
else -> 0xffffffff.toInt()
}
}
)
}
private fun whiteSurface(width: Int, height: Int): Surface {
val surface = Surface.makeRasterN32Premul(width, height)
val white = Paint().also { it.setARGB(255, 255, 255, 255) }
surface.canvas.drawRect(Rect(0f, 0f, width.toFloat(), height.toFloat()), white)
return surface
}
private fun Canvas.drawBlackPixel(x: Int, y: Int) {
val black = Paint().also { it.setARGB(255, 0, 0, 0) }
drawRect(Rect(x.toFloat(), y.toFloat(), (x + 1).toFloat(), (y + 1).toFloat()), black)
}
private fun Surface.assertPixelsMatch(pixArray: IntArray) {
assertContentSame(
expected = imageFromIntArray(
pixArray = pixArray,
imageWidth = width
),
got = makeImageSnapshot(),
sensitivity = 0.0
)
}
private fun Surface.assertSingleBlackPixelAt(x: Int, y: Int) {
val pixArray = IntArray(width * height){ 0xffffffff.toInt() }
pixArray[y*width + x] = 0xff000000.toInt()
assertPixelsMatch(pixArray)
}
}
......@@ -278,6 +278,30 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nConcat44
canvas->concat(*m);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nTranslate
(JNIEnv* env, jclass jclass, jlong ptr, jfloat dx, jfloat dy) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr));
canvas->translate(dx, dy);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nScale
(JNIEnv* env, jclass jclass, jlong ptr, jfloat sx, jfloat sy) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr));
canvas->scale(sx, sy);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nRotate
(JNIEnv* env, jclass jclass, jlong ptr, jfloat deg, jfloat x, jfloat y) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr));
canvas->rotate(deg, x, y);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_CanvasKt__1nSkew
(JNIEnv* env, jclass jclass, jlong ptr, jfloat sx, jfloat sy) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr));
canvas->skew(sx, sy);
}
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_CanvasKt__1nReadPixels
(JNIEnv* env, jclass jclass, jlong ptr, jlong bitmapPtr, jint srcX, jint srcY) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr));
......
......@@ -269,6 +269,34 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nConcat44
}
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nTranslate
(KNativePointer canvasPtr, KFloat dx, KFloat dy) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
canvas->translate(dx, dy);
}
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nScale
(KNativePointer canvasPtr, KFloat sx, KFloat sy) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
canvas->scale(sx, sy);
}
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nRotate
(KNativePointer canvasPtr, KFloat deg, KFloat x, KFloat y) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
canvas->rotate(deg, x, y);
}
SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nSkew
(KNativePointer canvasPtr, KFloat sx, KFloat sy) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((canvasPtr));
canvas->skew(sx, sy);
}
SKIKO_EXPORT KInt org_jetbrains_skia_Canvas__1nReadPixels
(KNativePointer ptr, KNativePointer bitmapPtr, KInt srcX, KInt srcY) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((ptr));
......
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