Need Help with a Skiko Issue (Incorrect Text Width...
# multiplatform
s
Need Help with a Skiko Issue (Incorrect Text Width) Wasm/Js and Native Environments In the Skiko project, I’ve encountered a potential issue with text measurement and encoding. Here's the context: • In
Skiko Native.native.kt
,
Native.js.kt
, and
Native.wasm.kt
, there is an
actual
implementation of the
expect
function
toInterOp
declared in
Native.kt
(CommonMain). • The function uses
convertToZeroTerminatedString()
to convert a
String
to a
ByteArray
, encoding it to UTF-8. However, in
NativeJsMain/Cpp/Font.cc
, the
measureText
function is configured as follows:
Copy code
SKIKO_EXPORT KFloat org_jetbrains_skia_Font__1nMeasureTextWidth
  (KNativePointer ptr, char* str, KInt len, KNativePointer paintPtr) {
    SkFont* instance = reinterpret_cast<SkFont*>(ptr);
    SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
    return instance->measureText(str, len * sizeof(KChar), SkTextEncoding::kUTF16, nullptr, paint);
}
The problem:
measureText
expects a UTF-16 encoded string, but the input string is in UTF-8 Below Snippet is from
jvmMain/cpp/Font.cc
,In this case, Text Measuring returns the correct width ( JVM Environment ), where the String's are processed as UTF-16.
Copy code
extern "C" JNIEXPORT jfloat JNICALL Java_org_jetbrains_skia_FontKt__1nMeasureTextWidth
  (JNIEnv* env, jclass jclass, jlong ptr, jstring str, jint len, jlong paintPtr) {
    SkFont* instance = reinterpret_cast<SkFont*>(static_cast<uintptr_t>(ptr));
    SkPaint* paint = reinterpret_cast<SkPaint*>(static_cast<uintptr_t>(paintPtr));
    const jchar* chars = env->GetStringCritical(str, nullptr);
    jfloat result = instance->measureText(chars, len * sizeof(jchar), SkTextEncoding::kUTF16, nullptr, paint);
    env->ReleaseStringCritical(str, chars);
    return result;
}
Workaround: Changing the encoding to UTF-8 in the
measureText
function gives the correct text width:
Copy code
SKIKO_EXPORT KFloat org_jetbrains_skia_Font__1nMeasureTextWidth
  (KNativePointer ptr, char* str, KInt len, KNativePointer paintPtr) {
    SkFont* instance = reinterpret_cast<SkFont*>(ptr);
    SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
    return instance->measureText(str, len, SkTextEncoding::kUTF8, nullptr, paint);
}
Question: Is this workaround correct, or am I addressing the issue incorrectly? If there’s a better way to ensure proper font measurement, I’d appreciate any guidance. Thanks in advance for your help!
a
@Oleksandr Karpovich [JB] ^^
o
I believe your workaround is rather correct. Initially there were only the bindings for java. Then when the bindings were added for k/native and k/web, some code was migrated from the existing bindings. And probably it's a mistake of the copy/paste. I see you've already reported this problem https://youtrack.jetbrains.com/issue/SKIKO-995/Skiko-Text-Measurement-Encoding-Issue-Font.measureTextWidth Thank you 🙂
Do you use these methods directly? I believe we missed the problem, because in Compose it's using Paragraph, which can return lineMetrics.
s
Yes, I'm using
Font.measureTextWidth()
directly in my code. I also tried using
ParagraphBuilder,
add text and retrieve the bounds, and it does return the correct text width. However, I needed a more straightforward approach, which is why I relied on
Font.measureTextWidth()
. Thanks again 😀
👍 1
Hi @Oleksandr Karpovich [JB] Any update 🙂 Thanks in advance.
o
Hey! No updates yet. Would you like to create a pull request + the tests?