Skip to content

Commit

Permalink
feat(pointers): [Skia] Use the already existing bubbling algorithm fo…
Browse files Browse the repository at this point in the history
…r pointer
  • Loading branch information
dr1rrb committed Sep 21, 2020
1 parent e3fa7b9 commit 17c81a4
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 43 deletions.
1 change: 0 additions & 1 deletion src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ internal PointerRoutedEventArgs(MotionEvent nativeEvent, int pointerIndex, UIEle
Pointer = new Pointer(pointerId, pointerType, isInContact, isInRange: true);
KeyModifiers = keys;
OriginalSource = originalSource;
CanBubbleNatively = true;

_properties = GetProperties(nativePointerType, nativePointerAction, nativePointerButtons); // Last: we need the Pointer property to be set!
}
Expand Down
8 changes: 8 additions & 0 deletions src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ namespace Windows.UI.Xaml.Input
{
public sealed partial class PointerRoutedEventArgs : RoutedEventArgs, ICancellableRoutedEventArgs, CoreWindow.IPointerEventArgs
{
#if __IOS__ || __MACOS__ || __ANDROID__ || __WASM__
internal const bool PlatformSupportsNativeBubbling = true;
#else
internal const bool PlatformSupportsNativeBubbling = false;
#endif

public PointerRoutedEventArgs()
{
// This is acceptable as all ctors of this class are internal
CoreWindow.GetForCurrentThread().SetLastPointerEvent(this);

CanBubbleNatively = PlatformSupportsNativeBubbling;
}

/// <inheritdoc />
Expand Down
1 change: 0 additions & 1 deletion src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ internal PointerRoutedEventArgs(uint pointerId, UITouch nativeTouch, UIEvent nat
Pointer = new Pointer(pointerId, deviceType, isInContact, isInRange: true);
KeyModifiers = VirtualKeyModifiers.None;
OriginalSource = FindOriginalSource(_nativeTouch) ?? receiver;
CanBubbleNatively = true; // Required for native gesture recognition (i.e. ScrollViewer), and integration of native components in the visual tree
}

public PointerPoint GetCurrentPoint(UIElement relativeTo)
Expand Down
3 changes: 1 addition & 2 deletions src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ internal PointerRoutedEventArgs(NSSet touches, NSEvent nativeEvent, UIElement so
Pointer = new Pointer(pointerId, pointerDeviceType, isInContact, isInRange: true);
KeyModifiers = GetVirtualKeyModifiers(nativeEvent);
OriginalSource = source;
CanBubbleNatively = true;
}

public PointerPoint GetCurrentPoint(UIElement relativeTo)
Expand Down Expand Up @@ -200,4 +199,4 @@ private static bool IsTabletPointingEvent(NSEvent nativeEvent)

#endregion
}
}
}
3 changes: 0 additions & 3 deletions src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ partial class PointerRoutedEventArgs
Pointer = GetPointer(pointerEventArgs);
KeyModifiers = pointerEventArgs.KeyModifiers;
OriginalSource = source;

// All events bubble in managed mode.
CanBubbleNatively = false;
}

public PointerPoint GetCurrentPoint(UIElement relativeTo)
Expand Down
4 changes: 1 addition & 3 deletions src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ partial class PointerRoutedEventArgs
VirtualKeyModifiers keys,
double pressure,
(bool isHorizontalWheel, double delta) wheel,
UIElement source,
bool canBubbleNatively)
UIElement source)
: this()
{
_timestamp = timestamp;
Expand All @@ -44,7 +43,6 @@ partial class PointerRoutedEventArgs
Pointer = new Pointer(pointerId, pointerType, isInContact, isInRange: true);
KeyModifiers = keys;
OriginalSource = source;
CanBubbleNatively = canBubbleNatively;
}

