Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[0.74] Cherry-pick: High dpi tooltips, platformcolor fix and clang codegen fix #14406

Merged
merged 4 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix build issue building component codegen using clang",
"packageName": "@react-native-windows/codegen",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix tooltips in high dpi",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix build issue building component codegen using clang",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Property updates switching between PlatformColors would no-op",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,15 @@ void Register::_COMPONENT_NAME_::NativeComponent(
userData->UpdateEventEmitter(std::make_shared<::_COMPONENT_NAME_::EventEmitter>(eventEmitter));
});

if constexpr (&TUserData::FinalizeUpdate != &Base::_COMPONENT_NAME_::<TUserData>::FinalizeUpdate) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::FinalizeUpdate != &Base::_COMPONENT_NAME_::<TUserData>::FinalizeUpdate) {
builder.SetFinalizeUpdateHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
winrt::Microsoft::ReactNative::ComponentViewUpdateMask mask) noexcept {
auto userData = view.UserData().as<TUserData>();
userData->FinalizeUpdate(view, mask);
});
}

if constexpr (&TUserData::UpdateState != &Base::_COMPONENT_NAME_::<TUserData>::UpdateState) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::UpdateState != &Base::_COMPONENT_NAME_::<TUserData>::UpdateState) {
builder.SetUpdateStateHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::IComponentState &newState) noexcept {
auto userData = view.UserData().as<TUserData>();
Expand All @@ -202,15 +202,15 @@ void Register::_COMPONENT_NAME_::NativeComponent(

::_REGISTER_CUSTOM_COMMAND_HANDLER_::

if constexpr (&TUserData::MountChildComponentView != &Base::_COMPONENT_NAME_::<TUserData>::MountChildComponentView) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::MountChildComponentView != &Base::_COMPONENT_NAME_::<TUserData>::MountChildComponentView) {
builder.SetMountChildComponentViewHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::MountChildComponentViewArgs &args) noexcept {
auto userData = view.UserData().as<TUserData>();
return userData->MountChildComponentView(view, args);
});
}

