react-native-windows 0.76.10 → 0.76.12

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 (58) hide show
  1. package/Directory.Build.props +2 -2
  2. package/Folly/TEMP_UntilFollyUpdate/json.cpp +4 -0
  3. package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.cpp +23 -15
  4. package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h +5 -5
  5. package/Folly/cgmanifest.json +1 -1
  6. package/Libraries/Components/Button.windows.js +3 -0
  7. package/Libraries/Components/ScrollView/ScrollView.windows.js +1959 -0
  8. package/Libraries/Components/View/View.windows.js +107 -56
  9. package/Libraries/Image/Image.windows.js +42 -21
  10. package/Libraries/Text/Text.d.ts +16 -1
  11. package/Microsoft.ReactNative/CompositionComponentView.idl +0 -5
  12. package/Microsoft.ReactNative/CompositionSwitcher.idl +4 -0
  13. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +32 -0
  14. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +159 -4
  15. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +11 -4
  16. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +0 -4
  17. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +22 -17
  18. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +1 -27
  19. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +0 -2
  20. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +36 -11
  21. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +3 -0
  22. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +50 -125
  23. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +9 -6
  24. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +31 -12
  25. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +6 -1
  26. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +2 -2
  27. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +145 -19
  28. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +13 -0
  29. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentDescriptor.h +0 -2
  30. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +134 -11
  31. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +6 -0
  32. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.cpp +31 -0
  33. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.h +14 -1
  34. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.cpp +6 -2
  35. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h +4 -1
  36. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +127 -109
  37. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +28 -25
  38. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.cpp +8 -18
  39. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.h +12 -35
  40. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +53 -11
  41. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +10 -2
  42. package/Microsoft.ReactNative/Fabric/ImageRequestParams.cpp +26 -0
  43. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +38 -8
  44. package/Microsoft.ReactNative/Fabric/WindowsImageManager.h +3 -1
  45. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +206 -41
  46. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h +14 -0
  47. package/Microsoft.ReactNative/Modules/Animated/AnimationDriver.cpp +2 -1
  48. package/Microsoft.ReactNative/ReactNativeIsland.idl +3 -0
  49. package/Microsoft.ReactNative/Utils/ImageUtils.h +1 -0
  50. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  51. package/PropertySheets/NuGet.LockFile.props +1 -1
  52. package/PropertySheets/WebView2.props +1 -1
  53. package/PropertySheets/WinUI.props +1 -1
  54. package/Shared/Networking/WinRTWebSocketResource.cpp +82 -96
  55. package/Shared/Networking/WinRTWebSocketResource.h +91 -7
  56. package/Shared/Shared.vcxitems +3 -1
  57. package/Shared/Shared.vcxitems.filters +1 -0
  58. package/package.json +1 -1
@@ -6,13 +6,13 @@
6
6
  #include <NativeModules.h>
7
7
  #include <React.h>
8
8
  #include <react/renderer/scheduler/SchedulerDelegate.h>
9
- #include <react/renderer/scheduler/SurfaceManager.h>
10
9
  #include <winrt/Windows.UI.Composition.h>
11
10
  #include "Composition/ComponentViewRegistry.h"
12
11
 
13
12
  namespace facebook::react {
14
13
  class Scheduler;
15
14
  class ReactNativeConfig;
15
+ class SurfaceHandler;
16
16
  } // namespace facebook::react
17
17
 
18
18
  namespace Microsoft::ReactNative {
@@ -47,6 +47,8 @@ struct FabricUIManager final : public std::enable_shared_from_this<FabricUIManag
47
47
  const facebook::react::LayoutConstraints &layoutConstraints,
48
48
  const facebook::react::LayoutContext &layoutContext) const noexcept;
49
49
 
50
+ void setProps(facebook::react::SurfaceId surfaceId, const folly::dynamic &props) const noexcept;
51
+
50
52
  const IComponentViewRegistry &GetViewRegistry() const noexcept;
51
53
 
52
54
  static winrt::Microsoft::ReactNative::ReactNotificationId<facebook::react::SurfaceId> NotifyMountedId() noexcept;
@@ -62,10 +64,13 @@ struct FabricUIManager final : public std::enable_shared_from_this<FabricUIManag
62
64
  facebook::react::SurfaceId surfaceId);
63
65
  void didMountComponentsWithRootTag(facebook::react::SurfaceId surfaceId) noexcept;
64
66
 
67
+ void visit(
68
+ facebook::react::SurfaceId surfaceId,
69
+ const std::function<void(const facebook::react::SurfaceHandler &surfaceHandler)> &callback) const noexcept;
70
+
65
71
  winrt::Microsoft::ReactNative::ReactContext m_context;
