Skip to content

Commit 994d432

Browse files
committed
fix background clip
1 parent 0dc04eb commit 994d432

4 files changed

Lines changed: 43 additions & 20 deletions

File tree

vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ constexpr float FOCUS_VISUAL_RADIUS = 3.0f;
3838

3939
// m_outerVisual
4040
// |
41-
// ----- m_visual <-- Background / clip - Can be a custom visual depending on Component type
41+
// ----- m_visual - Can be a custom visual depending on Component type
4242
// |
43-
// ----- Border Visuals x N (BorderPrimitive attached to m_visual)
44-
// ----- Outline Visuals x N(BorderPrimitive)
43+
// ----- m_backgroundVisual <-- Background / clip (ComponentViewFeatures::Background)
44+
// ----- Border Visuals x N (BorderPrimitive attached to m_visual) (ComponentViewFeatures::NativeBorder)
45+
// ----- Outline Visuals x N(BorderPrimitive) (ComponentViewFeatures::NativeBorder)
4546
// ----- <children> (default: directly in m_visual after border visuals)
4647
// ----- m_childrenContainer (created on demand when overflow:hidden, children moved here)
4748
// ------Focus Visual Container (created when hosting focus visuals)
@@ -80,13 +81,8 @@ facebook::react::Props::Shared ComponentView::props() noexcept {
8081
}
8182

