react-native-windows 0.76.11 → 0.76.13
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.
- package/Libraries/Components/Button.windows.js +3 -0
- package/Libraries/Components/ScrollView/ScrollView.windows.js +1959 -0
- package/Libraries/Components/View/View.windows.js +107 -56
- package/Libraries/Image/Image.windows.js +42 -21
- package/Libraries/Text/Text.d.ts +16 -1
- package/Microsoft.ReactNative/CompositionComponentView.idl +0 -5
- package/Microsoft.ReactNative/CompositionSwitcher.idl +4 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +32 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +159 -4
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +11 -4
- package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +0 -4
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +22 -17
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +1 -27
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +0 -2
- package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +36 -11
- package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +3 -0
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +50 -125
- package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +9 -6
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +31 -12
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +6 -1
- package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +2 -2
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +145 -19
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +13 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentDescriptor.h +0 -2
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +134 -11
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +6 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.cpp +31 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.h +14 -1
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.cpp +6 -2
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h +4 -1
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +127 -109
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +28 -25
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.cpp +8 -18
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.h +12 -35
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +53 -11
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +10 -2
- package/Microsoft.ReactNative/Fabric/ImageRequestParams.cpp +26 -0
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +38 -8
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.h +3 -1
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +206 -41
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h +14 -0
- package/Microsoft.ReactNative/Modules/Animated/AnimationDriver.cpp +2 -1
- package/Microsoft.ReactNative/ReactNativeIsland.idl +3 -0
- package/Microsoft.ReactNative/Utils/ImageUtils.h +1 -0
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/PropertySheets/NuGet.LockFile.props +1 -1
- package/PropertySheets/WebView2.props +1 -1
- package/PropertySheets/WinUI.props +1 -1
- package/Shared/Networking/WinRTWebSocketResource.cpp +82 -101
- package/Shared/Networking/WinRTWebSocketResource.h +91 -7
- package/Shared/Shared.vcxitems +3 -1
- package/Shared/Shared.vcxitems.filters +1 -0
- 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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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;
|
package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp
CHANGED
|
@@ -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 ¶graphAttributes,
|
|
22
70
|
Size size,
|
|
23
|
-
winrt::com_ptr<IDWriteTextLayout> &spTextLayout
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ¶graphAttributes,
|
|
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 ¶graphAttributes,
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
}
|
package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h
CHANGED
|
@@ -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 ¶graphAttributes,
|
|
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 ¶graphAttributes,
|
|
81
88
|
LayoutConstraints layoutConstraints,
|
|
82
89
|
winrt::com_ptr<IDWriteTextLayout> &spTextLayout) noexcept;
|
|
83
90
|
|
|
91
|
+
static void GetTextLayoutByAdjustingFontSizeToFit(
|
|
92
|
+
AttributedStringBox attributedStringBox,
|
|
93
|
+
const ParagraphAttributes ¶graphAttributes,
|
|
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
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
-->
|
|
11
11
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
12
12
|
<PropertyGroup>
|
|
13
|
-
<ReactNativeWindowsVersion>0.76.
|
|
13
|
+
<ReactNativeWindowsVersion>0.76.13</ReactNativeWindowsVersion>
|
|
14
14
|
<ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
|
|
15
15
|
<ReactNativeWindowsMinor>76</ReactNativeWindowsMinor>
|
|
16
|
-
<ReactNativeWindowsPatch>
|
|
16
|
+
<ReactNativeWindowsPatch>13</ReactNativeWindowsPatch>
|
|
17
17
|
<ReactNativeWindowsCanary>false</ReactNativeWindowsCanary>
|
|
18
|
-
<ReactNativeWindowsCommitId>
|
|
18
|
+
<ReactNativeWindowsCommitId>838423173a985d81b925df7c668072db0324a555</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'">
|
|
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.
|
|
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.
|
|
12
|
+
<WinUI3Version Condition="'$(WinUI3Version)'==''">1.7.250401001</WinUI3Version>
|
|
13
13
|
</PropertyGroup>
|
|
14
14
|
|
|
15
15
|
<PropertyGroup Label="WinUI2x versioning">
|