Skip to content

Commit

Permalink
fix(clipping): Fix GH652 - Problem with clipping on both Wasm & Skia
Browse files Browse the repository at this point in the history
  • Loading branch information
carldebilly committed Sep 8, 2020
1 parent ca7cc49 commit 703242b
Show file tree
Hide file tree
Showing 17 changed files with 68 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
This is an illustration of Github bug
<Hyperlink NavigateUri="https://github.com/unoplatform/uno/issues/652">#652</Hyperlink>
</TextBlock>
<Grid Width="100" Height="100" BorderBrush="Red" BorderThickness="1">
<Grid Width="100" Height="100" BorderBrush="Red" BorderThickness="1" x:Name="Grid1">
<Grid.Clip>
<RectangleGeometry Rect="0,0,110,110" />
</Grid.Clip>
Expand All @@ -21,7 +21,8 @@
Height="100"
Content="Hello world"
VerticalAlignment="Top"
HorizontalAlignment="Left">
HorizontalAlignment="Left"
x:Name="Button1">
<ToggleButton.RenderTransform>
<TranslateTransform X="50" Y="50"/>
</ToggleButton.RenderTransform>
Expand All @@ -31,7 +32,7 @@
It should be identical to this:
<LineBreak />(the button should be 100x100, but cut at 60x60)
</TextBlock>
<Grid HorizontalAlignment="Center">
<Grid HorizontalAlignment="Center" x:Name="Grid2">
<Border Width="100" Height="100" BorderBrush="Red" BorderThickness="1" VerticalAlignment="Top" HorizontalAlignment="Left" />
<Border Width="60" Height="60" VerticalAlignment="Top" HorizontalAlignment="Left">
<Border.RenderTransform>
Expand All @@ -41,7 +42,8 @@
Height="100"
Width="100"
VerticalAlignment="Top"
Content="Hello world" />
Content="Hello world"
x:Name="Button2"/>
</Border>
</Grid>
</StackPanel>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using Windows.UI.Xaml.Controls;
using System;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using Uno.UI.Samples.Controls;

using Uno.UI;