66
72
  winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext m_compContext;
67
73
  std::shared_ptr<facebook::react::Scheduler> m_scheduler;
68
- std::shared_ptr<facebook::react::SurfaceManager> m_surfaceManager;
69
74
  std::mutex m_schedulerMutex; // Protect m_scheduler
70
75
  bool m_transactionInFlight{false};
71
76
  bool m_followUpTransactionRequired{false};
@@ -77,6 +82,9 @@ struct FabricUIManager final : public std::enable_shared_from_this<FabricUIManag
77
82
 
78
83
  std::unordered_map<facebook::react::SurfaceId, SurfaceInfo> m_surfaceRegistry;
79
84
 
85
+ std::unordered_map<facebook::react::SurfaceId, facebook::react::SurfaceHandler> m_handlerRegistry{};
86
+ mutable std::shared_mutex m_handlerMutex;
87
+
80
88
  // Inherited via SchedulerDelegate
81
89
  virtual void schedulerDidFinishTransaction(
82
90
  const facebook::react::MountingCoordinator::Shared &mountingCoordinator) override;
@@ -0,0 +1,26 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+
6
+ #include <react/renderer/graphics/Float.h>
7
+
8
+ namespace facebook::react {
9
+
10
+ class ImageRequestParams {
11
+ public:
12
+ ImageRequestParams() = default;
13
+ explicit ImageRequestParams(Float blurRadius) : blurRadius(blurRadius) {}
14
+
15
+ Float blurRadius{};
16
+
17
+ bool operator==(const ImageRequestParams &rhs) const {
18
+ return this->blurRadius == rhs.blurRadius;
19
+ }
20
+
21
+ bool operator!=(const ImageRequestParams &rhs) const {
22
+ return !(*this == rhs);
23
+ }
24
+ };
25
+
26
+ } // namespace facebook::react
@@ -78,7 +78,9 @@ wicBitmapSourceFromStream(const winrt::Windows::Storage::Streams::IRandomAccessS
78
78
  }
79
79
 
80
80
  winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::ReactNative::Composition::ImageResponse>
81
- WindowsImageManager::GetImageRandomAccessStreamAsync(ReactImageSource source) const {
81
+ WindowsImageManager::GetImageRandomAccessStreamAsync(
82
+ ReactImageSource source,
83
+ std::function<void(uint64_t loaded, uint64_t total)> progressCallback) const {
82
84
  co_await winrt::resume_background();
83
85
 
84
86
  winrt::Windows::Foundation::Uri uri(winrt::to_hstring(source.uri));
@@ -123,6 +125,12 @@ WindowsImageManager::GetImageRandomAccessStreamAsync(ReactImageSource source) co
123
125
  }
124
126
  }
125
127
 
128
+ if (!source.body.empty()) {
129
+ auto bodyContent = winrt::Windows::Web::Http::HttpStringContent(
130
+ winrt::to_hstring(source.body), winrt::Windows::Storage::Streams::UnicodeEncoding::Utf8, L"application/json");
131
+ request.Content(bodyContent);
132
+ }
133
+
126
134
  winrt::Windows::Web::Http::HttpResponseMessage response(co_await m_httpClient.SendRequestAsync(request));
127
135
 
128
136
  if (!response.IsSuccessStatusCode()) {
@@ -130,8 +138,29 @@ WindowsImageManager::GetImageRandomAccessStreamAsync(ReactImageSource source) co
130
138
  response.ReasonPhrase(), response.StatusCode(), response.Headers());
131
139
  }
132
140
 
141
+ auto inputStream = co_await response.Content().ReadAsInputStreamAsync();
142
+ auto contentLengthRef = response.Content().Headers().ContentLength();
143
+ uint64_t total = contentLengthRef ? contentLengthRef.GetUInt64() : 0;
144
+ uint64_t loaded = 0;
145
+
133
146
  winrt::Windows::Storage::Streams::InMemoryRandomAccessStream memoryStream;
134
- co_await response.Content().WriteToStreamAsync(memoryStream);
147
+ winrt::Windows::Storage::Streams::DataReader reader(inputStream);
148
+ constexpr uint32_t bufferSize = 16 * 1024;
149
+
150
+ while (true) {
151
+ uint32_t loadedBuffer = co_await reader.LoadAsync(bufferSize);
152
+ if (loadedBuffer == 0)
153
+ break;
154
+
155
+ auto buffer = reader.ReadBuffer(loadedBuffer);
156
+ co_await memoryStream.WriteAsync(buffer);
157
+ loaded += loadedBuffer;
158
+
159
+ if (progressCallback) {
160
+ progressCallback(loaded, total);
161
+ }
162
+ }
163
+
135
164
  memoryStream.Seek(0);
