Unverified Commit bd7e73cf authored by Aleksandr Veselov's avatar Aleksandr Veselov Committed by GitHub

Implement SkTextBlob::Iter in Skiko (#512)

parent 8fccb7ea
#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;
};
...@@ -3,7 +3,7 @@ package org.jetbrains.skia ...@@ -3,7 +3,7 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.* import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad 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 { companion object {
/** /**
* Returns a TextBlob built from a single run of text with x-positions and a single y value. * Returns a TextBlob built from a single run of text with x-positions and a single y value.
...@@ -319,6 +319,54 @@ class TextBlob internal constructor(ptr: NativePointer) : Managed(ptr, _Finalize ...@@ -319,6 +319,54 @@ class TextBlob internal constructor(ptr: NativePointer) : Managed(ptr, _Finalize
private object _FinalizerHolder { private object _FinalizerHolder {
val PTR = TextBlob_nGetFinalizer() 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") @ExternalSymbolName("org_jetbrains_skia_TextBlob__1nGetFinalizer")
...@@ -380,3 +428,24 @@ private external fun _nGetFirstBaseline(ptr: NativePointer, resultArray: Interop ...@@ -380,3 +428,24 @@ private external fun _nGetFirstBaseline(ptr: NativePointer, resultArray: Interop
@ExternalSymbolName("org_jetbrains_skia_TextBlob__1nGetLastBaseline") @ExternalSymbolName("org_jetbrains_skia_TextBlob__1nGetLastBaseline")
private external fun _nGetLastBaseline(ptr: NativePointer, resultArray: InteropPointer): Boolean 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
package org.jetbrains.skia 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.assertCloseEnough
import org.jetbrains.skia.tests.assertContentCloseEnough import org.jetbrains.skia.tests.assertContentCloseEnough
import org.jetbrains.skia.tests.makeFromResource import org.jetbrains.skia.tests.makeFromResource
...@@ -231,4 +233,20 @@ class TextBlobTest { ...@@ -231,4 +233,20 @@ class TextBlobTest {
val blobFromData = TextBlob.makeFromData(data)!! val blobFromData = TextBlob.makeFromData(data)!!
assertContentEquals(expected = glyphs, actual = blobFromData.glyphs) 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())
}
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "interop.hh" #include "interop.hh"
#include "mppinterop.h" #include "mppinterop.h"
#include "RunRecordClone.hh" #include "RunRecordClone.hh"
#include "TexBlobIter.hh"
static void unrefTextBlob(SkTextBlob* ptr) { static void unrefTextBlob(SkTextBlob* ptr) {
ptr->unref(); ptr->unref();
...@@ -203,3 +204,46 @@ extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_TextBlobKt__1nGetL ...@@ -203,3 +204,46 @@ extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_TextBlobKt__1nGetL
env->ReleaseFloatArrayElements(resultArray, floats, 0); env->ReleaseFloatArrayElements(resultArray, floats, 0);
return hasValue; 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;
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "common.h" #include "common.h"
#include "RunRecordClone.hh" #include "RunRecordClone.hh"
#include "mppinterop.h" #include "mppinterop.h"
#include "TexBlobIter.hh"
static void unrefTextBlob(SkTextBlob* ptr) { static void unrefTextBlob(SkTextBlob* ptr) {
ptr->unref(); ptr->unref();
...@@ -174,3 +175,40 @@ SKIKO_EXPORT KBoolean org_jetbrains_skia_TextBlob__1nGetLastBaseline ...@@ -174,3 +175,40 @@ SKIKO_EXPORT KBoolean org_jetbrains_skia_TextBlob__1nGetLastBaseline
(KNativePointer ptr, KFloat* resultArray) { (KNativePointer ptr, KFloat* resultArray) {
return skikoMpp::textblob::getLastBaseline(reinterpret_cast<SkTextBlob*>(ptr), 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);
}
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