8283
void ComponentView::onThemeChanged() noexcept {
83-
if ((m_flags & ComponentViewFeatures::Background) == ComponentViewFeatures::Background) {
84-
if (viewProps()->backgroundColor) {
85-
Visual().as<Experimental::ISpriteVisual>().Brush(theme()->Brush(*viewProps()->backgroundColor));
86-
} else {
87-
Visual().as<Experimental::ISpriteVisual>().Brush(nullptr);
88-
}
89-
}
84+
if (m_backgroundVisual)
85+
m_backgroundVisual.Brush(theme()->Brush(*viewProps()->backgroundColor));
9086

9187
if (m_borderPrimitive) {
9288
m_borderPrimitive->onThemeChanged(
@@ -158,10 +154,16 @@ void ComponentView::updateProps(
158154

159155
if ((m_flags & ComponentViewFeatures::Background) == ComponentViewFeatures::Background) {
160156
if (oldViewProps.backgroundColor != newViewProps.backgroundColor) {
161-
if (newViewProps.backgroundColor) {
162-
Visual().as<Experimental::ISpriteVisual>().Brush(theme()->Brush(*newViewProps.backgroundColor));
157+
if (facebook::react::isColorMeaningful(newViewProps.backgroundColor)) {
158+
if (!m_backgroundVisual) {
159+
m_backgroundVisual = m_compContext.CreateSpriteVisual();
160+
m_backgroundVisual.RelativeSizeWithOffset({0, 0}, {1.0f, 1.0f});
161+
Visual().InsertAt(m_backgroundVisual, 0);
162+
}
163+
m_backgroundVisual.Brush(theme()->Brush(*newViewProps.backgroundColor));
164+
// todo set clipping?
163165
} else {
164-
Visual().as<Experimental::ISpriteVisual>().Brush(nullptr);
166+
m_backgroundVisual.Brush(nullptr);
165167
}
166168
}
167169
}
@@ -214,8 +216,9 @@ void ComponentView::updateProps(
214216
void ComponentView::updateLayoutMetrics(
215217
facebook::react::LayoutMetrics const &layoutMetrics,
216218
facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept {
219+
updateClippingPath(layoutMetrics, *viewProps());
220+
217221
if ((m_flags & ComponentViewFeatures::NativeBorder) == ComponentViewFeatures::NativeBorder) {
218-
updateClippingPath(layoutMetrics, *viewProps());
219222
OuterVisual().Size(
220223
{layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor,
221224
layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor});
@@ -322,7 +325,9 @@ void ComponentView::FinalizeUpdates(winrt::Microsoft::ReactNative::ComponentView
322325
auto outlineMetrics = outlineBorderMetrics();
323326
if (!m_outlinePrimitive && BorderPrimitive::requiresBorder(outlineMetrics, theme())) {
324327
m_outlinePrimitive = std::make_shared<BorderPrimitive>(*this);
325-
Visual().InsertAt(m_outlinePrimitive->RootVisual(), m_borderPrimitive ? m_borderPrimitive->numberOfVisuals() : 0);
328+
Visual().InsertAt(
329+
m_outlinePrimitive->RootVisual(),
330+
(m_backgroundVisual ? 1 : 0) + (m_borderPrimitive ? m_borderPrimitive->numberOfVisuals() : 0));
326331
}
327332

328333
if (m_outlinePrimitive) {
@@ -747,7 +752,7 @@ void ComponentView::hostFocusVisual(bool show, winrt::com_ptr<ComponentView> vie
747752
assert(
748753
view.get() ==
749754
this); // When not using lifted comp, focus visuals should always host within their own component
750-
OuterVisual().InsertAt(m_focusPrimitive->m_focusVisual, 1);
755+
OuterVisual().InsertAt(m_focusPrimitive->m_focusVisual, (m_backgroundVisual ? 2 : 1));
751756
}
752757
}
753758

@@ -991,9 +996,18 @@ void ComponentView::Toggle() noexcept {
991996
// no-op
992997
}
993998

999+
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ComponentView::VisualToApplyBackgroundClipTo() const noexcept
1000+
{
1001+
return m_backgroundVisual;
1002+
}
1003+
9941004
void ComponentView::updateClippingPath(
9951005
facebook::react::LayoutMetrics const &layoutMetrics,
9961006
const facebook::react::ViewProps &viewProps) noexcept {
1007+
auto clipTarget = VisualToApplyBackgroundClipTo();
1008+
if (!clipTarget)
1009+
return;
1010+
9971011
auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics(layoutMetrics, viewProps);
9981012

9991013
bool hasRoundedCorners = borderMetrics.borderRadii.topLeft.horizontal != 0 ||
@@ -1012,10 +1026,11 @@ void ComponentView::updateClippingPath(
10121026
winrt::com_ptr<ID2D1PathGeometry> pathGeometry = BorderPrimitive::GenerateRoundedRectPathGeometry(
10131027
m_compContext, borderMetrics.borderRadii, {0, 0, 0, 0}, {0, 0, viewWidth, viewHeight});
10141028

1015-
Visual().as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
1029+
clipTarget.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
10161030
pathGeometry.get());
10171031
} else {
1018-
Visual().as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(nullptr);
1032+
clipTarget.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
1033+
nullptr);
10191034
}
10201035
}
10211036

@@ -1180,7 +1195,7 @@ void ViewComponentView::ensureVisual() noexcept {
11801195
} else {
11811196
m_visual = createVisual();
11821197
}
1183-
OuterVisual().InsertAt(m_visual, 0);
1198+
OuterVisual().InsertAt(m_visual, m_backgroundVisual ? 1 : 0);
11841199
}
11851200
}
11861201

@@ -1478,7 +1493,7 @@ void ViewComponentView::updateChildrenClippingPath(
14781493
}
14791494

14801495
// Insert m_childrenContainer after border visuals in m_visual
1481-
Visual().InsertAt(m_childrenContainer, borderCount);
1496+
Visual().InsertAt(m_childrenContainer, (m_backgroundVisual ? 1 : 0) + borderCount);
14821497

14831498
// Use relative sizing so container automatically tracks parent's size
14841499
m_childrenContainer.RelativeSizeWithOffset({0, 0}, {1, 1});

vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ struct ComponentView : public ComponentViewT<
130130
void ThemeChanged(winrt::event_token const &token) noexcept;
131131

132132
protected:
133+
virtual winrt::Microsoft::ReactNative::Composition::Experimental::IVisual VisualToApplyBackgroundClipTo() const noexcept;
133134
bool anyHitTestHelper(
134135
facebook::react::Tag &targetTag,
135136
facebook::react::Point &ptContent,
@@ -141,6 +142,7 @@ struct ComponentView : public ComponentViewT<
141142
winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext m_compContext;
142143
comp::CompositionPropertySet m_centerPropSet{nullptr};
143144
facebook::react::SharedViewEventEmitter m_eventEmitter;
145+
winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual m_backgroundVisual { nullptr };
144146

145147
private:
146148
void updateFocusLayoutMetrics() noexcept;

vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ void ImageComponentView::onThemeChanged() noexcept {
236236
Super::onThemeChanged();
237237
}
238238

239+
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ImageComponentView::VisualToApplyBackgroundClipTo() const noexcept
240+
{
241+
return Visual();
242+
}
243+
239244
void ImageComponentView::ensureDrawingSurface() noexcept {
240245
assert(m_reactContext.UIDispatcher().HasThreadAccess());
241246

vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct ImageComponentView : ImageComponentViewT<ImageComponentView, ViewComponen
5252

5353
virtual std::string DefaultControlType() const noexcept;
5454
static facebook::react::SharedViewProps defaultProps() noexcept;
55+
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual VisualToApplyBackgroundClipTo() const noexcept override;
5556

5657
ImageComponentView(
5758
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,

0 commit comments

Comments
 (0)