basalt-core 0.0.0-rc5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cli/basalt.d.ts +3 -0
- package/dist/cli/basalt.d.ts.map +1 -0
- package/dist/cli/basalt.js +47 -0
- package/dist/cli/basalt.js.map +1 -0
- package/dist/cli/bundle-cli.d.ts +12 -0
- package/dist/cli/bundle-cli.d.ts.map +1 -0
- package/dist/cli/bundle-cli.js +124 -0
- package/dist/cli/bundle-cli.js.map +1 -0
- package/dist/cli/bundleWithAssets.d.ts +79 -0
- package/dist/cli/bundleWithAssets.d.ts.map +1 -0
- package/dist/cli/bundleWithAssets.js +198 -0
- package/dist/cli/bundleWithAssets.js.map +1 -0
- package/dist/cli/desktop.d.ts +339 -0
- package/dist/cli/desktop.d.ts.map +1 -0
- package/dist/cli/desktop.js +1029 -0
- package/dist/cli/desktop.js.map +1 -0
- package/dist/cli/doctor.d.ts +31 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +283 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.d.ts +77 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +442 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/metro.d.ts +49 -0
- package/dist/cli/metro.d.ts.map +1 -0
- package/dist/cli/metro.js +148 -0
- package/dist/cli/metro.js.map +1 -0
- package/dist/cli/packageApp.d.ts +102 -0
- package/dist/cli/packageApp.d.ts.map +1 -0
- package/dist/cli/packageApp.js +319 -0
- package/dist/cli/packageApp.js.map +1 -0
- package/dist/cli/steps.d.ts +34 -0
- package/dist/cli/steps.d.ts.map +1 -0
- package/dist/cli/steps.js +53 -0
- package/dist/cli/steps.js.map +1 -0
- package/dist/metro-config.d.ts +168 -0
- package/dist/metro-config.d.ts.map +1 -0
- package/dist/metro-config.js +671 -0
- package/dist/metro-config.js.map +1 -0
- package/dist/react-native.config.d.ts +7 -0
- package/dist/react-native.config.d.ts.map +1 -0
- package/dist/react-native.config.js +80 -0
- package/dist/react-native.config.js.map +1 -0
- package/dist/src/DragSource.d.ts +52 -0
- package/dist/src/DragSource.d.ts.map +1 -0
- package/dist/src/DragSource.js +97 -0
- package/dist/src/DragSource.js.map +1 -0
- package/dist/src/DropTarget.d.ts +58 -0
- package/dist/src/DropTarget.d.ts.map +1 -0
- package/dist/src/DropTarget.js +131 -0
- package/dist/src/DropTarget.js.map +1 -0
- package/dist/src/KeyHandler.d.ts +57 -0
- package/dist/src/KeyHandler.d.ts.map +1 -0
- package/dist/src/KeyHandler.js +48 -0
- package/dist/src/KeyHandler.js.map +1 -0
- package/dist/src/Menu.d.ts +72 -0
- package/dist/src/Menu.d.ts.map +1 -0
- package/dist/src/Menu.js +179 -0
- package/dist/src/Menu.js.map +1 -0
- package/dist/src/TitleBar.d.ts +75 -0
- package/dist/src/TitleBar.d.ts.map +1 -0
- package/dist/src/TitleBar.js +236 -0
- package/dist/src/TitleBar.js.map +1 -0
- package/dist/src/Window.d.ts +87 -0
- package/dist/src/Window.d.ts.map +1 -0
- package/dist/src/Window.js +248 -0
- package/dist/src/Window.js.map +1 -0
- package/dist/src/closeRequest.d.ts +55 -0
- package/dist/src/closeRequest.d.ts.map +1 -0
- package/dist/src/closeRequest.js +134 -0
- package/dist/src/closeRequest.js.map +1 -0
- package/dist/src/index.d.ts +45 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +92 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/overrides/Alert.d.ts +69 -0
- package/dist/src/overrides/Alert.d.ts.map +1 -0
- package/dist/src/overrides/Alert.js +112 -0
- package/dist/src/overrides/Alert.js.map +1 -0
- package/dist/src/overrides/BaseViewConfig.d.ts +28 -0
- package/dist/src/overrides/BaseViewConfig.d.ts.map +1 -0
- package/dist/src/overrides/BaseViewConfig.js +72 -0
- package/dist/src/overrides/BaseViewConfig.js.map +1 -0
- package/dist/src/overrides/Platform.linux.d.ts +10 -0
- package/dist/src/overrides/Platform.linux.d.ts.map +1 -0
- package/dist/src/overrides/Platform.linux.js +15 -0
- package/dist/src/overrides/Platform.linux.js.map +1 -0
- package/dist/src/overrides/Platform.macos.d.ts +10 -0
- package/dist/src/overrides/Platform.macos.d.ts.map +1 -0
- package/dist/src/overrides/Platform.macos.js +15 -0
- package/dist/src/overrides/Platform.macos.js.map +1 -0
- package/dist/src/overrides/Platform.windows.d.ts +10 -0
- package/dist/src/overrides/Platform.windows.d.ts.map +1 -0
- package/dist/src/overrides/Platform.windows.js +15 -0
- package/dist/src/overrides/Platform.windows.js.map +1 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts +24 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.d.ts.map +1 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.js +30 -0
- package/dist/src/overrides/ReactDevToolsSettingsManager.js.map +1 -0
- package/dist/src/overrides/RefreshControl.d.ts +52 -0
- package/dist/src/overrides/RefreshControl.d.ts.map +1 -0
- package/dist/src/overrides/RefreshControl.js +92 -0
- package/dist/src/overrides/RefreshControl.js.map +1 -0
- package/dist/src/overrides/ScrollView.d.ts +39 -0
- package/dist/src/overrides/ScrollView.d.ts.map +1 -0
- package/dist/src/overrides/ScrollView.js +59 -0
- package/dist/src/overrides/ScrollView.js.map +1 -0
- package/dist/src/overrides/Share.d.ts +96 -0
- package/dist/src/overrides/Share.d.ts.map +1 -0
- package/dist/src/overrides/Share.js +97 -0
- package/dist/src/overrides/Share.js.map +1 -0
- package/dist/src/overrides/TextInput.d.ts +81 -0
- package/dist/src/overrides/TextInput.d.ts.map +1 -0
- package/dist/src/overrides/TextInput.js +213 -0
- package/dist/src/overrides/TextInput.js.map +1 -0
- package/dist/src/overrides/View.d.ts +36 -0
- package/dist/src/overrides/View.d.ts.map +1 -0
- package/dist/src/overrides/View.js +99 -0
- package/dist/src/overrides/View.js.map +1 -0
- package/dist/src/overrides/createPlatform.d.ts +32 -0
- package/dist/src/overrides/createPlatform.d.ts.map +1 -0
- package/dist/src/overrides/createPlatform.js +84 -0
- package/dist/src/overrides/createPlatform.js.map +1 -0
- package/dist/src/overrides/setUpDeveloperTools.d.ts +28 -0
- package/dist/src/overrides/setUpDeveloperTools.d.ts.map +1 -0
- package/dist/src/overrides/setUpDeveloperTools.js +84 -0
- package/dist/src/overrides/setUpDeveloperTools.js.map +1 -0
- package/dist/src/overrides/setUpXHR.d.ts +46 -0
- package/dist/src/overrides/setUpXHR.d.ts.map +1 -0
- package/dist/src/overrides/setUpXHR.js +236 -0
- package/dist/src/overrides/setUpXHR.js.map +1 -0
- package/dist/src/quitRequest.d.ts +55 -0
- package/dist/src/quitRequest.d.ts.map +1 -0
- package/dist/src/quitRequest.js +121 -0
- package/dist/src/quitRequest.js.map +1 -0
- package/dist/src/resourcePath.d.ts +18 -0
- package/dist/src/resourcePath.d.ts.map +1 -0
- package/dist/src/resourcePath.js +31 -0
- package/dist/src/resourcePath.js.map +1 -0
- package/dist/src/responseBody.d.ts +76 -0
- package/dist/src/responseBody.d.ts.map +1 -0
- package/dist/src/responseBody.js +94 -0
- package/dist/src/responseBody.js.map +1 -0
- package/dist/src/responseHeaders.d.ts +40 -0
- package/dist/src/responseHeaders.d.ts.map +1 -0
- package/dist/src/responseHeaders.js +75 -0
- package/dist/src/responseHeaders.js.map +1 -0
- package/dist/src/titleBarState.d.ts +43 -0
- package/dist/src/titleBarState.d.ts.map +1 -0
- package/dist/src/titleBarState.js +77 -0
- package/dist/src/titleBarState.js.map +1 -0
- package/dist/src/useContextMenu.d.ts +113 -0
- package/dist/src/useContextMenu.d.ts.map +1 -0
- package/dist/src/useContextMenu.js +109 -0
- package/dist/src/useContextMenu.js.map +1 -0
- package/dist/src/useDialog.d.ts +98 -0
- package/dist/src/useDialog.d.ts.map +1 -0
- package/dist/src/useDialog.js +112 -0
- package/dist/src/useDialog.js.map +1 -0
- package/dist/src/useDisplays.d.ts +70 -0
- package/dist/src/useDisplays.d.ts.map +1 -0
- package/dist/src/useDisplays.js +118 -0
- package/dist/src/useDisplays.js.map +1 -0
- package/dist/src/useHandledKeys.d.ts +38 -0
- package/dist/src/useHandledKeys.d.ts.map +1 -0
- package/dist/src/useHandledKeys.js +70 -0
- package/dist/src/useHandledKeys.js.map +1 -0
- package/dist/src/useWindow.d.ts +140 -0
- package/dist/src/useWindow.d.ts.map +1 -0
- package/dist/src/useWindow.js +233 -0
- package/dist/src/useWindow.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/native/CMakeLists.txt +355 -0
- package/native/bootstrap.sh +613 -0
- package/native/cmake/CompilerFlags.cmake +49 -0
- package/native/cmake/Expo.cmake +125 -0
- package/native/cmake/ReactNativeCore.cmake +612 -0
- package/native/cmake/Reanimated.cmake +108 -0
- package/native/cmake/Skia.cmake +379 -0
- package/native/cmake/ThirdParty.cmake +290 -0
- package/native/cmake/Worklets.cmake +67 -0
- package/native/cmake/codegen/CMakeLists.txt +32 -0
- package/native/core/AppIdentity.cpp +85 -0
- package/native/core/AppIdentity.h +59 -0
- package/native/core/AppPaths.cpp +96 -0
- package/native/core/AppPaths.h +53 -0
- package/native/core/AppearanceModule.cpp +60 -0
- package/native/core/AppearanceModule.h +40 -0
- package/native/core/Backface.h +59 -0
- package/native/core/BlobModule.cpp +283 -0
- package/native/core/BlobModule.h +76 -0
- package/native/core/BlobRegistry.cpp +75 -0
- package/native/core/BlobRegistry.h +44 -0
- package/native/core/ColorScheme.cpp +105 -0
- package/native/core/ColorScheme.h +59 -0
- package/native/core/ComponentRegistry.h +30 -0
- package/native/core/ControlMetrics.h +37 -0
- package/native/core/CoreModules.cpp +592 -0
- package/native/core/CoreModules.h +308 -0
- package/native/core/DebuggingOverlay.cpp +106 -0
- package/native/core/DebuggingOverlay.h +65 -0
- package/native/core/DesktopControls.cpp +232 -0
- package/native/core/DesktopControls.h +170 -0
- package/native/core/DevBundle.cpp +108 -0
- package/native/core/DevBundle.h +69 -0
- package/native/core/DevMenu.cpp +99 -0
- package/native/core/DevMenu.h +75 -0
- package/native/core/DialogModule.cpp +150 -0
- package/native/core/DialogModule.h +51 -0
- package/native/core/DragAndDrop.cpp +45 -0
- package/native/core/DragAndDrop.h +225 -0
- package/native/core/ExpoImageComponent.cpp +79 -0
- package/native/core/ExpoImageComponent.h +80 -0
- package/native/core/ExpoModules.cpp +415 -0
- package/native/core/ExpoModules.h +115 -0
- package/native/core/ExpoRuntime.cpp +366 -0
- package/native/core/ExpoRuntime.h +42 -0
- package/native/core/FocusRing.h +36 -0
- package/native/core/FontRegistry.h +51 -0
- package/native/core/GestureHandlerModule.cpp +136 -0
- package/native/core/GestureHandlerModule.h +71 -0
- package/native/core/Gestures.cpp +533 -0
- package/native/core/Gestures.h +145 -0
- package/native/core/HoverTracker.cpp +69 -0
- package/native/core/HoverTracker.h +109 -0
- package/native/core/HttpClient.cpp +282 -0
- package/native/core/ImageBytes.cpp +205 -0
- package/native/core/ImageBytes.h +29 -0
- package/native/core/ImageCache.cpp +51 -0
- package/native/core/ImageCache.h +89 -0
- package/native/core/JsRuntimeAccess.cpp +70 -0
- package/native/core/JsRuntimeAccess.h +60 -0
- package/native/core/JsiPromise.h +51 -0
- package/native/core/KeyEvents.cpp +116 -0
- package/native/core/KeyEvents.h +144 -0
- package/native/core/LogBoxSurface.cpp +46 -0
- package/native/core/LogBoxSurface.h +68 -0
- package/native/core/MenuModel.h +117 -0
- package/native/core/MenuModule.cpp +209 -0
- package/native/core/MenuModule.h +66 -0
- package/native/core/MountingWalk.h +524 -0
- package/native/core/PackageModules.cpp.in +25 -0
- package/native/core/PackageModules.h +50 -0
- package/native/core/PlatformConstantsModule.cpp +63 -0
- package/native/core/PlatformConstantsModule.h +64 -0
- package/native/core/PlatformServices.h +213 -0
- package/native/core/PointerButtons.h +63 -0
- package/native/core/PullToRefresh.cpp +57 -0
- package/native/core/PullToRefresh.h +73 -0
- package/native/core/ReanimatedCompat.h +47 -0
- package/native/core/ReanimatedModule.cpp +203 -0
- package/native/core/ReanimatedModule.h +55 -0
- package/native/core/ScrollAnimation.cpp +59 -0
- package/native/core/ScrollAnimation.h +70 -0
- package/native/core/ScrollBounds.cpp +26 -0
- package/native/core/ScrollBounds.h +68 -0
- package/native/core/ScrollIndicator.cpp +50 -0
- package/native/core/ScrollIndicator.h +69 -0
- package/native/core/ScrollMomentum.cpp +71 -0
- package/native/core/ScrollMomentum.h +73 -0
- package/native/core/ScrollSnap.cpp +123 -0
- package/native/core/ScrollSnap.h +80 -0
- package/native/core/ShareFallback.cpp +101 -0
- package/native/core/ShareFallback.h +45 -0
- package/native/core/SkiaPictureViewComponent.cpp +11 -0
- package/native/core/SkiaPictureViewComponent.h +47 -0
- package/native/core/SourceCodeModule.cpp +55 -0
- package/native/core/SourceCodeModule.h +53 -0
- package/native/core/StatusBarModule.cpp +23 -0
- package/native/core/StatusBarModule.h +42 -0
- package/native/core/TestDialog.cpp +148 -0
- package/native/core/TestDialog.h +96 -0
- package/native/core/TestKeys.cpp +78 -0
- package/native/core/TestKeys.h +50 -0
- package/native/core/TestQuitFile.cpp +33 -0
- package/native/core/TestQuitFile.h +60 -0
- package/native/core/TestSettle.h +192 -0
- package/native/core/TitleBarRegions.h +31 -0
- package/native/core/TurboModuleProxy.cpp +51 -0
- package/native/core/TurboModuleProxy.h +46 -0
- package/native/core/UIManagerAccess.cpp +43 -0
- package/native/core/UIManagerAccess.h +43 -0
- package/native/core/WindowBoundsCache.cpp +319 -0
- package/native/core/WindowControl.h +235 -0
- package/native/core/WindowHost.h +158 -0
- package/native/core/WindowMethods.cpp +167 -0
- package/native/core/WindowMethods.h +84 -0
- package/native/core/WindowsModule.cpp +448 -0
- package/native/core/WindowsModule.h +133 -0
- package/native/core/WorkletsModule.cpp +199 -0
- package/native/core/WorkletsModule.h +57 -0
- package/native/core/portability_probe.cpp +210 -0
- package/native/tests/EventRecorder.h +124 -0
- package/native/tests/TestHarness.cpp +109 -0
- package/native/tests/TestHarness.h +89 -0
- package/native/tests/TreeDump.h +49 -0
- package/native/tests/test_app_identity.cpp +114 -0
- package/native/tests/test_app_paths.cpp +48 -0
- package/native/tests/test_appearance.cpp +107 -0
- package/native/tests/test_backface.cpp +79 -0
- package/native/tests/test_blobs.cpp +157 -0
- package/native/tests/test_controls.cpp +185 -0
- package/native/tests/test_devbundle.cpp +103 -0
- package/native/tests/test_drag_and_drop.cpp +143 -0
- package/native/tests/test_gestures.cpp +331 -0
- package/native/tests/test_hover.cpp +92 -0
- package/native/tests/test_image_cache.cpp +109 -0
- package/native/tests/test_js_runtime_access.cpp +137 -0
- package/native/tests/test_key_events.cpp +235 -0
- package/native/tests/test_momentum.cpp +138 -0
- package/native/tests/test_quit_file.cpp +104 -0
- package/native/tests/test_scroll_animation.cpp +120 -0
- package/native/tests/test_scroll_bounds.cpp +66 -0
- package/native/tests/test_scroll_indicator.cpp +149 -0
- package/native/tests/test_scroll_snap.cpp +112 -0
- package/native/tests/test_settle.cpp +115 -0
- package/native/tests/test_share.cpp +75 -0
- package/native/tests/test_sourcecode.cpp +62 -0
- package/native/tests/test_window_close.cpp +119 -0
- package/native/tests/test_window_limits.cpp +123 -0
- package/package.json +43 -0
- package/react-native.config.js +86 -0
- package/supported-versions.json +66 -0
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
// The mutation walk, with no toolkit in it.
|
|
2
|
+
//
|
|
3
|
+
// `IMountingManager` has two pure-virtual methods, and one of them --
|
|
4
|
+
// `executeMount` -- is where a platform is most likely to be wrong on its own.
|
|
5
|
+
// Fabric's mutation stream has rules that are not obvious from the interface:
|
|
6
|
+
// a Create does not attach, a Remove does not destroy, an Insert's index counts
|
|
7
|
+
// positions in the parent's *final* child list, virtual views have no peer at
|
|
8
|
+
// all, and a mutation naming a tag that no longer exists has to be survivable
|
|
9
|
+
// rather than fatal.
|
|
10
|
+
//
|
|
11
|
+
// None of that is about GTK or AppKit. Writing it twice means two chances to get
|
|
12
|
+
// it subtly different, and a difference here shows up as a layout that is wrong
|
|
13
|
+
// on one desktop and right on another -- which is the exact failure this project
|
|
14
|
+
// exists to avoid. So it is written once, here, and each platform supplies the
|
|
15
|
+
// half-dozen operations that do touch a view.
|
|
16
|
+
//
|
|
17
|
+
// CRTP rather than virtual dispatch: the view type differs per platform
|
|
18
|
+
// (`RnView *` under GObject, `RnAppKitView *` under ARC) and a template keeps it
|
|
19
|
+
// concrete in each translation unit, with no type erasure and no indirection on
|
|
20
|
+
// a path that runs for every mutation of every frame.
|
|
21
|
+
//
|
|
22
|
+
// A platform provides:
|
|
23
|
+
//
|
|
24
|
+
// using ViewRef = ...; // a pointer, nullable
|
|
25
|
+
// ViewRef createView(const ShadowView &); // owned; props not yet applied
|
|
26
|
+
// ViewRef createRootView(Tag); // owned; a surface's root
|
|
27
|
+
// void destroyView(ViewRef); // release the owned reference
|
|
28
|
+
// void insertChild(ViewRef parent, ViewRef child, int index);
|
|
29
|
+
// void removeChild(ViewRef parent, ViewRef child);
|
|
30
|
+
// void updateView(ViewRef, const ShadowView &); // props, layout, state
|
|
31
|
+
// void forgetTag(Tag); // per-tag side tables, if any
|
|
32
|
+
// void applyControlPeer(ViewRef, const ControlState &); // spinner/switch
|
|
33
|
+
// void setHighlights(ViewRef, const std::vector<Highlight> &); // DevTools
|
|
34
|
+
//
|
|
35
|
+
// and must call `releaseAllViews()` from its own destructor: this base cannot,
|
|
36
|
+
// because by the time a base destructor runs the platform half is already gone.
|
|
37
|
+
|
|
38
|
+
#pragma once
|
|
39
|
+
|
|
40
|
+
#include "DebuggingOverlay.h"
|
|
41
|
+
#include "DesktopControls.h"
|
|
42
|
+
#include "HoverTracker.h"
|
|
43
|
+
#include "TestSettle.h"
|
|
44
|
+
#include "PlatformServices.h"
|
|
45
|
+
#include "PullToRefresh.h"
|
|
46
|
+
|
|
47
|
+
#include <react/renderer/components/view/ViewProps.h>
|
|
48
|
+
#include <react/renderer/core/EventEmitter.h>
|
|
49
|
+
#include <react/renderer/mounting/ShadowViewMutation.h>
|
|
50
|
+
|
|
51
|
+
#include <glog/logging.h>
|
|
52
|
+
|
|
53
|
+
#include <algorithm>
|
|
54
|
+
#include <cassert>
|
|
55
|
+
#include <cstdint>
|
|
56
|
+
#include <memory>
|
|
57
|
+
#include <string_view>
|
|
58
|
+
#include <thread>
|
|
59
|
+
#include <unordered_map>
|
|
60
|
+
#include <unordered_set>
|
|
61
|
+
#include <vector>
|
|
62
|
+
|
|
63
|
+
namespace basalt {
|
|
64
|
+
|
|
65
|
+
template <typename Platform, typename ViewRefT>
|
|
66
|
+
class MountingWalk {
|
|
67
|
+
public:
|
|
68
|
+
using ViewRef = ViewRefT;
|
|
69
|
+
using Tag = facebook::react::Tag;
|
|
70
|
+
using SurfaceId = facebook::react::SurfaceId;
|
|
71
|
+
using ShadowView = facebook::react::ShadowView;
|
|
72
|
+
|
|
73
|
+
MountingWalk() : mainThreadId_(std::this_thread::get_id()) {}
|
|
74
|
+
|
|
75
|
+
// The mounted view for a tag, or null. Not `viewForTag` on purpose: platform
|
|
76
|
+
// code reads better saying what kind of thing it wants back.
|
|
77
|
+
ViewRef viewForTag(Tag tag) const {
|
|
78
|
+
const auto it = registry_.find(tag);
|
|
79
|
+
return it == registry_.end() ? ViewRef{} : it->second;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The event emitter for a mounted view, or null.
|
|
83
|
+
//
|
|
84
|
+
// Kept per tag rather than on the view because a view holds no React Native
|
|
85
|
+
// types, and because a view can sit detached between a Remove and its Delete
|
|
86
|
+
// while still needing to deliver a cancel.
|
|
87
|
+
facebook::react::EventEmitter::Shared eventEmitterForTag(Tag tag) const {
|
|
88
|
+
const auto it = eventEmitters_.find(tag);
|
|
89
|
+
return it == eventEmitters_.end() ? nullptr : it->second;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Which hover events this view listens for, as a HoverListener mask.
|
|
93
|
+
//
|
|
94
|
+
// Recorded here, next to the emitter, for the same reason: it comes off the
|
|
95
|
+
// props on every Create and Update, and a touch dispatcher asking per motion
|
|
96
|
+
// event must not have to reach into the shadow tree to find it. Views that
|
|
97
|
+
// listen for none -- nearly all of them -- are not stored at all.
|
|
98
|
+
// --- Controls -------------------------------------------------------------
|
|
99
|
+
//
|
|
100
|
+
// <Switch>, <ActivityIndicator>, <RefreshControl> and <Modal> are the four
|
|
101
|
+
// components that are more than a box, and every part of them that is not
|
|
102
|
+
// pixels is here rather than in three view layers: which views are controls,
|
|
103
|
+
// which scroll view a refresh control belongs to, which modals are open, and
|
|
104
|
+
// what size a modal thinks the window is. Only `applyControlPeer` -- making a
|
|
105
|
+
// GtkSwitch or drawing one -- is left to the platform.
|
|
106
|
+
|
|
107
|
+
// The pull past the top of a list. The platform's scroll view feeds it and
|
|
108
|
+
// calls `fireRefresh` when it says so; see core/PullToRefresh.h.
|
|
109
|
+
PullToRefreshTracker &pullToRefresh() {
|
|
110
|
+
return pullToRefresh_;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Tells the <RefreshControl> belonging to `scrollTag` that it was pulled.
|
|
114
|
+
// Safe on a scroll view that has none.
|
|
115
|
+
void fireRefresh(Tag scrollTag) {
|
|
116
|
+
const Tag control = pullToRefresh_.controlFor(scrollTag);
|
|
117
|
+
if (control != 0) {
|
|
118
|
+
emitRefresh(eventEmitterForTag(control));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// React DevTools' overlay commands, which every host answers the same way.
|
|
123
|
+
//
|
|
124
|
+
// Returns false for anything else, so a platform's `applyCommand` can try
|
|
125
|
+
// this first and carry on. The rectangles are parsed in
|
|
126
|
+
// core/DebuggingOverlay.h; what a platform supplies is the drawing.
|
|
127
|
+
bool applyOverlayCommand(Tag tag, const std::string &name, const folly::dynamic &args) {
|
|
128
|
+
ViewRef view = viewForTag(tag);
|
|
129
|
+
if (view == ViewRef{}) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (name == "clearElementsHighlights") {
|
|
134
|
+
platform().setHighlights(view, {});
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (name == "highlightElements") {
|
|
138
|
+
platform().setHighlights(view, parseElementHighlights(args));
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
if (name != "highlightTraceUpdates") {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
platform().setHighlights(view, parseTraceUpdates(args));
|
|
146
|
+
|
|
147
|
+
// A trace update flashes: React Native's own overlay clears them rather
|
|
148
|
+
// than waiting to be told, because a box left behind after a component
|
|
149
|
+
// stopped re-rendering says the opposite of what it means.
|
|
150
|
+
//
|
|
151
|
+
// The generation is what keeps a stale timer from clearing a *newer* set:
|
|
152
|
+
// these arrive many times a second while the DevTools option is on, so
|
|
153
|
+
// there is almost always more than one in flight.
|
|
154
|
+
const std::uint64_t generation = ++overlayGeneration_;
|
|
155
|
+
postDelayed(kTraceUpdateLifetimeMs, [this, alive = alive_, tag, generation] {
|
|
156
|
+
if (alive.use_count() == 1 || overlayGeneration_ != generation) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
ViewRef target = viewForTag(tag);
|
|
160
|
+
if (target != ViewRef{}) {
|
|
161
|
+
platform().setHighlights(target, {});
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// The user asked to close the topmost <Modal> -- Escape, on all three
|
|
168
|
+
// desktops. Returns false when no modal is open, so the host can let the key
|
|
169
|
+
// do whatever it did before.
|
|
170
|
+
bool requestCloseTopModal() {
|
|
171
|
+
if (modalStack_.empty()) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
emitModalRequestClose(eventEmitterForTag(modalStack_.back()));
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
bool hasOpenModal() const {
|
|
179
|
+
return !modalStack_.empty();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// The size of the window a surface is in, which a <Modal> lays out against.
|
|
183
|
+
//
|
|
184
|
+
// React Native's own cxx platform answers `ModalHostViewScreenSize()` with
|
|
185
|
+
// zero, so a modal that is never told otherwise lays out 0x0 and the app
|
|
186
|
+
// renders nothing at all -- no error, no warning, an empty window. The host
|
|
187
|
+
// calls this wherever it already updates its layout constraints.
|
|
188
|
+
void setSurfaceSize(float width, float height) {
|
|
189
|
+
if (width == surfaceWidth_ && height == surfaceHeight_) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
surfaceWidth_ = width;
|
|
193
|
+
surfaceHeight_ = height;
|
|
194
|
+
for (const auto &[tag, shadowView] : modalViews_) {
|
|
195
|
+
(void)tag;
|
|
196
|
+
if (modalScreenSizeNeedsUpdate(shadowView, surfaceWidth_, surfaceHeight_)) {
|
|
197
|
+
updateModalScreenSize(shadowView, surfaceWidth_, surfaceHeight_);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
std::uint16_t hoverListenersForTag(Tag tag) const {
|
|
203
|
+
const auto it = hoverListeners_.find(tag);
|
|
204
|
+
return it == hoverListeners_.end() ? HoverListenerNone : it->second;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Fabric emits no Create for a surface's root: the root shadow node is the
|
|
208
|
+
// base of every diff, so it must already exist when the first transaction
|
|
209
|
+
// arrives. The host makes one before `ReactHost::startSurface` and parents it
|
|
210
|
+
// into a window. In Fabric a SurfaceId *is* the root node's tag, which is what
|
|
211
|
+
// lets the root take part in the registry like any other view.
|
|
212
|
+
ViewRef createSurfaceRoot(SurfaceId surfaceId) {
|
|
213
|
+
const Tag rootTag = static_cast<Tag>(surfaceId);
|
|
214
|
+
if (const auto it = registry_.find(rootTag); it != registry_.end()) {
|
|
215
|
+
return it->second;
|
|
216
|
+
}
|
|
217
|
+
ViewRef root = platform().createRootView(rootTag);
|
|
218
|
+
registry_[rootTag] = root;
|
|
219
|
+
return root;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
void destroySurfaceRoot(SurfaceId surfaceId) {
|
|
223
|
+
const Tag rootTag = static_cast<Tag>(surfaceId);
|
|
224
|
+
if (const auto it = registry_.find(rootTag); it != registry_.end()) {
|
|
225
|
+
platform().destroyView(it->second);
|
|
226
|
+
registry_.erase(it);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
ViewRef getSurfaceRoot(SurfaceId surfaceId) const {
|
|
231
|
+
return viewForTag(static_cast<Tag>(surfaceId));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Applies one transaction's mutations, in order, on the platform's main
|
|
235
|
+
// thread. Read off `StubViewTree::mutate`, React Native's own reference walk.
|
|
236
|
+
void applyMutations(const facebook::react::ShadowViewMutationList &mutations) {
|
|
237
|
+
assert(std::this_thread::get_id() == mainThreadId_ &&
|
|
238
|
+
"mutations must be applied on the platform's main thread");
|
|
239
|
+
|
|
240
|
+
// That React has produced a tree and a host has put it on screen. The one
|
|
241
|
+
// place all three mount through, which is why BASALT_QUIT_WHEN_SETTLED needs
|
|
242
|
+
// this in one file rather than in three. Only the first is kept; see
|
|
243
|
+
// core/TestSettle.h.
|
|
244
|
+
noteMountApplied();
|
|
245
|
+
|
|
246
|
+
for (const auto &mutation : mutations) {
|
|
247
|
+
switch (mutation.type) {
|
|
248
|
+
case facebook::react::ShadowViewMutation::Create:
|
|
249
|
+
create(mutation.newChildShadowView);
|
|
250
|
+
break;
|
|
251
|
+
case facebook::react::ShadowViewMutation::Delete:
|
|
252
|
+
destroy(mutation.oldChildShadowView.tag);
|
|
253
|
+
break;
|
|
254
|
+
case facebook::react::ShadowViewMutation::Insert:
|
|
255
|
+
insert(mutation);
|
|
256
|
+
break;
|
|
257
|
+
case facebook::react::ShadowViewMutation::Remove:
|
|
258
|
+
remove(mutation);
|
|
259
|
+
break;
|
|
260
|
+
case facebook::react::ShadowViewMutation::Update:
|
|
261
|
+
update(mutation.newChildShadowView);
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// After the whole transaction rather than at each Insert.
|
|
267
|
+
//
|
|
268
|
+
// Fabric inserts a subtree from the bottom up: a <RefreshControl> is put
|
|
269
|
+
// inside the scroll view's content view before that content view is put
|
|
270
|
+
// inside the scroll view, so at the moment the control arrives its
|
|
271
|
+
// grandparent is not known yet and walking up finds nothing. The tree is
|
|
272
|
+
// whole here.
|
|
273
|
+
resolveRefreshControls();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
protected:
|
|
277
|
+
// Not virtual and not public: this is a mixin, never a base pointer.
|
|
278
|
+
~MountingWalk() = default;
|
|
279
|
+
|
|
280
|
+
// Platforms call this from their own destructor. See the note at the top.
|
|
281
|
+
void releaseAllViews() {
|
|
282
|
+
for (auto &[tag, view] : registry_) {
|
|
283
|
+
(void)tag;
|
|
284
|
+
platform().destroyView(view);
|
|
285
|
+
}
|
|
286
|
+
registry_.clear();
|
|
287
|
+
eventEmitters_.clear();
|
|
288
|
+
componentNames_.clear();
|
|
289
|
+
hoverListeners_.clear();
|
|
290
|
+
parentOf_.clear();
|
|
291
|
+
scrollTags_.clear();
|
|
292
|
+
modalViews_.clear();
|
|
293
|
+
modalStack_.clear();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
void rememberEventEmitter(const ShadowView &shadowView) {
|
|
297
|
+
if (shadowView.eventEmitter != nullptr) {
|
|
298
|
+
eventEmitters_[shadowView.tag] = shadowView.eventEmitter;
|
|
299
|
+
}
|
|
300
|
+
if (shadowView.componentName != nullptr) {
|
|
301
|
+
componentNames_[shadowView.tag] = shadowView.componentName;
|
|
302
|
+
}
|
|
303
|
+
rememberHoverListeners(shadowView);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// An Update can take listeners away as well as add them, so a view that stops
|
|
307
|
+
// listening is erased rather than left with its old mask.
|
|
308
|
+
void rememberHoverListeners(const ShadowView &shadowView) {
|
|
309
|
+
const auto *viewProps = dynamic_cast<const facebook::react::ViewProps *>(shadowView.props.get());
|
|
310
|
+
const std::uint16_t mask =
|
|
311
|
+
viewProps == nullptr ? HoverListenerNone : hoverListenersFrom(viewProps->events);
|
|
312
|
+
if (mask == HoverListenerNone) {
|
|
313
|
+
hoverListeners_.erase(shadowView.tag);
|
|
314
|
+
} else {
|
|
315
|
+
hoverListeners_[shadowView.tag] = mask;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
bool onMainThread() const {
|
|
320
|
+
return std::this_thread::get_id() == mainThreadId_;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// The portable half of mounting a control, called from the platform's
|
|
324
|
+
// `updateView`. Reads the props once, hands the platform the result, and
|
|
325
|
+
// keeps the bookkeeping the events need.
|
|
326
|
+
//
|
|
327
|
+
// Called from `updateView` rather than from the walk so that a platform
|
|
328
|
+
// applies it in its own order -- after layout on every host, because a
|
|
329
|
+
// spinner is centred in a frame that has to exist first.
|
|
330
|
+
void applyControls(ViewRef view, const ShadowView &shadowView) {
|
|
331
|
+
const ControlState state = controlStateOf(shadowView);
|
|
332
|
+
if (state.kind != ControlKind::None) {
|
|
333
|
+
platform().applyControlPeer(view, state);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (shadowView.componentName == nullptr) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const std::string_view name(shadowView.componentName);
|
|
341
|
+
if (name == "ScrollView") {
|
|
342
|
+
scrollTags_.insert(shadowView.tag);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (name != "ModalHostView") {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// A modal, which is where the screen size has to be corrected. The first
|
|
350
|
+
// sighting is also where `onShow` belongs: React Native fires it once, when
|
|
351
|
+
// the modal appears, and a modal appears by being mounted -- `visible` is
|
|
352
|
+
// false by not rendering the component at all.
|
|
353
|
+
const bool firstSighting = modalViews_.find(shadowView.tag) == modalViews_.end();
|
|
354
|
+
modalViews_[shadowView.tag] = shadowView;
|
|
355
|
+
if (firstSighting) {
|
|
356
|
+
modalStack_.push_back(shadowView.tag);
|
|
357
|
+
emitModalShow(shadowView.eventEmitter);
|
|
358
|
+
}
|
|
359
|
+
if (modalScreenSizeNeedsUpdate(shadowView, surfaceWidth_, surfaceHeight_)) {
|
|
360
|
+
updateModalScreenSize(shadowView, surfaceWidth_, surfaceHeight_);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private:
|
|
365
|
+
Platform &platform() {
|
|
366
|
+
return static_cast<Platform &>(*this);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Create allocates a view but does not attach it; an Insert follows, possibly
|
|
370
|
+
// in a later transaction.
|
|
371
|
+
void create(const ShadowView &shadowView) {
|
|
372
|
+
ViewRef view = platform().createView(shadowView);
|
|
373
|
+
platform().updateView(view, shadowView);
|
|
374
|
+
registry_[shadowView.tag] = view;
|
|
375
|
+
rememberEventEmitter(shadowView);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
void destroy(Tag tag) {
|
|
379
|
+
const auto it = registry_.find(tag);
|
|
380
|
+
if (it == registry_.end()) {
|
|
381
|
+
LOG(WARNING) << "Delete for unknown tag " << tag;
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
platform().destroyView(it->second);
|
|
385
|
+
registry_.erase(it);
|
|
386
|
+
eventEmitters_.erase(tag);
|
|
387
|
+
componentNames_.erase(tag);
|
|
388
|
+
hoverListeners_.erase(tag);
|
|
389
|
+
parentOf_.erase(tag);
|
|
390
|
+
scrollTags_.erase(tag);
|
|
391
|
+
pullToRefresh_.forget(tag);
|
|
392
|
+
modalViews_.erase(tag);
|
|
393
|
+
modalStack_.erase(std::remove(modalStack_.begin(), modalStack_.end(), tag), modalStack_.end());
|
|
394
|
+
platform().forgetTag(tag);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
void insert(const facebook::react::ShadowViewMutation &mutation) {
|
|
398
|
+
// Virtual views exist in the shadow tree only, to keep an EventEmitter
|
|
399
|
+
// alive. They have no peer to parent.
|
|
400
|
+
if (mutation.mutatedViewIsVirtual()) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
ViewRef parent = viewForTag(mutation.parentTag);
|
|
404
|
+
ViewRef child = viewForTag(mutation.newChildShadowView.tag);
|
|
405
|
+
if (parent == ViewRef{} || child == ViewRef{}) {
|
|
406
|
+
// Survivable rather than fatal: this is what a bug upstream, or a
|
|
407
|
+
// transaction racing a surface teardown, looks like from here.
|
|
408
|
+
LOG(WARNING) << "Insert with unknown tag (parent " << mutation.parentTag << ", child "
|
|
409
|
+
<< mutation.newChildShadowView.tag << ")";
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
// Props can change in the same transaction that inserts the view.
|
|
413
|
+
platform().updateView(child, mutation.newChildShadowView);
|
|
414
|
+
platform().insertChild(parent, child, static_cast<int>(mutation.index));
|
|
415
|
+
parentOf_[mutation.newChildShadowView.tag] = mutation.parentTag;
|
|
416
|
+
if (controlKindFor(mutation.newChildShadowView.componentName) == ControlKind::PullToRefresh) {
|
|
417
|
+
unresolvedRefreshControls_.push_back(mutation.newChildShadowView.tag);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
void remove(const facebook::react::ShadowViewMutation &mutation) {
|
|
422
|
+
if (mutation.mutatedViewIsVirtual()) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
ViewRef parent = viewForTag(mutation.parentTag);
|
|
426
|
+
ViewRef child = viewForTag(mutation.oldChildShadowView.tag);
|
|
427
|
+
if (parent == ViewRef{} || child == ViewRef{}) {
|
|
428
|
+
LOG(WARNING) << "Remove with unknown tag (parent " << mutation.parentTag << ", child "
|
|
429
|
+
<< mutation.oldChildShadowView.tag << ")";
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
// Detached, not destroyed: the Delete is a separate mutation and may never
|
|
433
|
+
// come -- a reparent is a Remove and an Insert with no Delete between them.
|
|
434
|
+
platform().removeChild(parent, child);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
void update(const ShadowView &shadowView) {
|
|
438
|
+
ViewRef view = viewForTag(shadowView.tag);
|
|
439
|
+
if (view == ViewRef{}) {
|
|
440
|
+
LOG(WARNING) << "Update for unknown tag " << shadowView.tag;
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
platform().updateView(view, shadowView);
|
|
444
|
+
// A clone carries a new emitter instance; keeping the old one would deliver
|
|
445
|
+
// touches to a stale target.
|
|
446
|
+
rememberEventEmitter(shadowView);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Ties each <RefreshControl> mounted in this transaction to the scroll view
|
|
450
|
+
// it refreshes.
|
|
451
|
+
//
|
|
452
|
+
// Not its parent: React Native's ScrollView puts the control inside the
|
|
453
|
+
// content container, so the scroll view is an ancestor. Walking up is also
|
|
454
|
+
// what makes this survive somebody wrapping the control in a <View>.
|
|
455
|
+
//
|
|
456
|
+
// A control whose scroll view is still not found is dropped rather than
|
|
457
|
+
// carried: it is a <RefreshControl> outside any list, which is an app bug
|
|
458
|
+
// and not something to keep retrying on every frame.
|
|
459
|
+
void resolveRefreshControls() {
|
|
460
|
+
for (const Tag tag : unresolvedRefreshControls_) {
|
|
461
|
+
for (Tag walk = tag; walk != 0;) {
|
|
462
|
+
const auto parent = parentOf_.find(walk);
|
|
463
|
+
if (parent == parentOf_.end()) {
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
walk = parent->second;
|
|
467
|
+
if (scrollTags_.count(walk) != 0) {
|
|
468
|
+
pullToRefresh_.attach(walk, tag);
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
unresolvedRefreshControls_.clear();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Views are held with a strong reference from Create until Delete. Between a
|
|
477
|
+
// Remove and its Delete a view has no parent, so this is the only thing
|
|
478
|
+
// keeping it alive.
|
|
479
|
+
std::unordered_map<Tag, ViewRef> registry_;
|
|
480
|
+
|
|
481
|
+
// Parallel to registry_, and torn down with it on Delete.
|
|
482
|
+
std::unordered_map<Tag, facebook::react::EventEmitter::Shared> eventEmitters_;
|
|
483
|
+
|
|
484
|
+
// Every view's component name, as the static string Fabric holds. Needed
|
|
485
|
+
// because a Remove and an Insert carry a ShadowView and the walk's own
|
|
486
|
+
// bookkeeping does not.
|
|
487
|
+
std::unordered_map<Tag, const char *> componentNames_;
|
|
488
|
+
|
|
489
|
+
// Sparse, unlike the two above: only views that listen for a hover event
|
|
490
|
+
// appear, so an app that uses none carries an empty map.
|
|
491
|
+
std::unordered_map<Tag, std::uint16_t> hoverListeners_;
|
|
492
|
+
|
|
493
|
+
// --- Controls ---------------------------------------------------------------
|
|
494
|
+
|
|
495
|
+
// Who each view's parent is, so a <RefreshControl> can find the scroll view
|
|
496
|
+
// it is nested inside. Fabric's mutations carry it and nothing else here
|
|
497
|
+
// needed it until now.
|
|
498
|
+
std::unordered_map<Tag, Tag> parentOf_;
|
|
499
|
+
std::unordered_set<Tag> scrollTags_;
|
|
500
|
+
PullToRefreshTracker pullToRefresh_;
|
|
501
|
+
// Controls mounted in the transaction being applied, resolved at the end of
|
|
502
|
+
// it; see resolveRefreshControls.
|
|
503
|
+
std::vector<Tag> unresolvedRefreshControls_;
|
|
504
|
+
|
|
505
|
+
// Modals, and the order they opened in. A vector rather than a set: Escape
|
|
506
|
+
// closes the topmost one, which needs an order.
|
|
507
|
+
std::unordered_map<Tag, ShadowView> modalViews_;
|
|
508
|
+
std::vector<Tag> modalStack_;
|
|
509
|
+
|
|
510
|
+
float surfaceWidth_{0.0F};
|
|
511
|
+
float surfaceHeight_{0.0F};
|
|
512
|
+
|
|
513
|
+
// DevTools' trace updates, and the token that tells a timer whether this
|
|
514
|
+
// manager is still here. The scroll views keep the same pair for the same
|
|
515
|
+
// reason: a delayed callback outlives whatever scheduled it.
|
|
516
|
+
std::uint64_t overlayGeneration_{0};
|
|
517
|
+
std::shared_ptr<bool> alive_{std::make_shared<bool>(true)};
|
|
518
|
+
|
|
519
|
+
// The main thread, recorded at construction. `executeMount` arrives on the JS
|
|
520
|
+
// thread and marshals here; `applyMutations` asserts it got there.
|
|
521
|
+
std::thread::id mainThreadId_;
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
} // namespace basalt
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Generated by CMake. Do not edit; edit core/PackageModules.cpp.in.
|
|
2
|
+
//
|
|
3
|
+
// One function calling each discovered capability package's installer. Empty
|
|
4
|
+
// when nothing was discovered, which is why core can call it unconditionally.
|
|
5
|
+
|
|
6
|
+
#include "PackageModules.h"
|
|
7
|
+
|
|
8
|
+
namespace basalt {
|
|
9
|
+
|
|
10
|
+
@basalt_package_declarations@
|
|
11
|
+
void installPackageExpoModules(facebook::jsi::Runtime &runtime, facebook::jsi::Object &modules) {
|
|
12
|
+
(void)runtime;
|
|
13
|
+
(void)modules;
|
|
14
|
+
@basalt_package_calls@}
|
|
15
|
+
|
|
16
|
+
@basalt_package_turbo_declarations@
|
|
17
|
+
std::shared_ptr<facebook::react::TurboModule> packageTurboModule(
|
|
18
|
+
const std::string &name,
|
|
19
|
+
const std::shared_ptr<facebook::react::CallInvoker> &jsInvoker) {
|
|
20
|
+
(void)name;
|
|
21
|
+
(void)jsInvoker;
|
|
22
|
+
@basalt_package_turbo_calls@ return nullptr;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
} // namespace basalt
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// How a capability that does not live in core reaches the runtime.
|
|
2
|
+
//
|
|
3
|
+
// The host is one binary. There is no dynamic native module loading here, so a
|
|
4
|
+
// capability shipped as its own package is still *compiled in* -- which means
|
|
5
|
+
// the question is not how it loads but how core learns it exists without
|
|
6
|
+
// naming it.
|
|
7
|
+
//
|
|
8
|
+
// It does not. CMake writes the answer. When the build discovers a package that
|
|
9
|
+
// declares native code, it generates a translation unit defining the function
|
|
10
|
+
// below to call that package's installer; when it discovers none, it generates
|
|
11
|
+
// one with an empty body. Core calls it either way and never mentions a
|
|
12
|
+
// package.
|
|
13
|
+
//
|
|
14
|
+
// Generated rather than registered at static initialisation, which is the
|
|
15
|
+
// obvious alternative and the wrong one here: a registrar in a static library
|
|
16
|
+
// is only linked in if something already references its translation unit, so
|
|
17
|
+
// the capability would vanish from a release build and stay in a debug one.
|
|
18
|
+
// That failure is silent and platform-specific, which is the worst shape a
|
|
19
|
+
// build problem can have.
|
|
20
|
+
|
|
21
|
+
#pragma once
|
|
22
|
+
|
|
23
|
+
#include <ReactCommon/CallInvoker.h>
|
|
24
|
+
#include <ReactCommon/TurboModule.h>
|
|
25
|
+
|
|
26
|
+
#include <jsi/jsi.h>
|
|
27
|
+
|
|
28
|
+
#include <memory>
|
|
29
|
+
#include <string>
|
|
30
|
+
|
|
31
|
+
namespace basalt {
|
|
32
|
+
|
|
33
|
+
// Sets each discovered package's Expo modules on `modules`, which is
|
|
34
|
+
// `globalThis.expo.modules`. Defined by the generated translation unit; see
|
|
35
|
+
// cmake/BasaltPackages.cmake.
|
|
36
|
+
void installPackageExpoModules(facebook::jsi::Runtime &runtime, facebook::jsi::Object &modules);
|
|
37
|
+
|
|
38
|
+
// A discovered package's TurboModule, or nullptr when no package supplies one by
|
|
39
|
+
// that name. Defined by the same generated translation unit.
|
|
40
|
+
//
|
|
41
|
+
// The signature is React Native's own `TurboModuleProvider`, so a host adds this
|
|
42
|
+
// to its list of providers directly rather than wrapping it -- which is the
|
|
43
|
+
// whole of the wiring, and why a package contributing a TurboModule costs a host
|
|
44
|
+
// nothing. A package that wants one names a factory of this shape in its
|
|
45
|
+
// CMakeLists; see basalt-subprocess.
|
|
46
|
+
std::shared_ptr<facebook::react::TurboModule> packageTurboModule(
|
|
47
|
+
const std::string &name,
|
|
48
|
+
const std::shared_ptr<facebook::react::CallInvoker> &jsInvoker);
|
|
49
|
+
|
|
50
|
+
} // namespace basalt
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#include "PlatformConstantsModule.h"
|
|
2
|
+
|
|
3
|
+
#include <cstdlib>
|
|
4
|
+
|
|
5
|
+
#ifndef BASALT_REACT_NATIVE_VERSION
|
|
6
|
+
// Only reachable if the build did not pass one, which CMake always does.
|
|
7
|
+
#define BASALT_REACT_NATIVE_VERSION "0.0.0"
|
|
8
|
+
#endif
|
|
9
|
+
|
|
10
|
+
namespace basalt {
|
|
11
|
+
|
|
12
|
+
using facebook::react::PlatformConstantsAndroid;
|
|
13
|
+
|
|
14
|
+
DesktopPlatformConstantsModule::Version DesktopPlatformConstantsModule::parseVersion(
|
|
15
|
+
const std::string &text) {
|
|
16
|
+
Version version;
|
|
17
|
+
|
|
18
|
+
// A prerelease is everything after the first '-', and it must not be parsed
|
|
19
|
+
// as part of the patch number: "0.88.0-rc.2" is patch 0, prerelease "rc.2".
|
|
20
|
+
const auto dash = text.find('-');
|
|
21
|
+
const std::string numbers = text.substr(0, dash);
|
|
22
|
+
if (dash != std::string::npos && dash + 1 < text.size()) {
|
|
23
|
+
version.prerelease = text.substr(dash + 1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
int *fields[] = {&version.major, &version.minor, &version.patch};
|
|
27
|
+
std::size_t start = 0;
|
|
28
|
+
for (int index = 0; index < 3 && start <= numbers.size(); ++index) {
|
|
29
|
+
const auto dot = numbers.find('.', start);
|
|
30
|
+
const std::string part =
|
|
31
|
+
numbers.substr(start, dot == std::string::npos ? std::string::npos : dot - start);
|
|
32
|
+
*fields[index] = std::atoi(part.c_str());
|
|
33
|
+
if (dot == std::string::npos) {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
start = dot + 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return version;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
PlatformConstantsAndroid DesktopPlatformConstantsModule::getConstants(facebook::jsi::Runtime &rt) {
|
|
43
|
+
// Everything but the version is what ReactCxxPlatform reports, kept in step
|
|
44
|
+
// with it deliberately: this class exists to correct one field, not to invent
|
|
45
|
+
// a different set of constants.
|
|
46
|
+
facebook::react::PlatformConstantsModule base{jsInvoker_};
|
|
47
|
+
PlatformConstantsAndroid constants = base.getConstants(rt);
|
|
48
|
+
|
|
49
|
+
const Version version = parseVersion(BASALT_REACT_NATIVE_VERSION);
|
|
50
|
+
constants.reactNativeVersion.major = version.major;
|
|
51
|
+
constants.reactNativeVersion.minor = version.minor;
|
|
52
|
+
constants.reactNativeVersion.patch = version.patch;
|
|
53
|
+
// Left absent deliberately. The Android spec this platform answers types
|
|
54
|
+
// `prerelease` as an optional *int*, so a tag like "rc.2" has nowhere to go;
|
|
55
|
+
// reporting nothing is at least not a lie, and a stable release has none
|
|
56
|
+
// anyway. The tag is still parsed off, above, so that it cannot be read as
|
|
57
|
+
// part of the patch number.
|
|
58
|
+
constants.reactNativeVersion.prerelease = std::nullopt;
|
|
59
|
+
|
|
60
|
+
return constants;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
} // namespace basalt
|