Skip to content

Commit baa67da

Browse files
Fixing box with corner radius doesn't have shadow (#15613)
* adding changes for adding shadow for rounded views * Change files
1 parent 27ce28e commit baa67da

File tree

4 files changed

+110
-2
lines changed

4 files changed

+110
-2
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"comment": "adding changes for adding shadow for rounded views",
3+
"type": "prerelease",
4+
"packageName": "react-native-windows",
5+
"email": "protikbiswas@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

vnext/Microsoft.ReactNative/CompositionSwitcher.idl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,16 @@ enum SnapPointsAlignment {
4545
void Opacity(Single value);
4646
void BlurRadius(Single value);
4747
void Color(Windows.UI.Color value);
48+
void Mask(IBrush mask);
49+
void SourcePolicy(CompositionDropShadowSourcePolicy policy);
4850
}
4951

50-
[webhosthidden][experimental] interface IVisual {
52+
[webhosthidden][experimental] enum CompositionDropShadowSourcePolicy {
53+
Default = 0,
54+
InheritedOnly = 1
55+
};
56+
57+
[webhosthidden][experimental] interface IVisual {
5158
void InsertAt(IVisual visual, Int32 index);
5259
void Remove(IVisual visual);
5360
IVisual GetAt(UInt32 index);

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct CompositionTypeTraits<WindowsTypeTag> {
5050
using CompositionStretch = winrt::Windows::UI::Composition::CompositionStretch;
5151
using CompositionStrokeCap = winrt::Windows::UI::Composition::CompositionStrokeCap;
5252
using CompositionSurfaceBrush = winrt::Windows::UI::Composition::CompositionSurfaceBrush;
53+
using CompositionDropShadowSourcePolicy = winrt::Windows::UI::Composition::CompositionDropShadowSourcePolicy;
5354
using Compositor = winrt::Windows::UI::Composition::Compositor;
5455
using ContainerVisual = winrt::Windows::UI::Composition::ContainerVisual;
5556
using CubicBezierEasingFunction = winrt::Windows::UI::Composition::CubicBezierEasingFunction;
@@ -122,6 +123,7 @@ struct CompositionTypeTraits<MicrosoftTypeTag> {
122123
using CompositionStretch = winrt::Microsoft::UI::Composition::CompositionStretch;
123124
using CompositionStrokeCap = winrt::Microsoft::UI::Composition::CompositionStrokeCap;
124125
using CompositionSurfaceBrush = winrt::Microsoft::UI::Composition::CompositionSurfaceBrush;
126+
using CompositionDropShadowSourcePolicy = winrt::Microsoft::UI::Composition::CompositionDropShadowSourcePolicy;
125127
using Compositor = winrt::Microsoft::UI::Composition::Compositor;
126128
using ContainerVisual = winrt::Microsoft::UI::Composition::ContainerVisual;
127129
using CubicBezierEasingFunction = winrt::Microsoft::UI::Composition::CubicBezierEasingFunction;
@@ -218,6 +220,19 @@ struct CompDropShadow : public winrt::implements<
218220
m_shadow.Color(color);
219221
}
220222

223+
void Mask(winrt::Microsoft::ReactNative::Composition::Experimental::IBrush const &mask) noexcept {
224+
if (mask) {
225+
m_shadow.Mask(mask.as<typename TTypeRedirects::IInnerCompositionBrush>()->InnerBrush());
226+
} else {
227+
m_shadow.Mask(nullptr);
228+
}
229+
}
230+
231+
void SourcePolicy(
232+
winrt::Microsoft::ReactNative::Composition::Experimental::CompositionDropShadowSourcePolicy policy) noexcept {
233+
m_shadow.SourcePolicy(static_cast<typename TTypeRedirects::CompositionDropShadowSourcePolicy>(policy));
234+
}
235+
221236
private:
222237
typename TTypeRedirects::DropShadow m_shadow;
223238
};

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

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,86 @@ void ComponentView::applyShadowProps(const facebook::react::ViewProps &viewProps
708708
shadow.Color(theme()->Color(*viewProps.shadowColor));
709709
}
710710

711-
Visual().as<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow(shadow);
711+
// Check if any border radius is set
712+
auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics(m_layoutMetrics, viewProps);
713+
bool hasBorderRadius = borderMetrics.borderRadii.topLeft.horizontal != 0 ||
714+
borderMetrics.borderRadii.topRight.horizontal != 0 || borderMetrics.borderRadii.bottomLeft.horizontal != 0 ||
715+
borderMetrics.borderRadii.bottomRight.horizontal != 0 || borderMetrics.borderRadii.topLeft.vertical != 0 ||
716+
borderMetrics.borderRadii.topRight.vertical != 0 || borderMetrics.borderRadii.bottomLeft.vertical != 0 ||
717+
borderMetrics.borderRadii.bottomRight.vertical != 0;
718+
719+
if (hasBorderRadius) {
720+
// When borderRadius is set, we need to create a shadow mask that follows the rounded rectangle shape.
721+
// Use CompositionVisualSurface to capture the clipped visual's appearance as the shadow mask.
722+
bool maskSet = false;
723+
724+
// Try Microsoft (WinUI3) Composition first
725+
auto msCompositor =
726+
winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerCompositor(
727+
m_compContext);
728+
if (msCompositor) {
729+
auto innerVisual =
730+
winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerVisual(
731+
Visual());
732+
if (innerVisual) {
733+
// Create a VisualSurface that captures the visual (with its clip applied)
734+
auto visualSurface = msCompositor.CreateVisualSurface();
735+
visualSurface.SourceVisual(innerVisual);
736+
visualSurface.SourceSize(
737+
{m_layoutMetrics.frame.size.width * m_layoutMetrics.pointScaleFactor,
738+
m_layoutMetrics.frame.size.height * m_layoutMetrics.pointScaleFactor});
739+
740+
// Create a brush from the visual surface to use as shadow mask
741+
auto maskBrush = msCompositor.CreateSurfaceBrush(visualSurface);
742+
maskBrush.Stretch(winrt::Microsoft::UI::Composition::CompositionStretch::Fill);
743+
744+
// Get the inner shadow and set the mask
745+
auto innerShadow = winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::
746+
InnerDropShadow(shadow);
747+
if (innerShadow) {
748+
innerShadow.Mask(maskBrush);
749+
maskSet = true;
750+
}
751+
}
752+
}
753+
754+
// Fallback to System (Windows.UI) Composition if Microsoft Composition is not available
755+
if (!maskSet) {
756+
auto sysCompositor =
757+
winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerCompositor(
758+
m_compContext);
759+
if (sysCompositor) {
760+
auto innerVisual =
761+
winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerVisual(
762+
Visual());
763+
if (innerVisual) {
764+
auto visualSurface = sysCompositor.CreateVisualSurface();
765+
visualSurface.SourceVisual(innerVisual);
766+
visualSurface.SourceSize(
767+
{m_layoutMetrics.frame.size.width * m_layoutMetrics.pointScaleFactor,
768+
m_layoutMetrics.frame.size.height * m_layoutMetrics.pointScaleFactor});
769+
770+
auto maskBrush = sysCompositor.CreateSurfaceBrush(visualSurface);
771+
maskBrush.Stretch(winrt::Windows::UI::Composition::CompositionStretch::Fill);
772+
773+
auto innerShadow =
774+
winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerDropShadow(
775+
shadow);
776+
if (innerShadow) {
777+
innerShadow.Mask(maskBrush);
778+
}
779+
}
780+
}
781+
}
782+
783+
// Apply shadow to OuterVisual (which is not clipped) so the shadow can extend beyond the clip
784+
OuterVisual().as<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow(shadow);
785+
Visual().as<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow(nullptr);
786+
} else {
787+
// No border radius - apply shadow directly to Visual (original behavior)
788+
Visual().as<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow(shadow);
789+
OuterVisual().as<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow(nullptr);
790+
}
712791
}
713792

714793
void ComponentView::updateTransformProps(

0 commit comments

Comments
 (0)