Skip to content

Commit

Permalink
feat: Basic implementation for detecting layout cycles
Browse files Browse the repository at this point in the history
(cherry picked from commit f2b46b3)
  • Loading branch information
Youssef1313 authored and mergify[bot] committed Jun 13, 2024
1 parent 63d5f47 commit 461d1f3
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 14 deletions.
14 changes: 0 additions & 14 deletions src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml/DebugSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,6 @@ public bool IsXamlResourceReferenceTracingEnabled
}
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::Microsoft.UI.Xaml.LayoutCycleTracingLevel LayoutCycleTracingLevel
{
get
{
throw new global::System.NotImplementedException("The member LayoutCycleTracingLevel DebugSettings.LayoutCycleTracingLevel is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=LayoutCycleTracingLevel%20DebugSettings.LayoutCycleTracingLevel");
}
set
{
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Microsoft.UI.Xaml.DebugSettings", "LayoutCycleTracingLevel DebugSettings.LayoutCycleTracingLevel");
}
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::Microsoft.UI.Xaml.LayoutCycleDebugBreakLevel LayoutCycleDebugBreakLevel
Expand Down
2 changes: 2 additions & 0 deletions src/Uno.UI/UI/Xaml/DebugSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Microsoft.UI.Xaml
{
public sealed partial class DebugSettings
{
public LayoutCycleTracingLevel LayoutCycleTracingLevel { get; set; }

[Uno.NotImplemented]
public bool EnableFrameRateCounter { get; set; }

Expand Down
19 changes: 19 additions & 0 deletions src/Uno.UI/UI/Xaml/FrameworkElement.Layout.crossruntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ void MeasureCoreWithTrace(Size availableSize)

private void InnerMeasureCore(Size availableSize)
{
if (_traceLayoutCycle && this.Log().IsEnabled(LogLevel.Error))
{
this.Log().LogError($"[LayoutCycleTracing] Measuring {this},{this.GetDebugName()} with availableSize {availableSize}.");
}

// Uno TODO
//CLayoutManager* pLayoutManager = VisualTree::GetLayoutManagerForElement(this);
//bool bInLayoutTransition = pLayoutManager ? pLayoutManager->GetTransitioningElement() == this : false;
Expand Down Expand Up @@ -351,6 +356,11 @@ private void InnerMeasureCore(Size availableSize)
desiredSize.Height = LayoutRound(desiredSize.Height);
}

if (_traceLayoutCycle && this.Log().IsEnabled(LogLevel.Error))
{
this.Log().LogError($"[LayoutCycleTracing] Measured {this},{this.GetDebugName()}: desiredSize is {desiredSize}.");
}

#if __SKIA__
if (desiredSize != DesiredSize)
#endif
Expand Down Expand Up @@ -432,6 +442,10 @@ void ArrangeCoreWithTrace(Rect finalRect)
private void InnerArrangeCore(Rect finalRect)
{
_logDebug?.Debug($"{DepthIndentation}{FormatDebugName()}: InnerArrangeCore({finalRect})");
if (_traceLayoutCycle && this.Log().IsEnabled(LogLevel.Error))
{
this.Log().LogError($"[LayoutCycleTracing] Arranging {this},{this.GetDebugName()} with finalRect {finalRect}.");
}

// Uno TODO:
//CLayoutManager* pLayoutManager = VisualTree::GetLayoutManagerForElement(this);
Expand Down Expand Up @@ -719,6 +733,11 @@ private void InnerArrangeCore(Rect finalRect)
var clippedFrame = GetClipRect(needsClipBounds, visualOffset, finalRect, new Size(maxWidth, maxHeight), margin);
ArrangeNative(visualOffset, clippedFrame);

if (_traceLayoutCycle && this.Log().IsEnabled(LogLevel.Error))
{
this.Log().LogError($"[LayoutCycleTracing] Arranged {this},{this.GetDebugName()}: {clippedFrame}.");
}

AfterArrange();
}

Expand Down
10 changes: 10 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.Layout.crossruntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public void InvalidateMeasure()
return;
}

if (_traceLayoutCycle && this.Log().IsEnabled(LogLevel.Error))
{
this.Log().LogError($"[LayoutCycleTracing] InvalidateMeasure {this},{this.GetDebugName()}");
}

SetLayoutFlags(LayoutFlag.MeasureDirty);

if (FeatureConfiguration.UIElement.UseInvalidateMeasurePath && !IsMeasureDirtyPathDisabled)
Expand Down Expand Up @@ -81,6 +86,11 @@ public void InvalidateArrange()
return; // Already dirty
}

if (_traceLayoutCycle && this.Log().IsEnabled(LogLevel.Error))
{
this.Log().LogError($"[LayoutCycleTracing] InvalidateArrange {this},{this.GetDebugName()}");
}

SetLayoutFlags(LayoutFlag.ArrangeDirty);

if (FeatureConfiguration.UIElement.UseInvalidateArrangePath && !IsArrangeDirtyPathDisabled)
Expand Down
13 changes: 13 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace Microsoft.UI.Xaml
{
public partial class UIElement : DependencyObject, IXUidProvider, IUIElement
{
private protected static bool _traceLayoutCycle;
private static readonly TypedEventHandler<UIElement, BringIntoViewRequestedEventArgs> OnBringIntoViewRequestedHandler =
(UIElement sender, BringIntoViewRequestedEventArgs args) => sender.OnBringIntoViewRequested(args);

Expand Down Expand Up @@ -824,6 +825,15 @@ private static void InnerUpdateLayout(UIElement root)

for (var i = MaxLayoutIterations; i > 0; i--)
{
if (i <= 10 && Application.Current is { DebugSettings.LayoutCycleTracingLevel: not LayoutCycleTracingLevel.None })
{
_traceLayoutCycle = true;
if (typeof(UIElement).Log().IsEnabled(LogLevel.Error))
{
typeof(UIElement).Log().LogError($"[LayoutCycleTracing] Low on countdown ({i}).");
}
}

if (root.IsMeasureDirtyOrMeasureDirtyPath)
{
root.Measure(bounds.Size);
Expand Down Expand Up @@ -863,17 +873,20 @@ private static void InnerUpdateLayout(UIElement root)
!root.IsArrangeDirtyOrArrangeDirtyPath &&
!eventManager.HasPendingViewportChangedEvents)
{
_traceLayoutCycle = false;
return;
}
}
#else
else
{
_traceLayoutCycle = false;
return;
}
#endif
}

_traceLayoutCycle = false;
throw new InvalidOperationException("Layout cycle detected.");
#endif
}
Expand Down

0 comments on commit 461d1f3

Please sign in to comment.