react-native-windows 0.81.3 → 0.81.5

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 (71) hide show
  1. package/Libraries/Core/ReactNativeVersion.js +1 -1
  2. package/Libraries/NativeComponent/ViewConfigIgnore.windows.js +45 -0
  3. package/Libraries/Renderer/implementations/ReactFabric-dev.js +38 -35
  4. package/Libraries/Renderer/implementations/ReactFabric-prod.js +51 -22
  5. package/Libraries/Renderer/implementations/ReactFabric-profiling.js +54 -24
  6. package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +36 -33
  7. package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +5 -5
  8. package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +5 -5
  9. package/Libraries/Renderer/shims/ReactNativeTypes.js +23 -11
  10. package/Libraries/Renderer/shims/ReactNativeTypes.windows.js +23 -12
  11. package/Microsoft.ReactNative/ABIViewManager.cpp +12 -1
  12. package/Microsoft.ReactNative/ComponentView.idl +2 -0
  13. package/Microsoft.ReactNative/Composition.Input.idl +7 -0
  14. package/Microsoft.ReactNative/CompositionComponentView.idl +5 -0
  15. package/Microsoft.ReactNative/CompositionHwndHost.idl +1 -0
  16. package/Microsoft.ReactNative/CompositionSwitcher.idl +16 -9
  17. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +19 -1
  18. package/Microsoft.ReactNative/Fabric/ComponentView.h +10 -1
  19. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.cpp +12 -0
  20. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.h +15 -0
  21. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +15 -0
  22. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +75 -0
  23. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +1 -0
  24. package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.cpp +10 -45
  25. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +86 -19
  26. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +4 -0
  27. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +95 -22
  28. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +15 -0
  29. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +61 -74
  30. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +71 -12
  31. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +11 -0
  32. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +4 -3
  33. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +2 -1
  34. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeWindow.cpp +245 -0
  35. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeWindow.h +80 -0
  36. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +33 -1
  37. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +17 -0
  38. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +47 -23
  39. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +3 -0
  40. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +3 -1
  41. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +8 -4
  42. package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +41 -15
  43. package/Microsoft.ReactNative/Modules/LogBoxModule.cpp +20 -95
  44. package/Microsoft.ReactNative/Modules/LogBoxModule.h +1 -1
  45. package/Microsoft.ReactNative/ReactNativeAppBuilder.cpp +0 -41
  46. package/Microsoft.ReactNative/ReactNativeAppBuilder.idl +0 -11
  47. package/Microsoft.ReactNative/ReactNativeIsland.idl +2 -3
  48. package/Microsoft.ReactNative/ReactNativeWin32App.cpp +31 -101
  49. package/Microsoft.ReactNative/ReactNativeWin32App.h +2 -13
  50. package/Microsoft.ReactNative/ReactNativeWindow.idl +44 -0
  51. package/Mso/src/dispatchQueue/queueService.cpp +3 -1
  52. package/Mso/src/dispatchQueue/uiScheduler_winrt.cpp +2 -1
  53. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  54. package/Shared/Networking/OriginPolicyHttpFilter.cpp +2 -1
  55. package/Shared/Shared.vcxitems +7 -0
  56. package/Shared/Shared.vcxitems.filters +6 -0
  57. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +2 -1
  58. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +42 -25
  59. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +2 -1
  60. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +2 -1
  61. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +11 -6
  62. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +11 -6
  63. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +1 -0
  64. package/codegen/react/components/rnwcore/InputAccessory.g.h +2 -1
  65. package/codegen/react/components/rnwcore/ModalHostView.g.h +40 -23
  66. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +11 -6
  67. package/codegen/react/components/rnwcore/SafeAreaView.g.h +1 -0
  68. package/codegen/react/components/rnwcore/Switch.g.h +11 -6
  69. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +2 -1
  70. package/codegen/react/components/rnwcore/VirtualView.g.h +41 -8
  71. package/package.json +21 -21
@@ -30,20 +30,33 @@ using namespace xaml::Media::Imaging;
30
30
 
