Unverified Commit 45c1a7df authored by Oleksandr Karpovich's avatar Oleksandr Karpovich Committed by GitHub

Add API to configure the fallback fonts provider when all default methods return null (#935)

New API:

```kotlin
fun TypefaceFontProvider.createAsFallbackProvider(): TypefaceFontProvider
fun FontMgr.defaultWithFallbackFontProvider(fallback: TypefaceFontProvider): FontMgr
```

Usage:

```kotlin
val fontCollection = FontCollection()

val notoEmojiTypeface = Typeface.makeFromData(Data.makeFromBytes(notoEmojisBytes))
val fallbackProvider = TypefaceFontProvider.createAsFallbackProvider().apply {
    registerTypeface(notoEmojiTypeface)
}

fontCollection.setDefaultFontManager(FontMgr.defaultWithFallbackFontProvider(fallbackProvider))
```

<img width="400" alt="Screenshot 2024-06-07 at 14 48 28"
src="https://github.com/JetBrains/skiko/assets/7372778/76dc1330-d8e2-4be7-ad92-68214b058b4f">
parent a03d0a59
...@@ -130,6 +130,7 @@ kotlin { ...@@ -130,6 +130,7 @@ kotlin {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
implementation("org.jetbrains.skiko:skiko:$version") implementation("org.jetbrains.skiko:skiko:$version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
} }
} }
......
kotlin.code.style=official kotlin.code.style=official
org.gradle.jvmargs=-Xmx3G -XX:MaxMetaspaceSize=512m org.gradle.jvmargs=-Xmx3G -XX:MaxMetaspaceSize=512m
kotlin.version=1.9.21 kotlin.version=1.9.21
#skiko.composite.build=1 skiko.composite.build=1
\ No newline at end of file \ No newline at end of file
...@@ -6,8 +6,11 @@ import javax.swing.* ...@@ -6,8 +6,11 @@ import javax.swing.*
fun main() { fun main() {
val skiaLayer = SkiaLayer() val skiaLayer = SkiaLayer()
val clocks = AwtClocks(skiaLayer) val app = run {
skiaLayer.renderDelegate = SkiaLayerRenderDelegate(skiaLayer, clocks) //EmojiStory()
AwtClocks(skiaLayer)
}
skiaLayer.renderDelegate = SkiaLayerRenderDelegate(skiaLayer, app)
SwingUtilities.invokeLater { SwingUtilities.invokeLater {
val window = JFrame("Skiko example").apply { val window = JFrame("Skiko example").apply {
defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
......
package org.jetbrains.skiko.sample
import org.jetbrains.skia.Canvas
import org.jetbrains.skia.FontMgr
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.ParagraphBuilder
import org.jetbrains.skia.paragraph.ParagraphStyle
import org.jetbrains.skia.paragraph.TextStyle
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.SkikoRenderDelegate
import org.jetbrains.skiko.hostOs
class EmojiStory : SkikoRenderDelegate {
private val platformYOffset = if (hostOs == OS.Ios) 50f else 5f
private val style = ParagraphStyle().apply {
textStyle = TextStyle().apply {
this.fontSize = 16.0f
}.setColor(0xFF000000.toInt())
}
private val paragraph = ParagraphBuilder(style, fontCollection)
.addText("\uD83D\uDCE1 Antenna - 天线\n")
.addText("⁉\uFE0F 〰\uFE0F ⁉\uFE0F\n")
.addText("\uD83D\uDE32 \uD83E\uDD14 \uD83D\uDCA1\n")
.addText("\uD83C\uDF0D Earth - 地球\n")
.addText("\uD83D\uDE80 Space rocket - 太空火箭\n")
.addText("\uD83C\uDF14 Moon - 月亮\n")
.addText("\uD83D\uDCAB Stars - 星星\n")
.addText("\uD83C\uDF0C Galaxy - 星系\n")
.addText("\uD83D\uDEF8 UFO - 飞碟\n")
.addText("\uD83D\uDC7D Alien - 外星人\n")
.addText("\uD83D\uDC4B \uD83E\uDD1D \uD83C\uDF7B \n")
.build()
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
paragraph.layout(Float.POSITIVE_INFINITY)
paragraph.paint(canvas, 5f, platformYOffset)
canvas.resetMatrix()
}
companion object {
val fontCollection = FontCollection()
.setDefaultFontManager(FontMgr.default)
}
}
\ No newline at end of file
package org.jetbrains.skiko.sample package org.jetbrains.skiko.sample
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import org.jetbrains.skia.Data
import org.jetbrains.skia.FontMgrWithFallback
import org.jetbrains.skia.Typeface
import org.jetbrains.skia.paragraph.TypefaceFontProviderWithFallback
import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerRenderDelegate import org.jetbrains.skiko.SkiaLayerRenderDelegate
import org.w3c.dom.HTMLCanvasElement import org.w3c.dom.HTMLCanvasElement
fun main() { fun main() {
runApp() //runClocksApp()
runEmojiStoryApp()
} }
internal fun runApp() { internal fun runClocksApp() {
val canvas = document.getElementById("SkikoTarget") as HTMLCanvasElement val canvas = document.getElementById("SkikoTarget") as HTMLCanvasElement
canvas.setAttribute("tabindex", "0") canvas.setAttribute("tabindex", "0")
val skiaLayer = SkiaLayer() val skiaLayer = SkiaLayer()
...@@ -17,3 +25,30 @@ internal fun runApp() { ...@@ -17,3 +25,30 @@ internal fun runApp() {
skiaLayer.renderDelegate = SkiaLayerRenderDelegate(skiaLayer, clocks) skiaLayer.renderDelegate = SkiaLayerRenderDelegate(skiaLayer, clocks)
skiaLayer.needRedraw() skiaLayer.needRedraw()
} }
private val notoColorEmoji = "https://storage.googleapis.com/skia-cdn/misc/NotoColorEmoji.ttf"
private val notoSancSC = "./NotoSansSC-Regular.ttf"
internal fun runEmojiStoryApp() {
val canvas = document.getElementById("SkikoTarget") as HTMLCanvasElement
canvas.setAttribute("tabindex", "0")
val skiaLayer = SkiaLayer()
val app = EmojiStory()
skiaLayer.renderDelegate = SkiaLayerRenderDelegate(skiaLayer, app)
skiaLayer.attachTo(canvas)
MainScope().launch {
val notoEmojisBytes = loadRes(notoColorEmoji).toByteArray()
val notoSansSCBytes = loadRes(notoSancSC).toByteArray()
val notoEmojiTypeface = Typeface.makeFromData(Data.makeFromBytes(notoEmojisBytes))
val notoSansSCTypeface = Typeface.makeFromData(Data.makeFromBytes(notoSansSCBytes))
val tfp = TypefaceFontProviderWithFallback().apply {
registerTypeface(notoEmojiTypeface)
registerTypeface(notoSansSCTypeface)
}
EmojiStory.fontCollection.setDefaultFontManager(FontMgrWithFallback(tfp))
skiaLayer.needRedraw()
}
}
package org.jetbrains.skiko.sample
import kotlinx.browser.window
import kotlinx.coroutines.await
import org.khronos.webgl.ArrayBuffer
import org.khronos.webgl.Int8Array
import org.w3c.fetch.Response
import org.w3c.xhr.XMLHttpRequest
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import kotlin.wasm.unsafe.UnsafeWasmMemoryApi
import kotlin.wasm.unsafe.withScopedMemoryAllocator
suspend fun loadRes(url: String): ArrayBuffer {
return window.fetch(url).await<Response>().arrayBuffer().await()
}
private class MissingResourceException(url: String): Exception("GET $url failed")
fun ArrayBuffer.toByteArray(): ByteArray {
val source = Int8Array(this, 0, byteLength)
return jsInt8ArrayToKotlinByteArray(source)
}
@JsFun(
""" (src, size, dstAddr) => {
const mem8 = new Int8Array(wasmExports.memory.buffer, dstAddr, size);
mem8.set(src);
}
"""
)
internal external fun jsExportInt8ArrayToWasm(src: Int8Array, size: Int, dstAddr: Int)
internal fun jsInt8ArrayToKotlinByteArray(x: Int8Array): ByteArray {
val size = x.length
@OptIn(UnsafeWasmMemoryApi::class)
return withScopedMemoryAllocator { allocator ->
val memBuffer = allocator.allocate(size)
val dstAddress = memBuffer.address.toInt()
jsExportInt8ArrayToWasm(x, size, dstAddress)
ByteArray(size) { i -> (memBuffer + i).loadByte() }
}
}
\ No newline at end of file
#include "FontMgrWithFallbackWrapper.hh"
FontMgrWithFallbackWrapper::FontMgrWithFallbackWrapper(sk_sp<TypefaceFontProviderWithFallback> fallbackTypefaceFontProvider)
: fallbackFontProvider(std::move(fallbackTypefaceFontProvider)) {
wrappedFntMgr = SkFontMgr::RefDefault();
}
int FontMgrWithFallbackWrapper::onCountFamilies() const {
return wrappedFntMgr->countFamilies();
}
void FontMgrWithFallbackWrapper::onGetFamilyName(int index, SkString* familyName) const {
wrappedFntMgr->getFamilyName(index, familyName);
}
sk_sp<SkFontStyleSet> FontMgrWithFallbackWrapper::onMatchFamily(const char familyName[]) const {
return wrappedFntMgr->matchFamily(familyName);
}
sk_sp<SkFontStyleSet> FontMgrWithFallbackWrapper::onCreateStyleSet(int ix) const {
return wrappedFntMgr->createStyleSet(ix);
}
sk_sp<SkTypeface> FontMgrWithFallbackWrapper::onMatchFamilyStyle(const char familyName[], const SkFontStyle& style) const {
return wrappedFntMgr->matchFamilyStyle(familyName, style);
}
sk_sp<SkTypeface> FontMgrWithFallbackWrapper::onMatchFamilyStyleCharacter(
const char fontFamily[], const SkFontStyle& style,
const char* bcp47[], int bcp47Count,
SkUnichar character
) const {
auto typeface = wrappedFntMgr->matchFamilyStyleCharacter(fontFamily, style, bcp47, bcp47Count, character);
if (!typeface) {
typeface = fallbackFontProvider->fallbackForChar(character);
}
return typeface;
}
sk_sp<SkTypeface> FontMgrWithFallbackWrapper::onMakeFromData(sk_sp<SkData> data, int ix) const {
return wrappedFntMgr->makeFromData(std::move(data), ix);
}
sk_sp<SkTypeface> FontMgrWithFallbackWrapper::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream, int ix) const {
return wrappedFntMgr->makeFromStream(std::move(stream), ix);
}
sk_sp<SkTypeface> FontMgrWithFallbackWrapper::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream, const SkFontArguments& args) const {
return wrappedFntMgr->makeFromStream(std::move(stream), args);
}
sk_sp<SkTypeface> FontMgrWithFallbackWrapper::onMakeFromFile(const char path[], int ix) const {
return wrappedFntMgr->makeFromFile(path, ix);
}
sk_sp<SkTypeface> FontMgrWithFallbackWrapper::onLegacyMakeTypeface(const char name[], SkFontStyle style) const {
return wrappedFntMgr->legacyMakeTypeface(name, style);
}
void FontMgrWithFallbackWrapper::setFallbackFontProvider(sk_sp<TypefaceFontProviderWithFallback> fontProvider) {
fallbackFontProvider = std::move(fontProvider);
}
/* TypefaceFontProviderWithFallback section */
size_t TypefaceFontProviderWithFallback::registerTypeface(sk_sp<SkTypeface> typeface) {
registeredTypefaces.push_back(typeface);
return TypefaceFontProvider::registerTypeface(std::move(typeface));
}
size_t TypefaceFontProviderWithFallback::registerTypeface(sk_sp<SkTypeface> typeface, const SkString& alias) {
registeredTypefaces.push_back(typeface);
return TypefaceFontProvider::registerTypeface(std::move(typeface), alias);
}
sk_sp<SkTypeface> TypefaceFontProviderWithFallback::fallbackForChar(SkUnichar character) const {
for (const auto& typeface : registeredTypefaces) {
if (!typeface) continue;
auto glyph = typeface->unicharToGlyph(character);
if (glyph != 0) {
return typeface;
}
}
return nullptr;
}
\ No newline at end of file
#ifndef FONT_MGR_WRAPPER_H
#define FONT_MGR_WRAPPER_H
#include "SkData.h"
#include "SkStream.h"
#include "SkTypeface.h"
#include "SkFontMgr.h"
#include "TypefaceFontProvider.h"
using namespace skia::textlayout;
// extends the default TypefaceFontProvider:
// - all registered Typefaces are collected in registeredTypefaces
// - then they are used to find a fallback Typeface in `fallbackForChar`
class TypefaceFontProviderWithFallback : public TypefaceFontProvider {
public:
size_t registerTypeface(sk_sp<SkTypeface> typeface);
size_t registerTypeface(sk_sp<SkTypeface> typeface, const SkString& alias);
sk_sp<SkTypeface> fallbackForChar(SkUnichar character) const;
private:
std::vector<sk_sp<SkTypeface>> registeredTypefaces;
};
// FontMgrWithFallbackWrapper implementation in most methods simply delegates to wrappedFntMgr.
// The only modified implementation is onMatchFamilyStyleCharacter, which attempts to find
// any Typeface (fallback) for a given character, if all other default fallbacks didn't find anything.
// To achieve this it relies on fallbackFontProvider set via `setFallbackFontProvider`.
class FontMgrWithFallbackWrapper : public SkFontMgr {
public:
explicit FontMgrWithFallbackWrapper(sk_sp<TypefaceFontProviderWithFallback>);
int onCountFamilies() const override;
void onGetFamilyName(int index, SkString* familyName) const override;
sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override;
sk_sp<SkFontStyleSet> onCreateStyleSet(int) const override;
sk_sp<SkTypeface> onMatchFamilyStyle(const char[], const SkFontStyle&) const override;
sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char[], const SkFontStyle&,
const char*[], int,
SkUnichar) const override;
sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int) const override;
sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>, int) const override;
sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
const SkFontArguments&) const override;
sk_sp<SkTypeface> onMakeFromFile(const char[], int) const override;
sk_sp<SkTypeface> onLegacyMakeTypeface(const char[], SkFontStyle) const override;
void setFallbackFontProvider(sk_sp<TypefaceFontProviderWithFallback>);
private:
sk_sp<SkFontMgr> wrappedFntMgr;
sk_sp<TypefaceFontProviderWithFallback> fallbackFontProvider;
};
#endif
\ No newline at end of file
...@@ -2,6 +2,7 @@ package org.jetbrains.skia ...@@ -2,6 +2,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
import org.jetbrains.skia.paragraph.TypefaceFontProvider
open class FontMgr : RefCnt { open class FontMgr : RefCnt {
companion object { companion object {
......
package org.jetbrains.skia
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.paragraph.TypefaceFontProviderWithFallback
/**
* Consider registering this FontMgr as a default one
* to let all other possibly registered Font managers to look for their fallbacks first:
* `FontCollection.setDefaultFontManager(...)`
*
* The fallbacks provided by this class will be used a last resort.
*/
class FontMgrWithFallback(
fallbackProvider: TypefaceFontProviderWithFallback
) : FontMgr(_nDefaultWithFallbackFontProvider(fallbackProvider._ptr))
@ExternalSymbolName("org_jetbrains_skia_FontMgrWithFallback__1nDefaultWithFallbackFontProvider")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_FontMgrWithFallback__1nDefaultWithFallbackFontProvider")
private external fun _nDefaultWithFallbackFontProvider(fallbackPtr: NativePointer): NativePointer
\ No newline at end of file
...@@ -12,14 +12,19 @@ import org.jetbrains.skia.impl.NativePointer ...@@ -12,14 +12,19 @@ import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.getPtr import org.jetbrains.skia.impl.getPtr
import org.jetbrains.skia.impl.interopScope import org.jetbrains.skia.impl.interopScope
class TypefaceFontProvider : FontMgr(TypefaceFontProvider_nMake()) { open class TypefaceFontProvider internal constructor(
ptr: NativePointer
) : FontMgr(ptr) {
constructor(): this(TypefaceFontProvider_nMake())
companion object { companion object {
init { init {
staticLoad() staticLoad()
} }
} }
fun registerTypeface(typeface: Typeface?, alias: String? = null): TypefaceFontProvider { open fun registerTypeface(typeface: Typeface?, alias: String? = null): TypefaceFontProvider {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
interopScope { interopScope {
...@@ -48,4 +53,4 @@ private external fun TypefaceFontProvider_nMake(): NativePointer ...@@ -48,4 +53,4 @@ private external fun TypefaceFontProvider_nMake(): NativePointer
@ExternalSymbolName("org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface") @ExternalSymbolName("org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface") @ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface")
private external fun _nRegisterTypeface(ptr: NativePointer, typefacePtr: NativePointer, alias: InteropPointer) private external fun _nRegisterTypeface(ptr: NativePointer, typefacePtr: NativePointer, alias: InteropPointer): Int
package org.jetbrains.skia.paragraph
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.FontMgr
import org.jetbrains.skia.ModuleImport
import org.jetbrains.skia.Typeface
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.getPtr
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skia.impl.reachabilityBarrier
class TypefaceFontProviderWithFallback private constructor(
ptr: NativePointer,
) : TypefaceFontProvider(ptr) {
constructor() : this(_nMakeAsFallbackProvider())
companion object {
init {
Library.staticLoad()
}
}
override fun registerTypeface(typeface: Typeface?, alias: String?): TypefaceFontProviderWithFallback {
return try {
Stats.onNativeCall()
interopScope {
_nRegisterTypefaceForFallback(
_ptr,
getPtr(typeface),
toInterop(alias)
)
}
this
} finally {
reachabilityBarrier(this)
reachabilityBarrier(typeface)
}
}
init {
Stats.onNativeCall()
}
}
@ExternalSymbolName("org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallback__1nMakeAsFallbackProvider")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallback__1nMakeAsFallbackProvider")
private external fun _nMakeAsFallbackProvider(): NativePointer
@ExternalSymbolName("org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallback__1nRegisterTypefaceForFallback")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallback__1nRegisterTypefaceForFallback")
private external fun _nRegisterTypefaceForFallback(
ptr: NativePointer,
typefacePtr: NativePointer,
alias: InteropPointer
): Int
\ No newline at end of file
...@@ -38,10 +38,11 @@ enum class KotlinBackend(val id: String) { ...@@ -38,10 +38,11 @@ enum class KotlinBackend(val id: String) {
JVM("jvm"), JVM("jvm"),
JS("js"), JS("js"),
Native("native"), Native("native"),
WASM("wasm"), Wasm("wasm"),
; ;
fun isNotJs() = this != JS fun isNotJs() = this != JS
fun isWeb() = this == JS || this == Wasm || this.id == "wasm"
} }
// Note: it returns the host OS for web apps too // Note: it returns the host OS for web apps too
......
package org.jetbrains.skia
import org.jetbrains.skia.impl.use
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.TypefaceFontProviderWithFallback
import org.jetbrains.skia.tests.makeFromResource
import org.jetbrains.skiko.kotlinBackend
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
class FontFallbackTest {
@Test
fun testChinese_withFallback() = runTest {
val fm = TypefaceFontProviderWithFallback()
val notoSansSC = Typeface.makeFromResource("./fonts/NotoSansSC-Regular.ttf", 0)
fm.registerTypeface(notoSansSC)
FontCollection().use {
it.setDefaultFontManager(FontMgrWithFallback(fm))
// 0x6C34 = "水"
val df = it.defaultFallback(0x6C34, FontStyle.NORMAL, null)!!
val glyphs = df.getStringGlyphs("水")
if (kotlinBackend.isWeb()) {
assertEquals("Noto Sans SC", df.familyName)
assertContentEquals(shortArrayOf(16391), glyphs)
} else {
// the actual font can be different on different systems,
// so just making sure it's not null
assertNotEquals<String?>(null, df.familyName)
}
}
}
}
\ No newline at end of file
package org.jetbrains.skia
import org.jetbrains.skia.impl.use
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
class FontFallbackWebTest {
@Test
fun testChinese_noFallback() = runTest {
FontCollection().use {
it.setDefaultFontManager(FontMgr.default)
// 0x6C34 = "水"
val df = it.defaultFallback(0x6C34, FontStyle.NORMAL, null)
assertEquals(null, df)
}
}
}
\ No newline at end of file
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "SkData.h" #include "SkData.h"
#include "SkTypeface.h" #include "SkTypeface.h"
#include "SkFontMgr.h" #include "SkFontMgr.h"
#include "FontMgrWithFallbackWrapper.hh"
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_FontMgrKt__1nGetFamiliesCount extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_FontMgrKt__1nGetFamiliesCount
(JNIEnv* env, jclass jclass, jlong ptr) { (JNIEnv* env, jclass jclass, jlong ptr) {
...@@ -71,3 +72,10 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_FontMgrKt__1nDefault ...@@ -71,3 +72,10 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_FontMgrKt__1nDefault
SkFontMgr* instance = SkFontMgr::RefDefault().release(); SkFontMgr* instance = SkFontMgr::RefDefault().release();
return reinterpret_cast<jlong>(instance); return reinterpret_cast<jlong>(instance);
} }
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_FontMgrWithFallbackKt__1nDefaultWithFallbackFontProvider
(JNIEnv* env, jclass jclass, jlong fallbackPtr) {
TypefaceFontProviderWithFallback* fallback = reinterpret_cast<TypefaceFontProviderWithFallback*>((fallbackPtr));
FontMgrWithFallbackWrapper* instance = new FontMgrWithFallbackWrapper(sk_ref_sp(fallback));
return reinterpret_cast<jlong>(instance);
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "../interop.hh" #include "../interop.hh"
#include "TypefaceFontProvider.h" #include "TypefaceFontProvider.h"
#include "SkTypeface.h" #include "SkTypeface.h"
#include "FontMgrWithFallbackWrapper.hh"
using namespace skia::textlayout; using namespace skia::textlayout;
...@@ -12,12 +13,31 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_paragraph_TypefaceFon ...@@ -12,12 +13,31 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_paragraph_TypefaceFon
return reinterpret_cast<jlong>(instance); return reinterpret_cast<jlong>(instance);
} }
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_paragraph_TypefaceFontProviderKt__1nRegisterTypeface extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_paragraph_TypefaceFontProviderKt__1nRegisterTypeface
(JNIEnv* env, jclass jclass, jlong ptr, jlong typefacePtr, jstring aliasStr) { (JNIEnv* env, jclass jclass, jlong ptr, jlong typefacePtr, jstring aliasStr) {
TypefaceFontProvider* instance = reinterpret_cast<TypefaceFontProvider*>(static_cast<uintptr_t>(ptr)); TypefaceFontProvider* instance = reinterpret_cast<TypefaceFontProvider*>(static_cast<uintptr_t>(ptr));
SkTypeface* typeface = reinterpret_cast<SkTypeface*>(static_cast<uintptr_t>(typefacePtr)); SkTypeface* typeface = reinterpret_cast<SkTypeface*>(static_cast<uintptr_t>(typefacePtr));
if (aliasStr == nullptr) if (aliasStr == nullptr) {
instance->registerTypeface(sk_ref_sp(typeface)); return instance->registerTypeface(sk_ref_sp(typeface));
else } else {
instance->registerTypeface(sk_ref_sp(typeface), skString(env, aliasStr)); return instance->registerTypeface(sk_ref_sp(typeface), skString(env, aliasStr));
}
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallbackKt__1nMakeAsFallbackProvider
(JNIEnv* env, jclass jclass) {
TypefaceFontProviderWithFallback* instance = new TypefaceFontProviderWithFallback();
return reinterpret_cast<jlong>(instance);
}
extern "C" JNIEXPORT jint JNICALL Java_org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallbackKt__1nRegisterTypefaceForFallback
(JNIEnv* env, jclass jclass, jlong ptr, jlong typefacePtr, jstring aliasStr) {
TypefaceFontProviderWithFallback* instance = reinterpret_cast<TypefaceFontProviderWithFallback*>((ptr));
SkTypeface* typeface = reinterpret_cast<SkTypeface*>((typefacePtr));
if (aliasStr == nullptr) {
return instance->registerTypeface(sk_ref_sp(typeface));
} else {
return instance->registerTypeface(sk_ref_sp(typeface), skString(env, aliasStr));
}
} }
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "SkTypeface.h" #include "SkTypeface.h"
#include "SkFontMgr.h" #include "SkFontMgr.h"
#include "common.h" #include "common.h"
#include "FontMgrWithFallbackWrapper.hh"
SKIKO_EXPORT KInt org_jetbrains_skia_FontMgr__1nGetFamiliesCount SKIKO_EXPORT KInt org_jetbrains_skia_FontMgr__1nGetFamiliesCount
(KNativePointer ptr) { (KNativePointer ptr) {
...@@ -72,3 +73,16 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_FontMgr__1nDefault ...@@ -72,3 +73,16 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_FontMgr__1nDefault
SkFontMgr* instance = SkFontMgr::RefDefault().release(); SkFontMgr* instance = SkFontMgr::RefDefault().release();
return reinterpret_cast<KNativePointer>(instance); return reinterpret_cast<KNativePointer>(instance);
} }
SKIKO_EXPORT KNativePointer org_jetbrains_skia_FontMgr__1nEmpty
() {
SkFontMgr* instance = SkFontMgr::RefEmpty().release();
return reinterpret_cast<KNativePointer>(instance);
}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_FontMgrWithFallback__1nDefaultWithFallbackFontProvider(KNativePointer fallbackFontProviderPtr) {
TypefaceFontProviderWithFallback* fallback = reinterpret_cast<TypefaceFontProviderWithFallback*>((fallbackFontProviderPtr));
FontMgrWithFallbackWrapper* instance = new FontMgrWithFallbackWrapper(sk_ref_sp(fallback));
return reinterpret_cast<KNativePointer>(instance);
}
\ No newline at end of file
#include <iostream> #include <iostream>
#include "TypefaceFontProvider.h" #include "TypefaceFontProvider.h"
#include "SkTypeface.h" #include "SkTypeface.h"
#include "FontMgrWithFallbackWrapper.hh"
using namespace skia::textlayout; using namespace skia::textlayout;
#include "common.h" #include "common.h"
...@@ -10,13 +11,31 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_paragraph_TypefaceFontProvider__1 ...@@ -10,13 +11,31 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_paragraph_TypefaceFontProvider__1
return reinterpret_cast<KNativePointer>(instance); return reinterpret_cast<KNativePointer>(instance);
} }
SKIKO_EXPORT void org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface SKIKO_EXPORT KNativePointer org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallback__1nMakeAsFallbackProvider
() {
TypefaceFontProviderWithFallback* instance = new TypefaceFontProviderWithFallback();
return reinterpret_cast<KNativePointer>(instance);
}
SKIKO_EXPORT KInt org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface
(KNativePointer ptr, KNativePointer typefacePtr, KInteropPointer aliasStr) { (KNativePointer ptr, KNativePointer typefacePtr, KInteropPointer aliasStr) {
TypefaceFontProvider* instance = reinterpret_cast<TypefaceFontProvider*>((ptr)); TypefaceFontProvider* instance = reinterpret_cast<TypefaceFontProvider*>((ptr));
SkTypeface* typeface = reinterpret_cast<SkTypeface*>((typefacePtr)); SkTypeface* typeface = reinterpret_cast<SkTypeface*>((typefacePtr));
if (aliasStr == nullptr) if (aliasStr == nullptr) {
instance->registerTypeface(sk_ref_sp(typeface)); return instance->registerTypeface(sk_ref_sp(typeface));
else } else {
instance->registerTypeface(sk_ref_sp(typeface), skString(aliasStr)); return instance->registerTypeface(sk_ref_sp(typeface), skString(aliasStr));
}
}
SKIKO_EXPORT KInt org_jetbrains_skia_paragraph_TypefaceFontProviderWithFallback__1nRegisterTypefaceForFallback
(KNativePointer ptr, KNativePointer typefacePtr, KInteropPointer aliasStr) {
TypefaceFontProviderWithFallback* instance = reinterpret_cast<TypefaceFontProviderWithFallback*>((ptr));
SkTypeface* typeface = reinterpret_cast<SkTypeface*>((typefacePtr));
if (aliasStr == nullptr) {
return instance->registerTypeface(sk_ref_sp(typeface));
} else {
return instance->registerTypeface(sk_ref_sp(typeface), skString(aliasStr));
}
} }
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