Garbage collection capable wrappers for skia interop

This commit is contained in:
Alexander Gorshenev
2021-05-06 19:11:05 +03:00
parent d9483ccb08
commit 9148094bbd
30 changed files with 1114 additions and 121 deletions
+28
View File
@@ -1,3 +1,4 @@
Skia interop support
====================
@@ -15,6 +16,33 @@ plugin = org.jetbrains.kotlin.native.cinterop.plugin.skia
language = C++
```
Interop
-------
There are two kinds of C++ classes used in Skia.
The ones with ref()/unref() reference counting are abstracted with SkiaRefCnt interface.
The ones without are abstracted with CPlusPlusClass interface.
So, for example, for SkPaint one has
class SkPaint(rawPtr) : CStructVar(rawPtr), CPlusPlusClass {
// A C interop-like function having methods,
// as well as low level __init__ and __destroy__
}
class Paint(cpp: SkPaint, managed: Boolean) : ManagedType(cpp) {
// A wrapper capable of garbage collection delegating all calls and fields to SkPaint
}
* pointer returned from C++ -> Wrapper(cpp, managed = false)
* sk_sp returned from C++ -> calls .release() ; Wrapper(cpp, managed = true)
* pointer passed to C++ -> kotlin.cpp.ptr
* sk_sp passed to C++ -> sk_ref_sp(kotlin.cpp.ptr)
* constructor call -> allocate Cpp; Wrapper(cpp, managed = true)
* garbage collection -> if (managed==true): calls __destroy__() for CPluaPlusClass or unref() for SkiaRefCnt
Implementation details
======================
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.native.interop.gen.Classifier
import org.jetbrains.kotlin.native.interop.gen.StubIrContext
import org.jetbrains.kotlin.native.interop.gen.StubsBuildingContextImpl
import org.jetbrains.kotlin.native.interop.indexer.StructDecl
import org.jetbrains.kotlin.native.interop.indexer.StructDef
class SkiaStubsBuildingContextImpl(stubIrContext: StubIrContext) : StubsBuildingContextImpl(stubIrContext) {
override val declarationMapper = SkiaDeclarationMapperImpl()
@@ -23,4 +24,21 @@ class SkiaStubsBuildingContextImpl(stubIrContext: StubIrContext) : StubsBuilding
return getKotlinClassForPointed(structArgument)
}
}
override fun isCppClass(spelling: String): Boolean {
val decl = nativeIndex.structs.firstOrNull { it.spelling == spelling } ?: return false
return decl.def?.kind == StructDef.Kind.CLASS
}
override fun managedWrapperClassifier(cppClassifier: Classifier): Classifier? {
if (cppClassifier.pkg != "org.jetbrains.skiko.skia.native") return null
// TODO: it'd be nice to check inheritance from SkiaRefCnt or CPlusPlusClass,
// but unable to do that at StubType level.
if (!(cppClassifier.topLevelName.startsWith("Sk") || cppClassifier.topLevelName.startsWith("Gr"))) return null
if (cppClassifier.topLevelName == "SkString") return null
// TODO: We only managed C++ classes, not structs for now.
if (!isCppClass(cppClassifier.topLevelName)) return null
return Classifier.topLevel(cppClassifier.pkg, cppClassifier.topLevelName.drop(2))
}
}