Skip to content

Commit

Permalink
perf: Skip ClearPointersStateIfNeeded during ctor
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed May 25, 2021
1 parent b0e1839 commit 7d74f48
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 62 deletions.
14 changes: 12 additions & 2 deletions src/Uno.UI/UI/Xaml/FrameworkPropertyMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,24 @@ CoerceValueCallback coerceValueCallback
) : base(defaultValue, propertyChangedCallback, coerceValueCallback, null)
{
}

internal FrameworkPropertyMetadata(
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback
) : base(propertyChangedCallback, coerceValueCallback)
{
}


internal FrameworkPropertyMetadata(
object defaultValue,
FrameworkPropertyMetadataOptions options,
BackingFieldUpdateCallback backingFieldUpdateCallback,
CoerceValueCallback coerceValueCallback
) : base(defaultValue: defaultValue, propertyChangedCallback: null, coerceValueCallback: coerceValueCallback, backingFieldUpdateCallback: backingFieldUpdateCallback)
{
Options = options.WithDefault();
}

internal FrameworkPropertyMetadata(
object defaultValue,
FrameworkPropertyMetadataOptions options,
Expand Down
51 changes: 28 additions & 23 deletions src/Uno.UI/UI/Xaml/UIElement.Pointers.Managed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Uno.UI;
using Uno.UI.Xaml;

namespace Windows.UI.Xaml
{
Expand Down Expand Up @@ -274,7 +275,7 @@ private void ClearPressedState(PointerRoutedEventArgs routedArgs)
}
}

#region Helpers
#region Helpers
private delegate void RaisePointerEventArgs(UIElement element, PointerRoutedEventArgs args, BubblingContext ctx);

private static readonly RaisePointerEventArgs Wheel = (elt, args, ctx) => elt.OnPointerWheel(args, ctx);
Expand Down Expand Up @@ -340,7 +341,7 @@ private static void RaiseUsingCaptures(RaisePointerEventArgs raise, UIElement or
raise(originalSource, routedArgs, BubblingContext.Bubble);
}
}
#endregion
#endregion
}

// TODO Should be per CoreWindow
Expand All @@ -354,7 +355,7 @@ partial void InitializePointersPartial()
}
}