136
165
 
137
166
  co_return winrt::Microsoft::ReactNative::Composition::StreamImageResponse(memoryStream.CloneStream());
@@ -160,7 +189,13 @@ facebook::react::ImageRequest WindowsImageManager::requestImage(
160
189
  source.width = imageSource.size.width;
161
190
  source.sourceType = ImageSourceType::Download;
162
191
 
163
- imageResponseTask = GetImageRandomAccessStreamAsync(source);
192
+ auto progressCallback = [weakObserverCoordinator](int64_t loaded, int64_t total) {
193
+ if (auto observerCoordinator = weakObserverCoordinator.lock()) {
194
+ float progress = total > 0 ? static_cast<float>(loaded) / static_cast<float>(total) : 1.0f;
195
+ observerCoordinator->nativeImageResponseProgress(progress, loaded, total);
196
+ }
197
+ };
198
+ imageResponseTask = GetImageRandomAccessStreamAsync(source, progressCallback);
164
199
  }
165
200
 
166
201
  imageResponseTask.Completed([weakObserverCoordinator](auto asyncOp, auto status) {
@@ -195,11 +230,6 @@ facebook::react::ImageRequest WindowsImageManager::requestImage(
195
230
  observerCoordinator->nativeImageResponseFailed(facebook::react::ImageLoadError(errorInfo));
196
231
  break;
197
232
  }
198
- case winrt::Windows::Foundation::AsyncStatus::Started: {
199
- // TODO progress? - Can we register for progress off the download task?
200
- // observerCoordinator->nativeImageResponseProgress(0.0/*progress*/, 0/*completed*/, 0/*total*/);
201
- break;
202
- }
203
233
  }
204
234
  });
205
235
  return imageRequest;
