Skip to content
Open
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": "prerelease",
"comment": "Implement overflow property support for Fabric architecture",
"packageName": "react-native-windows",
"email": "nitchaudhary@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,12 @@ void ViewComponentView::ensureVisual() noexcept {
}
OuterVisual().InsertAt(m_visual, 0);
}

// Create m_contentVisual as a child of m_visual if not already created
if (!m_contentVisual) {
m_contentVisual = m_compContext.CreateSpriteVisual();
m_visual.InsertAt(m_contentVisual, 0); // Insert at index 0 so it's below border visuals
}
}

winrt::Microsoft::ReactNative::ComponentView ViewComponentView::Create(
Expand All @@ -1084,7 +1090,8 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual
ViewComponentView::VisualToMountChildrenInto() noexcept {
if (m_builder && m_builder->VisualToMountChildrenIntoHandler())
return m_builder->VisualToMountChildrenIntoHandler()(*this);
return Visual();
// Mount children into m_contentVisual
return m_contentVisual ? m_contentVisual : Visual();
}

void ViewComponentView::MountChildComponentView(
Expand Down Expand Up @@ -1140,6 +1147,21 @@ void ViewComponentView::updateProps(
// update BaseComponentView props
updateAccessibilityProps(oldViewProps, newViewProps);
updateTransformProps(oldViewProps, newViewProps, Visual());

// Handle overflow property changes
if (oldViewProps.yogaStyle.overflow() != newViewProps.yogaStyle.overflow()) {
auto compVisual =
winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerVisual(
Visual());
if (compVisual) {
if (newViewProps.yogaStyle.overflow() == facebook::yoga::Overflow::Hidden) {
compVisual.Clip(Compositor().CreateInsetClip(0.0f, 0.0f, 0.0f, 0.0f));
} else {
compVisual.Clip(nullptr);
}
}
}

base_type::updateProps(props, oldProps);

m_props = std::static_pointer_cast<facebook::react::ViewProps const>(props);
Expand Down Expand Up @@ -1317,6 +1339,48 @@ void ViewComponentView::updateLayoutMetrics(
Visual().Size(
{layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor,
layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor});

// Size and offset m_contentVisual to match the content area, excluding borders
if (m_contentVisual && m_props) {
auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics(layoutMetrics, *m_props);
float borderLeft = borderMetrics.borderWidths.left;
float borderTop = borderMetrics.borderWidths.top;
float borderRight = borderMetrics.borderWidths.right;
float borderBottom = borderMetrics.borderWidths.bottom;
float scale = layoutMetrics.pointScaleFactor;
float contentWidth = layoutMetrics.frame.size.width * scale - borderLeft - borderRight;
float contentHeight = layoutMetrics.frame.size.height * scale - borderTop - borderBottom;
Comment on lines +1345 to +1352
Copy link
Contributor

@sundaramramaswamy sundaramramaswamy Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make these const.

Prefer const T var = value as much as possible, and drop const only when you know a variable is going to change value later on. Why? Refer What's "const correctness"? - ISO C++ FAQ.

m_contentVisual.Offset({borderLeft, borderTop, 0});
m_contentVisual.Size({std::max(0.f, contentWidth), std::max(0.f, contentHeight)});

// Apply clipping to m_contentVisual for overflow: hidden
if (m_props->getClipsContentToBounds()) {
// Calculate inner border radii for clipping (0 for rectangular clip)
facebook::react::RectangleCorners<facebook::react::CornerRadii> innerRadii;
innerRadii.topLeft = {
std::max(0.f, borderMetrics.borderRadii.topLeft.horizontal - borderLeft),
std::max(0.f, borderMetrics.borderRadii.topLeft.vertical - borderTop)};
innerRadii.topRight = {
std::max(0.f, borderMetrics.borderRadii.topRight.horizontal - borderRight),
std::max(0.f, borderMetrics.borderRadii.topRight.vertical - borderTop)};
innerRadii.bottomLeft = {
std::max(0.f, borderMetrics.borderRadii.bottomLeft.horizontal - borderLeft),
std::max(0.f, borderMetrics.borderRadii.bottomLeft.vertical - borderBottom)};
innerRadii.bottomRight = {
std::max(0.f, borderMetrics.borderRadii.bottomRight.horizontal - borderRight),
std::max(0.f, borderMetrics.borderRadii.bottomRight.vertical - borderBottom)};

winrt::com_ptr<ID2D1PathGeometry> pathGeometry = BorderPrimitive::GenerateRoundedRectPathGeometry(
m_compContext, innerRadii, {0, 0, 0, 0}, {0, 0, std::max(0.f, contentWidth), std::max(0.f, contentHeight)});

m_contentVisual.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
pathGeometry.get());
} else {
// Clear any existing clip
m_contentVisual.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
nullptr);
}
}
}

void ViewComponentView::prepareForRecycle() noexcept {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ struct ViewComponentView : public ViewComponentViewT<
bool m_hasNonVisualChildren{false};
facebook::react::SharedViewProps m_props;
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_visual{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_contentVisual{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::CreateInternalVisualDelegate m_createInternalVisualHandler{
nullptr};
};
Expand Down
Loading