#region HitTestVisibility
#region HitTestVisibility
internal void UpdateHitTest()
{
this.CoerceValue(HitTestVisibilityProperty);
Expand All @@ -366,27 +367,21 @@ internal void UpdateHitTest()
/// <remarks>
/// This property should never be directly set, and its value should always be calculated through coercion (see <see cref="CoerceHitTestVisibility(DependencyObject, object, bool)"/>.
/// </remarks>
private static readonly DependencyProperty HitTestVisibilityProperty =
DependencyProperty.Register(
"HitTestVisibility",
typeof(HitTestability),
typeof(UIElement),
new FrameworkPropertyMetadata(
HitTestability.Visible,
FrameworkPropertyMetadataOptions.Inherits,
coerceValueCallback: CoerceHitTestVisibility,
propertyChangedCallback: OnHitTestVisibilityChanged
)
);
[GeneratedDependencyProperty(DefaultValue = HitTestability.Collapsed, CoerceCallback = true, Options = FrameworkPropertyMetadataOptions.Inherits)]
internal static DependencyProperty HitTestVisibilityProperty { get; } = CreateHitTestVisibilityProperty();

internal HitTestability HitTestVisibility
{
get => GetHitTestVisibilityValue();
set => SetHitTestVisibilityValue(value);
}

/// <summary>
/// This calculates the final hit-test visibility of an element.
/// </summary>
/// <returns></returns>
private static object CoerceHitTestVisibility(DependencyObject dependencyObject, object baseValue)
private object CoerceHitTestVisibility(object baseValue)
{
var element = (UIElement)dependencyObject;

// The HitTestVisibilityProperty is never set directly. This means that baseValue is always the result of the parent's CoerceHitTestVisibility.
var baseHitTestVisibility = (HitTestability)baseValue;

Expand All @@ -399,15 +394,15 @@ private static object CoerceHitTestVisibility(DependencyObject dependencyObject,
// If we're not locally hit-test visible, visible, or enabled, we should be collapsed. Our children will be collapsed as well.
if (
#if !__MACOS__
!element.IsLoaded ||
!IsLoaded ||
#endif
!element.IsHitTestVisible || element.Visibility != Visibility.Visible || !element.IsEnabledOverride())
!IsHitTestVisible || Visibility != Visibility.Visible || !IsEnabledOverride())
{
return HitTestability.Collapsed;
}

// If we're not hit (usually means we don't have a Background/Fill), we're invisible. Our children will be visible or not, depending on their state.
if (!element.IsViewHit())
if (!IsViewHit())
{
return HitTestability.Invisible;
}
Expand All @@ -416,10 +411,20 @@ private static object CoerceHitTestVisibility(DependencyObject dependencyObject,
return HitTestability.Visible;
}

private static void OnHitTestVisibilityChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
internal void SetHitTestVisibilityForRoot()
{
// Root element must be visible to hit testing, regardless of the other properties values.
// The default value of HitTestVisibility is collapsed to avoid spending time coercing to a
// Collapsed.
HitTestVisibility = HitTestability.Visible;
}
#endregion

internal void ClearHitTestVisibilityForRoot()
{
this.ClearValue(HitTestVisibilityProperty);
}

#endregion

partial void CapturePointerNative(Pointer pointer)
=> CoreWindow.GetForCurrentThread()!.SetPointerCapture();
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/UIElement.Pointers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ private void InitializePointers()
internal HitTestability GetHitTestVisibility()
{
#if __WASM__ || __SKIA__
return (HitTestability)this.GetValue(HitTestVisibilityProperty);
return HitTestVisibility;
#else
// This is a coalesced HitTestVisible and should be unified with it
// We should follow the WASM way and unify it on all platforms!
Expand Down
61 changes: 29 additions & 32 deletions src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,33 +265,21 @@ internal void UpdateHitTest()
this.CoerceValue(HitTestVisibilityProperty);
}

/// <summary>
/// Represents the final calculated hit-test visibility of the element.
/// </summary>
/// <remarks>
/// This property should never be directly set, and its value should always be calculated through coercion (see <see cref="CoerceHitTestVisibility(DependencyObject, object, bool)"/>.
/// </remarks>
private static DependencyProperty HitTestVisibilityProperty { get ; } =
DependencyProperty.Register(
"HitTestVisibility",
typeof(HitTestability),
typeof(UIElement),
new FrameworkPropertyMetadata(
HitTestability.Visible,
FrameworkPropertyMetadataOptions.Inherits,
coerceValueCallback: (s, e) => CoerceHitTestVisibility(s, e),
propertyChangedCallback: (s, e) => OnHitTestVisibilityChanged(s, e)
)
);
[GeneratedDependencyProperty(DefaultValue = HitTestability.Collapsed, ChangedCallback = true, CoerceCallback = true, Options = FrameworkPropertyMetadataOptions.Inherits)]
internal static DependencyProperty HitTestVisibilityProperty { get; } = CreateHitTestVisibilityProperty();

internal HitTestability HitTestVisibility
{
get => GetHitTestVisibilityValue();
set => SetHitTestVisibilityValue(value);
}

/// <summary>
/// This calculates the final hit-test visibility of an element.
/// </summary>
/// <returns></returns>
private static object CoerceHitTestVisibility(DependencyObject dependencyObject, object baseValue)
private object CoerceHitTestVisibility(object baseValue)
{
var element = (UIElement)dependencyObject;

// The HitTestVisibilityProperty is never set directly. This means that baseValue is always the result of the parent's CoerceHitTestVisibility.
var baseHitTestVisibility = (HitTestability)baseValue;

Expand All @@ -302,13 +290,13 @@ private static object CoerceHitTestVisibility(DependencyObject dependencyObject,
}

// If we're not locally hit-test visible, visible, or enabled, we should be collapsed. Our children will be collapsed as well.
if (!element.IsLoaded || !element.IsHitTestVisible || element.Visibility != Visibility.Visible || !element.IsEnabledOverride())
if (!IsLoaded || !IsHitTestVisible || Visibility != Visibility.Visible || !IsEnabledOverride())
{
return HitTestability.Collapsed;
}

// If we're not hit (usually means we don't have a Background/Fill), we're invisible. Our children will be visible or not, depending on their state.
if (!element.IsViewHit())
if (!IsViewHit())
{
return HitTestability.Invisible;
}
Expand All @@ -317,19 +305,14 @@ private static object CoerceHitTestVisibility(DependencyObject dependencyObject,
return HitTestability.Visible;
}

private static void OnHitTestVisibilityChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
private protected virtual void OnHitTestVisibilityChanged(HitTestability oldValue, HitTestability newValue)
{
if (dependencyObject is UIElement element
&& args.OldValue is HitTestability oldValue
&& args.NewValue is HitTestability newValue)
{
element.OnHitTestVisibilityChanged(oldValue, newValue);
}
ApplyHitTestVisibility(newValue);
}

private protected virtual void OnHitTestVisibilityChanged(HitTestability oldValue, HitTestability newValue)
private void ApplyHitTestVisibility(HitTestability value)
{
if (newValue == HitTestability.Visible)
if (value == HitTestability.Visible)
{
// By default, elements have 'pointer-event' set to 'auto' (see Uno.UI.css .uno-uielement class).
// This means that they can be the target of hit-testing and will raise pointer events when interacted with.
Expand All @@ -349,6 +332,20 @@ private protected virtual void OnHitTestVisibilityChanged(HitTestability oldValu
UpdateDOMProperties();
}
}

internal void SetHitTestVisibilityForRoot()
{
// Root element must be visible to hit testing, regardless of the other properties values.
// The default value of HitTestVisibility is collapsed to avoid spending time coercing to a
// Collapsed.
HitTestVisibility = HitTestability.Visible;
}

internal void ClearHitTestVisibilityForRoot()
{
this.ClearValue(HitTestVisibilityProperty);
}

#endregion

// TODO: This should be marshaled instead of being parsed! https://github.com/unoplatform/uno/issues/2116
Expand Down
10 changes: 8 additions & 2 deletions src/Uno.UI/UI/Xaml/UIElement.netstd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,16 @@ internal static void LoadingRootElement(UIElement visualTreeRoot)
=> visualTreeRoot.OnElementLoading(1);

internal static void RootElementLoaded(UIElement visualTreeRoot)
=> visualTreeRoot.OnElementLoaded();
{
visualTreeRoot.SetHitTestVisibilityForRoot();
visualTreeRoot.OnElementLoaded();
}

internal static void RootElementUnloaded(UIElement visualTreeRoot)
=> visualTreeRoot.OnElementUnloaded();
{
visualTreeRoot.ClearHitTestVisibilityForRoot();
visualTreeRoot.OnElementUnloaded();
}

// Overloads for the FrameworkElement to raise the events
// (Load/Unload is actually a concept of the FwElement, but it's easier to handle it directly from the UIElement)
Expand Down
5 changes: 5 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.netstdref.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,10 @@ public UIElement()
protected virtual void OnVisibilityChanged(Visibility oldValue, Visibility newVisibility)
{
}


internal void SetHitTestVisibilityForRoot() => throw new NotSupportedException("Reference assembly");

internal void ClearHitTestVisibilityForRoot() => throw new NotSupportedException("Reference assembly");
}
}
7 changes: 5 additions & 2 deletions src/Uno.UI/WasmCSS/Uno.UI.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ body {
position: absolute;
display: inline;
outline: none;
pointer-events: auto;
/*
Disable pointer events by default to match HitTestVisibilityProperty
default value
*/
pointer-events: none;
/*
Padding & margin are required for measure/arrange to behave well:
margin & padding are calculated through Xaml elements.
*/
margin: 0 !important;
padding: 0;

line-height: normal;
-webkit-box-sizing: border-box !important;
-moz-box-sizing: border-box !important;
Expand Down

0 comments on commit 7d74f48

Please sign in to comment.