@@ -22,7 +22,9 @@ struct WindowsImageManager {
22
22
 
23
23
  private:
24
24
  winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::ReactNative::Composition::ImageResponse>
25
- GetImageRandomAccessStreamAsync(ReactImageSource source) const;
25
+ GetImageRandomAccessStreamAsync(
26
+ ReactImageSource source,
27
+ std::function<void(uint64_t loaded, uint64_t total)> progressCallback) const;
26
28
 
27
29
  winrt::Windows::Web::Http::HttpClient m_httpClient;
28
30
  winrt::Microsoft::ReactNative::ReactContext m_reactContext;
@@ -16,11 +16,60 @@
16
16
 
17
17
  namespace facebook::react {
18
18
 
19
+ // Creates an empty InlineObject since RN handles actually rendering the Inline object, this just reserves space for it.
20
+ class AttachmentInlineObject : public winrt::implements<AttachmentInlineObject, IDWriteInlineObject> {
21
+ public:
22
+ AttachmentInlineObject(float width, float height) : m_width(width), m_height(height) {}
23
+
24
+ // IDWriteInlineObject methods
25
+ STDMETHOD(Draw)
26
+ (_In_opt_ void *clientDrawingContext,
27
+ _In_ IDWriteTextRenderer *renderer,
28
+ FLOAT originX,
29
+ FLOAT originY,
30
+ BOOL isSideways,
31
+ BOOL isRightToLeft,
32
+ _In_opt_ IUnknown *clientDrawingEffect) override {
33
+ // We don't need to draw anything here since the actual rendering is handled by React Native
34
+ return S_OK;
35
+ }
36
+
37
+ STDMETHOD(GetMetrics)(_Out_ DWRITE_INLINE_OBJECT_METRICS *metrics) override {
38
+ metrics->width = m_width;
39
+ metrics->height = m_height;
40
+ metrics->baseline =
41
+ m_height; // If the baseline is at the bottom, then baseline = height
42
+ // (https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ns-dwrite-dwrite_inline_object_metrics)
43
+ metrics->supportsSideways = true;
44
+ return S_OK;
45
+ }
46
+
47
+ STDMETHOD(GetOverhangMetrics)(_Out_ DWRITE_OVERHANG_METRICS *overhangs) override {
48
+ overhangs->left = 0;
49
+ overhangs->top = 0;
50
+ overhangs->right = 0;
51
+ overhangs->bottom = 0;
52
+ return S_OK;
53
+ }
54
+
55
+ STDMETHOD(GetBreakConditions)
56
+ (_Out_ DWRITE_BREAK_CONDITION *breakConditionBefore, _Out_ DWRITE_BREAK_CONDITION *breakConditionAfter) override {
57
+ *breakConditionBefore = DWRITE_BREAK_CONDITION_NEUTRAL;
58
+ *breakConditionAfter = DWRITE_BREAK_CONDITION_NEUTRAL;
59
+ return S_OK;
60
+ }
61
+
62
+ private:
63
+ float m_width;
64
+ float m_height;
65
+ };
66
+
19
67
  void TextLayoutManager::GetTextLayout(
20
68
  const AttributedStringBox &attributedStringBox,
21
69
  const ParagraphAttributes &paragraphAttributes,
22
70
  Size size,
23
- winrt::com_ptr<IDWriteTextLayout> &spTextLayout) noexcept {
71
+ winrt::com_ptr<IDWriteTextLayout> &spTextLayout,
72
+ TextMeasurement::Attachments &attachments) noexcept {
24
73
  const auto &attributedString = attributedStringBox.getValue();
25
74
  auto fragments = attributedString.getFragments();
26
75
  auto outerFragment = fragments[0];
@@ -62,6 +111,7 @@ void TextLayoutManager::GetTextLayout(
62
111
  outerFragment.textAttributes.lineHeight * 0.8f));
63
112
  }
64
113
 
114
+ // Set text alignment
65
115
  DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT_LEADING;
66
116
  if (outerFragment.textAttributes.alignment) {
67
117
  switch (*outerFragment.textAttributes.alignment) {
@@ -87,6 +137,7 @@ void TextLayoutManager::GetTextLayout(
87
137
  }
88
138
  winrt::check_hresult(spTextFormat->SetTextAlignment(alignment));
89
139
 
140
+ // Get text with Object Replacement Characters for attachments
90
141
  auto str = GetTransformedText(attributedStringBox);
91
142
 
92
143
  winrt::check_hresult(Microsoft::ReactNative::DWriteFactory()->CreateTextLayout(
@@ -98,39 +149,75 @@ void TextLayoutManager::GetTextLayout(
98
149
  spTextLayout.put() // The IDWriteTextLayout interface pointer.
99
150
  ));
100
151
 
152
+ // Calculate positions for attachments and set inline objects
101
153
  unsigned int position = 0;
102
- unsigned int length = 0;
103
154
  for (const auto &fragment : fragments) {
104
- length = static_cast<UINT32>(fragment.string.length());
105
- DWRITE_TEXT_RANGE range = {position, length};
106
- TextAttributes attributes = fragment.textAttributes;
107
- DWRITE_FONT_STYLE fragmentStyle = DWRITE_FONT_STYLE_NORMAL;
108
- if (attributes.fontStyle == facebook::react::FontStyle::Italic)
109
- fragmentStyle = DWRITE_FONT_STYLE_ITALIC;
110
- else if (attributes.fontStyle == facebook::react::FontStyle::Oblique)
111
- fragmentStyle = DWRITE_FONT_STYLE_OBLIQUE;
112
-
113
- winrt::check_hresult(spTextLayout->SetFontFamilyName(
114
- attributes.fontFamily.empty() ? L"Segoe UI"
115
- : Microsoft::Common::Unicode::Utf8ToUtf16(attributes.fontFamily).c_str(),
116
- range));
117
- winrt::check_hresult(spTextLayout->SetFontWeight(
118
- static_cast<DWRITE_FONT_WEIGHT>(
119
- attributes.fontWeight.value_or(static_cast<facebook::react::FontWeight>(DWRITE_FONT_WEIGHT_REGULAR))),
120
- range));
121
- winrt::check_hresult(spTextLayout->SetFontStyle(fragmentStyle, range));
122
- winrt::check_hresult(spTextLayout->SetFontSize(
123
- (attributes.allowFontScaling.value_or(true) && !std::isnan(attributes.fontSizeMultiplier))
124
- ? (attributes.fontSizeMultiplier * attributes.fontSize)
125
- : attributes.fontSize,
126
- range));
127
-
128
- if (!isnan(attributes.letterSpacing)) {
129
- winrt::check_hresult(
130
- spTextLayout.as<IDWriteTextLayout1>()->SetCharacterSpacing(0, attributes.letterSpacing, 0, range));
131
- }
155
+ if (fragment.isAttachment()) {
156
+ float width = fragment.parentShadowView.layoutMetrics.frame.size.width;
157
+ float height = fragment.parentShadowView.layoutMetrics.frame.size.height;
158
+
159
+ // Get current height to check if attachment needs to be clipped
160
+ DWRITE_TEXT_METRICS dtm{};
161
+ winrt::check_hresult(spTextLayout->GetMetrics(&dtm));
162
+
163
+ // Check if the attachment should be clipped
164
+ // TODO #14443: clipping works on the first-levels view, but any nested view won't be clipped
165
+ bool isClipped = height > dtm.height;
166
+ if (isClipped) {
167
+ height = dtm.height;
168
+ }
132
169
 
133
- position += length;
170
+ // Create an inline object (this just reserves space in RichEdit for ReactNative to render the actual attachment)
171
+ auto inlineObject = winrt::make<AttachmentInlineObject>(width, height);
172
+ winrt::check_hresult(spTextLayout->SetInlineObject(inlineObject.get(), {position, 1}));
173
+
174
+ // Get the position of the Object Replacement Character
175
+ DWRITE_HIT_TEST_METRICS hitTestMetrics;
176
+ float x, y;
177
+ winrt::check_hresult(spTextLayout->HitTestTextPosition(position, false, &x, &y, &hitTestMetrics));
178
+
179
+ // Store the attachment position for RN to render later
180
+ TextMeasurement::Attachment attachment;
181
+ attachment.frame = {
182
+ x, // left
183
+ y, // top
184
+ width, // width
185
+ height // height
186
+ };
187
+ attachment.isClipped = isClipped;
188
+ attachments.push_back(attachment);
189
+ position += 1;
190
+ } else {
191
+ unsigned int length = static_cast<UINT32>(fragment.string.length());
192
+ DWRITE_TEXT_RANGE range = {position, length};
193
+ TextAttributes attributes = fragment.textAttributes;
194
+ DWRITE_FONT_STYLE fragmentStyle = DWRITE_FONT_STYLE_NORMAL;
195
+ if (attributes.fontStyle == facebook::react::FontStyle::Italic)
196
+ fragmentStyle = DWRITE_FONT_STYLE_ITALIC;
197
+ else if (attributes.fontStyle == facebook::react::FontStyle::Oblique)
198
+ fragmentStyle = DWRITE_FONT_STYLE_OBLIQUE;
199
+
200
+ winrt::check_hresult(spTextLayout->SetFontFamilyName(
201
+ attributes.fontFamily.empty() ? L"Segoe UI"
202
+ : Microsoft::Common::Unicode::Utf8ToUtf16(attributes.fontFamily).c_str(),
203
+ range));
204
+ winrt::check_hresult(spTextLayout->SetFontWeight(
205
+ static_cast<DWRITE_FONT_WEIGHT>(
206
+ attributes.fontWeight.value_or(static_cast<facebook::react::FontWeight>(DWRITE_FONT_WEIGHT_REGULAR))),
207
+ range));
208
+ winrt::check_hresult(spTextLayout->SetFontStyle(fragmentStyle, range));
209
+ winrt::check_hresult(spTextLayout->SetFontSize(
210
+ (attributes.allowFontScaling.value_or(true) && !std::isnan(attributes.fontSizeMultiplier))
211
+ ? (attributes.fontSizeMultiplier * attributes.fontSize)
212
+ : attributes.fontSize,
213
+ range));
214
+
215
+ if (!isnan(attributes.letterSpacing)) {
216
+ winrt::check_hresult(
217
+ spTextLayout.as<IDWriteTextLayout1>()->SetCharacterSpacing(0, attributes.letterSpacing, 0, range));
218
+ }
219
+ position += length;
220
+ }
134
221
  }
135
222
  }
136
223
 
@@ -142,9 +229,69 @@ void TextLayoutManager::GetTextLayout(
142
229
  if (attributedStringBox.getValue().isEmpty())
143
230
  return;
144
231
 
145
- GetTextLayout(attributedStringBox, paragraphAttributes, layoutConstraints.maximumSize, spTextLayout);
232
+ TextMeasurement::Attachments attachments;
233
+ if (paragraphAttributes.adjustsFontSizeToFit) {
234
+ GetTextLayoutByAdjustingFontSizeToFit(
235
+ attributedStringBox, paragraphAttributes, layoutConstraints, spTextLayout, attachments);
236
+ } else {
237
+ GetTextLayout(attributedStringBox, paragraphAttributes, layoutConstraints.maximumSize, spTextLayout, attachments);
238
+ }
239
+ }
240
+
241
+ void TextLayoutManager::GetTextLayoutByAdjustingFontSizeToFit(
242
+ AttributedStringBox attributedStringBox,
243
+ const ParagraphAttributes &paragraphAttributes,
244
+ LayoutConstraints layoutConstraints,
245
+ winrt::com_ptr<IDWriteTextLayout> &spTextLayout,
246
+ TextMeasurement::Attachments &attachments) noexcept {
247
+ /* This function constructs a text layout from the given parameters.
248
+ If the generated text layout doesn't fit within the given layout constraints,
249
+ it will reduce the font size and construct a new text layout. This process will
250
+ be repeated until the text layout meets the constraints.*/
251
+
252
+ DWRITE_TEXT_METRICS metrics;
253
+
254
+ // Better Approach should be implemented , this uses O(n)
255
+ do {
256
+ if (spTextLayout) // Font Size reduction
257
+ {
258
+ constexpr auto fontReduceFactor = 1.0f;
259
+
260
+ auto attributedStringToResize = attributedStringBox.getValue();
261
+
262
+ auto fragmentsCopyToResize = attributedStringToResize.getFragments();
263
+
264
+ attributedStringToResize.getFragments().clear();
265
+
266
+ for (auto fragment : fragmentsCopyToResize) {
267
+ fragment.textAttributes.fontSize -= fontReduceFactor;
268
+
269
+ attributedStringToResize.appendFragment(std::move(fragment));
270
+ }
271
+ attributedStringBox = facebook::react::AttributedStringBox(attributedStringToResize);
272
+ }
273
+
274
+ GetTextLayout(attributedStringBox, paragraphAttributes, layoutConstraints.maximumSize, spTextLayout, attachments);
275
+
276
+ if (spTextLayout) {
277
+ const auto defaultMinFontSize = 2.0f;
278
+
279
+ // TODO : changes for minimumFontScale prop can be added.
280
+
281
+ if (spTextLayout->GetFontSize() <= defaultMinFontSize) {
282
+ break; // reached minimum font size , so no more size reducing
283
+ }
284
+ winrt::check_hresult(spTextLayout->GetMetrics(&metrics));
285
+ } else {
286
+ return;
287
+ }
288
+
289
+ } while ((paragraphAttributes.maximumNumberOfLines != 0 &&
290
+ paragraphAttributes.maximumNumberOfLines < static_cast<int>(metrics.lineCount)) ||
291
+ metrics.height > metrics.layoutHeight || metrics.width > metrics.layoutWidth);
146
292
  }
147
293
 
294
+ // measure entire text (inluding attachments)
148
295
  TextMeasurement TextLayoutManager::measure(
149
296
  const AttributedStringBox &attributedStringBox,
150
297
  const ParagraphAttributes &paragraphAttributes,
@@ -152,6 +299,7 @@ TextMeasurement TextLayoutManager::measure(
152
299
  LayoutConstraints layoutConstraints) const {
153
300
  TextMeasurement measurement{};
154
301
  auto &attributedString = attributedStringBox.getValue();
302
+
155
303
  measurement = m_measureCache.get(
156
304
  {attributedString, paragraphAttributes, layoutConstraints}, [&](TextMeasureCacheKey const &key) {
157
305
  auto telemetry = TransactionTelemetry::threadLocalTelemetry();
@@ -161,7 +309,9 @@ TextMeasurement TextLayoutManager::measure(
161
309
 
162
310
  winrt::com_ptr<IDWriteTextLayout> spTextLayout;
163
311
 
164
- GetTextLayout(attributedStringBox, paragraphAttributes, layoutConstraints, spTextLayout);
312
+ TextMeasurement::Attachments attachments;
313
+ GetTextLayout(
314
+ attributedStringBox, paragraphAttributes, layoutConstraints.maximumSize, spTextLayout, attachments);
165
315
 
166
316
  if (spTextLayout) {
167
317
  auto maxHeight = std::numeric_limits<float>().max();
@@ -182,6 +332,7 @@ TextMeasurement TextLayoutManager::measure(
182
332
  DWRITE_TEXT_METRICS dtm{};
183
333
  winrt::check_hresult(spTextLayout->GetMetrics(&dtm));
184
334
  measurement.size = {dtm.width, std::min(dtm.height, maxHeight)};
335
+ measurement.attachments = attachments;
185
336
  }
186
337
 
187
338
  if (telemetry) {
@@ -190,7 +341,6 @@ TextMeasurement TextLayoutManager::measure(
190
341
 
191
342
  return measurement;
192
343
  });
193
-
194
344
  return measurement;
195
345
  }
196
346
 
@@ -232,8 +382,8 @@ LinesMeasurements TextLayoutManager::measureLines(
232
382
  LinesMeasurements lineMeasurements{};
233
383
 
234
384
  winrt::com_ptr<IDWriteTextLayout> spTextLayout;
235
-
236
- GetTextLayout(attributedStringBox, paragraphAttributes, size, spTextLayout);
385
+ TextMeasurement::Attachments attachments;
386
+ GetTextLayout(attributedStringBox, paragraphAttributes, size, spTextLayout, attachments);
237
387
 
238
388
  if (spTextLayout) {
239
389
  std::vector<DWRITE_LINE_METRICS> lineMetrics;
@@ -313,17 +463,32 @@ Float TextLayoutManager::baseline(
313
463
  AttributedStringBox attributedStringBox,
314
464
  ParagraphAttributes paragraphAttributes,
315
465
  Size size) const {
316
- return 0;
466
+ winrt::com_ptr<IDWriteTextLayout> spTextLayout;
467
+ TextMeasurement::Attachments attachments;
468
+ GetTextLayout(attributedStringBox, paragraphAttributes, size, spTextLayout, attachments);
469
+ if (!spTextLayout) {
470
+ return 0;
471
+ }
472
+
473
+ DWRITE_TEXT_METRICS metrics;
474
+ winrt::check_hresult(spTextLayout->GetMetrics(&metrics));
475
+ return metrics.height *
476
+ 0.8f; // https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritetextformat-getlinespacing
317
477
  }
318
478
 
319
479
  winrt::hstring TextLayoutManager::GetTransformedText(const AttributedStringBox &attributedStringBox) {
320
480
  winrt::hstring result{};
321
481
  const auto &attributedString = attributedStringBox.getValue();
482
+
322
483
  for (const auto &fragment : attributedString.getFragments()) {
323
- result = result +
324
- Microsoft::ReactNative::TransformableText::TransformText(
325
- winrt::hstring{Microsoft::Common::Unicode::Utf8ToUtf16(fragment.string)},
326
- ConvertTextTransform(fragment.textAttributes.textTransform));
484
+ if (fragment.isAttachment()) {
485
+ result = result + L"\uFFFC"; // Unicode Object Replacement Character, will be replaced with an inline object
486
+ } else {
487
+ result = result +
488
+ Microsoft::ReactNative::TransformableText::TransformText(
489
+ winrt::hstring{Microsoft::Common::Unicode::Utf8ToUtf16(fragment.string)},
490
+ ConvertTextTransform(fragment.textAttributes.textTransform));
491
+ }
327
492
  }
328
493
  return result;
329
494
  }
@@ -75,12 +75,26 @@ class TextLayoutManager {
75
75
  */
76
76
  void *getNativeTextLayoutManager() const;
77
77
 
78
+ static void GetTextLayout(
79
+ const AttributedStringBox &attributedStringBox,
80
+ const ParagraphAttributes &paragraphAttributes,
81
+ Size size,
82
+ winrt::com_ptr<IDWriteTextLayout> &spTextLayout,
83
+ TextMeasurement::Attachments &attachments) noexcept;
84
+
78
85
  static void GetTextLayout(
79
86
  const AttributedStringBox &attributedStringBox,
80
87
  const ParagraphAttributes &paragraphAttributes,
81
88
  LayoutConstraints layoutConstraints,
82
89
  winrt::com_ptr<IDWriteTextLayout> &spTextLayout) noexcept;
83
90
 
91
+ static void GetTextLayoutByAdjustingFontSizeToFit(
92
+ AttributedStringBox attributedStringBox,
93
+ const ParagraphAttributes &paragraphAttributes,
94
+ LayoutConstraints layoutConstraints,
95
+ winrt::com_ptr<IDWriteTextLayout> &spTextLayout,
96
+ TextMeasurement::Attachments &attachments) noexcept;
97
+
84
98
  #pragma endregion
85
99
 
86
100
  private:
@@ -50,7 +50,6 @@ void AnimationDriver::StartAnimation() {
50
50
  animatedValue->PropertySet().StartAnimation(ValueAnimatedNode::s_valueName, animation);
51
51
  animatedValue->AddActiveAnimation(m_id);
52
52
  }
53
- scopedBatch.End();
54
53
 
55
54
  m_scopedBatchCompletedToken = scopedBatch.Completed(
56
55
  [weakSelf = weak_from_this(), weakManager = m_manager, id = m_id, tag = m_animatedValueTag](auto sender, auto) {
@@ -74,6 +73,8 @@ void AnimationDriver::StartAnimation() {
74
73
  }
75
74
  });
76
75
 
76
+ scopedBatch.End();
77
+
77
78
  m_animation = animation;
78
79
  m_scopedBatch = scopedBatch;
79
80
  }
@@ -119,6 +119,9 @@ namespace Microsoft.ReactNative
119
119
  Microsoft.ReactNative.Composition.Theme Theme { get; };
120
120
  Int64 RootTag { get; };
121
121
 
122
+ DOC_STRING("Initial props should be set on ReactViewHost. This is used to update props after the initial props are set")
123
+ void SetProperties(JSValueArgWriter props);
124
+
122
125
  #ifdef USE_WINUI3
123
126
  Microsoft.UI.Content.ContentIsland Island { get; };
124
127
  #endif
@@ -15,6 +15,7 @@ struct ReactImageSource {
15
15
  std::string uri;
16
16
  std::string method;
17
17
  std::vector<std::pair<std::string, std::string>> headers;
18
+ std::string body;
18
19
  double width = 0;
19
20
  double height = 0;
20
21
  double scale = 1.0;
@@ -10,11 +10,11 @@
10
10
  -->
11
11
  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
12
12
  <PropertyGroup>
13
- <ReactNativeWindowsVersion>0.76.10</ReactNativeWindowsVersion>
13
+ <ReactNativeWindowsVersion>0.76.12</ReactNativeWindowsVersion>
14
14
  <ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
15
15
  <ReactNativeWindowsMinor>76</ReactNativeWindowsMinor>
16
- <ReactNativeWindowsPatch>10</ReactNativeWindowsPatch>
16
+ <ReactNativeWindowsPatch>12</ReactNativeWindowsPatch>
17
17
  <ReactNativeWindowsCanary>false</ReactNativeWindowsCanary>
18
- <ReactNativeWindowsCommitId>a2aced6bb38c7d0ff2721ef1ec60edb93b9ff64b</ReactNativeWindowsCommitId>
18
+ <ReactNativeWindowsCommitId>e9875d85951d401de0b9c8b26abdee6ce09e807d</ReactNativeWindowsCommitId>
19
19
  </PropertyGroup>
20
20
  </Project>
@@ -8,7 +8,7 @@
8
8
  -->
9
9
 
10
10
  <PropertyGroup>
11
- <RestoreLockedMode Condition="'$(RestoreLockedMode)'=='' OR '$(BuildingInRnwRepo)'=='true'">true</RestoreLockedMode>
11
+ <RestoreLockedMode Condition="'$(RestoreLockedMode)'=='' OR '$(BuildingInRnwRepo)'=='true'">false</RestoreLockedMode>
12
12
  <NuGetLockFileName>packages</NuGetLockFileName>
13
13
  <NuGetLockFileName Condition="'$(UseFabric)'=='true'">$(NuGetLockFileName).fabric</NuGetLockFileName>
14
14
  <NuGetLockFileName Condition="'$(UseExperimentalWinUI3)'=='true'">$(NuGetLockFileName).experimentalwinui3</NuGetLockFileName>
@@ -2,6 +2,6 @@
2
2
  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
3
  <PropertyGroup Label="WebView2 versioning">
4
4
  <!-- WinAppSDK 1.6+ has a dependency on Microsoft.Web.WebView2, there are a few places we need to pull in this package explicitly. -->
5
- <WebView2PackageVersion>1.0.2792.45</WebView2PackageVersion>
5
+ <WebView2PackageVersion Condition="'$(WebView2PackageVersion)'=='' Or $([MSBuild]::VersionLessThan('$(WebView2PackageVersion)', '1.0.2903.40'))">1.0.2903.40</WebView2PackageVersion>
6
6
  </PropertyGroup>
7
7
  </Project>
@@ -9,7 +9,7 @@
9
9
  <WinUI3ExperimentalVersion Condition="'$(WinUI3ExperimentalVersion)'==''">1.7.250109001-experimental2</WinUI3ExperimentalVersion>
10
10
  <!-- This value is also used by the CLI, see /packages/@react-native-windows/cli/.../autolinkWindows.ts -->
11
11
  <WinUI3Version Condition="'$(WinUI3Version)'=='' AND '$(UseExperimentalWinUI3)'=='true'">$(WinUI3ExperimentalVersion)</WinUI3Version>
12
- <WinUI3Version Condition="'$(WinUI3Version)'==''">1.6.240923002</WinUI3Version>
12
+ <WinUI3Version Condition="'$(WinUI3Version)'==''">1.7.250401001</WinUI3Version>
13
13
  </PropertyGroup>
14
14
 
15
15
  <PropertyGroup Label="WinUI2x versioning">