-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reviewed By: mdvacca Differential Revision: D7205065 fbshipit-source-id: 5876cb3e08ee96e39b80e6b377c60600f404ca21
- Loading branch information
1 parent
bec97dc
commit 3a2bdf5
Showing
6 changed files
with
416 additions
and
0 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
load("@xplat//ReactNative:DEFS.bzl", "react_native_dep", "react_native_target", "rn_android_library", "IS_OSS_BUILD") | ||
|
||
rn_android_library( | ||
name = "jsc", | ||
srcs = glob(["**/*.java"]), | ||
exported_deps = [ | ||
react_native_dep("java/com/facebook/jni:jni"), | ||
react_native_dep("java/com/facebook/proguard/annotations:annotations"), | ||
], | ||
provided_deps = [ | ||
react_native_dep("third-party/android/support/v4:lib-support-v4"), | ||
], | ||
required_for_source_only_abi = True, | ||
visibility = [ | ||
"PUBLIC", | ||
], | ||
deps = [ | ||
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), | ||
react_native_dep("third-party/java/infer-annotations:infer-annotations"), | ||
react_native_target("java/com/facebook/react/bridge:bridge"), | ||
react_native_target("java/com/facebook/react/fabric:fabric"), | ||
react_native_target("java/com/facebook/react/fabric/jsc/jni:jni"), | ||
], | ||
) |
35 changes: 35 additions & 0 deletions
35
ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Copyright 2004-present Facebook. All Rights Reserved. | ||
|
||
package com.facebook.react.fabric.jsc; | ||
|
||
import com.facebook.jni.HybridData; | ||
import com.facebook.proguard.annotations.DoNotStrip; | ||
import com.facebook.react.bridge.JavaScriptContextHolder; | ||
import com.facebook.react.fabric.FabricBinding; | ||
import com.facebook.react.fabric.FabricUIManager; | ||
import com.facebook.soloader.SoLoader; | ||
|
||
@DoNotStrip | ||
public class FabricJSCBinding implements FabricBinding { | ||
|
||
static { | ||
SoLoader.loadLibrary("fabricjscjni"); | ||
} | ||
|
||
// used from native | ||
@SuppressWarnings("unused") | ||
private final HybridData mHybridData; | ||
|
||
private static native HybridData initHybrid(); | ||
|
||
private native void installFabric(long jsContextNativePointer, Object fabricModule); | ||
|
||
public FabricJSCBinding() { | ||
mHybridData = initHybrid(); | ||
} | ||
|
||
@Override | ||
public void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule) { | ||
installFabric(jsContext.get(), fabricModule); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
load("@xplat//ReactNative:DEFS.bzl", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "FBJNI_TARGET", "ANDROID") | ||
|
||
rn_xplat_cxx_library( | ||
name = "jni", | ||
srcs = glob(["*.cpp"]), | ||
headers = glob(["*.h"]), | ||
compiler_flags = [ | ||
"-Wall", | ||
"-fexceptions", | ||
"-std=gnu++1y", | ||
], | ||
platforms = ANDROID, | ||
soname = "libfabricjscjni.$(ext)", | ||
visibility = ["PUBLIC"], | ||
deps = [ | ||
FBJNI_TARGET, | ||
react_native_xplat_target("jschelpers:jschelpers"), | ||
react_native_target("jni/react/jni:jni"), | ||
], | ||
) |
296 changes: 296 additions & 0 deletions
296
ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,296 @@ | ||
// Copyright 2004-present Facebook. All Rights Reserved. | ||
|
||
#include "FabricJSCBinding.h" | ||
#include <fb/fbjni.h> | ||
#include <react/jni/ReadableNativeMap.h> | ||
#include <jschelpers/JavaScriptCore.h> | ||
#include <jschelpers/Unicode.h> | ||
|
||
using namespace facebook::jni; | ||
|
||
namespace facebook { | ||
namespace react { | ||
|
||
namespace { | ||
|
||
bool useCustomJSC = false; | ||
|
||
struct JList : public JavaClass<JList> { | ||
static constexpr auto kJavaDescriptor = "Ljava/util/List;"; | ||
}; | ||
|
||
struct JShadowNode : public JavaClass<JShadowNode> { | ||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/uimanager/ReactShadowNode;"; | ||
}; | ||
|
||
typedef struct FabricJSCUIManager { | ||
FabricJSCUIManager(alias_ref<jobject> module, JSClassRef classRef, bool customJSC) | ||
: wrapperObjectClassRef(classRef) | ||
, useCustomJSC(customJSC) { | ||
fabricUiManager = make_global(module); | ||
} | ||
global_ref<jobject> fabricUiManager; | ||
JSClassRef wrapperObjectClassRef; | ||
bool useCustomJSC; | ||
} FabricJSCUIManager; | ||
|
||
jobject makePlainGlobalRef(jobject object) { | ||
// When storing the global reference we need it to be a plain | ||
// pointer. That's why we use plain jni instead of fbjni here. | ||
return Environment::current()->NewGlobalRef(object); | ||
} | ||
|
||
local_ref<JString> JSValueToJString(JSContextRef ctx, JSValueRef value) { | ||
JSStringRef strRef = JSC_JSValueToStringCopy(ctx, value, NULL); | ||
const size_t size = JSStringGetMaximumUTF8CStringSize(strRef); | ||
char buffer[size]; | ||
JSStringGetUTF8CString(strRef, buffer, size); | ||
JSC_JSStringRelease(ctx, strRef); | ||
return make_jstring(buffer); | ||
} | ||
|
||
local_ref<JShadowNode> JSValueToJShadowNode(JSContextRef ctx, JSValueRef value) { | ||
JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL); | ||
auto node = static_cast<JShadowNode::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj)); | ||
return make_local(node); | ||
} | ||
|
||
local_ref<JList> JSValueToJList(JSContextRef ctx, JSValueRef value) { | ||
JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL); | ||
auto node = static_cast<JList::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj)); | ||
return make_local(node); | ||
} | ||
|
||
local_ref<ReadableNativeMap::jhybridobject> JSValueToReadableMapViaJSON(JSContextRef ctx, JSValueRef value) { | ||
JSStringRef jsonRef = JSC_JSValueCreateJSONString(ctx, value, 0, NULL); | ||
size_t size = JSC_JSStringGetLength(ctx, jsonRef); | ||
const JSChar* utf16 = JSC_JSStringGetCharactersPtr(ctx, jsonRef); | ||
std::string json = unicode::utf16toUTF8(utf16, size); | ||
JSC_JSStringRelease(ctx, jsonRef); | ||
folly::dynamic dynamicValue = folly::parseJson(json); | ||
return ReadableNativeMap::newObjectCxxArgs(std::move(dynamicValue)); | ||
} | ||
|
||
JSValueRef createNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
JSClassRef classRef = managerWrapper->wrapperObjectClassRef; | ||
|
||
static auto createNode = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<alias_ref<JShadowNode>(jint, jstring, jint, ReadableNativeMap::javaobject)>("createNode"); | ||
|
||
int reactTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL); | ||
auto viewName = JSValueToJString(ctx, arguments[1]); | ||
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[2], NULL); | ||
auto props = JSC_JSValueIsNull(ctx, arguments[3]) ? local_ref<ReadableNativeMap::jhybridobject>(nullptr) : | ||
JSValueToReadableMapViaJSON(ctx, arguments[3]);; | ||
|
||
// TODO: Retain object in arguments[4] using a weak ref. | ||
|
||
auto node = createNode(manager, reactTag, viewName.get(), rootTag, props.get()); | ||
|
||
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(node.get())); | ||
} | ||
|
||
JSValueRef cloneNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
JSClassRef classRef = managerWrapper->wrapperObjectClassRef; | ||
|
||
static auto cloneNode = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNode"); | ||
|
||
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); | ||
auto newNode = cloneNode(manager, previousNode.get()); | ||
|
||
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); | ||
} | ||
|
||
JSValueRef cloneNodeWithNewChildren(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
JSClassRef classRef = managerWrapper->wrapperObjectClassRef; | ||
|
||
static auto cloneNodeWithNewChildren = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNodeWithNewChildren"); | ||
|
||
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); | ||
auto newNode = cloneNodeWithNewChildren(manager, previousNode.get()); | ||
|
||
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); | ||
} | ||
|
||
JSValueRef cloneNodeWithNewProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
JSClassRef classRef = managerWrapper->wrapperObjectClassRef; | ||
|
||
static auto cloneNodeWithNewProps = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewProps"); | ||
|
||
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); | ||
auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]); | ||
auto newNode = cloneNodeWithNewProps(manager, previousNode.get(), props.get()); | ||
|
||
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); | ||
} | ||
|
||
JSValueRef cloneNodeWithNewChildrenAndProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
JSClassRef classRef = managerWrapper->wrapperObjectClassRef; | ||
|
||
static auto cloneNodeWithNewChildrenAndProps = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewChildrenAndProps"); | ||
|
||
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); | ||
auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]); | ||
auto newNode = cloneNodeWithNewChildrenAndProps(manager, previousNode.get(), props.get()); | ||
|
||
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); | ||
} | ||
|
||
JSValueRef appendChild(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
|
||
static auto appendChild = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<void(JShadowNode::javaobject, JShadowNode::javaobject)>("appendChild"); | ||
|
||
auto parentNode = JSValueToJShadowNode(ctx, arguments[0]); | ||
auto childNode = JSValueToJShadowNode(ctx, arguments[1]); | ||
|
||
appendChild(manager, parentNode.get(), childNode.get()); | ||
|
||
return JSC_JSValueMakeUndefined(ctx); | ||
} | ||
|
||
JSValueRef createChildSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
JSClassRef classRef = managerWrapper->wrapperObjectClassRef; | ||
|
||
static auto createChildSet = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<alias_ref<JList>(jint)>("createChildSet"); | ||
|
||
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL); | ||
auto childSet = createChildSet(manager, rootTag); | ||
|
||
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(childSet.get())); | ||
} | ||
|
||
JSValueRef appendChildToSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
|
||
static auto appendChildToSet = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<void(JList::javaobject, JShadowNode::javaobject)>("appendChildToSet"); | ||
|
||
auto childSet = JSValueToJList(ctx, arguments[0]); | ||
auto childNode = JSValueToJShadowNode(ctx, arguments[1]); | ||
|
||
appendChildToSet(manager, childSet.get(), childNode.get()); | ||
|
||
return JSC_JSValueMakeUndefined(ctx); | ||
} | ||
|
||
JSValueRef completeRoot(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); | ||
alias_ref<jobject> manager = managerWrapper->fabricUiManager; | ||
|
||
static auto completeRoot = | ||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") | ||
->getMethod<void(jint, JList::javaobject)>("completeRoot"); | ||
|
||
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL); | ||
auto childSet = JSValueToJList(ctx, arguments[1]); | ||
|
||
completeRoot(manager, rootTag, childSet.get()); | ||
|
||
return JSC_JSValueMakeUndefined(ctx); | ||
} | ||
|
||
void finalizeJNIObject(JSObjectRef object) { | ||
// Release whatever global ref object we're storing here. | ||
jobject globalRef = (jobject)JSC_JSObjectGetPrivate(useCustomJSC, object); | ||
Environment::current()->DeleteGlobalRef(globalRef); | ||
} | ||
|
||
void finalizeWrapper(JSObjectRef object) { | ||
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, object); | ||
delete managerWrapper; | ||
} | ||
|
||
void addFabricMethod( | ||
JSContextRef context, | ||
jni::alias_ref<jobject> fabricModule, | ||
JSClassRef nodeClassRef, | ||
JSObjectRef module, | ||
const char *name, | ||
JSObjectCallAsFunctionCallback callback | ||
) { | ||
JSClassDefinition definition = kJSClassDefinitionEmpty; | ||
definition.callAsFunction = callback; | ||
definition.finalize = finalizeWrapper; | ||
JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition); | ||
FabricJSCUIManager *managerWrapper = new FabricJSCUIManager(fabricModule, nodeClassRef, useCustomJSC); | ||
JSObjectRef functionRef = JSC_JSObjectMake(context, classRef, managerWrapper); | ||
JSC_JSClassRelease(useCustomJSC, classRef); | ||
|
||
JSStringRef nameStr = JSC_JSStringCreateWithUTF8CString(context, name); | ||
JSC_JSObjectSetProperty(context, module, nameStr, functionRef, kJSPropertyAttributeNone, NULL); | ||
JSC_JSStringRelease(context, nameStr); | ||
} | ||
|
||
} | ||
|
||
jni::local_ref<FabricJSCBinding::jhybriddata> FabricJSCBinding::initHybrid( | ||
jni::alias_ref<jclass>) { | ||
return makeCxxInstance(); | ||
} | ||
|
||
void FabricJSCBinding::installFabric(jlong jsContextNativePointer, | ||
jni::alias_ref<jobject> fabricModule) { | ||
JSContextRef context = (JSContextRef)jsContextNativePointer; | ||
useCustomJSC = facebook::react::isCustomJSCPtr(context); | ||
|
||
JSObjectRef module = JSC_JSObjectMake(context, NULL, NULL); | ||
|
||
// Class definition for wrapper objects around nodes and sets | ||
JSClassDefinition definition = kJSClassDefinitionEmpty; | ||
definition.finalize = finalizeJNIObject; | ||
JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition); | ||
|
||
addFabricMethod(context, fabricModule, classRef, module, "createNode", createNode); | ||
addFabricMethod(context, fabricModule, classRef, module, "cloneNode", cloneNode); | ||
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildren", cloneNodeWithNewChildren); | ||
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewProps", cloneNodeWithNewProps); | ||
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildrenAndProps", cloneNodeWithNewChildrenAndProps); | ||
addFabricMethod(context, fabricModule, classRef, module, "appendChild", appendChild); | ||
addFabricMethod(context, fabricModule, classRef, module, "createChildSet", createChildSet); | ||
addFabricMethod(context, fabricModule, classRef, module, "appendChildToSet", appendChildToSet); | ||
addFabricMethod(context, fabricModule, classRef, module, "completeRoot", completeRoot); | ||
|
||
JSObjectRef globalObject = JSC_JSContextGetGlobalObject(context); | ||
JSStringRef globalName = JSC_JSStringCreateWithUTF8CString(context, "nativeFabricUIManager"); | ||
JSC_JSObjectSetProperty(context, globalObject, globalName, module, kJSPropertyAttributeNone, NULL); | ||
JSC_JSStringRelease(context, globalName); | ||
} | ||
|
||
void FabricJSCBinding::registerNatives() { | ||
registerHybrid({ | ||
makeNativeMethod("initHybrid", FabricJSCBinding::initHybrid), | ||
makeNativeMethod("installFabric", FabricJSCBinding::installFabric), | ||
}); | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.
3a2bdf5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ayc1 This module seems forget add to
Android.mk
support.3a2bdf5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ayc1 @gengjiawen @hramos
Will this break OSS builds? If so should we create a GitHub issue for it? I can create if you want.