31
31
  namespace Microsoft::ReactNative {
32
32
 
33
+ static const char *ERROR_INVALID_URI = "E_INVALID_URI";
34
+ static const char *ERROR_GET_SIZE_FAILURE = "E_GET_SIZE_FAILURE";
35
+
33
36
  winrt::fire_and_forget GetImageSizeAsync(
34
37
  const winrt::Microsoft::ReactNative::IReactPropertyBag &properties,
35
38
  std::string uriString,
36
39
  winrt::Microsoft::ReactNative::JSValue &&headers,
37
40
  Mso::Functor<void(int32_t width, int32_t height)> successCallback,
38
- Mso::Functor<void()> errorCallback
41
+ Mso::Functor<void(const char *errorCode, std::string errorMessage)> errorCallback
39
42
  #ifdef USE_FABRIC
40
43
  ,
41
44
  bool useFabric
42
45
  #endif // USE_FABRIC
43
46
  ) {
44
47
  bool succeeded{false};
48
+ const char *errorCode = ERROR_GET_SIZE_FAILURE;
49
+ std::string errorMessage;
45
50
 
46
51
  try {
52
+ // Validate URI is not empty
53
+ if (uriString.empty()) {
54
+ errorCode = ERROR_INVALID_URI;
55
+ errorMessage = "Cannot get the size of an image for an empty URI";
56
+ errorCallback(errorCode, errorMessage);
57
+ co_return;
58
+ }
59
+
47
60
  ReactImageSource source;
48
61
  source.uri = uriString;
49
62
  if (!headers.IsNull()) {
@@ -56,9 +69,10 @@ winrt::fire_and_forget GetImageSizeAsync(
56
69
  winrt::hstring scheme{uri.SchemeName()};
57
70
  bool needsDownload = (scheme == L"http") || (scheme == L"https");
58
71
  bool inlineData = scheme == L"data";
72
+ bool isLocalFile = (scheme == L"file") || (scheme == L"ms-appx") || (scheme == L"ms-appdata");
59
73
 
60
74
  winrt::IRandomAccessStream memoryStream;
61
- if (needsDownload) {
75
+ if (needsDownload || isLocalFile) {
62
76
  memoryStream = co_await GetImageStreamAsync(properties, source);
63
77
  } else if (inlineData) {
64
78
  memoryStream = co_await GetImageInlineDataAsync(source);
@@ -77,23 +91,31 @@ winrt::fire_and_forget GetImageSizeAsync(
77
91
  }
78
92
  #ifdef USE_FABRIC
79
93
  } else {
80
- auto result = wicBitmapSourceFromStream(memoryStream);
81
- if (!std::get<std::shared_ptr<facebook::react::ImageErrorInfo>>(result)) {
82
- auto imagingFactory = std::get<winrt::com_ptr<IWICImagingFactory>>(result);
83
- auto wicBmpSource = std::get<winrt::com_ptr<IWICBitmapSource>>(result);
84
- UINT width, height;
85
- if (SUCCEEDED(wicBmpSource->GetSize(&width, &height))) {
86
- successCallback(width, height);
87
- succeeded = true;
94
+ if (memoryStream) { // Added nullcheck to prevent app from crashing if value is uninitialized
95
+ auto result = wicBitmapSourceFromStream(memoryStream);
96
+ if (!std::get<std::shared_ptr<facebook::react::ImageErrorInfo>>(result)) {
97
+ auto imagingFactory = std::get<winrt::com_ptr<IWICImagingFactory>>(result);
98
+ auto wicBmpSource = std::get<winrt::com_ptr<IWICBitmapSource>>(result);
99
+ UINT width, height;
100
+ if (SUCCEEDED(wicBmpSource->GetSize(&width, &height))) {
101
+ successCallback(width, height);
102
+ succeeded = true;
103
+ }
88
104
  }
89
105
  }
90
106
  }
91
107
  #endif // USE_FABRIC
92
- } catch (winrt::hresult_error const &) {
108
+ } catch (winrt::hresult_error const &e) {
109
+ errorMessage = "Failed to get image size: " + Microsoft::Common::Unicode::Utf16ToUtf8(std::wstring(e.message())) +
110
+ " for URI: " + uriString;
93
111
  }
94
112
 
95
- if (!succeeded)
96
- errorCallback();
113
+ if (!succeeded) {
114
+ if (errorMessage.empty()) {
115
+ errorMessage = "Failed to get image size for URI: " + uriString;
116
+ }
117
+ errorCallback(errorCode, errorMessage);
118
+ }
97
119
 
98
120
  co_return;
99
121
  }
@@ -112,7 +134,9 @@ void ImageLoader::getSize(std::string uri, React::ReactPromise<std::vector<doubl
112
134
  [result](double width, double height) noexcept {
113
135
  result.Resolve(std::vector<double>{width, height});
114
136
  },
115
- [result]() noexcept { result.Reject("Failed"); }
137
+ [result](const char *errorCode, std::string errorMessage) noexcept {
138
+ result.Reject(React::ReactError{errorCode, errorMessage});
139
+ }
116
140
  #ifdef USE_FABRIC
117
141
  ,
118
142
  IsFabricEnabled(context.Properties().Handle())
@@ -137,7 +161,9 @@ void ImageLoader::getSizeWithHeaders(
137
161
  [result](double width, double height) noexcept {
138
162
  result.Resolve(Microsoft::ReactNativeSpecs::ImageLoaderIOSSpec_getSizeWithHeaders_returnType{width, height});
139
163
  },
140
- [result]() noexcept { result.Reject("Failed"); }
164
+ [result](const char *errorCode, std::string errorMessage) noexcept {
165
+ result.Reject(React::ReactError{errorCode, errorMessage});
166
+ }
141
167
  #ifdef USE_FABRIC
142
168
  ,
143
169
  IsFabricEnabled(context.Properties().Handle())
@@ -12,6 +12,7 @@
12
12
  #ifdef USE_FABRIC
13
13
  #include <Fabric/Composition/CompositionContextHelper.h>
14
14
  #include <Fabric/Composition/CompositionUIService.h>
15
+ #include <winrt/Microsoft.UI.Windowing.h>
15
16
  #include <winrt/Windows.UI.Composition.h>
16
17
  #else
17
18
  #include <UI.Xaml.Controls.Primitives.h>
@@ -22,16 +23,14 @@ namespace Microsoft::ReactNative {
22
23
 
23
24
  LogBox::~LogBox() {
24
25
  #ifdef USE_FABRIC
25
- if (m_hwnd) {
26
- m_context.UIDispatcher().Post([hwnd = m_hwnd]() { DestroyWindow(hwnd); });
27
- m_hwnd = nullptr;
26
+ if (m_rnWindow) {
27
+ m_context.UIDispatcher().Post([rnWindow = m_rnWindow]() { rnWindow.Close(); });
28
+ m_rnWindow = nullptr;
28
29
  }
29
30
  #endif
30
31
  }
31
32
 
32
33
  #ifdef USE_FABRIC
33
- constexpr PCWSTR c_logBoxWindowClassName = L"MS_REACTNATIVE_LOGBOX";
34
- constexpr auto CompHostProperty = L"CompHost";
35
34
  const int LOGBOX_DEFAULT_WIDTH = 700;
36
35
  const int LOGBOX_DEFAULT_HEIGHT = 1000;
37
36
  #endif // USE_FABRIC
@@ -55,69 +54,6 @@ void LogBox::Hide() noexcept {
55
54
  });
56
55
  }
57
56
 
58
- #ifdef USE_FABRIC
59
- LRESULT CALLBACK LogBoxWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) noexcept {
60
- auto data = reinterpret_cast<::IUnknown *>(GetProp(hwnd, CompHostProperty));
61
- winrt::com_ptr<winrt::IUnknown> spunk;
62
- React::CompositionHwndHost host{nullptr};
63
-
64
- if (data) {
65
- winrt::check_hresult(data->QueryInterface(winrt::guid_of<React::CompositionHwndHost>(), winrt::put_abi(host)));
66
- auto result = static_cast<LRESULT>(host.TranslateMessage(message, wparam, lparam));
67
- if (result)
68
- return result;
69
- }
70
-
71
- switch (message) {
72
- case WM_NCCREATE: {
73
- auto cs = reinterpret_cast<CREATESTRUCT *>(lparam);
74
- auto windowData = static_cast<::IUnknown *>(cs->lpCreateParams);
75
- SetProp(hwnd, CompHostProperty, reinterpret_cast<::IUnknown *>(windowData));
76
- break;
77
- }
78
- case WM_CREATE: {
79
- host.Initialize((uint64_t)hwnd);
80
- break;
81
- }
82
- case WM_CLOSE: {
83
- // Just hide the window instead of destroying it
84
- ::ShowWindow(hwnd, SW_HIDE);
85
- return 0;
86
- }
87
- case WM_DESTROY: {
88
- data->Release();
89
- SetProp(hwnd, CompHostProperty, nullptr);
90
- }
91
- }
92
-
93
- return DefWindowProc(hwnd, message, wparam, lparam);
94
- }
95
-
96
- void LogBox::RegisterWndClass() noexcept {
97
- static bool registered = false;
98
- if (registered)
99
- return;
100
-
101
- HINSTANCE hInstance = GetModuleHandle(NULL);
102
-
103
- WNDCLASSEXW wcex = {};
104
- wcex.cbSize = sizeof(WNDCLASSEX);
105
- wcex.style = CS_HREDRAW | CS_VREDRAW;
106
- wcex.lpfnWndProc = &LogBoxWndProc;
107
- wcex.cbClsExtra = DLGWINDOWEXTRA;
108
- wcex.cbWndExtra = sizeof(winrt::impl::abi<winrt::Microsoft::ReactNative::ICompositionHwndHost>::type *);
109
- wcex.hInstance = hInstance;
110
- wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
111
- wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
112
- wcex.lpszClassName = c_logBoxWindowClassName;
113
- ATOM classId = RegisterClassEx(&wcex);
114
- WINRT_VERIFY(classId);
115
- winrt::check_win32(!classId);
116
-
117
- registered = true;
118
- }
119
- #endif // USE_FABRIC
120
-
121
57
  void LogBox::ShowOnUIThread() noexcept {
122
58
  auto host = React::implementation::ReactNativeHost::GetReactNativeHost(m_context.Properties());
123
59
  if (!host)
@@ -173,45 +109,34 @@ void LogBox::ShowOnUIThread() noexcept {
173
109
  }
174
110
  #else
175
111
  else {
176
- RegisterWndClass();
177
-
178
- if (!m_hwnd) {
112
+ if (!m_rnWindow) {
113
+ m_rnWindow = winrt::Microsoft::ReactNative::ReactNativeWindow::CreateFromCompositor(
114
+ winrt::Microsoft::ReactNative::Composition::CompositionUIService::GetCompositor(
115
+ host.InstanceSettings().Properties()));
179
116
  auto CompositionHwndHost = React::CompositionHwndHost();
180
117
  winrt::Microsoft::ReactNative::ReactViewOptions viewOptions;
181
118
  viewOptions.ComponentName(L"LogBox");
182
- CompositionHwndHost.ReactViewHost(
119
+ m_rnWindow.AppWindow().Title(L"LogBox");
120
+ m_rnWindow.AppWindow().Closing([](winrt::Microsoft::UI::Windowing::AppWindow const & /*appWindow*/,
121
+ winrt::Microsoft::UI::Windowing::AppWindowClosingEventArgs const &args) {
122
+ // Prevent default close behavior - as JS will never try to show the logbox again if it isn't hidden through JS
123
+ args.Cancel(true);
124
+ });
125
+ m_rnWindow.ReactNativeIsland().ReactViewHost(
183
126
  winrt::Microsoft::ReactNative::ReactCoreInjection::MakeViewHost(host, viewOptions));
184
- HINSTANCE hInstance = GetModuleHandle(NULL);
185
- winrt::impl::abi<winrt::Microsoft::ReactNative::ICompositionHwndHost>::type *pHost{nullptr};
186
- winrt::com_ptr<::IUnknown> spunk;
187
- CompositionHwndHost.as(spunk);
188
- spunk->AddRef(); // Will be stored in windowData
189
-
190
- m_hwnd = CreateWindow(
191
- c_logBoxWindowClassName,
192
- L"React-Native LogBox",
193
- WS_OVERLAPPEDWINDOW,
194
- CW_USEDEFAULT,
195
- CW_USEDEFAULT,
196
- LOGBOX_DEFAULT_WIDTH,
197
- LOGBOX_DEFAULT_HEIGHT,
198
- nullptr,
199
- nullptr,
200
- hInstance,
201
- spunk.get());
127
+ m_rnWindow.AppWindow().ResizeClient({LOGBOX_DEFAULT_WIDTH, LOGBOX_DEFAULT_HEIGHT});
202
128
  }
203
129
 
204
- ShowWindow(m_hwnd, SW_NORMAL);
205
- BringWindowToTop(m_hwnd);
206
- SetFocus(m_hwnd);
130
+ m_rnWindow.AppWindow().Show(true);
131
+ m_rnWindow.AppWindow().MoveInZOrderAtTop();
207
132
  }
208
133
  #endif // USE_FABRIC
209
134
  }
210
135
 
211
136
  void LogBox::HideOnUIThread() noexcept {
212
137
  #ifdef USE_FABRIC
213
- if (m_hwnd) {
214
- ::ShowWindow(m_hwnd, SW_HIDE);
138
+ if (m_rnWindow) {
139
+ m_rnWindow.AppWindow().Hide();
215
140
  }
216
141
  #else // USE_FABRIC
217
142
  if (m_popup) {
@@ -31,7 +31,7 @@ struct LogBox : public std::enable_shared_from_this<LogBox> {
31
31
 
32
32
  winrt::Microsoft::ReactNative::ReactContext m_context;
33
33
  #ifdef USE_FABRIC
34
- HWND m_hwnd{nullptr};
34
+ winrt::Microsoft::ReactNative::ReactNativeWindow m_rnWindow{nullptr};
35
35
  #else
36
36
  xaml::Controls::Primitives::Popup m_popup{nullptr};
37
37
  winrt::Microsoft::ReactNative::ReactRootView m_logBoxContent{nullptr};
@@ -20,19 +20,6 @@ ReactNativeAppBuilder::ReactNativeAppBuilder() {
20
20
 
21
21
  ReactNativeAppBuilder::~ReactNativeAppBuilder() {}
22
22
 
23
- winrt::Microsoft::ReactNative::ReactNativeAppBuilder ReactNativeAppBuilder::SetDispatcherQueueController(
24
- winrt::Microsoft::UI::Dispatching::DispatcherQueueController const &dispatcherQueueController) {
25
- m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->DispatcherQueueController(
26
- dispatcherQueueController);
27
- return *this;
28
- }
29
-
30
- winrt::Microsoft::ReactNative::ReactNativeAppBuilder ReactNativeAppBuilder::SetCompositor(
31
- winrt::Microsoft::UI::Composition::Compositor const &compositor) {
32
- m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->Compositor(compositor);
33
- return *this;
34
- }
35
-
36
23
  winrt::Microsoft::ReactNative::ReactNativeAppBuilder ReactNativeAppBuilder::SetAppWindow(
37
24
  winrt::Microsoft::UI::Windowing::AppWindow const &appWindow) {
38
25
  m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->AppWindow(appWindow);
@@ -41,34 +28,6 @@ winrt::Microsoft::ReactNative::ReactNativeAppBuilder ReactNativeAppBuilder::SetA
41
28
  }
42
29
 
43
30
  winrt::Microsoft::ReactNative::ReactNativeWin32App ReactNativeAppBuilder::Build() {
44
- // Create the DispatcherQueueController if the app developer doesn't provide one
45
- if (m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->DispatcherQueueController() == nullptr) {
46
- assert(m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->Compositor() == nullptr);
47
-
48
- // Create a DispatcherQueue for this thread. This is needed for Composition, Content, and Input APIs.
49
- auto dispatcherQueueController =
50
- winrt::Microsoft::UI::Dispatching::DispatcherQueueController::CreateOnCurrentThread();
51
-
52
- m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->DispatcherQueueController(
53
- dispatcherQueueController);
54
- }
55
-
56
- // Create the Compositor if the app developer doesn't provide one
57
- if (m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->Compositor() == nullptr) {
58
- // Create the compositor on behalf of the App Developer.
59
- auto compositor = winrt::Microsoft::UI::Composition::Compositor();
60
- m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->Compositor(compositor);
61
- }
62
-
63
- // Create the AppWindow if the app developer doesn't provide one
64
- if (m_reactNativeWin32App.AppWindow() == nullptr) {
65
- auto appWindow = winrt::Microsoft::UI::Windowing::AppWindow::Create();
66
- appWindow.Title(L"ReactNativeWin32App");
67
- appWindow.Resize({1000, 1000});
68
-
69
- m_reactNativeWin32App.as<implementation::ReactNativeWin32App>().get()->AppWindow(appWindow);
70
- }
71
-
72
31
  return m_reactNativeWin32App;
73
32
  }
74
33
 
@@ -18,12 +18,6 @@ namespace Microsoft.ReactNative {
18
18
 
19
19
  ReactViewOptions ReactViewOptions {get;};
20
20
 
21
- // TODO: Hide these APIs for now until we're sure we need to expose them and can do so safely
22
- // Microsoft.UI.Composition.Compositor Compositor {get;};
23
- // Microsoft.UI.Content.DesktopChildSiteBridge DesktopChildSiteBridge {get;};
24
- // Microsoft.UI.Dispatching DispatcherQueueController {get;};
25
- // ReactNativeIsland ReactNativeIsland {get;};
26
-
27
21
  // Methods
28
22
  void Start();
29
23
  }
@@ -38,11 +32,6 @@ namespace Microsoft.ReactNative {
38
32
 
39
33
  ReactNativeAppBuilder SetAppWindow(Microsoft.UI.Windowing.AppWindow appWindow);
40
34
 
41
- // TODO: Hide these APIs for now until we're sure we need to expose them and can do so safely
42
- // Compositor depends on the DispatcherQueue created by DispatcherQueueController
43
- // ReactNativeAppBuilder SetCompositor(Microsoft.UI.Composition.Compositor compositor);
44
- // ReactNativeAppBuilder SetDispatcherQueueController(Microsoft.UI.Dispatching DispatcherQueueController);
45
-
46
35
  ReactNativeWin32App Build();
47
36
  }
48
37
  }
@@ -80,9 +80,6 @@ namespace Microsoft.ReactNative
80
80
  DOC_STRING("A windows composition component that hosts React Native UI elements.")
81
81
  runtimeclass ReactNativeIsland
82
82
  {
83
- DOC_STRING("Creates a new instance of @ReactNativeIsland. Can be implemented with a ReactViewHost or a ComponentView with reactContext")
84
- ReactNativeIsland();
85
-
86
83
  #ifdef USE_WINUI3
87
84
  ReactNativeIsland(Microsoft.UI.Composition.Compositor compositor);
88
85
 
@@ -100,6 +97,8 @@ namespace Microsoft.ReactNative
100
97
 
101
98
  Windows.Foundation.Size Size { get; };
102
99
 
100
+ Microsoft.UI.Composition.Compositor Compositor { get; };
101
+
103
102
  DOC_STRING("ScaleFactor for this windows (DPI/96)")
104
103
  Single ScaleFactor {get; set;};
105
104
 
@@ -15,34 +15,10 @@
15
15
  #include "winrt/Microsoft.UI.Interop.h"
16
16
  #include "winrt/Microsoft.UI.Windowing.h"
17
17
 
18
- // Scaling factor for the window's content based on the DPI of the display where the window is located.
19
- float ScaleFactor(HWND hwnd) noexcept {
20
- return GetDpiForWindow(hwnd) / static_cast<float>(USER_DEFAULT_SCREEN_DPI);
21
- }
22
-
23
- void UpdateRootViewSizeToAppWindow(
24
- winrt::Microsoft::ReactNative::ReactNativeIsland const &rootView,
25
- winrt::Microsoft::UI::Windowing::AppWindow const &window) {
26
- auto hwnd = winrt::Microsoft::UI::GetWindowFromWindowId(window.Id());
27
- auto scaleFactor = ScaleFactor(hwnd);
28
- winrt::Windows::Foundation::Size size{
29
- window.ClientSize().Width / scaleFactor, window.ClientSize().Height / scaleFactor};
30
- // Do not relayout when minimized
31
- if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
32
- winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
33
- winrt::Microsoft::ReactNative::LayoutConstraints constraints;
34
- constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
35
- constraints.MaximumSize = constraints.MinimumSize = size;
36
- rootView.Arrange(constraints, {0, 0});
37
- }
38
- }
39
-
40
18
  namespace winrt::Microsoft::ReactNative::implementation {
41
19
  ReactNativeWin32App::ReactNativeWin32App() {}
42
20
 
43
21
  ReactNativeWin32App::~ReactNativeWin32App() {
44
- m_desktopChildSiteBridge = nullptr;
45
-
46
22
  // Destroy all Composition objects
47
23
  if (m_compositor != nullptr) {
48
24
  m_compositor.Close();
@@ -51,7 +27,7 @@ ReactNativeWin32App::~ReactNativeWin32App() {
51
27
  }
52
28
 
53
29
  winrt::Microsoft::UI::Windowing::AppWindow ReactNativeWin32App::AppWindow() {
54
- return m_appWindow;
30
+ return ReactNativeWindow().AppWindow();
55
31
  }
56
32
 
57
33
  void ReactNativeWin32App::AppWindow(winrt::Microsoft::UI::Windowing::AppWindow const &appWindow) {
@@ -59,29 +35,19 @@ void ReactNativeWin32App::AppWindow(winrt::Microsoft::UI::Windowing::AppWindow c
59
35
  }
60
36
 
61
37
  winrt::Microsoft::UI::Composition::Compositor ReactNativeWin32App::Compositor() {
62
- return m_compositor;
63
- }
64
-
65
- void ReactNativeWin32App::Compositor(winrt::Microsoft::UI::Composition::Compositor const &compositor) {
66
- m_compositor = compositor;
67
- }
68
-
69
- void ReactNativeWin32App::DesktopChildSiteBridge(
70
- winrt::Microsoft::UI::Content::DesktopChildSiteBridge const &desktopChildSiteBridge) {
71
- m_desktopChildSiteBridge = desktopChildSiteBridge;
72
- }
73
-
74
- winrt::Microsoft::UI::Content::DesktopChildSiteBridge ReactNativeWin32App::DesktopChildSiteBridge() {
75
- return m_desktopChildSiteBridge;
76
- }
38
+ if (m_compositor == nullptr) {
39
+ // Create a DispatcherQueue for this thread. This is needed for Composition, Content, and Input APIs.
40
+ m_dispatcherQueueController = winrt::Microsoft::UI::Dispatching::DispatcherQueueController::CreateOnCurrentThread();
77
41
 
78
- winrt::Microsoft::UI::Dispatching::DispatcherQueueController ReactNativeWin32App::DispatcherQueueController() {
79
- return m_dispatcherQueueController;
80
- }
42
+ // Currently set the property to use current thread dispatcher as a default UI dispatcher.
43
+ ReactNativeHost().InstanceSettings().Properties().Set(
44
+ ReactDispatcherHelper::UIDispatcherProperty(), ReactDispatcherHelper::UIThreadDispatcher());
81
45
 
82
- void ReactNativeWin32App::DispatcherQueueController(
83
- winrt::Microsoft::UI::Dispatching::DispatcherQueueController const &dispatcherQueueController) {
84
- m_dispatcherQueueController = dispatcherQueueController;
46
+ m_compositor = winrt::Microsoft::UI::Composition::Compositor();
47
+ winrt::Microsoft::ReactNative::Composition::CompositionUIService::SetCompositor(
48
+ ReactNativeHost().InstanceSettings(), m_compositor);
49
+ }
50
+ return m_compositor;
85
51
  }
86
52
 
87
53
  winrt::Microsoft::ReactNative::ReactNativeHost ReactNativeWin32App::ReactNativeHost() {
@@ -91,18 +57,6 @@ winrt::Microsoft::ReactNative::ReactNativeHost ReactNativeWin32App::ReactNativeH
91
57
  return m_host;
92
58
  }
93
59
 
94
- void ReactNativeWin32App::ReactNativeHost(winrt::Microsoft::ReactNative::ReactNativeHost const &host) {
95
- m_host = host;
96
- }
97
-
98
- winrt::Microsoft::ReactNative::ReactNativeIsland ReactNativeWin32App::ReactNativeIsland() {
99
- return m_reactNativeIsland;
100
- }
101
-
102
- void ReactNativeWin32App::ReactNativeIsland(winrt::Microsoft::ReactNative::ReactNativeIsland const &reactNativeIsland) {
103
- m_reactNativeIsland = reactNativeIsland;
104
- }
105
-
106
60
  winrt::Microsoft::ReactNative::ReactViewOptions ReactNativeWin32App::ReactViewOptions() {
107
61
  if (m_reactViewOptions == nullptr) {
108
62
  m_reactViewOptions = winrt::make<winrt::Microsoft::ReactNative::implementation::ReactViewOptions>();
@@ -114,45 +68,36 @@ void ReactNativeWin32App::ReactViewOptions(winrt::Microsoft::ReactNative::ReactV
114
68
  m_reactViewOptions = viewOptions;
115
69
  }
116
70
 
71
+ winrt::Microsoft::ReactNative::ReactNativeWindow ReactNativeWin32App::ReactNativeWindow() noexcept {
72
+ if (!m_rnWindow) {
73
+ if (m_appWindow) {
74
+ m_rnWindow = winrt::Microsoft::ReactNative::ReactNativeWindow::CreateFromWindow(m_appWindow, Compositor());
75
+ } else {
76
+ m_rnWindow = winrt::Microsoft::ReactNative::ReactNativeWindow::CreateFromCompositor(Compositor());
77
+ m_appWindow = m_rnWindow.AppWindow();
78
+ m_appWindow.Title(L"ReactNativeWin32App");
79
+ m_appWindow.Resize({1000, 1000});
80
+ }
81
+ }
82
+
83
+ return m_rnWindow;
84
+ }
85
+
117
86
  void ReactNativeWin32App::Start() {
118
87
  // Show the hosting AppWindow
119
- m_appWindow.Show();
120
-
121
- // Currently set the property to use current thread dispatcher as a default UI dispatcher.
122
- // TODO: Use the correct dispatcher from a developer-provided DispatcherQueueController
123
- ReactNativeHost().InstanceSettings().Properties().Set(
124
- ReactDispatcherHelper::UIDispatcherProperty(), ReactDispatcherHelper::UIThreadDispatcher());
88
+ AppWindow().Show();
125
89
 
126
90
  auto hwnd{winrt::Microsoft::UI::GetWindowFromWindowId(m_appWindow.Id())};
127
91
 
128
92
  winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
129
93
  ReactNativeHost().InstanceSettings().Properties(), reinterpret_cast<uint64_t>(hwnd));
130
94
 
131
- winrt::Microsoft::ReactNative::Composition::CompositionUIService::SetCompositor(
132
- ReactNativeHost().InstanceSettings(), m_compositor);
133
-
134
95
  // Start the react-native instance, which will create a JavaScript runtime and load the applications bundle.
135
96
  ReactNativeHost().ReloadInstance();
136
97
 
137
- // Create a RootView which will present a react-native component
138
- if (m_reactNativeIsland == nullptr) {
139
- m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland(m_compositor);
140
- }
141
-
142
- m_reactNativeIsland.ReactViewHost(
98
+ m_rnWindow.ReactNativeIsland().ReactViewHost(
143
99
  winrt::Microsoft::ReactNative::ReactCoreInjection::MakeViewHost(ReactNativeHost(), ReactViewOptions()));
144
100
 
145
- // Update the size of the RootView when the AppWindow changes size
146
- m_appWindow.Changed([wkRootView = winrt::make_weak(m_reactNativeIsland)](
147
- winrt::Microsoft::UI::Windowing::AppWindow const &window,
148
- winrt::Microsoft::UI::Windowing::AppWindowChangedEventArgs const &args) {
149
- if (args.DidSizeChange() || args.DidVisibilityChange()) {
150
- if (auto rootView = wkRootView.get()) {
151
- UpdateRootViewSizeToAppWindow(rootView, window);
152
- }
153
- }
154
- });
155
-
156
101
  // Quit application when main window is closed
157
102
  m_appWindow.Destroying([this](
158
103
  winrt::Microsoft::UI::Windowing::AppWindow const &window,
@@ -166,28 +111,13 @@ void ReactNativeWin32App::Start() {
166
111
  });
167
112
  });
168
113
 
169
- // DesktopChildSiteBridge create a ContentSite that can host the RootView ContentIsland
170
- m_desktopChildSiteBridge =
171
- winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(m_compositor, m_appWindow.Id());
172
-
173
- m_desktopChildSiteBridge.Connect(m_reactNativeIsland.Island());
174
-
175
- m_desktopChildSiteBridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow);
176
-
177
- auto scaleFactor = ScaleFactor(hwnd);
178
- m_reactNativeIsland.ScaleFactor(scaleFactor);
179
-
180
- UpdateRootViewSizeToAppWindow(m_reactNativeIsland, m_appWindow);
181
-
182
- m_desktopChildSiteBridge.Show();
183
-
184
114
  // Run the main application event loop
185
115
  m_dispatcherQueueController.DispatcherQueue().RunEventLoop();
186
116
 
117
+ m_appWindow.Destroy();
118
+
187
119
  // Rundown the DispatcherQueue. This drains the queue and raises events to let components
188
120
  // know the message loop has finished.
189
121
  m_dispatcherQueueController.ShutdownQueue();
190
-
191
- m_desktopChildSiteBridge.Close();
192
122
  }
193
123
  } // namespace winrt::Microsoft::ReactNative::implementation
@@ -15,20 +15,10 @@ struct ReactNativeWin32App : ReactNativeWin32AppT<ReactNativeWin32App> {
15
15
  winrt::Microsoft::UI::Windowing::AppWindow AppWindow();
16
16
 
17
17
  winrt::Microsoft::UI::Composition::Compositor Compositor();
18
- void Compositor(winrt::Microsoft::UI::Composition::Compositor const &compositor);
19
-
20
- winrt::Microsoft::UI::Content::DesktopChildSiteBridge DesktopChildSiteBridge();
21
- void DesktopChildSiteBridge(winrt::Microsoft::UI::Content::DesktopChildSiteBridge const &desktopChildSiteBridge);
22
-
23
- winrt::Microsoft::UI::Dispatching::DispatcherQueueController DispatcherQueueController();
24
- void DispatcherQueueController(
25
- winrt::Microsoft::UI::Dispatching::DispatcherQueueController const &dispatcherQueueController);
26
18
 
27
19
  winrt::Microsoft::ReactNative::ReactNativeHost ReactNativeHost();
28
- void ReactNativeHost(winrt::Microsoft::ReactNative::ReactNativeHost const &host);
29
20
 
30
- winrt::Microsoft::ReactNative::ReactNativeIsland ReactNativeIsland();
31
- void ReactNativeIsland(winrt::Microsoft::ReactNative::ReactNativeIsland const &reactNativeIsland);
21
+ winrt::Microsoft::ReactNative::ReactNativeWindow ReactNativeWindow() noexcept;
32
22
 
33
23
  winrt::Microsoft::ReactNative::ReactViewOptions ReactViewOptions();
34
24
  void ReactViewOptions(winrt::Microsoft::ReactNative::ReactViewOptions const &reactViewOptions);
@@ -36,12 +26,11 @@ struct ReactNativeWin32App : ReactNativeWin32AppT<ReactNativeWin32App> {
36
26
  void Start();
37
27
 
38
28
  private:
29
+ winrt::Microsoft::ReactNative::ReactNativeWindow m_rnWindow{nullptr};
39
30
  winrt::Microsoft::UI::Windowing::AppWindow m_appWindow{nullptr};
40
31
  winrt::Microsoft::UI::Composition::Compositor m_compositor{nullptr};
41
- winrt::Microsoft::UI::Content::DesktopChildSiteBridge m_desktopChildSiteBridge{nullptr};
42
32
  winrt::Microsoft::UI::Dispatching::DispatcherQueueController m_dispatcherQueueController{nullptr};
43
33
  winrt::Microsoft::ReactNative::ReactNativeHost m_host{nullptr};
44
- winrt::Microsoft::ReactNative::ReactNativeIsland m_reactNativeIsland{nullptr};
45
34
  winrt::Microsoft::ReactNative::ReactViewOptions m_reactViewOptions{nullptr};
46
35
  };
47
36
  } // namespace winrt::Microsoft::ReactNative::implementation
@@ -0,0 +1,44 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ import "ReactNativeIsland.idl";
5
+
6
+ #include "NamespaceRedirect.h"
7
+ #include "DocString.h"
8
+
9
+ namespace Microsoft.ReactNative
10
+ {
11
+
12
+ [experimental]
13
+ enum ContentSizePolicy
14
+ {
15
+ None,
16
+ ResizeContentToParentWindow,
17
+ ResizeParentWindowToContent,
18
+ };
19
+
20
+ [default_interface]
21
+ [webhosthidden]
22
+ [experimental]
23
+ DOC_STRING("Simplifies hosting a ReactNativeIsland inside a Window.")
24
+ runtimeclass ReactNativeWindow : Windows.Foundation.IClosable
25
+ {
26
+ static ReactNativeWindow CreateFromCompositor(Microsoft.UI.Composition.Compositor compositor);
27
+ static ReactNativeWindow CreateFromWindow(Microsoft.UI.Windowing.AppWindow appWindow, Microsoft.UI.Composition.Compositor compositor);
28
+ static ReactNativeWindow CreateFromContentSiteBridgeAndIsland(Microsoft.UI.Content.IContentSiteBridge bridge, Microsoft.ReactNative.ReactNativeIsland island);
29
+ static ReactNativeWindow CreateFromWindowAndIsland(Microsoft.UI.Windowing.AppWindow appWindow, Microsoft.ReactNative.ReactNativeIsland island);
30
+
31
+ ReactNativeIsland ReactNativeIsland { get; };
32
+
33
+ Microsoft.UI.Windowing.AppWindow AppWindow { get; };
34
+
35
+ Microsoft.UI.Content.IContentSiteBridge ContentSiteBridge { get; };
36
+ ContentSizePolicy ResizePolicy { get; set; };
37
+
38
+ DOC_STRING("When the ResizePolicy is set to ResizeParentWindowToContent, these LayoutConstraints will control the layout of the content."
39
+ " When ResizePolicy is set to ResizeContentToParentWindow, these constraints will be ignored. Instead the window can be constrained using"
40
+ " OverlappedPresenter.PreferredMaximumHeight etc.")
41
+ LayoutConstraints LayoutConstraints { get; set; };
42
+ }
43
+
44
+ } // namespace Microsoft.ReactNative
@@ -205,8 +205,10 @@ void QueueService::InvokeTask(
205
205
  DispatchTask taskToInvoke{std::move(task)};
206
206
  taskToInvoke.Get()->Invoke(); // Call Get()->Invoke instead of operator() to flatten call stack
207
207
 
208
- while (taskToInvoke = context.TakeNextDeferredTask()) {
208
+ taskToInvoke = context.TakeNextDeferredTask();
209
+ while (taskToInvoke) {
209
210
  taskToInvoke.Get()->Invoke();
211
+ taskToInvoke = context.TakeNextDeferredTask();
210
212
  }
211
213
  }
212
214