Skip to content

Commit

Permalink
Fix String.intCodePoints() native implementations.
Browse files Browse the repository at this point in the history
  • Loading branch information
m-sasha committed Feb 27, 2025
1 parent 9fb619f commit fcddfc7
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 14 deletions.
51 changes: 51 additions & 0 deletions skiko/src/commonMain/kotlin/org/jetbrains/skia/CodePoint.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.jetbrains.skia

// Copied from CharHelpers.skiko.kt
// TODO Remove once it's available in common stdlib https://youtrack.jetbrains.com/issue/KT-23251
internal typealias CodePoint = Int

// Copied from CharHelpers.skiko.kt
/**
* The minimum value of a supplementary code point, `\u0x10000`.
*/
private const val MIN_SUPPLEMENTARY_CODE_POINT: Int = 0x10000

// Copied from CharHelpers.skiko.kt
/**
* Converts a surrogate pair to a unicode code point.
*/
internal fun toCodePoint(high: Char, low: Char): CodePoint =
(((high - Char.MIN_HIGH_SURROGATE) shl 10) or (low - Char.MIN_LOW_SURROGATE)) + MIN_SUPPLEMENTARY_CODE_POINT

// Copied from CharHelpers.skiko.kt
internal fun Int.charCount(): Int = if (this >= MIN_SUPPLEMENTARY_CODE_POINT) 2 else 1

internal val String.codePointsAsIntArray: IntArray
get() = codePoints.toList().toIntArray()

internal val String.codePoints
get() = codePointsAt(0)

internal fun String.codePointsAt(index: Int) = sequence {
var current = index
while (current < length) {
val codePoint = codePointAt(current)
yield(codePoint)
current += codePoint.charCount()
}
}

// Copied from CharHelpers.skiko.kt
/**
* Returns the character (Unicode code point) at the specified index.
*/
internal fun CharSequence.codePointAt(index: Int): CodePoint {
val high = this[index]
if (high.isHighSurrogate() && index + 1 < this.length) {
val low = this[index + 1]
if (low.isLowSurrogate()) {
return toCodePoint(high, low)
}
}
return high.code
}
2 changes: 0 additions & 2 deletions skiko/src/commonMain/kotlin/org/jetbrains/skia/Expects.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package org.jetbrains.skia

internal expect fun <R> commonSynchronized(lock: Any, block: () -> R)

internal expect fun String.intCodePoints(): IntArray

internal expect fun defaultLanguageTag(): String

expect class Pattern {
Expand Down
2 changes: 1 addition & 1 deletion skiko/src/commonMain/kotlin/org/jetbrains/skia/Font.kt
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ class Font : Managed {
* @return the corresponding glyph ids for each character.
*/
fun getStringGlyphs(s: String): ShortArray {
return getUTF32Glyphs(s.intCodePoints())
return getUTF32Glyphs(s.codePointsAsIntArray)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion skiko/src/commonMain/kotlin/org/jetbrains/skia/Typeface.kt
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class Typeface internal constructor(ptr: NativePointer) : RefCnt(ptr) {
* @return the corresponding glyph ids for each character.
*/
fun getStringGlyphs(s: String): ShortArray {
return getUTF32Glyphs(s.intCodePoints())
return getUTF32Glyphs(s.codePointsAsIntArray)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.jetbrains.skia.icu

import org.jetbrains.skia.intCodePoints
import org.jetbrains.skia.codePoints
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
Expand All @@ -17,13 +17,16 @@ class UnicodeTest {

@Test
fun binaryProperties() {
fun String.firstCodePointHasProperty(property: Int) =
CharProperties.codePointHasBinaryProperty(this.intCodePoints().first(), property)
fun String.firstCodePointHasProperty(property: Int): Boolean {
val codePoint = this.codePoints.first()
println(codePoint.toString(16))
return CharProperties.codePointHasBinaryProperty(codePoint, property)
}

assertTrue("".firstCodePointHasProperty(CharProperties.EMOJI))
assertTrue("".firstCodePointHasProperty(CharProperties.EMOJI_PRESENTATION))
assertTrue("♥️".firstCodePointHasProperty(CharProperties.EXTENDED_PICTOGRAPHIC))
assertTrue("\uD83C\uDDEE\uD83C\uDDF1".firstCodePointHasProperty(CharProperties.EMOJI)) // flag
assertTrue("🇮🇱".firstCodePointHasProperty(CharProperties.EMOJI)) // flag

assertFalse("x".firstCodePointHasProperty(CharProperties.EMOJI))
}
Expand Down
2 changes: 0 additions & 2 deletions skiko/src/jsWasmMain/kotlin/org/jetbrains/skia/Actuals.js.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ internal actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
block()
}

actual fun String.intCodePoints(): IntArray = IntArray(this.length) { this[it].code }

actual class Pattern constructor(regex: String) {
private val _regex = Regex(regex)

Expand Down
2 changes: 0 additions & 2 deletions skiko/src/jvmMain/kotlin/org/jetbrains/skia/Actuals.jvm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ internal actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
synchronized(lock, block)
}

internal actual fun String.intCodePoints(): IntArray = this.codePoints().toArray()

actual typealias Pattern = java.util.regex.Pattern

actual typealias Matcher = java.util.regex.Matcher
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ internal actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
block()
}

internal actual fun String.intCodePoints(): IntArray = IntArray(this.length) { this[it].code }

actual class Pattern constructor(regex: String) {
private val _regex = Regex(regex)

Expand Down

0 comments on commit fcddfc7

Please sign in to comment.