Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] MinGW x64 port #574

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
mingw64 skiko implementation (WGL)
viniciuslrangel committed Aug 21, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 0e38030cd5e07effc9a96ca4d3e5c9572c771332
54 changes: 54 additions & 0 deletions skiko/src/mingwMain/kotlin/org/jetbrains/skia/Actuals.native.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.jetbrains.skia

import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.CPointer
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.withResult

actual abstract class OutputStream

internal actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
block()
}

internal actual fun String.intCodePoints(): IntArray = IntArray(this.length) { this[it].code }

actual class Pattern constructor(regex: String) {
private val _regex = Regex(regex)

actual fun split(input: CharSequence): Array<String> = _regex.split(input).toTypedArray()
actual fun matcher(input: CharSequence): Matcher = Matcher(_regex, input)
}

actual class Matcher constructor(private val regex: Regex, private val input: CharSequence) {

private val matches: Boolean by lazy {
regex.matches(input)
}

private val groups: MatchGroupCollection? by lazy { regex.matchEntire(input)?.groups }

actual fun group(ix: Int): String? = groups?.get(ix)?.value
actual fun matches(): Boolean = matches
}

private val LANG by lazy {
val localeFromICU = uloc_getDefault()
var length = 0
val maxLength = 128
val langTag = withResult(ByteArray(maxLength)) {
length = uloc_toLanguageTag(localeFromICU, it, maxLength, false, toInterop(intArrayOf(0)))
}.decodeToString(0, length)
langTag.ifEmpty { "en-US" }
}

internal actual fun defaultLanguageTag(): String = LANG

internal actual fun compilePattern(regex: String): Pattern = Pattern(regex)

actual typealias ExternalSymbolName = kotlin.native.SymbolName

@SymbolName("uloc_getDefault")
private external fun uloc_getDefault(): CPointer<ByteVar>
@SymbolName("uloc_toLanguageTag")
private external fun uloc_toLanguageTag(localeId: CPointer<ByteVar>, buffer: InteropPointer, size: Int, strict: Boolean, err: InteropPointer): Int
15 changes: 15 additions & 0 deletions skiko/src/mingwMain/kotlin/org/jetbrains/skia/Data.native.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
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)))
}
}
18 changes: 18 additions & 0 deletions skiko/src/mingwMain/kotlin/org/jetbrains/skia/Typeface.native.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.jetbrains.skia.impl

actual class Library {
actual companion object {
actual fun staticLoad() {
// Not much here for now.
// We link statically for native.
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.jetbrains.skia.impl

import kotlinx.cinterop.nativeNullPtr
import org.jetbrains.skia.ExternalSymbolName
import kotlin.native.concurrent.AtomicNativePtr
import kotlin.native.concurrent.freeze
import kotlin.native.internal.createCleaner

private class FinalizationThunk(private val finalizer: NativePointer, val className: String, obj: NativePointer) {
private var obj = AtomicNativePtr(obj)

fun clean() {
val ptr = obj.value
if (ptr != nativeNullPtr && obj.compareAndSet(ptr, nativeNullPtr)) {
Stats.onDeallocated(className)
Stats.onNativeCall()
_nInvokeFinalizer(finalizer, ptr)
}
}
val isActive get() =
obj.value != nativeNullPtr
}

actual abstract class Managed actual constructor(
ptr: NativePointer, finalizer: NativePointer, managed: Boolean) : Native(ptr) {

private val thunk: FinalizationThunk? = if (managed) {
require(ptr != NullPointer) { "Managed ptr is nullptr" }
require(finalizer != NullPointer) { "Managed finalizer is nullptr" }
val className = this::class.simpleName ?: "<kotlin>"
Stats.onAllocated(className)
FinalizationThunk(finalizer, className, ptr).freeze()
} else null

@OptIn(ExperimentalStdlibApi::class)
private val cleaner = if (managed) {
createCleaner(thunk) {
it?.clean()
}
} else null

actual open fun close() {
require(_ptr != NullPointer) {
"Object already closed: ${this::class.simpleName}, _ptr=$_ptr"
}
requireNotNull(thunk) {
"Object is not managed in K/N runtime, can't close(): ${this::class.simpleName}, _ptr=$_ptr"
}
require(thunk.isActive) {
"Object is closed already, can't close(): ${this::class.simpleName}, _ptr=$_ptr"
}

thunk.clean()
_ptr = NullPointer
}

actual open val isClosed: Boolean
get() = _ptr == NullPointer
}

@ExternalSymbolName("org_jetbrains_skia_impl_Managed__invokeFinalizer")
internal external fun _nInvokeFinalizer(finalizer: NativePointer, ptr: NativePointer)
Loading