From ba64ab1d7c65134c06a306924c91d0ac1af61913 Mon Sep 17 00:00:00 2001 From: Andrew <30809111+acoates-ms@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:48:30 -0700 Subject: [PATCH 1/2] [Fabric] Handle scalefactor changes --- .../Composition/ParagraphComponentView.cpp | 10 ++++ .../Composition/ParagraphComponentView.h | 3 + .../Fabric/Composition/ReactNativeIsland.cpp | 59 +++++++++++++------ .../Fabric/Composition/ReactNativeIsland.h | 4 +- .../Fabric/WindowsImageManager.cpp | 5 ++ 5 files changed, 63 insertions(+), 18 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp index 8f171e637ee..dab5dae3aa5 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp @@ -83,6 +83,16 @@ void ParagraphComponentView::updateState( m_textLayout = nullptr; } +void ParagraphComponentView::updateLayoutMetrics( + facebook::react::LayoutMetrics const &layoutMetrics, + facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept { + Super::updateLayoutMetrics(layoutMetrics, oldLayoutMetrics); + + if (layoutMetrics.pointScaleFactor != oldLayoutMetrics.pointScaleFactor) { + m_textLayout = nullptr; + } +} + void ParagraphComponentView::FinalizeUpdates( winrt::Microsoft::ReactNative::ComponentViewUpdateMask updateMask) noexcept { ensureVisual(); diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h index 6277704a3fb..4e74704fa32 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h @@ -34,6 +34,9 @@ struct ParagraphComponentView : ParagraphComponentViewT CompositionReactViewInstance::PostInUIQueue(TAction &&a return promise.AsFuture(); } +void ApplyConstraints( + const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn, + facebook::react::LayoutConstraints &layoutConstraintsOut) noexcept { + layoutConstraintsOut.minimumSize = {layoutConstraintsIn.MinimumSize.Width, layoutConstraintsIn.MinimumSize.Height}; + layoutConstraintsOut.maximumSize = {layoutConstraintsIn.MaximumSize.Width, layoutConstraintsIn.MaximumSize.Height}; + layoutConstraintsOut.layoutDirection = + static_cast(layoutConstraintsIn.LayoutDirection); +} + ReactNativeIsland::ReactNativeIsland() noexcept {} #ifdef USE_WINUI3 @@ -136,6 +145,7 @@ ReactNativeIsland::~ReactNativeIsland() noexcept { #ifdef USE_WINUI3 if (m_island && m_island.IsConnected()) { m_island.AutomationProviderRequested(m_islandAutomationProviderRequestedToken); + m_island.StateChanged(m_islandStateChangedToken); } #endif @@ -251,6 +261,7 @@ void ReactNativeIsland::ScaleFactor(float value) noexcept { rootView.Scale({invScale, invScale, invScale}); } UpdateRootVisualSize(); + Arrange(m_layoutConstraints, m_viewportOffset); } } @@ -480,10 +491,14 @@ void ReactNativeIsland::ShowInstanceLoaded() noexcept { initProps = folly::dynamic::object(); } initProps["concurrentRoot"] = true; + + facebook::react::LayoutConstraints fbLayoutConstraints; + ApplyConstraints(m_layoutConstraints, fbLayoutConstraints); + uiManager->startSurface( *this, static_cast(m_rootTag), - m_layoutConstraints, + fbLayoutConstraints, to_string(m_reactViewOptions.ComponentName()), initProps); @@ -500,16 +515,21 @@ facebook::react::AttributedStringBox CreateLoadingAttributedString() noexcept { return facebook::react::AttributedStringBox{attributedString}; } -facebook::react::Size MeasureLoading(const facebook::react::LayoutConstraints &layoutConstraints, float scaleFactor) { +facebook::react::Size MeasureLoading( + const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints, + float scaleFactor) { + facebook::react::LayoutConstraints fbLayoutConstraints; + ApplyConstraints(layoutConstraints, fbLayoutConstraints); + auto attributedStringBox = CreateLoadingAttributedString(); winrt::com_ptr<::IDWriteTextLayout> textLayout; facebook::react::TextLayoutManager::GetTextLayout( - attributedStringBox, {} /*paragraphAttributes*/, layoutConstraints, textLayout); + attributedStringBox, {} /*paragraphAttributes*/, fbLayoutConstraints, textLayout); DWRITE_TEXT_METRICS tm; winrt::check_hresult(textLayout->GetMetrics(&tm)); - return layoutConstraints.clamp( + return fbLayoutConstraints.clamp( {loadingActivityHorizontalOffset * scaleFactor + tm.width, loadingBarHeight * scaleFactor}); } @@ -634,15 +654,6 @@ void ReactNativeIsland::ShowInstanceLoading() noexcept { InternalRootVisual().InsertAt(m_loadingVisual, m_hasRenderedVisual ? 1 : 0); } -void ApplyConstraints( - const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn, - facebook::react::LayoutConstraints &layoutConstraintsOut) noexcept { - layoutConstraintsOut.minimumSize = {layoutConstraintsIn.MinimumSize.Width, layoutConstraintsIn.MinimumSize.Height}; - layoutConstraintsOut.maximumSize = {layoutConstraintsIn.MaximumSize.Width, layoutConstraintsIn.MaximumSize.Height}; - layoutConstraintsOut.layoutDirection = - static_cast(layoutConstraintsIn.LayoutDirection); -} - winrt::Windows::Foundation::Size ReactNativeIsland::Measure( const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints, const winrt::Windows::Foundation::Point &viewportOffset) const noexcept { @@ -663,7 +674,7 @@ winrt::Windows::Foundation::Size ReactNativeIsland::Measure( size = fabricuiManager->measureSurface(static_cast(m_rootTag), constraints, context); } } else if (m_loadingVisual) { - size = MeasureLoading(constraints, m_scaleFactor); + size = MeasureLoading(layoutConstraints, m_scaleFactor); } auto clampedSize = constraints.clamp(size); @@ -673,7 +684,10 @@ winrt::Windows::Foundation::Size ReactNativeIsland::Measure( void ReactNativeIsland::Arrange( const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints, const winrt::Windows::Foundation::Point &viewportOffset) noexcept { - ApplyConstraints(layoutConstraints, m_layoutConstraints); + m_layoutConstraints = layoutConstraints; + m_viewportOffset = viewportOffset; + facebook::react::LayoutConstraints fbLayoutConstraints; + ApplyConstraints(layoutConstraints, fbLayoutConstraints); if (m_isInitialized && m_rootTag != -1) { if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties( @@ -684,11 +698,11 @@ void ReactNativeIsland::Arrange( context.viewportOffset = {viewportOffset.X, viewportOffset.Y}; fabricuiManager->constraintSurfaceLayout( - static_cast(m_rootTag), m_layoutConstraints, context); + static_cast(m_rootTag), fbLayoutConstraints, context); } } else if (m_loadingVisual) { // TODO: Resize to align loading - auto s = m_layoutConstraints.clamp(MeasureLoading(m_layoutConstraints, m_scaleFactor)); + auto s = fbLayoutConstraints.clamp(MeasureLoading(layoutConstraints, m_scaleFactor)); NotifySizeChanged(); } } @@ -738,6 +752,17 @@ winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() { pThis->m_island = nullptr; } }); + + m_islandStateChangedToken = + m_island.StateChanged([weakThis = get_weak()]( + winrt::Microsoft::UI::Content::ContentIsland const &island, + winrt::Microsoft::UI::Content::ContentIslandStateChangedEventArgs const &args) { + if (auto pThis = weakThis.get()) { + if (args.DidRasterizationScaleChange()) { + pThis->ScaleFactor(island.RasterizationScale()); + } + } + }); } return m_island; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h index cda46f75b43..e0605d5a107 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h @@ -125,6 +125,7 @@ struct ReactNativeIsland winrt::Microsoft::UI::Content::ContentIsland m_island{nullptr}; winrt::event_token m_islandFrameworkClosedToken; winrt::event_token m_islandAutomationProviderRequestedToken; + winrt::event_token m_islandStateChangedToken; #endif HWND m_hwnd{0}; @@ -147,7 +148,8 @@ struct ReactNativeIsland winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader m_resources{nullptr}; winrt::Microsoft::ReactNative::Composition::Theme m_theme{nullptr}; winrt::Microsoft::ReactNative::Composition::Theme::ThemeChanged_revoker m_themeChangedRevoker; - facebook::react::LayoutConstraints m_layoutConstraints; + winrt::Microsoft::ReactNative::LayoutConstraints m_layoutConstraints; + winrt::Windows::Foundation::Point m_viewportOffset{0, 0}; winrt::event> m_sizeChangedEvent; diff --git a/vnext/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp b/vnext/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp index 887d3a35bf2..9d9e26f7744 100644 --- a/vnext/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp @@ -95,6 +95,11 @@ WindowsImageManager::GetImageRandomAccessStreamAsync(ReactImageSource source) co } winrt::Windows::Storage::StorageFile file(co_await getFileSync); + + if (!file) { + co_return winrt::Microsoft::ReactNative::Composition::ImageFailedResponse(L"Failed to get file."); + } + co_return winrt::Microsoft::ReactNative::Composition::StreamImageResponse(co_await file.OpenReadAsync()); } From 5d2176f0dbb0c1fb9cc4515d21a7888836f9e02e Mon Sep 17 00:00:00 2001 From: Andrew <30809111+acoates-ms@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:48:40 -0700 Subject: [PATCH 2/2] Change files --- ...ative-windows-ee247e4c-9c8b-43b0-9e43-49050e45afc9.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-ee247e4c-9c8b-43b0-9e43-49050e45afc9.json diff --git a/change/react-native-windows-ee247e4c-9c8b-43b0-9e43-49050e45afc9.json b/change/react-native-windows-ee247e4c-9c8b-43b0-9e43-49050e45afc9.json new file mode 100644 index 00000000000..2a3bd8ef192 --- /dev/null +++ b/change/react-native-windows-ee247e4c-9c8b-43b0-9e43-49050e45afc9.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "[Fabric] Handle scalefactor changes", + "packageName": "react-native-windows", + "email": "30809111+acoates-ms@users.noreply.github.com", + "dependentChangeType": "patch" +}