basalt-win32 0.0.0-stage → 0.1.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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/cli/runWindows.js +35 -0
  3. package/cli/shared.js +75 -0
  4. package/native/CMakeLists.txt +429 -0
  5. package/native/tests/test_win32_accessibility.cpp +585 -0
  6. package/native/tests/test_win32_animated_image.cpp +351 -0
  7. package/native/tests/test_win32_clipboard.cpp +121 -0
  8. package/native/tests/test_win32_focus.cpp +195 -0
  9. package/native/tests/test_win32_hittest.cpp +750 -0
  10. package/native/tests/test_win32_image.cpp +370 -0
  11. package/native/tests/test_win32_imageloader.cpp +208 -0
  12. package/native/tests/test_win32_input.cpp +511 -0
  13. package/native/tests/test_win32_key_events.cpp +84 -0
  14. package/native/tests/test_win32_mounting.cpp +757 -0
  15. package/native/tests/test_win32_paint.cpp +1799 -0
  16. package/native/tests/test_win32_scrollview.cpp +647 -0
  17. package/native/tests/test_win32_selection.cpp +215 -0
  18. package/native/tests/test_win32_text.cpp +1456 -0
  19. package/native/tests/test_win32_textinput.cpp +1594 -0
  20. package/native/tests/test_win32_titlebar.cpp +111 -0
  21. package/native/tests/test_win32_titlebar_actions.cpp +62 -0
  22. package/native/tests/test_win32_view.cpp +222 -0
  23. package/native/win32/ColorSchemeWin32.cpp +56 -0
  24. package/native/win32/ComponentRegistryWin32.cpp +144 -0
  25. package/native/win32/DirectWriteLayout.cpp +485 -0
  26. package/native/win32/DirectWriteLayout.h +77 -0
  27. package/native/win32/DirectWriteLayoutManager.cpp +154 -0
  28. package/native/win32/FontRegistryDirectWrite.cpp +117 -0
  29. package/native/win32/PlatformServicesWin32.cpp +744 -0
  30. package/native/win32/RnWin32Accessible.cpp +343 -0
  31. package/native/win32/RnWin32Accessible.h +130 -0
  32. package/native/win32/RnWin32Image.cpp +588 -0
  33. package/native/win32/RnWin32Image.h +139 -0
  34. package/native/win32/RnWin32TextLayout.cpp +1379 -0
  35. package/native/win32/RnWin32TextLayout.h +390 -0
  36. package/native/win32/RnWin32View.cpp +2956 -0
  37. package/native/win32/RnWin32View.h +926 -0
  38. package/native/win32/Win32AnimationChoreographer.cpp +76 -0
  39. package/native/win32/Win32AnimationChoreographer.h +61 -0
  40. package/native/win32/Win32Clip.h +209 -0
  41. package/native/win32/Win32Cursors.cpp +309 -0
  42. package/native/win32/Win32Cursors.h +121 -0
  43. package/native/win32/Win32DropTarget.cpp +567 -0
  44. package/native/win32/Win32DropTarget.h +42 -0
  45. package/native/win32/Win32Focus.cpp +262 -0
  46. package/native/win32/Win32Focus.h +109 -0
  47. package/native/win32/Win32ImageLoader.cpp +199 -0
  48. package/native/win32/Win32ImageLoader.h +133 -0
  49. package/native/win32/Win32InputScopes.h +92 -0
  50. package/native/win32/Win32KeyEvents.cpp +126 -0
  51. package/native/win32/Win32KeyEvents.h +20 -0
  52. package/native/win32/Win32MenuBar.cpp +382 -0
  53. package/native/win32/Win32MenuBar.h +16 -0
  54. package/native/win32/Win32MountingManager.cpp +1282 -0
  55. package/native/win32/Win32MountingManager.h +243 -0
  56. package/native/win32/Win32Offscreen.h +53 -0
  57. package/native/win32/Win32Packaging.cpp +161 -0
  58. package/native/win32/Win32Packaging.h +56 -0
  59. package/native/win32/Win32RunLoopObserver.cpp +48 -0
  60. package/native/win32/Win32RunLoopObserver.h +42 -0
  61. package/native/win32/Win32ScrollView.cpp +718 -0
  62. package/native/win32/Win32ScrollView.h +256 -0
  63. package/native/win32/Win32SkiaContext.cpp +221 -0
  64. package/native/win32/Win32SkiaContext.h +53 -0
  65. package/native/win32/Win32SkiaModule.cpp +80 -0
  66. package/native/win32/Win32SkiaModule.h +50 -0
  67. package/native/win32/Win32SkiaPeer.cpp +358 -0
  68. package/native/win32/Win32SkiaPeer.h +66 -0
  69. package/native/win32/Win32SkiaUnicode.cpp +42 -0
  70. package/native/win32/Win32Snapshot.cpp +201 -0
  71. package/native/win32/Win32Snapshot.h +66 -0
  72. package/native/win32/Win32Strings.h +54 -0
  73. package/native/win32/Win32TextInput.cpp +1296 -0
  74. package/native/win32/Win32TextInput.h +341 -0
  75. package/native/win32/Win32TitleBar.cpp +562 -0
  76. package/native/win32/Win32TitleBar.h +146 -0
  77. package/native/win32/Win32TitleBarLayout.cpp +46 -0
  78. package/native/win32/Win32TitleBarLayout.h +58 -0
  79. package/native/win32/Win32TouchDispatcher.cpp +577 -0
  80. package/native/win32/Win32TouchDispatcher.h +201 -0
  81. package/native/win32/Win32UiThread.h +27 -0
  82. package/native/win32/Win32WindowControl.cpp +329 -0
  83. package/native/win32/Win32WindowModule.cpp +209 -0
  84. package/native/win32/Win32WindowModule.h +72 -0
  85. package/native/win32/demo_layout_win32.cpp +232 -0
  86. package/native/win32/main_win32.cpp +2722 -0
  87. package/native/win32/mount_harness_win32.cpp +316 -0
  88. package/package.json +25 -4
  89. package/react-native.config.js +22 -0
  90. package/README.md +0 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vince Vella
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `react-native run-windows`.
3
+ *
4
+ * Four strings and a path. Everything a desktop run actually does is in
5
+ * basalt-core's cli/desktop.js, shared with `run-linux` and
6
+ * `run-macos`, because none of it is about a toolkit -- see the note at the top
7
+ * of that file.
8
+ *
9
+ * The command name is react-native-windows', deliberately: an app that already
10
+ * knows `react-native run-windows` should not have to learn a second spelling
11
+ * to try this one. Same argument as the `windows` platform name.
12
+ *
13
+ * @format
14
+ */
15
+
16
+ // @ts-check
17
+ 'use strict';
18
+
19
+ const path = require('path');
20
+
21
+ const {shared, sharedPackageDir} = require('./shared');
22
+
23
+ const {makeRunCommand} = shared('cli/desktop');
24
+
25
+ module.exports = makeRunCommand({
26
+ platform: 'windows',
27
+ label: 'Windows',
28
+ command: 'run-windows',
29
+ binary: 'basalt_win32.exe',
30
+ nativeDir: path.resolve(__dirname, '..', 'native'),
31
+ coreDir: path.join(sharedPackageDir(), 'native'),
32
+ toolchain:
33
+ 'the Visual Studio Build Tools with clang-cl, a Git Bash to run bootstrap.sh in, ' +
34
+ 'and a vcpkg with glog, fmt, double-conversion, boost, gflags, openssl and curl',
35
+ });
package/cli/shared.js ADDED
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Reaching basalt-core, the shared half, from this package.
3
+ *
4
+ * The one file in a platform package's CLI that cannot itself be shared,
5
+ * because it is what finds the thing everything else is shared through. Two
6
+ * layouts matter and only one of them resolves by name.
7
+ *
8
+ * Installed into an app, basalt-core is a sibling in node_modules and
9
+ * `require('basalt-core/...')` finds it. In a checkout of this
10
+ * repository the two packages are sibling directories with nothing installed
11
+ * between them -- deliberately, since this repo has no node_modules of its own
12
+ * -- and the same require fails. So: by name first, because that is the layout
13
+ * an app is in, and beside us second, because that is the layout it is
14
+ * developed in.
15
+ *
16
+ * Both reach the *built* package. basalt-core is TypeScript: by name
17
+ * resolves through its `exports` map, which points into `dist/`, and the
18
+ * sibling path has to say so itself. A checkout that has not run
19
+ * scripts/build_ts.sh has nothing here to find, which is what the error says.
20
+ *
21
+ * @format
22
+ */
23
+
24
+ // @ts-check
25
+ 'use strict';
26
+
27
+ const path = require('path');
28
+
29
+ const SIBLING = path.resolve(__dirname, '..', '..', 'basalt-core');
30
+
31
+ /**
32
+ * Where basalt-core is on disk. Same two layouts, same order.
33
+ * @returns {string}
34
+ */
35
+ function sharedPackageDir() {
36
+ try {
37
+ return path.dirname(require.resolve('basalt-core/package.json'));
38
+ } catch (error) {
39
+ if (/** @type {NodeJS.ErrnoException} */ (error).code !== 'MODULE_NOT_FOUND') {
40
+ throw error;
41
+ }
42
+ return SIBLING;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * One of basalt-core's modules, by subpath.
48
+ * @param {string} subpath
49
+ * @returns {any}
50
+ */
51
+ function shared(subpath) {
52
+ const name = `basalt-core/${subpath}`;
53
+ try {
54
+ return require(name);
55
+ } catch (error) {
56
+ if (/** @type {NodeJS.ErrnoException} */ (error).code !== 'MODULE_NOT_FOUND') {
57
+ // The module was found and threw on its way up. Passing it through keeps
58
+ // a real error in that file from being reported as a missing package.
59
+ throw error;
60
+ }
61
+ try {
62
+ return require(path.join(SIBLING, 'dist', subpath));
63
+ } catch (siblingError) {
64
+ if (/** @type {NodeJS.ErrnoException} */ (siblingError).code === 'MODULE_NOT_FOUND') {
65
+ throw new Error(
66
+ `could not load ${name}. In a checkout, basalt-core has to be ` +
67
+ 'built first: run scripts/build_ts.sh.',
68
+ );
69
+ }
70
+ throw siblingError;
71
+ }
72
+ }
73
+ }
74
+
75
+ module.exports = {shared, sharedPackageDir};
@@ -0,0 +1,429 @@
1
+ # basalt-win32 — the Windows view layer, over Win32 and Direct2D.
2
+ #
3
+ # A view layer, a mounting manager and a host. Everything behind them is in
4
+ # basalt-core, which this adds as a subdirectory.
5
+ #
6
+ # `win32/` rather than `windows/`: the toolkit is what differs, and the name
7
+ # would be wrong the moment WinUI or something after it mattered. The npm
8
+ # package is `-win32` for the same reason `-appkit` is not `-macos`, and neither
9
+ # name is the JavaScript platform's -- that one is `windows`, matching
10
+ # react-native-windows, and lives in the shared package.
11
+
12
+ cmake_minimum_required(VERSION 3.13)
13
+ project(basalt_win32 CXX)
14
+
15
+ set(CMAKE_CXX_STANDARD 20)
16
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
17
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
18
+
19
+ # Executables at the top of the build tree whether this is configured directly
20
+ # or added by a wrapper, so `build/basalt_win32` means the same thing either
21
+ # way. Every script and document here names that path.
22
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
23
+ # ...including under the multi-config generators, which are the default on
24
+ # Windows: Visual Studio and Ninja Multi-Config both append Debug/ or Release/
25
+ # to the directory above unless told otherwise, and a document that says
26
+ # `build/basalt_win32_tests` would be wrong on the platform it was written for.
27
+ foreach(config ${CMAKE_CONFIGURATION_TYPES})
28
+ string(TOUPPER ${config} config_upper)
29
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${config_upper} ${CMAKE_BINARY_DIR})
30
+ endforeach()
31
+
32
+ # ---------------------------------------------------------------------------
33
+ # Finding basalt-core, the shared half.
34
+ #
35
+ # The default works in both layouts this can be built from: a checkout of this
36
+ # repository, where the packages are siblings under packages/, and an app's
37
+ # node_modules, where npm hoists them side by side.
38
+ #
39
+ # Guarded on the target rather than on the variable: a build that configures
40
+ # more than one platform package would otherwise add the same directory twice,
41
+ # which CMake refuses.
42
+ # ---------------------------------------------------------------------------
43
+ if(NOT TARGET basalt_core)
44
+ if(NOT DEFINED BASALT_CORE_DIR)
45
+ set(BASALT_CORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../basalt-core/native)
46
+ endif()
47
+ get_filename_component(BASALT_CORE_DIR "${BASALT_CORE_DIR}" ABSOLUTE)
48
+ if(NOT EXISTS ${BASALT_CORE_DIR}/CMakeLists.txt)
49
+ message(FATAL_ERROR
50
+ "basalt-core not found at ${BASALT_CORE_DIR}.\n"
51
+ "Pass -DBASALT_CORE_DIR=<path to basalt-core/native>.")
52
+ endif()
53
+ # Capability packages first, and only here, because they contribute include
54
+ # directories to basalt_core and CMake resolves those when the target is
55
+ # created rather than afterwards.
56
+ #
57
+ # This used to live only in the repository's root CMakeLists, which is the
58
+ # entry point for a checkout and is not the entry point for an app: the CLI
59
+ # configures -S <host package>/native, so the loop never ran and
60
+ # core/portability_probe.cpp failed on a Notifications.h that nothing had
61
+ # put on the path. A checkout could not see it, because there the root added
62
+ # the packages first and the header was always there.
63
+ #
64
+ # Guarded on the property rather than the variable for the same reason the
65
+ # block around it is guarded on the target: a build configuring two host
66
+ # packages must not add the same directory twice.
67
+ get_property(basalt_packages_added GLOBAL PROPERTY BASALT_PACKAGES_ADDED)
68
+ if(NOT basalt_packages_added)
69
+ set_property(GLOBAL PROPERTY BASALT_PACKAGES_ADDED TRUE)
70
+ foreach(package ${BASALT_PACKAGES})
71
+ if(EXISTS ${package}/native/CMakeLists.txt)
72
+ get_filename_component(basalt_package_name ${package} NAME)
73
+ message(STATUS "basalt: capability package ${basalt_package_name}")
74
+ add_subdirectory(${package}/native basalt-package-${basalt_package_name})
75
+ endif()
76
+ endforeach()
77
+ endif()
78
+
79
+ add_subdirectory(${BASALT_CORE_DIR} basalt_core)
80
+ endif()
81
+
82
+ # What capability packages contributed for this host; see
83
+ # packages/basalt-notifications for what a package sets.
84
+ #
85
+ # Read *after* the block above, because that block is where the packages are
86
+ # added. It used to be read at the top of this file, which worked for a
87
+ # checkout -- the root CMakeLists adds the packages before it adds this one --
88
+ # and silently contributed nothing for an app, where this file is the entry
89
+ # point. The symptom was a link error naming every notification seam.
90
+ get_property(BASALT_PACKAGE_WIN32_SOURCES GLOBAL PROPERTY BASALT_PACKAGE_WIN32_SOURCES)
91
+ # And what those sources need linked. A package contributing an implementation
92
+ # that reaches for a library had no way to say so; see the same property in the
93
+ # AppKit package for what went missing.
94
+ get_property(BASALT_PACKAGE_WIN32_LINK_LIBRARIES GLOBAL PROPERTY BASALT_PACKAGE_WIN32_LINK_LIBRARIES)
95
+ # And a package's own unit tests, which run in this host's suite. A capability
96
+ # with a platform half has nowhere else to be tested: it is compiled into the
97
+ # host binary, so the host's suite is the only binary that has it.
98
+ get_property(BASALT_PACKAGE_TESTS GLOBAL PROPERTY BASALT_PACKAGE_TESTS)
99
+
100
+ if(NOT WIN32)
101
+ # Not an error. A checkout builds every package it finds, and on anything but
102
+ # Windows this one has nothing it could compile.
103
+ message(STATUS "basalt-win32 skipped: not Windows")
104
+ return()
105
+ endif()
106
+
107
+ # ---------------------------------------------------------------------------
108
+ # What this project's own sources are held to.
109
+ #
110
+ # The GTK and AppKit halves say `-Wall -Wextra`, which MSVC does not speak.
111
+ # /W4 is the nearest equivalent and /permissive- is the part that matters more:
112
+ # without it MSVC accepts things no other compiler in this project would, and
113
+ # the first anyone would hear of it is the Linux build failing on code that
114
+ # compiled here. Set on targets rather than globally, so React Native's own
115
+ # sources -- which set their own flags and are not warning-clean under /W4 --
116
+ # never inherit them.
117
+ #
118
+ # Note that clang-cl reports as MSVC here, which is intended: it takes the same
119
+ # flags, and `docs/DECISIONS.md` prefers clang where there is a choice.
120
+ # ---------------------------------------------------------------------------
121
+ if(MSVC)
122
+ set(BASALT_WIN32_WARNINGS /W4 /permissive-)
123
+ else()
124
+ set(BASALT_WIN32_WARNINGS -Wall -Wextra)
125
+ endif()
126
+
127
+ # UNICODE, because every Win32 entry point in this project takes wide strings
128
+ # and the ANSI variants silently lose anything outside the active code page --
129
+ # which for React Native, where a string is UTF-8 from JavaScript, is most of
130
+ # the world. NOMINMAX and WIN32_LEAN_AND_MEAN because windows.h otherwise
131
+ # defines `min` and `max` as macros and breaks <algorithm> at a distance.
132
+ #
133
+ # _CRT_SECURE_NO_WARNINGS is not laziness about a real hazard: what it silences
134
+ # here is C4996 on `std::getenv`, which the other two platforms call in the same
135
+ # place for the same reason and which has no portable replacement. Anything that
136
+ # genuinely wants the checked CRT can ask for it on its own.
137
+ add_compile_definitions(UNICODE _UNICODE NOMINMAX WIN32_LEAN_AND_MEAN _CRT_SECURE_NO_WARNINGS)
138
+
139
+ # ---------------------------------------------------------------------------
140
+ # basalt_win32_view — the Win32 view layer.
141
+ #
142
+ # No React Native dependency, so it builds and is tested on its own, on a
143
+ # Windows box with nothing installed but a compiler and the SDK. Direct2D, WIC
144
+ # and USER32 all ship with the operating system; there is nothing to fetch.
145
+ # ---------------------------------------------------------------------------
146
+ add_library(basalt_win32_view STATIC
147
+ win32/RnWin32View.cpp
148
+ # The paragraph object. DirectWrite only, no React Native, which is what keeps
149
+ # this target buildable and testable with nothing else installed.
150
+ win32/RnWin32TextLayout.cpp
151
+ # <Image> pixels: the WIC decode and the four resize modes. The fetch that
152
+ # feeds it is core/ImageBytes.cpp in the shared half, because a URI means the
153
+ # same thing on every desktop.
154
+ win32/RnWin32Image.cpp
155
+ # UI Automation. Windows inverts what the other two do -- a provider answers
156
+ # questions rather than a widget carrying properties; see the header.
157
+ win32/RnWin32Accessible.cpp
158
+ # Offscreen rendering, to a PNG or to pixels a test can read. The second is
159
+ # why this is in the view target rather than beside the demo: it is what the
160
+ # rendering assertions in tests/test_win32_paint.cpp are built on.
161
+ win32/Win32Snapshot.cpp
162
+ # The cursors Windows has no stock art for -- six CSS keywords drawn here as
163
+ # DIBs. Header-only until they were drawn; see Win32Cursors.h.
164
+ win32/Win32Cursors.cpp
165
+ # Where a hidden title bar's pieces are -- the caption buttons and the drag
166
+ # regions. Pure geometry over the view tree, so it is tested here with no
167
+ # window and no React Native.
168
+ win32/Win32TitleBarLayout.cpp)
169
+ target_compile_options(basalt_win32_view PRIVATE ${BASALT_WIN32_WARNINGS})
170
+ target_include_directories(basalt_win32_view PUBLIC win32)
171
+ # The header-only part of core, and only that: FocusRing.h, Backface.h,
172
+ # ImageAnimation.h and ShadowShape.h so far. None of them has React Native in
173
+ # it, so taking them does not make this target depend on the half that does --
174
+ # and the alternative is a focus ring that is a different blue on each desktop,
175
+ # three toolkits each with their own idea of which way a rotated card is facing,
176
+ # a GIF paced differently on each, and a hand-rolled copy of CSS's shadow-corner
177
+ # cubic per platform.
178
+ #
179
+ # Header-only is the constraint, not a preference: this library links no core,
180
+ # so anything it takes from there has to be `inline`.
181
+ target_include_directories(basalt_win32_view PUBLIC
182
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../basalt-core/native/core)
183
+ # dxguid is for the effect CLSIDs, and it is the kind of thing that only a
184
+ # linker tells you: `CLSID_D2D1Shadow` and its siblings are `DEFINE_GUID`
185
+ # declarations in d2d1effects.h, so the symbols live in that library rather
186
+ # than in d2d1. Without it a text shadow compiles and fails to link.
187
+ target_link_libraries(basalt_win32_view PUBLIC
188
+ d2d1 dwrite windowscodecs uiautomationcore ole32 oleaut32 user32 shcore dxguid)
189
+
190
+ add_executable(demo_layout_win32 win32/demo_layout_win32.cpp)
191
+ target_compile_options(demo_layout_win32 PRIVATE ${BASALT_WIN32_WARNINGS})
192
+ target_link_libraries(demo_layout_win32 PRIVATE basalt_win32_view)
193
+
194
+ # The runner comes from the shared half, which knows about no toolkit: the test
195
+ # infrastructure is shared even though the views are not. Unlike the GTK suite
196
+ # this one brings no separate entry point -- there is nothing to initialise
197
+ # before a view exists -- so `main` sits at the bottom of test_win32_view.cpp,
198
+ # as it does on the AppKit side.
199
+ set(BASALT_WIN32_TEST_SOURCES
200
+ ${BASALT_TEST_HARNESS}
201
+ tests/test_win32_view.cpp
202
+ # What actually reached the pixels. Needs no display and no window, which is
203
+ # why this platform can assert it and the other two cannot; see the file.
204
+ tests/test_win32_paint.cpp
205
+ # Picking. In the view layer rather than beside a touch dispatcher, so that
206
+ # testing it needs no React Native -- the same arrangement AppKit settled on.
207
+ tests/test_win32_hittest.cpp
208
+ # DirectWrite measurement, against RnWin32TextLayout alone.
209
+ tests/test_win32_text.cpp
210
+ # The resize modes, against a real bitmap and real pixels.
211
+ tests/test_win32_image.cpp
212
+ # The UIA mapping. The React Native role name is what the cross-platform diff
213
+ # compares; this is where the platform half is checked.
214
+ tests/test_win32_accessibility.cpp
215
+ # A hidden title bar's geometry: the caption buttons and the drag regions.
216
+ tests/test_win32_titlebar.cpp)
217
+
218
+ # ---------------------------------------------------------------------------
219
+ # basalt_win32_mounting — the Windows half of the Fabric mounting manager.
220
+ #
221
+ # The mutation walk is not here: it is in the shared half, in
222
+ # core/MountingWalk.h. What is here is what is genuinely Windows about mounting,
223
+ # plus the four seams a platform owes the core.
224
+ #
225
+ # Skipped when the build was not pointed at a React Native, so the view layer
226
+ # above still builds and tests on a Windows box with nothing but a compiler.
227
+ # ---------------------------------------------------------------------------
228
+ if(TARGET basalt_core)
229
+ add_library(basalt_win32_mounting STATIC
230
+ win32/Win32MountingManager.cpp
231
+ # Mouse messages -> React Native touches. In the library rather than in the
232
+ # host so that tests can drive it, which is the only way the touch state
233
+ # machine is provable without a cursor.
234
+ win32/Win32Focus.cpp
235
+ win32/Win32KeyEvents.cpp
236
+ # Why Windows cannot show a notification; see the file.
237
+ ${BASALT_PACKAGE_WIN32_SOURCES}
238
+ # The AppUserModelID and the Start Menu shortcut behind it, which is what
239
+ # makes a notification say which application it came from.
240
+ win32/Win32Packaging.cpp
241
+ win32/Win32TouchDispatcher.cpp
242
+ # <ScrollView>: the offset, the unthrottled state write-back, the wheel and
243
+ # the commands. Routing the wheel is this platform's alone -- there is no
244
+ # responder chain and no per-widget controller to attach one to.
245
+ win32/Win32ScrollView.cpp
246
+ # <TextInput>: a real EDIT control, which is a child window rather than a
247
+ # painted view -- so it is also the only component whose peer the host has
248
+ # to position, forward messages to, and answer colour questions for.
249
+ win32/Win32TextInput.cpp
250
+ # <Image> pixels: the fetch and the decode, both off the UI thread. The
251
+ # fetch itself is core/ImageBytes.cpp in the shared half.
252
+ win32/Win32ImageLoader.cpp
253
+ # Which components this platform claims. See core/ComponentRegistry.h, and
254
+ # note this and Win32MountingManager::hasComponent must agree.
255
+ win32/ComponentRegistryWin32.cpp
256
+ # AttributedString -> RnWin32TextLayout. Shared by measurement and painting,
257
+ # so they agree, which is the whole reason it is one file.
258
+ win32/DirectWriteLayout.cpp
259
+ # Replaces React Native's stub TextLayoutManager; see the shared half's
260
+ # cmake/ReactNativeCore.cmake for why the stub has to leave the build.
261
+ win32/DirectWriteLayoutManager.cpp
262
+ # Windows' implementation of core/FontRegistry.h -- the seam phase 17 named.
263
+ win32/FontRegistryDirectWrite.cpp
264
+ # ...and of core/ColorScheme.h.
265
+ win32/ColorSchemeWin32.cpp
266
+ # ...and of core/PlatformServices.h, which is also where postToUiThread
267
+ # lives -- the marshalling the mounting manager depends on.
268
+ win32/PlatformServicesWin32.cpp
269
+ # The window's title bar: DWM's colours and dark mode, and the caption the
270
+ # host draws when an app hides the system's. And BasaltWindow, the module
271
+ # JavaScript reaches it through.
272
+ # Accepting a file or text dragged onto the window; see
273
+ # core/DragAndDrop.h for the model the three hosts share.
274
+ win32/Win32DropTarget.cpp
275
+ win32/Win32TitleBar.cpp
276
+ # A window's size, position and full-screen state; see core/WindowControl.h.
277
+ win32/Win32WindowControl.cpp
278
+ # The application menu; see core/MenuModel.h for why the three differ.
279
+ win32/Win32MenuBar.cpp
280
+ win32/Win32WindowModule.cpp)
281
+ target_compile_options(basalt_win32_mounting PRIVATE ${BASALT_WIN32_WARNINGS})
282
+ target_include_directories(basalt_win32_mounting PUBLIC win32)
283
+ target_link_libraries(basalt_win32_mounting PUBLIC basalt_win32_view basalt_core)
284
+
285
+ # @shopify/react-native-skia, when the build was pointed at an app that has
286
+ # it. See ../../basalt-core/native/cmake/Skia.cmake.
287
+ #
288
+ # Here rather than on basalt_core, for the reason the AppKit package gives:
289
+ # a platform context is a host's dependency. The Windows one reaches
290
+ # DirectWrite and the Win32 DPI call, and core/portability_probe.cpp links
291
+ # the core with no toolkit on purpose.
292
+ if(TARGET skia_core)
293
+ target_link_libraries(basalt_win32_mounting PUBLIC skia_core)
294
+ target_sources(basalt_win32_mounting PUBLIC $<TARGET_OBJECTS:skia_core>)
295
+ target_compile_definitions(basalt_win32_mounting PUBLIC BASALT_HAS_SKIA=1)
296
+ # This host's half: the TurboModule the package asks for by name, the
297
+ # platform context it hands to Skia, and the peer behind a `<Canvas>`.
298
+ # See win32/Win32SkiaModule.h and win32/Win32SkiaPeer.h.
299
+ target_sources(basalt_win32_mounting PRIVATE
300
+ win32/Win32SkiaModule.cpp
301
+ win32/Win32SkiaContext.cpp
302
+ # AppKitSkiaPeer.mm's opposite number. Where that one hands the package a
303
+ # Metal layer, this renders into memory and lets the Direct2D walk draw
304
+ # the result -- this host has no layer tree to hang a canvas in.
305
+ win32/Win32SkiaPeer.cpp
306
+ # The unicode factory the package asks for by name on anything that is
307
+ # not Apple, answered with the backend that is actually linked here.
308
+ win32/Win32SkiaUnicode.cpp)
309
+ endif()
310
+ # shell32 for ShellExecute; comctl32 for SetWindowSubclass, which is how a
311
+ # <TextInput>'s EDIT peer is subclassed without breaking anything else that
312
+ # subclasses it later.
313
+ # shell32 for Shell_NotifyIcon and SHGetKnownFolderPath, ole32 for the
314
+ # IShellLink that writes the Start Menu shortcut, propsys for the property
315
+ # store that puts the AppUserModelID on it.
316
+ target_link_libraries(basalt_win32_mounting PUBLIC shell32 comctl32 ole32 propsys)
317
+ # dwmapi for the title bar's colours and dark mode.
318
+ target_link_libraries(basalt_win32_mounting PUBLIC dwmapi)
319
+
320
+ # -------------------------------------------------------------------------
321
+ # basalt_win32 — a ReactHost, Hermes, and one surface in an HWND.
322
+ # -------------------------------------------------------------------------
323
+ add_executable(basalt_win32
324
+ win32/main_win32.cpp
325
+ # The event beat. Not an observer on Windows: there is no "about to wait"
326
+ # hook, so the message loop itself is here. See the header.
327
+ win32/Win32RunLoopObserver.cpp
328
+ win32/Win32AnimationChoreographer.cpp)
329
+ target_compile_options(basalt_win32 PRIVATE ${BASALT_WIN32_WARNINGS})
330
+ target_link_libraries(basalt_win32 PRIVATE basalt_win32_mounting)
331
+ if(BASALT_PACKAGE_WIN32_LINK_LIBRARIES)
332
+ target_link_libraries(basalt_win32 PRIVATE ${BASALT_PACKAGE_WIN32_LINK_LIBRARIES})
333
+ endif()
334
+
335
+ # Real mutations into real views, with no JavaScript anywhere. The checkpoint
336
+ # between "the mounting manager compiles" and "React Native runs": a mistake
337
+ # in the Create/Insert/Update/Remove/Delete handling shows up in a picture
338
+ # rather than in review.
339
+ add_executable(mount_harness_win32 win32/mount_harness_win32.cpp)
340
+ target_compile_options(mount_harness_win32 PRIVATE ${BASALT_WIN32_WARNINGS})
341
+ target_link_libraries(mount_harness_win32 PRIVATE basalt_win32_mounting)
342
+
343
+ list(APPEND BASALT_WIN32_TEST_SOURCES
344
+ ${BASALT_CORE_TESTS}
345
+ # Key events, and the mapping under test. Here rather than in the
346
+ # unconditional set above, which is where they were: core/KeyEvents.h
347
+ # speaks in facebook::react::Tag and includes ReactPrimitives.h for it, so
348
+ # anything touching it needs a React Native to have been found. The view
349
+ # layer deliberately has not found one -- that is what lets it build on a
350
+ # Windows box with nothing but a compiler -- and the release workflow's
351
+ # MSBuild job is exactly that build, so it failed there and nowhere else.
352
+ # This host is still the only one that can check the table, and the
353
+ # Windows CI shards, which do have React Native, still do.
354
+ tests/test_win32_key_events.cpp
355
+ # Selecting text with a pointer, here for the same reason and found the
356
+ # same way: it drives a Win32TouchDispatcher and asserts against
357
+ # core/TextSelection.h, both of which speak React Native, and it sat in
358
+ # the unconditional set above from the day it was written. The MSBuild job
359
+ # is the only build without a React Native, so it failed there and nowhere
360
+ # else -- the second time this file has learnt that, which is why the
361
+ # rule is now in the comment above rather than in a commit message.
362
+ tests/test_win32_selection.cpp
363
+ win32/Win32KeyEvents.cpp
364
+ # A package's own tests; see the AppKit package for why they sit with core's.
365
+ ${BASALT_PACKAGE_TESTS}
366
+ # Deliberately the same nine questions tests/test_mounting.cpp asks of GTK
367
+ # and tests/test_appkit_mounting.mm asks of AppKit, in the same order with
368
+ # the same tags. Most of what they test is whether the sharing still holds.
369
+ tests/test_win32_mounting.cpp
370
+ # The image loader: the cache, the failure paths, and the two lifetimes.
371
+ # In the RN-dependent set because the fetch is core/ImageBytes.cpp.
372
+ tests/test_win32_imageloader.cpp
373
+ # Animated GIFs: the frames WIC decodes and the pacing core shares. Here
374
+ # for the same reason as the loader's own tests -- the fixtures are `data:`
375
+ # URIs, read by core/ImageBytes.cpp -- even though most of the file is the
376
+ # view layer's.
377
+ tests/test_win32_animated_image.cpp
378
+ # The touch state machine and the gesture handover, asking what
379
+ # tests/test_appkit_input.mm asks of AppKit.
380
+ tests/test_win32_input.cpp
381
+ # <ScrollView>: the clamp, the throttle, the state write-back, the wheel's
382
+ # innermost-first routing and the commands.
383
+ tests/test_win32_focus.cpp
384
+ tests/test_win32_scrollview.cpp
385
+ # <TextInput>. The only tests here that make a window, because a text
386
+ # field's peer is one -- see the file.
387
+ tests/test_win32_textinput.cpp
388
+ # The clipboard, and what happens when another program has it open.
389
+ tests/test_win32_clipboard.cpp
390
+ # The caption actions with no window attached. Here rather than beside
391
+ # test_win32_titlebar.cpp because Win32TitleBar is in basalt_win32_mounting,
392
+ # which only exists when basalt_core does; its neighbour is pure geometry.
393
+ tests/test_win32_titlebar_actions.cpp)
394
+ endif()
395
+
396
+ # ---------------------------------------------------------------------------
397
+ # Still to come:
398
+ #
399
+ # mount_harness_win32 real ShadowViewMutations, no JavaScript, rendered
400
+ # to a PNG -- the checkpoint between "the mounting
401
+ # manager compiles" and "React Native runs".
402
+ # basalt_win32 a ReactHost, Hermes, and one surface in an HWND.
403
+ #
404
+ # And the components this platform does not claim yet: <ScrollView>, which
405
+ # needs onScroll and scroll state, and <TextInput>, which needs an EDIT peer.
406
+ # ---------------------------------------------------------------------------
407
+
408
+ # Without React Native there is no basalt_core to link, and the harness calls
409
+ # `basalt::installCrashHandler` whatever it is linked against -- so this build
410
+ # compiles that one file itself. The MSBuild job in release.yml is the only
411
+ # build that gets here, which is why the link error it answered with was
412
+ # invisible to every CI run.
413
+ if(NOT TARGET basalt_core)
414
+ list(APPEND BASALT_WIN32_TEST_SOURCES ${BASALT_CRASH_HANDLER})
415
+ endif()
416
+
417
+ add_executable(basalt_win32_tests ${BASALT_WIN32_TEST_SOURCES})
418
+ target_compile_options(basalt_win32_tests PRIVATE ${BASALT_WIN32_WARNINGS})
419
+ target_include_directories(basalt_win32_tests PRIVATE ${BASALT_TEST_INCLUDE})
420
+ # basalt_win32_mounting already carries basalt_win32_view; naming both makes the
421
+ # linker warn about a duplicate library rather than doing anything useful.
422
+ if(TARGET basalt_win32_mounting)
423
+ target_link_libraries(basalt_win32_tests PRIVATE basalt_win32_mounting)
424
+ if(BASALT_PACKAGE_WIN32_LINK_LIBRARIES)
425
+ target_link_libraries(basalt_win32_tests PRIVATE ${BASALT_PACKAGE_WIN32_LINK_LIBRARIES})
426
+ endif()
427
+ else()
428
+ target_link_libraries(basalt_win32_tests PRIVATE basalt_win32_view)
429
+ endif()