namespace UITests.Windows_UI_Xaml.Clipping
{
[Sample("Clipping", "GH Bugs")]
Expand All @@ -9,6 +13,17 @@ public sealed partial class ButtonClipping652 : Page
public ButtonClipping652()
{
this.InitializeComponent();

DumpTree();
}

private async void DumpTree()
{
#if NETSTANDARD
await Task.Delay(1200);
var tree = this.ShowLocalVisualTree();
System.Diagnostics.Debug.WriteLine(tree);
#endif
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<UserControl
<Page
x:Class="SamplesApp.Windows_UI_Xaml.Clipping.ButtonClippingTestsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Expand Down Expand Up @@ -133,4 +133,4 @@
</StackPanel>
</StackPanel>
</ScrollViewer>
</UserControl>
</Page>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace SamplesApp.Windows_UI_Xaml.Clipping
{
[SampleControlInfo("Clipping", viewModelType: typeof(ButtonTestsViewModel))]
public sealed partial class ButtonClippingTestsControl : UserControl
public sealed partial class ButtonClippingTestsControl : Page
{
public ButtonClippingTestsControl()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/Controls/Image/Image.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ protected override Size ArrangeOverride(Size finalSize)
// Calculate the position of the image to follow stretch and alignment requirements
var finalPosition = this.ArrangeSource(finalSize, containerSize);

_htmlImage.ArrangeVisual(finalPosition, false, clipRect: null);
_htmlImage.ArrangeVisual(finalPosition, clipRect: null);

if (this.Log().IsEnabled(LogLevel.Debug))
{
Expand Down
38 changes: 18 additions & 20 deletions src/Uno.UI/UI/Xaml/FrameworkElement.Layout.netstd.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#if !__NETSTD_REFERENCE__
#nullable enable
using System;
using System.Globalization;
using System.Linq;
Expand Down Expand Up @@ -165,12 +166,12 @@ private void InnerArrangeCore(Rect finalRect)
{
if (IsLessThanAndNotCloseTo(arrangeSize.Width, _unclippedDesiredSize.Width))
{
_logDebug?.Debug($"{DepthIndentation}{FormatDebugName()}: (arrangeSize.Width) {arrangeSize.Width} < {_unclippedDesiredSize.Width}: NEEDS CLIPPING.");
_logDebug?.Trace($"{DepthIndentation}{FormatDebugName()}: (arrangeSize.Width) {arrangeSize.Width} < {_unclippedDesiredSize.Width}: NEEDS CLIPPING.");
needsClipToSlot = true;
}
else if (IsLessThanAndNotCloseTo(arrangeSize.Height, _unclippedDesiredSize.Height))
{
_logDebug?.Debug($"{DepthIndentation}{FormatDebugName()}: (arrangeSize.Height) {arrangeSize.Height} < {_unclippedDesiredSize.Height}: NEEDS CLIPPING.");
_logDebug?.Trace($"{DepthIndentation}{FormatDebugName()}: (arrangeSize.Height) {arrangeSize.Height} < {_unclippedDesiredSize.Height}: NEEDS CLIPPING.");
needsClipToSlot = true;
}
}
Expand All @@ -196,13 +197,13 @@ private void InnerArrangeCore(Rect finalRect)
{
if (IsLessThanAndNotCloseTo(effectiveMaxSize.Width, arrangeSize.Width))
{
_logDebug?.Debug($"{DepthIndentation}{FormatDebugName()}: (effectiveMaxSize.Width) {effectiveMaxSize.Width} < {arrangeSize.Width}: NEEDS CLIPPING.");
_logDebug?.Trace($"{DepthIndentation}{FormatDebugName()}: (effectiveMaxSize.Width) {effectiveMaxSize.Width} < {arrangeSize.Width}: NEEDS CLIPPING.");
needsClipToSlot = true;
arrangeSize.Width = effectiveMaxSize.Width;
}
if (IsLessThanAndNotCloseTo(effectiveMaxSize.Height, arrangeSize.Height))
{
_logDebug?.Debug($"{DepthIndentation}{FormatDebugName()}: (effectiveMaxSize.Height) {effectiveMaxSize.Height} < {arrangeSize.Height}: NEEDS CLIPPING.");
_logDebug?.Trace($"{DepthIndentation}{FormatDebugName()}: (effectiveMaxSize.Height) {effectiveMaxSize.Height} < {arrangeSize.Height}: NEEDS CLIPPING.");
needsClipToSlot = true;
arrangeSize.Height = effectiveMaxSize.Height;
}
Expand Down Expand Up @@ -240,12 +241,12 @@ private void InnerArrangeCore(Rect finalRect)
_logDebug?.Debug(
$"{DepthIndentation}[{FormatDebugName()}] ArrangeChild(offset={offset}, margin={margin}) [oldRenderSize={oldRenderSize}] [RenderSize={RenderSize}] [clippedInkSize={clippedInkSize}] [RequiresClipping={needsClipToSlot}]");

RequiresClipping = needsClipToSlot;
NeedsClipToSlot = needsClipToSlot;

#if __WASM__
if (FeatureConfiguration.UIElement.AssignDOMXamlProperties)
{
UpdateDOMXamlProperty(nameof(RequiresClipping), RequiresClipping);
UpdateDOMXamlProperty(nameof(NeedsClipToSlot), NeedsClipToSlot);
}
#endif

Expand All @@ -266,11 +267,11 @@ private void InnerArrangeCore(Rect finalRect)
clippedFrameWithParentOrigin.Width,
clippedFrameWithParentOrigin.Height);

ArrangeNative(offset, clippedFrame);
ArrangeNative(offset, true, clippedFrame);
}
else
{
ArrangeNative(offset);
ArrangeNative(offset, false);
}

OnLayoutUpdated();
Expand All @@ -280,8 +281,9 @@ private void InnerArrangeCore(Rect finalRect)
/// Calculates and applies native arrange properties.
/// </summary>
/// <param name="offset">Offset of the view from its parent</param>
/// <param name="needsClipToSlot">If the control should be clip to its bounds</param>
/// <param name="clippedFrame">Zone to clip, if clipping is required</param>
private void ArrangeNative(Point offset, Rect clippedFrame = default)
private void ArrangeNative(Point offset, bool needsClipToSlot, Rect clippedFrame = default)
{
_visualOffset = offset;

Expand All @@ -301,25 +303,21 @@ private void ArrangeNative(Point offset, Rect clippedFrame = default)

Rect? getClip()
{
// Clip transform not supported yet on Wasm
// Clip transform not supported yet on Wasm/Skia

if (RequiresClipping) // if control should be clipped by layout constrains
var clip = Clip;
if (clip == null)
{
if (Clip != null)
{
return clippedFrame.IntersectWith(Clip.Rect);
}
return clippedFrame;
return !needsClipToSlot ? (Rect?) null : clippedFrame;
}

return Clip?.Rect;
return clip.Rect;
}

var clipRect = getClip();

_logDebug?.Trace($"{DepthIndentation}{FormatDebugName()}.ArrangeElementNative({newRect}, clip={clipRect} (RequiresClipping={RequiresClipping})");
_logDebug?.Trace($"{DepthIndentation}{FormatDebugName()}.ArrangeElementNative({newRect}, clip={clipRect} (NeedsClipToSlot={NeedsClipToSlot})");

ArrangeVisual(newRect, RequiresClipping, clipRect);
ArrangeVisual(newRect, clipRect);
}
}
}
Expand Down
8 changes: 2 additions & 6 deletions src/Uno.UI/UI/Xaml/Media/RectangleGeometry.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Text;
using Windows.Foundation;
#if XAMARIN_IOS
using UIKit;
Expand All @@ -18,8 +14,8 @@ public RectangleGeometry() { }

public Rect Rect
{
get { return (Rect)this.GetValue(RectProperty); }
set { this.SetValue(RectProperty, value); }
get => (Rect)this.GetValue(RectProperty);
set => this.SetValue(RectProperty, value);
}

public static DependencyProperty RectProperty { get ; } =
Expand Down
30 changes: 10 additions & 20 deletions src/Uno.UI/UI/Xaml/UIElement.Skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ partial void OnRenderTransformSet()
{
}

internal void ArrangeVisual(Rect finalRect, bool clipToBounds, Rect? clippedFrame = default)
internal void ArrangeVisual(Rect finalRect, Rect? clippedFrame = default)
{
LayoutSlotWithMarginsAndAlignments =
VisualTreeHelper.GetParent(this) is UIElement parent
Expand All @@ -260,27 +260,17 @@ internal void ArrangeVisual(Rect finalRect, bool clipToBounds, Rect? clippedFram
throw new InvalidOperationException($"{this}: Invalid frame size {newRect}. No dimension should be NaN or negative value.");
}

Rect? getClip()
Rect? clip;
if (this is Controls.ScrollViewer)
{
if (this is Controls.ScrollViewer)
{
return null;
}
else if (ClippingIsSetByCornerRadius)
{
// The clip geometry is set by the corner radius
// of Border, Grid, StackPanel, etc...
return null;
}
else if (Clip != null)
{
return Clip.Rect;
}

return new Rect(0, 0, newRect.Width, newRect.Height);
clip = (Rect?)null;
}
else
{
clip = clippedFrame;
}

OnArrangeVisual(newRect, getClip());
OnArrangeVisual(newRect, clip);
}
else
{
Expand All @@ -307,7 +297,7 @@ internal virtual void OnArrangeVisual(Rect rect, Rect? clip)
rightInset: (float)roundedRectClip.Right
);
}
else
else if (!ClippingIsSetByCornerRadius)
{
Visual.Clip = null;
}
Expand Down
2 changes: 0 additions & 2 deletions src/Uno.UI/UI/Xaml/UIElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ string IXUidProvider.Uid

partial void OnUidChangedPartial();

private protected bool RequiresClipping { get; set; } = true;

#region Clip DependencyProperty

public RectangleGeometry Clip
Expand Down
30 changes: 3 additions & 27 deletions src/Uno.UI/UI/Xaml/UIElement.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,8 @@ protected internal void SetClasses(string[] cssClasses, int index = -1)
/// Natively arranges and clips an element.
/// </summary>
/// <param name="rect">The dimensions to apply to the element</param>
/// <param name="clipToBounds">Whether the element should be clipped to its bounds</param>
/// <param name="clipRect">The Clip rect to set, if any</param>
protected internal void ArrangeVisual(Rect rect, bool clipToBounds, Rect? clipRect)
protected internal void ArrangeVisual(Rect rect, Rect? clipRect)
{
LayoutSlotWithMarginsAndAlignments =
VisualTreeHelper.GetParent(this) is UIElement parent
Expand All @@ -262,7 +261,7 @@ protected internal void ArrangeVisual(Rect rect, bool clipToBounds, Rect? clipRe
UpdateDOMXamlProperty(nameof(LayoutSlotWithMarginsAndAlignments), LayoutSlotWithMarginsAndAlignments);
}

Uno.UI.Xaml.WindowManagerInterop.ArrangeElement(HtmlId, rect, clipToBounds, clipRect);
Uno.UI.Xaml.WindowManagerInterop.ArrangeElement(HtmlId, rect, clipRect);

#if DEBUG
var count = ++_arrangeCount;
Expand All @@ -273,7 +272,7 @@ protected internal void ArrangeVisual(Rect rect, bool clipToBounds, Rect? clipRe

protected internal void SetNativeTransform(Matrix3x2 matrix)
{
Uno.UI.Xaml.WindowManagerInterop.SetElementTransform(HtmlId, matrix, requiresClipping: RequiresClipping);
Uno.UI.Xaml.WindowManagerInterop.SetElementTransform(HtmlId, matrix);
}

protected internal void ResetStyle(params string[] names)
Expand Down Expand Up @@ -332,29 +331,6 @@ protected internal void SetHtmlContent(string html)
Uno.UI.Xaml.WindowManagerInterop.SetContentHtml(HtmlId, html);
}

partial void ApplyNativeClip(Rect rect)
{

if (rect.IsEmpty)
{
SetStyle("clip", "");
return;
}

var width = double.IsInfinity(rect.Width) ? 100000.0f : rect.Width;
var height = double.IsInfinity(rect.Height) ? 100000.0f : rect.Height;

SetStyle(
"clip",
"rect("
+ Math.Floor(rect.Y) + "px,"
+ Math.Ceiling(rect.X + width) + "px,"
+ Math.Ceiling(rect.Y + height) + "px,"
+ Math.Floor(rect.X) + "px"
+ ")"
);
}

internal static UIElement GetElementFromHandle(int handle)
{
var gcHandle = GCHandle.FromIntPtr((IntPtr)handle);
Expand Down
Loading

0 comments on commit 703242b

Please sign in to comment.