Refactor uimanager stuff a bit
Summary: Simplies UIManager a bit and some other tweaks Reviewed By: shergin Differential Revision: D10211883 fbshipit-source-id: 93ab23dd2baab2fdc6d9c54e976b001a19efab7f
This commit is contained in:
parent
8258b6a280
commit
83da74b556
|
@ -33,6 +33,9 @@ inline void fromDynamic(const folly::dynamic &value, double &result) {
|
|||
inline void fromDynamic(const folly::dynamic &value, std::string &result) {
|
||||
result = value.getString();
|
||||
}
|
||||
inline void fromDynamic(const folly::dynamic &value, folly::dynamic &result) {
|
||||
result = value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void fromDynamic(const folly::dynamic &value, std::vector<T> &result) {
|
||||
|
|
|
@ -27,7 +27,7 @@ class ShadowNode;
|
|||
|
||||
using SharedShadowNode = std::shared_ptr<const ShadowNode>;
|
||||
using UnsharedShadowNode = std::shared_ptr<ShadowNode>;
|
||||
using SharedShadowNodeList = std::vector<std::shared_ptr<const ShadowNode>>;
|
||||
using SharedShadowNodeList = std::vector<SharedShadowNode>;
|
||||
using SharedShadowNodeSharedList = std::shared_ptr<const SharedShadowNodeList>;
|
||||
using SharedShadowNodeUnsharedList = std::shared_ptr<SharedShadowNodeList>;
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "ComponentDescriptorRegistry.h"
|
||||
|
||||
#include <fabric/core/ShadowNodeFragment.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
|
@ -33,5 +35,83 @@ const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](
|
|||
return it->second;
|
||||
}
|
||||
|
||||
static const std::string componentNameByReactViewName(std::string viewName) {
|
||||
// We need this function only for the transition period;
|
||||
// eventually, all names will be unified.
|
||||
|
||||
std::string rctPrefix("RCT");
|
||||
if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin())
|
||||
.first == rctPrefix.end()) {
|
||||
// If `viewName` has "RCT" prefix, remove it.
|
||||
viewName.erase(0, rctPrefix.length());
|
||||
}
|
||||
|
||||
// Fabric uses slightly new names for Text components because of differences
|
||||
// in semantic.
|
||||
if (viewName == "Text") {
|
||||
return "Paragraph";
|
||||
}
|
||||
if (viewName == "VirtualText") {
|
||||
return "Text";
|
||||
}
|
||||
|
||||
if (viewName == "ImageView") {
|
||||
return "Image";
|
||||
}
|
||||
|
||||
if (viewName == "AndroidHorizontalScrollView") {
|
||||
return "ScrollView";
|
||||
}
|
||||
|
||||
if (viewName == "AndroidProgressBar") {
|
||||
return "ActivityIndicatorView";
|
||||
}
|
||||
|
||||
// We need this temporarly for testing purposes until we have proper
|
||||
// implementation of core components.
|
||||
if (viewName == "SinglelineTextInputView" ||
|
||||
viewName == "MultilineTextInputView" || viewName == "RefreshControl" ||
|
||||
viewName == "SafeAreaView" || viewName == "ScrollContentView" ||
|
||||
viewName == "AndroidHorizontalScrollContentView" // Android
|
||||
) {
|
||||
return "View";
|
||||
}
|
||||
|
||||
return viewName;
|
||||
}
|
||||
|
||||
static const RawProps rawPropsFromDynamic(const folly::dynamic object) {
|
||||
// TODO: Convert this to something smarter, probably returning `std::iterator`.
|
||||
RawProps result;
|
||||
|
||||
if (object.isNull()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
assert(object.isObject());
|
||||
|
||||
for (const auto &pair : object.items()) {
|
||||
assert(pair.first.isString());
|
||||
result[pair.first.asString()] = pair.second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SharedShadowNode ComponentDescriptorRegistry::createNode(Tag tag, const std::string &viewName, Tag rootTag, const folly::dynamic &props, const SharedEventTarget &eventTarget) const {
|
||||
ComponentName componentName = componentNameByReactViewName(viewName);
|
||||
const SharedComponentDescriptor &componentDescriptor = (*this)[componentName];
|
||||
RawProps rawProps = rawPropsFromDynamic(props);
|
||||
|
||||
SharedShadowNode shadowNode =
|
||||
componentDescriptor->createShadowNode({
|
||||
.tag = tag,
|
||||
.rootTag = rootTag,
|
||||
.eventEmitter = componentDescriptor->createEventEmitter(std::move(eventTarget), tag),
|
||||
.props = componentDescriptor->cloneProps(nullptr, rawProps)
|
||||
});
|
||||
return shadowNode;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
|
|
@ -29,6 +29,8 @@ class ComponentDescriptorRegistry {
|
|||
const SharedShadowNode &shadowNode) const;
|
||||
const SharedComponentDescriptor operator[](
|
||||
const ComponentName &componentName) const;
|
||||
SharedShadowNode createNode(
|
||||
Tag tag, const std::string &viewName, Tag rootTag, const folly::dynamic &props, const SharedEventTarget &eventTarget) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<ComponentHandle, SharedComponentDescriptor>
|
||||
|
|
|
@ -40,51 +40,6 @@ static const RawProps rawPropsFromDynamic(const folly::dynamic object) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static const std::string componentNameByReactViewName(std::string viewName) {
|
||||
// We need this function only for the transition period;
|
||||
// eventually, all names will be unified.
|
||||
|
||||
std::string rctPrefix("RCT");
|
||||
if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin())
|
||||
.first == rctPrefix.end()) {
|
||||
// If `viewName` has "RCT" prefix, remove it.
|
||||
viewName.erase(0, rctPrefix.length());
|
||||
}
|
||||
|
||||
// Fabric uses slightly new names for Text components because of differences
|
||||
// in semantic.
|
||||
if (viewName == "Text") {
|
||||
return "Paragraph";
|
||||
}
|
||||
if (viewName == "VirtualText") {
|
||||
return "Text";
|
||||
}
|
||||
|
||||
if (viewName == "ImageView") {
|
||||
return "Image";
|
||||
}
|
||||
|
||||
if (viewName == "AndroidHorizontalScrollView") {
|
||||
return "ScrollView";
|
||||
}
|
||||
|
||||
if (viewName == "AndroidProgressBar") {
|
||||
return "ActivityIndicatorView";
|
||||
}
|
||||
|
||||
// We need this temporarly for testing purposes until we have proper
|
||||
// implementation of core components.
|
||||
if (viewName == "SinglelineTextInputView" ||
|
||||
viewName == "MultilineTextInputView" || viewName == "RefreshControl" ||
|
||||
viewName == "SafeAreaView" || viewName == "ScrollContentView" ||
|
||||
viewName == "AndroidHorizontalScrollContentView" // Android
|
||||
) {
|
||||
return "View";
|
||||
}
|
||||
|
||||
return viewName;
|
||||
}
|
||||
|
||||
FabricUIManager::FabricUIManager(
|
||||
std::unique_ptr<EventBeatBasedExecutor> executor,
|
||||
std::function<UIManagerInstaller> installer,
|
||||
|
@ -168,28 +123,11 @@ void FabricUIManager::stopSurface(SurfaceId surfaceId) const {
|
|||
(*executor_)([this, surfaceId] { stopSurfaceFunction_(surfaceId); });
|
||||
}
|
||||
|
||||
SharedShadowNode FabricUIManager::createNode(
|
||||
int tag,
|
||||
std::string viewName,
|
||||
int rootTag,
|
||||
folly::dynamic props,
|
||||
SharedEventTarget eventTarget) const {
|
||||
ComponentName componentName = componentNameByReactViewName(viewName);
|
||||
const SharedComponentDescriptor &componentDescriptor =
|
||||
(*componentDescriptorRegistry_)[componentName];
|
||||
RawProps rawProps = rawPropsFromDynamic(props);
|
||||
|
||||
SharedShadowNode shadowNode = componentDescriptor->createShadowNode(
|
||||
{.tag = tag,
|
||||
.rootTag = rootTag,
|
||||
.eventEmitter =
|
||||
componentDescriptor->createEventEmitter(std::move(eventTarget), tag),
|
||||
.props = componentDescriptor->cloneProps(nullptr, rawProps)});
|
||||
|
||||
SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, SharedEventTarget eventTarget) const {
|
||||
SharedShadowNode shadowNode = componentDescriptorRegistry_->createNode(tag, viewName, rootTag, props, eventTarget);
|
||||
if (delegate_) {
|
||||
delegate_->uiManagerDidCreateShadowNode(shadowNode);
|
||||
}
|
||||
|
||||
return shadowNode;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <fabric/core/LayoutContext.h>
|
||||
#include <fabric/uimanager/ComponentDescriptorRegistry.h>
|
||||
#include <fabric/uimanager/FabricUIManager.h>
|
||||
#include <fabric/uimanager/TemplateRenderer.h>
|
||||
|
||||
#include "ComponentDescriptorFactory.h"
|
||||
#include "Differentiator.h"
|
||||
|
@ -39,9 +40,11 @@ Scheduler::Scheduler(const SharedContextContainer &contextContainer)
|
|||
synchronousEventBeatFactory,
|
||||
asynchronousEventBeatFactory);
|
||||
|
||||
componentDescriptorRegistry_ = ComponentDescriptorFactory::buildRegistry(
|
||||
eventDispatcher, contextContainer);
|
||||
uiManager_->setComponentDescriptorRegistry(
|
||||
ComponentDescriptorFactory::buildRegistry(
|
||||
eventDispatcher, contextContainer));
|
||||
componentDescriptorRegistry_
|
||||
);
|
||||
|
||||
uiManager_->setDelegate(this);
|
||||
}
|
||||
|
@ -55,7 +58,7 @@ void Scheduler::startSurface(
|
|||
const std::string &moduleName,
|
||||
const folly::dynamic &initialProps,
|
||||
const LayoutConstraints &layoutConstraints,
|
||||
const LayoutContext &layoutContext) const {
|
||||
const LayoutContext &layoutContext) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
auto shadowTree =
|
||||
|
@ -64,7 +67,18 @@ void Scheduler::startSurface(
|
|||
shadowTreeRegistry_.emplace(surfaceId, std::move(shadowTree));
|
||||
|
||||
#ifndef ANDROID
|
||||
uiManager_->startSurface(surfaceId, moduleName, initialProps);
|
||||
|
||||
// TODO: Is this an ok place to do this?
|
||||
auto serializedCommands = initialProps.find("serializedCommands");
|
||||
if (serializedCommands != initialProps.items().end()) {
|
||||
auto tree = TemplateRenderer::buildShadowTree(serializedCommands->second.asString(), surfaceId, folly::dynamic::object(), *componentDescriptorRegistry_);
|
||||
|
||||
uiManagerDidFinishTransactionWithoutLock(surfaceId, std::make_shared<SharedShadowNodeList>(SharedShadowNodeList {tree}));
|
||||
// TODO: hydrate rather than replace
|
||||
uiManager_->startSurface(surfaceId, moduleName, initialProps);
|
||||
} else {
|
||||
uiManager_->startSurface(surfaceId, moduleName, initialProps);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -107,6 +121,16 @@ void Scheduler::constraintSurfaceLayout(
|
|||
});
|
||||
}
|
||||
|
||||
void Scheduler::uiManagerDidFinishTransactionWithoutLock(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) {
|
||||
const auto iterator = shadowTreeRegistry_.find(rootTag);
|
||||
if (iterator == shadowTreeRegistry_.end()) {
|
||||
// This might happen during surface unmounting/deallocation process
|
||||
// due to the asynchronous nature of JS calls.
|
||||
return;
|
||||
}
|
||||
iterator->second->complete(rootChildNodes);
|
||||
}
|
||||
|
||||
#pragma mark - Delegate
|
||||
|
||||
void Scheduler::setDelegate(SchedulerDelegate *delegate) {
|
||||
|
@ -134,15 +158,7 @@ void Scheduler::uiManagerDidFinishTransaction(
|
|||
Tag rootTag,
|
||||
const SharedShadowNodeUnsharedList &rootChildNodes) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
const auto iterator = shadowTreeRegistry_.find(rootTag);
|
||||
if (iterator == shadowTreeRegistry_.end()) {
|
||||
// This might happen during surface unmounting/deallocation process
|
||||
// due to the asynchronous nature of JS calls.
|
||||
return;
|
||||
}
|
||||
|
||||
iterator->second->complete(rootChildNodes);
|
||||
uiManagerDidFinishTransactionWithoutLock(rootTag, rootChildNodes);
|
||||
}
|
||||
|
||||
void Scheduler::uiManagerDidCreateShadowNode(
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <fabric/core/ComponentDescriptor.h>
|
||||
#include <fabric/core/LayoutConstraints.h>
|
||||
#include <fabric/uimanager/ComponentDescriptorRegistry.h>
|
||||
#include <fabric/uimanager/ContextContainer.h>
|
||||
#include <fabric/uimanager/SchedulerDelegate.h>
|
||||
#include <fabric/uimanager/ShadowTree.h>
|
||||
|
@ -36,7 +37,7 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate {
|
|||
const std::string &moduleName,
|
||||
const folly::dynamic &initialProps,
|
||||
const LayoutConstraints &layoutConstraints = {},
|
||||
const LayoutContext &layoutContext = {}) const;
|
||||
const LayoutContext &layoutContext = {});
|
||||
|
||||
void stopSurface(SurfaceId surfaceId) const;
|
||||
|
||||
|
@ -91,11 +92,15 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate {
|
|||
private:
|
||||
SchedulerDelegate *delegate_;
|
||||
std::shared_ptr<FabricUIManager> uiManager_;
|
||||
SharedComponentDescriptorRegistry componentDescriptorRegistry_;
|
||||
mutable std::mutex mutex_;
|
||||
mutable std::unordered_map<SurfaceId, std::unique_ptr<ShadowTree>>
|
||||
shadowTreeRegistry_; // Protected by `mutex_`.
|
||||
SharedEventDispatcher eventDispatcher_;
|
||||
SharedContextContainer contextContainer_;
|
||||
|
||||
void uiManagerDidFinishTransactionWithoutLock(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes);
|
||||
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "TemplateRenderer.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <fabric/components/view/ViewComponentDescriptor.h>
|
||||
#include <fabric/components/view/ViewProps.h>
|
||||
#include <fabric/components/view/ViewShadowNode.h>
|
||||
#include <fabric/core/componentDescriptor.h>
|
||||
#include <fabric/core/LayoutContext.h>
|
||||
#include <fabric/core/ShadowNodeFragment.h>
|
||||
#include <fabric/debug/DebugStringConvertible.h>
|
||||
#include <fabric/debug/DebugStringConvertibleItem.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
SharedShadowNode TemplateRenderer::buildShadowTree(const std::string &jsonStr, int rootTag, const folly::dynamic ¶ms, const ComponentDescriptorRegistry &componentDescriptorRegistry) {
|
||||
LOG(INFO) << "(strt) TemplateRenderer inject hardcoded 'server rendered' view tree";
|
||||
std::string content = jsonStr;
|
||||
for (const auto& param : params.items()) {
|
||||
const auto& key = param.first.asString();
|
||||
size_t start_pos = content.find(key);
|
||||
if(start_pos != std::string::npos) {
|
||||
content.replace(start_pos, key.length(), param.second.asString());
|
||||
}
|
||||
}
|
||||
auto json = folly::parseJson(content);
|
||||
std::vector<SharedShadowNode> nodes;
|
||||
nodes.resize(json.size() * 2);
|
||||
int tagOffset = 4560; // MAYBE TODO: use number of existing tags so they don't collide rather than random value
|
||||
for (const auto& command : json) {
|
||||
if (command[0] == "createNode") {
|
||||
int tag = command[1].asInt();
|
||||
const auto& type = command[2].asString();
|
||||
const auto& props = command[3];
|
||||
nodes[tag] = componentDescriptorRegistry.createNode(tag + tagOffset, type, rootTag, props, nullptr);
|
||||
} else if (command[0] == "appendChild") {
|
||||
auto parentShadowNode = nodes[command[1].asInt()];
|
||||
const SharedComponentDescriptor &componentDescriptor = componentDescriptorRegistry[parentShadowNode];
|
||||
componentDescriptor->appendChild(parentShadowNode, nodes[command[2].asInt()]);
|
||||
} else if (command[0] == "childSetNode") {
|
||||
LOG(INFO) << "(stop) TemplateView inject serialized 'server rendered' view tree";
|
||||
return nodes[command[1].asInt()];
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Missing childSetNode command in template content:\n" + content);
|
||||
return SharedShadowNode {};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
|
||||
#include <fabric/core/ShadowNode.h>
|
||||
#include <fabric/uimanager/ComponentDescriptorRegistry.h>
|
||||
#include <fabric/uimanager/UIManagerDelegate.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
class TemplateRenderer {
|
||||
public:
|
||||
static SharedShadowNode buildShadowTree(const std::string &jsonStr, int rootTag, const folly::dynamic ¶ms, const ComponentDescriptorRegistry &componentDescriptorRegistry);
|
||||
};
|
||||
} // react
|
||||
} // facebook
|
Loading…
Reference in New Issue