diff --git a/java/com/facebook/yoga/YogaConfigJNIBase.java b/java/com/facebook/yoga/YogaConfigJNIBase.java index 1f3ab04c..ceda9595 100644 --- a/java/com/facebook/yoga/YogaConfigJNIBase.java +++ b/java/com/facebook/yoga/YogaConfigJNIBase.java @@ -10,7 +10,7 @@ public abstract class YogaConfigJNIBase extends YogaConfig { long mNativePointer; private YogaLogger mLogger; - private boolean useVanillaJNI = false; + protected boolean useVanillaJNI = false; private YogaConfigJNIBase(long nativePointer) { if (nativePointer == 0) { @@ -85,7 +85,10 @@ public abstract class YogaConfigJNIBase extends YogaConfig { public void setLogger(YogaLogger logger) { mLogger = logger; - YogaNative.jni_YGConfigSetLogger(mNativePointer, logger); + if (useVanillaJNI) + YogaNative.jni_YGConfigSetLoggerJNI(mNativePointer, logger); + else + YogaNative.jni_YGConfigSetLogger(mNativePointer, logger); } public YogaLogger getLogger() { diff --git a/java/com/facebook/yoga/YogaConfigJNIFinalizer.java b/java/com/facebook/yoga/YogaConfigJNIFinalizer.java index 1d6fed64..ad177b90 100644 --- a/java/com/facebook/yoga/YogaConfigJNIFinalizer.java +++ b/java/com/facebook/yoga/YogaConfigJNIFinalizer.java @@ -28,7 +28,10 @@ public class YogaConfigJNIFinalizer extends YogaConfigJNIBase { if (mNativePointer != 0) { long nativePointer = mNativePointer; mNativePointer = 0; - YogaNative.jni_YGConfigFree(nativePointer); + if (useVanillaJNI) + YogaNative.jni_YGConfigFreeJNI(nativePointer); + else + YogaNative.jni_YGConfigFree(nativePointer); } } } diff --git a/java/com/facebook/yoga/YogaNative.java b/java/com/facebook/yoga/YogaNative.java index 1765ef5a..df3fe21e 100644 --- a/java/com/facebook/yoga/YogaNative.java +++ b/java/com/facebook/yoga/YogaNative.java @@ -116,14 +116,14 @@ public class YogaNative { // JNI methods that use Vanilla JNI // YGConfig related static native long jni_YGConfigNewJNI(); -// static native void jni_YGConfigFreeJNI(long nativePointer); + static native void jni_YGConfigFreeJNI(long nativePointer); static native void jni_YGConfigSetExperimentalFeatureEnabledJNI(long nativePointer, int feature, boolean enabled); static native void jni_YGConfigSetUseWebDefaultsJNI(long nativePointer, boolean useWebDefaults); static native void jni_YGConfigSetPrintTreeFlagJNI(long nativePointer, boolean enable); static native void jni_YGConfigSetPointScaleFactorJNI(long nativePointer, float pixelsInPoint); static native void jni_YGConfigSetUseLegacyStretchBehaviourJNI(long nativePointer, boolean useLegacyStretchBehaviour); static native void jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviourJNI(long nativePointer, boolean shouldDiffLayoutWithoutLegacyStretchBehaviour); -// static native void jni_YGConfigSetLoggerJNI(long nativePointer, Object logger); + static native void jni_YGConfigSetLoggerJNI(long nativePointer, YogaLogger logger); // YGNode related static native long jni_YGNodeNewJNI(); diff --git a/java/jni/YGJNIVanilla.cpp b/java/jni/YGJNIVanilla.cpp index 6a2a8a55..4920ecab 100644 --- a/java/jni/YGJNIVanilla.cpp +++ b/java/jni/YGJNIVanilla.cpp @@ -13,6 +13,7 @@ #include "YGJTypesVanilla.h" #include #include +#include using namespace facebook::yoga::vanillajni; using facebook::yoga::detail::Log; @@ -43,13 +44,13 @@ static jlong jni_YGConfigNewJNI(JNIEnv* env, jobject obj) { return reinterpret_cast(YGConfigNew()); } -// void jni_YGConfigFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) { -// const YGConfigRef config = _jlong2YGConfigRef(nativePointer); -// // unique_ptr will destruct the underlying global_ref, if present. -// auto context = std::unique_ptr>{ -// static_cast*>(YGConfigGetContext(config))}; -// YGConfigFree(config); -// } +static void jni_YGConfigFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + // unique_ptr will destruct the underlying global_ref, if present. + auto context = std::unique_ptr>{ + static_cast*>(YGConfigGetContext(config))}; + YGConfigFree(config); +} static void jni_YGConfigSetExperimentalFeatureEnabledJNI( JNIEnv* env, @@ -135,6 +136,76 @@ static jlong jni_YGNodeNewWithConfigJNI( return reinterpret_cast(node); } +static int YGJNILogFunc( + const YGConfigRef config, + const YGNodeRef node, + YGLogLevel level, + void* layoutContext, + const char* format, + va_list args) { + int result = vsnprintf(NULL, 0, format, args); + std::vector buffer(1 + result); + vsnprintf(buffer.data(), buffer.size(), format, args); + + auto jloggerPtr = + static_cast*>(YGConfigGetContext(config)); + if (jloggerPtr != nullptr) { + if (*jloggerPtr) { + JNIEnv* env = getCurrentEnv(); + + jclass cl = env->FindClass("Lcom/facebook/yoga/YogaLogLevel;"); + static const jmethodID smethodId = + facebook::yoga::vanillajni::getStaticMethodId( + env, cl, "fromInt", "(I)Lcom/facebook/yoga/YogaLogLevel;"); + ScopedLocalRef logLevel = + facebook::yoga::vanillajni::callStaticObjectMethod( + env, cl, smethodId, level); + + auto objectClass = facebook::yoga::vanillajni::make_local_ref( + env, env->GetObjectClass((*jloggerPtr).get())); + static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId( + env, + objectClass.get(), + "log", + "(Lcom/facebook/yoga/YogaLogLevel;Ljava/lang/String;)V"); + facebook::yoga::vanillajni::callVoidMethod( + env, + (*jloggerPtr).get(), + methodId, + logLevel.get(), + env->NewStringUTF(buffer.data())); + } + } + + return result; +} + +static void jni_YGConfigSetLoggerJNI( + JNIEnv* env, + jobject obj, + jlong nativePointer, + jobject logger) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + auto context = + reinterpret_cast*>(YGConfigGetContext(config)); + + if (logger) { + if (context == nullptr) { + context = new ScopedGlobalRef(); + YGConfigSetContext(config, context); + } + + *context = newGlobalRef(env, logger); + config->setLogger(YGJNILogFunc); + } else { + if (context != nullptr) { + delete context; + YGConfigSetContext(config, nullptr); + } + config->setLogger(nullptr); + } +} + static void jni_YGNodeFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) { if (nativePointer == 0) { return; @@ -666,7 +737,7 @@ static void jni_YGNodeSetStyleInputsJNI( static JNINativeMethod methods[] = { {"jni_YGConfigNewJNI", "()J", (void*) jni_YGConfigNewJNI}, - // {"jni_YGConfigFreeJNI", "(J)V", (void*) jni_YGConfigFreeJNI}, + {"jni_YGConfigFreeJNI", "(J)V", (void*) jni_YGConfigFreeJNI}, {"jni_YGConfigSetExperimentalFeatureEnabledJNI", "(JIZ)V", (void*) jni_YGConfigSetExperimentalFeatureEnabledJNI}, @@ -685,7 +756,9 @@ static JNINativeMethod methods[] = { {"jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviourJNI", "(JZ)V", (void*) jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviourJNI}, - // {"jni_YGConfigSetLoggerJNI", "(JO)V", (void*) jni_YGConfigSetLoggerJNI}, + {"jni_YGConfigSetLoggerJNI", + "(JLcom/facebook/yoga/YogaLogger;)V", + (void*) jni_YGConfigSetLoggerJNI}, {"jni_YGNodeNewJNI", "()J", (void*) jni_YGNodeNewJNI}, {"jni_YGNodeNewWithConfigJNI", "(J)J", (void*) jni_YGNodeNewWithConfigJNI}, {"jni_YGNodeFreeJNI", "(J)V", (void*) jni_YGNodeFreeJNI},