Skip to content

Commit 1f69de9

Browse files
authored
[Farbic] Extract RenderText into helper function + clean up Loading visuals (#12866)
* Extract RenderText into helper function * Change files
1 parent 8dfee7b commit 1f69de9

File tree

7 files changed

+331
-172
lines changed

7 files changed

+331
-172
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Extract RenderText into helper function",
4+
"packageName": "react-native-windows",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

vnext/Microsoft.ReactNative/Fabric/Composition/CompositionRootView.cpp

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "CompositionRootView.g.cpp"
66
#include "FocusNavigationRequest.g.cpp"
77

8+
#include <AutoDraw.h>
89
#include <DynamicWriter.h>
910
#include <Fabric/FabricUIManagerModule.h>
1011
#include <IReactInstance.h>
@@ -15,8 +16,10 @@
1516
#include <Utils/Helpers.h>
1617
#include <dispatchQueue/dispatchQueue.h>
1718
#include <eventWaitHandle/eventWaitHandle.h>
19+
#include <react/renderer/attributedstring/AttributedStringBox.h>
1820
#include <react/renderer/core/LayoutConstraints.h>
1921
#include <react/renderer/core/LayoutContext.h>
22+
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
2023
#include <winrt/Microsoft.ReactNative.Composition.h>
2124
#include <winrt/Microsoft.ReactNative.h>
2225
#include <winrt/Windows.UI.Core.h>
@@ -26,13 +29,20 @@
2629
#include "CompositionUIService.h"
2730
#include "ReactNativeHost.h"
2831
#include "RootComponentView.h"
32+
#include "TextDrawing.h"
2933

3034
#ifdef USE_WINUI3
3135
#include <winrt/Microsoft.UI.Content.h>
3236
#endif
3337

3438
namespace winrt::Microsoft::ReactNative::implementation {
3539

40+
constexpr float loadingActivitySize = 12.0f;
41+
constexpr float loadingActivityHorizontalOffset = 16.0f;
42+
constexpr float loadingBarHeight = 36.0f;
43+
constexpr float loadingBarFontSize = 20.0f;
44+
constexpr float loadingTextHorizontalOffset = 48.0f;
45+
3646
//! This class ensures that we access ReactRootView from UI thread.
3747
struct CompositionReactViewInstance
3848
: public winrt::implements<CompositionReactViewInstance, winrt::Microsoft::ReactNative::IReactViewInstance> {
@@ -149,6 +159,7 @@ void CompositionRootView::RootVisual(winrt::Microsoft::ReactNative::Composition:
149159
if (m_rootVisual != value) {
150160
assert(!m_rootVisual);
151161
m_rootVisual = value;
162+
UpdateRootVisualSize();
152163
}
153164
}
154165

@@ -172,14 +183,39 @@ winrt::Windows::Foundation::Size CompositionRootView::Size() noexcept {
172183

173184
void CompositionRootView::Size(winrt::Windows::Foundation::Size value) noexcept {
174185
m_size = value;
186+
UpdateRootVisualSize();
187+
}
188+
189+
void CompositionRootView::UpdateRootVisualSize() noexcept {
190+
if (m_rootVisual)
191+
m_rootVisual.Size({m_size.Width * m_scaleFactor, m_size.Height * m_scaleFactor});
192+
193+
UpdateLoadingVisualSize();
194+
}
195+
196+
void CompositionRootView::UpdateLoadingVisualSize() noexcept {
197+
if (m_loadingVisual) {
198+
auto drawingSurface = CreateLoadingVisualBrush();
199+
m_loadingVisual.Brush(drawingSurface);
200+
m_loadingVisual.Offset({0.0f, -(loadingBarHeight * m_scaleFactor / 2.0f), 0.0f}, {0.0f, 0.5f, 0.0f});
201+
m_loadingVisual.Size({m_size.Width * m_scaleFactor, loadingBarHeight * m_scaleFactor});
202+
m_loadingActivityVisual.Size(loadingActivitySize * m_scaleFactor);
203+
const float loadingActivityVerticalOffset = ((loadingBarHeight - (loadingActivitySize * 2)) * m_scaleFactor) / 2;
204+
205+
m_loadingActivityVisual.Offset(
206+
{loadingActivityHorizontalOffset * m_scaleFactor, loadingActivityVerticalOffset, 0.0f});
207+
}
175208
}
176209

177210
float CompositionRootView::ScaleFactor() noexcept {
178211
return m_scaleFactor;
179212
}
180213

181214
void CompositionRootView::ScaleFactor(float value) noexcept {
182-
m_scaleFactor = value;
215+
if (m_scaleFactor != value) {
216+
m_scaleFactor = value;
217+
UpdateRootVisualSize();
218+
}
183219
}
184220

185221
winrt::Microsoft::ReactNative::Composition::Theme CompositionRootView::Theme() noexcept {
@@ -397,6 +433,7 @@ void CompositionRootView::ClearLoadingUI() noexcept {
397433
RootVisual().Remove(m_loadingVisual);
398434

399435
m_loadingVisual = nullptr;
436+
m_loadingActivityVisual = nullptr;
400437
}
401438

402439
void CompositionRootView::EnsureLoadingUI() noexcept {}
@@ -425,6 +462,63 @@ void CompositionRootView::ShowInstanceError() noexcept {
425462
ClearLoadingUI();
426463
}
427464

465+
Composition::IDrawingSurfaceBrush CompositionRootView::CreateLoadingVisualBrush() noexcept {
466+
auto compContext =
467+
winrt::Microsoft::ReactNative::Composition::implementation::CompositionUIService::GetCompositionContext(
468+
m_context.Properties().Handle());
469+
470+
winrt::Windows::Foundation::Size surfaceSize = {
471+
m_size.Width * m_scaleFactor, std::min(m_size.Height, loadingBarHeight) * m_scaleFactor};
472+
auto drawingSurface = compContext.CreateDrawingSurfaceBrush(
473+
surfaceSize,
474+
winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized,
475+
winrt::Windows::Graphics::DirectX::DirectXAlphaMode::Premultiplied);
476+
477+
POINT offset;
478+
{
479+
::Microsoft::ReactNative::Composition::AutoDrawDrawingSurface autoDraw(drawingSurface, &offset);
480+
if (auto d2dDeviceContext = autoDraw.GetRenderTarget()) {
481+
d2dDeviceContext->Clear(D2D1::ColorF(D2D1::ColorF::Green));
482+
483+
facebook::react::LayoutConstraints constraints;
484+
constraints.maximumSize.width = std::max(0.0f, m_size.Width - loadingTextHorizontalOffset);
485+
constraints.maximumSize.height = std::max(0.0f, m_size.Height - loadingBarHeight);
486+
487+
auto attributedString = facebook::react::AttributedString{};
488+
auto fragment = facebook::react::AttributedString::Fragment{};
489+
fragment.string = "Loading";
490+
fragment.textAttributes.fontSize = loadingBarFontSize;
491+
attributedString.appendFragment(fragment);
492+
auto attributedStringBox = facebook::react::AttributedStringBox{attributedString};
493+
494+
auto textAttributes = facebook::react::TextAttributes{};
495+
textAttributes.foregroundColor = facebook::react::whiteColor();
496+
497+
winrt::com_ptr<::IDWriteTextLayout> textLayout;
498+
facebook::react::TextLayoutManager::GetTextLayout(
499+
attributedStringBox, {} /*paragraphAttributes*/, constraints, textLayout);
500+
501+
DWRITE_TEXT_METRICS tm;
502+
textLayout->GetMetrics(&tm);
503+
const float textVerticalOffsetWithinLoadingBar = ((loadingBarHeight - tm.height) * m_scaleFactor) / 2;
504+
505+
auto theme = winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::Theme>(Theme());
506+
507+
Composition::RenderText(
508+
*d2dDeviceContext,
509+
*textLayout,
510+
attributedStringBox.getValue(),
511+
textAttributes,
512+
{static_cast<float>(offset.x + (loadingTextHorizontalOffset * m_scaleFactor)),
513+
static_cast<float>(offset.y + textVerticalOffsetWithinLoadingBar)},
514+
m_scaleFactor,
515+
*theme);
516+
}
517+
}
518+
519+
return drawingSurface;
520+
}
521+
428522
void CompositionRootView::ShowInstanceLoading() noexcept {
429523
if (!Mso::React::ReactOptions::UseDeveloperSupport(m_context.Properties().Handle()))
430524
return;
@@ -436,19 +530,18 @@ void CompositionRootView::ShowInstanceLoading() noexcept {
436530
winrt::Microsoft::ReactNative::Composition::implementation::CompositionUIService::GetCompositionContext(
437531
m_context.Properties().Handle());
438532

439-
auto brush = compContext.CreateColorBrush({0x80, 0x03, 0x29, 0x29});
533+
auto drawingSurface = CreateLoadingVisualBrush();
534+
440535
m_loadingVisual = compContext.CreateSpriteVisual();
441-
m_loadingVisual.RelativeSizeWithOffset({0.0f, 50.0f}, {1.0f, 0.0f});
442-
m_loadingVisual.Offset({0.0f, -25.0f, 0.0f}, {0.0f, 0.5f, 0.0f});
443-
m_loadingVisual.Brush(brush);
536+
m_loadingVisual.Brush(drawingSurface);
444537

445538
auto foregroundBrush = compContext.CreateColorBrush({255, 255, 255, 255});
446539

447-
auto activity = compContext.CreateActivityVisual();
448-
activity.Size(15.0f);
449-
activity.Brush(foregroundBrush);
450-
activity.Offset({-50.0f, 5.0f, 0.0f}, {0.5f, 0.0f, 0.0f});
451-
m_loadingVisual.InsertAt(activity, 0);
540+
m_loadingActivityVisual = compContext.CreateActivityVisual();
541+
m_loadingActivityVisual.Brush(foregroundBrush);
542+
m_loadingVisual.InsertAt(m_loadingActivityVisual, 0);
543+
544+
UpdateLoadingVisualSize();
452545

453546
RootVisual().InsertAt(m_loadingVisual, m_hasRenderedVisual ? 1 : 0);
454547
}
@@ -523,7 +616,6 @@ winrt::Microsoft::UI::Content::ContentIsland CompositionRootView::Island() noexc
523616

524617
if (!m_island) {
525618
auto rootVisual = m_compositor.CreateSpriteVisual();
526-
rootVisual.RelativeSizeAdjustment({1, 1});
527619

528620
RootVisual(winrt::Microsoft::ReactNative::Composition::MicrosoftCompositionContextHelper::CreateVisual(rootVisual));
529621
m_island = winrt::Microsoft::UI::Content::ContentIsland::Create(rootVisual);

vnext/Microsoft.ReactNative/Fabric/Composition/CompositionRootView.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ struct CompositionRootView : CompositionRootViewT<CompositionRootView>, ::Micros
127127
std::shared_ptr<::Microsoft::ReactNative::CompositionEventHandler> m_CompositionEventHandler;
128128
winrt::Microsoft::ReactNative::Composition::IVisual m_rootVisual{nullptr};
129129
winrt::Microsoft::ReactNative::Composition::ISpriteVisual m_loadingVisual{nullptr};
130+
winrt::Microsoft::ReactNative::Composition::IActivityVisual m_loadingActivityVisual{nullptr};
130131
winrt::Microsoft::ReactNative::Composition::Theme m_theme{nullptr};
131132
winrt::Microsoft::ReactNative::ReactNotificationSubscription m_themeChangedSubscription{nullptr};
132133
winrt::Microsoft::ReactNative::Composition::Theme::ThemeChanged_revoker m_themeChangedRevoker;
@@ -137,6 +138,9 @@ struct CompositionRootView : CompositionRootViewT<CompositionRootView>, ::Micros
137138
void ShowInstanceLoaded() noexcept;
138139
void ShowInstanceError() noexcept;
139140
void ShowInstanceLoading() noexcept;
141+
void UpdateRootVisualSize() noexcept;
142+
void UpdateLoadingVisualSize() noexcept;
143+
Composition::IDrawingSurfaceBrush CreateLoadingVisualBrush() noexcept;
140144
};
141145

142146
} // namespace winrt::Microsoft::ReactNative::implementation

0 commit comments

Comments
 (0)