Files
yoga/java/jni/YGJNIVanilla.cpp

963 lines
34 KiB
C++
Raw Normal View History

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGJNIVanilla.h"
#include <bit>
#include <cstring>
#include <iostream>
#include <memory>
#include "LayoutContext.h"
#include "YGJNI.h"
#include "YGJTypesVanilla.h"
#include "YogaJniException.h"
#include "common.h"
#include "jni.h"
C++ Cleanup 2/N: Reorganize YGConfig (#1348) Summary: X-link: https://github.com/facebook/react-native/pull/39218 X-link: https://github.com/facebook/react-native/pull/39169 Pull Request resolved: https://github.com/facebook/yoga/pull/1348 ## This diff This diff adds a top level `config` directory for code related to configuring Yoga and Yoga Nodes. The public API for config handles is `YGConfigRef`, which is forward declared to be a pointer to a struct named `YGConfig`. The existing `YGConfig` is split into `yoga::Config`, as the private C++ implementation, inheriting from `YGConfig`, a marker type represented as an empty struct. The public API continues to accept `YGConfigRef`, which continues to be `YGConfig *`, but it must be cast to its concrete internal representation at the API boundary before doing work on it. ## This stack The organization of the C++ internals of Yoga are in need of attention. 1. Some of the C++ internals are namespaced, but others not. 2. Some of the namespaces include `detail`, but are meant to be used outside of the translation unit (FB Clang Tidy rules warn on any usage of these) 2. Most of the files are in a flat hierarchy, except for event tracing in its own folder 3. Some files and functions begin with YG, others don’t 4. Some functions are uppercase, others are not 5. Almost all of the interesting logic is in Yoga.cpp, and the file is too large to reason about 6. There are multiple grab bag files where folks put random functions they need in (Utils, BitUtils, Yoga-Internal.h) 7. There is no clear indication from file structure or type naming what is private vs not 8. Handles like `YGNodeRef` and `YGConfigRef` can be used to access internals just by importing headers This stack does some much needed spring cleaning: 1. All non-public headers and C++ implementation details are in separate folders from the root level `yoga`. This will give us room to split up logic and add more files without too large a flat hierarchy 3. All private C++ internals are under the `facebook::yoga` namespace. Details namespaces are only ever used within the same header, as they are intended 4. Utils files are split 5. Most C++ internals drop the YG prefix 6. Most C++ internal function names are all lower camel case 7. We start to split up Yoga.cpp 8. Every header beginning with YG or at the top-level directory is public and C only, with the exception of Yoga-Internal.h which has non-public functions for bindings 9. It is not possible to use private APIs without static casting handles to internal classes This will give us more leeway to continue splitting monolithic files, and consistent guidelines for style in new files as well. These changes should not be breaking to any project using only public Yoga headers. This includes every usage of Yoga in fbsource except for RN Fabric which is currently tied to internals. This refactor should make that boundary clearer. Changelog: [Internal] Reviewed By: shwanton Differential Revision: D48847257 fbshipit-source-id: 7a2157d169ba80a6f79620693ae45bb10dfca5a3
2023-08-30 16:27:32 -07:00
using namespace facebook;
using namespace facebook::yoga;
using namespace facebook::yoga::vanillajni;
static inline ScopedLocalRef<jobject> YGNodeJobject(YGNodeConstRef node) {
return LayoutContext::getNodeMap()->ref(node);
}
static inline YGNodeRef _jlong2YGNodeRef(jlong addr) {
return reinterpret_cast<YGNodeRef>(static_cast<intptr_t>(addr));
}
static inline YGConfigRef _jlong2YGConfigRef(jlong addr) {
return reinterpret_cast<YGConfigRef>(static_cast<intptr_t>(addr));
}
static jlong jni_YGConfigNewJNI(JNIEnv* /*env*/, jobject /*obj*/) {
return reinterpret_cast<jlong>(YGConfigNew());
}
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<ScopedGlobalRef<jobject>>{
static_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config))};
YGConfigFree(config);
}
static void jni_YGConfigSetExperimentalFeatureEnabledJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint feature,
jboolean enabled) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
YGConfigSetExperimentalFeatureEnabled(
config,
static_cast<YGExperimentalFeature>(feature),
static_cast<bool>(enabled));
}
static void jni_YGConfigSetUseWebDefaultsJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jboolean useWebDefaults) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
YGConfigSetUseWebDefaults(config, static_cast<bool>(useWebDefaults));
}
static void jni_YGConfigSetPointScaleFactorJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jfloat pixelsInPoint) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
YGConfigSetPointScaleFactor(config, pixelsInPoint);
}
static void jni_YGConfigSetErrataJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint errata) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
YGConfigSetErrata(config, static_cast<YGErrata>(errata));
}
static jint jni_YGConfigGetErrataJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
return static_cast<jint>(YGConfigGetErrata(config));
}
static jlong jni_YGNodeNewJNI(JNIEnv* /*env*/, jobject /*obj*/) {
const YGNodeRef node = YGNodeNew();
YGNodeSetContext(node, YGNodeContext{}.asVoidPtr);
return reinterpret_cast<jlong>(node);
}
static jlong jni_YGNodeNewWithConfigJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong configPointer) {
const YGNodeRef node = YGNodeNewWithConfig(_jlong2YGConfigRef(configPointer));
YGNodeSetContext(node, YGNodeContext{}.asVoidPtr);
return reinterpret_cast<jlong>(node);
}
static int YGJNILogFunc(
const YGConfigConstRef config,
const YGNodeConstRef /*node*/,
YGLogLevel level,
const char* format,
va_list args) {
va_list argsCopy;
va_copy(argsCopy, args);
int result = vsnprintf(nullptr, 0, format, argsCopy);
std::vector<char> buffer(1 + static_cast<size_t>(result));
vsnprintf(buffer.data(), buffer.size(), format, args);
auto jloggerPtr =
static_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config));
if (jloggerPtr != nullptr) {
if (*jloggerPtr) {
JNIEnv* env = getCurrentEnv();
jclass cl = env->FindClass("com/facebook/yoga/YogaLogLevel");
static const jmethodID smethodId =
facebook::yoga::vanillajni::getStaticMethodId(
env, cl, "fromInt", "(I)Lcom/facebook/yoga/YogaLogLevel;");
ScopedLocalRef<jobject> 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<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config));
if (logger != nullptr) {
if (context == nullptr) {
context = new ScopedGlobalRef<jobject>();
YGConfigSetContext(config, context);
}
*context = newGlobalRef(env, logger);
YGConfigSetLogger(config, YGJNILogFunc);
} else {
if (context != nullptr) {
delete context;
YGConfigSetContext(config, nullptr);
}
YGConfigSetLogger(config, nullptr);
}
}
static void
jni_YGNodeFinalizeJNI(JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) {
if (nativePointer == 0) {
return;
}
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
YGNodeFinalize(node);
}
static void
jni_YGNodeResetJNI(JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) {
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
void* context = YGNodeGetContext(node);
YGNodeReset(node);
YGNodeSetContext(node, context);
}
static void jni_YGNodeInsertChildJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jlong childPointer,
jint index) {
YGNodeInsertChild(
_jlong2YGNodeRef(nativePointer),
_jlong2YGNodeRef(childPointer),
static_cast<uint32_t>(index));
}
static void jni_YGNodeSwapChildJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jlong childPointer,
jint index) {
YGNodeSwapChild(
_jlong2YGNodeRef(nativePointer),
_jlong2YGNodeRef(childPointer),
static_cast<uint32_t>(index));
}
static void jni_YGNodeSetIsReferenceBaselineJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jboolean isReferenceBaseline) {
YGNodeSetIsReferenceBaseline(
_jlong2YGNodeRef(nativePointer), static_cast<bool>(isReferenceBaseline));
}
static jboolean jni_YGNodeIsReferenceBaselineJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer) {
return static_cast<jboolean>(
YGNodeIsReferenceBaseline(_jlong2YGNodeRef(nativePointer)));
}
static void jni_YGNodeRemoveAllChildrenJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer) {
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
YGNodeRemoveAllChildren(node);
}
static void jni_YGNodeRemoveChildJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jlong childPointer) {
YGNodeRemoveChild(
_jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer));
}
static void
YGTransferLayoutOutputsRecursive(JNIEnv* env, jobject thiz, YGNodeRef root) {
if (!YGNodeGetHasNewLayout(root)) {
return;
}
auto obj = YGNodeJobject(root);
if (!obj) {
return;
}
auto edgesSet = YGNodeEdges{root};
bool marginFieldSet = edgesSet.has(YGNodeEdges::MARGIN);
bool paddingFieldSet = edgesSet.has(YGNodeEdges::PADDING);
bool borderFieldSet = edgesSet.has(YGNodeEdges::BORDER);
int fieldFlags = edgesSet.get();
fieldFlags |= HAS_NEW_LAYOUT;
const int arrSize = 6 + (marginFieldSet ? 4 : 0) + (paddingFieldSet ? 4 : 0) +
(borderFieldSet ? 4 : 0);
float arr[18];
arr[LAYOUT_EDGE_SET_FLAG_INDEX] = static_cast<float>(fieldFlags);
arr[LAYOUT_WIDTH_INDEX] = YGNodeLayoutGetWidth(root);
arr[LAYOUT_HEIGHT_INDEX] = YGNodeLayoutGetHeight(root);
arr[LAYOUT_LEFT_INDEX] = YGNodeLayoutGetLeft(root);
arr[LAYOUT_TOP_INDEX] = YGNodeLayoutGetTop(root);
arr[LAYOUT_DIRECTION_INDEX] =
static_cast<float>(YGNodeLayoutGetDirection(root));
if (marginFieldSet) {
arr[LAYOUT_MARGIN_START_INDEX] = YGNodeLayoutGetMargin(root, YGEdgeLeft);
arr[LAYOUT_MARGIN_START_INDEX + 1] = YGNodeLayoutGetMargin(root, YGEdgeTop);
arr[LAYOUT_MARGIN_START_INDEX + 2] =
YGNodeLayoutGetMargin(root, YGEdgeRight);
arr[LAYOUT_MARGIN_START_INDEX + 3] =
YGNodeLayoutGetMargin(root, YGEdgeBottom);
}
if (paddingFieldSet) {
int paddingStartIndex =
LAYOUT_PADDING_START_INDEX - (marginFieldSet ? 0 : 4);
arr[paddingStartIndex] = YGNodeLayoutGetPadding(root, YGEdgeLeft);
arr[paddingStartIndex + 1] = YGNodeLayoutGetPadding(root, YGEdgeTop);
arr[paddingStartIndex + 2] = YGNodeLayoutGetPadding(root, YGEdgeRight);
arr[paddingStartIndex + 3] = YGNodeLayoutGetPadding(root, YGEdgeBottom);
}
if (borderFieldSet) {
int borderStartIndex = LAYOUT_BORDER_START_INDEX -
(marginFieldSet ? 0 : 4) - (paddingFieldSet ? 0 : 4);
arr[borderStartIndex] = YGNodeLayoutGetBorder(root, YGEdgeLeft);
arr[borderStartIndex + 1] = YGNodeLayoutGetBorder(root, YGEdgeTop);
arr[borderStartIndex + 2] = YGNodeLayoutGetBorder(root, YGEdgeRight);
arr[borderStartIndex + 3] = YGNodeLayoutGetBorder(root, YGEdgeBottom);
}
// Create scope to make sure to release any local refs created here
{
// Don't change this field name without changing the name of the field in
// Database.java
auto objectClass = facebook::yoga::vanillajni::make_local_ref(
env, env->GetObjectClass(obj.get()));
static const jfieldID arrField = facebook::yoga::vanillajni::getFieldId(
env, objectClass.get(), "arr", "[F");
ScopedLocalRef<jfloatArray> arrFinal =
make_local_ref(env, env->NewFloatArray(arrSize));
env->SetFloatArrayRegion(arrFinal.get(), 0, arrSize, arr);
env->SetObjectField(obj.get(), arrField, arrFinal.get());
}
YGNodeSetHasNewLayout(root, false);
for (size_t i = 0; i < YGNodeGetChildCount(root); i++) {
YGTransferLayoutOutputsRecursive(env, thiz, YGNodeGetChild(root, i));
}
}
static void jni_YGNodeCalculateLayoutJNI(
JNIEnv* env,
jobject obj,
jlong nativePointer,
jfloat width,
jfloat height,
jlongArray nativePointers,
jobjectArray javaNodes) {
try {
PtrJNodeMapVanilla* layoutContext = nullptr;
auto map = PtrJNodeMapVanilla{};
if (nativePointers != nullptr) {
map = PtrJNodeMapVanilla{nativePointers, javaNodes};
layoutContext = &map;
}
LayoutContext::Provider contextProvider(layoutContext);
const YGNodeRef root = _jlong2YGNodeRef(nativePointer);
YGNodeCalculateLayout(
root,
static_cast<float>(width),
static_cast<float>(height),
YGNodeStyleGetDirection(_jlong2YGNodeRef(nativePointer)));
YGTransferLayoutOutputsRecursive(env, obj, root);
} catch (const YogaJniException& jniException) {
ScopedLocalRef<jthrowable> throwable = jniException.getThrowable();
if (throwable.get() != nullptr) {
env->Throw(throwable.get());
}
} catch (const std::logic_error& ex) {
env->ExceptionClear();
jclass cl = env->FindClass("java/lang/IllegalStateException");
static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId(
env, cl, "<init>", "(Ljava/lang/String;)V");
auto throwable = env->NewObject(cl, methodId, env->NewStringUTF(ex.what()));
env->Throw(static_cast<jthrowable>(throwable));
}
}
static void
jni_YGNodeMarkDirtyJNI(JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) {
YGNodeMarkDirty(_jlong2YGNodeRef(nativePointer));
}
static jboolean
jni_YGNodeIsDirtyJNI(JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) {
return (jboolean)YGNodeIsDirty(_jlong2YGNodeRef(nativePointer));
}
static void jni_YGNodeCopyStyleJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong dstNativePointer,
jlong srcNativePointer) {
YGNodeCopyStyle(
_jlong2YGNodeRef(dstNativePointer), _jlong2YGNodeRef(srcNativePointer));
}
#define YG_NODE_JNI_STYLE_PROP(javatype, type, name) \
static javatype jni_YGNodeStyleGet##name##JNI( \
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \
return (javatype)YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \
} \
\
static void jni_YGNodeStyleSet##name##JNI( \
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, javatype value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<type>(value)); \
}
#define YG_NODE_JNI_STYLE_UNIT_PROP(name) \
static jlong jni_YGNodeStyleGet##name##JNI( \
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \
return YogaValue::asJavaLong( \
YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer))); \
} \
\
static void jni_YGNodeStyleSet##name##JNI( \
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, jfloat value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<float>(value)); \
} \
\
static void jni_YGNodeStyleSet##name##PercentJNI( \
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, jfloat value) { \
YGNodeStyleSet##name##Percent( \
_jlong2YGNodeRef(nativePointer), static_cast<float>(value)); \
}
#define YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(name) \
YG_NODE_JNI_STYLE_UNIT_PROP(name) \
static void jni_YGNodeStyleSet##name##AutoJNI( \
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \
YGNodeStyleSet##name##Auto(_jlong2YGNodeRef(nativePointer)); \
}
#define YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(name) \
static jlong jni_YGNodeStyleGet##name##JNI( \
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, jint edge) { \
return YogaValue::asJavaLong(YGNodeStyleGet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<YGEdge>(edge))); \
} \
\
static void jni_YGNodeStyleSet##name##JNI( \
JNIEnv* /*env*/, \
jobject /*obj*/, \
jlong nativePointer, \
jint edge, \
jfloat value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), \
static_cast<YGEdge>(edge), \
static_cast<float>(value)); \
} \
\
static void jni_YGNodeStyleSet##name##PercentJNI( \
JNIEnv* /*env*/, \
jobject /*obj*/, \
jlong nativePointer, \
jint edge, \
jfloat value) { \
YGNodeStyleSet##name##Percent( \
_jlong2YGNodeRef(nativePointer), \
static_cast<YGEdge>(edge), \
static_cast<float>(value)); \
}
YG_NODE_JNI_STYLE_PROP(jint, YGDirection, Direction);
YG_NODE_JNI_STYLE_PROP(jint, YGFlexDirection, FlexDirection);
YG_NODE_JNI_STYLE_PROP(jint, YGJustify, JustifyContent);
YG_NODE_JNI_STYLE_PROP(jint, YGAlign, AlignItems);
YG_NODE_JNI_STYLE_PROP(jint, YGAlign, AlignSelf);
YG_NODE_JNI_STYLE_PROP(jint, YGAlign, AlignContent);
YG_NODE_JNI_STYLE_PROP(jint, YGPositionType, PositionType);
YG_NODE_JNI_STYLE_PROP(jint, YGWrap, FlexWrap);
YG_NODE_JNI_STYLE_PROP(jint, YGOverflow, Overflow);
YG_NODE_JNI_STYLE_PROP(jint, YGDisplay, Display);
YG_NODE_JNI_STYLE_PROP(jfloat, float, Flex);
YG_NODE_JNI_STYLE_PROP(jfloat, float, FlexGrow);
YG_NODE_JNI_STYLE_PROP(jfloat, float, FlexShrink);
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(FlexBasis);
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(Width);
YG_NODE_JNI_STYLE_UNIT_PROP(MinWidth);
YG_NODE_JNI_STYLE_UNIT_PROP(MaxWidth);
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(Height);
YG_NODE_JNI_STYLE_UNIT_PROP(MinHeight);
YG_NODE_JNI_STYLE_UNIT_PROP(MaxHeight);
YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(Position);
static jlong jni_YGNodeStyleGetMarginJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
if (!YGNodeEdges{yogaNodeRef}.has(YGNodeEdges::MARGIN)) {
return YogaValue::undefinedAsJavaLong();
}
return YogaValue::asJavaLong(
YGNodeStyleGetMargin(yogaNodeRef, static_cast<YGEdge>(edge)));
}
static void jni_YGNodeStyleSetMarginJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge,
jfloat margin) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
YGNodeEdges{yogaNodeRef}.add(YGNodeEdges::MARGIN).setOn(yogaNodeRef);
YGNodeStyleSetMargin(
yogaNodeRef, static_cast<YGEdge>(edge), static_cast<float>(margin));
}
static void jni_YGNodeStyleSetMarginPercentJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge,
jfloat percent) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
YGNodeEdges{yogaNodeRef}.add(YGNodeEdges::MARGIN).setOn(yogaNodeRef);
YGNodeStyleSetMarginPercent(
yogaNodeRef, static_cast<YGEdge>(edge), static_cast<float>(percent));
}
static void jni_YGNodeStyleSetMarginAutoJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
YGNodeEdges{yogaNodeRef}.add(YGNodeEdges::MARGIN).setOn(yogaNodeRef);
YGNodeStyleSetMarginAuto(yogaNodeRef, static_cast<YGEdge>(edge));
}
static jlong jni_YGNodeStyleGetPaddingJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
if (!YGNodeEdges{yogaNodeRef}.has(YGNodeEdges::PADDING)) {
return YogaValue::undefinedAsJavaLong();
}
return YogaValue::asJavaLong(
YGNodeStyleGetPadding(yogaNodeRef, static_cast<YGEdge>(edge)));
}
static void jni_YGNodeStyleSetPaddingJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge,
jfloat padding) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
YGNodeEdges{yogaNodeRef}.add(YGNodeEdges::PADDING).setOn(yogaNodeRef);
YGNodeStyleSetPadding(
yogaNodeRef, static_cast<YGEdge>(edge), static_cast<float>(padding));
}
static void jni_YGNodeStyleSetPaddingPercentJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge,
jfloat percent) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
YGNodeEdges{yogaNodeRef}.add(YGNodeEdges::PADDING).setOn(yogaNodeRef);
YGNodeStyleSetPaddingPercent(
yogaNodeRef, static_cast<YGEdge>(edge), static_cast<float>(percent));
}
static jfloat jni_YGNodeStyleGetBorderJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
if (!YGNodeEdges{yogaNodeRef}.has(YGNodeEdges::BORDER)) {
return (jfloat)YGUndefined;
}
return (jfloat)YGNodeStyleGetBorder(yogaNodeRef, static_cast<YGEdge>(edge));
}
static void jni_YGNodeStyleSetBorderJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint edge,
jfloat border) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
YGNodeEdges{yogaNodeRef}.add(YGNodeEdges::BORDER).setOn(yogaNodeRef);
YGNodeStyleSetBorder(
yogaNodeRef, static_cast<YGEdge>(edge), static_cast<float>(border));
}
static void YGTransferLayoutDirection(YGNodeConstRef node, jobject javaNode) {
// Don't change this field name without changing the name of the field in
// Database.java
JNIEnv* env = getCurrentEnv();
auto objectClass = facebook::yoga::vanillajni::make_local_ref(
env, env->GetObjectClass(javaNode));
static const jfieldID layoutDirectionField =
facebook::yoga::vanillajni::getFieldId(
env, objectClass.get(), "mLayoutDirection", "I");
env->SetIntField(
javaNode,
layoutDirectionField,
static_cast<jint>(YGNodeLayoutGetDirection(node)));
}
static YGSize YGJNIMeasureFunc(
YGNodeConstRef node,
float width,
YGMeasureMode widthMode,
float height,
YGMeasureMode heightMode) {
if (auto obj = YGNodeJobject(node)) {
YGTransferLayoutDirection(node, obj.get());
JNIEnv* env = getCurrentEnv();
auto objectClass = facebook::yoga::vanillajni::make_local_ref(
env, env->GetObjectClass(obj.get()));
static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId(
env, objectClass.get(), "measure", "(FIFI)J");
const auto measureResult = facebook::yoga::vanillajni::callLongMethod(
env, obj.get(), methodId, width, widthMode, height, heightMode);
static_assert(
sizeof(measureResult) == 8,
"Expected measureResult to be 8 bytes, or two 32 bit ints");
uint32_t wBits = 0xFFFFFFFF & (measureResult >> 32);
uint32_t hBits = 0xFFFFFFFF & measureResult;
auto measuredWidth = std::bit_cast<float>(wBits);
auto measuredHeight = std::bit_cast<float>(hBits);
return YGSize{measuredWidth, measuredHeight};
} else {
return YGSize{
widthMode == YGMeasureModeUndefined ? 0 : width,
heightMode == YGMeasureModeUndefined ? 0 : height,
};
}
}
static void jni_YGNodeSetHasMeasureFuncJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jboolean hasMeasureFunc) {
YGNodeSetMeasureFunc(
_jlong2YGNodeRef(nativePointer),
static_cast<bool>(hasMeasureFunc) ? YGJNIMeasureFunc : nullptr);
}
static float YGJNIBaselineFunc(YGNodeConstRef node, float width, float height) {
if (auto obj = YGNodeJobject(node)) {
JNIEnv* env = getCurrentEnv();
auto objectClass = facebook::yoga::vanillajni::make_local_ref(
env, env->GetObjectClass(obj.get()));
static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId(
env, objectClass.get(), "baseline", "(FF)F");
return facebook::yoga::vanillajni::callFloatMethod(
env, obj.get(), methodId, width, height);
} else {
return height;
}
}
static void jni_YGNodeSetHasBaselineFuncJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jboolean hasBaselineFunc) {
YGNodeSetBaselineFunc(
_jlong2YGNodeRef(nativePointer),
static_cast<bool>(hasBaselineFunc) ? YGJNIBaselineFunc : nullptr);
}
static void jni_YGNodeSetAlwaysFormsContainingBlockJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jboolean alwaysFormsContainingBlock) {
YGNodeSetAlwaysFormsContainingBlock(
_jlong2YGNodeRef(nativePointer),
static_cast<bool>(alwaysFormsContainingBlock));
}
static jlong
jni_YGNodeCloneJNI(JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) {
auto node = _jlong2YGNodeRef(nativePointer);
const YGNodeRef clonedYogaNode = YGNodeClone(node);
YGNodeSetContext(clonedYogaNode, YGNodeGetContext(node));
return reinterpret_cast<jlong>(clonedYogaNode);
}
static jfloat jni_YGNodeStyleGetGapJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint gutter) {
return (jfloat)YGNodeStyleGetGap(
_jlong2YGNodeRef(nativePointer), static_cast<YGGutter>(gutter));
}
static void jni_YGNodeStyleSetGapJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint gutter,
jfloat gapLength) {
YGNodeStyleSetGap(
_jlong2YGNodeRef(nativePointer),
static_cast<YGGutter>(gutter),
static_cast<float>(gapLength));
}
// Yoga specific properties, not compatible with flexbox specification
YG_NODE_JNI_STYLE_PROP(jfloat, float, AspectRatio);
static JNINativeMethod methods[] = {
{"jni_YGConfigNewJNI", "()J", (void*)jni_YGConfigNewJNI},
{"jni_YGConfigFreeJNI", "(J)V", (void*)jni_YGConfigFreeJNI},
{"jni_YGConfigSetExperimentalFeatureEnabledJNI",
"(JIZ)V",
(void*)jni_YGConfigSetExperimentalFeatureEnabledJNI},
{"jni_YGConfigSetUseWebDefaultsJNI",
"(JZ)V",
(void*)jni_YGConfigSetUseWebDefaultsJNI},
{"jni_YGConfigSetPointScaleFactorJNI",
"(JF)V",
(void*)jni_YGConfigSetPointScaleFactorJNI},
{"jni_YGConfigSetErrataJNI", "(JI)V", (void*)jni_YGConfigSetErrataJNI},
{"jni_YGConfigGetErrataJNI", "(J)I", (void*)jni_YGConfigGetErrataJNI},
{"jni_YGConfigSetLoggerJNI",
"(JLcom/facebook/yoga/YogaLogger;)V",
(void*)jni_YGConfigSetLoggerJNI},
{"jni_YGNodeNewJNI", "()J", (void*)jni_YGNodeNewJNI},
{"jni_YGNodeNewWithConfigJNI", "(J)J", (void*)jni_YGNodeNewWithConfigJNI},
{"jni_YGNodeFinalizeJNI", "(J)V", (void*)jni_YGNodeFinalizeJNI},
{"jni_YGNodeResetJNI", "(J)V", (void*)jni_YGNodeResetJNI},
{"jni_YGNodeInsertChildJNI", "(JJI)V", (void*)jni_YGNodeInsertChildJNI},
{"jni_YGNodeSwapChildJNI", "(JJI)V", (void*)jni_YGNodeSwapChildJNI},
{"jni_YGNodeSetIsReferenceBaselineJNI",
"(JZ)V",
(void*)jni_YGNodeSetIsReferenceBaselineJNI},
{"jni_YGNodeIsReferenceBaselineJNI",
"(J)Z",
(void*)jni_YGNodeIsReferenceBaselineJNI},
{"jni_YGNodeRemoveAllChildrenJNI",
"(J)V",
(void*)jni_YGNodeRemoveAllChildrenJNI},
{"jni_YGNodeRemoveChildJNI", "(JJ)V", (void*)jni_YGNodeRemoveChildJNI},
{"jni_YGNodeCalculateLayoutJNI",
"(JFF[J[Lcom/facebook/yoga/YogaNodeJNIBase;)V",
(void*)jni_YGNodeCalculateLayoutJNI},
{"jni_YGNodeMarkDirtyJNI", "(J)V", (void*)jni_YGNodeMarkDirtyJNI},
{"jni_YGNodeIsDirtyJNI", "(J)Z", (void*)jni_YGNodeIsDirtyJNI},
{"jni_YGNodeCopyStyleJNI", "(JJ)V", (void*)jni_YGNodeCopyStyleJNI},
{"jni_YGNodeStyleGetDirectionJNI",
"(J)I",
(void*)jni_YGNodeStyleGetDirectionJNI},
{"jni_YGNodeStyleSetDirectionJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetDirectionJNI},
{"jni_YGNodeStyleGetFlexDirectionJNI",
"(J)I",
(void*)jni_YGNodeStyleGetFlexDirectionJNI},
{"jni_YGNodeStyleSetFlexDirectionJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetFlexDirectionJNI},
{"jni_YGNodeStyleGetJustifyContentJNI",
"(J)I",
(void*)jni_YGNodeStyleGetJustifyContentJNI},
{"jni_YGNodeStyleSetJustifyContentJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetJustifyContentJNI},
{"jni_YGNodeStyleGetAlignItemsJNI",
"(J)I",
(void*)jni_YGNodeStyleGetAlignItemsJNI},
{"jni_YGNodeStyleSetAlignItemsJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetAlignItemsJNI},
{"jni_YGNodeStyleGetAlignSelfJNI",
"(J)I",
(void*)jni_YGNodeStyleGetAlignSelfJNI},
{"jni_YGNodeStyleSetAlignSelfJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetAlignSelfJNI},
{"jni_YGNodeStyleGetAlignContentJNI",
"(J)I",
(void*)jni_YGNodeStyleGetAlignContentJNI},
{"jni_YGNodeStyleSetAlignContentJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetAlignContentJNI},
{"jni_YGNodeStyleGetPositionTypeJNI",
"(J)I",
(void*)jni_YGNodeStyleGetPositionTypeJNI},
{"jni_YGNodeStyleSetPositionTypeJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetPositionTypeJNI},
{"jni_YGNodeStyleGetFlexWrapJNI",
"(J)I",
(void*)jni_YGNodeStyleGetFlexWrapJNI},
{"jni_YGNodeStyleSetFlexWrapJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetFlexWrapJNI},
{"jni_YGNodeStyleGetOverflowJNI",
"(J)I",
(void*)jni_YGNodeStyleGetOverflowJNI},
{"jni_YGNodeStyleSetOverflowJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetOverflowJNI},
{"jni_YGNodeStyleGetDisplayJNI",
"(J)I",
(void*)jni_YGNodeStyleGetDisplayJNI},
{"jni_YGNodeStyleSetDisplayJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetDisplayJNI},
{"jni_YGNodeStyleGetFlexJNI", "(J)F", (void*)jni_YGNodeStyleGetFlexJNI},
{"jni_YGNodeStyleSetFlexJNI", "(JF)V", (void*)jni_YGNodeStyleSetFlexJNI},
{"jni_YGNodeStyleGetFlexGrowJNI",
"(J)F",
(void*)jni_YGNodeStyleGetFlexGrowJNI},
{"jni_YGNodeStyleSetFlexGrowJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetFlexGrowJNI},
{"jni_YGNodeStyleGetFlexShrinkJNI",
"(J)F",
(void*)jni_YGNodeStyleGetFlexShrinkJNI},
{"jni_YGNodeStyleSetFlexShrinkJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetFlexShrinkJNI},
{"jni_YGNodeStyleGetFlexBasisJNI",
"(J)J",
(void*)jni_YGNodeStyleGetFlexBasisJNI},
{"jni_YGNodeStyleSetFlexBasisJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetFlexBasisJNI},
{"jni_YGNodeStyleSetFlexBasisPercentJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetFlexBasisPercentJNI},
{"jni_YGNodeStyleSetFlexBasisAutoJNI",
"(J)V",
(void*)jni_YGNodeStyleSetFlexBasisAutoJNI},
{"jni_YGNodeStyleGetMarginJNI",
"(JI)J",
(void*)jni_YGNodeStyleGetMarginJNI},
{"jni_YGNodeStyleSetMarginJNI",
"(JIF)V",
(void*)jni_YGNodeStyleSetMarginJNI},
{"jni_YGNodeStyleSetMarginPercentJNI",
"(JIF)V",
(void*)jni_YGNodeStyleSetMarginPercentJNI},
{"jni_YGNodeStyleSetMarginAutoJNI",
"(JI)V",
(void*)jni_YGNodeStyleSetMarginAutoJNI},
{"jni_YGNodeStyleGetPaddingJNI",
"(JI)J",
(void*)jni_YGNodeStyleGetPaddingJNI},
{"jni_YGNodeStyleSetPaddingJNI",
"(JIF)V",
(void*)jni_YGNodeStyleSetPaddingJNI},
{"jni_YGNodeStyleSetPaddingPercentJNI",
"(JIF)V",
(void*)jni_YGNodeStyleSetPaddingPercentJNI},
{"jni_YGNodeStyleGetBorderJNI",
"(JI)F",
(void*)jni_YGNodeStyleGetBorderJNI},
{"jni_YGNodeStyleSetBorderJNI",
"(JIF)V",
(void*)jni_YGNodeStyleSetBorderJNI},
{"jni_YGNodeStyleGetPositionJNI",
"(JI)J",
(void*)jni_YGNodeStyleGetPositionJNI},
{"jni_YGNodeStyleSetPositionJNI",
"(JIF)V",
(void*)jni_YGNodeStyleSetPositionJNI},
{"jni_YGNodeStyleSetPositionPercentJNI",
"(JIF)V",
(void*)jni_YGNodeStyleSetPositionPercentJNI},
{"jni_YGNodeStyleGetWidthJNI", "(J)J", (void*)jni_YGNodeStyleGetWidthJNI},
{"jni_YGNodeStyleSetWidthJNI", "(JF)V", (void*)jni_YGNodeStyleSetWidthJNI},
{"jni_YGNodeStyleSetWidthPercentJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetWidthPercentJNI},
{"jni_YGNodeStyleSetWidthAutoJNI",
"(J)V",
(void*)jni_YGNodeStyleSetWidthAutoJNI},
{"jni_YGNodeStyleGetHeightJNI", "(J)J", (void*)jni_YGNodeStyleGetHeightJNI},
{"jni_YGNodeStyleSetHeightJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetHeightJNI},
{"jni_YGNodeStyleSetHeightPercentJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetHeightPercentJNI},
{"jni_YGNodeStyleSetHeightAutoJNI",
"(J)V",
(void*)jni_YGNodeStyleSetHeightAutoJNI},
{"jni_YGNodeStyleGetMinWidthJNI",
"(J)J",
(void*)jni_YGNodeStyleGetMinWidthJNI},
{"jni_YGNodeStyleSetMinWidthJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMinWidthJNI},
{"jni_YGNodeStyleSetMinWidthPercentJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMinWidthPercentJNI},
{"jni_YGNodeStyleGetMinHeightJNI",
"(J)J",
(void*)jni_YGNodeStyleGetMinHeightJNI},
{"jni_YGNodeStyleSetMinHeightJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMinHeightJNI},
{"jni_YGNodeStyleSetMinHeightPercentJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMinHeightPercentJNI},
{"jni_YGNodeStyleGetMaxWidthJNI",
"(J)J",
(void*)jni_YGNodeStyleGetMaxWidthJNI},
{"jni_YGNodeStyleSetMaxWidthJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMaxWidthJNI},
{"jni_YGNodeStyleSetMaxWidthPercentJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMaxWidthPercentJNI},
{"jni_YGNodeStyleGetMaxHeightJNI",
"(J)J",
(void*)jni_YGNodeStyleGetMaxHeightJNI},
{"jni_YGNodeStyleSetMaxHeightJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMaxHeightJNI},
{"jni_YGNodeStyleSetMaxHeightPercentJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetMaxHeightPercentJNI},
{"jni_YGNodeStyleGetAspectRatioJNI",
"(J)F",
(void*)jni_YGNodeStyleGetAspectRatioJNI},
{"jni_YGNodeStyleSetAspectRatioJNI",
"(JF)V",
(void*)jni_YGNodeStyleSetAspectRatioJNI},
{"jni_YGNodeSetHasMeasureFuncJNI",
"(JZ)V",
(void*)jni_YGNodeSetHasMeasureFuncJNI},
{"jni_YGNodeStyleGetGapJNI", "(JI)F", (void*)jni_YGNodeStyleGetGapJNI},
{"jni_YGNodeStyleSetGapJNI", "(JIF)V", (void*)jni_YGNodeStyleSetGapJNI},
{"jni_YGNodeSetHasBaselineFuncJNI",
"(JZ)V",
(void*)jni_YGNodeSetHasBaselineFuncJNI},
{"jni_YGNodeSetAlwaysFormsContainingBlockJNI",
"(JZ)V",
(void*)jni_YGNodeSetAlwaysFormsContainingBlockJNI},
{"jni_YGNodeCloneJNI", "(J)J", (void*)jni_YGNodeCloneJNI},
};
void YGJNIVanilla::registerNatives(JNIEnv* env) {
facebook::yoga::vanillajni::registerNatives(
env,
"com/facebook/yoga/YogaNative",
methods,
sizeof(methods) / sizeof(JNINativeMethod));
}