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

Remove typealias for bytebuffer, replace it with NativePointers or Pixmap where appropriate (#308)

* remove ByteBuffer typealias and use NativePointer instead

* after-rebase changes

* prevent GC from cleaning up underlying memory for Data and Pixmap until they get cleaned by themselves

* skiko Data: make underlyingMemoryOwner mandatory when using makeWithoutCopy
Co-authored-by: 's avatarOleksandr Karpovich <oleksandr.karpovich@jetbrains.com>
parent 21d7595e
......@@ -7,6 +7,13 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad
* Data holds an immutable data buffer.
*/
class Data internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR) {
/**
* A reference to the underlying memory owner to prevent it from being cleaned by GC until Data instance finalization.
* It's used in [makeWithoutCopy].
*/
private var underlyingMemoryOwner: Managed? = null
companion object {
fun makeFromBytes(bytes: ByteArray, offset: Int = 0, length: Int = bytes.size): Data {
Stats.onNativeCall()
......@@ -17,6 +24,24 @@ class Data internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
)
}
/**
* makeWithoutCopy uses NoopReleaseProc as a ReleaseProc, therefore memory needs to be cleaned up by caller side
* (or by [underlyingMemoryOwner] if provided).
*
* @param underlyingMemoryOwner - is stored in Data instance to prevent underlying memory getting cleaned by GC in cases when
* [underlyingMemoryOwner] doesn't have any other references.
*/
fun makeWithoutCopy(memoryAddr: NativePointer, length: Int, underlyingMemoryOwner: Managed): Data {
Stats.onNativeCall()
return Data(
interopScope {
_nMakeWithoutCopy(memoryAddr, length)
}
).also {
it.underlyingMemoryOwner = underlyingMemoryOwner
}
}
/**
* Returns a new empty dataref (or a reference to a shared empty dataref).
* New or shared, the caller must see that [.close] is eventually called.
......@@ -26,6 +51,11 @@ class Data internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
return Data(_nMakeEmpty())
}
fun makeUninitialized(length: Int): Data {
Stats.onNativeCall()
return Data(_nMakeUninitialized(length))
}
init {
staticLoad()
}
......@@ -96,10 +126,10 @@ class Data internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
}
}
fun toByteBuffer(): ByteBuffer {
fun writableData(): NativePointer {
return try {
Stats.onNativeCall()
_nToByteBuffer(_ptr)
_nWritableData(_ptr)
} finally {
reachabilityBarrier(this)
}
......@@ -123,12 +153,12 @@ private external fun _nBytes(ptr: NativePointer, offset: Int, length: Int, destB
@ExternalSymbolName("org_jetbrains_skia_Data__1nEquals")
private external fun _nEquals(ptr: NativePointer, otherPtr: NativePointer): Boolean
@ExternalSymbolName("org_jetbrains_skia_Data__1nToByteBuffer")
private external fun _nToByteBuffer(ptr: NativePointer): ByteBuffer
@ExternalSymbolName("org_jetbrains_skia_Data__1nMakeFromBytes")
private external fun _nMakeFromBytes(bytes: InteropPointer, offset: Int, length: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Data__1nMakeWithoutCopy")
private external fun _nMakeWithoutCopy(memoryAddr: NativePointer, length: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Data__1nMakeFromFileName")
internal external fun _nMakeFromFileName(path: InteropPointer): NativePointer
......@@ -137,3 +167,9 @@ private external fun _nMakeSubset(ptr: NativePointer, offset: Int, length: Int):
@ExternalSymbolName("org_jetbrains_skia_Data__1nMakeEmpty")
private external fun _nMakeEmpty(): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Data__1nMakeUninitialized")
private external fun _nMakeUninitialized(length: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Data__1nWritableData")
private external fun _nWritableData(dataPtr: NativePointer): NativePointer
package org.jetbrains.skia
expect abstract class ByteBuffer
expect fun <R> commonSynchronized(lock: Any, block: () -> R)
expect fun String.intCodePoints(): IntArray
......
......@@ -246,17 +246,19 @@ class Image internal constructor(ptr: NativePointer) : RefCnt(ptr), IHasImageInf
}
/**
* If pixel address is available, return ByteBuffer wrapping it.
* If pixel address is available, return [Pixmap].
* If pixel address is not available, return null.
*
* @return ByteBuffer with direct access to pixels, or null
*
* @see [https://fiddle.skia.org/c/@Image_peekPixels](https://fiddle.skia.org/c/@Image_peekPixels)
*/
fun peekPixels(): ByteBuffer? {
fun peekPixels(): Pixmap? {
return try {
Stats.onNativeCall()
Image_nPeekPixels(_ptr)
Image_nPeekPixels(_ptr).takeIf {
it != NullPointer
}?.let {
Pixmap(it, true)
}
} finally {
reachabilityBarrier(this)
}
......@@ -376,7 +378,7 @@ private external fun Image_nGetImageInfo(ptr: NativePointer, imageInfo: InteropP
private external fun Image_nMakeShader(ptr: NativePointer, tmx: Int, tmy: Int, samplingMode: Long, localMatrix: InteropPointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Image__1nPeekPixels")
private external fun Image_nPeekPixels(ptr: NativePointer): ByteBuffer?
private external fun Image_nPeekPixels(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Image__1nMakeRaster")
private external fun _nMakeRaster(
......
......@@ -4,6 +4,13 @@ import org.jetbrains.skia.impl.*
class Pixmap internal constructor(ptr: NativePointer, managed: Boolean) :
Managed(ptr, _FinalizerHolder.PTR, managed) {
/**
* A reference to the underlying memory to prevent it from being cleaned up by GC.
* It's used in [reset] and [make].
*/
private var underlyingMemoryOwner: Managed? = null
constructor() : this(_nMakeNull(), true) {
Stats.onNativeCall()
}
......@@ -11,10 +18,11 @@ class Pixmap internal constructor(ptr: NativePointer, managed: Boolean) :
fun reset() {
Stats.onNativeCall()
Pixmap_nReset(_ptr)
underlyingMemoryOwner = null
reachabilityBarrier(this)
}
fun reset(info: ImageInfo, addr: NativePointer, rowBytes: Int) {
fun reset(info: ImageInfo, addr: NativePointer, rowBytes: Int, underlyingMemoryOwner: Managed? = null) {
Stats.onNativeCall()
_nResetWithInfo(
_ptr,
......@@ -23,12 +31,13 @@ class Pixmap internal constructor(ptr: NativePointer, managed: Boolean) :
info.colorInfo.alphaType.ordinal,
getPtr(info.colorInfo.colorSpace), addr, rowBytes
)
this.underlyingMemoryOwner = underlyingMemoryOwner
reachabilityBarrier(this)
reachabilityBarrier(info.colorInfo.colorSpace)
}
fun reset(info: ImageInfo, buffer: ByteBuffer, rowBytes: Int) {
reset(info, BufferUtil.getPointerFromByteBuffer(buffer), rowBytes)
fun reset(info: ImageInfo, buffer: Data, rowBytes: Int) {
reset(info = info, addr = buffer.writableData(), rowBytes = rowBytes, underlyingMemoryOwner = buffer)
}
fun setColorSpace(colorSpace: ColorSpace?) {
......@@ -54,8 +63,8 @@ class Pixmap internal constructor(ptr: NativePointer, managed: Boolean) :
}
}
fun extractSubset(buffer: ByteBuffer, area: IRect): Boolean {
return extractSubset(BufferUtil.getPointerFromByteBuffer(buffer), area)
fun extractSubset(subset: Pixmap, area: IRect): Boolean {
return extractSubset(subset._ptr, area)
}
val info: ImageInfo
......@@ -240,19 +249,23 @@ class Pixmap internal constructor(ptr: NativePointer, managed: Boolean) :
}
}
val buffer: ByteBuffer?
get() = BufferUtil.getByteBufferFromPointer(addr, computeByteSize())
val buffer: Data
get() = (underlyingMemoryOwner as? Data) ?: Data.makeWithoutCopy(
memoryAddr = addr,
length = computeByteSize(),
underlyingMemoryOwner = this
)
private object _FinalizerHolder {
val PTR = Pixmap_nGetFinalizer()
}
companion object {
fun make(info: ImageInfo, buffer: ByteBuffer, rowBytes: Int): Pixmap {
return make(info, BufferUtil.getPointerFromByteBuffer(buffer), rowBytes)
fun make(info: ImageInfo, buffer: Data, rowBytes: Int): Pixmap {
return make(info, buffer.writableData(), rowBytes, underlyingMemoryOwner = buffer)
}
fun make(info: ImageInfo, addr: NativePointer, rowBytes: Int): Pixmap {
fun make(info: ImageInfo, addr: NativePointer, rowBytes: Int, underlyingMemoryOwner: Managed? = null): Pixmap {
return try {
val ptr = Pixmap_nMake(
info.width, info.height,
......@@ -261,7 +274,9 @@ class Pixmap internal constructor(ptr: NativePointer, managed: Boolean) :
getPtr(info.colorInfo.colorSpace), addr, rowBytes
)
require(ptr != NullPointer) { "Failed to create Pixmap." }
Pixmap(ptr, true)
Pixmap(ptr, true).also {
it.underlyingMemoryOwner = underlyingMemoryOwner
}
} finally {
reachabilityBarrier(info.colorInfo.colorSpace)
}
......@@ -390,4 +405,4 @@ private external fun _nEraseSubset(
t: Int,
r: Int,
b: Int
): Boolean // TODO float erase methods not included
\ No newline at end of file
): Boolean // TODO float erase methods not included
......@@ -113,4 +113,21 @@ class BitmapTest {
assertEquals(setArray.size, result.size)
assertContentEquals(setArray, result)
}
@Test
fun canPeekPixelsAndCompare() = runTest {
val bitmap = Bitmap()
bitmap.allocPixels(ImageInfo.makeS32(2, 2, ColorAlphaType.OPAQUE))
val setArray = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
assertTrue(bitmap.installPixels(setArray))
val dataBytes = bitmap.peekPixels()!!.buffer.bytes
assertEquals(setArray.size, dataBytes.size)
setArray.forEachIndexed { ix, value ->
assertEquals(value, dataBytes[ix])
}
}
}
package org.jetbrains.skia
import org.jetbrains.skia.impl.Native.Companion.NullPointer
import org.jetbrains.skia.impl.use
import org.jetbrains.skiko.tests.runTest
import kotlin.test.*
......@@ -63,4 +64,58 @@ class DataTest {
assertContentEquals(byteArrayOf(), it.getBytes(5, 0))
}
}
@Test
fun memorySuppliedToMakeDataWithoutCopyDoesntGetCleanedUp() = runTest {
val bytes = byteArrayOf(1, 2, 3, 4, 5)
val originalData = Data.makeFromBytes(bytes)
val originalDataPtr = originalData._ptr
// `use()` calls `close()` in the end
val copiedData = Data.makeWithoutCopy(
memoryAddr = originalData.writableData(),
length = 5,
underlyingMemoryOwner = originalData
).use {
assertNotEquals(NullPointer, it._ptr)
assertContentEquals(bytes, it.bytes)
it
}
assertEquals(NullPointer, copiedData._ptr)
assertEquals(originalDataPtr, originalData._ptr)
assertContentEquals(
bytes,
originalData.bytes,
message = "Memory is not expected to get cleaned up because Data.makeWithoutCopy uses NoopReleaseProc as a ReleaseProc"
)
}
@Test
fun canMakeUninitialized() = runTest {
val data = Data.makeUninitialized(100)
assertEquals(100, data.bytes.size)
println(data.bytes.joinToString())
val imageInfo = ImageInfo.makeN32Premul(5, 5)
val pixmap = Pixmap.make(imageInfo, data, imageInfo.minRowBytes)
val surface = Surface.makeRasterDirect(pixmap)
surface.canvas.clear(Color.WHITE)
// check that data contains all white pixels
assertContentEquals(
expected = ByteArray(100) { -1 },
actual = data.bytes
)
surface.canvas.clear(Color.BLACK)
// check that data contains all black pixels
assertContentEquals(
// every 4th byte is -1, the rest is 0 for Color.BLACK
expected = ByteArray(100) { if ((it + 1) % 4 == 0) -1 else 0 },
actual = data.bytes
)
}
}
......@@ -3,6 +3,7 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.use
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertTrue
......@@ -69,6 +70,28 @@ class ImageTest {
val image = Image.makeRaster(imageInfo, bytes, 5)
}
@Test
fun canPeekPixels() = runTest {
val bytes = intArrayOf(
0xCA, 0xDA, 0xCA, 0xC9, 0xA3,
0xAC, 0xA8, 0x89, 0xA7, 0x87,
0x9B, 0xB5, 0xE5, 0x95, 0x46,
0x90, 0x81, 0xC5, 0x71, 0x33,
0x75, 0x55, 0x44, 0x40, 0x30
).map { it.toByte() }.toByteArray()
val imageInfo = ImageInfo(
width = 5, height = 5,
colorType = ColorType.GRAY_8,
alphaType = ColorAlphaType.OPAQUE
)
val image = Image.makeRaster(imageInfo, bytes, 5)
val pixels = image.peekPixels()!!.buffer.bytes
assertContentEquals(bytes, pixels)
}
private fun <T> imageUnderTest(block: (Image) -> T): T {
return Surface.makeRasterN32Premul(100, 100).use { surface ->
val paint = Paint()
......
package org.jetbrains.skiko.tests
import org.jetbrains.skia.ByteBuffer
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.impl.*
......@@ -36,12 +35,6 @@ class TestHelpers {
}
}
fun getPointerFromByteBuffer(buffer: ByteBuffer): NativePointer {
val result = _nGetPointerFromByteBuffer(buffer)
require(result != Native.NullPointer) { "The given buffer " + buffer + "is not a direct buffer or current JVM doesn't support JNI direct buffer access!" }
return result
}
init {
Library.staticLoad()
}
......@@ -61,6 +54,3 @@ private external fun _nFillIntArrayOf5(interopPointer: InteropPointer)
@ExternalSymbolName("org_jetbrains_skiko_tests_TestHelpers__1nFillDoubleArrayOf5")
private external fun _nFillDoubleArrayOf5(interopPointer: InteropPointer)
@ExternalSymbolName("org_jetbrains_skiko_tests_TestHelpers__1nGetPointerFromByteBuffer")
private external fun _nGetPointerFromByteBuffer(buffer: ByteBuffer?): NativePointer
package org.jetbrains.skia
actual abstract class OutputStream
actual abstract class ByteBuffer
actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
block()
......
......@@ -46,6 +46,13 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DataKt__1nMakeFromByt
return reinterpret_cast<jlong>(instance);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DataKt__1nMakeWithoutCopy
(JNIEnv* env, jclass jclass, jlong memoryAddr, jint length) {
SkData* instance = SkData::MakeWithoutCopy(reinterpret_cast<void*>(memoryAddr), length).release();
return reinterpret_cast<jlong>(instance);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DataKt__1nMakeFromFileName
(JNIEnv* env, jclass jclass, jstring pathStr) {
SkString path = skString(env, pathStr);
......@@ -65,3 +72,15 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DataKt__1nMakeEmpty
SkData* instance = SkData::MakeEmpty().release();
return reinterpret_cast<jlong>(instance);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DataKt__1nMakeUninitialized
(JNIEnv* env, jclass jclass, jint length) {
SkData* instance = SkData::MakeUninitialized(length).release();
return reinterpret_cast<jlong>(instance);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DataKt__1nWritableData
(JNIEnv* env, jclass jclass, jlong ptr) {
SkData* instance = reinterpret_cast<SkData*>(static_cast<uintptr_t>(ptr));
return reinterpret_cast<jlong>(instance->writable_data());
}
......@@ -81,14 +81,17 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ImageKt_Image_1nMakeS
return reinterpret_cast<jlong>(shader.release());
}
extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skia_ImageKt_Image_1nPeekPixels
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ImageKt_Image_1nPeekPixels
(JNIEnv* env, jclass jclass, jlong ptr) {
SkImage* instance = reinterpret_cast<SkImage*>(static_cast<uintptr_t>(ptr));
SkPixmap pixmap;
if (instance->peekPixels(&pixmap))
return env->NewDirectByteBuffer(pixmap.writable_addr(), pixmap.rowBytes() * pixmap.height());
else
return nullptr;
SkPixmap* pixmap = new SkPixmap();
if (instance->peekPixels(pixmap))
return ptrToJlong(pixmap);
else {
delete pixmap;
return 0;
}
}
extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_ImageKt__1nPeekPixelsToPixmap
......
......@@ -2,8 +2,6 @@ package org.jetbrains.skia
import java.util.*
actual typealias ByteBuffer = java.nio.ByteBuffer
actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
synchronized(lock, block)
}
......
package org.jetbrains.skia.impl
import org.jetbrains.skia.ByteBuffer
import org.jetbrains.skia.ExternalSymbolName
import java.nio.ByteBuffer
object BufferUtil {
fun getByteBufferFromPointer(ptr: NativePointer, size: Int): ByteBuffer {
......@@ -16,9 +15,6 @@ object BufferUtil {
}
}
@ExternalSymbolName("org_jetbrains_skia_BufferUtil__1nGetByteBufferFromPointer")
private external fun _nGetByteBufferFromPointer(ptr: NativePointer, size: Int): ByteBuffer?
@ExternalSymbolName("org_jetbrains_skia_BufferUtil__1nGetPointerFromByteBuffer")
private external fun _nGetPointerFromByteBuffer(buffer: ByteBuffer?): NativePointer
\ No newline at end of file
private external fun _nGetPointerFromByteBuffer(buffer: ByteBuffer?): NativePointer
......@@ -5,6 +5,7 @@ import org.jetbrains.skia.ColorAlphaType
import org.jetbrains.skia.ColorType
import org.jetbrains.skia.ImageInfo
import org.jetbrains.skia.Image
import org.jetbrains.skia.impl.BufferUtil
import java.awt.Transparency
import java.awt.color.ColorSpace
import java.awt.image.*
......@@ -19,6 +20,33 @@ private class DirectDataBuffer(val backing: ByteBuffer): DataBuffer(TYPE_BYTE, b
}
}
fun Bitmap.toBufferedImage(): BufferedImage {
val pixelsNativePointer = this.peekPixels()!!.addr
val pixelsBuffer = BufferUtil.getByteBufferFromPointer(pixelsNativePointer, this.rowBytes * this.height)
val order = when (this.colorInfo.colorType) {
ColorType.RGB_888X -> intArrayOf(0, 1, 2, 3)
ColorType.BGRA_8888 -> intArrayOf(2, 1, 0, 3)
else -> throw UnsupportedOperationException("unsupported color type ${this.colorInfo.colorType}")
}
val raster = Raster.createInterleavedRaster(
DirectDataBuffer(pixelsBuffer),
this.width,
this.height,
this.width * 4,
4,
order,
null
)
val colorModel = ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
true,
false,
Transparency.TRANSLUCENT,
DataBuffer.TYPE_BYTE
)
return BufferedImage(colorModel, raster!!, false, null)
}
fun BufferedImage.toBitmap(): Bitmap {
val bytesPerPixel = 4
......@@ -47,4 +75,4 @@ fun BufferedImage.toBitmap(): Bitmap {
fun BufferedImage.toImage(): Image {
return Image.makeFromBitmap(toBitmap())
}
\ No newline at end of file
}
......@@ -55,9 +55,3 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skiko_tests_TestHelpersKt__
result_double[4] = 10000000.9991;
env->ReleaseDoubleArrayElements(jdarray, result_double, 0);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_tests_TestHelpersKt__1nGetPointerFromByteBuffer
(JNIEnv *env, jclass, jobject buffer) {
return reinterpret_cast<jlong>(env->GetDirectBufferAddress(buffer));
}
package org.jetbrains.skiko.tests
import kotlinx.coroutines.runBlocking
import org.jetbrains.skia.impl.BufferUtil
import org.jetbrains.skia.impl.InteropScope
import org.jetbrains.skia.impl.NativePointer
import java.nio.ByteBuffer
......@@ -12,5 +13,5 @@ actual fun runTest(block: suspend () -> Unit) {
}
actual fun InteropScope.allocateBytesForPixels(size: Int): NativePointer {
return TestHelpers().getPointerFromByteBuffer(ByteBuffer.allocateDirect(size))
return BufferUtil.getPointerFromByteBuffer(ByteBuffer.allocateDirect(size))
}
package org.jetbrains.skiko.tests.org.jetbrains.skiko
import org.jetbrains.skia.*
import org.jetbrains.skiko.toBitmap
import org.jetbrains.skiko.toBufferedImage
import org.junit.Test
import kotlin.test.assertEquals
class ConvertorsTests {
@Test
fun canConvertBitmapToBufferedImage() {
val bytes = intArrayOf(
0xCA, 0xDA, 0xCA, 0xC9, 0xA3, 0xAC, 0xA8, 0x89,
0x9B, 0xB5, 0xE5, 0x95, 0x46, 0x90, 0x81, 0xC5
).map { it.toByte() }.toByteArray()
val imageInfo = ImageInfo(
width = 2, height = 2,
colorType = ColorType.RGB_888X,
alphaType = ColorAlphaType.OPAQUE
)
val image = Image.makeRaster(imageInfo, bytes, 8)
val bitmap = Bitmap.makeFromImage(image)
val bufferedImage = bitmap.toBufferedImage()
val bitmapConverted = bufferedImage.toBitmap()
val pixels = bitmapConverted.readPixels(imageInfo)!!
assertEquals(bytes.size, pixels.size)
}
}
package org.jetbrains.skiko.util
import org.jetbrains.skia.ByteBuffer
import org.jetbrains.skia.Data
import org.jetbrains.skia.Image
import org.jetbrains.skia.Pixmap
import java.awt.Color
......@@ -16,12 +16,12 @@ fun isContentSame(img1: Image, img2: Image, sensitivity: Double): Boolean {
pixMap1.reset(
img1.imageInfo,
ByteBuffer.allocateDirect(img1.bytesPerPixel * img1.width * img1.height),
Data.makeUninitialized(img1.bytesPerPixel * img1.width * img1.height),
img1.bytesPerPixel * img1.width
)
pixMap2.reset(
img2.imageInfo,
ByteBuffer.allocateDirect(img2.bytesPerPixel * img2.width * img2.height),
Data.makeUninitialized(img2.bytesPerPixel * img2.width * img2.height),
img2.bytesPerPixel * img2.width
)
check(img1.readPixels(pixMap1, 0, 0, false))
......
......@@ -19,22 +19,6 @@ SKIKO_EXPORT KInt org_jetbrains_skia_Data__1nSize
return instance->size();
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Data__1nToByteBuffer
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Data__1nToByteBuffer");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Data__1nToByteBuffer
(KNativePointer ptr) {
SkData* instance = reinterpret_cast<SkData*>((ptr));
return env->NewDirectByteBuffer(instance->writable_data(), instance->size());
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_Data__1nBytes
(KNativePointer ptr, int offset, int length, KByte* destBytes) {
SkData* instance = reinterpret_cast<SkData*>(ptr);
......@@ -58,6 +42,13 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeFromBytes
return instance;
}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeWithoutCopy
(KNativePointer memoryAddr, KInt length) {
SkData* instance = SkData::MakeWithoutCopy(reinterpret_cast<void*>(memoryAddr), length).release();
return reinterpret_cast<KNativePointer>(instance);
}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeFromFileName
(KInteropPointer pathStr) {
SkString path = skString(pathStr);
......@@ -77,3 +68,14 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeEmpty() {
SkData* instance = SkData::MakeEmpty().release();
return reinterpret_cast<KNativePointer>(instance);
}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeUninitialized(KInt length) {
SkData* instance = SkData::MakeUninitialized(length).release();
return reinterpret_cast<KNativePointer>(instance);
}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nWritableData
(KNativePointer ptr) {
SkData* instance = reinterpret_cast<SkData*>(ptr);
return reinterpret_cast<KNativePointer>(instance->writable_data());
}
......@@ -84,25 +84,17 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Image__1nMakeShader
return reinterpret_cast<KNativePointer>(shader.release());
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Image__1nPeekPixels
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Image__1nPeekPixels");
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Image__1nPeekPixels
(KNativePointer ptr) {
SkImage* instance = reinterpret_cast<SkImage*>((ptr));
SkPixmap pixmap;
if (instance->peekPixels(&pixmap))
return env->NewDirectByteBuffer(pixmap.writable_addr(), pixmap.rowBytes() * pixmap.height());
else
return nullptr;
SkImage* instance = reinterpret_cast<SkImage*>(ptr);
SkPixmap* pixmap = new SkPixmap();
if (instance->peekPixels(pixmap)) {
return reinterpret_cast<KNativePointer>(pixmap);
} else {
delete pixmap;
return nullptr;
}
}
#endif
SKIKO_EXPORT KBoolean org_jetbrains_skia_Image__1nPeekPixelsToPixmap
(KNativePointer ptr, KNativePointer pixmapPtr) {
......
package org.jetbrains.skia
actual abstract class ByteBuffer
actual abstract class OutputStream
actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
......
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