Skip to content

Fix border inner rounded clip#20647

Closed
wieslawsoltes wants to merge 16 commits intoAvaloniaUI:masterfrom
wieslawsoltes:fix/border-inner-rounded-clip
Closed

Fix border inner rounded clip#20647
wieslawsoltes wants to merge 16 commits intoAvaloniaUI:masterfrom
wieslawsoltes:fix/border-inner-rounded-clip

Conversation

@wieslawsoltes
Copy link

@wieslawsoltes wieslawsoltes commented Feb 9, 2026

PR Summary: Child-Only Layout Clipping, Composition Parity, and Samples

What

  • Add a child-only layout clip API aligned with WPF UIElement.GetLayoutClip.
  • Implement rounded inner-edge child clipping for Border and ContentPresenter when ClipToBounds is enabled.
  • Align immediate rendering, composition rendering, and composition hit-testing with child-only layout clips.
  • Preserve visual rendering while applying child-only clips (background/border unaffected).
  • Fix composition rendering parity for BackgroundSizing on Border and ContentPresenter.
  • Add render tests and expected images for layout-clip geometry and ContentPresenter rounded clipping.
  • Add render tests and baselines for BackgroundSizing parity.
  • Add a ControlCatalog "Child Clipping" page with rounded child clip, adorner clip, and geometry layout clip examples.

How

  • Added Visual.GetLayoutClip(Size layoutSlotSize) and TryGetChildClipCore(...) to provide child-only clips.
  • Stored the arranged layout slot size in Layoutable.Arrange and used it when computing layout clips.
  • Border and ContentPresenter override TryGetChildClipCore to return a rounded inner-edge RoundedRect using GeometryBuilder.CalculateRoundedCornersRectangleWinUI with BackgroundSizing.InnerBorderEdge.
  • Immediate renderer now uses the layout clip around child rendering and keeps the visual clip separate.
  • Composition serialization carries child clip data; server rendering swaps the clip around children only.
  • Composition hit testing respects layout clips regardless of ClipToBounds and without clamping to visual bounds.
  • Composition border visuals now serialize BackgroundSizing to match immediate rendering.

Why

  • Child content should be clipped to rounded inner edges without clipping the control's own background/border.
  • WPF-aligned GetLayoutClip behavior should be based on layout slot size and independent from ClipToBounds.
  • Consistent behavior across immediate and composition render paths is required to avoid visual mismatches.

Behavioral Notes

  • GetLayoutClip affects only children; the visual's own rendering is not clipped.
  • ClipToBounds = true on Border/ContentPresenter yields rounded inner-edge child clipping.
  • ClipToBounds = false does not prevent layout clips provided by GetLayoutClip.
  • Composition and immediate renderers follow the same child-only clip semantics.

Test Coverage

  • GeometryChildClip_Clips_Child
  • GeometryChildClip_Clips_When_ClipToBounds_False
  • GeometryChildClip_Uses_LayoutSlotSize
  • ContentPresenter_RoundedClip_Clips_Child
  • Border_BackgroundSizing_OuterBorderEdge
  • ContentPresenter_BackgroundSizing_OuterBorderEdge
  • New expected images added for the above render tests.

Sample Coverage

  • ControlCatalog "Child Clipping" page shows:
    • Rounded child clipping for Border.
    • Rounded child clipping for ContentPresenter.
    • Adorner clipping respecting rounded bounds.
    • Geometry layout clip example that works without ClipToBounds.

Fixes #2105

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0062051-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0062055-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@robloo
Copy link
Contributor

robloo commented Feb 10, 2026

Awesome! Thanks so much for picking this up. Will definitely dig into the details for my own experience as well.

Comment on lines +224 to +234
bool IVisualWithChildClip.TryGetChildClip(out RoundedRect clip)
{
var bounds = new Rect(Bounds.Size);
var keypoints = GeometryBuilder.CalculateRoundedCornersRectangleWinUI(
bounds,
LayoutThickness,
CornerRadius,
BackgroundSizing.InnerBorderEdge);
clip = keypoints.ToRoundedRect();
return true;
}
Copy link
Contributor

@robloo robloo Feb 10, 2026

Choose a reason for hiding this comment

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

I know this is still draft so won't comment heavily. But should we try to support ALL geometries rather than just RoundedRect here? If someone creates a star-shaped control and needs to clip children this API won't work.

Note: The geometries can get crazy even in WinUI but I guess theoretically for a border are always some form of RoundedRect.

Image

Note: We also need to support clipping in ContentPresenter

Copy link
Contributor

@robloo robloo Feb 10, 2026

Choose a reason for hiding this comment

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

Also note WPF supports arbitrary geometry here as well: https://learn.microsoft.com/en-us/dotnet/api/system.windows.uielement.getlayoutclip

This comment was marked as abuse.

}
}

public Thickness BorderThickness
Copy link
Contributor

Choose a reason for hiding this comment

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

Side comment: BackgroundSizing should be added too I think for border visuals to render the same. This is unrelated to the changes here though.

This comment was marked as abuse.

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0062115-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0062186-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

/// <summary>
/// Attempts to get a child-only clip. By default this uses <see cref="GetLayoutClip"/>.
/// </summary>
protected virtual bool TryGetChildClipCore(out RoundedRect clip, out Geometry? geometryClip)
Copy link
Contributor

Choose a reason for hiding this comment

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

If we look at GetLayoutClip based on WPF:

  • There is no need for anything other than Geometry which covers all cases
  • The return is nullable which means there isn't a need for true/false and Try semantics

I think these TryGetChildClip methods should be the same... just return an nullable Geometry. Is there really such a performance benefit to justify this non-ideal API?

If the method becomes protected virtual Geometry? GetChildClip() why have both it and the GetLayoutClip() method as well? They are actually redundant.

}
}

public BackgroundSizing BackgroundSizing
Copy link
Contributor

Choose a reason for hiding this comment

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

Should all these inheritdoc ? I'm not sure the convention for visuals like this.

protected override void RenderCore(ServerVisualRenderContext ctx, LtrbRect currentTransformedClip)
{
base.RenderCore(ctx, currentTransformedClip);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: missing newline separating methods

{
private CornerRadius _cornerRadius;
private Thickness _borderThickness;
private BackgroundSizing _backgroundSizing;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: missing newline separating fields from method

@robloo
Copy link
Contributor

robloo commented Mar 20, 2026

Is there any chance the core avalonia team will have a chance to go over this? I'm worried it's going to miss 12.0. It's a pretty big flaw at this layer of the code though.

@wieslawsoltes

This comment was marked as abuse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Clipping to rounded corners

3 participants