if constexpr (&TUserData::UnmountChildComponentView != &Base::_COMPONENT_NAME_::<TUserData>::UnmountChildComponentView) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::UnmountChildComponentView != &Base::_COMPONENT_NAME_::<TUserData>::UnmountChildComponentView) {
builder.SetUnmountChildComponentViewHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::UnmountChildComponentViewArgs &args) noexcept {
auto userData = view.UserData().as<TUserData>();
Expand All @@ -220,13 +220,13 @@ void Register::_COMPONENT_NAME_::NativeComponent(

compBuilder.SetViewComponentViewInitializer([](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
auto userData = winrt::make_self<TUserData>();
if constexpr (&TUserData::Initialize != &Base::_COMPONENT_NAME_::<TUserData>::Initialize) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::Initialize != &Base::_COMPONENT_NAME_::<TUserData>::Initialize) {
userData->Initialize(view);
}
view.UserData(*userData);
});

if constexpr (&TUserData::CreateVisual != &Base::_COMPONENT_NAME_::<TUserData>::CreateVisual) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::CreateVisual != &Base::_COMPONENT_NAME_::<TUserData>::CreateVisual) {
compBuilder.SetCreateVisualHandler([](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
auto userData = view.UserData().as<TUserData>();
return userData->CreateVisual(view);
Expand Down
9 changes: 9 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/NativeModules.h
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,15 @@ inline ReactModuleProvider MakeTurboModuleProvider() noexcept {
return MakeModuleProvider<TModule>();
}

// Clang does not allow a virtual function address to be a constexpr statement
#if !defined(CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS)
#if defined(__clang__)
#define CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS
#else
#define CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS constexpr
#endif
#endif

} // namespace winrt::Microsoft::ReactNative

namespace React {
Expand Down
18 changes: 8 additions & 10 deletions vnext/Microsoft.ReactNative/Fabric/AbiViewProps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,12 @@ winrt::Microsoft::ReactNative::Color Color::ReadValue(
switch (reader.ValueType()) {
case JSValueType::Int64: {
auto argb = reader.GetInt64();
return winrt::make<Color>(facebook::react::Color{
/*m_isDefined*/ true,
/*color*/
{static_cast<uint8_t>((argb >> 24) & 0xFF),
static_cast<uint8_t>((argb >> 16) & 0xFF),
static_cast<uint8_t>((argb >> 8) & 0xFF),
static_cast<uint8_t>(argb & 0xFF)},
{}});
return winrt::make<Color>(facebook::react::Color{/*color*/
{static_cast<uint8_t>((argb >> 24) & 0xFF),
static_cast<uint8_t>((argb >> 16) & 0xFF),
static_cast<uint8_t>((argb >> 8) & 0xFF),
static_cast<uint8_t>(argb & 0xFF)},
{}});
}
case JSValueType::Object: {
std::vector<std::string> platformColors;
Expand All @@ -96,10 +94,10 @@ winrt::Microsoft::ReactNative::Color Color::ReadValue(
SkipValue<JSValue>(reader); // Skip this property
}
}
return winrt::make<Color>(facebook::react::Color{/*m_isDefined*/ true, /*color*/ {}, std::move(platformColors)});
return winrt::make<Color>(facebook::react::Color{/*color*/ {}, std::move(platformColors)});
}
default:
return winrt::make<Color>(facebook::react::Color{/*m_isDefined*/ false, /*color*/ {0, 0, 0, 0}, {}});
return winrt::make<Color>(facebook::react::Color{/*color*/ {0, 0, 0, 0}, {}});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ void ComponentView::updateProps(
updateShadowProps(oldViewProps, newViewProps);
}
if (oldViewProps.tooltip != newViewProps.tooltip) {
if (!m_tooltipTracked && newViewProps.tooltip) {
if (!m_tooltipTracked && newViewProps.tooltip && !newViewProps.tooltip->empty()) {
TooltipService::GetCurrent(m_reactContext.Properties())->StartTracking(*this);
m_tooltipTracked = true;
} else if (m_tooltipTracked && !newViewProps.tooltip) {
Expand Down
78 changes: 41 additions & 37 deletions vnext/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
#include <winrt/Microsoft.ReactNative.Composition.h>
#include <winrt/Windows.UI.ViewManagement.h>
#include "TextDrawing.h"
#include "dwmapi.h"

Expand Down Expand Up @@ -49,7 +50,9 @@ facebook::react::AttributedStringBox CreateTooltipAttributedString(const std::st
auto fragment = facebook::react::AttributedString::Fragment{};
fragment.string = tooltip;
fragment.textAttributes.fontSize = tooltipFontSize;
attributedString.appendFragment(fragment);
fragment.textAttributes.fontSizeMultiplier =
static_cast<float>(winrt::Windows::UI::ViewManagement::UISettings().TextScaleFactor());
attributedString.appendFragment(std::move(fragment));
return facebook::react::AttributedStringBox{attributedString};
}

Expand Down Expand Up @@ -231,14 +234,13 @@ void TooltipTracker::OnUnmounted(
}

void TooltipTracker::ShowTooltip(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
auto viewCompView = view.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();

auto selfView =
winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView>(viewCompView);
auto parentHwnd = selfView->GetHwndForParenting();
DestroyTimer();

if (!m_hwndTip) {
auto viewCompView = view.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();
auto selfView =
winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView>(viewCompView);
auto parentHwnd = selfView->GetHwndForParenting();
auto tooltipData = std::make_unique<TooltipData>(view);
tooltipData->attributedString = CreateTooltipAttributedString(*selfView->viewProps()->tooltip);

Expand All @@ -256,37 +258,39 @@ void TooltipTracker::ShowTooltip(const winrt::Microsoft::ReactNative::ComponentV
facebook::react::TextLayoutManager::GetTextLayout(
tooltipData->attributedString, {} /*paragraphAttributes*/, layoutConstraints, tooltipData->textLayout);

DWRITE_TEXT_METRICS tm;
winrt::check_hresult(tooltipData->textLayout->GetMetrics(&tm));

tooltipData->width =
static_cast<int>(tm.width + ((tooltipHorizontalPadding + tooltipHorizontalPadding) * scaleFactor));
tooltipData->height = static_cast<int>(tm.height + ((tooltipTopPadding + tooltipBottomPadding) * scaleFactor));

POINT pt = {static_cast<LONG>(m_pos.X), static_cast<LONG>(m_pos.Y)};
ClientToScreen(parentHwnd, &pt);

RegisterTooltipWndClass();
HINSTANCE hInstance = GetModuleHandle(NULL);
m_hwndTip = CreateWindow(
c_tooltipWindowClassName,
L"Tooltip",
WS_POPUP,
pt.x - tooltipData->width / 2,
static_cast<int>(pt.y - tooltipData->height - (toolTipPlacementMargin * scaleFactor)),
tooltipData->width,
tooltipData->height,
parentHwnd,
NULL,
hInstance,
tooltipData.get());

DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUNDSMALL;
UINT borderThickness = 0;
DwmSetWindowAttribute(m_hwndTip, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));

tooltipData.release();
AnimateWindow(m_hwndTip, toolTipAnimationTimeMs, AW_BLEND);
if (tooltipData->textLayout) {
DWRITE_TEXT_METRICS tm;
winrt::check_hresult(tooltipData->textLayout->GetMetrics(&tm));

tooltipData->width =
static_cast<int>((tm.width + tooltipHorizontalPadding + tooltipHorizontalPadding) * scaleFactor);
tooltipData->height = static_cast<int>((tm.height + tooltipTopPadding + tooltipBottomPadding) * scaleFactor);

POINT pt = {static_cast<LONG>(m_pos.X), static_cast<LONG>(m_pos.Y)};
ClientToScreen(parentHwnd, &pt);

RegisterTooltipWndClass();
HINSTANCE hInstance = GetModuleHandle(NULL);
m_hwndTip = CreateWindow(
c_tooltipWindowClassName,
L"Tooltip",
WS_POPUP,
pt.x - tooltipData->width / 2,
static_cast<int>(pt.y - tooltipData->height - (toolTipPlacementMargin * scaleFactor)),
tooltipData->width,
tooltipData->height,
parentHwnd,
NULL,
hInstance,
tooltipData.get());

DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUNDSMALL;
UINT borderThickness = 0;
DwmSetWindowAttribute(m_hwndTip, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));

tooltipData.release();
AnimateWindow(m_hwndTip, toolTipAnimationTimeMs, AW_BLEND);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,10 @@ namespace facebook::react {

struct Color {
bool operator==(const Color &otherColor) const {
return m_isUndefined && otherColor.m_isUndefined ||
(m_isUndefined == otherColor.m_isUndefined && m_color == otherColor.m_color &&
m_platformColor == otherColor.m_platformColor);
return m_color == otherColor.m_color && m_platformColor == otherColor.m_platformColor;
}
bool operator!=(const Color &otherColor) const {
return m_isUndefined != otherColor.m_isUndefined || m_color != otherColor.m_color ||
m_platformColor != otherColor.m_platformColor;
return m_color != otherColor.m_color || m_platformColor != otherColor.m_platformColor;
}

winrt::Windows::UI::Color AsWindowsColor() const {
Expand All @@ -36,13 +33,12 @@ struct Color {
return RGB(m_color.R, m_color.G, m_color.B) | (m_color.A << 24);
}

bool m_isUndefined;
winrt::Windows::UI::Color m_color;
std::vector<std::string> m_platformColor;
};

namespace HostPlatformColor {
static const facebook::react::Color UndefinedColor{true};
static const facebook::react::Color UndefinedColor{{0, 0, 0, 0} /*Black*/, {} /*Empty PlatformColors*/};
} // namespace HostPlatformColor

inline Color hostPlatformColorFromComponents(ColorComponents components) {
Expand All @@ -53,7 +49,6 @@ inline Color hostPlatformColorFromComponents(ColorComponents components) {
static_cast<uint8_t>((int)round(components.green * ratio) & 0xff),
static_cast<uint8_t>((int)round(components.blue * ratio) & 0xff)};
return {
/* .m_isUndefined = */ false,
/* .m_color = */ color,
/* .m_platformColor = */ {}};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ parsePlatformColor(const ContextContainer &contextContainer, int32_t surfaceId,
auto map = (std::unordered_map<std::string, std::vector<std::string>>)value;
if (map.find("windowsbrush") != map.end()) {
facebook::react::Color color = {
/* .m_isDefined = */ true,
/* .m_color = */ {},
/* .m_platformColor = */ std::move(map["windowsbrush"]),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,31 +147,31 @@ void RegisterActivityIndicatorViewNativeComponent(
userData->UpdateEventEmitter(std::make_shared<ActivityIndicatorViewEventEmitter>(eventEmitter));
});

if constexpr (&TUserData::FinalizeUpdate != &BaseActivityIndicatorView<TUserData>::FinalizeUpdate) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::FinalizeUpdate != &BaseActivityIndicatorView<TUserData>::FinalizeUpdate) {
builder.SetFinalizeUpdateHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
winrt::Microsoft::ReactNative::ComponentViewUpdateMask mask) noexcept {
auto userData = view.UserData().as<TUserData>();
userData->FinalizeUpdate(view, mask);
});
}

if constexpr (&TUserData::UpdateState != &BaseActivityIndicatorView<TUserData>::UpdateState) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::UpdateState != &BaseActivityIndicatorView<TUserData>::UpdateState) {
builder.SetUpdateStateHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::IComponentState &newState) noexcept {
auto userData = view.UserData().as<TUserData>();
userData->UpdateState(view, newState);
});
}

if constexpr (&TUserData::MountChildComponentView != &BaseActivityIndicatorView<TUserData>::MountChildComponentView) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::MountChildComponentView != &BaseActivityIndicatorView<TUserData>::MountChildComponentView) {
builder.SetMountChildComponentViewHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::MountChildComponentViewArgs &args) noexcept {
auto userData = view.UserData().as<TUserData>();
return userData->MountChildComponentView(view, args);
});
}

if constexpr (&TUserData::UnmountChildComponentView != &BaseActivityIndicatorView<TUserData>::UnmountChildComponentView) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::UnmountChildComponentView != &BaseActivityIndicatorView<TUserData>::UnmountChildComponentView) {
builder.SetUnmountChildComponentViewHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::UnmountChildComponentViewArgs &args) noexcept {
auto userData = view.UserData().as<TUserData>();
Expand All @@ -181,13 +181,13 @@ void RegisterActivityIndicatorViewNativeComponent(

compBuilder.SetViewComponentViewInitializer([](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
auto userData = winrt::make_self<TUserData>();
if constexpr (&TUserData::Initialize != &BaseActivityIndicatorView<TUserData>::Initialize) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::Initialize != &BaseActivityIndicatorView<TUserData>::Initialize) {
userData->Initialize(view);
}
view.UserData(*userData);
});

if constexpr (&TUserData::CreateVisual != &BaseActivityIndicatorView<TUserData>::CreateVisual) {
if CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS (&TUserData::CreateVisual != &BaseActivityIndicatorView<TUserData>::CreateVisual) {
compBuilder.SetCreateVisualHandler([](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
auto userData = view.UserData().as<TUserData>();
return userData->CreateVisual(view);
Expand Down
Loading
Loading