Skip to content

Commit

Permalink
feat(element_measure_dirth_path_disabled): Added the ability to deact…
Browse files Browse the repository at this point in the history
…ivate the new InvalidateMeasureDirtyPath at element-level instead of just globally
  • Loading branch information
carldebilly committed Feb 4, 2022
1 parent a1b0697 commit 6779b34
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/Uno.UI/Extensions/ViewExtensions.netstd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ StringBuilder AppendView(UIElement innerView)
.Append(uiElement?.RenderTransform.GetTransformDetails())
.Append(uiElement?.IsMeasureDirty is true ? " MEASURE_DIRTY" : "")
.Append(uiElement?.IsMeasureDirtyPath is true ? " MEASURE_DIRTY_PATH" : "")
.Append(uiElement?.IsMeasureDirtyPathDisabled is true ? " MEASURE_DIRTY_PATH_DISABLED" : "")
.Append(uiElement?.IsArrangeDirty is true ? " ARRANGE_DIRTY" : "")
.AppendLine();
}
Expand Down
44 changes: 41 additions & 3 deletions src/Uno.UI/UI/Xaml/FrameworkElementHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static class FrameworkElementHelper
/// ElementNameSubject and TargetProperty path to only keep weak references
/// to their targets.
/// </summary>
private static ConditionalWeakTable<DependencyObject, object> _contextAssociation = new ConditionalWeakTable<DependencyObject, object>();
private static readonly ConditionalWeakTable<DependencyObject, object> _contextAssociation = new ConditionalWeakTable<DependencyObject, object>();

/// <summary>
/// Set the rendering phase, defined via x:Phase.
Expand Down Expand Up @@ -49,7 +49,7 @@ public static void SetDataTemplateRenderPhases(FrameworkElement target, int[] de

public static void SetBaseUri(FrameworkElement target, string uri)
{
if (target is FrameworkElement fe)
if (target is { } fe)
{
fe.BaseUri = new Uri(uri);
}
Expand All @@ -63,8 +63,46 @@ public static void SetBaseUri(FrameworkElement target, string uri)
/// code alive alonside the top-level control of thete.
/// </remarks>
public static void AddObjectReference(DependencyObject target, object context)
=> _contextAssociation.Add(target, context);

/// <summary>
/// This is the equivalent of <see cref="FeatureConfiguration.UIElement.UseInvalidateMeasurePath"/>
/// but just for a specific element (and its descendants) in the visual tree.
/// </summary>
/// <remarks>
/// This will have no effect is <see cref="FeatureConfiguration.UIElement.UseInvalidateMeasurePath"/>
/// is set to false.
/// </remarks>
#if !(__WASM__ || __SKIA__)
[NotImplemented]
#endif
public static void SetUseMeasurePathDisabled(UIElement element, bool state = true, bool eager = true, bool invalidate = true)
{
_contextAssociation.Add(target, context);
#if __WASM__ || __SKIA__
element.IsMeasureDirtyPathDisabled = state;

if (eager)
{
using var children = element.GetChildren().GetEnumerator();
while (children.MoveNext())
{
if (children.Current is { } child)
{
SetUseMeasurePathDisabled(child, state, eager: true, invalidate);
}
}
}

if (invalidate)
{
element.InvalidateMeasure();
}
#else
// Not implemented for this platform
#endif
}

public static bool GetUseMeasurePathDisabled(FrameworkElement element)
=> element.IsMeasureDirtyPathDisabled;
}
}
42 changes: 39 additions & 3 deletions src/Uno.UI/UI/Xaml/UIElement.Layout.netstd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ private protected enum LayoutFlag : byte
/// </summary>
FirstMeasureDone = 0b0000_0100,

/// <summary>
/// Means the MeasureDirtyPath is disabled on this element.
/// </summary>
/// <remarks>
/// This flag is copied to children when they are attached, but can be re-enabled afterwards.
/// This flag is used during invalidation
/// </remarks>
MeasureDirtyPathDisabled = 0b0000_1000,

