@@ -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
8283void 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(
214216void 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+
9941004void 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 });
0 commit comments