Unverified Commit 537bb123 authored by Aleksandr Veselov's avatar Aleksandr Veselov Committed by GitHub

Implement common test resource loading (#303)

parent ed2e75d3
......@@ -387,17 +387,20 @@ kotlin {
val darwinMain by creating {
dependsOn(nativeMain)
}
val darwinTest by creating {
dependsOn(nativeTest)
}
val macosMain by creating {
dependsOn(darwinMain)
}
val macosTest by creating {
dependsOn(nativeTest)
dependsOn(darwinTest)
}
val iosMain by creating {
dependsOn(darwinMain)
}
val iosTest by creating {
dependsOn(nativeTest)
dependsOn(darwinTest)
}
val macosArch = when (targetArch) {
Arch.X64 -> {
......
......@@ -7,17 +7,38 @@ config.browserConsoleLogOptions.level = "debug";
const basePath = config.basePath;
const projectPath = path.resolve(basePath, "..", "..", "..", "..", "..");
const wasmPath = path.resolve(projectPath, "build", "out", "link", "Release-wasm-wasm")
const generatedAssetsPath = path.resolve(projectPath, "build", "karma-webpack-out")
const debug = message => console.log(`[karma-config] ${message}`);
debug(`karma basePath: ${basePath}`);
debug(`karma wasmPath: ${wasmPath}`);
debug(`karma generatedAssetsPath: ${generatedAssetsPath}`);
config.proxies = {
"/wasm/": wasmPath
}
config.webpack.output = Object.assign(config.webpack.output || {}, {
path: generatedAssetsPath
})
config.webpack.module.rules.push(
{
test: /\.(ttf|woff|woff2)$/,
type: 'asset/resource',
generator: {
filename: "assets/fonts/[name][ext]"
}
},
{
test: /\.txt$/,
type: 'asset/inline'
},
);
config.files = [
path.resolve(wasmPath, "skiko.js"),
{pattern: path.resolve(wasmPath, "skiko.wasm"), included: false, served: true, watched: false},
{pattern: path.resolve(generatedAssetsPath, "**/*"), included: false, served: true, watched: false},
].concat(config.files);
......@@ -17,15 +17,6 @@ class Data internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
)
}
/**
* Create a new dataref the file with the specified path.
* If the file cannot be opened, this returns null.
*/
fun makeFromFileName(path: String?): Data {
Stats.onNativeCall()
return Data(_nMakeFromFileName(path))
}
/**
* Returns a new empty dataref (or a reference to a shared empty dataref).
* New or shared, the caller must see that [.close] is eventually called.
......@@ -139,7 +130,7 @@ private external fun _nToByteBuffer(ptr: NativePointer): ByteBuffer
private external fun _nMakeFromBytes(bytes: InteropPointer, offset: Int, length: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Data__1nMakeFromFileName")
private external fun _nMakeFromFileName(path: String?): NativePointer
internal external fun _nMakeFromFileName(path: InteropPointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Data__1nMakeSubset")
private external fun _nMakeSubset(ptr: NativePointer, offset: Int, length: Int): NativePointer
......
package org.jetbrains.skia
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad
import org.jetbrains.skia.impl.RefCnt
import org.jetbrains.skia.impl.Native
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.reachabilityBarrier
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.getPtr
class Typeface internal constructor(ptr: NativePointer) : RefCnt(ptr) {
companion object {
......@@ -30,24 +25,7 @@ class Typeface internal constructor(ptr: NativePointer) : RefCnt(ptr) {
Stats.onNativeCall()
return Typeface(_nMakeFromName(name, style._value))
}
/**
* @return a new typeface given a file
* @throws IllegalArgumentException If the file does not exist, or is not a valid font file
*/
/**
* @return a new typeface given a file
* @throws IllegalArgumentException If the file does not exist, or is not a valid font file
*/
fun makeFromFile(path: String, index: Int = 0): Typeface {
Stats.onNativeCall()
val ptr = _nMakeFromFile(path, index)
require(ptr != NullPointer) { "Failed to create Typeface from path=\"$path\" index=$index" }
return Typeface(ptr)
}
/**
* @return a new typeface given a Data
* @throws IllegalArgumentException If the data is null, or is not a valid font file
*/
/**
* @return a new typeface given a Data
* @throws IllegalArgumentException If the data is null, or is not a valid font file
......@@ -388,7 +366,7 @@ private external fun _nGetVariationAxes(ptr: NativePointer): Array<FontVariation
private external fun _nMakeFromName(name: String?, fontStyle: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Typeface__1nMakeFromFile")
private external fun _nMakeFromFile(path: String?, index: Int): NativePointer
internal external fun _nMakeFromFile(path: InteropPointer, index: Int): NativePointer
@ExternalSymbolName("org_jetbrains_skia_Typeface__1nMakeFromData")
private external fun _nMakeFromData(dataPtr: NativePointer, index: Int): NativePointer
......
......@@ -3,4 +3,6 @@ package org.jetbrains.skia.impl
expect abstract class RefCnt : Managed {
protected constructor(ptr: NativePointer)
protected constructor(ptr: NativePointer, allowClose: Boolean)
val refCount: Int
}
\ No newline at end of file
package org.jetbrains.skiko
expect suspend fun loadBytesFromPath(path: String): ByteArray
......@@ -3,9 +3,6 @@ package org.jetbrains.skia.tests
import org.jetbrains.skia.Data
import org.jetbrains.skia.Typeface
private const val RESOURCES_PATH = "src/jvmTest/resources/fonts"
expect suspend fun Typeface.Companion.makeFromResource(resourceId: String, index: Int = 0): Typeface
fun Typeface.Companion.makeFromResource(resourceId: String, index: Int = 0): Typeface =
makeFromFile("$RESOURCES_PATH/$resourceId", index)
fun Data.Companion.makeFromResource(resourceId: String) = makeFromFileName("$RESOURCES_PATH/$resourceId")
expect suspend fun Data.Companion.makeFromResource(resourceId: String): Data
package org.jetbrains.skiko
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test
import kotlin.test.assertContentEquals
class ResourceTest {
@Test
fun loadFromPathTest() = runTest {
val bytes = loadBytesFromPath(resourcePath("./hello_world.txt"))
assertContentEquals("Hello, world!".encodeToByteArray(), bytes)
}
@Test
fun loadResourceTest() = runTest {
val bytes = loadResourceAsBytes("./hello_world.txt")
assertContentEquals("Hello, world!".encodeToByteArray(), bytes)
}
@Test
fun loadFontTest() = runTest {
val url = resourcePath("./fonts/FiraCode-Regular.ttf")
val res = loadBytesFromPath(url).sliceArray(0..9)
assertContentEquals(byteArrayOf(
0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04
), res)
}
}
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skia.*
import org.jetbrains.skia.tests.makeFromResource
import org.jetbrains.skiko.tests.runTest
import kotlin.test.*
class TypefaceTest {
@Test
fun typefaceTest() = runTest {
// TODO Commonize array and string results and uncomment
val inter = Typeface.makeFromResource("./fonts/Inter-Hinted-Regular.ttf")
val interV = Typeface.makeFromResource("./fonts/Inter-V.ttf")
val jbMono = Typeface.makeFromResource("./fonts/JetBrainsMono-Regular.ttf")
val jbMonoBold = Typeface.makeFromData(Data.makeFromResource("./fonts/JetBrainsMono-Bold.ttf"))
assertEquals(FontStyle.NORMAL, inter.fontStyle)
assertFalse(inter.isBold)
assertFalse(inter.isItalic)
assertEquals(FontStyle.BOLD, jbMonoBold.fontStyle)
assertTrue(jbMonoBold.isBold)
assertFalse(jbMonoBold.isItalic)
assertFalse(inter.isFixedPitch)
assertTrue(jbMono.isFixedPitch)
if (kotlinBackend == KotlinBackend.JVM) {
assertNull(inter.variationAxes)
assertNull(inter.variations)
val axes = arrayOf(
FontVariationAxis("wght", 100f, 400f, 900f),
FontVariationAxis("slnt", -10f, 0f, 0f)
)
assertContentEquals(axes, interV.variationAxes)
val inter500: Typeface = interV.makeClone(FontVariation("wght", 500f))
assertNotEquals(inter500, interV)
assertContentEquals(FontVariation.parse("wght=500 slnt=0"), inter500.variations)
val inter400: Typeface = interV.makeClone(FontVariation("wght", 400f))
}
assertNotEquals(inter.uniqueId, interV.uniqueId)
assertNotEquals(inter, interV)
assertNotNull(Typeface.makeDefault())
if (kotlinBackend == KotlinBackend.JVM) {
val Skia = intArrayOf(83, 107, 105, 97)
assertContentEquals(shortArrayOf(394, 713, 677, 503), inter.getUTF32Glyphs(Skia))
assertContentEquals(shortArrayOf(394, 713, 677, 503), inter.getStringGlyphs("Skia"))
}
assertEquals(394, inter.getUTF32Glyph(83))
assertEquals(2548, interV.glyphsCount)
assertEquals(17, inter.tablesCount)
if (kotlinBackend == KotlinBackend.JVM) {
assertContentEquals(
arrayOf(
"GDEF",
"GPOS",
"GSUB",
"OS/2",
"cmap",
"cvt ",
"fpgm",
"gasp",
"glyf",
"head",
"hhea",
"hmtx",
"loca",
"maxp",
"name",
"post",
"prep"
), inter.tableTags
)
}
assertTrue(inter.getTableData("loca")!!.size > 0)
assertEquals(2816, inter.unitsPerEm)
if (kotlinBackend == KotlinBackend.JVM) {
assertNull(jbMono.getKerningPairAdjustments(null))
assertNull(jbMono.getKerningPairAdjustments(jbMono.getStringGlyphs("TAV")))
assertContentEquals(arrayOf(FontFamilyName("Inter", "en-US")), interV.familyNames)
assertEquals("Inter", interV.familyName)
}
}
}
\ No newline at end of file
package org.jetbrains.skiko
expect fun resourcePath(resourceId: String): String
suspend inline fun loadResourceAsBytes(resourcePath: String): ByteArray
= loadBytesFromPath(resourcePath(resourcePath))
\ No newline at end of file
Hello, world!
\ No newline at end of file
package org.jetbrains.skiko
import platform.Foundation.NSBundle
import platform.Foundation.NSURL
private val KEXE_DIR: String = NSBundle.mainBundle.bundlePath
private const val RESOURCES_PATH = "src/commonTest/resources"
actual fun resourcePath(resourceId: String) = run {
val filePath = "$KEXE_DIR/../../../../$RESOURCES_PATH/$resourceId"
// Remove all '..' and '.'
val standardized = NSURL.URLWithString(filePath)?.standardizedURL?.absoluteString
standardized ?: filePath
}
......@@ -6,7 +6,7 @@ actual abstract class RefCnt : Managed {
actual protected constructor(ptr: NativePointer): super(ptr, _FinalizerHolder.PTR, true)
actual protected constructor(ptr: NativePointer, allowClose: Boolean): super(ptr, _FinalizerHolder.PTR, allowClose)
val refCount: Int
actual val refCount: Int
get() {
Stats.onNativeCall()
return _nGetRefCount(_ptr)
......
package org.jetbrains.skiko
import kotlinx.browser.window
import kotlinx.coroutines.await
import org.khronos.webgl.Int8Array
actual suspend fun loadBytesFromPath(path: String): ByteArray {
val arrayBuffer = window.fetch(path)
.await()
.arrayBuffer()
.await()
val byteArray = Int8Array(arrayBuffer)
return byteArray.unsafeCast<ByteArray>()
}
package org.jetbrains.skia.tests
import org.jetbrains.skia.Data
import org.jetbrains.skia.Typeface
import org.jetbrains.skiko.loadResourceAsBytes
actual suspend inline fun Typeface.Companion.makeFromResource(resourceId: String, index: Int): Typeface =
makeFromData(Data.makeFromResource(resourceId), index)
actual suspend inline fun Data.Companion.makeFromResource(resourceId: String) =
makeFromBytes(loadResourceAsBytes(resourceId))
package org.jetbrains.skiko
import org.jetbrains.skiko.tests.runTest
import org.khronos.webgl.Int8Array
import kotlin.test.Test
import kotlin.test.assertContentEquals
class ResourcesTest {
@Test
fun loadFromPathInlineTest() = runTest {
val bytes = loadBytesFromPath(resourcePath("./hello_world.txt"))
assertContentEquals("Hello, world!".encodeToByteArray(), bytes)
}
@Test
fun loadFromPathExternTest() = runTest {
val url = resourcePath("./fonts/FiraCode-Regular.ttf")
val res = loadBytesFromPath(url).sliceArray(0..9)
assertContentEquals(byteArrayOf(
0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04
), res)
}
@Test
fun loadResourceInlineTest() = runTest {
val bytes = loadResourceAsBytes("./hello_world.txt")
assertContentEquals("Hello, world!".encodeToByteArray(), bytes)
}
@Test
fun loadResourceExternTest() = runTest {
val res = loadResourceAsBytes("./fonts/FiraCode-Regular.ttf").sliceArray(0..9)
assertContentEquals(byteArrayOf(
0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04
), res)
}
@Test
fun loadFromPathByNonLiteralPathTest() = runTest {
suspend fun loadFont(style: String): ByteArray {
val url = resourcePath("./fonts/FiraCode-$style.ttf")
val res = loadBytesFromPath(url).sliceArray(0..9)
return res
}
assertContentEquals(byteArrayOf(
0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04
), loadFont("Regular"))
}
@Test
fun typedArrayCastTest() {
val data = Int8Array(byteArrayOf(1, 2, 3, 4, 5).toTypedArray())
val casted = data.unsafeCast<ByteArray>()
assertContentEquals(byteArrayOf(1, 2, 3, 4, 5), casted)
}
}
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skia.ExternalSymbolName
@ExternalSymbolName("require")
actual external fun resourcePath(resourceId: String): String
package org.jetbrains.skia
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.interopScope
/**
* Create a new dataref the file with the specified path.
* If the file cannot be opened, this returns null.
*/
fun Data.Companion.makeFromFileName(path: String?): Data {
Stats.onNativeCall()
interopScope {
return Data(_nMakeFromFileName(toInterop(path)))
}
}
\ No newline at end of file
package org.jetbrains.skia
import org.jetbrains.skia.impl.Native
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.interopScope
/**
* @return a new typeface given a file
* @throws IllegalArgumentException If the file does not exist, or is not a valid font file
*/
fun Typeface.Companion.makeFromFile(path: String, index: Int = 0): Typeface {
Stats.onNativeCall()
interopScope {
val ptr = _nMakeFromFile(toInterop(path), index)
require(ptr != Native.NullPointer) { "Failed to create Typeface from path=\"$path\" index=$index" }
return Typeface(ptr)
}
}
\ No newline at end of file
......@@ -6,7 +6,7 @@ actual abstract class RefCnt : Managed {
protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR, true)
protected actual constructor(ptr: NativePointer, allowClose: Boolean) : super(ptr, _FinalizerHolder.PTR, allowClose)
val refCount: Int
actual val refCount: Int
get() = try {
Stats.onNativeCall()
_nGetRefCount(_ptr)
......
package org.jetbrains.skiko
import java.io.File
actual suspend fun loadBytesFromPath(path: String): ByteArray {
return File(path).readBytes()
}
package org.jetbrains.skia.tests
import org.jetbrains.skia.Data
import org.jetbrains.skia.Typeface
import org.jetbrains.skia.makeFromFile
import org.jetbrains.skia.makeFromFileName
import org.jetbrains.skiko.resourcePath
actual suspend fun Typeface.Companion.makeFromResource(resourceId: String, index: Int): Typeface =
makeFromFile(resourcePath(resourceId), index)
actual suspend fun Data.Companion.makeFromResource(resourceId: String) =
makeFromFileName(resourcePath(resourceId))
......@@ -3,24 +3,26 @@ package org.jetbrains.skiko
import org.jetbrains.skia.Data
import org.jetbrains.skia.FontStyle
import org.jetbrains.skia.Typeface
import org.jetbrains.skia.makeFromFileName
import org.jetbrains.skia.paragraph.TypefaceFontProvider
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import org.jetbrains.skia.tests.makeFromResource
import org.jetbrains.skiko.tests.runTest
class FontMgrTest {
@Test
fun fontMgrTest() {
fun fontMgrTest() = runTest {
val fontManager = TypefaceFontProvider()
val jbMono = Typeface.makeFromResource("JetBrainsMono-Regular.ttf")
val jbMono = Typeface.makeFromResource("./fonts/JetBrainsMono-Regular.ttf")
fontManager.registerTypeface(jbMono)
val jbMonoBold = Typeface.makeFromResource("JetBrainsMono-Bold.ttf")
val jbMonoBold = Typeface.makeFromResource("./fonts/JetBrainsMono-Bold.ttf")
fontManager.registerTypeface(jbMonoBold)
val inter: Typeface = Typeface.makeFromResource("InterHinted-Regular.ttf")
val inter: Typeface = Typeface.makeFromResource("./fonts/Inter-Hinted-Regular.ttf")
fontManager.registerTypeface(inter, "Interface")
assertEquals(2, fontManager.familiesCount)
......@@ -84,7 +86,7 @@ class FontMgrTest {
fontManager.matchFamilyStyleCharacter("JetBrains Mono", FontStyle.BOLD, arrayOf("en-US"), 65 /* A */)
)
Data.makeFromFileName("src/jvmTest/resources/fonts/JetBrainsMono-Italic.ttf").use { data ->
Data.makeFromFileName("src/commonTest/resources/fonts/JetBrainsMono-Italic.ttf").use { data ->
fontManager.makeFromData(data).use {
fontManager.matchFamily("JetBrains Mono").use { styleSet ->
assertEquals(2, fontManager.familiesCount)
......
......@@ -9,15 +9,22 @@ import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import org.jetbrains.skia.tests.makeFromResource
import org.jetbrains.skia.tests.assertCloseEnough
import org.jetbrains.skiko.tests.runTest
class TextLineTest {
private var inter36: Font = Font(Typeface.makeFromResource("InterHinted-Regular.ttf"), 36f)
private var firaCode36: Font = Font(Typeface.makeFromResource("FiraCode-Regular.ttf"), 36f)
private var jbMono36: Font = Font(Typeface.makeFromResource("JetBrainsMono-Regular.ttf"), 36f)
private val inter36: suspend () -> Font = suspend {
Font(Typeface.makeFromResource("./fonts/Inter-Hinted-Regular.ttf"), 36f)
}
private val firaCode36: suspend () -> Font = suspend {
Font(Typeface.makeFromResource("./fonts/FiraCode-Regular.ttf"), 36f)
}
private val jbMono36: suspend () -> Font = suspend {
Font(Typeface.makeFromResource("./fonts/JetBrainsMono-Regular.ttf"), 36f)
}
@Test
fun getOffsetAtCoordTest() {
TextLine.make("abc", inter36).use { line ->
fun getOffsetAtCoordTest() = runTest {
TextLine.make("abc", inter36()).use { line ->
assertContentEquals(shortArrayOf(503, 574, 581), line.glyphs)
assertEquals(0, line.getOffsetAtCoord(-10f)) // before “a”
assertEquals(0, line.getOffsetAtCoord(0f)) // beginning of “a”
......@@ -38,8 +45,8 @@ class TextLineTest {
}
@Test
fun getLeftOffsetAtCoordTest() {
TextLine.make("abc", inter36).use { line ->
fun getLeftOffsetAtCoordTest() = runTest {
TextLine.make("abc", inter36()).use { line ->
assertEquals(0, line.getLeftOffsetAtCoord(-10f)) // before “a”
assertEquals(0, line.getLeftOffsetAtCoord(0f)) // beginning of “a”
assertEquals(0, line.getLeftOffsetAtCoord(5f)) // left half of “a”
......@@ -59,8 +66,8 @@ class TextLineTest {
}
@Test
fun getCoordAtOffsetTest() {
TextLine.make("abc", inter36).use { line ->
fun getCoordAtOffsetTest() = runTest {
TextLine.make("abc", inter36()).use { line ->
assertCloseEnough(0f, line.getCoordAtOffset(0))
assertCloseEnough(20f, line.getCoordAtOffset(1))
assertCloseEnough(42f, line.getCoordAtOffset(2))
......@@ -69,8 +76,8 @@ class TextLineTest {
}
@Test
fun ligaturesTest() {
TextLine.make("<=>->", inter36).use { line ->
fun ligaturesTest() = runTest {
TextLine.make("<=>->", inter36()).use { line ->
assertContentEquals(shortArrayOf(1712, 1701), line.glyphs)
assertEquals(0, line.getOffsetAtCoord(0f))
......@@ -90,12 +97,12 @@ class TextLineTest {
}
@Test
fun combiningTest() {
fun combiningTest() = runTest {
// u U+0075 LATIN SMALL LETTER U
// ̈ U+0308 COMBINING DIAERESIS
// a U+0061 LATIN SMALL LETTER A
// ̧ U+0327 COMBINING CEDILLA
TextLine.make("üa̧", inter36).use { line ->
TextLine.make("üa̧", inter36()).use { line ->
assertContentEquals(shortArrayOf(898 /* ü */, 503 /* a */, 1664 /* ̧ */), line.glyphs)
assertEquals(0, line.getOffsetAtCoord(0f))
......@@ -113,8 +120,8 @@ class TextLineTest {
assertCloseEnough(41f, line.getCoordAtOffset(4))
}
TextLine.make("ă", jbMono36).use { line -> }
TextLine.make("aa̧", jbMono36).use { line ->
TextLine.make("ă", jbMono36()).use { line -> }
TextLine.make("aa̧", jbMono36()).use { line ->
// JetBrains Mono supports “a” but not “ ̧ ”
// Second grapheme cluster should fall back together, second “a” should resolve to different glyph
assertNotEquals(line.glyphs.get(0), line.glyphs.get(1))
......@@ -122,9 +129,9 @@ class TextLineTest {
}
@Test
fun emojiTest() {
TextLine.make("☺", firaCode36).use { misc ->
TextLine.make("☺️", firaCode36).use { emoji ->
fun emojiTest() = runTest {
TextLine.make("☺", firaCode36()).use { misc ->
TextLine.make("☺️", firaCode36()).use { emoji ->
assertContentEquals(shortArrayOf(1706), misc.glyphs)
assertEquals(1, emoji.glyphs.size)
assertNotEquals(misc.glyphs.get(0), emoji.glyphs.get(0))
......
package org.jetbrains.skiko
import org.jetbrains.skia.Data
import org.jetbrains.skia.FontFamilyName
import org.jetbrains.skia.FontStyle
import org.jetbrains.skia.FontVariation
import org.jetbrains.skia.FontVariationAxis
import org.jetbrains.skia.Typeface
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.jetbrains.skia.tests.makeFromResource
class TypefaceTest {
@Test
fun typefaceTest() {
val inter = Typeface.makeFromResource("InterHinted-Regular.ttf")
val interV = Typeface.makeFromResource("Inter-V.ttf")
val jbMono = Typeface.makeFromResource("JetBrainsMono-Regular.ttf")
val jbMonoBold = Typeface.makeFromData(Data.makeFromResource("JetBrainsMono-Bold.ttf"))
assertEquals(FontStyle.NORMAL, inter.fontStyle)
assertFalse(inter.isBold)
assertFalse(inter.isItalic)
assertEquals(FontStyle.BOLD, jbMonoBold.fontStyle)
assertTrue(jbMonoBold.isBold)
assertFalse(jbMonoBold.isItalic)
assertFalse(inter.isFixedPitch)
assertTrue(jbMono.isFixedPitch)
assertNull(inter.variationAxes)
assertNull(inter.variations)
val axes = arrayOf(
FontVariationAxis("wght", 100f, 400f, 900f),
FontVariationAxis("slnt", -10f, 0f, 0f)
)
assertContentEquals(axes, interV.variationAxes)
val inter500: Typeface = interV.makeClone(FontVariation("wght", 500f))
assertNotEquals(inter500, interV)
assertContentEquals(FontVariation.parse("wght=500 slnt=0"), inter500.variations)
val inter400: Typeface = interV.makeClone(FontVariation("wght", 400f))
assertNotEquals(inter.uniqueId, interV.uniqueId)
assertNotEquals(inter, interV)
assertNotNull(Typeface.makeDefault())
val Skia = intArrayOf(83, 107, 105, 97)
assertContentEquals(shortArrayOf(394, 713, 677, 503), inter.getUTF32Glyphs(Skia))
assertContentEquals(shortArrayOf(394, 713, 677, 503), inter.getStringGlyphs("Skia"))
assertEquals(394, inter.getUTF32Glyph(83))
assertEquals(2548, interV.glyphsCount)
assertEquals(17, inter.tablesCount)
assertContentEquals(
arrayOf(
"GDEF",
"GPOS",
"GSUB",
"OS/2",
"cmap",
"cvt ",
"fpgm",
"gasp",
"glyf",
"head",
"hhea",
"hmtx",
"loca",
"maxp",
"name",
"post",
"prep"
), inter.tableTags
)
assertTrue(inter.getTableData("loca")!!.size > 0)
assertEquals(2816, inter.unitsPerEm)
assertNull(jbMono.getKerningPairAdjustments(null))
assertNull(jbMono.getKerningPairAdjustments(jbMono.getStringGlyphs("TAV")))
assertContentEquals(arrayOf(FontFamilyName("Inter", "en-US")), interV.familyNames)
assertEquals("Inter", interV.familyName)
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@ import org.jetbrains.skia.Typeface
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.TypefaceFontProvider
import org.jetbrains.skia.tests.makeFromResource
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
......@@ -13,12 +14,12 @@ import kotlin.test.assertEquals
class FontCollectionTest {
@Test
fun fontCollectionTest() {
fun fontCollectionTest() = runTest {
val fm = TypefaceFontProvider()
val jbMono = Typeface.makeFromResource("JetBrainsMono-Regular.ttf", 0)
val jbMono = Typeface.makeFromResource("./fonts/JetBrainsMono-Regular.ttf", 0)
fm.registerTypeface(jbMono)
val inter = Typeface.makeFromResource("InterHinted-Regular.ttf", 0)
val inter = Typeface.makeFromResource("./fonts/Inter-Hinted-Regular.ttf", 0)
fm.registerTypeface(inter, "Interface")
// FontCollection
......
package org.jetbrains.skiko
import java.nio.file.Paths
private const val RESOURCES_PATH = "src/commonTest/resources"
actual fun resourcePath(resourceId: String) =
Paths.get("${RESOURCES_PATH}/$resourceId").normalize().toAbsolutePath().toString()
package org.jetbrains.skiko
import platform.posix.realpath
import platform.posix.PATH_MAX
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.toKString
import kotlinx.cinterop.usePinned
private const val RESOURCES_PATH = "src/commonTest/resources"
actual fun resourcePath(resourceId: String) = run {
val filePath = "$RESOURCES_PATH/$resourceId"
// Remove all '..' and '.'
var buffer = ByteArray(PATH_MAX)
val standardized = buffer.usePinned {
realpath(filePath, it.addressOf(0))?.toKString()
}
standardized ?: filePath
}
......@@ -60,7 +60,10 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeFromBytes
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeFromFileName
(KInteropPointer pathStr) {
TODO("implement org_jetbrains_skia_Data__1nMakeFromFileName");
SkString path = skString(pathStr);
sk_sp<SkData> instance = SkData::MakeFromFileName(path.c_str());
SkData* ptr = instance.release();
return reinterpret_cast<KNativePointer>(ptr);
}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Data__1nMakeSubset
......
......@@ -7,18 +7,11 @@
#include "common.h"
SKIKO_EXPORT KInt org_jetbrains_skia_Typeface__1nGetFontStyle
(KNativePointer ptr) {
TODO("implement org_jetbrains_skia_Typeface__1nGetFontStyle");
}
#if 0
SKIKO_EXPORT KInt org_jetbrains_skia_Typeface__1nGetFontStyle
(KNativePointer ptr) {
SkTypeface* instance = reinterpret_cast<SkTypeface*>((ptr));
return skija::FontStyle::toJava(instance->fontStyle());
return skija::FontStyle::toKotlin(instance->fontStyle());
}
#endif
SKIKO_EXPORT KBoolean org_jetbrains_skia_Typeface__1nIsFixedPitch
......@@ -139,18 +132,11 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Typeface__1nMakeFromName
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Typeface__1nMakeFromFile
(KInteropPointer pathStr, KInt index) {
TODO("implement org_jetbrains_skia_Typeface__1nMakeFromFile");
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Typeface__1nMakeFromFile
(KInteropPointer pathStr, KInt index) {
SkString path = skString(env, pathStr);
SkString path = skString(pathStr);
sk_sp<SkTypeface> instance = SkTypeface::MakeFromFile(path.c_str(), index);
SkTypeface* ptr = setDefaultVariationCoords(instance).release();
return reinterpret_cast<KNativePointer>(ptr);
}
#endif
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Typeface__1nMakeFromData
......
......@@ -13,13 +13,6 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_paragraph_TypefaceFontProvider__1
return reinterpret_cast<KNativePointer>(instance);
}
SKIKO_EXPORT void org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface
(KNativePointer ptr, KNativePointer typefacePtr, KInteropPointer aliasStr) {
TODO("implement org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface");
}
#if 0
SKIKO_EXPORT void org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterTypeface
(KNativePointer ptr, KNativePointer typefacePtr, KInteropPointer aliasStr) {
TypefaceFontProvider* instance = reinterpret_cast<TypefaceFontProvider*>((ptr));
......@@ -27,7 +20,6 @@ SKIKO_EXPORT void org_jetbrains_skia_paragraph_TypefaceFontProvider__1nRegisterT
if (aliasStr == nullptr)
instance->registerTypeface(sk_ref_sp(typeface));
else
instance->registerTypeface(sk_ref_sp(typeface), skString(env, aliasStr));
instance->registerTypeface(sk_ref_sp(typeface), skString(aliasStr));
}
#endif
package org.jetbrains.skia
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.interopScope
/**
* Create a new dataref the file with the specified path.
* If the file cannot be opened, this returns null.
*/
fun Data.Companion.makeFromFileName(path: String?): Data {
Stats.onNativeCall()
interopScope {
return Data(_nMakeFromFileName(toInterop(path)))
}
}
\ No newline at end of file
package org.jetbrains.skia
import org.jetbrains.skia.impl.Native
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.interopScope
/**
* @return a new typeface given a file
* @throws IllegalArgumentException If the file does not exist, or is not a valid font file
*/
fun Typeface.Companion.makeFromFile(path: String, index: Int = 0): Typeface {
Stats.onNativeCall()
interopScope {
val ptr = _nMakeFromFile(toInterop(path), index)
require(ptr != Native.NullPointer) { "Failed to create Typeface from path=\"$path\" index=$index" }
return Typeface(ptr)
}
}
\ No newline at end of file
......@@ -6,7 +6,7 @@ actual abstract class RefCnt : Managed {
protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR, true) {}
protected actual constructor(ptr: NativePointer, allowClose: Boolean) : super(ptr, _FinalizerHolder.PTR, allowClose)
val refCount: Int
actual val refCount: Int
get() = try {
Stats.onNativeCall()
_nGetRefCount(_ptr)
......
package org.jetbrains.skiko
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.toKString
import kotlinx.cinterop.usePinned
import platform.posix.*
actual suspend fun loadBytesFromPath(path: String): ByteArray {
val file = fopen(path, "r") ?: run {
val error = strerror(errno)?.toKString() ?: "Unknown error"
throw Error("Can not open file '$path': $error")
}
val size = file.let {
fseek(it, 0, SEEK_END)
val size = ftell(it)
fseek(it, 0, SEEK_SET)
size
}
if (size < 0) {
fclose(file)
throw Error("Can not read file '$path'")
}
if (size > Int.MAX_VALUE.toLong()) {
fclose(file)
throw Error("File '$path' is too long")
}
if (size == 0L) {
fclose(file)
return byteArrayOf()
}
val bytes = ByteArray(size.toInt())
val result = bytes.usePinned {
fread(it.addressOf(0), 1, size.toULong(), file)
}
fclose(file)
if (result != size.toULong()) {
throw Error("Can not read file '$path'")
}
return bytes
}
package org.jetbrains.skia.tests
import org.jetbrains.skia.Data
import org.jetbrains.skia.Typeface
import org.jetbrains.skia.makeFromFile
import org.jetbrains.skia.makeFromFileName
import org.jetbrains.skiko.resourcePath
actual suspend fun Typeface.Companion.makeFromResource(resourceId: String, index: Int): Typeface =
makeFromFile(resourcePath(resourceId), index)
actual suspend fun Data.Companion.makeFromResource(resourceId: String) =
makeFromFileName(resourcePath(resourceId))
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