Skip to content

Commit

Permalink
Implement SkTextBlob::Iter in Skiko (#512)
Browse files Browse the repository at this point in the history
  • Loading branch information
VeselovAlex authored Mar 6, 2022
1 parent 8fccb7e commit bd7e73c
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 1 deletion.
39 changes: 39 additions & 0 deletions skiko/src/commonMain/cpp/common/include/TexBlobIter.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include "SkTextBlob.h"

class TextBlobIter {
public:
TextBlobIter(SkTextBlob* blob): _blob(sk_ref_sp(blob)), _iter(*blob), _buffer(), _hasNext() {
fetch();
}

bool fetch() {
_hasNext = _iter.next(&_buffer);
return _hasNext;
}

bool hasNext() const {
return _hasNext;
}

sk_sp<SkTypeface> getTypeface() const {
return sk_ref_sp(_buffer.fTypeface);
}

int getGlyphCount() const {
return _buffer.fGlyphCount;
}

int writeGlyphs(uint16_t* dst, int max) const {
int count = std::min(max, _buffer.fGlyphCount);
std::memcpy(dst, _buffer.fGlyphIndices, count * sizeof(uint16_t));
return _buffer.fGlyphCount;
}

private:
SkTextBlob::Iter::Run _buffer;
SkTextBlob::Iter _iter;
bool _hasNext;
sk_sp<SkTextBlob> _blob;
};
71 changes: 70 additions & 1 deletion skiko/src/commonMain/kotlin/org/jetbrains/skia/TextBlob.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad

class TextBlob internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR) {
class TextBlob internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR), Iterable<TextBlob.TextBlobIter.Run> {
companion object {
/**
* Returns a TextBlob built from a single run of text with x-positions and a single y value.
Expand Down Expand Up @@ -319,6 +319,54 @@ class TextBlob internal constructor(ptr: NativePointer) : Managed(ptr, _Finalize
private object _FinalizerHolder {
val PTR = TextBlob_nGetFinalizer()
}

override fun iterator(): Iterator<TextBlobIter.Run> = TextBlobIter(this)

class TextBlobIter(val textBlob: TextBlob) : Iterator<TextBlobIter.Run>, Managed(Iter_nCreate(textBlob._ptr), FinalizerHolder.PTR) {
data class Run(val typeface: Typeface, val glyphs: ShortArray) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Run) return false

return typeface == other.typeface && glyphs.contentEquals(other.glyphs)
}

override fun hashCode(): Int {
var result = typeface.hashCode()
result = 31 * result + glyphs.contentHashCode()
return result
}
}

override fun hasNext(): Boolean {
Stats.onNativeCall()
try {
return Iter_nHasNext(_ptr)
} finally {
reachabilityBarrier(this)
}
}

override fun next(): Run {
Stats.onNativeCall()
try {
val typeface = Typeface(Iter_nGetTypeface(_ptr))
val glyphCount = Iter_nGetGlyphCount(_ptr)
val glyphs = withResult(ShortArray(glyphCount)) {
Iter_nGetGlyphs(_ptr, it, glyphCount)
}
Iter_nFetch(_ptr)
return Run(typeface, glyphs)
} finally {
reachabilityBarrier(this)
}
}

private object FinalizerHolder {
val PTR = Iter_nGetFinalizer()
}
}

}

@ExternalSymbolName("org_jetbrains_skia_TextBlob__1nGetFinalizer")
Expand Down Expand Up @@ -380,3 +428,24 @@ private external fun _nGetFirstBaseline(ptr: NativePointer, resultArray: Interop

@ExternalSymbolName("org_jetbrains_skia_TextBlob__1nGetLastBaseline")
private external fun _nGetLastBaseline(ptr: NativePointer, resultArray: InteropPointer): Boolean

@ExternalSymbolName("org_jetbrains_skia_TextBlob_Iter__1nCreate")
private external fun Iter_nCreate(textBlobPtr: NativePointer): NativePointer

@ExternalSymbolName("org_jetbrains_skia_TextBlob_Iter__1nGetFinalizer")
private external fun Iter_nGetFinalizer(): NativePointer

@ExternalSymbolName("org_jetbrains_skia_TextBlob_Iter__1nFetch")
private external fun Iter_nFetch(ptr: NativePointer): Boolean

@ExternalSymbolName("org_jetbrains_skia_TextBlob_Iter__1nGetTypeface")
private external fun Iter_nGetTypeface(ptr: NativePointer): NativePointer

@ExternalSymbolName("org_jetbrains_skia_TextBlob_Iter__1nHasNext")
private external fun Iter_nHasNext(ptr: NativePointer): Boolean

@ExternalSymbolName("org_jetbrains_skia_TextBlob_Iter__1nGetGlyphCount")
private external fun Iter_nGetGlyphCount(ptr: NativePointer): Int

@ExternalSymbolName("org_jetbrains_skia_TextBlob_Iter__1nGetGlyphs")
private external fun Iter_nGetGlyphs(ptr: NativePointer, glyphs: InteropPointer, max: Int): Int
18 changes: 18 additions & 0 deletions skiko/src/commonTest/kotlin/org/jetbrains/skia/TextBlobTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jetbrains.skia

import org.jetbrains.skia.paragraph.TypefaceFontProvider
import org.jetbrains.skia.shaper.Shaper
import org.jetbrains.skia.tests.assertCloseEnough
import org.jetbrains.skia.tests.assertContentCloseEnough
import org.jetbrains.skia.tests.makeFromResource
Expand Down Expand Up @@ -231,4 +233,20 @@ class TextBlobTest {
val blobFromData = TextBlob.makeFromData(data)!!
assertContentEquals(expected = glyphs, actual = blobFromData.glyphs)
}

@Test
fun iterTest() = runTest {
val interFont = inter36()
val fontMgr = TypefaceFontProvider().apply {
registerTypeface(interFont.typeface, "Inter")
}
val text = "Hello, world!"
val glyphs = shortArrayOf(161, 611, 721, 721, 773, 1398, 1673, 934, 773, 835, 721, 593, 1326)
val runs = listOf(
TextBlob.TextBlobIter.Run(interFont.typeface!!, glyphs)
)
val textBlob = Shaper.make(fontMgr).shape(text, interFont)

assertContentEquals(runs, textBlob!!.toList())
}
}
44 changes: 44 additions & 0 deletions skiko/src/jvmMain/cpp/common/TextBlob.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "interop.hh"
#include "mppinterop.h"
#include "RunRecordClone.hh"
#include "TexBlobIter.hh"

static void unrefTextBlob(SkTextBlob* ptr) {
ptr->unref();
Expand Down Expand Up @@ -203,3 +204,46 @@ extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_TextBlobKt__1nGetL
env->ReleaseFloatArrayElements(resultArray, floats, 0);
return hasValue;
}


extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_TextBlobKt_Iter_1nCreate(JNIEnv* env, jclass jclass, jlong textBlobPtr) {
TextBlobIter* result = new TextBlobIter(reinterpret_cast<SkTextBlob*>(textBlobPtr));
return static_cast<jlong>(reinterpret_cast<uintptr_t>(result));
}

static void deleteTextBlobIter(TextBlobIter* ptr) {
delete ptr;
}

extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_TextBlobKt_Iter_1nGetFinalizer(JNIEnv* env, jclass jclass) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deleteTextBlobIter));
}

extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_TextBlobKt_Iter_1nFetch(JNIEnv* env, jclass jclass, jlong ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(static_cast<uintptr_t>(ptr));
return (jboolean) instance->fetch();
}

extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_TextBlobKt_Iter_1nHasNext(JNIEnv* env, jclass jclass, jlong ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(static_cast<uintptr_t>(ptr));
return (jboolean) instance->hasNext();
}

extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_TextBlobKt_Iter_1nGetTypeface(JNIEnv* env, jclass jclass, jlong ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(static_cast<uintptr_t>(ptr));
return (jlong) instance->getTypeface().release();
}

extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_TextBlobKt_Iter_1nGetGlyphCount(JNIEnv* env, jclass jclass, jlong ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(static_cast<uintptr_t>(ptr));
return (jint) instance->getGlyphCount();
}

extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_TextBlobKt_Iter_1nGetGlyphs
(JNIEnv* env, jclass jclass, jlong ptr, jshortArray dstArray, jint max) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(static_cast<uintptr_t>(ptr));
jshort* dst = env->GetShortArrayElements(dstArray, nullptr);
int size = instance->writeGlyphs((uint16_t*) dst, max);
env->ReleaseShortArrayElements(dstArray, dst, 0);
return (jint) size;
}
38 changes: 38 additions & 0 deletions skiko/src/nativeJsMain/cpp/TextBlob.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "common.h"
#include "RunRecordClone.hh"
#include "mppinterop.h"
#include "TexBlobIter.hh"

static void unrefTextBlob(SkTextBlob* ptr) {
ptr->unref();
Expand Down Expand Up @@ -174,3 +175,40 @@ SKIKO_EXPORT KBoolean org_jetbrains_skia_TextBlob__1nGetLastBaseline
(KNativePointer ptr, KFloat* resultArray) {
return skikoMpp::textblob::getLastBaseline(reinterpret_cast<SkTextBlob*>(ptr), resultArray);
}

SKIKO_EXPORT KNativePointer org_jetbrains_skia_TextBlob_Iter__1nCreate(KNativePointer textBlobPtr) {
return new TextBlobIter(reinterpret_cast<SkTextBlob*>(textBlobPtr));
}

static void deleteTextBlobIter(TextBlobIter* ptr) {
delete ptr;
}

SKIKO_EXPORT KNativePointer org_jetbrains_skia_TextBlob_Iter__1nGetFinalizer() {
return reinterpret_cast<KNativePointer>(&deleteTextBlobIter);
}

SKIKO_EXPORT KBoolean org_jetbrains_skia_TextBlob_Iter__1nFetch(KNativePointer ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(ptr);
return (KBoolean) instance->fetch();
}

SKIKO_EXPORT KBoolean org_jetbrains_skia_TextBlob_Iter__1nHasNext(KNativePointer ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(ptr);
return (KBoolean) instance->hasNext();
}

SKIKO_EXPORT KNativePointer org_jetbrains_skia_TextBlob_Iter__1nGetTypeface(KNativePointer ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(ptr);
return (KNativePointer) instance->getTypeface().release();
}

SKIKO_EXPORT KInt org_jetbrains_skia_TextBlob_Iter__1nGetGlyphCount(KNativePointer ptr) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(ptr);
return (KInt) instance->getGlyphCount();
}

SKIKO_EXPORT KInt org_jetbrains_skia_TextBlob_Iter__1nGetGlyphs(KNativePointer ptr, KInteropPointer dst, KInt max) {
TextBlobIter* instance = reinterpret_cast<TextBlobIter*>(ptr);
return (KInt) instance->writeGlyphs((uint16_t*) dst, max);
}

0 comments on commit bd7e73c

Please sign in to comment.