Skip to content

Commit

Permalink
Use convertToZeroTerminatedString on both wasm and js targets (#972)
Browse files Browse the repository at this point in the history
This is supposed to be fix for
#967

The idea is pass strings as (utf8) byte arrays directly through the
border just like we do it on native
  • Loading branch information
Schahen authored Aug 7, 2024
1 parent c1f8197 commit 2a47e23
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class ManagedStringTest {

val ms3 = ManagedString("你好!")
assertEquals("你好!", ms3.toString())

val msEmpty = ManagedString("")
assertEquals("", msEmpty.toString())
}

@Test
Expand All @@ -45,6 +48,9 @@ class ManagedStringTest {

val ms3 = ManagedString("你好").append(",世界")
assertEquals("你好,世界", ms3.toString())

val msEmpty = ManagedString("Empty string").append("")
assertEquals("Empty string", msEmpty.toString())
}

@Test
Expand All @@ -57,6 +63,9 @@ class ManagedStringTest {

val ms3 = ManagedString("世界").insert(0,"你好,")
assertEquals("你好,世界", ms3.toString())

val msEmpty = ManagedString("Empty string").insert(1, "").insert(0, "")
assertEquals("Empty string", msEmpty.toString())
}

@Test
Expand All @@ -72,5 +81,8 @@ class ManagedStringTest {

val ms4 = ManagedString("你好,世界!").remove(from = 2, length = 3) // ',' is 1 symbol
assertEquals("你好!", ms4.toString())

val msEmpty = ManagedString("World!").remove(from = 2, length = 0)
assertEquals("World!", msEmpty.toString())
}
}
7 changes: 1 addition & 6 deletions skiko/src/jsMain/kotlin/org/jetbrains/skia/impl/Native.js.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,13 @@ internal actual fun fromWasm(src: NativePointer, result: DoubleArray) {
result.asDynamic().set(HEAPF64.subarray(startIndex, startIndex + result.size))
}

internal actual external fun stringToUTF8(str: String, outPtr: NativePointer, maxBytesToWrite: Int)

internal actual class InteropScope actual constructor() {
private val elements = mutableListOf<NativePointer>()
private var callbacksInitialized = false

actual fun toInterop(string: String?): InteropPointer {
return if (string != null) {
val data = _malloc(string.length * 4)
stringToUTF8(string, data, string.length * 4)
elements.add(data)
data
toInterop(convertToZeroTerminatedString(string))
} else {
0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@ internal external fun _malloc(size: Int): NativePointer
@ModuleImport("./skiko.mjs", "free")
internal external fun _free(ptr: NativePointer)

private external fun lengthBytesUTF8(str: String): Int

internal expect fun stringToUTF8(str: String, outPtr: NativePointer, maxBytesToWrite: Int)

private external fun UTF8ToString(ptr: NativePointer): String

// Data copying routines.
internal expect fun toWasm(dest: NativePointer, src: ByteArray)
internal expect fun toWasm(dest: NativePointer, src: ShortArray)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.jetbrains.skia.impl

/**
* Converts String to zero-terminated utf-8 byte array.
*/
internal fun convertToZeroTerminatedString(string: String): ByteArray {
// C++ needs char* with zero byte at the end. So we need to copy array with an extra zero byte.

val utf8 = string.encodeToByteArray() // encodeToByteArray encodes to utf8
// TODO Remove array copy, use `skString(data, length)` instead of `skString(data)`
return utf8.copyOf(utf8.size + 1)
}
Original file line number Diff line number Diff line change
Expand Up @@ -281,14 +281,3 @@ private external fun initCallbacks(
callVoid: COpaquePointer,
dispose: COpaquePointer
)

/**
* Converts String to zero-terminated utf-8 byte array.
*/
private fun convertToZeroTerminatedString(string: String): ByteArray {
// C++ needs char* with zero byte at the end. So we need to copy array with an extra zero byte.

val utf8 = string.encodeToByteArray() // encodeToByteArray encodes to utf8
// TODO Remove array copy, use `skString(data, length)` instead of `skString(data)`
return utf8.copyOf(utf8.size + 1)
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,30 +124,13 @@ internal actual fun fromWasm(src: NativePointer, result: DoubleArray) {
}
}

internal actual fun stringToUTF8(str: String, outPtr: NativePointer, maxBytesToWrite: Int) {
if (maxBytesToWrite <= 0) return

val utf8 = str.encodeToByteArray()
val lastIndex = minOf(maxBytesToWrite - 1, utf8.size)

var index = 0
while (index < lastIndex) {
skia_memSetByte(outPtr + index, utf8[index])
index++
}
skia_memSetByte(outPtr + index, 0)
}

internal actual class InteropScope actual constructor() {
private val elements = mutableListOf<NativePointer>()
private var callbacksInitialized = false

actual fun toInterop(string: String?): InteropPointer {
return if (string != null) {
val data = _malloc(string.length * 4)
stringToUTF8(string, data, string.length * 4)
elements.add(data)
data
toInterop(convertToZeroTerminatedString(string))
} else {
0
}
Expand Down

0 comments on commit 2a47e23

Please sign in to comment.