Unverified Commit b73b3744 authored by Artem Bobrov's avatar Artem Bobrov Committed by GitHub

Add a new saveLayer method to Canvas (already exists in Skia) (#995)

Co-authored-by: 's avatarArtem Bobrov <artem.bobrov@jetbrains.com>
parent 1bd3058d
...@@ -1349,6 +1349,36 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -1349,6 +1349,36 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
} }
} }
fun saveLayer(layerRec: SaveLayerRec): Int {
return try {
Stats.onNativeCall()
if (layerRec.bounds != null) {
_nSaveLayerSaveLayerRecRect(
_ptr,
layerRec.bounds.left,
layerRec.bounds.top,
layerRec.bounds.right,
layerRec.bounds.bottom,
getPtr(layerRec.paint),
getPtr(layerRec.backdrop),
getPtr(layerRec.colorSpace),
layerRec.saveLayerFlags.mask
)
} else {
_nSaveLayerSaveLayerRec(
_ptr,
getPtr(layerRec.paint),
getPtr(layerRec.backdrop),
getPtr(layerRec.colorSpace),
layerRec.saveLayerFlags.mask
)
}
} finally {
reachabilityBarrier(this)
reachabilityBarrier(layerRec)
}
}
val saveCount: Int val saveCount: Int
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
...@@ -1369,6 +1399,39 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -1369,6 +1399,39 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
return this return this
} }
class SaveLayerRec(
val bounds: Rect? = null,
val paint: Paint? = null,
val backdrop: ImageFilter? = null,
val colorSpace: ColorSpace? = null,
val saveLayerFlags: SaveLayerFlags = SaveLayerFlags()
)
enum class SaveLayerFlagsSet(val mask: Int) {
PreserveLCDText(1 shl 1),
InitWithPrevious(1 shl 2),
F16ColorType(1 shl 4)
}
class SaveLayerFlags internal constructor(internal val mask: Int) {
constructor(vararg flagsSet: SaveLayerFlagsSet) : this(flagsSet.fold(0) { acc, flag -> acc or flag.mask })
operator fun contains(flag: SaveLayerFlagsSet): Boolean = (mask and flag.mask) != 0
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as SaveLayerFlags
return mask == other.mask
}
override fun hashCode(): Int {
return mask
}
}
private object _FinalizerHolder { private object _FinalizerHolder {
val PTR = Canvas_nGetFinalizer() val PTR = Canvas_nGetFinalizer()
} }
...@@ -1645,6 +1708,29 @@ private external fun _nSaveLayerRect( ...@@ -1645,6 +1708,29 @@ private external fun _nSaveLayerRect(
paintPtr: NativePointer paintPtr: NativePointer
): Int ): Int
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRec")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRec")
private external fun _nSaveLayerSaveLayerRec(
ptr: NativePointer,
paintPtr: NativePointer,
backdropImageFilterPtr: NativePointer,
colorSpacePtr: NativePointer,
saveLayerFlags: Int
): Int
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRecRect")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRecRect")
private external fun _nSaveLayerSaveLayerRecRect(
ptr: NativePointer,
left: Float,
top: Float,
right: Float,
bottom: Float,
paintPtr: NativePointer,
backdropImageFilterPtr: NativePointer,
colorSpacePtr: NativePointer,
saveLayerFlags: Int
): Int
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nGetSaveCount") @ExternalSymbolName("org_jetbrains_skia_Canvas__1nGetSaveCount")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nGetSaveCount") @ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nGetSaveCount")
......
...@@ -210,7 +210,7 @@ class CanvasTest { ...@@ -210,7 +210,7 @@ class CanvasTest {
surface.canvas.drawBlackPixel(1, 1) surface.canvas.drawBlackPixel(1, 1)
surface.assertPixelsMatch( surface.assertPixelsMatch(
IntArray(16){ index -> IntArray(16) { index ->
when (index) { when (index) {
10, 11, 14, 15 -> 0xff000000.toInt() 10, 11, 14, 15 -> 0xff000000.toInt()
else -> 0xffffffff.toInt() else -> 0xffffffff.toInt()
...@@ -233,7 +233,7 @@ class CanvasTest { ...@@ -233,7 +233,7 @@ class CanvasTest {
@Test @Test
fun testRotateXY() { fun testRotateXY() {
val surface = whiteSurface(4, 4) val surface = whiteSurface(4, 4)
surface.canvas.rotate(deg = 90f, x = 2f, y=2f) surface.canvas.rotate(deg = 90f, x = 2f, y = 2f)
surface.canvas.drawBlackPixel(0, 0) surface.canvas.drawBlackPixel(0, 0)
surface.assertSingleBlackPixelAt(3, 0) surface.assertSingleBlackPixelAt(3, 0)
...@@ -247,7 +247,7 @@ class CanvasTest { ...@@ -247,7 +247,7 @@ class CanvasTest {
surface.canvas.drawBlackPixel(0, 2) surface.canvas.drawBlackPixel(0, 2)
surface.assertPixelsMatch( surface.assertPixelsMatch(
IntArray(16){ index -> IntArray(16) { index ->
when (index) { when (index) {
// Skewing skews the shape of the pixel itself, so it becomes a parallelogram // Skewing skews the shape of the pixel itself, so it becomes a parallelogram
9 -> 0xff3f3f3f.toInt() 9 -> 0xff3f3f3f.toInt()
...@@ -258,6 +258,56 @@ class CanvasTest { ...@@ -258,6 +258,56 @@ class CanvasTest {
) )
} }
@Test
fun testSaveLayerRecRect() {
val surface = whiteSurface(5, 5)
surface.canvas.saveLayer(
Canvas.SaveLayerRec(
bounds = Rect(1f, 1f, 4f, 4f),
saveLayerFlags = Canvas.SaveLayerFlags(Canvas.SaveLayerFlagsSet.InitWithPrevious)
)
)
val black = Paint().also { it.setARGB(255, 0, 0, 0) }
surface.canvas.drawRect(Rect(1f, 1f, 4f, 4f), black)
surface.canvas.restore()
surface.assertPixelsMatch(
intArrayOf(
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
)
)
}
@Test
fun testSaveLayerRec() {
val surface = whiteSurface(5, 5)
surface.canvas.saveLayer(Canvas.SaveLayerRec(saveLayerFlags = Canvas.SaveLayerFlags(Canvas.SaveLayerFlagsSet.InitWithPrevious)))
val black = Paint().also { it.setARGB(255, 0, 0, 0) }
surface.canvas.drawRect(Rect(1f, 1f, 4f, 4f), black)
surface.canvas.restore()
surface.assertPixelsMatch(
intArrayOf(
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
)
)
}
private fun whiteSurface(width: Int, height: Int): Surface { private fun whiteSurface(width: Int, height: Int): Surface {
val surface = Surface.makeRasterN32Premul(width, height) val surface = Surface.makeRasterN32Premul(width, height)
...@@ -286,8 +336,8 @@ class CanvasTest { ...@@ -286,8 +336,8 @@ class CanvasTest {
private fun Surface.assertSingleBlackPixelAt(x: Int, y: Int) { private fun Surface.assertSingleBlackPixelAt(x: Int, y: Int) {
val pixArray = IntArray(width * height){ 0xffffffff.toInt() } val pixArray = IntArray(width * height) { 0xffffffff.toInt() }
pixArray[y*width + x] = 0xff000000.toInt() pixArray[y * width + x] = 0xff000000.toInt()
assertPixelsMatch(pixArray) assertPixelsMatch(pixArray)
} }
......
...@@ -335,6 +335,27 @@ extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_CanvasKt__1nSaveLayerR ...@@ -335,6 +335,27 @@ extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_CanvasKt__1nSaveLayerR
return canvas->saveLayer(&bounds, paint); return canvas->saveLayer(&bounds, paint);
} }
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_CanvasKt__1nSaveLayerSaveLayerRec
(JNIEnv* env, jclass jclass, jlong ptr, jlong paintPtr, jlong backdropImageFilterPtr, jlong colorSpacePtr, jint saveLayerFlags) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr));
SkPaint* paint = reinterpret_cast<SkPaint*>(static_cast<uintptr_t>(paintPtr));
SkImageFilter* backdrop = reinterpret_cast<SkImageFilter*>(backdropImageFilterPtr);
SkColorSpace* colorSpace = reinterpret_cast<SkColorSpace*>(colorSpacePtr);
return canvas->saveLayer(SkCanvas::SaveLayerRec(nullptr, paint, backdrop, colorSpace, saveLayerFlags));
}
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_CanvasKt__1nSaveLayerSaveLayerRecRect
(JNIEnv* env, jclass jclass, jlong ptr, jfloat left, jfloat top, jfloat right, jfloat bottom, jlong paintPtr, jlong backdropImageFilterPtr, jlong colorSpacePtr, jint saveLayerFlags) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr));
SkRect bounds {left, top, right, bottom};
SkPaint* paint = reinterpret_cast<SkPaint*>(static_cast<uintptr_t>(paintPtr));
SkImageFilter* backdrop = reinterpret_cast<SkImageFilter*>(backdropImageFilterPtr);
SkColorSpace* colorSpace = reinterpret_cast<SkColorSpace*>(colorSpacePtr);
return canvas->saveLayer(SkCanvas::SaveLayerRec(&bounds, paint, backdrop, colorSpace, saveLayerFlags));
}
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_CanvasKt__1nGetSaveCount(JNIEnv* env, jclass jclass, jlong ptr) { extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_CanvasKt__1nGetSaveCount(JNIEnv* env, jclass jclass, jlong ptr) {
return reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr))->getSaveCount(); return reinterpret_cast<SkCanvas*>(static_cast<uintptr_t>(ptr))->getSaveCount();
} }
......
...@@ -330,6 +330,27 @@ SKIKO_EXPORT KInt org_jetbrains_skia_Canvas__1nSaveLayerRect ...@@ -330,6 +330,27 @@ SKIKO_EXPORT KInt org_jetbrains_skia_Canvas__1nSaveLayerRect
return canvas->saveLayer(&bounds, paint); return canvas->saveLayer(&bounds, paint);
} }
SKIKO_EXPORT KInt org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRec
(KNativePointer ptr, KNativePointer paintPtr, KNativePointer backdropImageFilterPtr, KNativePointer colorSpacePtr, KInt saveLayerFlags) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((ptr));
SkPaint* paint = reinterpret_cast<SkPaint*>((paintPtr));
SkImageFilter* backdrop = reinterpret_cast<SkImageFilter*>(backdropImageFilterPtr);
SkColorSpace* colorSpace = reinterpret_cast<SkColorSpace*>(colorSpacePtr);
return canvas->saveLayer(SkCanvas::SaveLayerRec(nullptr, paint, backdrop, colorSpace, saveLayerFlags));
}
SKIKO_EXPORT KInt org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRecRect
(KNativePointer ptr, KFloat left, KFloat top, KFloat right, KFloat bottom, KNativePointer paintPtr, KNativePointer backdropImageFilterPtr, KNativePointer colorSpacePtr, KInt saveLayerFlags) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>((ptr));
SkRect bounds {left, top, right, bottom};
SkPaint* paint = reinterpret_cast<SkPaint*>((paintPtr));
SkImageFilter* backdrop = reinterpret_cast<SkImageFilter*>(backdropImageFilterPtr);
SkColorSpace* colorSpace = reinterpret_cast<SkColorSpace*>(colorSpacePtr);
return canvas->saveLayer(SkCanvas::SaveLayerRec(&bounds, paint, backdrop, colorSpace, saveLayerFlags));
}
SKIKO_EXPORT KInt org_jetbrains_skia_Canvas__1nGetSaveCount(KNativePointer ptr) { SKIKO_EXPORT KInt org_jetbrains_skia_Canvas__1nGetSaveCount(KNativePointer ptr) {
return reinterpret_cast<SkCanvas*>((ptr))->getSaveCount(); return reinterpret_cast<SkCanvas*>((ptr))->getSaveCount();
} }
......
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