Unverified Commit c20bf0c5 authored by Aleksandr Veselov's avatar Aleksandr Veselov Committed by GitHub

Implement `skottie::Logger` for native (#376)

parent 23a7d626
...@@ -150,6 +150,16 @@ inline fun withStringReferenceResult(block: () -> NativePointer): String { ...@@ -150,6 +150,16 @@ inline fun withStringReferenceResult(block: () -> NativePointer): String {
return string.toString() return string.toString()
} }
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
inline fun withStringReferenceNullableResult(block: () -> NativePointer): String? {
val ptr = block()
if (ptr == Native.NullPointer) return null
val string = ManagedString(ptr, false)
return string.toString()
}
interface ArrayInteropDecoder<T> { interface ArrayInteropDecoder<T> {
fun getArrayElement(array: InteropPointer, index: Int): T fun getArrayElement(array: InteropPointer, index: Int): T
fun getArraySize(array: InteropPointer): Int fun getArraySize(array: InteropPointer): Int
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION") @file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia.skottie package org.jetbrains.skia.skottie
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.Library.Companion.staticLoad import org.jetbrains.skia.impl.Library.Companion.staticLoad
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.RefCnt import org.jetbrains.skia.impl.RefCnt
import org.jetbrains.skia.impl.Stats import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.impl.NativePointer
/** /**
* *
...@@ -19,17 +20,30 @@ abstract class Logger : RefCnt(_nMake()) { ...@@ -19,17 +20,30 @@ abstract class Logger : RefCnt(_nMake()) {
} }
} }
abstract fun log(level: LogLevel?, message: String?, json: String?) abstract fun log(level: LogLevel, message: String, json: String?)
init { init {
Stats.onNativeCall() Stats.onNativeCall()
Stats.onNativeCall() Stats.onNativeCall()
_nInit(_ptr) doInit(_ptr)
} }
} }
internal expect fun Logger.doInit(ptr: NativePointer)
@ExternalSymbolName("org_jetbrains_skia_skottie_Logger__1nMake") @ExternalSymbolName("org_jetbrains_skia_skottie_Logger__1nMake")
private external fun _nMake(): NativePointer private external fun _nMake(): NativePointer
// Native/JS only
@ExternalSymbolName("org_jetbrains_skia_skottie_Logger__1nInit") @ExternalSymbolName("org_jetbrains_skia_skottie_Logger__1nInit")
external fun _nInit(ptr: NativePointer) internal external fun Logger_nInit(ptr: NativePointer, onLog: InteropPointer)
@ExternalSymbolName("org_jetbrains_skia_skottie_Logger__1nGetLogMessage")
internal external fun Logger_nGetLogMessage(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_skottie_Logger__1nGetLogJson")
internal external fun Logger_nGetLogJson(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_skottie_Logger__1nGetLogLevel")
internal external fun Logger_nGetLogLevel(ptr: NativePointer): Int
package org.jetbrains.skia.skottie
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
class LoggerTest {
@Test
fun canLog() {
var actualLevel: LogLevel? = null
var actualMessage: String? = null
var actualJson: String? = null
val logger = object: Logger() {
override fun log(level: LogLevel, message: String, json: String?) {
actualLevel = level
actualMessage = message
actualJson = json
}
}
try {
AnimationBuilder().setLogger(logger).buildFromString(
"""{"nm": "Test","v": "1.42.0","ip": <ERROR HERE>,"op": 180,"fr": 60,"w": 32,"h": 32,"layers": []}"""
)
} catch (e: IllegalArgumentException) {
// Must fail
}
assertEquals("Failed to parse JSON input.\n", actualMessage)
assertEquals(LogLevel.ERROR, actualLevel)
assertNull(actualJson)
}
}
\ No newline at end of file
...@@ -4,18 +4,18 @@ ...@@ -4,18 +4,18 @@
using namespace skottie; using namespace skottie;
class SkijaLoggerImpl: public Logger { class SkikoLogger: public Logger {
public: public:
SkijaLoggerImpl() { SkikoLogger() {
} }
~SkijaLoggerImpl() { ~SkikoLogger() {
fEnv->DeleteWeakGlobalRef(fObject); fEnv->DeleteGlobalRef(fObject);
} }
void init(JNIEnv* e, jobject o) { void init(JNIEnv* e, jobject o) {
fEnv = e; fEnv = e;
fObject = fEnv->NewWeakGlobalRef(o); fObject = fEnv->NewGlobalRef(o);
} }
public: public:
...@@ -39,12 +39,12 @@ private: ...@@ -39,12 +39,12 @@ private:
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_skottie_LoggerKt__1nMake extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_skottie_LoggerKt__1nMake
(JNIEnv* env, jclass jclass) { (JNIEnv* env, jclass jclass) {
SkijaLoggerImpl* instance = new SkijaLoggerImpl(); SkikoLogger* instance = new SkikoLogger();
return reinterpret_cast<jlong>(instance); return reinterpret_cast<jlong>(instance);
} }
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_skottie_LoggerKt__1nInit extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_skottie_Logger_1jvmKt__1nInit
(JNIEnv* env, jobject jthis, jlong ptr) { (JNIEnv* env, jclass jclass, jobject jthis, jlong ptr) {
SkijaLoggerImpl* instance = reinterpret_cast<SkijaLoggerImpl*>(static_cast<uintptr_t>(ptr)); SkikoLogger* instance = reinterpret_cast<SkikoLogger*>(static_cast<uintptr_t>(ptr));
instance->init(env, jthis); instance->init(env, jthis);
} }
package org.jetbrains.skia.skottie
import org.jetbrains.skia.impl.NativePointer
internal actual fun Logger.doInit(ptr: NativePointer) {
_nInit(this, ptr)
}
private external fun _nInit(thisPtr: Logger, ptr: NativePointer)
\ No newline at end of file
...@@ -5,32 +5,72 @@ ...@@ -5,32 +5,72 @@
using namespace skottie; using namespace skottie;
#include "common.h" #include "common.h"
class SkikoLogger: public Logger {
public:
SkikoLogger() : _log(nullptr) {}
SKIKO_EXPORT KNativePointer org_jetbrains_skia_skottie_Logger__1nMake void init(KInteropPointer onLog) {
() { _log = KVoidCallback(onLog);
TODO("implement org_jetbrains_skia_skottie_Logger__1nMake"); }
}
SkString* logMessage() {
return &_logMessage;
}
SkString* logJson() {
return _hasLogJson ? &_logJson : nullptr;
}
Level logLevel() const {
return _logLevel;
}
void log(Level level, const char message[], const char* json = nullptr) override {
_logLevel = level;
_logMessage = message;
_hasLogJson = json != nullptr;
_logJson = json;
_log();
_logLevel = Level::kError;
_logMessage = nullptr;
_logJson = nullptr;
_hasLogJson = false;
}
private:
SkString _logMessage;
SkString _logJson;
KVoidCallback _log;
Level _logLevel;
bool _hasLogJson;
};
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_skottie_Logger__1nMake SKIKO_EXPORT KNativePointer org_jetbrains_skia_skottie_Logger__1nMake
() { () {
SkijaLoggerImpl* instance = new SkijaLoggerImpl(); SkikoLogger* instance = sk_sp<SkikoLogger>(new SkikoLogger()).release();
return reinterpret_cast<KNativePointer>(instance); return reinterpret_cast<KNativePointer>(instance);
} }
#endif
SKIKO_EXPORT void org_jetbrains_skia_skottie_Logger__1nInit SKIKO_EXPORT void org_jetbrains_skia_skottie_Logger__1nInit
(KNativePointer ptr, KInteropPointer onLog) {
SkikoLogger* instance = reinterpret_cast<SkikoLogger*>((ptr));
instance->init(onLog);
}
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_skottie_Logger__1nGetLogMessage
(KNativePointer ptr) { (KNativePointer ptr) {
TODO("implement org_jetbrains_skia_skottie_Logger__1nInit"); SkikoLogger* instance = reinterpret_cast<SkikoLogger*>((ptr));
return reinterpret_cast<KInteropPointer>(instance->logMessage());
} }
#if 0 SKIKO_EXPORT KInteropPointer org_jetbrains_skia_skottie_Logger__1nGetLogJson
SKIKO_EXPORT void org_jetbrains_skia_skottie_Logger__1nInit
(KNativePointer ptr) { (KNativePointer ptr) {
SkijaLoggerImpl* instance = reinterpret_cast<SkijaLoggerImpl*>((ptr)); SkikoLogger* instance = reinterpret_cast<SkikoLogger*>((ptr));
instance->init(env, jthis); return reinterpret_cast<KInteropPointer>(instance->logJson());
} }
#endif
SKIKO_EXPORT KInt org_jetbrains_skia_skottie_Logger__1nGetLogLevel
(KNativePointer ptr) {
SkikoLogger* instance = reinterpret_cast<SkikoLogger*>((ptr));
return static_cast<KInt>(instance->logLevel());
}
package org.jetbrains.skia.skottie
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skia.impl.withStringReferenceNullableResult
import org.jetbrains.skia.impl.withStringReferenceResult
internal actual fun Logger.doInit(ptr: NativePointer) {
interopScope {
val onLog = virtual {
val level = LogLevel.values()[Logger_nGetLogLevel(ptr)]
val message = withStringReferenceResult { Logger_nGetLogMessage(ptr) }
val json = withStringReferenceNullableResult { Logger_nGetLogJson(ptr) }
log(level, message, json)
}
Logger_nInit(ptr, onLog)
}
}
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