Skip to content

Commit

Permalink
perf: Misc performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Aug 19, 2023
1 parent ac256db commit 53ca794
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ private static PointerDeviceType GetDeviceType(Gdk.Device sourceDevice)
}

private static bool IsPressed(ModifierType state, ModifierType mask, PointerUpdateKind update, PointerUpdateKind pressed, PointerUpdateKind released)
=> update == pressed || (state.HasFlag(mask) && update != released);
=> update == pressed || (((state & mask) != 0) && update != released);
#endregion

private void RaisePointerEntered(PointerEventArgs ptArgs, [CallerMemberName] string caller = "")
Expand Down
50 changes: 25 additions & 25 deletions src/Uno.UI/UI/Xaml/Controls/Control/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,127 +330,127 @@ private void SubscribeToOverridenRoutedEvents()

var implementedEvents = GetImplementedRoutedEventsForType(GetType());

if (implementedEvents.HasFlag(RoutedEventFlag.PointerPressed))
if ((implementedEvents & RoutedEventFlag.PointerPressed) != 0)
{
PointerPressed += OnPointerPressedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.PointerReleased))
if ((implementedEvents & RoutedEventFlag.PointerReleased) != 0)
{
PointerReleased += OnPointerReleasedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.PointerMoved))
if ((implementedEvents & RoutedEventFlag.PointerMoved) != 0)
{
PointerMoved += OnPointerMovedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.PointerEntered))
if ((implementedEvents & RoutedEventFlag.PointerEntered) != 0)
{
PointerEntered += OnPointerEnteredHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.PointerExited))
if ((implementedEvents & RoutedEventFlag.PointerExited) != 0)
{
PointerExited += OnPointerExitedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.PointerCanceled))
if ((implementedEvents & RoutedEventFlag.PointerCanceled) != 0)
{
PointerCanceled += OnPointerCanceledHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.PointerCaptureLost))
if ((implementedEvents & RoutedEventFlag.PointerCaptureLost) != 0)
{
PointerCaptureLost += OnPointerCaptureLostHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.PointerWheelChanged))
if ((implementedEvents & RoutedEventFlag.PointerWheelChanged) != 0)
{
PointerWheelChanged += OnPointerWheelChangedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.ManipulationStarting))
if ((implementedEvents & RoutedEventFlag.ManipulationStarting) != 0)
{
ManipulationStarting += OnManipulationStartingHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.ManipulationStarted))
if ((implementedEvents & RoutedEventFlag.ManipulationStarted) != 0)
{
ManipulationStarted += OnManipulationStartedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.ManipulationDelta))
if ((implementedEvents & RoutedEventFlag.ManipulationDelta) != 0)
{
ManipulationDelta += OnManipulationDeltaHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.ManipulationInertiaStarting))
if ((implementedEvents & RoutedEventFlag.ManipulationInertiaStarting) != 0)
{
ManipulationInertiaStarting += OnManipulationInertiaStartingHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.ManipulationCompleted))
if ((implementedEvents & RoutedEventFlag.ManipulationCompleted) != 0)
{
ManipulationCompleted += OnManipulationCompletedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.Tapped))
if ((implementedEvents & RoutedEventFlag.Tapped) != 0)
{
Tapped += OnTappedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.DoubleTapped))
if ((implementedEvents & RoutedEventFlag.DoubleTapped) != 0)
{
DoubleTapped += OnDoubleTappedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.RightTapped))
if ((implementedEvents & RoutedEventFlag.RightTapped) != 0)
{
RightTapped += OnRightTappedHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.DragEnter))
if ((implementedEvents & RoutedEventFlag.DragEnter) != 0)
{
DragEnter += OnDragEnterHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.DragOver))
if ((implementedEvents & RoutedEventFlag.DragOver) != 0)
{
DragOver += OnDragOverHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.DragLeave))
if ((implementedEvents & RoutedEventFlag.DragLeave) != 0)
{
DragLeave += OnDragLeaveHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.Drop))
if ((implementedEvents & RoutedEventFlag.Drop) != 0)
{
Drop += OnDropHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.Holding))
if ((implementedEvents & RoutedEventFlag.Holding) != 0)
{
Holding += OnHoldingHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.KeyDown))
if ((implementedEvents & RoutedEventFlag.KeyDown) != 0)
{
KeyDown += OnKeyDownHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.KeyUp))
if ((implementedEvents & RoutedEventFlag.KeyUp) != 0)
{
KeyUp += OnKeyUpHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.GotFocus))
if ((implementedEvents & RoutedEventFlag.GotFocus) != 0)
{
GotFocus += OnGotFocusHandler;
}

