react-native-unistyles 3.3.0 → 3.5.0
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/README.md +26 -10
- package/android/build.gradle +12 -1
- package/android/src/main/cxx/NativeUnistylesModule.cpp +8 -4
- package/android/src/main/cxx/NativeUnistylesModule.h +5 -1
- package/components/native/ActivityIndicator/package.json +1 -1
- package/cxx/common/UnistylesConstants.h +1 -0
- package/cxx/converters/TransformOriginConverter.cpp +106 -0
- package/cxx/core/StyleSheetRegistry.cpp +9 -9
- package/cxx/core/StyleSheetRegistry.h +3 -3
- package/cxx/core/UnistyleWrapper.h +13 -1
- package/cxx/core/UnistylesRegistry.cpp +226 -54
- package/cxx/core/UnistylesRegistry.h +64 -7
- package/cxx/hybridObjects/HybridShadowRegistry.cpp +128 -11
- package/cxx/hybridObjects/HybridShadowRegistry.h +20 -0
- package/cxx/hybridObjects/HybridStyleSheet.cpp +20 -12
- package/cxx/hybridObjects/HybridUnistylesRuntime.cpp +11 -1
- package/cxx/hybridObjects/HybridUnistylesRuntime.h +4 -2
- package/cxx/parser/Parser.cpp +30 -3
- package/cxx/parser/Parser.h +1 -0
- package/cxx/shadowTree/NativeProps.h +88 -0
- package/cxx/shadowTree/ShadowLeafUpdate.h +8 -0
- package/cxx/shadowTree/ShadowTrafficController.h +18 -35
- package/cxx/shadowTree/ShadowTreeDiagnostics.cpp +339 -0
- package/cxx/shadowTree/ShadowTreeDiagnostics.h +18 -0
- package/cxx/shadowTree/ShadowTreeManager.cpp +14 -148
- package/cxx/shadowTree/ShadowTreeManager.h +2 -6
- package/diagnostics/package.json +6 -0
- package/ios/UnistylesModuleOnLoad.mm +9 -3
- package/lib/commonjs/components/native/ActivityIndicator.native.js +10 -0
- package/lib/commonjs/components/native/ActivityIndicator.native.js.map +1 -0
- package/lib/commonjs/components/native/Animated.js +2 -0
- package/lib/commonjs/components/native/Animated.js.map +1 -1
- package/lib/commonjs/components/native/NativeText.js +6 -0
- package/lib/commonjs/components/native/NativeText.js.map +1 -1
- package/lib/commonjs/components/native/NativeText.native.js +17 -1
- package/lib/commonjs/components/native/NativeText.native.js.map +1 -1
- package/lib/commonjs/components/native/NativeView.js +6 -0
- package/lib/commonjs/components/native/NativeView.js.map +1 -1
- package/lib/commonjs/components/native/NativeView.native.js +22 -3
- package/lib/commonjs/components/native/NativeView.native.js.map +1 -1
- package/lib/commonjs/components/native/Pressable.js +9 -3
- package/lib/commonjs/components/native/Pressable.js.map +1 -1
- package/lib/commonjs/components/native/Pressable.native.js +2 -0
- package/lib/commonjs/components/native/Pressable.native.js.map +1 -1
- package/lib/commonjs/components/native/TouchableHighlight.native.js +10 -0
- package/lib/commonjs/components/native/TouchableHighlight.native.js.map +1 -0
- package/lib/commonjs/core/createUnistylesActivityIndicator.js +41 -0
- package/lib/commonjs/core/createUnistylesActivityIndicator.js.map +1 -0
- package/lib/commonjs/core/createUnistylesElement.js +59 -14
- package/lib/commonjs/core/createUnistylesElement.js.map +1 -1
- package/lib/commonjs/core/createUnistylesTouchableHighlight.js +58 -0
- package/lib/commonjs/core/createUnistylesTouchableHighlight.js.map +1 -0
- package/lib/commonjs/core/index.js +14 -0
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/diagnostics/index.js +13 -0
- package/lib/commonjs/diagnostics/index.js.map +1 -0
- package/lib/commonjs/diagnostics/types.js +2 -0
- package/lib/commonjs/diagnostics/types.js.map +1 -0
- package/lib/commonjs/diagnostics/verify.js +19 -0
- package/lib/commonjs/diagnostics/verify.js.map +1 -0
- package/lib/commonjs/diagnostics/verify.native.js +12 -0
- package/lib/commonjs/diagnostics/verify.native.js.map +1 -0
- package/lib/commonjs/index.js +38 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/mocks.js +41 -0
- package/lib/commonjs/mocks.js.map +1 -1
- package/lib/commonjs/reanimated/variant/useUpdateVariantColor.native.js +8 -0
- package/lib/commonjs/reanimated/variant/useUpdateVariantColor.native.js.map +1 -1
- package/lib/commonjs/specs/ShadowRegistry/index.js +97 -1
- package/lib/commonjs/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/commonjs/specs/StyleSheet/index.js +5 -1
- package/lib/commonjs/specs/StyleSheet/index.js.map +1 -1
- package/lib/commonjs/specs/UnistylesRuntime/index.js.map +1 -1
- package/lib/commonjs/web/convert/object/boxShadow.js +2 -2
- package/lib/commonjs/web/convert/object/boxShadow.js.map +1 -1
- package/lib/commonjs/web/index.js.map +1 -1
- package/lib/commonjs/web/registry.js +3 -0
- package/lib/commonjs/web/registry.js.map +1 -1
- package/lib/module/components/native/ActivityIndicator.native.js +6 -0
- package/lib/module/components/native/ActivityIndicator.native.js.map +1 -0
- package/lib/module/components/native/Animated.js +3 -0
- package/lib/module/components/native/Animated.js.map +1 -1
- package/lib/module/components/native/NativeText.js +1 -1
- package/lib/module/components/native/NativeText.js.map +1 -1
- package/lib/module/components/native/NativeText.native.js +15 -1
- package/lib/module/components/native/NativeText.native.js.map +1 -1
- package/lib/module/components/native/NativeView.js +1 -0
- package/lib/module/components/native/NativeView.js.map +1 -1
- package/lib/module/components/native/NativeView.native.js +19 -2
- package/lib/module/components/native/NativeView.native.js.map +1 -1
- package/lib/module/components/native/Pressable.js +9 -3
- package/lib/module/components/native/Pressable.js.map +1 -1
- package/lib/module/components/native/Pressable.native.js +2 -0
- package/lib/module/components/native/Pressable.native.js.map +1 -1
- package/lib/module/components/native/TouchableHighlight.native.js +6 -0
- package/lib/module/components/native/TouchableHighlight.native.js.map +1 -0
- package/lib/module/core/createUnistylesActivityIndicator.js +35 -0
- package/lib/module/core/createUnistylesActivityIndicator.js.map +1 -0
- package/lib/module/core/createUnistylesElement.js +58 -13
- package/lib/module/core/createUnistylesElement.js.map +1 -1
- package/lib/module/core/createUnistylesTouchableHighlight.js +52 -0
- package/lib/module/core/createUnistylesTouchableHighlight.js.map +1 -0
- package/lib/module/core/index.js +2 -0
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/diagnostics/index.js +5 -0
- package/lib/module/diagnostics/index.js.map +1 -0
- package/lib/module/diagnostics/types.js +2 -0
- package/lib/module/diagnostics/types.js.map +1 -0
- package/lib/module/diagnostics/verify.js +14 -0
- package/lib/module/diagnostics/verify.js.map +1 -0
- package/lib/module/diagnostics/verify.native.js +8 -0
- package/lib/module/diagnostics/verify.native.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/mocks.js +41 -0
- package/lib/module/mocks.js.map +1 -1
- package/lib/module/reanimated/variant/useUpdateVariantColor.native.js +9 -1
- package/lib/module/reanimated/variant/useUpdateVariantColor.native.js.map +1 -1
- package/lib/module/specs/ShadowRegistry/index.js +97 -1
- package/lib/module/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/module/specs/StyleSheet/index.js +6 -1
- package/lib/module/specs/StyleSheet/index.js.map +1 -1
- package/lib/module/specs/UnistylesRuntime/index.js.map +1 -1
- package/lib/module/web/convert/object/boxShadow.js +2 -2
- package/lib/module/web/convert/object/boxShadow.js.map +1 -1
- package/lib/module/web/index.js.map +1 -1
- package/lib/module/web/registry.js +3 -0
- package/lib/module/web/registry.js.map +1 -1
- package/lib/typescript/src/components/native/ActivityIndicator.native.d.ts +2 -0
- package/lib/typescript/src/components/native/ActivityIndicator.native.d.ts.map +1 -0
- package/lib/typescript/src/components/native/Animated.d.ts +16 -36
- package/lib/typescript/src/components/native/Animated.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeText.d.ts +1 -1
- package/lib/typescript/src/components/native/NativeText.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeText.native.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeView.d.ts +1 -0
- package/lib/typescript/src/components/native/NativeView.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeView.native.d.ts +2 -2
- package/lib/typescript/src/components/native/NativeView.native.d.ts.map +1 -1
- package/lib/typescript/src/components/native/Pressable.d.ts +4 -2
- package/lib/typescript/src/components/native/Pressable.d.ts.map +1 -1
- package/lib/typescript/src/components/native/Pressable.native.d.ts +5 -2
- package/lib/typescript/src/components/native/Pressable.native.d.ts.map +1 -1
- package/lib/typescript/src/components/native/TouchableHighlight.native.d.ts +2 -0
- package/lib/typescript/src/components/native/TouchableHighlight.native.d.ts.map +1 -0
- package/lib/typescript/src/core/createUnistylesActivityIndicator.d.ts +3 -0
- package/lib/typescript/src/core/createUnistylesActivityIndicator.d.ts.map +1 -0
- package/lib/typescript/src/core/createUnistylesElement.d.ts.map +1 -1
- package/lib/typescript/src/core/createUnistylesTouchableHighlight.d.ts +3 -0
- package/lib/typescript/src/core/createUnistylesTouchableHighlight.d.ts.map +1 -0
- package/lib/typescript/src/core/index.d.ts +2 -0
- package/lib/typescript/src/core/index.d.ts.map +1 -1
- package/lib/typescript/src/core/useUnistyles.d.ts +1 -1
- package/lib/typescript/src/diagnostics/index.d.ts +3 -0
- package/lib/typescript/src/diagnostics/index.d.ts.map +1 -0
- package/lib/typescript/src/diagnostics/types.d.ts +19 -0
- package/lib/typescript/src/diagnostics/types.d.ts.map +1 -0
- package/lib/typescript/src/diagnostics/verify.d.ts +3 -0
- package/lib/typescript/src/diagnostics/verify.d.ts.map +1 -0
- package/lib/typescript/src/diagnostics/verify.native.d.ts +3 -0
- package/lib/typescript/src/diagnostics/verify.native.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/variant/useUpdateVariantColor.native.d.ts.map +1 -1
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts +5 -1
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/ShadowRegistry/types.d.ts +3 -0
- package/lib/typescript/src/specs/ShadowRegistry/types.d.ts.map +1 -1
- package/lib/typescript/src/specs/StyleSheet/index.d.ts +4 -1
- package/lib/typescript/src/specs/StyleSheet/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/UnistylesRuntime/index.d.ts +2 -2
- package/lib/typescript/src/specs/UnistylesRuntime/index.d.ts.map +1 -1
- package/lib/typescript/src/types/breakpoints.d.ts +1 -1
- package/lib/typescript/src/types/breakpoints.d.ts.map +1 -1
- package/lib/typescript/src/types/core.d.ts +7 -2
- package/lib/typescript/src/types/core.d.ts.map +1 -1
- package/lib/typescript/src/types/stylesheet.d.ts +3 -3
- package/lib/typescript/src/types/stylesheet.d.ts.map +1 -1
- package/lib/typescript/src/web/index.d.ts.map +1 -1
- package/lib/typescript/src/web/registry.d.ts.map +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Func_void_UnistylesNativeMiniRuntime.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Func_void_std__vector_UnistyleDependency__UnistylesNativeMiniRuntime.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/HybridNativePlatformSpec.kt +2 -0
- package/package.json +35 -26
- package/plugin/index.d.ts +4 -4
- package/plugin/index.js +21 -5
- package/src/components/native/ActivityIndicator.native.tsx +5 -0
- package/src/components/native/Animated.tsx +18 -1
- package/src/components/native/NativeText.native.tsx +18 -1
- package/src/components/native/NativeText.tsx +1 -1
- package/src/components/native/NativeView.native.tsx +22 -2
- package/src/components/native/NativeView.tsx +2 -0
- package/src/components/native/Pressable.native.tsx +10 -2
- package/src/components/native/Pressable.tsx +15 -4
- package/src/components/native/TouchableHighlight.native.tsx +5 -0
- package/src/core/createUnistylesActivityIndicator.tsx +47 -0
- package/src/core/createUnistylesElement.tsx +45 -14
- package/src/core/createUnistylesTouchableHighlight.tsx +69 -0
- package/src/core/index.ts +2 -0
- package/src/diagnostics/index.ts +3 -0
- package/src/diagnostics/types.ts +25 -0
- package/src/diagnostics/verify.native.ts +7 -0
- package/src/diagnostics/verify.ts +13 -0
- package/src/index.ts +4 -1
- package/src/mocks.ts +41 -0
- package/src/reanimated/variant/useUpdateVariantColor.native.ts +7 -1
- package/src/specs/ShadowRegistry/index.ts +128 -1
- package/src/specs/ShadowRegistry/types.ts +3 -0
- package/src/specs/StyleSheet/index.ts +10 -2
- package/src/specs/UnistylesRuntime/index.ts +7 -2
- package/src/types/breakpoints.ts +5 -3
- package/src/types/core.ts +7 -28
- package/src/types/stylesheet.ts +3 -3
- package/src/web/convert/object/boxShadow.ts +2 -2
- package/src/web/index.ts +2 -1
- package/src/web/registry.ts +3 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "UnistylesRegistry.h"
|
|
2
2
|
#include "UnistylesState.h"
|
|
3
3
|
#include "Parser.h"
|
|
4
|
+
#include "NativeProps.h"
|
|
4
5
|
|
|
5
6
|
using namespace margelo::nitro::unistyles;
|
|
6
7
|
using namespace facebook;
|
|
@@ -8,7 +9,13 @@ using namespace facebook::react;
|
|
|
8
9
|
|
|
9
10
|
std::atomic<int> core::UnistylesRegistry::_nextStyleSheetTag{0};
|
|
10
11
|
|
|
11
|
-
void core::UnistylesRegistry::registerTheme(jsi::Runtime& rt, std::string name, jsi::Value& theme) {
|
|
12
|
+
void core::UnistylesRegistry::registerTheme(jsi::Runtime& rt, uint64_t generation, std::string name, jsi::Value& theme) {
|
|
13
|
+
std::lock_guard<std::mutex> lock(this->_ownershipMutex);
|
|
14
|
+
|
|
15
|
+
if (!this->isCurrent(generation)) {
|
|
16
|
+
throw std::runtime_error(helpers::RUNTIME_REPLACED_ERROR);
|
|
17
|
+
}
|
|
18
|
+
|
|
12
19
|
auto& state = this->getState();
|
|
13
20
|
|
|
14
21
|
state._jsThemes.emplace(name, std::move(theme));
|
|
@@ -45,7 +52,7 @@ void core::UnistylesRegistry::createState() {
|
|
|
45
52
|
this->_state = std::make_unique<UnistylesState>();
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
void core::UnistylesRegistry::updateTheme(jsi::Runtime& rt, std::string& themeName, jsi::Function&& callback) {
|
|
55
|
+
void core::UnistylesRegistry::updateTheme(jsi::Runtime& rt, uint64_t generation, std::string& themeName, jsi::Function&& callback) {
|
|
49
56
|
auto& state = this->getState();
|
|
50
57
|
auto it = state._jsThemes.find(themeName);
|
|
51
58
|
|
|
@@ -55,42 +62,103 @@ void core::UnistylesRegistry::updateTheme(jsi::Runtime& rt, std::string& themeNa
|
|
|
55
62
|
|
|
56
63
|
helpers::assertThat(rt, result.isObject(), "Unistyles: Returned theme is not an object. Please check your updateTheme function.");
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
auto theme = result.asObject(rt);
|
|
66
|
+
std::lock_guard<std::mutex> lock(this->_ownershipMutex);
|
|
67
|
+
|
|
68
|
+
if (!this->isCurrent(generation)) {
|
|
69
|
+
throw std::runtime_error(helpers::RUNTIME_REPLACED_ERROR);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
it->second = std::move(theme);
|
|
59
73
|
}
|
|
60
74
|
|
|
61
75
|
void core::UnistylesRegistry::linkShadowNodeWithUnistyle(
|
|
62
76
|
jsi::Runtime& rt,
|
|
63
|
-
|
|
77
|
+
uint64_t generation,
|
|
78
|
+
const std::shared_ptr<const ShadowNodeFamily>& shadowNodeFamily,
|
|
64
79
|
std::vector<std::shared_ptr<UnistyleData>>& unistylesData,
|
|
65
80
|
std::optional<folly::dynamic> initialScopedUpdate
|
|
66
81
|
) {
|
|
67
|
-
|
|
82
|
+
// released after unlocking, so a family destructor never runs within the lock
|
|
83
|
+
ReleasedFamilies releasedFamilies;
|
|
84
|
+
std::lock_guard<std::mutex> lock(this->_ownershipMutex);
|
|
85
|
+
|
|
86
|
+
if (!this->isCurrent(generation)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this->trafficController.withLock([this, &unistylesData, &shadowNodeFamily, &initialScopedUpdate, &releasedFamilies](){
|
|
91
|
+
auto family = shadowNodeFamily.get();
|
|
92
|
+
auto it = this->_shadowRegistry.find(family);
|
|
93
|
+
|
|
68
94
|
// Clear suspension state if this family was previously suspended
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
mutableFamily->nativeProps_DEPRECATED.reset();
|
|
95
|
+
// native props stay, they hold values from theme changes that React doesn't know about
|
|
96
|
+
if (it != this->_shadowRegistry.end() && it->second.isSuspended) {
|
|
72
97
|
// Clear old registry entries to prevent stale UnistyleData accumulation
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this->trafficController.removeShadowNode(shadowNodeFamily);
|
|
98
|
+
// and any stale traffic controller entry (e.g. from a theme change during suspension)
|
|
99
|
+
this->forgetFamilyUnsafe(family, releasedFamilies);
|
|
76
100
|
}
|
|
77
101
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
102
|
+
auto& linkedFamily = this->_shadowRegistry[family];
|
|
103
|
+
|
|
104
|
+
linkedFamily.family = shadowNodeFamily;
|
|
105
|
+
linkedFamily.unistyles.insert(linkedFamily.unistyles.end(), unistylesData.begin(), unistylesData.end());
|
|
81
106
|
|
|
82
107
|
// Required for scoped themes to apply on initial mount
|
|
83
108
|
if (initialScopedUpdate.has_value()) {
|
|
84
|
-
|
|
109
|
+
this->trafficController.setUpdate(shadowNodeFamily, std::move(*initialScopedUpdate));
|
|
110
|
+
}
|
|
85
111
|
|
|
86
|
-
|
|
87
|
-
|
|
112
|
+
// families unmounted without unlink (eg. while frozen) are pinned by us only
|
|
113
|
+
// sweep them once the registry doubles, so it's amortized O(1) per link
|
|
114
|
+
if (this->_shadowRegistry.size() >= this->_sweepThreshold) {
|
|
115
|
+
this->sweepUnownedFamiliesUnsafe(releasedFamilies);
|
|
116
|
+
this->_sweepThreshold = std::max(MIN_SWEEP_THRESHOLD, this->_shadowRegistry.size() * 2);
|
|
88
117
|
}
|
|
89
118
|
});
|
|
90
119
|
}
|
|
91
120
|
|
|
121
|
+
bool core::UnistylesRegistry::isOwnedOnlyByUnistyles(const LinkedFamily& linkedFamily) noexcept {
|
|
122
|
+
// shadow nodes own their family, so if nothing but our pin owns it, the family is not part of any
|
|
123
|
+
// shadow tree anymore. React Native can't get it back, as it only keeps weak references beside shadow nodes
|
|
124
|
+
return linkedFamily.family.use_count() == 1;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void core::UnistylesRegistry::forgetFamilyUnsafe(const ShadowNodeFamily* shadowNodeFamily, ReleasedFamilies& releasedFamilies) {
|
|
128
|
+
auto it = this->_shadowRegistry.find(shadowNodeFamily);
|
|
129
|
+
|
|
130
|
+
if (it != this->_shadowRegistry.end()) {
|
|
131
|
+
releasedFamilies.emplace_back(std::move(it->second.family));
|
|
132
|
+
this->_shadowRegistry.erase(it);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (auto pendingFamily = this->trafficController.removeShadowNode(shadowNodeFamily)) {
|
|
136
|
+
releasedFamilies.emplace_back(std::move(pendingFamily));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void core::UnistylesRegistry::sweepUnownedFamiliesUnsafe(ReleasedFamilies& releasedFamilies) {
|
|
141
|
+
std::vector<const ShadowNodeFamily*> unownedFamilies;
|
|
142
|
+
|
|
143
|
+
for (const auto& [family, linkedFamily] : this->_shadowRegistry) {
|
|
144
|
+
if (isOwnedOnlyByUnistyles(linkedFamily)) {
|
|
145
|
+
unownedFamilies.emplace_back(family);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
for (const auto* family : unownedFamilies) {
|
|
150
|
+
this->forgetFamilyUnsafe(family, releasedFamilies);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
92
154
|
void core::UnistylesRegistry::removeDuplicatedUnistyles(const ShadowNodeFamily *shadowNodeFamily, std::vector<core::Unistyle::Shared>& unistyles) {
|
|
93
|
-
auto
|
|
155
|
+
auto it = this->_shadowRegistry.find(shadowNodeFamily);
|
|
156
|
+
|
|
157
|
+
if (it == this->_shadowRegistry.end()) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
auto& targetFamilyUnistyles = it->second.unistyles;
|
|
94
162
|
|
|
95
163
|
unistyles.erase(
|
|
96
164
|
std::remove_if(
|
|
@@ -111,26 +179,36 @@ void core::UnistylesRegistry::removeDuplicatedUnistyles(const ShadowNodeFamily *
|
|
|
111
179
|
}
|
|
112
180
|
|
|
113
181
|
void core::UnistylesRegistry::unlinkShadowNodeWithUnistyles(const ShadowNodeFamily* shadowNodeFamily) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this->
|
|
182
|
+
ReleasedFamilies releasedFamilies;
|
|
183
|
+
|
|
184
|
+
this->trafficController.withLock([this, shadowNodeFamily, &releasedFamilies](){
|
|
185
|
+
this->forgetFamilyUnsafe(shadowNodeFamily, releasedFamilies);
|
|
118
186
|
});
|
|
119
187
|
}
|
|
120
188
|
|
|
121
189
|
void core::UnistylesRegistry::suspendShadowNode(const ShadowNodeFamily* shadowNodeFamily) {
|
|
122
190
|
this->trafficController.withLock([this, shadowNodeFamily](){
|
|
123
|
-
|
|
124
|
-
|
|
191
|
+
auto it = this->_shadowRegistry.find(shadowNodeFamily);
|
|
192
|
+
|
|
193
|
+
if (it != this->_shadowRegistry.end()) {
|
|
194
|
+
it->second.isSuspended = true;
|
|
125
195
|
}
|
|
126
196
|
});
|
|
127
197
|
}
|
|
128
198
|
|
|
129
199
|
bool core::UnistylesRegistry::isSuspended(const ShadowNodeFamily* family) const noexcept {
|
|
130
|
-
|
|
200
|
+
auto it = this->_shadowRegistry.find(family);
|
|
201
|
+
|
|
202
|
+
return it != this->_shadowRegistry.end() && it->second.isSuspended;
|
|
131
203
|
}
|
|
132
204
|
|
|
133
|
-
std::shared_ptr<core::StyleSheet> core::UnistylesRegistry::addStyleSheet(jsi::Runtime& rt, core::StyleSheetType type, jsi::Object&& rawValue) {
|
|
205
|
+
std::shared_ptr<core::StyleSheet> core::UnistylesRegistry::addStyleSheet(jsi::Runtime& rt, uint64_t generation, core::StyleSheetType type, jsi::Object&& rawValue) {
|
|
206
|
+
std::lock_guard<std::mutex> lock(this->_ownershipMutex);
|
|
207
|
+
|
|
208
|
+
if (!this->isCurrent(generation)) {
|
|
209
|
+
throw std::runtime_error(helpers::RUNTIME_REPLACED_ERROR);
|
|
210
|
+
}
|
|
211
|
+
|
|
134
212
|
int tag = _nextStyleSheetTag.fetch_add(1);
|
|
135
213
|
|
|
136
214
|
auto sheet = std::make_shared<core::StyleSheet>(tag, type, std::move(rawValue));
|
|
@@ -143,36 +221,56 @@ core::DependencyMap core::UnistylesRegistry::buildDependencyMap(std::vector<Unis
|
|
|
143
221
|
core::DependencyMap dependencyMap;
|
|
144
222
|
|
|
145
223
|
std::unordered_set<UnistyleDependency> uniqueDependencies(deps.begin(), deps.end());
|
|
224
|
+
ReleasedFamilies releasedFamilies;
|
|
225
|
+
|
|
226
|
+
// families stay pinned by the registry until the shadow tree update is committed
|
|
227
|
+
this->trafficController.withLock([this, &dependencyMap, &uniqueDependencies, &releasedFamilies](){
|
|
228
|
+
// we iterate whole registry anyway, so it's a free moment to drop families unmounted without unlink
|
|
229
|
+
this->sweepUnownedFamiliesUnsafe(releasedFamilies);
|
|
230
|
+
|
|
231
|
+
for (const auto& [family, linkedFamily] : this->_shadowRegistry) {
|
|
232
|
+
bool hasAnyOfDependencies = false;
|
|
233
|
+
|
|
234
|
+
// Check if any dependency matches
|
|
235
|
+
for (const auto& unistyleData : linkedFamily.unistyles) {
|
|
236
|
+
for (const auto& dep : unistyleData->unistyle->dependencies) {
|
|
237
|
+
if (uniqueDependencies.count(dep)) {
|
|
238
|
+
hasAnyOfDependencies = true;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
146
242
|
|
|
147
|
-
|
|
148
|
-
bool hasAnyOfDependencies = false;
|
|
149
|
-
|
|
150
|
-
// Check if any dependency matches
|
|
151
|
-
for (const auto& unistyleData : unistyles) {
|
|
152
|
-
for (const auto& dep : unistyleData->unistyle->dependencies) {
|
|
153
|
-
if (uniqueDependencies.count(dep)) {
|
|
154
|
-
hasAnyOfDependencies = true;
|
|
243
|
+
if (hasAnyOfDependencies) {
|
|
155
244
|
break;
|
|
156
|
-
}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!hasAnyOfDependencies) {
|
|
249
|
+
continue;
|
|
157
250
|
}
|
|
158
251
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
252
|
+
dependencyMap[family].insert(
|
|
253
|
+
dependencyMap[family].end(),
|
|
254
|
+
linkedFamily.unistyles.begin(),
|
|
255
|
+
linkedFamily.unistyles.end()
|
|
256
|
+
);
|
|
162
257
|
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
return dependencyMap;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
void core::UnistylesRegistry::queueShadowLeafUpdatesUnsafe(shadow::ShadowLeafUpdates& updates) {
|
|
264
|
+
for (auto& [family, props] : updates) {
|
|
265
|
+
auto it = this->_shadowRegistry.find(family);
|
|
163
266
|
|
|
164
|
-
|
|
267
|
+
// family was unlinked in the meantime, there is nothing to update
|
|
268
|
+
if (it == this->_shadowRegistry.end()) {
|
|
165
269
|
continue;
|
|
166
270
|
}
|
|
167
271
|
|
|
168
|
-
|
|
169
|
-
dependencyMap[family].end(),
|
|
170
|
-
unistyles.begin(),
|
|
171
|
-
unistyles.end()
|
|
172
|
-
);
|
|
272
|
+
this->trafficController.setUpdate(it->second.family, std::move(props));
|
|
173
273
|
}
|
|
174
|
-
|
|
175
|
-
return dependencyMap;
|
|
176
274
|
}
|
|
177
275
|
|
|
178
276
|
// called from proxied function only, we don't know host
|
|
@@ -185,15 +283,15 @@ void core::UnistylesRegistry::shadowLeafUpdateFromUnistyle(jsi::Runtime& rt, Uni
|
|
|
185
283
|
? std::make_optional(maybePressableId.asString(rt).utf8(rt))
|
|
186
284
|
: std::nullopt;
|
|
187
285
|
|
|
188
|
-
for (const auto& [family,
|
|
189
|
-
for (const auto& unistyleData : unistyles) {
|
|
286
|
+
for (const auto& [family, linkedFamily] : this->_shadowRegistry) {
|
|
287
|
+
for (const auto& unistyleData : linkedFamily.unistyles) {
|
|
190
288
|
if (unistyleData->unistyle == unistyle) {
|
|
191
289
|
updates[family] = parser.parseStylesToShadowTreeStyles(rt, { unistyleData });
|
|
192
290
|
}
|
|
193
291
|
}
|
|
194
292
|
}
|
|
195
293
|
|
|
196
|
-
this->
|
|
294
|
+
this->queueShadowLeafUpdatesUnsafe(updates);
|
|
197
295
|
});
|
|
198
296
|
}
|
|
199
297
|
|
|
@@ -262,11 +360,85 @@ void core::UnistylesRegistry::setScopedTheme(std::optional<std::string> themeNam
|
|
|
262
360
|
this->_scopedTheme = std::move(themeName);
|
|
263
361
|
}
|
|
264
362
|
|
|
265
|
-
|
|
266
|
-
this->
|
|
267
|
-
this->
|
|
268
|
-
|
|
269
|
-
|
|
363
|
+
uint64_t core::UnistylesRegistry::takeOwnership() {
|
|
364
|
+
std::lock_guard<std::mutex> lock(this->_ownershipMutex);
|
|
365
|
+
auto previousGeneration = this->_generation.load();
|
|
366
|
+
|
|
367
|
+
if (previousGeneration != 0) {
|
|
368
|
+
this->_replacedStates[previousGeneration] = this->takeOwnedState();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
this->_generation.store(++this->_lastGeneration);
|
|
372
|
+
|
|
373
|
+
return this->_lastGeneration;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
void core::UnistylesRegistry::releaseOwnership(uint64_t generation) {
|
|
377
|
+
// called when module is invalidated, before React Native destroys the runtime
|
|
378
|
+
// declared before the lock, so jsi values and pins are released after unlocking
|
|
379
|
+
OwnedState releasedState;
|
|
380
|
+
|
|
381
|
+
{
|
|
382
|
+
std::lock_guard<std::mutex> lock(this->_ownershipMutex);
|
|
383
|
+
|
|
384
|
+
if (this->isCurrent(generation)) {
|
|
385
|
+
releasedState = this->takeOwnedState();
|
|
386
|
+
this->_generation.store(0);
|
|
387
|
+
} else if (auto it = this->_replacedStates.find(generation); it != this->_replacedStates.end()) {
|
|
388
|
+
releasedState = std::move(it->second);
|
|
389
|
+
this->_replacedStates.erase(it);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
for (auto& [_, styleSheet] : releasedState.styleSheets) {
|
|
394
|
+
styleSheet->unistyles.clear();
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
core::UnistylesRegistry::OwnedState core::UnistylesRegistry::takeOwnedState() {
|
|
399
|
+
OwnedState ownedState;
|
|
400
|
+
|
|
401
|
+
this->trafficController.withLock([this, &ownedState](){
|
|
402
|
+
ownedState.shadowRegistry = std::exchange(this->_shadowRegistry, {});
|
|
403
|
+
ownedState.updates = this->trafficController.takeUpdates();
|
|
404
|
+
this->_sweepThreshold = MIN_SWEEP_THRESHOLD;
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
ownedState.styleSheets = std::exchange(this->_styleSheetRegistry, {});
|
|
408
|
+
ownedState.state = std::move(this->_state);
|
|
270
409
|
this->_scopedTheme = std::nullopt;
|
|
410
|
+
this->_committedTags.clear();
|
|
271
411
|
_nextStyleSheetTag.store(0);
|
|
412
|
+
|
|
413
|
+
return ownedState;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
std::vector<core::LinkedFamilySnapshot> core::UnistylesRegistry::getLinkedFamiliesSnapshot() {
|
|
417
|
+
std::vector<LinkedFamilySnapshot> snapshot;
|
|
418
|
+
|
|
419
|
+
this->trafficController.withLock([this, &snapshot](){
|
|
420
|
+
snapshot.reserve(this->_shadowRegistry.size());
|
|
421
|
+
|
|
422
|
+
for (const auto& [_, linkedFamily] : this->_shadowRegistry) {
|
|
423
|
+
const bool isOwnedOnlyByUnistyles = this->isOwnedOnlyByUnistyles(linkedFamily);
|
|
424
|
+
|
|
425
|
+
snapshot.push_back({linkedFamily.family, linkedFamily.unistyles, linkedFamily.isSuspended, isOwnedOnlyByUnistyles});
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
return snapshot;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
size_t core::UnistylesRegistry::getPendingUpdatesCount() {
|
|
433
|
+
return this->trafficController.withLock([this](){
|
|
434
|
+
return this->trafficController.getUpdatesCount();
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
void core::UnistylesRegistry::setCommittedTags(std::vector<Tag>&& tags) {
|
|
439
|
+
this->_committedTags = std::move(tags);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
std::vector<Tag> core::UnistylesRegistry::takeCommittedTags() {
|
|
443
|
+
return std::exchange(this->_committedTags, {});
|
|
272
444
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include "set"
|
|
4
4
|
#include <atomic>
|
|
5
|
+
#include <mutex>
|
|
5
6
|
#include <jsi/jsi.h>
|
|
6
7
|
#include <folly/dynamic.h>
|
|
7
8
|
#include <react/renderer/uimanager/UIManager.h>
|
|
@@ -23,6 +24,19 @@ using namespace facebook::react;
|
|
|
23
24
|
|
|
24
25
|
using DependencyMap = std::unordered_map<const ShadowNodeFamily*, std::vector<std::shared_ptr<UnistyleData>>>;
|
|
25
26
|
|
|
27
|
+
struct LinkedFamily {
|
|
28
|
+
std::shared_ptr<const ShadowNodeFamily> family;
|
|
29
|
+
std::vector<std::shared_ptr<UnistyleData>> unistyles;
|
|
30
|
+
bool isSuspended = false;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
struct LinkedFamilySnapshot {
|
|
34
|
+
std::shared_ptr<const ShadowNodeFamily> family;
|
|
35
|
+
std::vector<std::shared_ptr<UnistyleData>> unistyles;
|
|
36
|
+
bool isSuspended = false;
|
|
37
|
+
bool isOwnedOnlyByUnistyles = false;
|
|
38
|
+
};
|
|
39
|
+
|
|
26
40
|
struct UnistylesRegistry: public StyleSheetRegistry {
|
|
27
41
|
static UnistylesRegistry& get();
|
|
28
42
|
|
|
@@ -31,38 +45,81 @@ struct UnistylesRegistry: public StyleSheetRegistry {
|
|
|
31
45
|
|
|
32
46
|
bool shouldUsePointsForBreakpoints = false;
|
|
33
47
|
|
|
34
|
-
void registerTheme(jsi::Runtime& rt, std::string name, jsi::Value& theme);
|
|
48
|
+
void registerTheme(jsi::Runtime& rt, uint64_t generation, std::string name, jsi::Value& theme);
|
|
35
49
|
void registerBreakpoints(std::vector<std::pair<std::string, double>>& sortedBreakpoints);
|
|
36
50
|
void setPrefersAdaptiveThemes(bool prefersAdaptiveThemes);
|
|
37
51
|
void setInitialThemeName(std::string themeName);
|
|
38
|
-
void updateTheme(jsi::Runtime& rt, std::string& themeName, jsi::Function&& callback);
|
|
52
|
+
void updateTheme(jsi::Runtime& rt, uint64_t generation, std::string& themeName, jsi::Function&& callback);
|
|
39
53
|
|
|
40
54
|
UnistylesState& getState();
|
|
41
55
|
void createState();
|
|
42
56
|
std::vector<std::shared_ptr<core::StyleSheet>> getStyleSheetsToRefresh(std::vector<UnistyleDependency>& unistylesDependencies);
|
|
43
|
-
void linkShadowNodeWithUnistyle(jsi::Runtime& rt, const ShadowNodeFamily
|
|
57
|
+
void linkShadowNodeWithUnistyle(jsi::Runtime& rt, uint64_t generation, const std::shared_ptr<const ShadowNodeFamily>& shadowNodeFamily, std::vector<std::shared_ptr<UnistyleData>>& unistylesData, std::optional<folly::dynamic> initialScopedUpdate = std::nullopt);
|
|
44
58
|
void unlinkShadowNodeWithUnistyles(const ShadowNodeFamily*);
|
|
45
59
|
void suspendShadowNode(const ShadowNodeFamily*);
|
|
46
60
|
bool isSuspended(const ShadowNodeFamily*) const noexcept;
|
|
47
|
-
std::shared_ptr<core::StyleSheet> addStyleSheet(jsi::Runtime& rt, core::StyleSheetType type, jsi::Object&& rawValue);
|
|
61
|
+
std::shared_ptr<core::StyleSheet> addStyleSheet(jsi::Runtime& rt, uint64_t generation, core::StyleSheetType type, jsi::Object&& rawValue);
|
|
48
62
|
DependencyMap buildDependencyMap(std::vector<UnistyleDependency>& deps);
|
|
49
63
|
void shadowLeafUpdateFromUnistyle(jsi::Runtime& rt, Unistyle::Shared unistyle, jsi::Value& maybePressableId);
|
|
64
|
+
// call it only within trafficController.withLock!
|
|
65
|
+
void queueShadowLeafUpdatesUnsafe(shadow::ShadowLeafUpdates& updates);
|
|
50
66
|
shadow::ShadowTrafficController trafficController{};
|
|
51
67
|
const std::optional<std::string> getScopedTheme();
|
|
52
68
|
void removeDuplicatedUnistyles(const ShadowNodeFamily* shadowNodeFamily, std::vector<core::Unistyle::Shared>& unistyles);
|
|
53
69
|
void setScopedTheme(std::optional<std::string> themeName);
|
|
54
70
|
core::Unistyle::Shared getUnistyleById(std::string unistyleID);
|
|
55
|
-
|
|
71
|
+
std::vector<LinkedFamilySnapshot> getLinkedFamiliesSnapshot();
|
|
72
|
+
size_t getPendingUpdatesCount();
|
|
73
|
+
void setCommittedTags(std::vector<Tag>&& tags);
|
|
74
|
+
std::vector<Tag> takeCommittedTags();
|
|
75
|
+
|
|
76
|
+
// newest installed runtime owns the registry, generation 0 means no owner
|
|
77
|
+
// previous runtime's state is kept aside until it releases ownership, as it may still run JS
|
|
78
|
+
uint64_t takeOwnership();
|
|
79
|
+
void releaseOwnership(uint64_t generation);
|
|
80
|
+
|
|
81
|
+
inline bool isCurrent(uint64_t generation) const noexcept {
|
|
82
|
+
return generation != 0 && generation == this->_generation.load();
|
|
83
|
+
}
|
|
56
84
|
|
|
57
85
|
private:
|
|
86
|
+
using ReleasedFamilies = std::vector<std::shared_ptr<const ShadowNodeFamily>>;
|
|
87
|
+
|
|
88
|
+
struct OwnedState {
|
|
89
|
+
std::unordered_map<const ShadowNodeFamily*, LinkedFamily> shadowRegistry;
|
|
90
|
+
shadow::PinnedShadowLeafUpdates updates;
|
|
91
|
+
std::unordered_map<int, std::shared_ptr<core::StyleSheet>> styleSheets;
|
|
92
|
+
std::unique_ptr<UnistylesState> state;
|
|
93
|
+
};
|
|
94
|
+
|
|
58
95
|
UnistylesRegistry() = default;
|
|
59
96
|
|
|
97
|
+
// call it only within _ownershipMutex!
|
|
98
|
+
// destructs nothing, so it can run on the next runtime's thread
|
|
99
|
+
OwnedState takeOwnedState();
|
|
100
|
+
|
|
101
|
+
// call it only within trafficController.withLock!
|
|
102
|
+
// pins are moved to releasedFamilies, so they can be released after unlocking
|
|
103
|
+
void forgetFamilyUnsafe(const ShadowNodeFamily* shadowNodeFamily, ReleasedFamilies& releasedFamilies);
|
|
104
|
+
void sweepUnownedFamiliesUnsafe(ReleasedFamilies& releasedFamilies);
|
|
105
|
+
|
|
106
|
+
// React Native doesn't own the family anymore, it was unmounted without unlink
|
|
107
|
+
static bool isOwnedOnlyByUnistyles(const LinkedFamily& linkedFamily) noexcept;
|
|
108
|
+
|
|
109
|
+
static constexpr size_t MIN_SWEEP_THRESHOLD = 64;
|
|
110
|
+
|
|
111
|
+
// lock order is _ownershipMutex -> trafficController, never call JS within
|
|
112
|
+
std::mutex _ownershipMutex;
|
|
113
|
+
std::atomic<uint64_t> _generation{0};
|
|
114
|
+
uint64_t _lastGeneration = 0;
|
|
115
|
+
std::unordered_map<uint64_t, OwnedState> _replacedStates{};
|
|
60
116
|
static std::atomic<int> _nextStyleSheetTag;
|
|
61
117
|
std::optional<std::string> _scopedTheme{};
|
|
62
118
|
std::unique_ptr<UnistylesState> _state{};
|
|
63
119
|
std::unordered_map<int, std::shared_ptr<core::StyleSheet>> _styleSheetRegistry{};
|
|
64
|
-
std::unordered_map<const ShadowNodeFamily*,
|
|
65
|
-
|
|
120
|
+
std::unordered_map<const ShadowNodeFamily*, LinkedFamily> _shadowRegistry{};
|
|
121
|
+
size_t _sweepThreshold = MIN_SWEEP_THRESHOLD;
|
|
122
|
+
std::vector<Tag> _committedTags{};
|
|
66
123
|
};
|
|
67
124
|
|
|
68
125
|
inline UnistylesRegistry& UnistylesRegistry::get() {
|