/// <summary>
/// Means the Arrange is dirty on the current element or one of its child
/// </summary>
Expand All @@ -47,6 +56,11 @@ private protected enum LayoutFlag : byte
}

private const LayoutFlag DEFAULT_STARTING_LAYOUTFLAGS = 0;
private const LayoutFlag LAYOUT_FLAGS_TO_CLEAR_ON_RESET =
LayoutFlag.MeasureDirty |
LayoutFlag.MeasureDirtyPath |
LayoutFlag.FirstMeasureDone |
LayoutFlag.ArrangeDirty;

private LayoutFlag _layoutFlags = DEFAULT_STARTING_LAYOUTFLAGS;

Expand All @@ -68,17 +82,30 @@ private protected enum LayoutFlag : byte
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private protected void SetLayoutFlags(LayoutFlag flags) => _layoutFlags |= flags;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private protected void SetLayoutFlags(LayoutFlag flags, bool state)
{
if (state)
{
SetLayoutFlags(flags);
}
else
{
ClearLayoutFlags(flags);
}
}

/// <summary>
/// Reset one or many flags (set flag to zero)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private protected void ClearLayoutFlags(LayoutFlag flag) => _layoutFlags &= ~flag;
private protected void ClearLayoutFlags(LayoutFlag flags) => _layoutFlags &= ~flags;

/// <summary>
/// Reset flags to original state
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private protected void ResetLayoutFlags() => _layoutFlags = DEFAULT_STARTING_LAYOUTFLAGS;
private protected void ResetLayoutFlags() => ClearLayoutFlags(LAYOUT_FLAGS_TO_CLEAR_ON_RESET);

internal bool IsMeasureDirty
{
Expand All @@ -104,6 +131,15 @@ internal bool IsArrangeDirty
get => IsLayoutFlagSet(LayoutFlag.ArrangeDirty);
}

internal bool IsMeasureDirtyPathDisabled
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => IsLayoutFlagSet(LayoutFlag.MeasureDirtyPathDisabled);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => SetLayoutFlags(LayoutFlag.MeasureDirtyPathDisabled, value);
}

public void InvalidateMeasure()
{
if (ShouldInterceptInvalidate)
Expand All @@ -118,7 +154,7 @@ public void InvalidateMeasure()

SetLayoutFlags(LayoutFlag.MeasureDirty);

if (FeatureConfiguration.UIElement.UseInvalidateMeasurePath)
if (FeatureConfiguration.UIElement.UseInvalidateMeasurePath && !IsMeasureDirtyPathDisabled)
{
InvalidateParentMeasurePath();
}
Expand Down
9 changes: 8 additions & 1 deletion src/Uno.UI/UI/Xaml/UIElement.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,14 @@ public void AddChild(UIElement child, int? index = null)
// Reset to original (invalidated) state
child.ResetLayoutFlags();

child.InvalidateMeasure();
if (IsMeasureDirtyPathDisabled)
{
FrameworkElementHelper.SetUseMeasurePathDisabled(child); // will invalidate too
}
else
{
child.InvalidateMeasure();
}

if (child.IsArrangeDirty && !IsArrangeDirty)
{
Expand Down
9 changes: 8 additions & 1 deletion src/Uno.UI/UI/Xaml/UIElement.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,14 @@ public void AddChild(UIElement child, int? index = null)

child.ResetLayoutFlags();

child.InvalidateMeasure();
if (IsMeasureDirtyPathDisabled)
{
FrameworkElementHelper.SetUseMeasurePathDisabled(child, eager: true, invalidate: true);
}
else
{
child.InvalidateMeasure();
}

// Arrange is required to unset the uno-unarranged CSS class
child.InvalidateArrange();
Expand Down

0 comments on commit 6779b34

Please sign in to comment.