@@ -210,20 +210,20 @@ private void UpdateVisualOpacityMask(AttachedShadowElementContext context)
210
210
return ;
211
211
}
212
212
213
- // Create a rounded rectangle Visual with a thick outline and no fill, then use a VisualSurface of it as an opacity mask for the shadow.
214
- // This will have the effect of clipping the inner content of the shadow, so that the casting element is not covered by the shadow,
215
- // while the shadow is still rendered outside of the element. Similar to what takes place in GetVisualClip,
216
- // except here we use a brush to mask content instead of a pure geometric clip.
217
- var shapeVisual = context . GetResource ( OpacityMaskShapeVisualResourceKey ) ??
213
+ // Create ShapeVisual, and CompositionSpriteShape with geometry, these will provide the visuals for the opacity mask.
214
+ ShapeVisual shapeVisual = context . GetResource ( OpacityMaskShapeVisualResourceKey ) ??
218
215
context . AddResource ( OpacityMaskShapeVisualResourceKey , context . Compositor . CreateShapeVisual ( ) ) ;
219
216
220
- CompositionRoundedRectangleGeometry geom = context . GetResource ( OpacityMaskGeometryResourceKey ) ??
217
+ CompositionRoundedRectangleGeometry geometry = context . GetResource ( OpacityMaskGeometryResourceKey ) ??
221
218
context . AddResource ( OpacityMaskGeometryResourceKey , context . Compositor . CreateRoundedRectangleGeometry ( ) ) ;
222
219
CompositionSpriteShape shape = context . GetResource ( OpacityMaskSpriteShapeResourceKey ) ??
223
- context . AddResource ( OpacityMaskSpriteShapeResourceKey , context . Compositor . CreateSpriteShape ( geom ) ) ;
220
+ context . AddResource ( OpacityMaskSpriteShapeResourceKey , context . Compositor . CreateSpriteShape ( geometry ) ) ;
224
221
225
- geom . Offset = new Vector2 ( MaxBlurRadius / 2 ) ;
226
- geom . CornerRadius = new Vector2 ( ( MaxBlurRadius / 2 ) + ( float ) CornerRadius ) ;
222
+ // Set the attributes of the geometry, and add the CompositionSpriteShape to the ShapeVisual.
223
+ // The geometry will have a thick outline and no fill, meaning that when used as a mask,
224
+ // the shadow will only be rendered on the outer area covered by the outline, clipping out its inner portion.
225
+ geometry . Offset = new Vector2 ( MaxBlurRadius / 2 ) ;
226
+ geometry . CornerRadius = new Vector2 ( ( MaxBlurRadius / 2 ) + ( float ) CornerRadius ) ;
227
227
shape . StrokeThickness = MaxBlurRadius ;
228
228
shape . StrokeBrush = shape . StrokeBrush ?? context . Compositor . CreateColorBrush ( Colors . Black ) ;
229
229
@@ -232,42 +232,57 @@ private void UpdateVisualOpacityMask(AttachedShadowElementContext context)
232
232
shapeVisual . Shapes . Add ( shape ) ;
233
233
}
234
234
235
- var visualSurface = context . GetResource ( OpacityMaskShapeVisualSurfaceResourceKey ) ??
235
+ // Create CompositionVisualSurface using the ShapeVisual as the source visual.
236
+ CompositionVisualSurface visualSurface = context . GetResource ( OpacityMaskShapeVisualSurfaceResourceKey ) ??
236
237
context . AddResource ( OpacityMaskShapeVisualSurfaceResourceKey , context . Compositor . CreateVisualSurface ( ) ) ;
237
238
visualSurface . SourceVisual = shapeVisual ;
238
239
239
- geom . Size = new Vector2 ( ( float ) context . Element . ActualWidth , ( float ) context . Element . ActualHeight ) + new Vector2 ( MaxBlurRadius ) ;
240
+ geometry . Size = new Vector2 ( ( float ) context . Element . ActualWidth , ( float ) context . Element . ActualHeight ) + new Vector2 ( MaxBlurRadius ) ;
240
241
shapeVisual . Size = visualSurface . SourceSize = new Vector2 ( ( float ) context . Element . ActualWidth , ( float ) context . Element . ActualHeight ) + new Vector2 ( MaxBlurRadius * 2 ) ;
241
242
242
- var surfaceBrush = context . GetResource ( OpacityMaskShapeVisualSurfaceBrushResourceKey ) ??
243
+ // Create a CompositionSurfaceBrush using the CompositionVisualSurface as the source, this essentially converts the ShapeVisual into a brush.
244
+ // This brush can then be used as a mask.
245
+ CompositionSurfaceBrush opacityMask = context . GetResource ( OpacityMaskShapeVisualSurfaceBrushResourceKey ) ??
243
246
context . AddResource ( OpacityMaskShapeVisualSurfaceBrushResourceKey , context . Compositor . CreateSurfaceBrush ( ) ) ;
244
- surfaceBrush . Surface = visualSurface ;
247
+ opacityMask . Surface = visualSurface ;
245
248
}
246
249
247
250
/// <inheritdoc/>
248
251
protected override void SetElementChildVisual ( AttachedShadowElementContext context )
249
252
{
250
- if ( context . TryGetResource ( OpacityMaskShapeVisualSurfaceBrushResourceKey , out var opacityMask ) )
253
+ if ( context . TryGetResource ( OpacityMaskShapeVisualSurfaceBrushResourceKey , out CompositionSurfaceBrush opacityMask ) )
251
254
{
252
- var visualSurface = context . GetResource ( OpacityMaskVisualSurfaceResourceKey ) ??
255
+ // If the resource for OpacityMaskShapeVisualSurfaceBrushResourceKey exists it means this.InnerContentClipMode == CompositionVisualSurface,
256
+ // which means we need to take some steps to set up an opacity mask.
257
+
258
+ // Create a CompositionVisualSurface, and use the SpriteVisual containing the shadow as the source.
259
+ CompositionVisualSurface shadowVisualSurface = context . GetResource ( OpacityMaskVisualSurfaceResourceKey ) ??
253
260
context . AddResource ( OpacityMaskVisualSurfaceResourceKey , context . Compositor . CreateVisualSurface ( ) ) ;
254
- visualSurface . SourceVisual = context . SpriteVisual ;
261
+ shadowVisualSurface . SourceVisual = context . SpriteVisual ;
255
262
context . SpriteVisual . RelativeSizeAdjustment = Vector2 . Zero ;
256
263
context . SpriteVisual . Size = new Vector2 ( ( float ) context . Element . ActualWidth , ( float ) context . Element . ActualHeight ) ;
257
- visualSurface . SourceOffset = new Vector2 ( - MaxBlurRadius ) ;
258
- visualSurface . SourceSize = new Vector2 ( ( float ) context . Element . ActualWidth , ( float ) context . Element . ActualHeight ) + new Vector2 ( MaxBlurRadius * 2 ) ;
259
264
260
- var surfaceBrush = context . GetResource ( OpacityMaskSurfaceBrushResourceKey ) ??
265
+ // Adjust the offset and size of the CompositionVisualSurface to accommodate the thick outline of the shape created in UpdateVisualOpacityMask().
266
+ shadowVisualSurface . SourceOffset = new Vector2 ( - MaxBlurRadius ) ;
267
+ shadowVisualSurface . SourceSize = new Vector2 ( ( float ) context . Element . ActualWidth , ( float ) context . Element . ActualHeight ) + new Vector2 ( MaxBlurRadius * 2 ) ;
268
+
269
+ // Create a CompositionSurfaceBrush from the CompositionVisualSurface. This allows us to render the shadow in a brush.
270
+ CompositionSurfaceBrush shadowSurfaceBrush = context . GetResource ( OpacityMaskSurfaceBrushResourceKey ) ??
261
271
context . AddResource ( OpacityMaskSurfaceBrushResourceKey , context . Compositor . CreateSurfaceBrush ( ) ) ;
262
- surfaceBrush . Surface = visualSurface ;
263
- surfaceBrush . Stretch = CompositionStretch . None ;
272
+ shadowSurfaceBrush . Surface = shadowVisualSurface ;
273
+ shadowSurfaceBrush . Stretch = CompositionStretch . None ;
264
274
275
+ // Create a CompositionMaskBrush, using the CompositionSurfaceBrush of the shadow as the source,
276
+ // and the CompositionSurfaceBrush created in UpdateVisualOpacityMask() as the mask.
277
+ // This creates a brush that renders the shadow with its inner portion clipped out.
265
278
CompositionMaskBrush maskBrush = context . GetResource ( OpacityMaskBrushResourceKey ) ??
266
279
context . AddResource ( OpacityMaskBrushResourceKey , context . Compositor . CreateMaskBrush ( ) ) ;
267
- maskBrush . Source = surfaceBrush ;
280
+ maskBrush . Source = shadowSurfaceBrush ;
268
281
maskBrush . Mask = opacityMask ;
269
282
270
- var visual = context . GetResource ( OpacityMaskVisualResourceKey ) ??
283
+ // Create a SpriteVisual and set its brush to the CompositionMaskBrush created in the previous step,
284
+ // then set it as the child of the element in the context.
285
+ SpriteVisual visual = context . GetResource ( OpacityMaskVisualResourceKey ) ??
271
286
context . AddResource ( OpacityMaskVisualResourceKey , context . Compositor . CreateSpriteVisual ( ) ) ;
272
287
visual . RelativeSizeAdjustment = Vector2 . One ;
273
288
visual . Offset = new Vector3 ( - MaxBlurRadius , - MaxBlurRadius , 0 ) ;
@@ -288,21 +303,21 @@ protected override void SetElementChildVisual(AttachedShadowElementContext conte
288
303
/// <inheritdoc />
289
304
protected internal override void OnSizeChanged ( AttachedShadowElementContext context , Size newSize , Size previousSize )
290
305
{
291
- var sizeAsVec2 = newSize . ToVector2 ( ) ;
306
+ Vector2 sizeAsVec2 = newSize . ToVector2 ( ) ;
292
307
293
- var geometry = context . GetResource ( RoundedRectangleGeometryResourceKey ) ;
308
+ CompositionRoundedRectangleGeometry geometry = context . GetResource ( RoundedRectangleGeometryResourceKey ) ;
294
309
if ( geometry != null )
295
310
{
296
311
geometry . Size = sizeAsVec2 ;
297
312
}
298
313
299
- var visualSurface = context . GetResource ( VisualSurfaceResourceKey ) ;
314
+ CompositionVisualSurface visualSurface = context . GetResource ( VisualSurfaceResourceKey ) ;
300
315
if ( geometry != null )
301
316
{
302
317
visualSurface . SourceSize = sizeAsVec2 ;
303
318
}
304
319
305
- var shapeVisual = context . GetResource ( ShapeVisualResourceKey ) ;
320
+ ShapeVisual shapeVisual = context . GetResource ( ShapeVisualResourceKey ) ;
306
321
if ( geometry != null )
307
322
{
308
323
shapeVisual . Size = sizeAsVec2 ;
0 commit comments