if (implementedEvents.HasFlag(RoutedEventFlag.LostFocus))
if ((implementedEvents & RoutedEventFlag.LostFocus) != 0)
{
LostFocus += OnLostFocusHandler;
}
Expand Down
76 changes: 44 additions & 32 deletions src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,15 @@
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using Uno.Collections;
using Uno.Extensions;

using Uno.UI;
using Uno.UI.Extensions;
using Uno.UI.Xaml.Core;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Uno.Extensions;
using Uno.Disposables;
using Windows.Globalization.DateTimeFormatting;
using Windows.UI.Core;
using Uno.Foundation.Logging;
using Uno.UI.Extensions;
using Windows.UI.Xaml.Controls.Primitives;
using Uno.UI.Xaml.Core;
using Uno.UI.DataBinding;
using WinUICoreServices = Uno.UI.Xaml.Core.CoreServices;

#if __IOS__
Expand Down Expand Up @@ -67,19 +61,26 @@ public static IEnumerable<UIElement> FindElementsInHostCoordinates(Point interse
yield return subtree;
}

foreach (var child in subtree.GetChildren().OfType<UIElement>())
foreach (var uiElement in subtree.GetChildren())
{
#if __ANDROID__ || __IOS__ || __MACOS__
// On Wasm and Skia, child is always UIElement.
if (uiElement is not UIElement)
{
continue;
}
#endif
var canTest = includeAllElements
|| (child.IsHitTestVisible && child.IsViewHit());
|| (uiElement.IsHitTestVisible && uiElement.IsViewHit());

if (child is UIElement uiElement && canTest)
if (canTest)
{
if (IsElementIntersecting(intersectingPoint, uiElement))
{
yield return uiElement;
}

foreach (var subChild in FindElementsInHostCoordinates(intersectingPoint, child, includeAllElements))
foreach (var subChild in FindElementsInHostCoordinates(intersectingPoint, uiElement, includeAllElements))
{
yield return subChild;
}
Expand Down Expand Up @@ -111,7 +112,6 @@ public static IEnumerable<UIElement> FindElementsInHostCoordinates(Rect intersec
#else
return (reference as UIElement)?
.GetChildren()
.OfType<DependencyObject>()
.ElementAtOrDefault(childIndex);
#endif
}
Expand All @@ -126,7 +126,6 @@ public static int GetChildrenCount(DependencyObject reference)
#else
return (reference as UIElement)?
.GetChildren()
.OfType<DependencyObject>()
.Count() ?? 0;
#endif
}
Expand Down Expand Up @@ -284,7 +283,7 @@ internal static void AddChild(UIElement view, UIElement child)
view.AddView(child);
#elif __IOS__ || __MACOS__
view.AddSubview(child);
#elif UNO_REFERENCE_API
#elif __CROSSRUNTIME__
view.AddChild(child);
#elif IS_UNIT_TESTS
if (view is FrameworkElement fe)
Expand All @@ -309,7 +308,7 @@ internal static void RemoveChild(UIElement view, UIElement child)
{
child.RemoveFromSuperview();
}
#elif UNO_REFERENCE_API
#elif __CROSSRUNTIME__
view.RemoveChild(child);
#else
throw new NotImplementedException("AddChild not implemented on this platform.");
Expand All @@ -333,7 +332,7 @@ internal static IReadOnlyList<_View> ClearChildren(UIElement view)
children.ForEach(v => v.RemoveFromSuperview());

return children;
#elif UNO_REFERENCE_API
#elif __CROSSRUNTIME__
var children = GetChildren<_View>(view).ToList();
view.ClearChildren();

Expand All @@ -343,11 +342,7 @@ internal static IReadOnlyList<_View> ClearChildren(UIElement view)
#endif
}

internal static readonly GetHitTestability DefaultGetTestability;
static VisualTreeHelper()
{
DefaultGetTestability = elt => (elt.GetHitTestVisibility(), DefaultGetTestability!);
}
internal static readonly GetHitTestability DefaultGetTestability = elt => (elt.GetHitTestVisibility(), DefaultGetTestability!);

internal static (UIElement? element, Branch? stale) HitTest(
Point position,
Expand Down Expand Up @@ -375,8 +370,7 @@ private static (UIElement? element, Branch? stale) SearchDownForTopMostElementAt
Point posRelToParent,
UIElement element,
GetHitTestability getVisibility,
StalePredicate? isStale = null,
Func<IEnumerable<UIElement>, IEnumerable<UIElement>>? childrenFilter = null)
StalePredicate? isStale = null)
{
var stale = default(Branch?);
HitTestability elementHitTestVisibility;
Expand Down Expand Up @@ -464,9 +458,19 @@ private static (UIElement? element, Branch? stale) SearchDownForTopMostElementAt
}

// Validate if any child is an acceptable target
var children = childrenFilter is null ? GetManagedVisualChildren(element) : childrenFilter(GetManagedVisualChildren(element));
using var child = children.Reverse().GetEnumerator();
var children = GetManagedVisualChildren(element);

var isChildStale = isStale;

using var child = children
#if __IOS__ || __MACOS__ || __ANDROID__
.Reverse().GetEnumerator();
#else
// On Skia and Wasm, we can get concrete data structure (MaterializableList in this case) instead of IEnumerable<T>.
// It has an efficient "ReverseEnumerator". This will also avoid the boxing allocations of the enumerator when it's a struct.
.GetReverseEnumerator();
#endif

while (child.MoveNext())
{
var childResult = SearchDownForTopMostElementAt(posRelToElement, child.Current!, getVisibility, isChildStale);
Expand Down Expand Up @@ -571,8 +575,16 @@ internal static UIElement SearchDownForLeaf(UIElement root, StalePredicate predi

private static UIElement SearchDownForLeafCore(UIElement root, StalePredicate predicate)
{
foreach (var child in GetManagedVisualChildren(root).Reverse())
using var enumerator = GetManagedVisualChildren(root)
#if __IOS__ || __MACOS__ || __ANDROID__
.Reverse().GetEnumerator();
#else
.GetReverseEnumerator();
#endif

while (enumerator.MoveNext())
{
var child = enumerator.Current;
#if TRACE_HIT_TESTING
SET_TRACE_SUBJECT(child);
#endif
Expand Down Expand Up @@ -653,8 +665,8 @@ internal static IEnumerable<UIElement> GetManagedVisualChildren(_ViewGroup view)
}
}
#else
internal static IEnumerable<UIElement> GetManagedVisualChildren(_View view)
=> view.GetChildren().OfType<UIElement>();
internal static MaterializableList<UIElement> GetManagedVisualChildren(_View view)
=> view._children;
#endif
#endregion

Expand Down
7 changes: 5 additions & 2 deletions src/Uno.UI/UI/Xaml/UIElement.RoutedEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ internal bool RaiseEvent(RoutedEvent routedEvent, RoutedEventArgs args, Bubbling

// [3] Any local handlers?
var isHandled = IsHandled(args);
if (!ctx.Mode.HasFlag(BubblingMode.IgnoreElement)
if (!ctx.ModeHasFlag(BubblingMode.IgnoreElement)
&& !ctx.IsInternal
&& _eventHandlerStore.TryGetValue(routedEvent, out var handlers)
&& handlers.Any())
Expand Down Expand Up @@ -719,7 +719,7 @@ internal bool RaiseEvent(RoutedEvent routedEvent, RoutedEventArgs args, Bubbling
}
}

if (routedEvent.IsTunnelingEvent || ctx.Mode.HasFlag(BubblingMode.IgnoreParents) || ctx.Root == this)
if (routedEvent.IsTunnelingEvent || ctx.ModeHasFlag(BubblingMode.IgnoreParents) || ctx.Root == this)
{
return isHandled;
}
Expand Down Expand Up @@ -885,6 +885,9 @@ public static BubblingContext BubbleUpTo(UIElement root)
public BubblingContext WithMode(BubblingMode mode)
=> this with { Mode = mode };

public bool ModeHasFlag(BubblingMode flag)
=> (Mode & flag) != 0;

public override string ToString()
=> $"{Mode}{(IsInternal ? " *internal*" : "")}{(Root is { } r ? $" up to {Root.GetDebugName()}" : "")}";
}
Expand Down
2 changes: 0 additions & 2 deletions src/Uno.UI/UI/Xaml/UIElement.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,6 @@ private void InnerRemoveChild(UIElement child)

internal UIElement FindFirstChild() => _children.FirstOrDefault();

partial void InitializeCapture();

internal bool IsPointerCaptured { get; set; }

public virtual IEnumerable<UIElement> GetChildren() => _children;
Expand Down
Loading

0 comments on commit 53ca794

Please sign in to comment.