5
5
#include " CompositionRootView.g.cpp"
6
6
#include " FocusNavigationRequest.g.cpp"
7
7
8
+ #include < AutoDraw.h>
8
9
#include < DynamicWriter.h>
9
10
#include < Fabric/FabricUIManagerModule.h>
10
11
#include < IReactInstance.h>
15
16
#include < Utils/Helpers.h>
16
17
#include < dispatchQueue/dispatchQueue.h>
17
18
#include < eventWaitHandle/eventWaitHandle.h>
19
+ #include < react/renderer/attributedstring/AttributedStringBox.h>
18
20
#include < react/renderer/core/LayoutConstraints.h>
19
21
#include < react/renderer/core/LayoutContext.h>
22
+ #include < react/renderer/textlayoutmanager/TextLayoutManager.h>
20
23
#include < winrt/Microsoft.ReactNative.Composition.h>
21
24
#include < winrt/Microsoft.ReactNative.h>
22
25
#include < winrt/Windows.UI.Core.h>
26
29
#include " CompositionUIService.h"
27
30
#include " ReactNativeHost.h"
28
31
#include " RootComponentView.h"
32
+ #include " TextDrawing.h"
29
33
30
34
#ifdef USE_WINUI3
31
35
#include < winrt/Microsoft.UI.Content.h>
32
36
#endif
33
37
34
38
namespace winrt ::Microsoft::ReactNative::implementation {
35
39
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
+
36
46
// ! This class ensures that we access ReactRootView from UI thread.
37
47
struct CompositionReactViewInstance
38
48
: public winrt::implements<CompositionReactViewInstance, winrt::Microsoft::ReactNative::IReactViewInstance> {
@@ -149,6 +159,7 @@ void CompositionRootView::RootVisual(winrt::Microsoft::ReactNative::Composition:
149
159
if (m_rootVisual != value) {
150
160
assert (!m_rootVisual);
151
161
m_rootVisual = value;
162
+ UpdateRootVisualSize ();
152
163
}
153
164
}
154
165
@@ -172,14 +183,39 @@ winrt::Windows::Foundation::Size CompositionRootView::Size() noexcept {
172
183
173
184
void CompositionRootView::Size (winrt::Windows::Foundation::Size value) noexcept {
174
185
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
+ }
175
208
}
176
209
177
210
float CompositionRootView::ScaleFactor () noexcept {
178
211
return m_scaleFactor;
179
212
}
180
213
181
214
void CompositionRootView::ScaleFactor (float value) noexcept {
182
- m_scaleFactor = value;
215
+ if (m_scaleFactor != value) {
216
+ m_scaleFactor = value;
217
+ UpdateRootVisualSize ();
218
+ }
183
219
}
184
220
185
221
winrt::Microsoft::ReactNative::Composition::Theme CompositionRootView::Theme () noexcept {
@@ -397,6 +433,7 @@ void CompositionRootView::ClearLoadingUI() noexcept {
397
433
RootVisual ().Remove (m_loadingVisual);
398
434
399
435
m_loadingVisual = nullptr ;
436
+ m_loadingActivityVisual = nullptr ;
400
437
}
401
438
402
439
void CompositionRootView::EnsureLoadingUI () noexcept {}
@@ -425,6 +462,63 @@ void CompositionRootView::ShowInstanceError() noexcept {
425
462
ClearLoadingUI ();
426
463
}
427
464
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
+
428
522
void CompositionRootView::ShowInstanceLoading () noexcept {
429
523
if (!Mso::React::ReactOptions::UseDeveloperSupport (m_context.Properties ().Handle ()))
430
524
return ;
@@ -436,19 +530,18 @@ void CompositionRootView::ShowInstanceLoading() noexcept {
436
530
winrt::Microsoft::ReactNative::Composition::implementation::CompositionUIService::GetCompositionContext (
437
531
m_context.Properties ().Handle ());
438
532
439
- auto brush = compContext.CreateColorBrush ({0x80 , 0x03 , 0x29 , 0x29 });
533
+ auto drawingSurface = CreateLoadingVisualBrush ();
534
+
440
535
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);
444
537
445
538
auto foregroundBrush = compContext.CreateColorBrush ({255 , 255 , 255 , 255 });
446
539
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 ( );
452
545
453
546
RootVisual ().InsertAt (m_loadingVisual, m_hasRenderedVisual ? 1 : 0 );
454
547
}
@@ -523,7 +616,6 @@ winrt::Microsoft::UI::Content::ContentIsland CompositionRootView::Island() noexc
523
616
524
617
if (!m_island) {
525
618
auto rootVisual = m_compositor.CreateSpriteVisual ();
526
- rootVisual.RelativeSizeAdjustment ({1 , 1 });
527
619
528
620
RootVisual (winrt::Microsoft::ReactNative::Composition::MicrosoftCompositionContextHelper::CreateVisual (rootVisual));
529
621
m_island = winrt::Microsoft::UI::Content::ContentIsland::Create (rootVisual);
0 commit comments