[Fabric] LayoutDirection and FontSizeMultiplier support (#13866)
* [Fabric] LayoutDirection and FontSizeMultiplier support * Change files * Missed a few places not setting LayoutDirection * fix crash on logbox * Fix textinput caret * fix * RichEdit has to be told its multiline before we can set a multiline string
This commit is contained in:
Родитель
0f4ade8357
Коммит
e43ea51ea7
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "prerelease",
|
||||||
|
"comment": "[Fabric] LayoutDirection and FontSizeMultiplier support",
|
||||||
|
"packageName": "react-native-windows",
|
||||||
|
"email": "30809111+acoates-ms@users.noreply.github.com",
|
||||||
|
"dependentChangeType": "patch"
|
||||||
|
}
|
|
@ -51,6 +51,7 @@ void UpdateRootViewSizeToAppWindow(
|
||||||
if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
|
if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
|
||||||
winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
|
winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
|
||||||
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
||||||
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
||||||
constraints.MaximumSize = constraints.MinimumSize = size;
|
constraints.MaximumSize = constraints.MinimumSize = size;
|
||||||
rootView.Arrange(constraints, {0, 0});
|
rootView.Arrange(constraints, {0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,7 @@ struct WindowData {
|
||||||
winrt::Microsoft::ReactNative::ReactInstanceSettings m_instanceSettings{nullptr};
|
winrt::Microsoft::ReactNative::ReactInstanceSettings m_instanceSettings{nullptr};
|
||||||
bool m_useLiftedComposition{true};
|
bool m_useLiftedComposition{true};
|
||||||
bool m_sizeToContent{false};
|
bool m_sizeToContent{false};
|
||||||
|
bool m_forceRTL{false};
|
||||||
winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget m_target{nullptr};
|
winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget m_target{nullptr};
|
||||||
LONG m_height{0};
|
LONG m_height{0};
|
||||||
LONG m_width{0};
|
LONG m_width{0};
|
||||||
|
@ -255,6 +256,10 @@ struct WindowData {
|
||||||
m_bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
|
m_bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
|
||||||
g_liftedCompositor, winrt::Microsoft::UI::GetWindowIdFromWindow(hwnd));
|
g_liftedCompositor, winrt::Microsoft::UI::GetWindowIdFromWindow(hwnd));
|
||||||
|
|
||||||
|
if (m_forceRTL) {
|
||||||
|
m_bridge.LayoutDirectionOverride(winrt::Microsoft::UI::Content::ContentLayoutDirection::RightToLeft);
|
||||||
|
}
|
||||||
|
|
||||||
auto appContent = m_compRootView.Island();
|
auto appContent = m_compRootView.Island();
|
||||||
|
|
||||||
m_bridge.Connect(appContent);
|
m_bridge.Connect(appContent);
|
||||||
|
@ -262,7 +267,7 @@ struct WindowData {
|
||||||
|
|
||||||
m_compRootView.ScaleFactor(ScaleFactor(hwnd));
|
m_compRootView.ScaleFactor(ScaleFactor(hwnd));
|
||||||
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
||||||
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight;
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
||||||
constraints.MaximumSize =
|
constraints.MaximumSize =
|
||||||
constraints.MinimumSize = {m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
|
constraints.MinimumSize = {m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
|
||||||
|
|
||||||
|
@ -327,6 +332,7 @@ struct WindowData {
|
||||||
SystemCompositionContextHelper::CreateVisual(root));
|
SystemCompositionContextHelper::CreateVisual(root));
|
||||||
m_compRootView.ScaleFactor(ScaleFactor(hwnd));
|
m_compRootView.ScaleFactor(ScaleFactor(hwnd));
|
||||||
winrt::Microsoft::ReactNative::LayoutConstraints contraints;
|
winrt::Microsoft::ReactNative::LayoutConstraints contraints;
|
||||||
|
contraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
||||||
contraints.MaximumSize =
|
contraints.MaximumSize =
|
||||||
contraints.MinimumSize = {m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
|
contraints.MinimumSize = {m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
|
||||||
m_compRootView.Arrange(contraints, {0, 0});
|
m_compRootView.Arrange(contraints, {0, 0});
|
||||||
|
@ -371,8 +377,10 @@ struct WindowData {
|
||||||
OutputDebugStringA("Instance Unload completed\n");
|
OutputDebugStringA("Instance Unload completed\n");
|
||||||
|
|
||||||
uidispatch.Post([&]() {
|
uidispatch.Post([&]() {
|
||||||
m_bridge.Close();
|
if (m_bridge) {
|
||||||
m_bridge = nullptr;
|
m_bridge.Close();
|
||||||
|
m_bridge = nullptr;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
assert(asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed);
|
assert(asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed);
|
||||||
});
|
});
|
||||||
|
@ -380,6 +388,14 @@ struct WindowData {
|
||||||
m_instanceSettings = nullptr;
|
m_instanceSettings = nullptr;
|
||||||
m_host = nullptr;
|
m_host = nullptr;
|
||||||
} break;
|
} break;
|
||||||
|
case IDM_TOGGLE_LAYOUT_DIRECTION: {
|
||||||
|
if (m_bridge) {
|
||||||
|
m_bridge.LayoutDirectionOverride(
|
||||||
|
(m_forceRTL) ? winrt::Microsoft::UI::Content::ContentLayoutDirection::LeftToRight
|
||||||
|
: winrt::Microsoft::UI::Content::ContentLayoutDirection::RightToLeft);
|
||||||
|
}
|
||||||
|
m_forceRTL = !m_forceRTL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -400,7 +416,7 @@ struct WindowData {
|
||||||
winrt::Windows::Foundation::Size size{m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
|
winrt::Windows::Foundation::Size size{m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
|
||||||
if (!IsIconic(hwnd)) {
|
if (!IsIconic(hwnd)) {
|
||||||
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
||||||
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight;
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
||||||
constraints.MinimumSize = constraints.MaximumSize = size;
|
constraints.MinimumSize = constraints.MaximumSize = size;
|
||||||
if (m_sizeToContent) {
|
if (m_sizeToContent) {
|
||||||
ApplyConstraintsForContentSizedWindow(constraints);
|
ApplyConstraintsForContentSizedWindow(constraints);
|
||||||
|
|
|
@ -58,6 +58,7 @@ BEGIN
|
||||||
MENUITEM "&New Window\tCtrl+N", IDM_NEWWINDOW
|
MENUITEM "&New Window\tCtrl+N", IDM_NEWWINDOW
|
||||||
MENUITEM "&Refresh\tF5", IDM_REFRESH
|
MENUITEM "&Refresh\tF5", IDM_REFRESH
|
||||||
MENUITEM "&Unload", IDM_UNLOAD
|
MENUITEM "&Unload", IDM_UNLOAD
|
||||||
|
MENUITEM "Toggle Layout &Direction", IDM_TOGGLE_LAYOUT_DIRECTION
|
||||||
MENUITEM SEPARATOR
|
MENUITEM SEPARATOR
|
||||||
MENUITEM "&Settings...\tAlt+S", IDM_SETTINGS
|
MENUITEM "&Settings...\tAlt+S", IDM_SETTINGS
|
||||||
MENUITEM SEPARATOR
|
MENUITEM SEPARATOR
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#define IDC_JSENGINELABEL 111
|
#define IDC_JSENGINELABEL 111
|
||||||
#define IDC_SIZETOCONTENT 112
|
#define IDC_SIZETOCONTENT 112
|
||||||
#define IDM_UNLOAD 113
|
#define IDM_UNLOAD 113
|
||||||
|
#define IDM_TOGGLE_LAYOUT_DIRECTION 114
|
||||||
#define IDI_ICON1 1008
|
#define IDI_ICON1 1008
|
||||||
|
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
|
|
|
@ -262,8 +262,8 @@ void ComponentView::HandleCommand(const winrt::Microsoft::ReactNative::HandleCom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *
|
winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *ComponentView::rootComponentView()
|
||||||
ComponentView::rootComponentView() noexcept {
|
const noexcept {
|
||||||
if (m_rootView)
|
if (m_rootView)
|
||||||
return m_rootView;
|
return m_rootView;
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,8 @@ struct ComponentView : public ComponentViewT<ComponentView> {
|
||||||
facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept;
|
facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept;
|
||||||
virtual void prepareForRecycle() noexcept;
|
virtual void prepareForRecycle() noexcept;
|
||||||
virtual facebook::react::Props::Shared props() noexcept;
|
virtual facebook::react::Props::Shared props() noexcept;
|
||||||
virtual winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *rootComponentView() noexcept;
|
virtual winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *rootComponentView()
|
||||||
|
const noexcept;
|
||||||
virtual void parent(const winrt::Microsoft::ReactNative::ComponentView &parent) noexcept;
|
virtual void parent(const winrt::Microsoft::ReactNative::ComponentView &parent) noexcept;
|
||||||
virtual winrt::Microsoft::ReactNative::ComponentView Parent() const noexcept;
|
virtual winrt::Microsoft::ReactNative::ComponentView Parent() const noexcept;
|
||||||
virtual winrt::IVectorView<winrt::Microsoft::ReactNative::ComponentView> Children() const noexcept;
|
virtual winrt::IVectorView<winrt::Microsoft::ReactNative::ComponentView> Children() const noexcept;
|
||||||
|
@ -253,7 +254,7 @@ struct ComponentView : public ComponentViewT<ComponentView> {
|
||||||
bool m_mounted : 1 {false};
|
bool m_mounted : 1 {false};
|
||||||
const facebook::react::Tag m_tag;
|
const facebook::react::Tag m_tag;
|
||||||
winrt::IInspectable m_userData;
|
winrt::IInspectable m_userData;
|
||||||
winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *m_rootView{nullptr};
|
mutable winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *m_rootView{nullptr};
|
||||||
mutable winrt::Microsoft::ReactNative::Composition::implementation::Theme *m_theme{nullptr};
|
mutable winrt::Microsoft::ReactNative::Composition::implementation::Theme *m_theme{nullptr};
|
||||||
const winrt::Microsoft::ReactNative::ReactContext m_reactContext;
|
const winrt::Microsoft::ReactNative::ReactContext m_reactContext;
|
||||||
winrt::Microsoft::ReactNative::ComponentView m_parent{nullptr};
|
winrt::Microsoft::ReactNative::ComponentView m_parent{nullptr};
|
||||||
|
|
|
@ -102,6 +102,7 @@ void CompositionHwndHost::UpdateSize() noexcept {
|
||||||
// Do not relayout when minimized
|
// Do not relayout when minimized
|
||||||
if (!IsIconic(m_hwnd)) {
|
if (!IsIconic(m_hwnd)) {
|
||||||
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
||||||
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
||||||
constraints.MinimumSize = constraints.MaximumSize = size;
|
constraints.MinimumSize = constraints.MaximumSize = size;
|
||||||
m_compRootView.Arrange(constraints, {0, 0});
|
m_compRootView.Arrange(constraints, {0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,21 +98,36 @@ void CompositionReactViewInstance::UninitRootView() noexcept {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyConstraints(
|
void ReactNativeIsland::ApplyConstraints(
|
||||||
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn,
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn,
|
||||||
facebook::react::LayoutConstraints &layoutConstraintsOut) noexcept {
|
facebook::react::LayoutConstraints &layoutConstraintsOut) const noexcept {
|
||||||
layoutConstraintsOut.minimumSize = {layoutConstraintsIn.MinimumSize.Width, layoutConstraintsIn.MinimumSize.Height};
|
layoutConstraintsOut.minimumSize = {layoutConstraintsIn.MinimumSize.Width, layoutConstraintsIn.MinimumSize.Height};
|
||||||
layoutConstraintsOut.maximumSize = {layoutConstraintsIn.MaximumSize.Width, layoutConstraintsIn.MaximumSize.Height};
|
layoutConstraintsOut.maximumSize = {layoutConstraintsIn.MaximumSize.Width, layoutConstraintsIn.MaximumSize.Height};
|
||||||
layoutConstraintsOut.layoutDirection =
|
if (layoutConstraintsIn.LayoutDirection == winrt::Microsoft::ReactNative::LayoutDirection::Undefined) {
|
||||||
static_cast<facebook::react::LayoutDirection>(layoutConstraintsIn.LayoutDirection);
|
if (m_island) {
|
||||||
|
layoutConstraintsOut.layoutDirection =
|
||||||
|
(m_island.LayoutDirection() == winrt::Microsoft::UI::Content::ContentLayoutDirection::LeftToRight)
|
||||||
|
? facebook::react::LayoutDirection::LeftToRight
|
||||||
|
: facebook::react::LayoutDirection::RightToLeft;
|
||||||
|
} else if (m_hwnd) {
|
||||||
|
auto styles = GetWindowLongPtrW(m_hwnd, GWL_EXSTYLE);
|
||||||
|
layoutConstraintsOut.layoutDirection = ((styles & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL)
|
||||||
|
? facebook::react::LayoutDirection::RightToLeft
|
||||||
|
: facebook::react::LayoutDirection::LeftToRight;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
layoutConstraintsOut.layoutDirection =
|
||||||
|
static_cast<facebook::react::LayoutDirection>(layoutConstraintsIn.LayoutDirection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactNativeIsland::ReactNativeIsland() noexcept {}
|
|
||||||
|
|
||||||
#ifdef USE_WINUI3
|
|
||||||
ReactNativeIsland::ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept
|
ReactNativeIsland::ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept
|
||||||
: m_compositor(compositor) {}
|
: m_compositor(compositor),
|
||||||
#endif
|
m_layoutConstraints({{0, 0}, {0, 0}, winrt::Microsoft::ReactNative::LayoutDirection::Undefined}) {
|
||||||
|
InitTextScaleMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactNativeIsland::ReactNativeIsland() noexcept : ReactNativeIsland(nullptr) {}
|
||||||
|
|
||||||
ReactNativeIsland::~ReactNativeIsland() noexcept {
|
ReactNativeIsland::~ReactNativeIsland() noexcept {
|
||||||
#ifdef USE_WINUI3
|
#ifdef USE_WINUI3
|
||||||
|
@ -248,6 +263,10 @@ void ReactNativeIsland::ScaleFactor(float value) noexcept {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float ReactNativeIsland::FontSizeMultiplier() const noexcept {
|
||||||
|
return m_textScaleMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t ReactNativeIsland::RootTag() const noexcept {
|
int64_t ReactNativeIsland::RootTag() const noexcept {
|
||||||
return m_rootTag;
|
return m_rootTag;
|
||||||
}
|
}
|
||||||
|
@ -431,10 +450,9 @@ void ReactNativeIsland::UninitRootView() noexcept {
|
||||||
uiManager->stopSurface(static_cast<facebook::react::SurfaceId>(RootTag()));
|
uiManager->stopSurface(static_cast<facebook::react::SurfaceId>(RootTag()));
|
||||||
|
|
||||||
// This is needed to ensure that the unmount JS logic is completed before the the instance is shutdown during
|
// This is needed to ensure that the unmount JS logic is completed before the the instance is shutdown during
|
||||||
// instance destruction. Aligns with similar code in ReactInstanceWin::DetachRootView for paper Future: Instead this
|
// instance destruction. Aligns with similar code in ReactInstanceWin::DetachRootView for paper Future: Instead
|
||||||
// method should return a Promise, which should be resolved when the JS logic is complete.
|
// this method should return a Promise, which should be resolved when the JS logic is complete. The task will auto
|
||||||
// The task will auto set the event on destruction to ensure that the event is set if the JS Queue has already been
|
// set the event on destruction to ensure that the event is set if the JS Queue has already been shutdown
|
||||||
// shutdown
|
|
||||||
Mso::ManualResetEvent mre;
|
Mso::ManualResetEvent mre;
|
||||||
m_context.JSDispatcher().Post([autoMRE = std::make_unique<AutoMRE>(AutoMRE{mre})]() {});
|
m_context.JSDispatcher().Post([autoMRE = std::make_unique<AutoMRE>(AutoMRE{mre})]() {});
|
||||||
mre.Wait();
|
mre.Wait();
|
||||||
|
@ -499,9 +517,8 @@ facebook::react::AttributedStringBox CreateLoadingAttributedString() noexcept {
|
||||||
return facebook::react::AttributedStringBox{attributedString};
|
return facebook::react::AttributedStringBox{attributedString};
|
||||||
}
|
}
|
||||||
|
|
||||||
facebook::react::Size MeasureLoading(
|
facebook::react::Size ReactNativeIsland::MeasureLoading(
|
||||||
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints) const noexcept {
|
||||||
float scaleFactor) {
|
|
||||||
facebook::react::LayoutConstraints fbLayoutConstraints;
|
facebook::react::LayoutConstraints fbLayoutConstraints;
|
||||||
ApplyConstraints(layoutConstraints, fbLayoutConstraints);
|
ApplyConstraints(layoutConstraints, fbLayoutConstraints);
|
||||||
|
|
||||||
|
@ -514,7 +531,7 @@ facebook::react::Size MeasureLoading(
|
||||||
winrt::check_hresult(textLayout->GetMetrics(&tm));
|
winrt::check_hresult(textLayout->GetMetrics(&tm));
|
||||||
|
|
||||||
return fbLayoutConstraints.clamp(
|
return fbLayoutConstraints.clamp(
|
||||||
{loadingActivityHorizontalOffset * scaleFactor + tm.width, loadingBarHeight * scaleFactor});
|
{loadingActivityHorizontalOffset * m_scaleFactor + tm.width, loadingBarHeight * m_scaleFactor});
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt::event_token ReactNativeIsland::SizeChanged(
|
winrt::event_token ReactNativeIsland::SizeChanged(
|
||||||
|
@ -544,7 +561,7 @@ void ReactNativeIsland::NotifySizeChanged() noexcept {
|
||||||
if (rootComponentView) {
|
if (rootComponentView) {
|
||||||
size = rootComponentView->layoutMetrics().frame.size;
|
size = rootComponentView->layoutMetrics().frame.size;
|
||||||
} else if (m_loadingVisual) {
|
} else if (m_loadingVisual) {
|
||||||
size = MeasureLoading(m_layoutConstraints, m_scaleFactor);
|
size = MeasureLoading(m_layoutConstraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_size = {size.width, size.height};
|
m_size = {size.width, size.height};
|
||||||
|
@ -638,11 +655,34 @@ void ReactNativeIsland::ShowInstanceLoading() noexcept {
|
||||||
InternalRootVisual().InsertAt(m_loadingVisual, m_hasRenderedVisual ? 1 : 0);
|
InternalRootVisual().InsertAt(m_loadingVisual, m_hasRenderedVisual ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReactNativeIsland::InitTextScaleMultiplier() noexcept {
|
||||||
|
m_uiSettings = winrt::Windows::UI::ViewManagement::UISettings();
|
||||||
|
m_textScaleMultiplier = static_cast<float>(m_uiSettings.TextScaleFactor());
|
||||||
|
m_textScaleChangedRevoker = m_uiSettings.TextScaleFactorChanged(
|
||||||
|
winrt::auto_revoke,
|
||||||
|
[this](const winrt::Windows::UI::ViewManagement::UISettings &uiSettings, const winrt::IInspectable &) {
|
||||||
|
if (m_context) {
|
||||||
|
m_context.UIDispatcher().Post(
|
||||||
|
[wkThis = get_weak(), textScaleMultiplier = static_cast<float>(uiSettings.TextScaleFactor())]() {
|
||||||
|
if (auto strongThis = wkThis.get()) {
|
||||||
|
strongThis->m_textScaleMultiplier = textScaleMultiplier;
|
||||||
|
strongThis->Arrange(strongThis->m_layoutConstraints, strongThis->m_viewportOffset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
|
winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
|
||||||
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
||||||
const winrt::Windows::Foundation::Point &viewportOffset) const noexcept {
|
const winrt::Windows::Foundation::Point &viewportOffset) const {
|
||||||
facebook::react::Size size{0, 0};
|
facebook::react::Size size{0, 0};
|
||||||
|
|
||||||
|
if (layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight &&
|
||||||
|
layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::RightToLeft &&
|
||||||
|
layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::Undefined)
|
||||||
|
winrt::throw_hresult(E_INVALIDARG);
|
||||||
|
|
||||||
facebook::react::LayoutConstraints constraints;
|
facebook::react::LayoutConstraints constraints;
|
||||||
ApplyConstraints(layoutConstraints, constraints);
|
ApplyConstraints(layoutConstraints, constraints);
|
||||||
|
|
||||||
|
@ -650,15 +690,14 @@ winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
|
||||||
if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
|
if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
|
||||||
winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()))) {
|
winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()))) {
|
||||||
facebook::react::LayoutContext context;
|
facebook::react::LayoutContext context;
|
||||||
// TODO scaling factor
|
context.fontSizeMultiplier = m_textScaleMultiplier;
|
||||||
context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
|
context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
|
||||||
context.fontSizeMultiplier = static_cast<facebook::react::Float>(m_scaleFactor);
|
|
||||||
context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
|
context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
|
||||||
|
|
||||||
size = fabricuiManager->measureSurface(static_cast<facebook::react::SurfaceId>(m_rootTag), constraints, context);
|
size = fabricuiManager->measureSurface(static_cast<facebook::react::SurfaceId>(m_rootTag), constraints, context);
|
||||||
}
|
}
|
||||||
} else if (m_loadingVisual) {
|
} else if (m_loadingVisual) {
|
||||||
size = MeasureLoading(layoutConstraints, m_scaleFactor);
|
size = MeasureLoading(layoutConstraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clampedSize = constraints.clamp(size);
|
auto clampedSize = constraints.clamp(size);
|
||||||
|
@ -667,7 +706,12 @@ winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
|
||||||
|
|
||||||
void ReactNativeIsland::Arrange(
|
void ReactNativeIsland::Arrange(
|
||||||
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
||||||
const winrt::Windows::Foundation::Point &viewportOffset) noexcept {
|
const winrt::Windows::Foundation::Point &viewportOffset) {
|
||||||
|
if (layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight &&
|
||||||
|
layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::RightToLeft &&
|
||||||
|
layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::Undefined)
|
||||||
|
winrt::throw_hresult(E_INVALIDARG);
|
||||||
|
|
||||||
m_layoutConstraints = layoutConstraints;
|
m_layoutConstraints = layoutConstraints;
|
||||||
m_viewportOffset = viewportOffset;
|
m_viewportOffset = viewportOffset;
|
||||||
facebook::react::LayoutConstraints fbLayoutConstraints;
|
facebook::react::LayoutConstraints fbLayoutConstraints;
|
||||||
|
@ -677,8 +721,8 @@ void ReactNativeIsland::Arrange(
|
||||||
if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
|
if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
|
||||||
winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()))) {
|
winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()))) {
|
||||||
facebook::react::LayoutContext context;
|
facebook::react::LayoutContext context;
|
||||||
|
context.fontSizeMultiplier = m_textScaleMultiplier;
|
||||||
context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
|
context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
|
||||||
context.fontSizeMultiplier = static_cast<facebook::react::Float>(m_scaleFactor);
|
|
||||||
context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
|
context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
|
||||||
|
|
||||||
fabricuiManager->constraintSurfaceLayout(
|
fabricuiManager->constraintSurfaceLayout(
|
||||||
|
@ -686,12 +730,11 @@ void ReactNativeIsland::Arrange(
|
||||||
}
|
}
|
||||||
} else if (m_loadingVisual) {
|
} else if (m_loadingVisual) {
|
||||||
// TODO: Resize to align loading
|
// TODO: Resize to align loading
|
||||||
auto s = fbLayoutConstraints.clamp(MeasureLoading(layoutConstraints, m_scaleFactor));
|
auto s = fbLayoutConstraints.clamp(MeasureLoading(layoutConstraints));
|
||||||
NotifySizeChanged();
|
NotifySizeChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_WINUI3
|
|
||||||
winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
|
winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
|
||||||
if (!m_compositor) {
|
if (!m_compositor) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -745,6 +788,9 @@ winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
|
||||||
if (args.DidRasterizationScaleChange()) {
|
if (args.DidRasterizationScaleChange()) {
|
||||||
pThis->ScaleFactor(island.RasterizationScale());
|
pThis->ScaleFactor(island.RasterizationScale());
|
||||||
}
|
}
|
||||||
|
if (args.DidLayoutDirectionChange()) {
|
||||||
|
pThis->Arrange(pThis->m_layoutConstraints, pThis->m_viewportOffset);
|
||||||
|
}
|
||||||
#ifndef USE_EXPERIMENTAL_WINUI3 // Use this in place of Connected/Disconnected events for now. -- Its not quite what we
|
#ifndef USE_EXPERIMENTAL_WINUI3 // Use this in place of Connected/Disconnected events for now. -- Its not quite what we
|
||||||
// want, but it will do for now.
|
// want, but it will do for now.
|
||||||
if (args.DidSiteVisibleChange()) {
|
if (args.DidSiteVisibleChange()) {
|
||||||
|
@ -777,7 +823,6 @@ winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
|
||||||
}
|
}
|
||||||
return m_island;
|
return m_island;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void ReactNativeIsland::OnMounted() noexcept {
|
void ReactNativeIsland::OnMounted() noexcept {
|
||||||
if (m_mounted)
|
if (m_mounted)
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <react/renderer/core/LayoutConstraints.h>
|
#include <react/renderer/core/LayoutConstraints.h>
|
||||||
#include <winrt/Microsoft.ReactNative.Composition.Experimental.h>
|
#include <winrt/Microsoft.ReactNative.Composition.Experimental.h>
|
||||||
#include <winrt/Microsoft.ReactNative.h>
|
#include <winrt/Microsoft.ReactNative.h>
|
||||||
|
#include <winrt/Windows.UI.ViewManagement.h>
|
||||||
#include "CompositionEventHandler.h"
|
#include "CompositionEventHandler.h"
|
||||||
#include "ReactHost/React.h"
|
#include "ReactHost/React.h"
|
||||||
|
|
||||||
|
@ -46,10 +47,8 @@ struct ReactNativeIsland
|
||||||
ReactNativeIsland() noexcept;
|
ReactNativeIsland() noexcept;
|
||||||
~ReactNativeIsland() noexcept;
|
~ReactNativeIsland() noexcept;
|
||||||
|
|
||||||
#ifdef USE_WINUI3
|
|
||||||
ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept;
|
ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept;
|
||||||
winrt::Microsoft::UI::Content::ContentIsland Island();
|
winrt::Microsoft::UI::Content::ContentIsland Island();
|
||||||
#endif
|
|
||||||
|
|
||||||
// property ReactViewHost
|
// property ReactViewHost
|
||||||
ReactNative::IReactViewHost ReactViewHost() noexcept;
|
ReactNative::IReactViewHost ReactViewHost() noexcept;
|
||||||
|
@ -72,6 +71,8 @@ struct ReactNativeIsland
|
||||||
float ScaleFactor() noexcept;
|
float ScaleFactor() noexcept;
|
||||||
void ScaleFactor(float value) noexcept;
|
void ScaleFactor(float value) noexcept;
|
||||||
|
|
||||||
|
float FontSizeMultiplier() const noexcept;
|
||||||
|
|
||||||
winrt::event_token SizeChanged(
|
winrt::event_token SizeChanged(
|
||||||
winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::RootViewSizeChangedEventArgs> const
|
winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::RootViewSizeChangedEventArgs> const
|
||||||
&handler) noexcept;
|
&handler) noexcept;
|
||||||
|
@ -90,10 +91,10 @@ struct ReactNativeIsland
|
||||||
|
|
||||||
winrt::Windows::Foundation::Size Measure(
|
winrt::Windows::Foundation::Size Measure(
|
||||||
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
||||||
const winrt::Windows::Foundation::Point &viewportOffset) const noexcept;
|
const winrt::Windows::Foundation::Point &viewportOffset) const;
|
||||||
void Arrange(
|
void Arrange(
|
||||||
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
|
||||||
const winrt::Windows::Foundation::Point &viewportOffset) noexcept;
|
const winrt::Windows::Foundation::Point &viewportOffset);
|
||||||
|
|
||||||
winrt::Microsoft::ReactNative::FocusNavigationResult NavigateFocus(
|
winrt::Microsoft::ReactNative::FocusNavigationResult NavigateFocus(
|
||||||
const winrt::Microsoft::ReactNative::FocusNavigationRequest &request) noexcept;
|
const winrt::Microsoft::ReactNative::FocusNavigationRequest &request) noexcept;
|
||||||
|
@ -143,6 +144,9 @@ struct ReactNativeIsland
|
||||||
winrt::IInspectable m_uiaProvider{nullptr};
|
winrt::IInspectable m_uiaProvider{nullptr};
|
||||||
int64_t m_rootTag{-1};
|
int64_t m_rootTag{-1};
|
||||||
float m_scaleFactor{1.0};
|
float m_scaleFactor{1.0};
|
||||||
|
float m_textScaleMultiplier{1.0};
|
||||||
|
winrt::Windows::UI::ViewManagement::UISettings::TextScaleFactorChanged_revoker m_textScaleChangedRevoker;
|
||||||
|
winrt::Windows::UI::ViewManagement::UISettings m_uiSettings{nullptr};
|
||||||
winrt::Windows::Foundation::Size m_size{0, 0};
|
winrt::Windows::Foundation::Size m_size{0, 0};
|
||||||
winrt::Microsoft::ReactNative::ReactContext m_context;
|
winrt::Microsoft::ReactNative::ReactContext m_context;
|
||||||
winrt::Microsoft::ReactNative::IReactViewHost m_reactViewHost;
|
winrt::Microsoft::ReactNative::IReactViewHost m_reactViewHost;
|
||||||
|
@ -168,6 +172,12 @@ struct ReactNativeIsland
|
||||||
void UpdateRootVisualSize() noexcept;
|
void UpdateRootVisualSize() noexcept;
|
||||||
void UpdateLoadingVisualSize() noexcept;
|
void UpdateLoadingVisualSize() noexcept;
|
||||||
Composition::Experimental::IDrawingSurfaceBrush CreateLoadingVisualBrush() noexcept;
|
Composition::Experimental::IDrawingSurfaceBrush CreateLoadingVisualBrush() noexcept;
|
||||||
|
void ApplyConstraints(
|
||||||
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn,
|
||||||
|
facebook::react::LayoutConstraints &layoutConstraintsOut) const noexcept;
|
||||||
|
facebook::react::Size MeasureLoading(
|
||||||
|
const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints) const noexcept;
|
||||||
|
void InitTextScaleMultiplier() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace winrt::Microsoft::ReactNative::implementation
|
} // namespace winrt::Microsoft::ReactNative::implementation
|
||||||
|
|
|
@ -40,8 +40,8 @@ winrt::Microsoft::ReactNative::ComponentView RootComponentView::Create(
|
||||||
return winrt::make<RootComponentView>(compContext, tag, reactContext);
|
return winrt::make<RootComponentView>(compContext, tag, reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
RootComponentView *RootComponentView::rootComponentView() noexcept {
|
RootComponentView *RootComponentView::rootComponentView() const noexcept {
|
||||||
return this;
|
return const_cast<RootComponentView *>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootComponentView::updateLayoutMetrics(
|
void RootComponentView::updateLayoutMetrics(
|
||||||
|
@ -211,6 +211,15 @@ winrt::IInspectable RootComponentView::UiaProviderFromPoint(const POINT &ptPixel
|
||||||
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(view)->EnsureUiaProvider();
|
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(view)->EnsureUiaProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float RootComponentView::FontSizeMultiplier() const noexcept {
|
||||||
|
if (auto rootView = m_wkRootView.get()) {
|
||||||
|
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)
|
||||||
|
->FontSizeMultiplier();
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
winrt::Microsoft::UI::Content::ContentIsland RootComponentView::parentContentIsland() noexcept {
|
winrt::Microsoft::UI::Content::ContentIsland RootComponentView::parentContentIsland() noexcept {
|
||||||
if (auto rootView = m_wkRootView.get()) {
|
if (auto rootView = m_wkRootView.get()) {
|
||||||
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)->Island();
|
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)->Island();
|
||||||
|
|
|
@ -36,7 +36,7 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
|
||||||
|
|
||||||
bool TryMoveFocus(bool next) noexcept;
|
bool TryMoveFocus(bool next) noexcept;
|
||||||
|
|
||||||
RootComponentView *rootComponentView() noexcept override;
|
RootComponentView *rootComponentView() const noexcept override;
|
||||||
|
|
||||||
winrt::Microsoft::UI::Content::ContentIsland parentContentIsland() noexcept;
|
winrt::Microsoft::UI::Content::ContentIsland parentContentIsland() noexcept;
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
|
||||||
|
|
||||||
HRESULT GetFragmentRoot(IRawElementProviderFragmentRoot **pRetVal) noexcept;
|
HRESULT GetFragmentRoot(IRawElementProviderFragmentRoot **pRetVal) noexcept;
|
||||||
winrt::Microsoft::ReactNative::implementation::ClipState getClipState() noexcept override;
|
winrt::Microsoft::ReactNative::implementation::ClipState getClipState() noexcept override;
|
||||||
|
float FontSizeMultiplier() const noexcept;
|
||||||
|
|
||||||
void updateLayoutMetrics(
|
void updateLayoutMetrics(
|
||||||
facebook::react::LayoutMetrics const &layoutMetrics,
|
facebook::react::LayoutMetrics const &layoutMetrics,
|
||||||
|
|
|
@ -176,9 +176,8 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_outer->m_caretVisual.Position(
|
auto pt = m_outer->getClientOffset();
|
||||||
{x - (m_outer->m_layoutMetrics.frame.origin.x * m_outer->m_layoutMetrics.pointScaleFactor),
|
m_outer->m_caretVisual.Position({x - pt.x, y - pt.y});
|
||||||
y - (m_outer->m_layoutMetrics.frame.origin.y * m_outer->m_layoutMetrics.pointScaleFactor)});
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +261,7 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
|
||||||
|
|
||||||
//@cmember Retrieves the coordinates of a window's client area
|
//@cmember Retrieves the coordinates of a window's client area
|
||||||
HRESULT TxGetClientRect(LPRECT prc) override {
|
HRESULT TxGetClientRect(LPRECT prc) override {
|
||||||
*prc = m_outer->m_rcClient;
|
*prc = m_outer->getClientRect();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,6 +454,7 @@ facebook::react::AttributedString WindowsTextInputComponentView::getAttributedSt
|
||||||
// Use BaseTextShadowNode to get attributed string from children
|
// Use BaseTextShadowNode to get attributed string from children
|
||||||
|
|
||||||
auto childTextAttributes = facebook::react::TextAttributes::defaultTextAttributes();
|
auto childTextAttributes = facebook::react::TextAttributes::defaultTextAttributes();
|
||||||
|
childTextAttributes.fontSizeMultiplier = m_fontSizeMultiplier;
|
||||||
|
|
||||||
childTextAttributes.apply(windowsTextInputProps().textAttributes);
|
childTextAttributes.apply(windowsTextInputProps().textAttributes);
|
||||||
|
|
||||||
|
@ -464,9 +464,9 @@ facebook::react::AttributedString WindowsTextInputComponentView::getAttributedSt
|
||||||
// BaseTextShadowNode only gets children. We must detect and prepend text
|
// BaseTextShadowNode only gets children. We must detect and prepend text
|
||||||
// value attributes manually.
|
// value attributes manually.
|
||||||
auto text = GetTextFromRichEdit();
|
auto text = GetTextFromRichEdit();
|
||||||
// if (!m_props->text.empty()) {
|
|
||||||
if (!text.empty()) {
|
if (!text.empty()) {
|
||||||
auto textAttributes = facebook::react::TextAttributes::defaultTextAttributes();
|
auto textAttributes = facebook::react::TextAttributes::defaultTextAttributes();
|
||||||
|
textAttributes.fontSizeMultiplier = m_fontSizeMultiplier;
|
||||||
textAttributes.apply(windowsTextInputProps().textAttributes);
|
textAttributes.apply(windowsTextInputProps().textAttributes);
|
||||||
auto fragment = facebook::react::AttributedString::Fragment{};
|
auto fragment = facebook::react::AttributedString::Fragment{};
|
||||||
fragment.string = text;
|
fragment.string = text;
|
||||||
|
@ -492,35 +492,7 @@ WindowsTextInputComponentView::WindowsTextInputComponentView(
|
||||||
compContext,
|
compContext,
|
||||||
tag,
|
tag,
|
||||||
reactContext,
|
reactContext,
|
||||||
ComponentViewFeatures::Default & ~ComponentViewFeatures::Background) {
|
ComponentViewFeatures::Default & ~ComponentViewFeatures::Background) {}
|
||||||
/*
|
|
||||||
m_textChangedRevoker =
|
|
||||||
m_element.TextChanged(winrt::auto_revoke, [this](auto sender, xaml::Controls::TextChangedEventArgs args) {
|
|
||||||
auto data = m_state->getData();
|
|
||||||
data.attributedString = getAttributedString();
|
|
||||||
data.mostRecentEventCount = m_nativeEventCount;
|
|
||||||
m_state->updateState(std::move(data));
|
|
||||||
|
|
||||||
if (m_eventEmitter && !m_comingFromJS) {
|
|
||||||
auto emitter = std::static_pointer_cast<const facebook::react::WindowsTextInputEventEmitter>(m_eventEmitter);
|
|
||||||
facebook::react::WindowsTextInputEventEmitter::OnChange onChangeArgs;
|
|
||||||
onChangeArgs.text = winrt::to_string(m_element.Text());
|
|
||||||
onChangeArgs.eventCount = ++m_nativeEventCount;
|
|
||||||
emitter->onChange(onChangeArgs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m_SelectionChangedRevoker = m_element.SelectionChanged(winrt::auto_revoke, [this](auto sender, auto args) {
|
|
||||||
if (m_eventEmitter) {
|
|
||||||
auto emitter = std::static_pointer_cast<const facebook::react::WindowsTextInputEventEmitter>(m_eventEmitter);
|
|
||||||
facebook::react::WindowsTextInputEventEmitter::OnSelectionChange onSelectionChangeArgs;
|
|
||||||
onSelectionChangeArgs.selection.start = m_element.SelectionStart();
|
|
||||||
onSelectionChangeArgs.selection.end = m_element.SelectionStart() + m_element.SelectionLength();
|
|
||||||
emitter->onSelectionChange(onSelectionChangeArgs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowsTextInputComponentView::HandleCommand(
|
void WindowsTextInputComponentView::HandleCommand(
|
||||||
const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept {
|
const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept {
|
||||||
|
@ -531,26 +503,27 @@ void WindowsTextInputComponentView::HandleCommand(
|
||||||
auto commandName = args.CommandName();
|
auto commandName = args.CommandName();
|
||||||
if (commandName == L"setTextAndSelection") {
|
if (commandName == L"setTextAndSelection") {
|
||||||
int eventCount, begin, end;
|
int eventCount, begin, end;
|
||||||
winrt::hstring text;
|
std::optional<winrt::hstring> text;
|
||||||
|
|
||||||
winrt::Microsoft::ReactNative::ReadArgs(args.CommandArgs(), eventCount, text, begin, end);
|
winrt::Microsoft::ReactNative::ReadArgs(args.CommandArgs(), eventCount, text, begin, end);
|
||||||
if (eventCount >= m_nativeEventCount) {
|
if (eventCount >= m_nativeEventCount) {
|
||||||
m_comingFromJS = true;
|
m_comingFromJS = true;
|
||||||
UpdateText(winrt::to_string(text));
|
{
|
||||||
|
if (text.has_value()) {
|
||||||
|
DrawBlock db(*this);
|
||||||
|
UpdateText(winrt::to_string(text.value()));
|
||||||
|
}
|
||||||
|
|
||||||
SELCHANGE sc;
|
SELCHANGE sc;
|
||||||
memset(&sc, 0, sizeof(sc));
|
memset(&sc, 0, sizeof(sc));
|
||||||
sc.chrg.cpMin = static_cast<LONG>(begin);
|
sc.chrg.cpMin = static_cast<LONG>(begin);
|
||||||
sc.chrg.cpMax = static_cast<LONG>(end);
|
sc.chrg.cpMax = static_cast<LONG>(end);
|
||||||
sc.seltyp = (begin == end) ? SEL_EMPTY : SEL_TEXT;
|
sc.seltyp = (begin == end) ? SEL_EMPTY : SEL_TEXT;
|
||||||
|
|
||||||
LRESULT res;
|
LRESULT res;
|
||||||
/*
|
winrt::check_hresult(
|
||||||
winrt::check_hresult(m_textServices->TxSendMessage(
|
m_textServices->TxSendMessage(EM_SETSEL, static_cast<WPARAM>(begin), static_cast<LPARAM>(end), &res));
|
||||||
EM_SELCHANGE, 0 , reinterpret_cast<WPARAM>(&sc), &res));
|
}
|
||||||
*/
|
|
||||||
winrt::check_hresult(
|
|
||||||
m_textServices->TxSendMessage(EM_SETSEL, static_cast<WPARAM>(begin), static_cast<LPARAM>(end), &res));
|
|
||||||
|
|
||||||
m_comingFromJS = false;
|
m_comingFromJS = false;
|
||||||
}
|
}
|
||||||
|
@ -989,37 +962,35 @@ void WindowsTextInputComponentView::updateProps(
|
||||||
*std::static_pointer_cast<const facebook::react::WindowsTextInputProps>(oldProps ? oldProps : viewProps());
|
*std::static_pointer_cast<const facebook::react::WindowsTextInputProps>(oldProps ? oldProps : viewProps());
|
||||||
const auto &newTextInputProps = *std::static_pointer_cast<const facebook::react::WindowsTextInputProps>(props);
|
const auto &newTextInputProps = *std::static_pointer_cast<const facebook::react::WindowsTextInputProps>(props);
|
||||||
|
|
||||||
DWORD propBitsMask = 0;
|
|
||||||
DWORD propBits = 0;
|
|
||||||
|
|
||||||
Super::updateProps(props, oldProps);
|
Super::updateProps(props, oldProps);
|
||||||
|
|
||||||
if (!facebook::react::floatEquality(
|
if (!facebook::react::floatEquality(
|
||||||
oldTextInputProps.textAttributes.fontSize, newTextInputProps.textAttributes.fontSize) ||
|
oldTextInputProps.textAttributes.fontSize, newTextInputProps.textAttributes.fontSize) ||
|
||||||
|
(oldTextInputProps.textAttributes.allowFontScaling != newTextInputProps.textAttributes.allowFontScaling) ||
|
||||||
oldTextInputProps.textAttributes.fontWeight != newTextInputProps.textAttributes.fontWeight) {
|
oldTextInputProps.textAttributes.fontWeight != newTextInputProps.textAttributes.fontWeight) {
|
||||||
propBitsMask |= TXTBIT_CHARFORMATCHANGE;
|
m_propBitsMask |= TXTBIT_CHARFORMATCHANGE;
|
||||||
propBits |= TXTBIT_CHARFORMATCHANGE;
|
m_propBits |= TXTBIT_CHARFORMATCHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldTextInputProps.secureTextEntry != newTextInputProps.secureTextEntry) {
|
if (oldTextInputProps.secureTextEntry != newTextInputProps.secureTextEntry) {
|
||||||
propBitsMask |= TXTBIT_USEPASSWORD;
|
m_propBitsMask |= TXTBIT_USEPASSWORD;
|
||||||
if (newTextInputProps.secureTextEntry) {
|
if (newTextInputProps.secureTextEntry) {
|
||||||
propBits |= TXTBIT_USEPASSWORD;
|
m_propBits |= TXTBIT_USEPASSWORD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldTextInputProps.multiline != newTextInputProps.multiline) {
|
if (oldTextInputProps.multiline != newTextInputProps.multiline) {
|
||||||
m_multiline = newTextInputProps.multiline;
|
m_multiline = newTextInputProps.multiline;
|
||||||
propBitsMask |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
|
m_propBitsMask |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
|
||||||
if (newTextInputProps.multiline) {
|
if (newTextInputProps.multiline) {
|
||||||
propBits |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
|
m_propBits |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldTextInputProps.editable != newTextInputProps.editable) {
|
if (oldTextInputProps.editable != newTextInputProps.editable) {
|
||||||
propBitsMask |= TXTBIT_READONLY;
|
m_propBitsMask |= TXTBIT_READONLY;
|
||||||
if (!newTextInputProps.editable) {
|
if (!newTextInputProps.editable) {
|
||||||
propBits |= TXTBIT_READONLY;
|
m_propBits |= TXTBIT_READONLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,62 +1022,7 @@ void WindowsTextInputComponentView::updateProps(
|
||||||
m_submitKeyEvents.clear();
|
m_submitKeyEvents.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
UpdatePropertyBits();
|
||||||
if (oldTextInputProps.textAttributes.foregroundColor != newTextInputProps.textAttributes.foregroundColor) {
|
|
||||||
if (newTextInputProps.textAttributes.foregroundColor)
|
|
||||||
m_element.Foreground(newTextInputProps.textAttributes.foregroundColor.AsWindowsBrush());
|
|
||||||
else
|
|
||||||
m_element.ClearValue(::xaml::Controls::TextBlock::ForegroundProperty());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldTextInputProps.textAttributes.fontStyle != newTextInputProps.textAttributes.fontStyle) {
|
|
||||||
switch (newTextInputProps.textAttributes.fontStyle.value_or(facebook::react::FontStyle::Normal)) {
|
|
||||||
case facebook::react::FontStyle::Italic:
|
|
||||||
m_element.FontStyle(winrt::Windows::UI::Text::FontStyle::Italic);
|
|
||||||
break;
|
|
||||||
case facebook::react::FontStyle::Normal:
|
|
||||||
m_element.FontStyle(winrt::Windows::UI::Text::FontStyle::Normal);
|
|
||||||
break;
|
|
||||||
case facebook::react::FontStyle::Oblique:
|
|
||||||
m_element.FontStyle(winrt::Windows::UI::Text::FontStyle::Oblique);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldTextInputProps.textAttributes.fontFamily != newTextInputProps.textAttributes.fontFamily) {
|
|
||||||
if (newTextInputProps.textAttributes.fontFamily.empty())
|
|
||||||
m_element.FontFamily(xaml::Media::FontFamily(L"Segoe UI"));
|
|
||||||
else
|
|
||||||
m_element.FontFamily(xaml::Media::FontFamily(
|
|
||||||
Microsoft::Common::Unicode::Utf8ToUtf16(newTextInputProps.textAttributes.fontFamily)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldTextInputProps.allowFontScaling != newTextInputProps.allowFontScaling) {
|
|
||||||
m_element.IsTextScaleFactorEnabled(newTextInputProps.allowFontScaling);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldTextInputProps.selection.start != newTextInputProps.selection.start ||
|
|
||||||
oldTextInputProps.selection.end != newTextInputProps.selection.end) {
|
|
||||||
m_element.Select(
|
|
||||||
newTextInputProps.selection.start, newTextInputProps.selection.end - newTextInputProps.selection.start);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldTextInputProps.autoCapitalize != newTextInputProps.autoCapitalize) {
|
|
||||||
if (newTextInputProps.autoCapitalize == "characters") {
|
|
||||||
m_element.CharacterCasing(xaml::Controls::CharacterCasing::Upper);
|
|
||||||
} else { // anything else turns off autoCap (should be "None" but
|
|
||||||
// we don't support "words"/"sentences" yet)
|
|
||||||
m_element.CharacterCasing(xaml::Controls::CharacterCasing::Normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (propBitsMask != 0) {
|
|
||||||
DrawBlock db(*this);
|
|
||||||
winrt::check_hresult(m_textServices->OnTxPropertyBitsChange(propBitsMask, propBits));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowsTextInputComponentView::updateState(
|
void WindowsTextInputComponentView::updateState(
|
||||||
|
@ -1116,7 +1032,6 @@ void WindowsTextInputComponentView::updateState(
|
||||||
|
|
||||||
if (!m_state) {
|
if (!m_state) {
|
||||||
assert(false && "State is `null` for <TextInput> component.");
|
assert(false && "State is `null` for <TextInput> component.");
|
||||||
// m_element.Text(L"");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,14 +1039,19 @@ void WindowsTextInputComponentView::updateState(
|
||||||
m_mostRecentEventCount = m_state->getData().mostRecentEventCount;
|
m_mostRecentEventCount = m_state->getData().mostRecentEventCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto root = rootComponentView()) {
|
||||||
|
auto fontSizeMultiplier = root->FontSizeMultiplier();
|
||||||
|
if (fontSizeMultiplier != m_fontSizeMultiplier) {
|
||||||
|
fontSizeMultiplier = m_fontSizeMultiplier;
|
||||||
|
m_propBitsMask |= TXTBIT_CHARFORMATCHANGE;
|
||||||
|
m_propBits |= TXTBIT_CHARFORMATCHANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_mostRecentEventCount == m_state->getData().mostRecentEventCount) {
|
if (m_mostRecentEventCount == m_state->getData().mostRecentEventCount) {
|
||||||
m_comingFromState = true;
|
m_comingFromState = true;
|
||||||
// Only handle single/empty fragments right now -- ignore the other fragments
|
auto &fragments = m_state->getData().attributedString.getFragments();
|
||||||
|
UpdateText(fragments.size() ? fragments[0].string : "");
|
||||||
UpdateText(
|
|
||||||
m_state->getData().attributedString.getFragments().size()
|
|
||||||
? m_state->getData().attributedString.getFragments()[0].string
|
|
||||||
: "");
|
|
||||||
|
|
||||||
m_comingFromState = false;
|
m_comingFromState = false;
|
||||||
}
|
}
|
||||||
|
@ -1246,12 +1166,41 @@ std::string WindowsTextInputComponentView::GetTextFromRichEdit() const noexcept
|
||||||
void WindowsTextInputComponentView::FinalizeUpdates(
|
void WindowsTextInputComponentView::FinalizeUpdates(
|
||||||
winrt::Microsoft::ReactNative::ComponentViewUpdateMask updateMask) noexcept {
|
winrt::Microsoft::ReactNative::ComponentViewUpdateMask updateMask) noexcept {
|
||||||
Super::FinalizeUpdates(updateMask);
|
Super::FinalizeUpdates(updateMask);
|
||||||
ensureDrawingSurface();
|
InternalFinalize();
|
||||||
if (m_needsRedraw) {
|
}
|
||||||
DrawText();
|
|
||||||
|
void WindowsTextInputComponentView::UpdatePropertyBits() noexcept {
|
||||||
|
if (m_propBitsMask != 0) {
|
||||||
|
DrawBlock db(*this);
|
||||||
|
winrt::check_hresult(m_textServices->OnTxPropertyBitsChange(m_propBitsMask, m_propBits));
|
||||||
|
m_propBitsMask = 0;
|
||||||
|
m_propBits = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowsTextInputComponentView::InternalFinalize() noexcept {
|
||||||
|
if (m_mounted) {
|
||||||
|
UpdatePropertyBits();
|
||||||
|
|
||||||
|
ensureDrawingSurface();
|
||||||
|
if (m_needsRedraw) {
|
||||||
|
DrawText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsTextInputComponentView::onMounted() noexcept {
|
||||||
|
Super::onMounted();
|
||||||
|
|
||||||
|
auto fontSizeMultiplier = rootComponentView()->FontSizeMultiplier();
|
||||||
|
if (m_fontSizeMultiplier != fontSizeMultiplier) {
|
||||||
|
m_fontSizeMultiplier = fontSizeMultiplier;
|
||||||
|
m_propBitsMask |= TXTBIT_CHARFORMATCHANGE;
|
||||||
|
m_propBits |= TXTBIT_CHARFORMATCHANGE;
|
||||||
|
}
|
||||||
|
InternalFinalize();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::string> WindowsTextInputComponentView::getAccessiblityValue() noexcept {
|
std::optional<std::string> WindowsTextInputComponentView::getAccessiblityValue() noexcept {
|
||||||
return GetTextFromRichEdit();
|
return GetTextFromRichEdit();
|
||||||
}
|
}
|
||||||
|
@ -1294,9 +1243,9 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
|
||||||
|
|
||||||
// set font size -- 15 to convert twips to pt
|
// set font size -- 15 to convert twips to pt
|
||||||
const auto &props = windowsTextInputProps();
|
const auto &props = windowsTextInputProps();
|
||||||
float fontSize = props.textAttributes.fontSize;
|
float fontSize = m_fontSizeMultiplier *
|
||||||
if (std::isnan(fontSize))
|
(std::isnan(props.textAttributes.fontSize) ? facebook::react::TextAttributes::defaultTextAttributes().fontSize
|
||||||
fontSize = facebook::react::TextAttributes::defaultTextAttributes().fontSize;
|
: props.textAttributes.fontSize);
|
||||||
// TODO get fontSize from props.textAttributes, or defaultTextAttributes, or fragment?
|
// TODO get fontSize from props.textAttributes, or defaultTextAttributes, or fragment?
|
||||||
cfNew.dwMask |= CFM_SIZE;
|
cfNew.dwMask |= CFM_SIZE;
|
||||||
cfNew.yHeight = static_cast<LONG>(fontSize * 15);
|
cfNew.yHeight = static_cast<LONG>(fontSize * 15);
|
||||||
|
@ -1363,8 +1312,8 @@ void WindowsTextInputComponentView::ensureDrawingSurface() noexcept {
|
||||||
winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
||||||
winrt::Windows::Graphics::DirectX::DirectXAlphaMode::Premultiplied);
|
winrt::Windows::Graphics::DirectX::DirectXAlphaMode::Premultiplied);
|
||||||
|
|
||||||
m_rcClient = getClientRect();
|
auto rc = getClientRect();
|
||||||
winrt::check_hresult(m_textServices->OnTxInPlaceActivate(&m_rcClient));
|
winrt::check_hresult(m_textServices->OnTxInPlaceActivate(&rc));
|
||||||
|
|
||||||
LRESULT lresult;
|
LRESULT lresult;
|
||||||
winrt::check_hresult(
|
winrt::check_hresult(
|
||||||
|
@ -1394,6 +1343,7 @@ winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceho
|
||||||
if (std::isnan(props.textAttributes.fontSize)) {
|
if (std::isnan(props.textAttributes.fontSize)) {
|
||||||
textAttributes.fontSize = 12.0f;
|
textAttributes.fontSize = 12.0f;
|
||||||
}
|
}
|
||||||
|
textAttributes.fontSizeMultiplier = m_fontSizeMultiplier;
|
||||||
fragment1.string = props.placeholder;
|
fragment1.string = props.placeholder;
|
||||||
fragment1.textAttributes = textAttributes;
|
fragment1.textAttributes = textAttributes;
|
||||||
attributedString.appendFragment(fragment1);
|
attributedString.appendFragment(fragment1);
|
||||||
|
@ -1443,7 +1393,11 @@ void WindowsTextInputComponentView::DrawText() noexcept {
|
||||||
static_cast<LONG>(offset.x) + static_cast<LONG>(m_imgWidth),
|
static_cast<LONG>(offset.x) + static_cast<LONG>(m_imgWidth),
|
||||||
static_cast<LONG>(offset.y) + static_cast<LONG>(m_imgHeight)};
|
static_cast<LONG>(offset.y) + static_cast<LONG>(m_imgHeight)};
|
||||||
|
|
||||||
winrt::check_hresult(m_textServices->OnTxInPlaceActivate(&rcClient));
|
{
|
||||||
|
m_cDrawBlock++; // Dont use AutoDrawBlock as we are already in draw, and dont need to draw again.
|
||||||
|
winrt::check_hresult(m_textServices->OnTxInPlaceActivate(&rcClient));
|
||||||
|
m_cDrawBlock--;
|
||||||
|
}
|
||||||
|
|
||||||
const auto &props = windowsTextInputProps();
|
const auto &props = windowsTextInputProps();
|
||||||
if (facebook::react::isColorMeaningful(props.backgroundColor)) {
|
if (facebook::react::isColorMeaningful(props.backgroundColor)) {
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct WindowsTextInputComponentView
|
||||||
void OnKeyUp(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
|
void OnKeyUp(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
|
||||||
void OnCharacterReceived(const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs
|
void OnCharacterReceived(const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs
|
||||||
&args) noexcept override;
|
&args) noexcept override;
|
||||||
|
void onMounted() noexcept override;
|
||||||
|
|
||||||
std::optional<std::string> getAccessiblityValue() noexcept override;
|
std::optional<std::string> getAccessiblityValue() noexcept override;
|
||||||
void setAcccessiblityValue(std::string &&value) noexcept override;
|
void setAcccessiblityValue(std::string &&value) noexcept override;
|
||||||
|
@ -100,6 +101,8 @@ struct WindowsTextInputComponentView
|
||||||
const facebook::react::SharedColor &foregroundColor) noexcept;
|
const facebook::react::SharedColor &foregroundColor) noexcept;
|
||||||
bool ShouldSubmit(
|
bool ShouldSubmit(
|
||||||
const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept;
|
const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept;
|
||||||
|
void InternalFinalize() noexcept;
|
||||||
|
void UpdatePropertyBits() noexcept;
|
||||||
|
|
||||||
winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
|
winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
|
||||||
winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr};
|
winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr};
|
||||||
|
@ -113,7 +116,7 @@ struct WindowsTextInputComponentView
|
||||||
winrt::com_ptr<ITextServices2> m_textServices;
|
winrt::com_ptr<ITextServices2> m_textServices;
|
||||||
unsigned int m_imgWidth{0}, m_imgHeight{0};
|
unsigned int m_imgWidth{0}, m_imgHeight{0};
|
||||||
std::shared_ptr<facebook::react::WindowsTextInputShadowNode::ConcreteState const> m_state;
|
std::shared_ptr<facebook::react::WindowsTextInputShadowNode::ConcreteState const> m_state;
|
||||||
RECT m_rcClient;
|
float m_fontSizeMultiplier{1.0};
|
||||||
int64_t m_mostRecentEventCount{0};
|
int64_t m_mostRecentEventCount{0};
|
||||||
int m_nativeEventCount{0};
|
int m_nativeEventCount{0};
|
||||||
bool m_comingFromJS{false};
|
bool m_comingFromJS{false};
|
||||||
|
@ -123,6 +126,8 @@ struct WindowsTextInputComponentView
|
||||||
bool m_drawing{false};
|
bool m_drawing{false};
|
||||||
bool m_clearTextOnSubmit{false};
|
bool m_clearTextOnSubmit{false};
|
||||||
bool m_multiline{false};
|
bool m_multiline{false};
|
||||||
|
DWORD m_propBitsMask{0};
|
||||||
|
DWORD m_propBits{0};
|
||||||
std::vector<facebook::react::CompWindowsTextInputSubmitKeyEventsStruct> m_submitKeyEvents;
|
std::vector<facebook::react::CompWindowsTextInputSubmitKeyEventsStruct> m_submitKeyEvents;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@ void WindowsTextInputShadowNode::setContextContainer(ContextContainer *contextCo
|
||||||
m_contextContainer = contextContainer;
|
m_contextContainer = contextContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributedString WindowsTextInputShadowNode::getAttributedString() const {
|
AttributedString WindowsTextInputShadowNode::getAttributedString(const LayoutContext &layoutContext) const {
|
||||||
// Use BaseTextShadowNode to get attributed string from children
|
// Use BaseTextShadowNode to get attributed string from children
|
||||||
|
|
||||||
auto childTextAttributes = TextAttributes::defaultTextAttributes();
|
auto childTextAttributes = TextAttributes::defaultTextAttributes();
|
||||||
|
childTextAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
||||||
|
|
||||||
childTextAttributes.apply(getConcreteProps().textAttributes);
|
childTextAttributes.apply(getConcreteProps().textAttributes);
|
||||||
// Don't propagate the background color of the TextInput onto the attributed
|
// Don't propagate the background color of the TextInput onto the attributed
|
||||||
|
@ -42,6 +43,7 @@ AttributedString WindowsTextInputShadowNode::getAttributedString() const {
|
||||||
// value attributes manually.
|
// value attributes manually.
|
||||||
if (!getConcreteProps().text.empty()) {
|
if (!getConcreteProps().text.empty()) {
|
||||||
auto textAttributes = TextAttributes::defaultTextAttributes();
|
auto textAttributes = TextAttributes::defaultTextAttributes();
|
||||||
|
textAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
||||||
textAttributes.apply(getConcreteProps().textAttributes);
|
textAttributes.apply(getConcreteProps().textAttributes);
|
||||||
auto fragment = AttributedString::Fragment{};
|
auto fragment = AttributedString::Fragment{};
|
||||||
fragment.string = getConcreteProps().text;
|
fragment.string = getConcreteProps().text;
|
||||||
|
@ -63,7 +65,7 @@ AttributedString WindowsTextInputShadowNode::getAttributedString() const {
|
||||||
// display at all.
|
// display at all.
|
||||||
// TODO T67606511: We will redefine the measurement of empty strings as part
|
// TODO T67606511: We will redefine the measurement of empty strings as part
|
||||||
// of T67606511
|
// of T67606511
|
||||||
AttributedString WindowsTextInputShadowNode::getPlaceholderAttributedString() const {
|
AttributedString WindowsTextInputShadowNode::getPlaceholderAttributedString(const LayoutContext &layoutContext) const {
|
||||||
// Return placeholder text, since text and children are empty.
|
// Return placeholder text, since text and children are empty.
|
||||||
auto textAttributedString = AttributedString{};
|
auto textAttributedString = AttributedString{};
|
||||||
auto fragment = AttributedString::Fragment{};
|
auto fragment = AttributedString::Fragment{};
|
||||||
|
@ -74,6 +76,7 @@ AttributedString WindowsTextInputShadowNode::getPlaceholderAttributedString() co
|
||||||
}
|
}
|
||||||
|
|
||||||
auto textAttributes = TextAttributes::defaultTextAttributes();
|
auto textAttributes = TextAttributes::defaultTextAttributes();
|
||||||
|
textAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
||||||
textAttributes.apply(getConcreteProps().textAttributes);
|
textAttributes.apply(getConcreteProps().textAttributes);
|
||||||
|
|
||||||
// If there's no text, it's possible that this Fragment isn't actually
|
// If there's no text, it's possible that this Fragment isn't actually
|
||||||
|
@ -90,10 +93,10 @@ void WindowsTextInputShadowNode::setTextLayoutManager(SharedTextLayoutManager te
|
||||||
m_textLayoutManager = std::move(textLayoutManager);
|
m_textLayoutManager = std::move(textLayoutManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributedString WindowsTextInputShadowNode::getMostRecentAttributedString() const {
|
AttributedString WindowsTextInputShadowNode::getMostRecentAttributedString(const LayoutContext &layoutContext) const {
|
||||||
const auto &state = getStateData();
|
const auto &state = getStateData();
|
||||||
|
|
||||||
auto reactTreeAttributedString = getAttributedString();
|
auto reactTreeAttributedString = getAttributedString(layoutContext);
|
||||||
|
|
||||||
// Sometimes the treeAttributedString will only differ from the state
|
// Sometimes the treeAttributedString will only differ from the state
|
||||||
// not by inherent properties (string or prop attributes), but by the frame of
|
// not by inherent properties (string or prop attributes), but by the frame of
|
||||||
|
@ -105,10 +108,10 @@ AttributedString WindowsTextInputShadowNode::getMostRecentAttributedString() con
|
||||||
return (!treeAttributedStringChanged ? state.attributedString : reactTreeAttributedString);
|
return (!treeAttributedStringChanged ? state.attributedString : reactTreeAttributedString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowsTextInputShadowNode::updateStateIfNeeded() {
|
void WindowsTextInputShadowNode::updateStateIfNeeded(const LayoutContext &layoutContext) {
|
||||||
ensureUnsealed();
|
ensureUnsealed();
|
||||||
|
|
||||||
auto reactTreeAttributedString = getAttributedString();
|
auto reactTreeAttributedString = getAttributedString(layoutContext);
|
||||||
const auto &state = getStateData();
|
const auto &state = getStateData();
|
||||||
|
|
||||||
// Tree is often out of sync with the value of the TextInput.
|
// Tree is often out of sync with the value of the TextInput.
|
||||||
|
@ -129,13 +132,13 @@ void WindowsTextInputShadowNode::updateStateIfNeeded() {
|
||||||
// in the AttributedString, and when State is updated, it needs some way to
|
// in the AttributedString, and when State is updated, it needs some way to
|
||||||
// reconstruct a Fragment with default TextAttributes.
|
// reconstruct a Fragment with default TextAttributes.
|
||||||
auto defaultTextAttributes = TextAttributes::defaultTextAttributes();
|
auto defaultTextAttributes = TextAttributes::defaultTextAttributes();
|
||||||
|
defaultTextAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
||||||
defaultTextAttributes.apply(getConcreteProps().textAttributes);
|
defaultTextAttributes.apply(getConcreteProps().textAttributes);
|
||||||
|
|
||||||
auto newEventCount = state.reactTreeAttributedString.isContentEqual(reactTreeAttributedString)
|
auto newEventCount = state.reactTreeAttributedString.isContentEqual(reactTreeAttributedString)
|
||||||
? 0
|
? 0
|
||||||
: getConcreteProps().mostRecentEventCount;
|
: getConcreteProps().mostRecentEventCount;
|
||||||
auto newAttributedString = getMostRecentAttributedString();
|
auto newAttributedString = getMostRecentAttributedString(layoutContext);
|
||||||
|
|
||||||
// Even if we're here and updating state, it may be only to update the layout
|
// Even if we're here and updating state, it may be only to update the layout
|
||||||
// manager If that is the case, make sure we don't update text: pass in the
|
// manager If that is the case, make sure we don't update text: pass in the
|
||||||
|
@ -172,10 +175,10 @@ Size WindowsTextInputShadowNode::measureContent(
|
||||||
// during layout, but not during `measure`. If State is out-of-date in layout,
|
// during layout, but not during `measure`. If State is out-of-date in layout,
|
||||||
// it's too late: measure will have already operated on old State. Thus, we
|
// it's too late: measure will have already operated on old State. Thus, we
|
||||||
// use the same value here that we *will* use in layout to update the state.
|
// use the same value here that we *will* use in layout to update the state.
|
||||||
AttributedString attributedString = getMostRecentAttributedString();
|
AttributedString attributedString = getMostRecentAttributedString(layoutContext);
|
||||||
|
|
||||||
if (attributedString.isEmpty()) {
|
if (attributedString.isEmpty()) {
|
||||||
attributedString = getPlaceholderAttributedString();
|
attributedString = getPlaceholderAttributedString(layoutContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributedString.isEmpty() && getStateData().mostRecentEventCount != 0) {
|
if (attributedString.isEmpty() && getStateData().mostRecentEventCount != 0) {
|
||||||
|
@ -194,7 +197,7 @@ Size WindowsTextInputShadowNode::measureContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowsTextInputShadowNode::layout(LayoutContext layoutContext) {
|
void WindowsTextInputShadowNode::layout(LayoutContext layoutContext) {
|
||||||
updateStateIfNeeded();
|
updateStateIfNeeded(layoutContext);
|
||||||
ConcreteViewShadowNode::layout(layoutContext);
|
ConcreteViewShadowNode::layout(layoutContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,8 @@ class WindowsTextInputShadowNode final : public ConcreteViewShadowNode<
|
||||||
/*
|
/*
|
||||||
* Returns a `AttributedString` which represents text content of the node.
|
* Returns a `AttributedString` which represents text content of the node.
|
||||||
*/
|
*/
|
||||||
AttributedString getAttributedString() const;
|
AttributedString getAttributedString(const LayoutContext &layoutContext) const;
|
||||||
AttributedString getPlaceholderAttributedString() const;
|
AttributedString getPlaceholderAttributedString(const LayoutContext &layoutContext) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Associates a shared TextLayoutManager with the node.
|
* Associates a shared TextLayoutManager with the node.
|
||||||
|
@ -63,13 +63,13 @@ class WindowsTextInputShadowNode final : public ConcreteViewShadowNode<
|
||||||
/**
|
/**
|
||||||
* Get the most up-to-date attributed string for measurement and State.
|
* Get the most up-to-date attributed string for measurement and State.
|
||||||
*/
|
*/
|
||||||
AttributedString getMostRecentAttributedString() const;
|
AttributedString getMostRecentAttributedString(const LayoutContext &layoutContext) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a `State` object (with `AttributedText` and
|
* Creates a `State` object (with `AttributedText` and
|
||||||
* `TextLayoutManager`) if needed.
|
* `TextLayoutManager`) if needed.
|
||||||
*/
|
*/
|
||||||
void updateStateIfNeeded();
|
void updateStateIfNeeded(const LayoutContext &layoutContext);
|
||||||
|
|
||||||
SharedTextLayoutManager m_textLayoutManager;
|
SharedTextLayoutManager m_textLayoutManager;
|
||||||
|
|
||||||
|
|
|
@ -31,17 +31,4 @@ WindowsTextInputState::WindowsTextInputState(
|
||||||
defaultThemePaddingTop(defaultThemePaddingTop),
|
defaultThemePaddingTop(defaultThemePaddingTop),
|
||||||
defaultThemePaddingBottom(defaultThemePaddingBottom) {}
|
defaultThemePaddingBottom(defaultThemePaddingBottom) {}
|
||||||
|
|
||||||
WindowsTextInputState::WindowsTextInputState(const WindowsTextInputState &previousState, const folly::dynamic &data)
|
|
||||||
: mostRecentEventCount(data.getDefault("mostRecentEventCount", previousState.mostRecentEventCount).getInt()),
|
|
||||||
cachedAttributedStringId(data.getDefault("opaqueCacheId", previousState.cachedAttributedStringId).getInt()),
|
|
||||||
attributedString(previousState.attributedString),
|
|
||||||
reactTreeAttributedString(previousState.reactTreeAttributedString),
|
|
||||||
paragraphAttributes(previousState.paragraphAttributes),
|
|
||||||
defaultThemePaddingStart(
|
|
||||||
data.getDefault("themePaddingStart", previousState.defaultThemePaddingStart).getDouble()),
|
|
||||||
defaultThemePaddingEnd(data.getDefault("themePaddingEnd", previousState.defaultThemePaddingEnd).getDouble()),
|
|
||||||
defaultThemePaddingTop(data.getDefault("themePaddingTop", previousState.defaultThemePaddingTop).getDouble()),
|
|
||||||
defaultThemePaddingBottom(
|
|
||||||
data.getDefault("themePaddingBottom", previousState.defaultThemePaddingBottom).getDouble()){};
|
|
||||||
|
|
||||||
} // namespace facebook::react
|
} // namespace facebook::react
|
||||||
|
|
|
@ -66,9 +66,6 @@ class WindowsTextInputState final {
|
||||||
double defaultThemePaddingBottom);
|
double defaultThemePaddingBottom);
|
||||||
|
|
||||||
WindowsTextInputState() = default;
|
WindowsTextInputState() = default;
|
||||||
WindowsTextInputState(const WindowsTextInputState &previousState, const folly::dynamic &data);
|
|
||||||
folly::dynamic getDynamic() const;
|
|
||||||
MapBuffer getMapBuffer() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace facebook::react
|
} // namespace facebook::react
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <Fabric/ComponentView.h>
|
#include <Fabric/ComponentView.h>
|
||||||
#include <Fabric/Composition/CompositionUIService.h>
|
#include <Fabric/Composition/CompositionUIService.h>
|
||||||
#include <Fabric/Composition/CompositionViewComponentView.h>
|
#include <Fabric/Composition/CompositionViewComponentView.h>
|
||||||
|
#include <Fabric/Composition/ReactNativeIsland.h>
|
||||||
#include <Fabric/Composition/RootComponentView.h>
|
#include <Fabric/Composition/RootComponentView.h>
|
||||||
#include <Fabric/FabricUIManagerModule.h>
|
#include <Fabric/FabricUIManagerModule.h>
|
||||||
#include <Fabric/ReactNativeConfigProperties.h>
|
#include <Fabric/ReactNativeConfigProperties.h>
|
||||||
|
@ -141,7 +142,7 @@ void FabricUIManager::startSurface(
|
||||||
|
|
||||||
facebook::react::LayoutContext layoutContext;
|
facebook::react::LayoutContext layoutContext;
|
||||||
layoutContext.pointScaleFactor = rootView.ScaleFactor();
|
layoutContext.pointScaleFactor = rootView.ScaleFactor();
|
||||||
layoutContext.fontSizeMultiplier = rootView.ScaleFactor();
|
layoutContext.fontSizeMultiplier = rootView.FontSizeMultiplier();
|
||||||
|
|
||||||
m_surfaceManager->startSurface(
|
m_surfaceManager->startSurface(
|
||||||
surfaceId,
|
surfaceId,
|
||||||
|
|
|
@ -41,7 +41,10 @@ void TextLayoutManager::GetTextLayout(
|
||||||
static_cast<facebook::react::FontWeight>(DWRITE_FONT_WEIGHT_REGULAR))),
|
static_cast<facebook::react::FontWeight>(DWRITE_FONT_WEIGHT_REGULAR))),
|
||||||
style,
|
style,
|
||||||
DWRITE_FONT_STRETCH_NORMAL,
|
DWRITE_FONT_STRETCH_NORMAL,
|
||||||
outerFragment.textAttributes.fontSize,
|
(outerFragment.textAttributes.allowFontScaling.value_or(true) &&
|
||||||
|
!std::isnan(outerFragment.textAttributes.fontSizeMultiplier))
|
||||||
|
? (outerFragment.textAttributes.fontSizeMultiplier * outerFragment.textAttributes.fontSize)
|
||||||
|
: outerFragment.textAttributes.fontSize,
|
||||||
L"",
|
L"",
|
||||||
spTextFormat.put()));
|
spTextFormat.put()));
|
||||||
|
|
||||||
|
@ -116,7 +119,11 @@ void TextLayoutManager::GetTextLayout(
|
||||||
attributes.fontWeight.value_or(static_cast<facebook::react::FontWeight>(DWRITE_FONT_WEIGHT_REGULAR))),
|
attributes.fontWeight.value_or(static_cast<facebook::react::FontWeight>(DWRITE_FONT_WEIGHT_REGULAR))),
|
||||||
range));
|
range));
|
||||||
winrt::check_hresult(spTextLayout->SetFontStyle(fragmentStyle, range));
|
winrt::check_hresult(spTextLayout->SetFontStyle(fragmentStyle, range));
|
||||||
winrt::check_hresult(spTextLayout->SetFontSize(attributes.fontSize, range));
|
winrt::check_hresult(spTextLayout->SetFontSize(
|
||||||
|
(attributes.allowFontScaling.value_or(true) && !std::isnan(attributes.fontSizeMultiplier))
|
||||||
|
? (attributes.fontSizeMultiplier * attributes.fontSize)
|
||||||
|
: attributes.fontSize,
|
||||||
|
range));
|
||||||
|
|
||||||
if (!isnan(attributes.letterSpacing)) {
|
if (!isnan(attributes.letterSpacing)) {
|
||||||
winrt::check_hresult(
|
winrt::check_hresult(
|
||||||
|
|
|
@ -25,6 +25,7 @@ void UpdateRootViewSizeToAppWindow(
|
||||||
if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
|
if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
|
||||||
winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
|
winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
|
||||||
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
||||||
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
||||||
constraints.MaximumSize = constraints.MinimumSize = size;
|
constraints.MaximumSize = constraints.MinimumSize = size;
|
||||||
rootView.Arrange(constraints, {0, 0});
|
rootView.Arrange(constraints, {0, 0});
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,8 @@ namespace Microsoft.ReactNative
|
||||||
DOC_STRING("ScaleFactor for this windows (DPI/96)")
|
DOC_STRING("ScaleFactor for this windows (DPI/96)")
|
||||||
Single ScaleFactor {get; set;};
|
Single ScaleFactor {get; set;};
|
||||||
|
|
||||||
|
Single FontSizeMultiplier { get; };
|
||||||
|
|
||||||
DOC_STRING("Move focus to this @ReactNativeIsland")
|
DOC_STRING("Move focus to this @ReactNativeIsland")
|
||||||
FocusNavigationResult NavigateFocus(FocusNavigationRequest request);
|
FocusNavigationResult NavigateFocus(FocusNavigationRequest request);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ void UpdateRootViewSizeToAppWindow(
|
||||||
if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
|
if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
|
||||||
winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
|
winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
|
||||||
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
||||||
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
||||||
constraints.MaximumSize = constraints.MinimumSize = size;
|
constraints.MaximumSize = constraints.MinimumSize = size;
|
||||||
rootView.Arrange(constraints, {0,0});
|
rootView.Arrange(constraints, {0,0});
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче