Unverified Commit d389d095 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

First step in Android support. (#425)

So far we cannot really build Skiko for Android (as no Android-specific code for rendering integration is made), however it refactor the build system to make this (along with other alternative JVM-based implementations) feasible.
parent 56d6fa7f
......@@ -264,5 +264,6 @@ afterEvaluate {
extensions.configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> {
versions.webpackDevServer.version = "4.0.0"
versions.webpackCli.version = "4.9.0"
nodeVersion = "16.0.0"
}
}
......@@ -2,12 +2,8 @@ package org.jetbrains.skiko.sample
import platform.AppKit.*
import org.jetbrains.skia.*
import org.jetbrains.skiko.*
import kotlinx.cinterop.*
import platform.Foundation.NSMakeRect
import platform.Foundation.NSBundle
import platform.Foundation.NSNotification
import platform.Foundation.NSSelectorFromString
import platform.darwin.NSObject
......
......@@ -199,8 +199,6 @@ fun compileNativeBridgesTask(os: OS, arch: Arch): TaskProvider<CompileSkikoCppTa
}
}
val skiaBinSubdir = "out/${buildType.id}-${targetOs.id}-${targetArch.id}"
internal val Project.isInIdea: Boolean
get() {
return System.getProperty("idea.active")?.toBoolean() == true
......@@ -212,6 +210,9 @@ val Project.supportNative: Boolean
val Project.supportWasm: Boolean
get() = findProperty("skiko.wasm.enabled") == "true" || isInIdea
val Project.supportAndroid: Boolean
get() = findProperty("skiko.android.enabled") == "true"
kotlin {
jvm {
compilations.all {
......@@ -254,9 +255,17 @@ kotlin {
implementation(kotlin("test-annotations-common"))
}
}
/*
val androidMain by getting {
dependencies {
compileOnly(files(androidJar()))
}
} */
val jvmMain by getting {
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("stdlib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")
}
......@@ -265,7 +274,6 @@ kotlin {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
implementation(kotlin("test-junit"))
implementation(kotlin("test"))
}
}
......@@ -287,7 +295,7 @@ kotlin {
val jsTest by getting {
dependsOn(nativeJsTest)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation(kotlin("test-js"))
}
}
......@@ -298,7 +306,7 @@ kotlin {
val nativeMain by creating {
dependsOn(nativeJsMain)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
}
}
val nativeTest by creating {
......@@ -521,8 +529,62 @@ fun skiaStaticLibraries(skiaDir: String, targetString: String): List<String> {
}
val skiaJvmBindingsDir: Provider<File> = registerOrGetSkiaDirProvider(targetOs, targetArch)
val compileJvmBindings = createCompileJvmBindingsTask(targetOs, targetArch, skiaJvmBindingsDir)
val linkJvmBindings = createLinkJvmBindings(targetOs, targetArch, skiaJvmBindingsDir, compileJvmBindings)
val maybeSign = maybeSignTask(targetOs, targetArch, linkJvmBindings)
val createChecksums = createChecksumsTask(targetOs, targetArch, maybeSign, skiaJvmBindingsDir)
val skikoJvmRuntimeJar = skikoJvmRuntimeJarTask(targetOs, targetArch, maybeSign, createChecksums, skiaJvmBindingsDir)
val skikoRuntimeDirForTests = skikoRuntimeDirForTestsTask(targetOs, targetArch, skikoJvmRuntimeJar)
val allJvmRuntimeJars = mutableMapOf((targetOs to targetArch) to skikoJvmRuntimeJar)
if (supportAndroid) {
val os = OS.Android
for (arch in arrayOf(Arch.X64, Arch.Arm64)) {
val skiaAndroidBindingsDir = registerOrGetSkiaDirProvider(os, arch)
val compileAndroidBindings = createCompileJvmBindingsTask(os, arch, skiaAndroidBindingsDir)
val linkAndroidBindings =
createLinkJvmBindings(OS.Android, arch, skiaAndroidBindingsDir, compileAndroidBindings)
val maybeSignAndroid = maybeSignTask(os, arch, linkAndroidBindings)
val createChecksumsAndroid = createChecksumsTask(os, arch, maybeSignAndroid, skiaAndroidBindingsDir)
val skikoJvmRuntimeJarAndroid = skikoJvmRuntimeJarTask(os, arch, maybeSignAndroid, createChecksumsAndroid, skiaAndroidBindingsDir)
allJvmRuntimeJars[os to arch] = skikoJvmRuntimeJarAndroid
}
}
val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings") {
fun androidHome() = when (hostOs) {
OS.MacOS -> File("${System.getProperty("user.home")}/Library/Android/sdk")
OS.Linux -> File("${System.getProperty("user.home")}/.android")
else -> throw GradleException("unsupported $hostOs")
}
fun androidClangFor(targetArch: Arch, version: String = "30"): String {
val androidHome = androidHome()
val ndkVersion =
arrayOf("ndk/23.0.7599858", "ndk-bundle").find {
androidHome.resolve(it).exists()
}!!
val androidArch = when (targetArch) {
Arch.Arm64 -> "aarch64"
Arch.X64 -> "x86_64"
else -> throw GradleException("unsupported $targetArch")
}
val hostOsArch = when (hostOs) {
OS.MacOS -> "darwin-x86_64"
OS.Linux -> "linux-x86_64"
else -> throw GradleException("unsupported $hostOs")
}
val ndkDir = File(androidHome, "/$ndkVersion/toolchains/llvm/prebuilt/$hostOsArch")
return ndkDir.resolve("bin/$androidArch-linux-android$version-clang++").absolutePath
}
fun androidJar(version: String = "30"): String {
val androidHome = androidHome()
return androidHome.resolve("platforms/android-$version/android.jar").absolutePath
}
fun createCompileJvmBindingsTask(targetOs: OS, targetArch: Arch, skiaJvmBindingsDir: Provider<File>) =
tasks.register<CompileSkikoCppTask>("compileJvmBindings-${targetOs.id}-${targetArch.id}") {
// Prefer 'java.home' system property to simplify overriding from Intellij.
// When used from command-line, it is effectively equal to JAVA_HOME.
if (JavaVersion.current() < JavaVersion.VERSION_11) {
......@@ -542,8 +604,7 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
"src/jvmTest/cpp"
)
sourceRoots.set(srcDirs)
includeHeadersNonRecursive(jdkHome.resolve("include"))
if (targetOs != OS.Android) includeHeadersNonRecursive(jdkHome.resolve("include"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaJvmBindingsDir.get()))
includeHeadersNonRecursive(projectDir.resolve("src/jvmMain/cpp/include"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include"))
......@@ -601,6 +662,17 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
// "-DSK_ANGLE",
)
}
OS.Android -> {
compiler.set(androidClangFor(targetArch))
osFlags = arrayOf(
*buildType.clangFlags,
"-fno-rtti",
"-fno-exceptions",
"-fvisibility=hidden",
"-fPIC",
"-DSK_BUILD_FOR_ANDROID"
)
}
OS.Wasm, OS.IOS -> error("Should not reach here")
}
......@@ -612,97 +684,109 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
)
}
val linkJvmBindings = tasks.register<LinkSkikoTask>("linkJvmBindings") {
val skiaBinDir = skiaJvmBindingsDir.get().absolutePath + "/" + skiaBinSubdir
val osFlags: Array<String>
fun createLinkJvmBindings(targetOs: OS, targetArch: Arch,
skiaJvmBindingsDir: Provider<File>,
compileTask: TaskProvider<CompileSkikoCppTask>) =
tasks.register<LinkSkikoTask>("linkJvmBindings-${targetOs.id}-${targetArch.id}") {
val target = targetId(targetOs, targetArch)
val skiaBinSubdir = "out/${buildType.id}-$target"
val skiaBinDir = skiaJvmBindingsDir.get().absolutePath + "/" + skiaBinSubdir
val osFlags: Array<String>
libFiles = fileTree(skiaJvmBindingsDir.map { it.resolve(skiaBinSubdir)}) {
include(if (targetOs.isWindows) "*.lib" else "*.a")
}
libFiles = fileTree(skiaJvmBindingsDir.map { it.resolve(skiaBinSubdir)}) {
include(if (targetOs.isWindows) "*.lib" else "*.a")
}
dependsOn(compileTask)
objectFiles = fileTree(compileTask.map { it.outDir.get() }) {
include("**/*.o")
}
dependsOn(compileJvmBindings)
objectFiles = fileTree(compileJvmBindings.map { it.outDir.get() }) {
include("**/*.o")
}
val libNamePrefix = if (targetOs.isWindows) "skiko" else "libskiko"
libOutputFileName.set("$libNamePrefix-${targetOs.id}-${targetArch.id}${targetOs.dynamicLibExt}")
buildTargetOS.set(targetOs)
buildTargetArch.set(targetArch)
buildVariant.set(buildType)
linker.set(linkerForTarget(targetOs, targetArch))
val libNamePrefix = if (targetOs.isWindows) "skiko" else "libskiko"
libOutputFileName.set("$libNamePrefix-${targetOs.id}-${targetArch.id}${targetOs.dynamicLibExt}")
buildTargetOS.set(targetOs)
buildTargetArch.set(targetArch)
buildVariant.set(buildType)
linker.set(linkerForTarget(targetOs, targetArch))
when (targetOs) {
OS.MacOS -> {
dependsOn("objcCompile")
objectFiles += fileTree("$buildDir/objc/$target") {
include("**/*.o")
}
when (targetOs) {
OS.MacOS -> {
dependsOn("objcCompile")
objectFiles += fileTree("$buildDir/objc/$target") {
include("**/*.o")
osFlags = arrayOf(
*targetOs.clangFlags,
"-shared",
"-dead_strip",
"-lobjc",
"-framework", "AppKit",
"-framework", "CoreFoundation",
"-framework", "CoreGraphics",
"-framework", "CoreServices",
"-framework", "CoreText",
"-framework", "Foundation",
"-framework", "IOKit",
"-framework", "Metal",
"-framework", "OpenGL",
"-framework", "QuartzCore" // for CoreAnimation
)
}
OS.Linux -> {
osFlags = arrayOf(
"-shared",
"-static-libstdc++",
"-static-libgcc",
"-lGL",
"-lfontconfig",
// A fix for https://github.com/JetBrains/compose-jb/issues/413.
// Dynamic position independent linking uses PLT thunks relying on jump targets in GOT (Global Offsets Table).
// GOT entries marked as (for example) R_X86_64_JUMP_SLOT in the relocation table. So, if there's code loading
// platform libstdc++.so, lazy resolve code will resolve GOT entries to platform libstdc++.so on first invocation,
// and so further execution will break, as those two libstdc++ are not compatible.
// To fix it we enforce resolve of all GOT entries at library load time, and make it read-only afterwards.
"-Wl,-z,relro,-z,now",
// Hack to fix problem with linker not always finding certain declarations.
"$skiaBinDir/libsksg.a",
"$skiaBinDir/libskia.a",
"$skiaBinDir/libskunicode.a"
)
}
OS.Windows -> {
linker.set(windowsSdkPaths.linker.absolutePath)
libDirs.set(windowsSdkPaths.libDirs)
osFlags = arrayOf(
*buildType.msvcLinkerFlags,
"/NOLOGO",
"/DLL",
"Advapi32.lib",
"gdi32.lib",
"Dwmapi.lib",
"opengl32.lib",
"shcore.lib",
"user32.lib",
)
}
OS.Android -> {
osFlags = arrayOf(
"-shared"
)
linker.set(androidClangFor(targetArch))
}
OS.Wasm, OS.IOS -> {
throw GradleException("This task shalln't be used with $targetOs")
}
osFlags = arrayOf(
*targetOs.clangFlags,
"-shared",
"-dead_strip",
"-lobjc",
"-framework", "AppKit",
"-framework", "CoreFoundation",
"-framework", "CoreGraphics",
"-framework", "CoreServices",
"-framework", "CoreText",
"-framework", "Foundation",
"-framework", "IOKit",
"-framework", "Metal",
"-framework", "OpenGL",
"-framework", "QuartzCore" // for CoreAnimation
)
}
OS.Linux -> {
osFlags = arrayOf(
"-shared",
"-static-libstdc++",
"-static-libgcc",
"-lGL",
"-lfontconfig",
// A fix for https://github.com/JetBrains/compose-jb/issues/413.
// Dynamic position independent linking uses PLT thunks relying on jump targets in GOT (Global Offsets Table).
// GOT entries marked as (for example) R_X86_64_JUMP_SLOT in the relocation table. So, if there's code loading
// platform libstdc++.so, lazy resolve code will resolve GOT entries to platform libstdc++.so on first invocation,
// and so further execution will break, as those two libstdc++ are not compatible.
// To fix it we enforce resolve of all GOT entries at library load time, and make it read-only afterwards.
"-Wl,-z,relro,-z,now",
// Hack to fix problem with linker not always finding certain declarations.
"$skiaBinDir/libsksg.a",
"$skiaBinDir/libskia.a",
"$skiaBinDir/libskunicode.a"
)
}
OS.Windows -> {
linker.set(windowsSdkPaths.linker.absolutePath)
libDirs.set(windowsSdkPaths.libDirs)
osFlags = arrayOf(
*buildType.msvcLinkerFlags,
"/NOLOGO",
"/DLL",
"Advapi32.lib",
"gdi32.lib",
"Dwmapi.lib",
"opengl32.lib",
"shcore.lib",
"user32.lib",
)
}
OS.Wasm, OS.IOS -> {
throw GradleException("This task shalln't be used with WASM")
}
flags.set(listOf(*osFlags))
}
flags.set(listOf(*osFlags))
}
if (hostOs == OS.MacOS) {
// Very hacky way to compile Objective-C sources and add the
// resulting object files into the final library.
// TODO: rewrite using SkikoCompileTask
project.tasks.register<Exec>("objcCompile") {
val target = targetId(targetOs, targetArch)
val inputDir = "$projectDir/src/jvmMain/objectiveC/${targetOs.id}"
val outDir = "$buildDir/objc/$target"
val names = File(inputDir).listFiles()!!.map { it.name.removeSuffix(".mm") }
......@@ -732,7 +816,9 @@ if (hostOs == OS.MacOS) {
}
}
val generateVersion = project.tasks.register("generateVersion") {
val generateVersion = generateVersionTask(targetOs, targetArch)
fun generateVersionTask(targetOs: OS, targetArch: Arch) = project.tasks.register("generateVersion") {
val outDir = generatedKotlin
file(outDir).mkdirs()
val out = "$outDir/Version.kt"
......@@ -750,12 +836,13 @@ val generateVersion = project.tasks.register("generateVersion") {
}
}
val skikoJvmJar: Provider<Jar> by tasks.registering(Jar::class) {
val skikoJvmJar by project.tasks.registering(Jar::class) {
archiveBaseName.set("skiko-jvm")
from(kotlin.jvm().compilations["main"].output.allOutputs)
from(kotlin.jvm().compilations["main"].output.allOutputs)
}
val maybeSign by project.tasks.registering(SealAndSignSharedLibraryTask::class) {
fun maybeSignTask(targetOs: OS, targetArch: Arch, linkJvmBindings: Provider<LinkSkikoTask>) =
project.tasks.register<SealAndSignSharedLibraryTask>("maybeSign-${targetOs.id}-${targetArch.id}") {
dependsOn(linkJvmBindings)
val linkOutputFile = linkJvmBindings.map { task ->
......@@ -783,26 +870,40 @@ val maybeSign by project.tasks.registering(SealAndSignSharedLibraryTask::class)
signToken.set(skiko.signToken)
}
val createChecksums by project.tasks.registering(org.gradle.crypto.checksum.Checksum::class) {
dependsOn(maybeSign)
files = project.files(maybeSign.flatMap { it.outputFiles }) +
if (targetOs.isWindows) files(skiaJvmBindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }) else files()
algorithm = Checksum.Algorithm.SHA256
outputDir = file("$buildDir/checksums")
}
val skikoJvmRuntimeJar by project.tasks.registering(Jar::class) {
dependsOn(createChecksums)
archiveBaseName.set("skiko-$target")
from(skikoJvmJar.map { zipTree(it.archiveFile) })
from(maybeSign.flatMap { it.outputFiles })
if (targetOs.isWindows) {
from(files(skiaJvmBindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }))
fun createChecksumsTask(targetOs: OS, targetArch: Arch,
maybeSign: Provider<SealAndSignSharedLibraryTask>,
bindingsDir: Provider<File>) =
project.tasks.register<Checksum>("createChecksums-${targetOs.id}-${targetArch.id}") {
val skiaBinSubdir = "out/${buildType.id}-${targetOs.id}-${targetArch.id}"
dependsOn(maybeSign)
files = project.files(maybeSign.flatMap { it.outputFiles }) +
if (targetOs.isWindows) files(bindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }) else files()
algorithm = Checksum.Algorithm.SHA256
outputDir = file("$buildDir/checksums")
}
from(createChecksums.map { it.outputs.files })
fun skikoJvmRuntimeJarTask(targetOs: OS, targetArch: Arch,
maybeSign: Provider<SealAndSignSharedLibraryTask>,
createChecksums: Provider<Checksum>,
bindingsDir: Provider<File>) =
project.tasks.register<Jar>("skikoJvmRuntimeJar-${targetOs.id}-${targetArch.id}") {
dependsOn(maybeSign)
dependsOn(createChecksums)
dependsOn(skikoJvmJar)
val target = targetId(targetOs, targetArch)
val skiaBinSubdir = "out/${buildType.id}-$target"
archiveBaseName.set("skiko-$target")
from(skikoJvmJar.map { zipTree(it.archiveFile) })
from(maybeSign.flatMap { it.outputFiles })
if (targetOs.isWindows) {
from(files(bindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }))
}
from(createChecksums.map { it.outputs.files })
}
val skikoRuntimeDirForTests by project.tasks.registering(Copy::class) {
fun skikoRuntimeDirForTestsTask(targetOs: OS, targetArch: Arch,
skikoJvmRuntimeJar: Provider<Jar>) =
project.tasks.register<Copy>("skikoRuntimeDirForTests-${targetOs.id}-${targetArch.id}") {
dependsOn(skikoJvmRuntimeJar)
from(zipTree(skikoJvmRuntimeJar.flatMap { it.archiveFile })) {
include("*.so")
......@@ -812,6 +913,7 @@ val skikoRuntimeDirForTests by project.tasks.registering(Copy::class) {
}
destinationDir = project.buildDir.resolve("skiko-runtime-for-tests")
}
tasks.withType<Test>().configureEach {
dependsOn(skikoRuntimeDirForTests)
dependsOn(skikoJvmRuntimeJar)
......@@ -926,19 +1028,23 @@ publishing {
}
}
create<MavenPublication>("skikoJvmRuntime") {
pomNameForPublication[name] = "Skiko JVM Runtime for ${targetOs.name} ${targetArch.name}"
artifactId = SkikoArtifacts.jvmRuntimeArtifactIdFor(targetOs, targetArch)
afterEvaluate {
artifact(skikoJvmRuntimeJar.map { it.archiveFile.get() })
var jvmSourcesArtifact: Any? = null
kotlin.jvm().mavenPublication {
jvmSourcesArtifact = artifacts.find { it.classifier == "sources" }
}
if (jvmSourcesArtifact == null) {
error("Could not find sources jar artifact for JVM target")
} else {
artifact(jvmSourcesArtifact)
allJvmRuntimeJars.forEach { entry ->
val os = entry.key.first
val arch = entry.key.second
create<MavenPublication>("skikoJvmRuntime${targetId(os, arch)}") {
pomNameForPublication[name] = "Skiko JVM Runtime for ${os.name} ${arch.name}"
artifactId = SkikoArtifacts.jvmRuntimeArtifactIdFor(os, arch)
afterEvaluate {
artifact(entry.value.map { it.archiveFile.get() })
var jvmSourcesArtifact: Any? = null
kotlin.jvm().mavenPublication {
jvmSourcesArtifact = artifacts.find { it.classifier == "sources" }
}
if (jvmSourcesArtifact == null) {
error("Could not find sources jar artifact for JVM target")
} else {
artifact(jvmSourcesArtifact)
}
}
}
}
......
......@@ -6,6 +6,7 @@ enum class OS(
val clangFlags: Array<String>
) {
Linux("linux", arrayOf()),
Android("android", arrayOf()),
Windows("windows", arrayOf()),
MacOS("macos", arrayOf("-mmacosx-version-min=10.13")),
Wasm("wasm", arrayOf()),
......@@ -22,6 +23,7 @@ val OS.isCompatibleWithHost: Boolean
OS.Windows -> hostOs == OS.Windows
OS.MacOS, OS.IOS -> hostOs == OS.MacOS
OS.Wasm -> true
OS.Android -> true
}
fun compilerForTarget(os: OS, arch: Arch): String =
......@@ -31,6 +33,7 @@ fun compilerForTarget(os: OS, arch: Arch): String =
Arch.Arm64 -> "clang++"
Arch.Wasm -> "Unexpected combination: $os & $arch"
}
OS.Android -> "clang++"
OS.Windows -> "cl.exe"
OS.MacOS, OS.IOS -> "clang++"
OS.Wasm -> "emcc"
......@@ -41,7 +44,7 @@ fun linkerForTarget(os: OS, arch: Arch): String =
val OS.dynamicLibExt: String
get() = when (this) {
OS.Linux -> ".so"
OS.Linux, OS.Android -> ".so"
OS.Windows -> ".dll"
OS.MacOS, OS.IOS -> ".dylib"
OS.Wasm -> ".wasm"
......@@ -115,8 +118,6 @@ fun findTargetArch() = when (System.getProperty("skiko.target.os.arch")) {
val targetOs = findTargetOs() ?: hostOs
val targetArch = findTargetArch() ?: hostArch
val target = targetId(targetOs, targetArch)
fun targetId(os: OS, arch: Arch) =
"${os.id}-${arch.id}"
......
......@@ -11,5 +11,7 @@ dependencies.skia.macos-arm64=m97-0b898c4b8e
dependencies.skia.wasm-wasm=m97-0b898c4b8e
dependencies.skia.ios-x64=m97-0b898c4b8e
dependencies.skia.ios-arm64=m97-0b898c4b8e
dependencies.skia.android-x64=m97-0b898c4b8e
dependencies.skia.android-arm64=m97-0b898c4b8e
org.gradle.jvmargs=-Xmx3G
package org.jetbrains.skiko
enum class OS(val id: String) {
Android("android"),
Linux("linux"),
Windows("windows"),
MacOS("macos"),
......
......@@ -5,12 +5,11 @@
class SkijaDrawableImpl: public SkDrawable {
public:
SkijaDrawableImpl() {
}
SkijaDrawableImpl() {}
~SkijaDrawableImpl() {
JNIEnv* env;
if (fJavaVM->GetEnv(AS_JNI_ENV_PTR(&env), SKIKO_JNI_VERSION) == JNI_OK)
if (fJavaVM->GetEnv(reinterpret_cast<void**>(&env), SKIKO_JNI_VERSION) == JNI_OK)
env->DeleteGlobalRef(fObject);
}
......
......@@ -440,7 +440,7 @@ public:
~JCallback() {
if (callback != nullptr) {
JNIEnv* localEnv;
if (javaVM->GetEnv(AS_JNI_ENV_PTR(&localEnv), SKIKO_JNI_VERSION) == JNI_OK) {
if (javaVM->GetEnv(reinterpret_cast<void**>(&localEnv), SKIKO_JNI_VERSION) == JNI_OK) {
localEnv->DeleteGlobalRef(callback);
}
}
......
......@@ -8,7 +8,7 @@ actual class Library {
var loaded = AtomicBoolean(false)
@JvmStatic
actual fun staticLoad() {
if (!loaded.compareAndExchange(false, true)) {
if (loaded.compareAndSet(false, true)) {
Library.load()
}
}
......
......@@ -53,7 +53,7 @@ object Library {
// localization resource on platforms where it is needed.
@Synchronized
fun load() {
if (loaded.compareAndExchange(false, true)) return
if (!loaded.compareAndSet(false, true)) return
// Find/unpack a usable copy of the native library.
findAndLoad()
......
......@@ -4,8 +4,9 @@ actual val hostOs: OS by lazy {
val osName = System.getProperty("os.name")
when {
osName == "Mac OS X" -> OS.MacOS
osName == "Linux" -> OS.Linux
osName.startsWith("Win") -> OS.Windows
"The Android Project" == System.getProperty("java.specification.vendor") -> OS.Android
osName == "Linux" -> OS.Linux
else -> throw Error("Unknown OS $osName")
}
}
......
......@@ -119,6 +119,7 @@ internal val platformOperations: PlatformOperations by lazy {
}
}
}
OS.Android -> TODO()
OS.JS, OS.Ios -> {
TODO("Commonize me")
}
......
......@@ -32,6 +32,7 @@ private fun makeDefaultRenderFactory(): RenderFactory {
GraphicsApi.SOFTWARE_FAST -> LinuxSoftwareRedrawer(layer, properties)
else -> LinuxOpenGLRedrawer(layer, properties)
}
OS.Android -> TODO()
OS.JS, OS.Ios -> {
TODO("Commonize me")
}
......
......@@ -19,8 +19,8 @@ internal fun makeMetalContext() = DirectContext(
makeMetalContextNative().also { if (it == 0L) TODO("not yet supported") }
)
external private fun makeGLRenderTargetNative(width: Int, height: Int, sampleCnt: Int, stencilBits: Int, fbId: Int, fbFormat: Int): Long
external private fun makeGLContextNative(): Long
private external fun makeGLRenderTargetNative(width: Int, height: Int, sampleCnt: Int, stencilBits: Int, fbId: Int, fbFormat: Int): Long
private external fun makeGLContextNative(): Long
external private fun makeMetalRenderTargetNative(width: Int, height: Int, sampleCnt: Int): Long
external private fun makeMetalContextNative(): Long
private external fun makeMetalRenderTargetNative(width: Int, height: Int, sampleCnt: Int): Long
private external fun makeMetalContextNative(): Long
......@@ -56,6 +56,7 @@ internal object SkikoProperties {
OS.MacOS -> return GraphicsApi.METAL
OS.Linux -> return GraphicsApi.OPENGL
OS.Windows -> return GraphicsApi.DIRECT3D
OS.Android -> return GraphicsApi.OPENGL
OS.JS, OS.Ios -> TODO("commonize me")
}
}
......@@ -65,6 +66,7 @@ internal object SkikoProperties {
OS.Linux -> listOf(GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
OS.MacOS -> listOf(GraphicsApi.METAL, GraphicsApi.SOFTWARE_COMPAT)
OS.Windows -> listOf(GraphicsApi.DIRECT3D, GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
OS.Android -> return listOf(GraphicsApi.OPENGL)
OS.JS, OS.Ios -> TODO("commonize me")
}
......
......@@ -10,7 +10,7 @@ import java.lang.ref.Reference
internal class DirectSoftwareContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
var isInited = false
val softwareRedrawer: AbstractDirectSoftwareRedrawer
private val softwareRedrawer: AbstractDirectSoftwareRedrawer
get() = layer.redrawer!! as AbstractDirectSoftwareRedrawer
private var currentWidth = 0
......
......@@ -3,7 +3,6 @@ package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.*
import org.jetbrains.skiko.context.Direct3DContextHandler
import org.jetbrains.skiko.context.OpenGLContextHandler
internal class LinuxOpenGLRedrawer(
......
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