basalt-win32 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/cli/runWindows.js +35 -0
- package/cli/shared.js +75 -0
- package/native/CMakeLists.txt +398 -0
- package/native/tests/test_win32_accessibility.cpp +271 -0
- package/native/tests/test_win32_clipboard.cpp +121 -0
- package/native/tests/test_win32_focus.cpp +195 -0
- package/native/tests/test_win32_hittest.cpp +410 -0
- package/native/tests/test_win32_image.cpp +239 -0
- package/native/tests/test_win32_imageloader.cpp +208 -0
- package/native/tests/test_win32_input.cpp +361 -0
- package/native/tests/test_win32_key_events.cpp +84 -0
- package/native/tests/test_win32_mounting.cpp +410 -0
- package/native/tests/test_win32_paint.cpp +505 -0
- package/native/tests/test_win32_scrollview.cpp +385 -0
- package/native/tests/test_win32_text.cpp +258 -0
- package/native/tests/test_win32_textinput.cpp +609 -0
- package/native/tests/test_win32_titlebar.cpp +111 -0
- package/native/tests/test_win32_titlebar_actions.cpp +62 -0
- package/native/tests/test_win32_view.cpp +222 -0
- package/native/win32/ColorSchemeWin32.cpp +56 -0
- package/native/win32/ComponentRegistryWin32.cpp +124 -0
- package/native/win32/DirectWriteLayout.cpp +116 -0
- package/native/win32/DirectWriteLayout.h +36 -0
- package/native/win32/DirectWriteLayoutManager.cpp +124 -0
- package/native/win32/FontRegistryDirectWrite.cpp +117 -0
- package/native/win32/PlatformServicesWin32.cpp +643 -0
- package/native/win32/RnWin32Accessible.cpp +258 -0
- package/native/win32/RnWin32Accessible.h +91 -0
- package/native/win32/RnWin32Image.cpp +265 -0
- package/native/win32/RnWin32Image.h +93 -0
- package/native/win32/RnWin32TextLayout.cpp +310 -0
- package/native/win32/RnWin32TextLayout.h +160 -0
- package/native/win32/RnWin32View.cpp +1281 -0
- package/native/win32/RnWin32View.h +506 -0
- package/native/win32/Win32AnimationChoreographer.cpp +76 -0
- package/native/win32/Win32AnimationChoreographer.h +61 -0
- package/native/win32/Win32Clip.h +173 -0
- package/native/win32/Win32DropTarget.cpp +567 -0
- package/native/win32/Win32DropTarget.h +42 -0
- package/native/win32/Win32Focus.cpp +262 -0
- package/native/win32/Win32Focus.h +109 -0
- package/native/win32/Win32ImageLoader.cpp +167 -0
- package/native/win32/Win32ImageLoader.h +104 -0
- package/native/win32/Win32KeyEvents.cpp +126 -0
- package/native/win32/Win32KeyEvents.h +20 -0
- package/native/win32/Win32MenuBar.cpp +352 -0
- package/native/win32/Win32MenuBar.h +16 -0
- package/native/win32/Win32MountingManager.cpp +727 -0
- package/native/win32/Win32MountingManager.h +203 -0
- package/native/win32/Win32Packaging.cpp +161 -0
- package/native/win32/Win32Packaging.h +56 -0
- package/native/win32/Win32RunLoopObserver.cpp +48 -0
- package/native/win32/Win32RunLoopObserver.h +42 -0
- package/native/win32/Win32ScrollView.cpp +515 -0
- package/native/win32/Win32ScrollView.h +208 -0
- package/native/win32/Win32SkiaContext.cpp +221 -0
- package/native/win32/Win32SkiaContext.h +53 -0
- package/native/win32/Win32SkiaModule.cpp +80 -0
- package/native/win32/Win32SkiaModule.h +50 -0
- package/native/win32/Win32SkiaPeer.cpp +358 -0
- package/native/win32/Win32SkiaPeer.h +66 -0
- package/native/win32/Win32SkiaUnicode.cpp +42 -0
- package/native/win32/Win32Snapshot.cpp +201 -0
- package/native/win32/Win32Snapshot.h +66 -0
- package/native/win32/Win32Strings.h +54 -0
- package/native/win32/Win32TextInput.cpp +811 -0
- package/native/win32/Win32TextInput.h +232 -0
- package/native/win32/Win32TitleBar.cpp +562 -0
- package/native/win32/Win32TitleBar.h +146 -0
- package/native/win32/Win32TitleBarLayout.cpp +46 -0
- package/native/win32/Win32TitleBarLayout.h +58 -0
- package/native/win32/Win32TouchDispatcher.cpp +443 -0
- package/native/win32/Win32TouchDispatcher.h +153 -0
- package/native/win32/Win32UiThread.h +27 -0
- package/native/win32/Win32WindowControl.cpp +329 -0
- package/native/win32/Win32WindowModule.cpp +209 -0
- package/native/win32/Win32WindowModule.h +72 -0
- package/native/win32/demo_layout_win32.cpp +232 -0
- package/native/win32/main_win32.cpp +2481 -0
- package/native/win32/mount_harness_win32.cpp +316 -0
- package/package.json +26 -0
- package/react-native.config.js +22 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
// Tests for Win32MountingManager: does a stream of ShadowViewMutations produce
|
|
2
|
+
// the view tree it describes?
|
|
3
|
+
//
|
|
4
|
+
// Deliberately the same nine questions `tests/test_mounting.cpp` asks of GTK
|
|
5
|
+
// and `tests/test_appkit_mounting.mm` asks of AppKit, in the same order, with
|
|
6
|
+
// the same tags and frames. All three managers share their walk, so most of
|
|
7
|
+
// this is asking whether the sharing actually holds -- and the day it stops,
|
|
8
|
+
// these fail here rather than in an app.
|
|
9
|
+
//
|
|
10
|
+
// One is new and is about this platform specifically:
|
|
11
|
+
// `win32_delete_frees_the_view` exists because Windows is the first of the
|
|
12
|
+
// three where the registry's ownership is written out rather than delegated to
|
|
13
|
+
// a refcount or to ARC.
|
|
14
|
+
|
|
15
|
+
#include "TestHarness.h"
|
|
16
|
+
#include "TreeDump.h"
|
|
17
|
+
|
|
18
|
+
#include "Win32MountingManager.h"
|
|
19
|
+
|
|
20
|
+
#include <react/renderer/components/view/ViewProps.h>
|
|
21
|
+
#include <react/renderer/graphics/Color.h>
|
|
22
|
+
|
|
23
|
+
#include <cstdint>
|
|
24
|
+
#include <sstream>
|
|
25
|
+
#include <vector>
|
|
26
|
+
|
|
27
|
+
using basalt::Win32MountingManager;
|
|
28
|
+
using basalt::win32::RnWin32View;
|
|
29
|
+
using facebook::react::ColorComponents;
|
|
30
|
+
using facebook::react::LayoutMetrics;
|
|
31
|
+
using facebook::react::MountingTransaction;
|
|
32
|
+
using facebook::react::ShadowView;
|
|
33
|
+
using facebook::react::ShadowViewMutation;
|
|
34
|
+
using facebook::react::ShadowViewMutationList;
|
|
35
|
+
using facebook::react::SurfaceId;
|
|
36
|
+
using facebook::react::Tag;
|
|
37
|
+
using facebook::react::TransactionTelemetry;
|
|
38
|
+
using facebook::react::ViewProps;
|
|
39
|
+
|
|
40
|
+
namespace {
|
|
41
|
+
|
|
42
|
+
constexpr SurfaceId kSurfaceId = 1;
|
|
43
|
+
|
|
44
|
+
ShadowView makeView(Tag tag,
|
|
45
|
+
float x,
|
|
46
|
+
float y,
|
|
47
|
+
float width,
|
|
48
|
+
float height,
|
|
49
|
+
float red = 0.0F,
|
|
50
|
+
float green = 0.0F,
|
|
51
|
+
float blue = 0.0F) {
|
|
52
|
+
auto props = std::make_shared<ViewProps>();
|
|
53
|
+
props->backgroundColor = facebook::react::colorFromComponents(
|
|
54
|
+
ColorComponents{.red = red, .green = green, .blue = blue, .alpha = 1.0F});
|
|
55
|
+
|
|
56
|
+
LayoutMetrics metrics;
|
|
57
|
+
metrics.frame = {.origin = {.x = x, .y = y}, .size = {.width = width, .height = height}};
|
|
58
|
+
|
|
59
|
+
ShadowView view;
|
|
60
|
+
view.componentName = "View";
|
|
61
|
+
view.surfaceId = kSurfaceId;
|
|
62
|
+
view.tag = tag;
|
|
63
|
+
view.props = props;
|
|
64
|
+
view.layoutMetrics = metrics;
|
|
65
|
+
return view;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Applies mutations synchronously. executeMount would post to the UI thread,
|
|
69
|
+
// which a test has no message loop to pump -- though with no host installed
|
|
70
|
+
// postToUiThread runs inline anyway, so this is about being explicit rather
|
|
71
|
+
// than about avoiding a hang.
|
|
72
|
+
void apply(Win32MountingManager &manager, ShadowViewMutationList &&mutations) {
|
|
73
|
+
manager.applyTransaction(
|
|
74
|
+
kSurfaceId, MountingTransaction(kSurfaceId, 1, std::move(mutations), TransactionTelemetry{}));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
size_t childCount(const RnWin32View *view) {
|
|
78
|
+
return view->children().size();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// The tag of the nth child, or -1.
|
|
82
|
+
int32_t childTagAt(const RnWin32View *view, size_t index) {
|
|
83
|
+
if (index >= view->children().size()) {
|
|
84
|
+
return -1;
|
|
85
|
+
}
|
|
86
|
+
return view->children()[index]->tag();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
} // namespace
|
|
90
|
+
|
|
91
|
+
TEST(win32_create_and_insert_builds_the_tree) {
|
|
92
|
+
Win32MountingManager manager;
|
|
93
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
94
|
+
|
|
95
|
+
ShadowViewMutationList mutations;
|
|
96
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(makeView(10, 0, 0, 100, 50)));
|
|
97
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(makeView(11, 0, 60, 100, 50)));
|
|
98
|
+
mutations.push_back(
|
|
99
|
+
ShadowViewMutation::InsertMutation(kSurfaceId, makeView(10, 0, 0, 100, 50), 0));
|
|
100
|
+
mutations.push_back(
|
|
101
|
+
ShadowViewMutation::InsertMutation(kSurfaceId, makeView(11, 0, 60, 100, 50), 1));
|
|
102
|
+
apply(manager, std::move(mutations));
|
|
103
|
+
|
|
104
|
+
EXPECT_EQ(childCount(root), size_t{2});
|
|
105
|
+
EXPECT_EQ(childTagAt(root, 0), 10);
|
|
106
|
+
EXPECT_EQ(childTagAt(root, 1), 11);
|
|
107
|
+
|
|
108
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
TEST(win32_insert_honours_the_index) {
|
|
112
|
+
Win32MountingManager manager;
|
|
113
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
114
|
+
|
|
115
|
+
ShadowViewMutationList first;
|
|
116
|
+
first.push_back(ShadowViewMutation::CreateMutation(makeView(20, 0, 0, 10, 10)));
|
|
117
|
+
first.push_back(ShadowViewMutation::CreateMutation(makeView(21, 0, 0, 10, 10)));
|
|
118
|
+
first.push_back(ShadowViewMutation::InsertMutation(kSurfaceId, makeView(20, 0, 0, 10, 10), 0));
|
|
119
|
+
first.push_back(ShadowViewMutation::InsertMutation(kSurfaceId, makeView(21, 0, 0, 10, 10), 1));
|
|
120
|
+
apply(manager, std::move(first));
|
|
121
|
+
|
|
122
|
+
// An Insert's index counts positions in the parent's *final* child list, so
|
|
123
|
+
// this lands between the two. An append-only implementation passes every
|
|
124
|
+
// other test in this file.
|
|
125
|
+
ShadowViewMutationList second;
|
|
126
|
+
second.push_back(ShadowViewMutation::CreateMutation(makeView(22, 0, 0, 10, 10)));
|
|
127
|
+
second.push_back(ShadowViewMutation::InsertMutation(kSurfaceId, makeView(22, 0, 0, 10, 10), 1));
|
|
128
|
+
apply(manager, std::move(second));
|
|
129
|
+
|
|
130
|
+
EXPECT_EQ(childCount(root), size_t{3});
|
|
131
|
+
EXPECT_EQ(childTagAt(root, 0), 20);
|
|
132
|
+
EXPECT_EQ(childTagAt(root, 1), 22);
|
|
133
|
+
EXPECT_EQ(childTagAt(root, 2), 21);
|
|
134
|
+
|
|
135
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
TEST(win32_remove_detaches_but_does_not_destroy) {
|
|
139
|
+
Win32MountingManager manager;
|
|
140
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
141
|
+
|
|
142
|
+
ShadowViewMutationList mutations;
|
|
143
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(makeView(30, 0, 0, 10, 10)));
|
|
144
|
+
mutations.push_back(ShadowViewMutation::InsertMutation(kSurfaceId, makeView(30, 0, 0, 10, 10), 0));
|
|
145
|
+
apply(manager, std::move(mutations));
|
|
146
|
+
|
|
147
|
+
ShadowViewMutationList removal;
|
|
148
|
+
removal.push_back(ShadowViewMutation::RemoveMutation(kSurfaceId, makeView(30, 0, 0, 10, 10), 0));
|
|
149
|
+
apply(manager, std::move(removal));
|
|
150
|
+
|
|
151
|
+
// A reparent is a Remove and an Insert with no Delete between them, so the
|
|
152
|
+
// view has to survive the gap -- and the registry is the only thing holding
|
|
153
|
+
// it. Asking the registry is the assertion: if Remove had destroyed it, this
|
|
154
|
+
// would be null or a dangling pointer.
|
|
155
|
+
EXPECT_EQ(childCount(root), size_t{0});
|
|
156
|
+
EXPECT(manager.viewForTag(30) != nullptr);
|
|
157
|
+
|
|
158
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
TEST(win32_update_changes_frame_without_reparenting) {
|
|
162
|
+
Win32MountingManager manager;
|
|
163
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
164
|
+
|
|
165
|
+
ShadowViewMutationList mutations;
|
|
166
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(makeView(40, 0, 0, 100, 50)));
|
|
167
|
+
mutations.push_back(
|
|
168
|
+
ShadowViewMutation::InsertMutation(kSurfaceId, makeView(40, 0, 0, 100, 50), 0));
|
|
169
|
+
apply(manager, std::move(mutations));
|
|
170
|
+
|
|
171
|
+
ShadowViewMutationList update;
|
|
172
|
+
update.push_back(ShadowViewMutation::UpdateMutation(
|
|
173
|
+
makeView(40, 0, 0, 100, 50), makeView(40, 5, 6, 70, 30), kSurfaceId));
|
|
174
|
+
apply(manager, std::move(update));
|
|
175
|
+
|
|
176
|
+
RnWin32View *view = manager.viewForTag(40);
|
|
177
|
+
EXPECT(view != nullptr);
|
|
178
|
+
EXPECT_EQ(childCount(root), size_t{1});
|
|
179
|
+
EXPECT_NEAR(view->frame().x, 5.0, 0.001);
|
|
180
|
+
EXPECT_NEAR(view->frame().y, 6.0, 0.001);
|
|
181
|
+
EXPECT_NEAR(view->frame().width, 70.0, 0.001);
|
|
182
|
+
EXPECT_NEAR(view->frame().height, 30.0, 0.001);
|
|
183
|
+
|
|
184
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
TEST(win32_delete_removes_the_view_from_the_registry) {
|
|
188
|
+
Win32MountingManager manager;
|
|
189
|
+
manager.createSurfaceRoot(kSurfaceId);
|
|
190
|
+
|
|
191
|
+
ShadowViewMutationList mutations;
|
|
192
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(makeView(50, 0, 0, 10, 10)));
|
|
193
|
+
mutations.push_back(ShadowViewMutation::InsertMutation(kSurfaceId, makeView(50, 0, 0, 10, 10), 0));
|
|
194
|
+
apply(manager, std::move(mutations));
|
|
195
|
+
EXPECT(manager.viewForTag(50) != nullptr);
|
|
196
|
+
|
|
197
|
+
// Fabric guarantees the Remove before the Delete, and this is that order.
|
|
198
|
+
ShadowViewMutationList teardown;
|
|
199
|
+
teardown.push_back(ShadowViewMutation::RemoveMutation(kSurfaceId, makeView(50, 0, 0, 10, 10), 0));
|
|
200
|
+
teardown.push_back(ShadowViewMutation::DeleteMutation(makeView(50, 0, 0, 10, 10)));
|
|
201
|
+
apply(manager, std::move(teardown));
|
|
202
|
+
|
|
203
|
+
EXPECT(manager.viewForTag(50) == nullptr);
|
|
204
|
+
|
|
205
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
TEST(win32_nested_children_are_parented_to_their_own_parent) {
|
|
209
|
+
Win32MountingManager manager;
|
|
210
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
211
|
+
|
|
212
|
+
ShadowViewMutationList mutations;
|
|
213
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(makeView(60, 0, 0, 100, 100)));
|
|
214
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(makeView(61, 10, 10, 20, 20)));
|
|
215
|
+
mutations.push_back(
|
|
216
|
+
ShadowViewMutation::InsertMutation(kSurfaceId, makeView(60, 0, 0, 100, 100), 0));
|
|
217
|
+
// Parented to 60, not to the surface root.
|
|
218
|
+
mutations.push_back(ShadowViewMutation::InsertMutation(60, makeView(61, 10, 10, 20, 20), 0));
|
|
219
|
+
apply(manager, std::move(mutations));
|
|
220
|
+
|
|
221
|
+
EXPECT_EQ(childCount(root), size_t{1});
|
|
222
|
+
RnWin32View *middle = manager.viewForTag(60);
|
|
223
|
+
EXPECT(middle != nullptr);
|
|
224
|
+
EXPECT_EQ(childCount(middle), size_t{1});
|
|
225
|
+
EXPECT_EQ(childTagAt(middle, 0), 61);
|
|
226
|
+
|
|
227
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
TEST(win32_surface_root_is_reused_not_recreated) {
|
|
231
|
+
Win32MountingManager manager;
|
|
232
|
+
RnWin32View *first = manager.createSurfaceRoot(kSurfaceId);
|
|
233
|
+
RnWin32View *second = manager.createSurfaceRoot(kSurfaceId);
|
|
234
|
+
|
|
235
|
+
// In Fabric a SurfaceId *is* the root node's tag, and Fabric emits no Create
|
|
236
|
+
// for it -- the root shadow node is the base of every diff, so it must
|
|
237
|
+
// already exist when the first transaction arrives. Asking twice must not
|
|
238
|
+
// make two.
|
|
239
|
+
EXPECT(first == second);
|
|
240
|
+
|
|
241
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
TEST(win32_a_mutation_for_an_unknown_tag_is_survivable) {
|
|
245
|
+
Win32MountingManager manager;
|
|
246
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
247
|
+
|
|
248
|
+
// What a bug upstream, or a transaction racing a surface teardown, looks like
|
|
249
|
+
// from down here. It must not be fatal.
|
|
250
|
+
ShadowViewMutationList mutations;
|
|
251
|
+
mutations.push_back(
|
|
252
|
+
ShadowViewMutation::InsertMutation(kSurfaceId, makeView(999, 0, 0, 10, 10), 0));
|
|
253
|
+
mutations.push_back(ShadowViewMutation::RemoveMutation(kSurfaceId, makeView(998, 0, 0, 10, 10), 0));
|
|
254
|
+
mutations.push_back(ShadowViewMutation::DeleteMutation(makeView(997, 0, 0, 10, 10)));
|
|
255
|
+
apply(manager, std::move(mutations));
|
|
256
|
+
|
|
257
|
+
EXPECT_EQ(childCount(root), size_t{0});
|
|
258
|
+
|
|
259
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
TEST(win32_props_reach_the_view_through_a_mutation) {
|
|
263
|
+
Win32MountingManager manager;
|
|
264
|
+
manager.createSurfaceRoot(kSurfaceId);
|
|
265
|
+
|
|
266
|
+
ShadowViewMutationList mutations;
|
|
267
|
+
mutations.push_back(
|
|
268
|
+
ShadowViewMutation::CreateMutation(makeView(70, 0, 0, 64, 32, 1.0F, 0.0F, 0.0F)));
|
|
269
|
+
mutations.push_back(ShadowViewMutation::InsertMutation(
|
|
270
|
+
kSurfaceId, makeView(70, 0, 0, 64, 32, 1.0F, 0.0F, 0.0F), 0));
|
|
271
|
+
apply(manager, std::move(mutations));
|
|
272
|
+
|
|
273
|
+
// The whole trip: a ViewProps built here, through the walk, into the view's
|
|
274
|
+
// own state and out again as the dump the three hosts compare.
|
|
275
|
+
RnWin32View *view = manager.viewForTag(70);
|
|
276
|
+
EXPECT(view != nullptr);
|
|
277
|
+
EXPECT(view->hasBackgroundColor());
|
|
278
|
+
EXPECT_EQ(view->describeTree(), std::string("view tag=70 frame=(0,0 64x32) bg=#ff0000ff\n"));
|
|
279
|
+
|
|
280
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
TEST(win32_has_component_matches_the_registered_descriptors) {
|
|
284
|
+
Win32MountingManager manager;
|
|
285
|
+
|
|
286
|
+
// Two statements of one fact, and when they disagree the registry wins:
|
|
287
|
+
// Fabric builds shadow nodes nothing can mount and the app renders blank
|
|
288
|
+
// rectangles rather than reporting anything. See ComponentRegistryWin32.cpp.
|
|
289
|
+
EXPECT(manager.hasComponent("View"));
|
|
290
|
+
EXPECT(manager.hasComponent("RootView"));
|
|
291
|
+
EXPECT(manager.hasComponent("Paragraph"));
|
|
292
|
+
EXPECT(manager.hasComponent("Image"));
|
|
293
|
+
EXPECT(manager.hasComponent("ScrollView"));
|
|
294
|
+
EXPECT(manager.hasComponent("TextInput"));
|
|
295
|
+
EXPECT(manager.hasComponent("ActivityIndicatorView"));
|
|
296
|
+
EXPECT(manager.hasComponent("Switch"));
|
|
297
|
+
EXPECT(manager.hasComponent("ModalHostView"));
|
|
298
|
+
EXPECT(manager.hasComponent("PullToRefreshView"));
|
|
299
|
+
// What React Native substitutes for a component nobody registered. Mounting
|
|
300
|
+
// it is what turns "nothing happens" into a view the tree dump can show.
|
|
301
|
+
EXPECT(manager.hasComponent("UnimplementedNativeView"));
|
|
302
|
+
|
|
303
|
+
// Claiming a component this host cannot mount is worse than admitting the
|
|
304
|
+
// gap. `ActivityIndicator` is here rather than above on purpose: the
|
|
305
|
+
// component React Native actually mounts is `ActivityIndicatorView`, and
|
|
306
|
+
// answering to the name a reader expects would be answering to a name
|
|
307
|
+
// nothing sends.
|
|
308
|
+
EXPECT(!manager.hasComponent("Slider"));
|
|
309
|
+
EXPECT(!manager.hasComponent("ActivityIndicator"));
|
|
310
|
+
EXPECT(!manager.hasComponent("SomethingNobodyHasHeardOf"));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// --- transformOrigin --------------------------------------------------------
|
|
314
|
+
//
|
|
315
|
+
// `resolveTransform` folds the origin into the matrix, and all three hosts
|
|
316
|
+
// call it -- so this has been "passed through but never exercised" since it
|
|
317
|
+
// was written. What makes it checkable without a display is that the anchor
|
|
318
|
+
// is a claim about a point: scaling about the top-left must leave the
|
|
319
|
+
// top-left corner exactly where it was.
|
|
320
|
+
//
|
|
321
|
+
// The hosts anchor a transform at the view's centre, which is what an
|
|
322
|
+
// untouched `transformOrigin` means, so the matrix is in centre-relative
|
|
323
|
+
// coordinates and the top-left corner is at (-w/2, -h/2).
|
|
324
|
+
//
|
|
325
|
+
// The same two tests are in the other two suites, with the same tags, for the
|
|
326
|
+
// same reason the ones above are.
|
|
327
|
+
|
|
328
|
+
namespace {
|
|
329
|
+
|
|
330
|
+
ShadowView makeTransformed(Tag tag,
|
|
331
|
+
float width,
|
|
332
|
+
float height,
|
|
333
|
+
facebook::react::Transform transform,
|
|
334
|
+
facebook::react::TransformOrigin origin = {}) {
|
|
335
|
+
// Fresh props rather than a copy of makeView's: BaseViewProps has a deleted
|
|
336
|
+
// copy constructor at React Native 0.86, which is what a current Expo app
|
|
337
|
+
// installs. Copying compiled against main and broke the version an app
|
|
338
|
+
// actually has -- found by building a real create-expo-app, not here.
|
|
339
|
+
ShadowView view = makeView(tag, 0.0F, 0.0F, width, height);
|
|
340
|
+
auto props = std::make_shared<ViewProps>();
|
|
341
|
+
props->transform = transform;
|
|
342
|
+
props->transformOrigin = origin;
|
|
343
|
+
view.props = props;
|
|
344
|
+
return view;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
} // namespace
|
|
348
|
+
|
|
349
|
+
TEST(transform_origin_anchors_the_corner_it_names) {
|
|
350
|
+
Win32MountingManager manager;
|
|
351
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
352
|
+
|
|
353
|
+
using facebook::react::Transform;
|
|
354
|
+
using facebook::react::TransformOrigin;
|
|
355
|
+
using facebook::react::UnitType;
|
|
356
|
+
using facebook::react::ValueUnit;
|
|
357
|
+
|
|
358
|
+
// Doubled about the top-left of a 100x50 view.
|
|
359
|
+
TransformOrigin topLeft;
|
|
360
|
+
topLeft.xy = {ValueUnit(0.0F, UnitType::Point), ValueUnit(0.0F, UnitType::Point)};
|
|
361
|
+
|
|
362
|
+
ShadowViewMutationList mutations;
|
|
363
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(
|
|
364
|
+
makeTransformed(30, 100.0F, 50.0F, Transform::Scale(2.0F, 2.0F, 1.0F), topLeft)));
|
|
365
|
+
mutations.push_back(ShadowViewMutation::InsertMutation(
|
|
366
|
+
kSurfaceId,
|
|
367
|
+
makeTransformed(30, 100.0F, 50.0F, Transform::Scale(2.0F, 2.0F, 1.0F), topLeft),
|
|
368
|
+
0));
|
|
369
|
+
apply(manager, std::move(mutations));
|
|
370
|
+
|
|
371
|
+
const auto matrix = basalt::testing::transformIn(root->describeTree(), 30);
|
|
372
|
+
EXPECT_EQ(matrix[0], 2.0);
|
|
373
|
+
EXPECT_EQ(matrix[3], 2.0);
|
|
374
|
+
|
|
375
|
+
// The corner the origin names, in the centre-relative coordinates the
|
|
376
|
+
// matrix is written in, has to come back to itself: (-50,-25) scaled by two
|
|
377
|
+
// is (-100,-50), so the translation has to put 50 and 25 back.
|
|
378
|
+
const double cornerX = matrix[0] * -50.0 + matrix[2] * -25.0 + matrix[4];
|
|
379
|
+
const double cornerY = matrix[1] * -50.0 + matrix[3] * -25.0 + matrix[5];
|
|
380
|
+
EXPECT_EQ(cornerX, -50.0);
|
|
381
|
+
EXPECT_EQ(cornerY, -25.0);
|
|
382
|
+
|
|
383
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// And with no origin set, the centre is the anchor -- which is the default
|
|
387
|
+
// every host relies on, and the reason an unset origin must not be folded in
|
|
388
|
+
// as (0,0).
|
|
389
|
+
TEST(no_transform_origin_anchors_the_centre) {
|
|
390
|
+
Win32MountingManager manager;
|
|
391
|
+
RnWin32View *root = manager.createSurfaceRoot(kSurfaceId);
|
|
392
|
+
|
|
393
|
+
using facebook::react::Transform;
|
|
394
|
+
|
|
395
|
+
ShadowViewMutationList mutations;
|
|
396
|
+
mutations.push_back(ShadowViewMutation::CreateMutation(
|
|
397
|
+
makeTransformed(31, 100.0F, 50.0F, Transform::Scale(2.0F, 2.0F, 1.0F))));
|
|
398
|
+
mutations.push_back(ShadowViewMutation::InsertMutation(
|
|
399
|
+
kSurfaceId, makeTransformed(31, 100.0F, 50.0F, Transform::Scale(2.0F, 2.0F, 1.0F)), 0));
|
|
400
|
+
apply(manager, std::move(mutations));
|
|
401
|
+
|
|
402
|
+
const auto matrix = basalt::testing::transformIn(root->describeTree(), 31);
|
|
403
|
+
EXPECT_EQ(matrix[0], 2.0);
|
|
404
|
+
EXPECT_EQ(matrix[3], 2.0);
|
|
405
|
+
// No translation at all: the centre is already the anchor.
|
|
406
|
+
EXPECT_EQ(matrix[4], 0.0);
|
|
407
|
+
EXPECT_EQ(matrix[5], 0.0);
|
|
408
|
+
|
|
409
|
+
manager.destroySurfaceRoot(kSurfaceId);
|
|
410
|
+
}
|