public PointerPoint GetCurrentPoint(UIElement relativeTo)
Expand Down
68 changes: 41 additions & 27 deletions src/Uno.UI/UI/Xaml/UIElement.Pointers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,10 @@ private bool OnPointerEnter(PointerRoutedEventArgs args, bool isManagedBubblingE
{
// We override the isOver for the relevancy check as we will update it right after.
var isOverOrCaptured = ValidateAndUpdateCapture(args, isOver: true);
var handledInManaged = SetOver(args, true, muteEvent: isManagedBubblingEvent || !isOverOrCaptured);
var isHandled = PointerRoutedEventArgs.PlatformSupportsNativeBubbling
? isManagedBubblingEvent
: args.Handled;
var handledInManaged = SetOver(args, true, muteEvent: isHandled || !isOverOrCaptured);

return handledInManaged;
}
Expand All @@ -449,9 +452,12 @@ private bool OnPointerDown(PointerRoutedEventArgs args, bool isManagedBubblingEv
// it due to an invalid state. So here we make sure to not stay in an invalid state that would
// prevent any interaction with the application.
var isOverOrCaptured = ValidateAndUpdateCapture(args, isOver: true, forceRelease: true);
var handledInManaged = SetPressed(args, true, muteEvent: isManagedBubblingEvent || !isOverOrCaptured);
var isHandled = PointerRoutedEventArgs.PlatformSupportsNativeBubbling
? isManagedBubblingEvent
: args.Handled;
var handledInManaged = SetPressed(args, true, muteEvent: isHandled || !isOverOrCaptured);

if (!isManagedBubblingEvent && !isOverOrCaptured)
if (PointerRoutedEventArgs.PlatformSupportsNativeBubbling && !isManagedBubblingEvent && !isOverOrCaptured)
{
// This case is for safety only, it should not happen as we should never get a Pointer down while not
// on this UIElement, and no capture should prevent the dispatch as no parent should hold a capture at this point.
Expand All @@ -472,10 +478,10 @@ private bool OnPointerDown(PointerRoutedEventArgs args, bool isManagedBubblingEv

recognizer.ProcessDownEvent(point);

#if __WASM__
#if __WASM__ || __SKIA__
// On iOS and Android, pointers are implicitly captured, so we will receive the "irrelevant" (i.e. !isOverOrCaptured)
// pointer moves and we can use them for manipulation. But on WASM we have to explicitly request to get those events
// (expect on FF where they are also implicitly captured ... but we still capture them).
// pointer moves and we can use them for manipulation. But on WASM and SKIA we have to explicitly request to get those events
// (expect on FF where they are also implicitly captured ... but we still capture them anyway).
if (recognizer.PendingManipulation?.IsActive(point.PointerDevice.PointerDeviceType, point.PointerId) ?? false)
{
Capture(args.Pointer, PointerCaptureKind.Implicit, args);
Expand Down Expand Up @@ -505,9 +511,6 @@ private bool OnNativePointerMoveWithOverCheck(PointerRoutedEventArgs args, bool

if (_gestures.IsValueCreated)
{
// We need to process only events that are bubbling natively to this control,
// if they are bubbling in managed it means that they were handled by a child control,
// so we should not use them for gesture recognition.
_gestures.Value.ProcessMoveEvents(args.GetIntermediatePoints(this), isOverOrCaptured);
}

Expand All @@ -519,10 +522,13 @@ private bool OnNativePointerMoveWithOverCheck(PointerRoutedEventArgs args, bool

private bool OnPointerMove(PointerRoutedEventArgs args, bool isManagedBubblingEvent)
{
var isOverOrCaptured = ValidateAndUpdateCapture(args);
var handledInManaged = false;
var isOverOrCaptured = ValidateAndUpdateCapture(args);
var isHandled = PointerRoutedEventArgs.PlatformSupportsNativeBubbling
? isManagedBubblingEvent
: args.Handled;

if (!isManagedBubblingEvent && isOverOrCaptured)
if (!isHandled && isOverOrCaptured)
{
// If this pointer was wrongly dispatched here (out of the bounds and not captured),
// we don't raise the 'move' event
Expand All @@ -533,10 +539,9 @@ private bool OnPointerMove(PointerRoutedEventArgs args, bool isManagedBubblingEv

if (_gestures.IsValueCreated)
{
// We need to process only events that are bubbling natively to this control,
// if they are bubbling in managed it means that they were handled by a child control,
// We need to process only events that were not handled by a child control,
// so we should not use them for gesture recognition.
_gestures.Value.ProcessMoveEvents(args.GetIntermediatePoints(this), !isManagedBubblingEvent || isOverOrCaptured);
_gestures.Value.ProcessMoveEvents(args.GetIntermediatePoints(this), !isHandled || isOverOrCaptured);
}

return handledInManaged;
Expand All @@ -549,8 +554,11 @@ private bool OnPointerUp(PointerRoutedEventArgs args, bool isManagedBubblingEven
{
var handledInManaged = false;
var isOverOrCaptured = ValidateAndUpdateCapture(args, out var isOver);
var isHandled = PointerRoutedEventArgs.PlatformSupportsNativeBubbling
? isManagedBubblingEvent
: args.Handled;

handledInManaged |= SetPressed(args, false, muteEvent: isManagedBubblingEvent || !isOverOrCaptured);
handledInManaged |= SetPressed(args, false, muteEvent: isHandled || !isOverOrCaptured);


// Note: We process the UpEvent between Release and Exited as the gestures like "Tap"
Expand All @@ -560,7 +568,7 @@ private bool OnPointerUp(PointerRoutedEventArgs args, bool isManagedBubblingEven
// We need to process only events that are bubbling natively to this control (i.e. isOverOrCaptured == true),
// if they are bubbling in managed it means that they where handled a child control,
// so we should not use them for gesture recognition.
_gestures.Value.ProcessUpEvent(args.GetCurrentPoint(this), !isManagedBubblingEvent || isOverOrCaptured);
_gestures.Value.ProcessUpEvent(args.GetCurrentPoint(this), !isHandled || isOverOrCaptured);
}

// We release the captures on up but only after the released event and processed the gesture
Expand All @@ -581,8 +589,11 @@ private bool OnPointerExited(PointerRoutedEventArgs args, bool isManagedBubbling
{
var handledInManaged = false;
var isOverOrCaptured = ValidateAndUpdateCapture(args);
var isHandled = PointerRoutedEventArgs.PlatformSupportsNativeBubbling
? isManagedBubblingEvent
: args.Handled;

handledInManaged |= SetOver(args, false, muteEvent: isManagedBubblingEvent || !isOverOrCaptured);
handledInManaged |= SetOver(args, false, muteEvent: isHandled || !isOverOrCaptured);

// We release the captures on exit when pointer if not pressed
// Note: for a "Tap" with a finger the sequence is Up / Exited / Lost, so the lost cannot be raised on Up
Expand Down Expand Up @@ -611,6 +622,9 @@ private bool OnNativePointerCancel(PointerRoutedEventArgs args, bool isSwallowed
private bool OnPointerCancel(PointerRoutedEventArgs args, bool isManagedBubblingEvent)
{
var isOverOrCaptured = ValidateAndUpdateCapture(args); // Check this *before* updating the pressed / over states!
var isHandled = PointerRoutedEventArgs.PlatformSupportsNativeBubbling
? isManagedBubblingEvent
: args.Handled;

// When a pointer is cancelled / swallowed by the system, we don't even receive "Released" nor "Exited"
SetPressed(args, false, muteEvent: true);
Expand All @@ -634,7 +648,7 @@ private bool OnPointerCancel(PointerRoutedEventArgs args, bool isManagedBubbling
else
{
args.Handled = false;
handledInManaged |= !isManagedBubblingEvent && RaisePointerEvent(PointerCanceledEvent, args);
handledInManaged |= !isHandled && RaisePointerEvent(PointerCanceledEvent, args);
handledInManaged |= SetNotCaptured(args);
}

Expand Down Expand Up @@ -668,9 +682,9 @@ private bool RaisePointerEvent(RoutedEvent evt, PointerRoutedEventArgs args)
_pendingRaisedEvent = (null, null, null);
}
}
#endregion
#endregion

#region Pointer over state (Updated by the partial API OnNative***)
#region Pointer over state (Updated by the partial API OnNative***)
/// <summary>
/// Indicates if a pointer (no matter the pointer) is currently over the element (i.e. OverState)
/// WARNING: This might not be maintained for all controls, cf. remarks.
Expand Down Expand Up @@ -717,9 +731,9 @@ private bool SetOver(PointerRoutedEventArgs args, bool isOver, bool muteEvent =
return RaisePointerEvent(PointerExitedEvent, args);
}
}
#endregion
#endregion

#region Pointer pressed state (Updated by the partial API OnNative***)
#region Pointer pressed state (Updated by the partial API OnNative***)
private readonly HashSet<uint> _pressedPointers = new HashSet<uint>();

/// <summary>
Expand Down Expand Up @@ -791,9 +805,9 @@ private bool SetPressed(PointerRoutedEventArgs args, bool isPressed, bool muteEv
}

private void ClearPressed() => _pressedPointers.Clear();
#endregion
#endregion

#region Pointer capture state (Updated by the partial API OnNative***)
#region Pointer capture state (Updated by the partial API OnNative***)
/*
* About pointer capture
*
Expand All @@ -807,7 +821,7 @@ private bool SetPressed(PointerRoutedEventArgs args, bool isPressed, bool muteEv

private List<Pointer> _localExplicitCaptures;

#region Capture public (and internal) API ==> This manages only Explicit captures
#region Capture public (and internal) API ==> This manages only Explicit captures
public static DependencyProperty PointerCapturesProperty { get; } = DependencyProperty.Register(
"PointerCaptures",
typeof(IReadOnlyList<Pointer>),
Expand Down Expand Up @@ -874,7 +888,7 @@ public void ReleasePointerCaptures()

Release(PointerCaptureKind.Explicit);
}
#endregion
#endregion

partial void CapturePointerNative(Pointer pointer);
partial void ReleasePointerNative(Pointer pointer);
Expand Down Expand Up @@ -973,6 +987,6 @@ private bool Release(PointerCapture capture, PointerCaptureKind kinds, PointerRo
relatedARgs.Handled = false;
return RaisePointerEvent(PointerCaptureLostEvent, relatedARgs);
}
#endregion
#endregion
}
}
10 changes: 4 additions & 6 deletions src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ public partial class UIElement : DependencyObject
// we just ensure that the managed code won't try to bubble it by its own.
// However, if the event is Handled in managed, it will then bubble while it should not! https://github.com/unoplatform/uno/issues/3007
private static bool DispatchNativePointerEnter(UIElement target, string eventPayload)
=> TryParse(eventPayload, out var args) && target.OnNativePointerEnter(ToPointerArgs(target, args, isInContact: false, canBubble: true));
=> TryParse(eventPayload, out var args) && target.OnNativePointerEnter(ToPointerArgs(target, args, isInContact: false));

private static bool DispatchNativePointerLeave(UIElement target, string eventPayload)
=> TryParse(eventPayload, out var args) && target.OnNativePointerExited(ToPointerArgs(target, args, isInContact: false, canBubble: true));
=> TryParse(eventPayload, out var args) && target.OnNativePointerExited(ToPointerArgs(target, args, isInContact: false));

private static bool DispatchNativePointerDown(UIElement target, string eventPayload)
=> TryParse(eventPayload, out var args) && target.OnNativePointerDown(ToPointerArgs(target, args, isInContact: true));
Expand Down Expand Up @@ -183,8 +183,7 @@ private static bool TryParse(string eventPayload, out NativePointerEventArgs arg
UIElement snd,
NativePointerEventArgs args,
bool? isInContact,
(bool isHorizontalWheel, double delta) wheel = default,
bool canBubble = true)
(bool isHorizontalWheel, double delta) wheel = default)
{
var pointerId = (uint)args.pointerId;
var src = GetElementFromHandle(args.srcHandle) ?? (UIElement)snd;
Expand All @@ -205,8 +204,7 @@ private static bool TryParse(string eventPayload, out NativePointerEventArgs arg
keyModifiers,
args.pressure,
wheel,
src,
canBubble);
src);
}

private static PointerDeviceType ConvertPointerTypeString(string typeStr)
Expand Down

0 comments on commit 17c81a4

Please sign in to comment.