From 4d68131ff56cba42a4c878436c45eb8bf4e21141 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 22 Jul 2024 10:35:27 -0400 Subject: [PATCH 01/24] feat(wasm): Enabled managed pointers on wasm --- src/Uno.CrossTargetting.targets | 2 +- .../Runtime/BrowserPointerInputSource.wasm.cs | 374 +++++++++++++ src/Uno.UI/UI/Xaml/Application.wasm.cs | 5 +- .../Xaml/DragDrop/DragDropExtension.wasm.cs | 3 +- .../Xaml/Input/PointerRoutedEventArgs.wasm.cs | 152 +----- .../Internal/InputManager.Pointers.Managed.cs | 3 +- .../UI/Xaml/Internal/InputManager.Pointers.cs | 2 +- .../UI/Xaml/Internal/PointerCapture.wasm.cs | 37 -- src/Uno.UI/UI/Xaml/Shapes/Shape.wasm.cs | 11 +- .../UI/Xaml/UIElement.Pointers.Managed.cs | 12 +- src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs | 509 +----------------- .../ts/Runtime/BrowserPointerInputSource.ts | 206 +++++++ .../3.0.0.0/Windows.UI.Core/CoreWindow.cs | 20 +- src/Uno.UWP/UI/Core/CoreWindow.wasm.cs | 26 - .../Input/Preview.Injection/InputInjector.cs | 2 +- 15 files changed, 632 insertions(+), 732 deletions(-) create mode 100644 src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs delete mode 100644 src/Uno.UI/UI/Xaml/Internal/PointerCapture.wasm.cs create mode 100644 src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts delete mode 100644 src/Uno.UWP/UI/Core/CoreWindow.wasm.cs diff --git a/src/Uno.CrossTargetting.targets b/src/Uno.CrossTargetting.targets index 2e2de37aa02a..44ec3404b2bc 100644 --- a/src/Uno.CrossTargetting.targets +++ b/src/Uno.CrossTargetting.targets @@ -63,7 +63,7 @@ - $(DefineConstants);__WASM__;UNO_HAS_ENHANCED_HIT_TEST_PROPERTY;UNO_HAS_ENHANCED_LIFECYCLE + $(DefineConstants);__WASM__;UNO_HAS_ENHANCED_HIT_TEST_PROPERTY;UNO_HAS_ENHANCED_LIFECYCLE;UNO_HAS_MANAGED_POINTERS diff --git a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs new file mode 100644 index 000000000000..7079491e73be --- /dev/null +++ b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs @@ -0,0 +1,374 @@ +#nullable enable + +using System; +using Windows.Devices.Input; +using Windows.Foundation; +using Windows.UI.Core; +using Windows.UI.Input; +using Microsoft.UI.Xaml.Controls; +using static Windows.UI.Input.PointerUpdateKind; +using Uno.Foundation.Logging; +using System.Runtime.InteropServices.JavaScript; + +using _PointerIdentifierPool = Windows.Devices.Input.PointerIdentifierPool; // internal type (should be in Uno namespace) +using _PointerIdentifier = Windows.Devices.Input.PointerIdentifier; // internal type (should be in Uno namespace) +using _NativeMethods = __Windows.UI.Core.CoreWindow.NativeMethods; +using System.Runtime.InteropServices; +using Windows.System; + +namespace Uno.UI.Runtime; + +internal partial class BrowserPointerInputSource : IUnoCorePointerInputSource +{ + // Ref: + // https://www.w3.org/TR/pointerevents/ + // https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent + // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent + + private static readonly Logger _log = typeof(BrowserPointerInputSource).Log(); + private static readonly Logger? _logTrace = _log.IsTraceEnabled(LogLevel.Trace) ? _log : null; + + private ulong _bootTime; + private PointerPoint? _lastPoint; + private CoreCursor _pointerCursor = new(CoreCursorType.Arrow, 0); + +#pragma warning disable CS0067 // Some event are not raised on skia browser ... yet! + public event TypedEventHandler? PointerCaptureLost; +#pragma warning restore CS0067 // Some event are not raised on skia browser ... yet! + public event TypedEventHandler? PointerEntered; + public event TypedEventHandler? PointerExited; + public event TypedEventHandler? PointerMoved; + public event TypedEventHandler? PointerPressed; + public event TypedEventHandler? PointerReleased; + public event TypedEventHandler? PointerWheelChanged; + public event TypedEventHandler? PointerCancelled; // Uno Only + + public BrowserPointerInputSource() + { + _logTrace?.Trace("Initializing BrowserPointerInputSource"); + + Initialize(this); + } + + [JSImport("globalThis.Uno.UI.Runtime.Skia.BrowserPointerInputSource.initialize")] + private static partial void Initialize([JSMarshalAs] object inputSource); + + [JSExport] + private static void OnInitialized([JSMarshalAs] object inputSource, double bootTime) + { + ((BrowserPointerInputSource)inputSource)._bootTime = (ulong)bootTime; + + _logTrace?.Trace("Complete initialization of BrowserPointerInputSource, we are now ready to receive pointer events!"); + } + + [JSExport] + [return: JSMarshalAs] + private static int OnNativeEvent( + [JSMarshalAs] object inputSource, + byte @event, // ONE of NativePointerEvent + double timestamp, + int deviceType, // ONE of _PointerDeviceType + double pointerId, // Warning: This is a Number in JS, and it might be negative on safari for iOS + double x, + double y, + bool ctrl, + bool shift, + int buttons, + int buttonUpdate, + double pressure, + double wheelDeltaX, + double wheelDeltaY, + bool hasRelatedTarget) + { + + try + { + _logTrace?.Trace($"Pointer evt={(HtmlPointerEvent)@event}|id={pointerId}|x={x}|y={x}|ctrl={ctrl}|shift={shift}|bts={buttons}|btUpdate={buttonUpdate}|type={(PointerDeviceType)deviceType}|ts={timestamp}|pres={pressure}|wheelX={wheelDeltaX}|wheelY={wheelDeltaY}|relTarget={hasRelatedTarget}"); + + var that = (BrowserPointerInputSource)inputSource; + var evt = (HtmlPointerEvent)@event; + var pointerType = (PointerDeviceType)deviceType; + var pointerDevice = PointerDevice.For(pointerType); + var pointerIdentifier = _PointerIdentifierPool.RentManaged(new _PointerIdentifier((PointerDeviceType)deviceType, (uint)pointerId)); + + var frameId = ToFrameId(timestamp); + var ts = that.ToTimeStamp(timestamp); + var isInContact = buttons != 0; + var isInRange = GetIsInRange(@event, hasRelatedTarget, pointerType, isInContact); + var keyModifiers = GetKeyModifiers(ctrl, shift); + var position = new Point(x, y); + + var properties = GetProperties(pointerType, isInRange, (HtmlPointerButtonsState)buttons, (HtmlPointerButtonUpdate)buttonUpdate, wheel: (false, -wheelDeltaY), pressure); + + var point = new PointerPoint(frameId, ts, pointerDevice, pointerIdentifier.Id, position, position, isInContact, properties); + var args = new PointerEventArgs(point, keyModifiers); + + that._lastPoint = point; + + switch (evt) + { + case HtmlPointerEvent.pointerover: + that.PointerEntered?.Invoke(that, args); + break; + + case HtmlPointerEvent.pointerout: + that.PointerExited?.Invoke(that, args); + break; + + case HtmlPointerEvent.pointerdown: + that.PointerPressed?.Invoke(that, args); + break; + + case HtmlPointerEvent.pointerup: + //case HtmlPointerEvent.lostpointercapture: // if pointer is captured, we don't get a up, just a capture lost (with skia for wasm) + that.PointerReleased?.Invoke(that, args); + break; + + case HtmlPointerEvent.pointermove: + that.PointerMoved?.Invoke(that, args); + break; + + case HtmlPointerEvent.wheel: + if (wheelDeltaY is not 0) + { + that.PointerWheelChanged?.Invoke(that, args); + } + + if (wheelDeltaX is not 0) + { + properties = GetProperties(pointerType, isInRange, (HtmlPointerButtonsState)buttons, (HtmlPointerButtonUpdate)buttonUpdate, wheel: (true, wheelDeltaX), pressure); + point = new PointerPoint(frameId, ts, pointerDevice, pointerIdentifier.Id, position, position, isInContact, properties); + args = new PointerEventArgs(point, keyModifiers); + + that.PointerWheelChanged?.Invoke(that, args); + } + + break; + + case HtmlPointerEvent.pointercancel: + that.PointerCancelled?.Invoke(that, args); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(@event), $"Unknown event ({@event}-{evt})."); + } + + return (int)Microsoft.UI.Xaml.HtmlEventDispatchResult.Ok; + } + catch (Exception error) + { + if (_log.IsEnabled(LogLevel.Error)) + { + _log.Error($"Failed to dispatch native pointer event: {error}"); + } + + return (int)Microsoft.UI.Xaml.HtmlEventDispatchResult.Ok; + } + } + + [NotImplemented] public bool HasCapture => false; + + public CoreCursor PointerCursor + { + get => _pointerCursor; + set + { + _pointerCursor = value; + _NativeMethods.SetCursor(_pointerCursor.Type.ToCssCursor()); + } + } + + public Point PointerPosition => _lastPoint?.Position ?? default; + + #region Captures + public void SetPointerCapture() + { + if (_lastPoint is not null) + { + SetPointerCapture(_lastPoint.Pointer); + } + } + public void SetPointerCapture(PointerIdentifier pointer) + { + if (_PointerIdentifierPool.TryGetNative(pointer, out var native)) + { + SetPointerCaptureNative(native.Id); + } + else if (this.Log().IsEnabled(LogLevel.Warning)) + { + this.Log().Warn($"Cannot capture pointer, could not find native pointer id for managed pointer id {pointer}"); + } + } + + [JSImport("globalThis.Uno.UI.Runtime.Skia.BrowserPointerInputSource.setPointerCapture")] + private static partial void SetPointerCaptureNative(double pointerId); // double as it might be negative on safari for iOS + + public void ReleasePointerCapture() + { + if (_lastPoint is not null) + { + ReleasePointerCapture(_lastPoint.Pointer); + } + } + + public void ReleasePointerCapture(PointerIdentifier pointer) + { + if (_PointerIdentifierPool.TryGetNative(pointer, out var native)) + { + ReleasePointerCaptureNative(native.Id); + } + else if (this.Log().IsEnabled(LogLevel.Warning)) + { + this.Log().Warn($"Cannot release pointer, could not find native pointer id for managed pointer id {pointer}"); + } + } + + [JSImport("globalThis.Uno.UI.Runtime.Skia.BrowserPointerInputSource.releasePointerCapture")] + private static partial void ReleasePointerCaptureNative(double pointerId); // double as it might be negative on safari for iOS + #endregion + + #region Native to manage convertion helpers + private static VirtualKeyModifiers GetKeyModifiers(bool ctrl, bool shift) + { + var keyModifiers = VirtualKeyModifiers.None; + if (ctrl) keyModifiers |= VirtualKeyModifiers.Control; + if (shift) keyModifiers |= VirtualKeyModifiers.Shift; + return keyModifiers; + } + + private static bool GetIsInRange(byte @event, bool hasRelatedTarget, PointerDeviceType pointerType, bool isInContact) + { + const int cancel = (int)HtmlPointerEvent.pointercancel; + const int exitOrUp = (int)(HtmlPointerEvent.pointerout | HtmlPointerEvent.pointerup); + + var isInRange = true; + if (@event is cancel) + { + isInRange = false; + } + else if ((@event & exitOrUp) != 0) + { + isInRange = pointerType switch + { + PointerDeviceType.Mouse => true, // Mouse is always in range (unless for 'cancel' eg. if it was unplugged from computer) + PointerDeviceType.Touch => false, // If we get a pointer out for touch, it means that pointer left the screen (pt up - a.k.a. Implicit capture) + PointerDeviceType.Pen => hasRelatedTarget, // If the relatedTarget is null it means pointer left the detection range ... but only for out event! + _ => !isInContact // Safety! + }; + } + + return isInRange; + } + + private static PointerPointProperties GetProperties( + PointerDeviceType deviceType, + bool isInRange, + HtmlPointerButtonsState buttons, + HtmlPointerButtonUpdate buttonUpdate, + (bool isHorizontalWheel, double delta) wheel, + double pressure) + { + var props = new PointerPointProperties + { + IsPrimary = true, + IsInRange = isInRange, + IsLeftButtonPressed = buttons.HasFlag(HtmlPointerButtonsState.Left), + IsMiddleButtonPressed = buttons.HasFlag(HtmlPointerButtonsState.Middle), + IsRightButtonPressed = buttons.HasFlag(HtmlPointerButtonsState.Right), + IsXButton1Pressed = buttons.HasFlag(HtmlPointerButtonsState.X1), + IsXButton2Pressed = buttons.HasFlag(HtmlPointerButtonsState.X2), + IsEraser = buttons.HasFlag(HtmlPointerButtonsState.Eraser), + IsHorizontalMouseWheel = wheel.isHorizontalWheel, + MouseWheelDelta = (int)wheel.delta + }; + + switch (deviceType) + { + // For touch and mouse, we keep the default pressure of .5, as WinUI + + case PointerDeviceType.Pen: + // !!! WARNING !!! Here we have a slight different behavior compared to WinUI: + // On WinUI we will get IsRightButtonPressed (with IsBarrelButtonPressed) only if the user is pressing + // the barrel button when pen goes "in contact" (i.e. touches the screen), otherwise we will get + // IsLeftButtonPressed and IsBarrelButtonPressed. + // Here we set IsRightButtonPressed as soon as the barrel button was pressed, no matter + // if the pen was already in contact or not. + // This is acceptable since the UIElement pressed state is **per pointer** (not buttons of pointer) + // and GestureRecognizer always checks that pressed buttons didn't changed for a single gesture. + props.IsBarrelButtonPressed = props.IsRightButtonPressed; + props.Pressure = (float)pressure; + break; + } + + // Needs to be computed only after the props is almost completed + props.PointerUpdateKind = ToUpdateKind(buttonUpdate, props); + + return props; + } + + internal static uint ToFrameId(double timestamp) + // Known limitation: After 49 days, we will overflow the uint and frame IDs will restart at 0. + => (uint)(timestamp % uint.MaxValue); + + private ulong ToTimeStamp(double timestamp) + => _bootTime + (ulong)(timestamp * TimeSpan.TicksPerMillisecond); + + private static PointerUpdateKind ToUpdateKind(HtmlPointerButtonUpdate update, PointerPointProperties props) + => update switch + { + HtmlPointerButtonUpdate.Left when props.IsLeftButtonPressed => PointerUpdateKind.LeftButtonPressed, + HtmlPointerButtonUpdate.Left => PointerUpdateKind.LeftButtonReleased, + HtmlPointerButtonUpdate.Middle when props.IsMiddleButtonPressed => PointerUpdateKind.MiddleButtonPressed, + HtmlPointerButtonUpdate.Middle => PointerUpdateKind.MiddleButtonReleased, + HtmlPointerButtonUpdate.Right when props.IsRightButtonPressed => PointerUpdateKind.RightButtonPressed, + HtmlPointerButtonUpdate.Right => PointerUpdateKind.RightButtonReleased, + HtmlPointerButtonUpdate.X1 when props.IsXButton1Pressed => PointerUpdateKind.XButton1Pressed, + HtmlPointerButtonUpdate.X1 => PointerUpdateKind.XButton1Released, + HtmlPointerButtonUpdate.X2 when props.IsXButton2Pressed => PointerUpdateKind.XButton1Pressed, + HtmlPointerButtonUpdate.X2 => PointerUpdateKind.XButton1Released, + _ => PointerUpdateKind.Other + }; + + private enum HtmlPointerEvent : byte + { + // WARNING: This enum has a corresponding version in TypeScript! + + // Minimal default pointer required to maintain state + pointerover = 1, + pointerout = 1 << 1, + pointerdown = 1 << 2, + pointerup = 1 << 3, + pointercancel = 1 << 4, + pointermove = 1 << 5, // Required since when pt is captured, isOver will be maintained by the moveWithOverCheck + lostpointercapture = 1 << 6, // Required to get pointer up when pointer is captured + + // Optional pointer events + wheel = 1 << 7, + } + + [Flags] + private enum HtmlPointerButtonsState + { + // https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#Determining_button_states + + None = 0, + Left = 1, + Middle = 4, + Right = 2, + X1 = 8, + X2 = 16, + Eraser = 32, + } + + private enum HtmlPointerButtonUpdate + { + None = -1, + Left = 0, + Middle = 1, + Right = 2, + X1 = 3, + X2 = 4, + Eraser = 5 + } + #endregion +} diff --git a/src/Uno.UI/UI/Xaml/Application.wasm.cs b/src/Uno.UI/UI/Xaml/Application.wasm.cs index 6ceb301fc845..41b240f3e855 100644 --- a/src/Uno.UI/UI/Xaml/Application.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Application.wasm.cs @@ -23,7 +23,7 @@ using Uno.Helpers; using Uno.UI.Xaml.Controls; using Uno.UI.Dispatching; - +using Uno.UI.Runtime; #if HAS_UNO_WINUI using LaunchActivatedEventArgs = Microsoft/* UWP don't rename */.UI.Xaml.LaunchActivatedEventArgs; @@ -46,6 +46,9 @@ partial void InitializePartial() throw new InvalidOperationException("The application must be started using Application.Start first, e.g. Microsoft.UI.Xaml.Application.Start(_ => new App());"); } + global::Uno.Foundation.Extensibility.ApiExtensibility.Register( + typeof(IUnoCorePointerInputSource), + o => new BrowserPointerInputSource()); global::Uno.Foundation.Extensibility.ApiExtensibility.Register( typeof(global::Windows.ApplicationModel.DataTransfer.DragDrop.Core.IDragDropExtension), o => global::Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension.GetForCurrentView()); diff --git a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs index 02c433dd0dc7..61eae35043e1 100644 --- a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs +++ b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs @@ -32,6 +32,7 @@ using NativeMethods = __Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension.NativeMethods; using System.Runtime.InteropServices.JavaScript; +using Uno.UI.Runtime; // As IDragDropExtension is internal, the generated registration cannot be used. // [assembly: ApiExtension(typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.IDragDropExtension), typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension))] @@ -381,7 +382,7 @@ public NativeDrop(DragDropExtensionEventArgs args) public long Id => _args.id; /// - public uint FrameId => PointerRoutedEventArgs.ToFrameId(_args.timestamp); + public uint FrameId => BrowserPointerInputSource.ToFrameId(_args.timestamp); /// public (Point location, DragDropModifiers modifier) GetState() diff --git a/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.wasm.cs b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.wasm.cs index b9e81c09255d..69ff1f43e62b 100644 --- a/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.wasm.cs @@ -1,149 +1,17 @@ using System; -using System.Globalization; using Windows.Foundation; -using Windows.System; -using Uno.Foundation; -using Uno.UI.Xaml; using Uno.UI.Xaml.Input; -using PointerIdentifier = Windows.Devices.Input.PointerIdentifier; // internal type (should be in Uno namespace) -#if HAS_UNO_WINUI -using Microsoft.UI.Input; -#else -using Windows.Devices.Input; -using Windows.UI.Input; -#endif +namespace Microsoft.UI.Xaml.Input; -namespace Microsoft.UI.Xaml.Input +partial class PointerRoutedEventArgs : IHtmlHandleableRoutedEventArgs { - partial class PointerRoutedEventArgs : IHtmlHandleableRoutedEventArgs - { - private readonly double _timestamp; - private readonly Point _absolutePosition; - private readonly WindowManagerInterop.HtmlPointerButtonsState _buttons; - private readonly WindowManagerInterop.HtmlPointerButtonUpdate _buttonUpdate; - private readonly double _pressure; - private readonly (bool isHorizontalWheel, double delta) _wheel; - - internal PointerRoutedEventArgs( - double timestamp, - PointerIdentifier pointerUniqueId, - Point absolutePosition, - bool isInContact, - bool isInRange, - WindowManagerInterop.HtmlPointerButtonsState buttons, - WindowManagerInterop.HtmlPointerButtonUpdate buttonUpdate, - VirtualKeyModifiers keys, - double pressure, - (bool isHorizontalWheel, double delta) wheel, - UIElement source) - : this() - { - _timestamp = timestamp; - _absolutePosition = absolutePosition; - _buttons = buttons; - _buttonUpdate = buttonUpdate; - _pressure = pressure; - _wheel = wheel; - - FrameId = ToFrameId(timestamp); - Pointer = new Pointer(pointerUniqueId, isInContact, isInRange); - KeyModifiers = keys; - OriginalSource = source; - } - - /// - /// Default value for pointers is . - HtmlEventDispatchResult IHtmlHandleableRoutedEventArgs.HandledResult { get; set; } = HtmlEventDispatchResult.StopPropagation; - - public PointerPoint GetCurrentPoint(UIElement relativeTo) - { - var timestamp = ToTimeStamp(_timestamp); - var device = global::Windows.Devices.Input.PointerDevice.For((global::Windows.Devices.Input.PointerDeviceType)Pointer.PointerDeviceType); - var rawPosition = _absolutePosition; - var position = relativeTo == null - ? rawPosition - : relativeTo.TransformToVisual(null).Inverse.TransformPoint(_absolutePosition); - var properties = GetProperties(); - - return new PointerPoint(FrameId, timestamp, device, Pointer.PointerId, rawPosition, position, Pointer.IsInContact, properties); - } - - private PointerPointProperties GetProperties() - { - var props = new PointerPointProperties() - { - IsPrimary = true, - IsInRange = Pointer.IsInRange, - }; - - props.IsLeftButtonPressed = _buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Left); - props.IsMiddleButtonPressed = _buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Middle); - props.IsRightButtonPressed = _buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Right); - props.IsXButton1Pressed = _buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.X1); - props.IsXButton2Pressed = _buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.X2); - props.IsEraser = _buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Eraser); - - props.IsHorizontalMouseWheel = _wheel.isHorizontalWheel; - props.MouseWheelDelta = (int)_wheel.delta; - - switch (Pointer.PointerDeviceType) - { - // For touch and mouse, we keep the default pressure of .5, as WinUI - - case PointerDeviceType.Pen: - // !!! WARNING !!! Here we have a slight different behavior compared to WinUI: - // On WinUI we will get IsRightButtonPressed (with IsBarrelButtonPressed) only if the user is pressing - // the barrel button when pen goes "in contact" (i.e. touches the screen), otherwise we will get - // IsLeftButtonPressed and IsBarrelButtonPressed. - // Here we set IsRightButtonPressed as soon as the barrel button was pressed, no matter - // if the pen was already in contact or not. - // This is acceptable since the UIElement pressed state is **per pointer** (not buttons of pointer) - // and GestureRecognizer always checks that pressed buttons didn't changed for a single gesture. - props.IsBarrelButtonPressed = props.IsRightButtonPressed; - props.Pressure = (float)_pressure; - break; - } - - props.PointerUpdateKind = ToUpdateKind(_buttonUpdate, props); - - return props; - } - - #region Misc static helpers - private static ulong? _bootTime; - - private static ulong ToTimeStamp(double timestamp) - { - _bootTime ??= (ulong)(WindowManagerInterop.GetBootTime() * TimeSpan.TicksPerMillisecond); - - return _bootTime.Value + (ulong)(timestamp * TimeSpan.TicksPerMillisecond); - } - - internal static uint ToFrameId(double timestamp) - // Known limitation: After 49 days, we will overflow the uint and frame IDs will restart at 0. - => (uint)(timestamp % uint.MaxValue); - - internal static Point ToRelativePosition(Point absolutePosition, UIElement relativeTo) - => relativeTo == null - ? absolutePosition - : relativeTo.TransformToVisual(null).Inverse.TransformPoint(absolutePosition); - - private static PointerUpdateKind ToUpdateKind(WindowManagerInterop.HtmlPointerButtonUpdate update, PointerPointProperties props) - => update switch - { - WindowManagerInterop.HtmlPointerButtonUpdate.Left when props.IsLeftButtonPressed => PointerUpdateKind.LeftButtonPressed, - WindowManagerInterop.HtmlPointerButtonUpdate.Left => PointerUpdateKind.LeftButtonReleased, - WindowManagerInterop.HtmlPointerButtonUpdate.Middle when props.IsMiddleButtonPressed => PointerUpdateKind.MiddleButtonPressed, - WindowManagerInterop.HtmlPointerButtonUpdate.Middle => PointerUpdateKind.MiddleButtonReleased, - WindowManagerInterop.HtmlPointerButtonUpdate.Right when props.IsRightButtonPressed => PointerUpdateKind.RightButtonPressed, - WindowManagerInterop.HtmlPointerButtonUpdate.Right => PointerUpdateKind.RightButtonReleased, - WindowManagerInterop.HtmlPointerButtonUpdate.X1 when props.IsXButton1Pressed => PointerUpdateKind.XButton1Pressed, - WindowManagerInterop.HtmlPointerButtonUpdate.X1 => PointerUpdateKind.XButton1Released, - WindowManagerInterop.HtmlPointerButtonUpdate.X2 when props.IsXButton2Pressed => PointerUpdateKind.XButton1Pressed, - WindowManagerInterop.HtmlPointerButtonUpdate.X2 => PointerUpdateKind.XButton1Released, - _ => PointerUpdateKind.Other - }; - #endregion - } + /// + /// Default value for pointers is . + HtmlEventDispatchResult IHtmlHandleableRoutedEventArgs.HandledResult { get; set; } = HtmlEventDispatchResult.StopPropagation; + + internal static Point ToRelativePosition(Point absolutePosition, UIElement relativeTo) + => relativeTo == null + ? absolutePosition + : relativeTo.TransformToVisual(null).Inverse.TransformPoint(absolutePosition); } diff --git a/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.Managed.cs b/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.Managed.cs index 31d3042f411b..1c1e14ceba94 100644 --- a/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.Managed.cs +++ b/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.Managed.cs @@ -74,8 +74,7 @@ public void Init(object host) { if (this.Log().IsEnabled(LogLevel.Error)) { - this.Log().Error( - "Failed to initialize the PointerManager: cannot resolve the IUnoCorePointerInputSource."); + this.Log().Error("Failed to initialize the PointerManager: cannot resolve the IUnoCorePointerInputSource."); } return; } diff --git a/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs b/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs index 73bf0ea793d1..480fe884f2c7 100644 --- a/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs +++ b/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs @@ -71,7 +71,7 @@ public PointerManager(InputManager inputManager) UIElement.PointerReleasedEvent, new PointerEventHandler((snd, args) => ProcessPointerUp(args, false)), handledEventsToo: true); -#if __WASM__ +#if __WASM__ && !UNO_HAS_MANAGED_POINTERS rootElement.AddHandler( UIElement.PointerCanceledEvent, new PointerEventHandler((snd, args) => ProcessPointerCancelled(args)), diff --git a/src/Uno.UI/UI/Xaml/Internal/PointerCapture.wasm.cs b/src/Uno.UI/UI/Xaml/Internal/PointerCapture.wasm.cs deleted file mode 100644 index 474a5428e841..000000000000 --- a/src/Uno.UI/UI/Xaml/Internal/PointerCapture.wasm.cs +++ /dev/null @@ -1,37 +0,0 @@ -#nullable enable - -using System; -using System.Linq; -using Windows.Devices.Input; -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Input; -using Uno.Foundation.Logging; - -namespace Uno.UI.Xaml.Core; - -internal partial class PointerCapture -{ - partial void CaptureNative(UIElement target, Pointer pointer) - { - if (PointerIdentifierPool.TryGetNative(pointer.UniqueId, out var native)) - { - WindowManagerInterop.SetPointerCapture(target.HtmlId, native.Id); - } - else if (this.Log().IsEnabled(LogLevel.Warning)) - { - this.Log().Warn($"Cannot capture pointer, could not find native pointer id for managed pointer id {pointer.UniqueId}"); - } - } - - partial void ReleaseNative(UIElement target, Pointer pointer) - { - if (PointerIdentifierPool.TryGetNative(pointer.UniqueId, out var native)) - { - WindowManagerInterop.ReleasePointerCapture(target.HtmlId, native.Id); - } - else if (this.Log().IsEnabled(LogLevel.Warning)) - { - this.Log().Warn($"Cannot release pointer, could not find native pointer id for managed pointer id {pointer.UniqueId}"); - } - } -} diff --git a/src/Uno.UI/UI/Xaml/Shapes/Shape.wasm.cs b/src/Uno.UI/UI/Xaml/Shapes/Shape.wasm.cs index f46caa449680..755e967b59bb 100644 --- a/src/Uno.UI/UI/Xaml/Shapes/Shape.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Shapes/Shape.wasm.cs @@ -42,12 +42,11 @@ private protected void UpdateRender() UpdateStrokeDashArray(); } - - private protected override void OnHitTestVisibilityChanged(HitTestability oldValue, HitTestability newValue) - { - // We don't invoke the base, so we stay at the default "pointer-events: none" defined in Uno.UI.css in class svg.uno-uielement. - // This is required to avoid this SVG element (which is actually only a collection) to stoll pointer events. - } + //private protected override void OnHitTestVisibilityChanged(HitTestability oldValue, HitTestability newValue) + //{ + // // We don't invoke the base, so we stay at the default "pointer-events: none" defined in Uno.UI.css in class svg.uno-uielement. + // // This is required to avoid this SVG element (which is actually only a collection) to stoll pointer events. + //} private void OnFillBrushChanged() { diff --git a/src/Uno.UI/UI/Xaml/UIElement.Pointers.Managed.cs b/src/Uno.UI/UI/Xaml/UIElement.Pointers.Managed.cs index 7475c668a2ca..1052ee069908 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.Pointers.Managed.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.Pointers.Managed.cs @@ -79,7 +79,9 @@ private object CoerceHitTestVisibility(object baseValue) // 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__ +#if __WASM__ + !(IsLoaded || HtmlTagIsSvg) || +#elif !__MACOS__ !IsLoaded || #endif !IsHitTestVisible || Visibility != Visibility.Visible || !IsEnabledOverride()) @@ -87,6 +89,14 @@ private object CoerceHitTestVisibility(object baseValue) return HitTestability.Collapsed; } +#if __WASM__ + // Special case for external html element, we are always considering them as hit testable. + if (HtmlTagIsExternallyDefined && !FeatureConfiguration.FrameworkElement.UseLegacyHitTest) + { + return HitTestability.Visible; + } +#endif + // 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 (!IsViewHit()) { diff --git a/src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs b/src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs index 1b56726e2ded..d5007e7206b3 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs @@ -1,527 +1,30 @@ #nullable enable -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.JavaScript; -using Uno.Foundation; -using Windows.Foundation; -using Microsoft.UI.Xaml.Input; -using Windows.System; -using Uno; -using Uno.Foundation.Interop; -using Uno.Foundation.Logging; using Uno.UI; -using Uno.UI.Extensions; using Uno.UI.Xaml; -using Uno.UI.Xaml.Core; -using Uno.UI.Xaml.Islands; -using WinUICoreServices = Uno.UI.Xaml.Core.CoreServices; - -using PointerIdentifierPool = Windows.Devices.Input.PointerIdentifierPool; // internal type (should be in Uno namespace) -using PointerIdentifier = Windows.Devices.Input.PointerIdentifier; // internal type (should be in Uno namespace) -using PointerIdentifierDeviceType = Windows.Devices.Input.PointerDeviceType; // PointerIdentifier always uses Windows.Devices as it does noe have access to Microsoft.UI.Input (Uno.UI assembly) -#if HAS_UNO_WINUI -using Microsoft.UI.Input; -using PointerDeviceType = Microsoft.UI.Input.PointerDeviceType; -#else -using Windows.UI.Input; -using PointerDeviceType = Windows.Devices.Input.PointerDeviceType; -#endif namespace Microsoft.UI.Xaml; public partial class UIElement : DependencyObject { - private static TSInteropMarshaller.HandleRef _pointerEventArgs; - private static TSInteropMarshaller.HandleRef _pointerEventResult; - - private static Microsoft/* UWP don't rename */.UI.Input.InputSystemCursorShape? _lastSetCursor; - - // Ref: - // https://www.w3.org/TR/pointerevents/ - // https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent - // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent - - #region Native event registration handling - private NativePointerEvent _subscribedNativeEvents; - - partial void OnGestureRecognizerInitialized(GestureRecognizer recognizer) - { - // When a gesture recognizer is initialized, we subscribe to pointer events in order to feed it. - // Note: We register to Move, so it will also register Enter, Exited, Pressed, Released and Cancel. - // Gesture recognizer does not needs CaptureLost nor Wheel events. - AddPointerHandler(PointerMovedEvent, 1, default, default); - } - - partial void AddPointerHandler(RoutedEvent routedEvent, int handlersCount, object handler, bool handledEventsToo) - { - if (_pointerEventArgs == null) - { - _pointerEventArgs = TSInteropMarshaller.Allocate("UnoStatic_Windows_UI_Xaml_UIElement:setPointerEventArgs"); - _pointerEventResult = TSInteropMarshaller.Allocate("UnoStatic_Windows_UI_Xaml_UIElement:setPointerEventResult"); - } - - if (handlersCount != 1 - || routedEvent == PointerCaptureLostEvent) // Captures are handled in managed code only - { - return; - } - - var events = default(NativePointerEvent); - - // First we make sure to subscribe to the missing defaults events - events |= ~_subscribedNativeEvents & NativePointerEvent.Defaults; - - // Add optional events - switch (routedEvent.Flag) - { - case RoutedEventFlag.PointerWheelChanged when !_subscribedNativeEvents.HasFlag(NativePointerEvent.wheel): - events |= NativePointerEvent.wheel; - break; - } - - if (events is not default(NativePointerEvent)) - { - TSInteropMarshaller.InvokeJS( - "UnoStatic_Windows_UI_Xaml_UIElement:subscribePointerEvents", - new NativePointerSubscriptionParams - { - HtmlId = Handle, - Events = (byte)events - }); - - _subscribedNativeEvents |= events; - } - } - - partial void RemovePointerHandler(RoutedEvent routedEvent, int remainingHandlersCount, object handler) - { - if (remainingHandlersCount > 0) - { - return; - } - - if (!IsLoaded) - { - // If element is not in the visual tree its native element might also have been already destroyed, - // in that case we just ignore the native handler removal. - // The native handler will somehow leak, but if the control is re-used we will actually avoid the cost to re-create the handler, - // and if the control if dropped, then native handler will also be dropped. - // Even if not recommended, it might happen that users use the control finalizer to remove pointer events - // (cf. WinUI's TreeViewItem.RecycleEvents() invoked by the finalizer), this check make sure to not crash in the finalizer! - return; - } - - if (_gestures is null - && CountHandler(PointerEnteredEvent) is 0 - && CountHandler(PointerExitedEvent) is 0 - && CountHandler(PointerPressedEvent) is 0 - && CountHandler(PointerReleasedEvent) is 0 - && CountHandler(PointerCanceledEvent) is 0 - && CountHandler(PointerMovedEvent) is 0 - && CountHandler(PointerWheelChangedEvent) is 0) - { - TSInteropMarshaller.InvokeJS( - "UnoStatic_Windows_UI_Xaml_UIElement:unSubscribePointerEvents", - new NativePointerSubscriptionParams - { - HtmlId = Handle, - Events = (byte)_subscribedNativeEvents - }); - - _subscribedNativeEvents = default; - } - } - #endregion - - #region Native event dispatch - [EditorBrowsable(EditorBrowsableState.Never)] - [JSExport] - internal static void OnNativePointerEvent() - { - var result = new HtmlEventDispatchResultHelper(); - try - { - _logTrace?.Trace("Receiving native pointer event."); - - var args = _pointerEventArgs.Value; - var element = GetElementFromHandle(args.HtmlId); - - if (element is null) - { - if (_log.IsEnabled(LogLevel.Error)) - { - _log.Error($"Received pointer event for '{args.HtmlId}' but element does not exists anymore."); - } - - return; - } - - _logTrace?.Trace($"Dispatching to {element.GetDebugName()} pointer arg: {args}."); - - PointerRoutedEventArgs? routedArgs = null; - switch ((NativePointerEvent)args.Event) - { - case NativePointerEvent.pointerover: - { - // On WASM we do get 'pointerover' event for sub elements, - // so we can avoid useless work by validating if the pointer is already flagged as over element. - // If so, we stop bubbling since our parent will do the same! - routedArgs = ToPointerArgs(element, args); - if (element.IsOver(routedArgs.Pointer)) - { - result.Add(HtmlEventDispatchResult.StopPropagation); - } - else - { - result.Add(routedArgs, element.OnNativePointerEnter(routedArgs)); - } - - break; - } - - case NativePointerEvent.pointerout: // No needs to check IsOver (leaving vs. bubbling), it's already done in native code - { - routedArgs = ToPointerArgs(element, args); - var handled = element.OnNativePointerExited(routedArgs); - result.Add(routedArgs, handled); - - break; - } - - case NativePointerEvent.pointerdown: - { - routedArgs = ToPointerArgs(element, args); - var handled = element.OnNativePointerDown(routedArgs); - result.Add(routedArgs, handled); - - break; - } - - case NativePointerEvent.pointerup: - { - routedArgs = ToPointerArgs(element, args); - var handled = element.OnNativePointerUp(routedArgs); - result.Add(routedArgs, handled); - - if (result.ShouldStop) - { - element.XamlRoot?.VisualTree.ContentRoot.InputManager.Pointers.ProcessPointerUp(routedArgs, isAfterHandledUp: true); - } - - break; - } - - case NativePointerEvent.pointermove: - { - routedArgs = ToPointerArgs(element, args); - - // We do have "implicit capture" for touch and pen on chromium browsers, they won't raise 'pointerout' once in contact, - // this means that we need to validate the isOver to raise enter and exit like on UWP. - var needsToCheckIsOver = routedArgs.Pointer.PointerDeviceType switch - { - PointerDeviceType.Touch => routedArgs.Pointer.IsInRange, // If pointer no longer in range, isOver is always false - PointerDeviceType.Pen => routedArgs.Pointer.IsInContact, // We can ignore check when only hovering elements, browser does its job in that case - PointerDeviceType.Mouse => PointerCapture.TryGet(routedArgs.Pointer, out _), // Browser won't raise pointerenter/out as soon has we have an active capture - _ => true // For safety - }; - var handled = needsToCheckIsOver - ? element.OnNativePointerMoveWithOverCheck(routedArgs, isOver: routedArgs.IsPointCoordinatesOver(element)) - : element.OnNativePointerMove(routedArgs); - result.Add(routedArgs, handled); - - break; - } - - case NativePointerEvent.pointercancel: - { - routedArgs = ToPointerArgs(element, args); - var handled = element.OnNativePointerCancel(routedArgs, isSwallowedBySystem: true); - result.Add(routedArgs, handled); - - break; - } - - case NativePointerEvent.wheel: - if (args.wheelDeltaX is not 0) - { - routedArgs = ToPointerArgs(element, args, wheel: (true, args.wheelDeltaX)); - var handled = element.OnNativePointerWheel(routedArgs); - result.Add(routedArgs, handled); - } - - if (args.wheelDeltaY is not 0) - { - // Note: Web browser vertical scrolling is the opposite compared to WinUI! - routedArgs = ToPointerArgs(element, args, wheel: (false, -args.wheelDeltaY)); - var handled = element.OnNativePointerWheel(routedArgs); - result.Add(routedArgs, handled); - } - - break; - } - - if (routedArgs is { } && (NativePointerEvent)args.Event is not NativePointerEvent.pointerout) - { - // This corresponds to SetSourceCursor in InputManager.Pointers.managed.cs - if ((routedArgs.OriginalSource as UIElement)?.CalculatedFinalCursor is { } cursorShape) - { - if (_lastSetCursor is not { } c || c != cursorShape) - { - WindowManagerInterop.SetBodyCursor(Microsoft/* UWP don't rename */.UI.Input.InputSystemCursorShapeExtensions.ToCssProtectedCursor(cursorShape)); - _lastSetCursor = cursorShape; - } - } - else - { - WindowManagerInterop.SetBodyCursor("none"); // hides the cursor - } - } - } - catch (Exception error) - { - if (_log.IsEnabled(LogLevel.Error)) - { - _log.Error($"Failed to dispatch native pointer event: {error}"); - } - } - finally - { - _pointerEventResult.Value = new NativePointerEventResult - { - Result = (byte)result.Value - }; - } - } - - private static PointerRoutedEventArgs ToPointerArgs( - UIElement snd, - NativePointerEventArgs args, - (bool isHorizontalWheel, double delta) wheel = default) - { - const int cancel = (int)NativePointerEvent.pointercancel; - const int exitOrUp = (int)(NativePointerEvent.pointerout | NativePointerEvent.pointerup); - - var pointerType = (PointerDeviceType)args.deviceType; - var pointerId = PointerIdentifierPool.RentManaged(new PointerIdentifier((PointerIdentifierDeviceType)pointerType, (uint)args.pointerId)); - - var src = GetElementFromHandle(args.srcHandle) ?? (UIElement)snd; - var position = new Point(args.x, args.y); - var isInContact = args.buttons != 0; - var isInRange = true; - if (args.Event is cancel) - { - isInRange = false; - } - else if ((args.Event & exitOrUp) != 0) - { - isInRange = pointerType switch - { - PointerDeviceType.Mouse => true, // Mouse is always in range (unless for 'cancel' eg. if it was unplugged from computer) - PointerDeviceType.Touch => false, // If we get a pointer out for touch, it means that pointer left the screen (pt up - a.k.a. Implicit capture) - PointerDeviceType.Pen => args.hasRelatedTarget, // If the relatedTarget is null it means pointer left the detection range ... but only for out event! - _ => !isInContact // Safety! - }; - } - var keyModifiers = VirtualKeyModifiers.None; - if (args.ctrl) keyModifiers |= VirtualKeyModifiers.Control; - if (args.shift) keyModifiers |= VirtualKeyModifiers.Shift; - - var buttons = (WindowManagerInterop.HtmlPointerButtonsState)args.buttons; - var buttonUpdate = (WindowManagerInterop.HtmlPointerButtonUpdate)args.buttonUpdate; - - if (args.Event == (int)NativePointerEvent.pointerdown && - buttons == WindowManagerInterop.HtmlPointerButtonsState.None && - args.deviceType == (int)PointerDeviceType.Mouse) - { - // This scenario should technically not occur, but it may happen for macOS devices with the trackpad tap to click setting - // enabled (see discussion in issue #16076). To work around this, we use the buttonUpdate value which seems to be reliable. - buttons = buttonUpdate switch - { - WindowManagerInterop.HtmlPointerButtonUpdate.Left => WindowManagerInterop.HtmlPointerButtonsState.Left, - WindowManagerInterop.HtmlPointerButtonUpdate.Middle => WindowManagerInterop.HtmlPointerButtonsState.Middle, - WindowManagerInterop.HtmlPointerButtonUpdate.Right => WindowManagerInterop.HtmlPointerButtonsState.Right, - WindowManagerInterop.HtmlPointerButtonUpdate.X1 => WindowManagerInterop.HtmlPointerButtonsState.X1, - WindowManagerInterop.HtmlPointerButtonUpdate.X2 => WindowManagerInterop.HtmlPointerButtonsState.X2, - WindowManagerInterop.HtmlPointerButtonUpdate.Eraser => WindowManagerInterop.HtmlPointerButtonsState.Eraser, - _ => WindowManagerInterop.HtmlPointerButtonsState.None - }; - } - - return new PointerRoutedEventArgs( - args.timestamp, - pointerId, - position, - isInContact, - isInRange, - buttons, - buttonUpdate, - keyModifiers, - args.pressure, - wheel, - src); - } - #endregion - - partial void OnManipulationModeChanged(ManipulationModes oldMode, ManipulationModes newMode) - { - if (newMode == ManipulationModes.System) - { - ResetStyle("touch-action"); - } - else - { - // 'none' here means that the browser is not allowed to steal pointer for it's own manipulations - SetStyle("touch-action", "none"); - } - } - - #region HitTestVisibility - internal void UpdateHitTest() - { - this.CoerceValue(HitTestVisibilityProperty); - } - - [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); - } - - /// - /// This calculates the final hit-test visibility of an element. - /// - /// - private object CoerceHitTestVisibility(object baseValue) - { - if (this is RootVisual or XamlIsland) - { - return HitTestability.Visible; - } - - // The HitTestVisibilityProperty is never set directly. This means that baseValue is always the result of the parent's CoerceHitTestVisibility. - var baseHitTestVisibility = (HitTestability)baseValue; - - // If the parent is collapsed, we should be collapsed as well. This takes priority over everything else, even if we would be visible otherwise. - if (baseHitTestVisibility == HitTestability.Collapsed) - { - return HitTestability.Collapsed; - } - - // If we're not locally hit-test visible, visible, or enabled, we should be collapsed. Our children will be collapsed as well. - // SvgElements are an exception here since they won't be loaded. - if (!(IsLoaded || HtmlTagIsSvg) || !IsHitTestVisible || Visibility != Visibility.Visible || !IsEnabledOverride()) - { - return HitTestability.Collapsed; - } - - // Special case for external html element, we are always considering them as hit testable. - if (HtmlTagIsExternallyDefined && !FeatureConfiguration.FrameworkElement.UseLegacyHitTest) - { - return HitTestability.Visible; - } - - // If we're not collapsed or invisible, we can be targeted by hit-testing. This means that we can be the source of pointer events. - if (IsViewHit()) - { - return HitTestability.Visible; - } - - // 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. - return HitTestability.Invisible; - } - private protected virtual void OnHitTestVisibilityChanged(HitTestability oldValue, HitTestability newValue) - { - ApplyHitTestVisibility(newValue); - } - - private void ApplyHitTestVisibility(HitTestability value) { // By default, elements have 'pointer-event' set to 'none' (see Uno.UI.css .uno-uielement class) // which is aligned with HitTestVisibilityProperty's default value of Visible. // If HitTestVisibilityProperty is calculated to Invisible or Collapsed, // we don't want to be the target of hit-testing and raise any pointer events. // This is done by setting 'pointer-events' to 'none'. - // However setting it to 'none' will allow pointer event to pass through the element (a.k.a. Invisible) + // However, setting it to 'none' will allow pointer event to pass through the element (a.k.a. Invisible) - WindowManagerInterop.SetPointerEvents(HtmlId, value is HitTestability.Visible); + // Note: Even if we are now dispatching events in managed code only, we still want to properly set the pointer-events value in order to + // 1. support managed only element, + // 2. support "default" behavior of browser (like scrolling). + + WindowManagerInterop.SetPointerEvents(HtmlId, newValue is HitTestability.Visible); if (FeatureConfiguration.UIElement.AssignDOMXamlProperties) { UpdateDOMProperties(); } } - - #endregion - - [TSInteropMessage(Marshaller = CodeGeneration.Disabled, UnMarshaller = CodeGeneration.Enabled)] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct NativePointerSubscriptionParams - { - public IntPtr HtmlId; - - public byte Events; // One or multiple NativePointerEvent - } - - [TSInteropMessage(Marshaller = CodeGeneration.Enabled, UnMarshaller = CodeGeneration.Disabled)] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct NativePointerEventArgs - { - public IntPtr HtmlId; - - public byte Event; // ONE of NativePointerEvent - - public double pointerId; // Warning: This is a Number in JS, and it might be negative on safari for iOS - public double x; - public double y; - public bool ctrl; - public bool shift; - public int buttons; - public int buttonUpdate; - public int deviceType; - public int srcHandle; - public double timestamp; - public double pressure; - public double wheelDeltaX; - public double wheelDeltaY; - public bool hasRelatedTarget; - - /// - public override string ToString() - => $"elt={HtmlId}|evt={(NativePointerEvent)Event}|id={pointerId}|x={x}|y={x}|ctrl={ctrl}|shift={shift}|bts={buttons}|btUpdate={buttonUpdate}|type={(PointerDeviceType)deviceType}|srcId={srcHandle}|ts={timestamp}|pres={pressure}|wheelX={wheelDeltaX}|wheelY={wheelDeltaY}|relTarget={hasRelatedTarget}"; - } - - [TSInteropMessage(Marshaller = CodeGeneration.Disabled, UnMarshaller = CodeGeneration.Enabled)] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct NativePointerEventResult - { - public byte Result; // HtmlEventDispatchResult - } - - [Flags] - private enum NativePointerEvent : byte - { - // WARNING: This enum has a corresponding version in TypeScript! - - // Minimal default pointer required to maintain state - pointerover = 1, - pointerout = 1 << 1, - pointerdown = 1 << 2, - pointerup = 1 << 3, - pointercancel = 1 << 4, - pointermove = 1 << 5, // Required since when pt is captured, isOver will be maintained by the moveWithOverCheck - - // Optional pointer events - wheel = 1 << 6, - - Defaults = pointerover | pointerout | pointerdown | pointerup | pointercancel | pointermove, - } } diff --git a/src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts b/src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts new file mode 100644 index 000000000000..307b319df7ca --- /dev/null +++ b/src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts @@ -0,0 +1,206 @@ +namespace Uno.UI.Runtime.Skia { + //TODO import PointerDeviceType = Windows.Devices.Input.PointerDeviceType; + import HtmlEventDispatchResult = Uno.UI.HtmlEventDispatchResult; + + export enum PointerDeviceType { + Touch = 0, + Pen = 1, + Mouse = 2, + } + + export enum HtmlPointerEvent { + pointerover = 1, + pointerout = 1 << 1, + pointerdown = 1 << 2, + pointerup = 1 << 3, + pointercancel = 1 << 4, + + // Optional pointer events + pointermove = 1 << 5, + lostpointercapture = 1 << 6, + wheel = 1 << 7, + } + + export class BrowserPointerInputSource { + + private static _exports: any; + + public static async initialize(inputSource: any): Promise { + + const module = window.Module; + if (BrowserPointerInputSource._exports == undefined + && module.getAssemblyExports !== undefined) { + + const browserExports = (await module.getAssemblyExports("Uno.UI")); + + BrowserPointerInputSource._exports = browserExports.Uno.UI.Runtime.BrowserPointerInputSource; + } + + return new BrowserPointerInputSource(inputSource); + } + + public static setPointerCapture(pointerId: number): void { + document.body.setPointerCapture(pointerId); + } + + public static releasePointerCapture(pointerId: number): void { + document.body.releasePointerCapture(pointerId); + } + + private _source: any; + private _bootTime: Number; + + private constructor(manageSource: any) { + this._bootTime = Date.now() - performance.now(); + this._source = manageSource; + + BrowserPointerInputSource._exports.OnInitialized(manageSource, this._bootTime); + this.subscribePointerEvents(); // Subscribe only after the managed initialization is done + } + + private subscribePointerEvents() { + const element = document.body; + + element.addEventListener("pointerover", this.onPointerEventReceived.bind(this), { capture: false }); + element.addEventListener("pointerout", this.onPointerEventReceived.bind(this), { capture: false }); + element.addEventListener("pointerdown", this.onPointerEventReceived.bind(this), { capture: false }); + element.addEventListener("pointerup", this.onPointerEventReceived.bind(this), { capture: false }); + //element.addEventListener("lostpointercapture", this.onPointerEventReceived.bind(this), { capture: false }); + element.addEventListener("pointercancel", this.onPointerEventReceived.bind(this), { capture: false }); + element.addEventListener("pointermove", this.onPointerEventReceived.bind(this), { capture: false }); + element.addEventListener("wheel", this.onPointerEventReceived.bind(this), { capture: false }); + } + + private onPointerEventReceived(evt: PointerEvent): void { + //let id = (evt.target as HTMLElement)?.id; + //if (id != "uno-canvas" && !id.startsWith("uno-semantics-")) { + // // We have a div to enable accessibility (see enableA11y in WebAssemblyWindowWrapper). + // // Pressing space on keyboard to click it will trigger pointer event which we want to ignore. + // // So, we only care about events that come from uno-canvas. + // return; + //} + + // pointer events may have some side effects (like changing focus or opening a context menu on right clicking) + // We blanket-disable all the native behaviour so we don't have to whack-a-mole all the edge cases. + //evt.preventDefault(); + + const event = BrowserPointerInputSource.toHtmlPointerEvent(evt.type); + + let pointerId: number, pointerType: PointerDeviceType, pressure: number; + let wheelDeltaX: number, wheelDeltaY: number; + if (evt instanceof WheelEvent) { + pointerId = (evt as any).mozInputSource ? 0 : 1; // Try to match the mouse pointer ID 0 for FF, 1 for others + pointerType = PointerDeviceType.Mouse; + pressure = 0.5; // like WinUI + wheelDeltaX = evt.deltaX; + wheelDeltaY = evt.deltaY; + + switch (evt.deltaMode) { + case WheelEvent.DOM_DELTA_LINE: // Actually this is supported only by FF + const lineSize = BrowserPointerInputSource.wheelLineSize; + wheelDeltaX *= lineSize; + wheelDeltaY *= lineSize; + break; + case WheelEvent.DOM_DELTA_PAGE: + wheelDeltaX *= document.documentElement.clientWidth; + wheelDeltaY *= document.documentElement.clientHeight; + break; + } + } else { + pointerId = evt.pointerId; + pointerType = BrowserPointerInputSource.toPointerDeviceType(evt.pointerType); + pressure = evt.pressure; + wheelDeltaX = 0; + wheelDeltaY = 0; + } + + const result = BrowserPointerInputSource._exports.OnNativeEvent( + this._source, + event, //byte @event, // ONE of NativePointerEvent + evt.timeStamp, //double timestamp, + pointerType, //int deviceType, // ONE of _PointerDeviceType + pointerId, //double pointerId, // Warning: This is a Number in JS, and it might be negative on safari for iOS + evt.clientX, //double x, + evt.clientY, //double y, + evt.ctrlKey, //bool ctrl, + evt.shiftKey, //bool shift, + evt.buttons, //int buttons, + evt.button, //int buttonUpdate, + pressure, //double pressure, + wheelDeltaX, //double wheelDeltaX, + wheelDeltaY, //double wheelDeltaY, + evt.relatedTarget !== null //bool hasRelatedTarget) + ); + //if (result & HtmlEventDispatchResult.StopPropagation) { + // evt.stopPropagation(); + //} + if (result & HtmlEventDispatchResult.PreventDefault) { + evt.preventDefault(); + } + } + + //#region WheelLineSize + private static _wheelLineSize: number = undefined; + private static get wheelLineSize(): number { + // In web browsers, scroll might happen by pixels, line or page. + // But WinUI works only with pixels, so we have to convert it before send the value to the managed code. + // The issue is that there is no easy way get the "size of a line", instead we have to determine the CSS "line-height" + // defined in the browser settings. + // https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line + if (this._wheelLineSize == undefined) { + const el = document.createElement("div"); + el.style.fontSize = "initial"; + el.style.display = "none"; + document.body.appendChild(el); + const fontSize = window.getComputedStyle(el).fontSize; + document.body.removeChild(el); + + this._wheelLineSize = fontSize ? parseInt(fontSize) : 16; /* 16 = The current common default font size */ + + // Based on observations, even if the event reports 3 lines (the settings of windows), + // the browser will actually scroll of about 6 lines of text. + this._wheelLineSize *= 2.0; + } + + return this._wheelLineSize; + } + //#endregion + + //#region Helpers + private static toHtmlPointerEvent(eventName: string): HtmlPointerEvent { + switch (eventName) { + case "pointerover": + return HtmlPointerEvent.pointerover; + case "pointerout": + return HtmlPointerEvent.pointerout; + case "pointerdown" : + return HtmlPointerEvent.pointerdown; + case "pointerup" : + return HtmlPointerEvent.pointerup; + case "pointercancel" : + return HtmlPointerEvent.pointercancel; + case "pointermove" : + return HtmlPointerEvent.pointermove; + case "wheel": + return HtmlPointerEvent.wheel; + default: + return undefined; + } + } + + private static toPointerDeviceType(type: string): PointerDeviceType { + switch (type) { + case "touch": + return PointerDeviceType.Touch; + case "pen": + // Note: As of 2019-11-28, once pen pressed events pressed/move/released are reported as TOUCH on Firefox + // https://bugzilla.mozilla.org/show_bug.cgi?id=1449660 + return PointerDeviceType.Pen; + case "mouse": + default: + return PointerDeviceType.Mouse; + } + } + //#endregion + } +} diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.UI.Core/CoreWindow.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.UI.Core/CoreWindow.cs index c04a752e834d..e49b4947f834 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.UI.Core/CoreWindow.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.UI.Core/CoreWindow.cs @@ -101,15 +101,15 @@ public void Close() #endif // Skipping already declared method Windows.UI.Core.CoreWindow.GetAsyncKeyState(Windows.System.VirtualKey) // Skipping already declared method Windows.UI.Core.CoreWindow.GetKeyState(Windows.System.VirtualKey) -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false + [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__NETSTD_REFERENCE__")] public void ReleasePointerCapture() { global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Core.CoreWindow", "void CoreWindow.ReleasePointerCapture()"); } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false + [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__NETSTD_REFERENCE__")] public void SetPointerCapture() { global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Core.CoreWindow", "void CoreWindow.SetPointerCapture()"); @@ -286,7 +286,7 @@ public string GetCurrentKeyEventDeviceId() } } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] public event global::Windows.Foundation.TypedEventHandler PointerEntered { @@ -302,7 +302,7 @@ public string GetCurrentKeyEventDeviceId() } } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] public event global::Windows.Foundation.TypedEventHandler PointerExited { @@ -318,7 +318,7 @@ public string GetCurrentKeyEventDeviceId() } } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] public event global::Windows.Foundation.TypedEventHandler PointerMoved { @@ -334,7 +334,7 @@ public string GetCurrentKeyEventDeviceId() } } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] public event global::Windows.Foundation.TypedEventHandler PointerPressed { @@ -350,7 +350,7 @@ public string GetCurrentKeyEventDeviceId() } } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] public event global::Windows.Foundation.TypedEventHandler PointerReleased { @@ -366,7 +366,7 @@ public string GetCurrentKeyEventDeviceId() } } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || false +#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] public event global::Windows.Foundation.TypedEventHandler PointerWheelChanged { diff --git a/src/Uno.UWP/UI/Core/CoreWindow.wasm.cs b/src/Uno.UWP/UI/Core/CoreWindow.wasm.cs deleted file mode 100644 index 93a0d97f3457..000000000000 --- a/src/Uno.UWP/UI/Core/CoreWindow.wasm.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Uno.Foundation; - -using NativeMethods = __Windows.UI.Core.CoreWindow.NativeMethods; - -namespace Windows.UI.Core; - -public partial class CoreWindow -{ - private CoreCursor _pointerCursor = new CoreCursor(CoreCursorType.Arrow, 0); - - public global::Windows.UI.Core.CoreCursor PointerCursor - { - get => _pointerCursor; - set - { - _pointerCursor = value; - Internal_SetPointerCursor(); - } - - } - - private void Internal_SetPointerCursor() - { - NativeMethods.SetCursor(_pointerCursor.Type.ToCssCursor()); - } -} diff --git a/src/Uno.UWP/UI/Input/Preview.Injection/InputInjector.cs b/src/Uno.UWP/UI/Input/Preview.Injection/InputInjector.cs index a6d4be333c7e..6149ff47e933 100644 --- a/src/Uno.UWP/UI/Input/Preview.Injection/InputInjector.cs +++ b/src/Uno.UWP/UI/Input/Preview.Injection/InputInjector.cs @@ -24,7 +24,7 @@ internal static void SetTargetForCurrentThread(IInputInjectorTarget manager) _inputManager ??= manager; // Set only once per thread. } - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__", "__MACOS__")] + [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__NETSTD_REFERENCE__", "__MACOS__")] public static InputInjector? TryCreate() => _inputManager is not null ? new InputInjector(_inputManager) : null; From 675ef812c92eaed50ecf73d79caf6cac2f13a5e1 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 23 Jul 2024 08:57:31 -0400 Subject: [PATCH 02/24] fix(reg): Fix the managed pointer ID handling --- .../Runtime/BrowserPointerInputSource.wasm.cs | 2 ++ .../UI/Xaml/Internal/InputManager.Pointers.cs | 15 --------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs index 7079491e73be..d8da8eca14f4 100644 --- a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs +++ b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs @@ -122,6 +122,7 @@ private static int OnNativeEvent( case HtmlPointerEvent.pointerup: //case HtmlPointerEvent.lostpointercapture: // if pointer is captured, we don't get a up, just a capture lost (with skia for wasm) that.PointerReleased?.Invoke(that, args); + _PointerIdentifierPool.ReleaseManaged(pointerIdentifier); break; case HtmlPointerEvent.pointermove: @@ -147,6 +148,7 @@ private static int OnNativeEvent( case HtmlPointerEvent.pointercancel: that.PointerCancelled?.Invoke(that, args); + _PointerIdentifierPool.ReleaseManaged(pointerIdentifier); break; default: diff --git a/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs b/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs index 480fe884f2c7..13099ab950bd 100644 --- a/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs +++ b/src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs @@ -71,12 +71,6 @@ public PointerManager(InputManager inputManager) UIElement.PointerReleasedEvent, new PointerEventHandler((snd, args) => ProcessPointerUp(args, false)), handledEventsToo: true); -#if __WASM__ && !UNO_HAS_MANAGED_POINTERS - rootElement.AddHandler( - UIElement.PointerCanceledEvent, - new PointerEventHandler((snd, args) => ProcessPointerCancelled(args)), - handledEventsToo: true); -#endif } #region Re-routing (Flyout.OverlayInputPassThroughElement) @@ -206,21 +200,12 @@ internal void ProcessPointerUp(PointerRoutedEventArgs args, bool isAfterHandledU ReleaseCaptures(args.Reset(canBubbleNatively: false)); -#if __WASM__ - PointerIdentifierPool.ReleaseManaged(args.Pointer.UniqueId); -#endif - // At the end of our "up" processing, we reset the flag to make sure that the native handler (iOS, Android and WASM) // won't try to sent it to us again (if not already the case ^^). // (This could be the case if the args was flagged as handled in the ReleaseCaptures call above, like in RatingControl). args.Handled = isAfterHandledUp; } -#if __WASM__ - private static void ProcessPointerCancelled(PointerRoutedEventArgs args) - => PointerIdentifierPool.ReleaseManaged(args.Pointer.UniqueId); -#endif - // As focus event are either async or cancellable, // the FocusManager will explicitly notify us instead of listing to its events internal void NotifyFocusChanged() From 7f2a8b9f6677567b19708b067f14268107f5262d Mon Sep 17 00:00:00 2001 From: David Date: Wed, 24 Jul 2024 10:25:33 -0400 Subject: [PATCH 03/24] test(wasm): Run compatible UI tests as runtime tests on wasm --- .../SampleControlUITestBase.cs | 6 +++++ ...s.Flyout_OverlayInputPassThroughElement.cs | 2 +- .../ListViewTests/Selection_Pointers.cs | 6 +++++ .../SwipeControlTests/SwipeControlTests.cs | 19 ++++++++-------- .../Windows_UI_Xaml_Input/Capture_Tests.cs | 4 +--- ...lper.cs => RuntimeTestsApp.MouseHelper.cs} | 2 +- .../{SkiaApp.cs => RuntimeTestsApp.cs} | 22 +++++++++++++++---- ...nsions.cs => RuntimeTestsAppExtensions.cs} | 2 +- .../_Engine/SampleControlUITestBase.cs | 6 ++++- .../UnoUITests/Helpers/QueryExtensions.cs | 4 ++-- .../Uno.UI.RuntimeTests.Wasm.csproj | 1 + 11 files changed, 51 insertions(+), 23 deletions(-) rename src/Uno.UI.RuntimeTests/UITests/_Engine/{SkiaApp.MouseHelper.cs => RuntimeTestsApp.MouseHelper.cs} (98%) rename src/Uno.UI.RuntimeTests/UITests/_Engine/{SkiaApp.cs => RuntimeTestsApp.cs} (91%) rename src/Uno.UI.RuntimeTests/UITests/_Engine/{SkiaAppExtensions.cs => RuntimeTestsAppExtensions.cs} (96%) diff --git a/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs b/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs index dbeaa0ff1279..dacf493805d8 100644 --- a/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs +++ b/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs @@ -281,6 +281,9 @@ private void WriteSystemLogs(string fileName) } } + public async ValueTask TakeScreenshotAsync(string stepName, bool? ignoreInSnapshotCompare = null) + => TakeScreenshot(stepName, ignoreInSnapshotCompare); + public ScreenshotInfo TakeScreenshot(string stepName, bool? ignoreInSnapshotCompare = null) => TakeScreenshot( stepName, @@ -289,6 +292,9 @@ public ScreenshotInfo TakeScreenshot(string stepName, bool? ignoreInSnapshotComp : null ); + public async ValueTask TakeScreenshotAsync(string stepName, ScreenshotOptions options) + => TakeScreenshot(stepName, options); + public ScreenshotInfo TakeScreenshot(string stepName, ScreenshotOptions options) { if (_app == null) diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout_OverlayInputPassThroughElement.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout_OverlayInputPassThroughElement.cs index 2b187dffc6a4..d6ed4d47c83c 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout_OverlayInputPassThroughElement.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout_OverlayInputPassThroughElement.cs @@ -11,7 +11,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.FlyoutTests; -#if __SKIA__ +#if IS_RUNTIME_UI_TESTS [TestFixture] partial class Flyout_Tests : SampleControlUITestBase #else diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/Selection_Pointers.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/Selection_Pointers.cs index aedc61d2f0f6..b908e6fe44a2 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/Selection_Pointers.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/Selection_Pointers.cs @@ -19,36 +19,42 @@ public partial class ListViewTests_Tests : SampleControlUITestBase [Test] [AutoRetry] [InjectedPointer(PointerDeviceType.Touch)] + [InjectedPointer(PointerDeviceType.Mouse)] public Task When_NoSelection_Then_PointersEvents() => RunTest("_noSelection_noClick", clicked: false); [Test] [AutoRetry] [InjectedPointer(PointerDeviceType.Touch)] + [InjectedPointer(PointerDeviceType.Mouse)] public Task When_SingleSelectionWithoutItemClick_Then_PointersEvents() => RunTest("_singleSelection_noClick", clicked: false); [Test] [AutoRetry] [InjectedPointer(PointerDeviceType.Touch)] + [InjectedPointer(PointerDeviceType.Mouse)] public Task When_MultipleSelectionWithoutItemClick_Then_PointersEvents() => RunTest("_multipleSelection_noClick", clicked: false); [Test] [AutoRetry] [InjectedPointer(PointerDeviceType.Touch)] + [InjectedPointer(PointerDeviceType.Mouse)] public Task When_ExtendedSelectionWithoutItemClick_Then_PointersEvents() => RunTest("_extendedSelection_noClick", clicked: false); [Test] [AutoRetry] [InjectedPointer(PointerDeviceType.Touch)] + [InjectedPointer(PointerDeviceType.Mouse)] public Task When_NoSelectionWithItemClick_Then_PointersEvents() => RunTest("_noSelection_withClick", clicked: true); [Test] [AutoRetry] [InjectedPointer(PointerDeviceType.Touch)] + [InjectedPointer(PointerDeviceType.Mouse)] public Task When_SingleSelectionWithItemClick_Then_PointersEvents() => RunTest("_singleSelection_withClick", clicked: true); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs index cd23b074de81..6b607a5c55c8 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs @@ -9,6 +9,7 @@ using SamplesApp.UITests.Extensions; using SamplesApp.UITests.TestFramework; using Uno.Testing; +using Uno.UI.RuntimeTests.Helpers; using Uno.UITest.Helpers.Queries; namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.SwipeControlTests @@ -66,7 +67,6 @@ public async Task When_MultipleItems() } -#if !__SKIA__ // No screenshot on skia [Test] [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] @@ -84,37 +84,36 @@ private async Task When_InScrollableContainer(string testName) QueryEx sut = new QueryEx(q => q.All().Marked("SUT")); QueryEx output = new QueryEx(q => q.All().Marked("Output")); - Run(testName, skipInitialScreenshot: true); + await RunAsync(testName); - var sutPhyRect = _app.GetPhysicalRect(sut); - var item2PhyPosition = new Point((int)sutPhyRect.X + 150, (int)sutPhyRect.Y + 150).LogicalToPhysicalPixels(_app); + var sutPhyRect = App.GetPhysicalRect(sut); + var item2PhyPosition = new Point((int)sutPhyRect.X + 150, (int)sutPhyRect.Y + 150).LogicalToPhysicalPixels(App); // Validate initial state - var initial = TakeScreenshot("initial"); + var initial = await TakeScreenshotAsync("initial"); ImageAssert.HasColorAt(initial, item2PhyPosition.X, item2PhyPosition.Y, "#FFFFA52C"); // Execute left command on item 2 - _app.DragCoordinates(item2PhyPosition.X, item2PhyPosition.Y, item2PhyPosition.X + 300.LogicalToPhysicalPixels(_app), item2PhyPosition.Y); + App.DragCoordinates(item2PhyPosition.X, item2PhyPosition.Y, item2PhyPosition.X + 300.LogicalToPhysicalPixels(App), item2PhyPosition.Y); await Task.Delay(1000); // We cannot detect the animation ... var swippedItem = output.GetDependencyPropertyValue("Text"); Assert.AreEqual("#FFFFA52C", swippedItem); // Scroll up - _app.DragCoordinates(sutPhyRect.CenterX, sutPhyRect.Bottom - 10.LogicalToPhysicalPixels(_app), sutPhyRect.CenterX, sutPhyRect.Y + 10.LogicalToPhysicalPixels(_app)); + App.DragCoordinates(sutPhyRect.CenterX, sutPhyRect.Bottom - 10.LogicalToPhysicalPixels(App), sutPhyRect.CenterX, sutPhyRect.Y + 10.LogicalToPhysicalPixels(App)); // Validate scrolled successfully - var postScroll = TakeScreenshot("after scroll"); + var postScroll = await TakeScreenshotAsync("after scroll"); ImageAssert.DoesNotHaveColorAt(postScroll, item2PhyPosition.X, item2PhyPosition.Y, "#FFFFA52C"); // Execute left command on item that is now at item 2 location - _app.DragCoordinates(item2PhyPosition.X, item2PhyPosition.Y, item2PhyPosition.X + 300.LogicalToPhysicalPixels(_app), item2PhyPosition.Y); + App.DragCoordinates(item2PhyPosition.X, item2PhyPosition.Y, item2PhyPosition.X + 300.LogicalToPhysicalPixels(App), item2PhyPosition.Y); await Task.Delay(1000); // We cannot detect the animation ... swippedItem = output.GetDependencyPropertyValue("Text"); Assert.AreNotEqual("#FFFFA52C", swippedItem); } -#endif [Test] [AutoRetry] diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs index e3007d924e48..00cb26a099bf 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs @@ -70,9 +70,7 @@ private async Task RunTest(string testName, Action act = null) App.WaitForElement(target); act(target); -#if !__SKIA__ - TakeScreenshot("Result"); -#endif + await TakeScreenshotAsync("Result"); result.GetDependencyPropertyValue("Text").Should().Be("SUCCESS"); } diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaApp.MouseHelper.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.MouseHelper.cs similarity index 98% rename from src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaApp.MouseHelper.cs rename to src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.MouseHelper.cs index 5e5d14622fc0..4a737acd1ae9 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaApp.MouseHelper.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.MouseHelper.cs @@ -9,7 +9,7 @@ namespace Uno.UITest; -public partial class SkiaApp +public partial class RuntimeTestsApp { private class MouseHelper { diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaApp.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs similarity index 91% rename from src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaApp.cs rename to src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs index c45ab63e2d68..53f1776491df 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaApp.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs @@ -14,19 +14,20 @@ using Private.Infrastructure; using Uno.UI.Extensions; using Uno.UI.RuntimeTests; +using Uno.UI.RuntimeTests.Helpers; using Uno.UITest.Helpers.Queries; namespace Uno.UITest; -public partial class SkiaApp : IApp +public partial class RuntimeTestsApp : IApp { - private static SkiaApp? _current; // Make sure to not create multiple instances of the app (with a single InputInjector instance)! - internal static SkiaApp Current => _current ??= new(); + private static RuntimeTestsApp? _current; // Make sure to not create multiple instances of the app (with a single InputInjector instance)! + internal static RuntimeTestsApp Current => _current ??= new(); private readonly InputInjector _input; private MouseHelper Mouse { get; } - private SkiaApp() + private RuntimeTestsApp() { _input = InputInjector.TryCreate() ?? throw new InvalidOperationException("Cannot create input injector"); Mouse = new MouseHelper(_input); @@ -46,7 +47,11 @@ private SkiaApp() public async Task RunAsync(string metadataName) { +#if __SKIA__ var assemblyName = "SamplesApp.Skia"; +#elif __WASM__ + var assemblyName = "SamplesApp.Wasm"; +#endif if (TestServices.WindowHelper.IsXamlIsland) { assemblyName = "UnoIslands" + assemblyName; @@ -256,4 +261,13 @@ private void InjectMouseInput(params InjectedInputMouseInfo?[] input) private Exception NotSupported([CallerMemberName] string operation = "") => new NotSupportedException($"'{operation}' with type '{CurrentPointerType}' is not supported yet on this platform. Feel free to contribute!"); + + public async ValueTask TakeScreenshotAsync(string name) + { + var screenshot = await UITestHelper.ScreenShot((FrameworkElement)TestServices.WindowHelper.CurrentTestWindow.Content!); +#if false + UITestHelper.Save(screenshot, name); +#endif + return screenshot; + } } diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaAppExtensions.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsAppExtensions.cs similarity index 96% rename from src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaAppExtensions.cs rename to src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsAppExtensions.cs index 49b681de59e1..1abdfb47b11f 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/SkiaAppExtensions.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsAppExtensions.cs @@ -5,7 +5,7 @@ namespace Uno.UITest.Helpers.Queries; -internal static class SkiaAppExtensions +internal static class RuntimeTestsAppExtensions { // This class contains compatibility method to match the Uno.UITest.IApp contract. // Those methods are directly on the IApp interface but are not expected to be imported on the refreshed diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/SampleControlUITestBase.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/SampleControlUITestBase.cs index a4e2935107b7..71a576f4d5eb 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/SampleControlUITestBase.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/SampleControlUITestBase.cs @@ -5,6 +5,7 @@ using Windows.Devices.Input; using Uno.Testing; using Uno.UI.RuntimeTests; +using Uno.UI.RuntimeTests.Helpers; using Uno.UITest; namespace SamplesApp.UITests; @@ -12,7 +13,7 @@ namespace SamplesApp.UITests; // Note: All tests that are inheriting from this base class will run on UI thread. public class SampleControlUITestBase : IInjectPointers { - protected SkiaApp App => SkiaApp.Current; + protected RuntimeTestsApp App => RuntimeTestsApp.Current; /// /// Gets the default pointer type for the current platform @@ -32,4 +33,7 @@ void IInjectPointers.CleanupPointers() /// public IDisposable SetPointer(PointerDeviceType type) => App.SetPointer(type); + + public ValueTask TakeScreenshotAsync(string name) + => App.TakeScreenshotAsync(name); } diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/UnoUITests/Helpers/QueryExtensions.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/UnoUITests/Helpers/QueryExtensions.cs index af107a7b776e..5c92ad2167f0 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/UnoUITests/Helpers/QueryExtensions.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/UnoUITests/Helpers/QueryExtensions.cs @@ -11,14 +11,14 @@ namespace Uno.UITest.Helpers.Queries; internal static class Helpers { - internal static SkiaApp App { get; set; } + internal static RuntimeTestsApp App { get; set; } } internal static partial class QueryExtensions { // This class contains extensions method to match the Uno.UITest.Helpers.Queries.QueryExtensions contract. - private static SkiaApp App => Helpers.App; + private static RuntimeTestsApp App => Helpers.App; public static void Tap(this QueryEx query) { diff --git a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj index 19b6d9556d96..1b9f1b598365 100644 --- a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj +++ b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.Wasm.csproj @@ -40,6 +40,7 @@ + From d0cd60f8cab77c26672356927f98f64470a58fa8 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 24 Jul 2024 10:26:18 -0400 Subject: [PATCH 04/24] test: Enable pointer injection on wasm runtime tests --- src/Uno.CrossTargetting.targets | 2 +- .../common/TestServices.InputHelper.cs | 2 +- .../SplitButtonTests_InteractionTests.cs | 8 ++++---- .../Tests/Uno_UI_Xaml_Core/Given_InputManager.cs | 2 +- .../Given_InputInjector.cs | 2 +- .../Tests/Windows_UI_Xaml/Given_UIElement.cs | 6 +++--- .../Windows_UI_Xaml_Controls/Given_TextBlock.cs | 14 ++++++++------ 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Uno.CrossTargetting.targets b/src/Uno.CrossTargetting.targets index 44ec3404b2bc..2214c7f005fb 100644 --- a/src/Uno.CrossTargetting.targets +++ b/src/Uno.CrossTargetting.targets @@ -63,7 +63,7 @@ - $(DefineConstants);__WASM__;UNO_HAS_ENHANCED_HIT_TEST_PROPERTY;UNO_HAS_ENHANCED_LIFECYCLE;UNO_HAS_MANAGED_POINTERS + $(DefineConstants);__WASM__;UNO_HAS_ENHANCED_HIT_TEST_PROPERTY;UNO_HAS_ENHANCED_LIFECYCLE;UNO_HAS_MANAGED_POINTERS;HAS_INPUT_INJECTOR diff --git a/src/Uno.UI.RuntimeTests/IntegrationTests/common/TestServices.InputHelper.cs b/src/Uno.UI.RuntimeTests/IntegrationTests/common/TestServices.InputHelper.cs index f8c00a04582f..71add1ece833 100644 --- a/src/Uno.UI.RuntimeTests/IntegrationTests/common/TestServices.InputHelper.cs +++ b/src/Uno.UI.RuntimeTests/IntegrationTests/common/TestServices.InputHelper.cs @@ -50,7 +50,7 @@ public static void Hold(UIElement element) public static void Tap(UIElement element, uint waitBetweenPressRelease = 0) { -#if WINAPPSDK || __SKIA__ +#if WINAPPSDK || HAS_INPUT_INJECTOR Finger finger = null; MUXControlsTestApp.Utilities.RunOnUIThread.Execute(() => { diff --git a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs index 97688f13aa40..7a2d42f2aa23 100644 --- a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs +++ b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs @@ -31,7 +31,7 @@ namespace Windows.UI.Xaml.Tests.MUXControls.InteractionTests public partial class SplitButtonTests { [TestMethod] -#if !__SKIA__ +#if !HAS_INPUT_INJECTOR [Ignore("InputInjector is only supported on skia")] #endif public async Task BasicInteractionTest() @@ -70,7 +70,7 @@ public async Task BasicInteractionTest() } [TestMethod] -#if !__SKIA__ +#if !HAS_INPUT_INJECTOR [Ignore("InputInjector is only supported on skia")] #endif public async Task CommandTest() @@ -123,7 +123,7 @@ public async Task CommandTest() } [TestMethod] -#if !__SKIA__ +#if !HAS_INPUT_INJECTOR [Ignore("InputInjector is only supported on skia")] #endif public async Task TouchTest() @@ -265,7 +265,7 @@ public async Task KeyboardTest() } [TestMethod] -#if !__SKIA__ +#if !HAS_INPUT_INJECTOR [Ignore("InputInjector is only supported on skia")] #endif public async Task ToggleTest() diff --git a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs index 1de289638a6c..d503ef2a63f9 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs @@ -1,4 +1,4 @@ -#if __SKIA__ +#if HAS_INPUT_INJECTOR using System; using System.Collections.Generic; using System.Reflection; diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Input_Preview_Injection/Given_InputInjector.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Input_Preview_Injection/Given_InputInjector.cs index 4b05de419f0b..eb79f60cf283 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Input_Preview_Injection/Given_InputInjector.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Input_Preview_Injection/Given_InputInjector.cs @@ -1,4 +1,4 @@ -#if __SKIA__ +#if HAS_INPUT_INJECTOR using System; using System.Collections.Generic; diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs index e586e3e089dd..f29a083d2355 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs @@ -1320,7 +1320,7 @@ public async Task When_Explicit_Size_Clip_Changes() } #endif -#if __SKIA__ || WINAPPSDK +#if HAS_INPUT_INJECTOR || WINAPPSDK [TestMethod] [RunsOnUIThread] [RequiresFullWindow] @@ -1335,7 +1335,7 @@ public async Task When_Visual_Offset_Changes_HitTest() var rect = await UITestHelper.Load(sut); -#if __SKIA__ +#if HAS_UNO var (element, _) = VisualTreeHelper.HitTest(rect.GetCenter(), sut.XamlRoot); Assert.IsTrue(sut.IsAncestorOf(element)); #endif @@ -1371,7 +1371,7 @@ public async Task When_Visual_Offset_Changes_HitTest() Assert.AreEqual(rect.Height * 2, matrix4.OffsetY - matrix1.OffsetY); #endif -#if __SKIA__ +#if HAS_UNO var (element2, _) = VisualTreeHelper.HitTest(rect.GetCenter(), sut.XamlRoot); Assert.IsFalse(sut.IsAncestorOf(element2)); diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs index 138b83c82719..b306c96946ac 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading.Tasks; using Uno.Helpers; using Uno.UI.RuntimeTests.Helpers; @@ -20,13 +21,14 @@ using Size = Windows.Foundation.Size; #if __SKIA__ -using System; -using Windows.ApplicationModel.DataTransfer; -using Windows.System; -using Windows.UI.Input.Preview.Injection; using SkiaSharp; using Microsoft.UI.Xaml.Documents.TextFormatting; +#endif +#if HAS_INPUT_INJECTOR using Microsoft.UI.Xaml.Input; +using Windows.ApplicationModel.DataTransfer; +using Windows.System; +using Windows.UI.Input.Preview.Injection; #endif namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls @@ -903,7 +905,7 @@ public async Task When_TextTrimmingNone() #if HAS_UNO // GetMouse is not available on WinUI #region IsTextSelectionEnabled -#if __SKIA__ // enable this region when InputInjector and IsTextSelectionEnabled are supported on more platforms +#if HAS_INPUT_INJECTOR [TestMethod] public async Task When_IsTextSelectionEnabled_PointerDrag() { From 425b7f2b42c384263b736256f5d63195cce1fc89 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 24 Jul 2024 10:58:34 -0400 Subject: [PATCH 05/24] chore: Remove deprecated code --- .../Runtime/BrowserPointerInputSource.wasm.cs | 2 +- .../Xaml/DragDrop/DragDropExtension.wasm.cs | 11 +- .../Xaml/Window/WindowManagerInterop.wasm.cs | 73 +--- src/Uno.UI/ts/MonoSupport.ts | 1 - src/Uno.UI/ts/WindowManager.ts | 22 +- .../ts/Windows/UI/Xaml/UIElement.Pointers.ts | 351 ------------------ src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts | 7 - 7 files changed, 9 insertions(+), 458 deletions(-) delete mode 100644 src/Uno.UI/ts/Windows/UI/Xaml/UIElement.Pointers.ts delete mode 100644 src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts diff --git a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs index d8da8eca14f4..a59a8e3a2346 100644 --- a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs +++ b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs @@ -349,7 +349,7 @@ private enum HtmlPointerEvent : byte } [Flags] - private enum HtmlPointerButtonsState + internal enum HtmlPointerButtonsState { // https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#Determining_button_states diff --git a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs index 61eae35043e1..a77c7e999089 100644 --- a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs +++ b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs @@ -33,6 +33,7 @@ using NativeMethods = __Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension.NativeMethods; using System.Runtime.InteropServices.JavaScript; using Uno.UI.Runtime; +using _HtmlPointerButtonsState = Uno.UI.Runtime.BrowserPointerInputSource.HtmlPointerButtonsState; // As IDragDropExtension is internal, the generated registration cannot be used. // [assembly: ApiExtension(typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.IDragDropExtension), typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension))] @@ -390,16 +391,16 @@ public NativeDrop(DragDropExtensionEventArgs args) var position = new Point(_args.x, _args.y); var modifier = DragDropModifiers.None; - var buttons = (WindowManagerInterop.HtmlPointerButtonsState)_args.buttons; - if (buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Left)) + var buttons = (_HtmlPointerButtonsState)_args.buttons; + if (buttons.HasFlag(_HtmlPointerButtonsState.Left)) { modifier |= DragDropModifiers.LeftButton; } - if (buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Middle)) + if (buttons.HasFlag(_HtmlPointerButtonsState.Middle)) { modifier |= DragDropModifiers.MiddleButton; } - if (buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Right)) + if (buttons.HasFlag(_HtmlPointerButtonsState.Right)) { modifier |= DragDropModifiers.RightButton; } @@ -466,7 +467,7 @@ private struct DragDropExtensionEventArgs public override string ToString() { return $"[{eventName}] {timestamp:F0} @({x:F2},{y:F2})" - + $" | buttons: {(WindowManagerInterop.HtmlPointerButtonsState)buttons}" + + $" | buttons: {(_HtmlPointerButtonsState)buttons}" + $" | modifiers: {string.Join(", ", GetModifiers(this))}" + $" | allowed: {allowedOperations} ({ToDataPackageOperation(allowedOperations)})" + $" | accepted: {acceptedOperation}" diff --git a/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs b/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs index 2d08394a6a56..869ff5196969 100644 --- a/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs @@ -144,27 +144,8 @@ internal static void SetPointerEvents(IntPtr htmlId, bool enabled) NativeMethods.SetPointerEvents(htmlId, enabled); } - [TSInteropMessage] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct WindowManagerSetPointerEventsParams - { - public IntPtr HtmlId; - - public bool Enabled; - } - #endregion - internal static void SetPointerCapture(IntPtr htmlId, uint pointerId) - { - NativeMethods.SetPointerCapture(htmlId, pointerId); - } - - internal static void ReleasePointerCapture(IntPtr htmlId, uint pointerId) - { - NativeMethods.ReleasePointerCapture(htmlId, pointerId); - } - #region MeasureView internal static Size MeasureView(IntPtr htmlId, Size availableSize, bool measureContent) { @@ -775,25 +756,6 @@ private struct WindowManagerRegisterEventOnViewParams } #endregion - #region registerPointerEventsOnView - internal static void RegisterPointerEventsOnView(IntPtr htmlId) - { - var parms = new WindowManagerRegisterPointerEventsOnViewParams() - { - HtmlId = htmlId, - }; - - TSInteropMarshaller.InvokeJS("Uno:registerPointerEventsOnView", parms); - } - - [TSInteropMessage] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct WindowManagerRegisterPointerEventsOnViewParams - { - public IntPtr HtmlId; - } - #endregion - #region GetBBox internal static Rect GetBBox(IntPtr htmlId) @@ -1061,33 +1023,6 @@ internal static bool GetIsOverflowing(IntPtr htmlId) internal static void SetIsFocusable(IntPtr htmlId, bool isFocusable) => NativeMethods.SetIsFocusable(htmlId, isFocusable); - #region Pointers - [Flags] - internal enum HtmlPointerButtonsState - { - // https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#Determining_button_states - - None = 0, - Left = 1, - Middle = 4, - Right = 2, - X1 = 8, - X2 = 16, - Eraser = 32, - } - - internal enum HtmlPointerButtonUpdate - { - None = -1, - Left = 0, - Middle = 1, - Right = 2, - X1 = 3, - X2 = 4, - Eraser = 5 - } - #endregion - internal static partial class NativeMethods { [JSImport("globalThis.Uno.UI.WindowManager.current.arrangeElementNativeFast")] @@ -1145,9 +1080,6 @@ internal static partial void ArrangeElement( [JSImport("globalThis.Uno.UI.WindowManager.current.rawPixelsToBase64EncodeImage")] internal static partial string RawPixelsToBase64EncodeImage(IntPtr data, int width, int height); - [JSImport("globalThis.Uno.UI.WindowManager.current.releasePointerCapture")] - internal static partial void ReleasePointerCapture(IntPtr htmlId, double pointerId); - [JSImport("globalThis.Uno.UI.WindowManager.current.selectInputRange")] internal static partial void SelectInputRange(IntPtr htmlId, int start, int length); @@ -1163,10 +1095,7 @@ internal static partial void ArrangeElement( [JSImport("globalThis.Uno.UI.WindowManager.current.setCornerRadius")] internal static partial void SetCornerRadius(IntPtr htmlId, float topLeftX, float topLeftY, float topRightX, float topRightY, float bottomRightX, float bottomRightY, float bottomLeftX, float bottomLeftY); - [JSImport("globalThis.Uno.UI.WindowManager.current.setPointerCapture")] - internal static partial void SetPointerCapture(IntPtr htmlId, double pointerId); - - [JSImport("globalThis.Uno.UI.WindowManager.current.setPointerEventsNativeFast")] + [JSImport("globalThis.Uno.UI.WindowManager.current.setPointerEvents")] internal static partial void SetPointerEvents(IntPtr htmlId, bool enabled); [JSImport("globalThis.Uno.UI.WindowManager.current.setPropertyNativeFast")] diff --git a/src/Uno.UI/ts/MonoSupport.ts b/src/Uno.UI/ts/MonoSupport.ts index e532ae224dc7..faa7ad6c07bd 100644 --- a/src/Uno.UI/ts/MonoSupport.ts +++ b/src/Uno.UI/ts/MonoSupport.ts @@ -32,7 +32,6 @@ namespace MonoSupport { jsCallDispatcher.registerScope("UnoStatic_Windows_Storage_StorageFolder", Windows.Storage.StorageFolder); jsCallDispatcher.registerScope("UnoStatic_Windows_Storage_ApplicationDataContainer", Windows.Storage.ApplicationDataContainer); jsCallDispatcher.registerScope("UnoStatic_Windows_ApplicationModel_DataTransfer_DragDrop_Core_DragDropExtension", Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension); - jsCallDispatcher.registerScope("UnoStatic_Windows_UI_Xaml_UIElement", Microsoft.UI.Xaml.UIElement); jsCallDispatcher._isUnoRegistered = true; } diff --git a/src/Uno.UI/ts/WindowManager.ts b/src/Uno.UI/ts/WindowManager.ts index 1cb003d2cbf8..bd01736e4714 100644 --- a/src/Uno.UI/ts/WindowManager.ts +++ b/src/Uno.UI/ts/WindowManager.ts @@ -832,19 +832,7 @@ namespace Uno.UI { this.setAsArranged(element); } - private setPointerEvents(htmlId: number, enabled: boolean) { - const element = this.getView(htmlId); - element.style.pointerEvents = enabled ? "auto" : "none"; - } - - public setPointerEventsNative(pParams: number): boolean { - const params = WindowManagerSetPointerEventsParams.unmarshal(pParams); - this.setPointerEvents(params.HtmlId, params.Enabled); - - return true; - } - - public setPointerEventsNativeFast(htmlId: number, enabled: boolean) { + public setPointerEvents(htmlId: number, enabled: boolean) { this.getView(htmlId).style.pointerEvents = enabled ? "auto" : "none"; } @@ -1465,14 +1453,6 @@ namespace Uno.UI { element.style.overflow = "hidden"; // overflow: hidden is required here because the clipping can't do its job when it's non-rectangular. } - public setPointerCapture(viewId: number, pointerId: number): void { - this.getView(viewId).setPointerCapture(pointerId); - } - - public releasePointerCapture(viewId: number, pointerId: number): void { - this.getView(viewId).releasePointerCapture(pointerId); - } - public focusView(elementId: number): void { const element = this.getView(elementId); diff --git a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.Pointers.ts b/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.Pointers.ts deleted file mode 100644 index 5e6fe81d25da..000000000000 --- a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.Pointers.ts +++ /dev/null @@ -1,351 +0,0 @@ -namespace Microsoft.UI.Xaml { - import WindowManager = Uno.UI.WindowManager; - import HtmlEventDispatchResult = Uno.UI.HtmlEventDispatchResult; - import PointerDeviceType = Windows.Devices.Input.PointerDeviceType; - - export enum NativePointerEvent { - pointerover = 1, - pointerout = 1 << 1, - pointerdown = 1 << 2, - pointerup = 1 << 3, - pointercancel = 1 << 4, - - // Optional pointer events - pointermove = 1 << 5, - wheel = 1 << 6, - } - - export class UIElement_Pointers { - - private static _dispatchPointerEventMethod: any; - private static _dispatchPointerEventArgs: number; - private static _dispatchPointerEventResult: number; - private static _isManualyDispatchingOut: boolean = false; - - private static ensurePointersInit(): void { - if (!UIElement._dispatchPointerEventMethod) { - if ((globalThis).DotnetExports !== undefined) { - UIElement._dispatchPointerEventMethod = (globalThis).DotnetExports.UnoUI.Microsoft.UI.Xaml.UIElement.OnNativePointerEvent; - } else { - UIElement._dispatchPointerEventMethod = (Module).mono_bind_static_method("[Uno.UI] Microsoft.UI.Xaml.UIElement:OnNativePointerEvent"); - } - - document.getRootNode().addEventListener("pointerover", UIElement_Pointers.onRootPointerOverDispatching, { capture: true, passive: true }); - } - } - - public static setPointerEventArgs(pArgs: number): void { - UIElement_Pointers.ensurePointersInit(); - UIElement._dispatchPointerEventArgs = pArgs; - } - - public static setPointerEventResult(pArgs: number): void { - UIElement_Pointers.ensurePointersInit(); - UIElement._dispatchPointerEventResult = pArgs; - } - - public static subscribePointerEvents(pParams: number): void { - const params = Microsoft.UI.Xaml.NativePointerSubscriptionParams.unmarshal(pParams); - const element = WindowManager.current.getView(params.HtmlId); - - if (params.Events & NativePointerEvent.pointerover) { - element.addEventListener("pointerover", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerout) { - element.addEventListener("pointerout", UIElement.onPointerOutReceived); - } - if (params.Events & NativePointerEvent.pointerdown) { - element.addEventListener("pointerdown", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerup) { - element.addEventListener("pointerup", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointercancel) { - element.addEventListener("pointercancel", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointermove) { - element.addEventListener("pointermove", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.wheel) { - element.addEventListener("wheel", UIElement.onPointerEventReceived); - } - } - - public static unSubscribePointerEvents(pParams: number): void { - const params = Microsoft.UI.Xaml.NativePointerSubscriptionParams.unmarshal(pParams); - const element = WindowManager.current.getView(params.HtmlId); - - if (!element) { - return; - } - - if (params.Events & NativePointerEvent.pointerover) { - element.removeEventListener("pointerover", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerout) { - element.removeEventListener("pointerout", UIElement.onPointerOutReceived); - } - if (params.Events & NativePointerEvent.pointerdown) { - element.removeEventListener("pointerdown", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerup) { - element.removeEventListener("pointerup", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointercancel) { - element.removeEventListener("pointercancel", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointermove) { - element.removeEventListener("pointermove", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.wheel) { - element.removeEventListener("wheel", UIElement.onPointerEventReceived); - } - } - - private static onPointerEventReceived(evt: PointerEvent): void { - UIElement.dispatchPointerEvent(evt.currentTarget as HTMLElement | SVGElement, evt); - } - - private static onRootPointerOverDispatching(evt: PointerEvent): void { - const target = evt.target as HTMLElement | SVGElement; - if (!target) { - return; - } - - if (target.hasPointerCapture(evt.pointerId)) { - return; - } - - let prevElt: Element = null; - for (let elt of document.elementsFromPoint(evt.clientX, evt.clientY)) { - if (!elt.contains(target) // The elt is under the target (not a parent!) - && !elt.contains(prevElt) // The elt is not a parent of the previous element (so it has already been processed!) - ) { - // The element is under the target (not a parent!), with chromium browsers, if the target just popped up, - // it happens that the pointerout event is not raised on those elemnts under. - // Here we ensure to raise it manually before the pointerover event is being dispatched. - try { - UIElement._isManualyDispatchingOut = true; - elt.dispatchEvent(new PointerEvent("pointerout", evt)); - } - finally { - UIElement._isManualyDispatchingOut = false; - } - } - prevElt = elt; - } - } - - private static onPointerOutReceived(evt: PointerEvent): void { - if (UIElement._isManualyDispatchingOut) { - UIElement.onPointerEventReceived(evt); - return; - } - - const element = evt.currentTarget as HTMLElement | SVGElement; - - // When we capture the pointer, browser will raise an "out" event on nested elements - // and then an "over" on the element that captured the pointer. - // But those events will be raise right BEFORE the NEXT pointer event (e.g. a move). - // Note: We don't filter out the "over" event because it's handled in managed by tracking the IsOver state. - - // Here we filter the "out" event that is being raised after capture or release - // If the relatedTarget (the element that capture or release the pointer) is a child of (or is) the current element, - // it means pointer might not leaving the current element! - let elt = evt.relatedTarget as HTMLElement | SVGElement; - if (elt - && element.contains(elt) - && ( - // on capture, we just check if it has the the capture - elt.hasPointerCapture(evt.pointerId) - // on release, the target is the element itself - || evt.target == element) - ) - { - evt.stopPropagation(); - return; - } - - // Finally, here we filter out the events that are being raised when the pointer is leaving a nested element (which is bubbling in browser) - const targetBounds = (evt.target as HTMLElement | SVGElement).getBoundingClientRect(); - elt = evt.target as HTMLElement | SVGElement; - while (elt && elt != element) { - if (elt.style.pointerEvents != "none") { - const bounds = elt.getBoundingClientRect(); - if ( - (evt.clientY > bounds.top && (Math.abs(targetBounds.top - bounds.top) > 1)) - && (evt.clientY < bounds.bottom && (Math.abs(targetBounds.bottom - bounds.bottom) > 1)) - && (evt.clientX > bounds.left && (Math.abs(targetBounds.left - bounds.left) > 1)) - && (evt.clientX < bounds.right && (Math.abs(targetBounds.right - bounds.right) > 1)) - ) { - // There is child that is still under the pointer (and which will raise pointer events), so we should not propagate the event. - // Note: If the child is sharing the bounds with the target, we consider that the pointer is also leaving the intermediate child. - evt.stopPropagation(); - return; - } - } - elt = elt.parentElement; - } - - UIElement.onPointerEventReceived(evt); - } - - private static dispatchPointerEvent(element: HTMLElement | SVGElement, evt: PointerEvent): void { - if (!evt) { - return; - } - - const args = UIElement.toNativePointerEventArgs(evt); - args.HtmlId = Number(element.getAttribute("XamlHandle")); - - args.marshal(UIElement._dispatchPointerEventArgs); - UIElement._dispatchPointerEventMethod(); - const response = Microsoft.UI.Xaml.NativePointerEventResult.unmarshal(UIElement._dispatchPointerEventResult); - - if (response.Result & HtmlEventDispatchResult.StopPropagation) { - evt.stopPropagation(); - } - if (response.Result & HtmlEventDispatchResult.PreventDefault) { - evt.preventDefault(); - } - } - - //#region WheelLineSize - private static _wheelLineSize: number = undefined; - private static get wheelLineSize(): number { - // In web browsers, scroll might happen by pixels, line or page. - // But WinUI works only with pixels, so we have to convert it before send the value to the managed code. - // The issue is that there is no easy way get the "size of a line", instead we have to determine the CSS "line-height" - // defined in the browser settings. - // https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line - if (this._wheelLineSize == undefined) { - const el = document.createElement("div"); - el.style.fontSize = "initial"; - el.style.display = "none"; - document.body.appendChild(el); - const fontSize = window.getComputedStyle(el).fontSize; - document.body.removeChild(el); - - this._wheelLineSize = fontSize ? parseInt(fontSize) : 16; /* 16 = The current common default font size */ - - // Based on observations, even if the event reports 3 lines (the settings of windows), - // the browser will actually scroll of about 6 lines of text. - this._wheelLineSize *= 2.0; - } - - return this._wheelLineSize; - } - //#endregion - - //#region Helpers - private static toNativePointerEventArgs(evt: PointerEvent | WheelEvent): Microsoft.UI.Xaml.NativePointerEventArgs { - let src = evt.target as HTMLElement | SVGElement; - if (src instanceof SVGElement) { - // The XAML SvgElement are UIElement in Uno (so they have a XamlHandle), - // but as on WinUI they are not part of the visual tree, they should not be used as OriginalElement. - // Instead we should use the actual parent which is the XAML Shape. - const shape = (src as any).ownerSVGElement; - if (shape) { - src = shape; - } - } else if (src instanceof HTMLImageElement) { - // Same as above for images ( == HtmlImage, we use the parent
which is the XAML Image). - src = src.parentElement; - } - - let srcHandle = "0"; - while (src) { - const handle = src.getAttribute("XamlHandle"); - if (handle) { - srcHandle = handle; - break; - } - - src = src.parentElement; - } - - let pointerId: number, pointerType: PointerDeviceType, pressure: number; - let wheelDeltaX: number, wheelDeltaY: number; - if (evt instanceof WheelEvent) { - pointerId = (evt as any).mozInputSource ? 0 : 1; // Try to match the mouse pointer ID 0 for FF, 1 for others - pointerType = PointerDeviceType.Mouse; - pressure = 0.5; // like WinUI - wheelDeltaX = evt.deltaX; - wheelDeltaY = evt.deltaY; - - switch (evt.deltaMode) { - case WheelEvent.DOM_DELTA_LINE: // Actually this is supported only by FF - const lineSize = UIElement.wheelLineSize; - wheelDeltaX *= lineSize; - wheelDeltaY *= lineSize; - break; - case WheelEvent.DOM_DELTA_PAGE: - wheelDeltaX *= document.documentElement.clientWidth; - wheelDeltaY *= document.documentElement.clientHeight; - break; - } - } else { - pointerId = evt.pointerId; - pointerType = UIElement.toPointerDeviceType(evt.pointerType); - pressure = evt.pressure; - wheelDeltaX = 0; - wheelDeltaY = 0; - } - - const args = new Microsoft.UI.Xaml.NativePointerEventArgs(); - args.Event = UIElement.toNativeEvent(evt.type); - args.pointerId = pointerId; - args.x = evt.clientX; - args.y = evt.clientY; - args.ctrl = evt.ctrlKey; - args.shift = evt.shiftKey; - args.hasRelatedTarget = evt.relatedTarget !== null; - args.buttons = evt.buttons; - args.buttonUpdate = evt.button; - args.deviceType = pointerType; - args.srcHandle = Number(srcHandle); - args.timestamp = evt.timeStamp; - args.pressure = pressure; - args.wheelDeltaX = wheelDeltaX; - args.wheelDeltaY = wheelDeltaY; - - return args; - } - - private static toNativeEvent(eventName: string): NativePointerEvent { - switch (eventName) { - case "pointerover": - return NativePointerEvent.pointerover; - case "pointerout": - return NativePointerEvent.pointerout; - case "pointerdown" : - return NativePointerEvent.pointerdown; - case "pointerup" : - return NativePointerEvent.pointerup; - case "pointercancel" : - return NativePointerEvent.pointercancel; - case "pointermove" : - return NativePointerEvent.pointermove; - case "wheel": - return NativePointerEvent.wheel; - default: - return undefined; - } - } - - private static toPointerDeviceType(type: string): PointerDeviceType { - switch (type) { - case "touch": - return PointerDeviceType.Touch; - case "pen": - // Note: As of 2019-11-28, once pen pressed events pressed/move/released are reported as TOUCH on Firefox - // https://bugzilla.mozilla.org/show_bug.cgi?id=1449660 - return PointerDeviceType.Pen; - case "mouse": - default: - return PointerDeviceType.Mouse; - } - } - //#endregion - } -} diff --git a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts b/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts deleted file mode 100644 index 0b14b6bf5125..000000000000 --- a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -namespace Microsoft.UI.Xaml { - export class UIElement extends Microsoft.UI.Xaml.UIElement_Pointers { - - } -} From 597fee38dae722234868e28fce257f402a2f480a Mon Sep 17 00:00:00 2001 From: David Date: Thu, 25 Jul 2024 12:28:40 -0400 Subject: [PATCH 06/24] chore(reg): Fix CI build - iteration 1 --- .../SwipeControlTests/SwipeControlTests.cs | 3 +++ src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs index 6b607a5c55c8..38578810a941 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs @@ -70,6 +70,9 @@ public async Task When_MultipleItems() [Test] [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] +#if __SKIA__ + [Ignore("Invalid layout of items")] +#endif public Task When_InListView() => When_InScrollableContainer("UITests.Windows_UI_Xaml_Controls.SwipeControlTests.SwipeControl_ListView"); diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs index 53f1776491df..8bb36e429780 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs @@ -51,6 +51,9 @@ public async Task RunAsync(string metadataName) var assemblyName = "SamplesApp.Skia"; #elif __WASM__ var assemblyName = "SamplesApp.Wasm"; +#else + throw new PlatformNotSupportedException(); +#pragma warning disable CS0162 #endif if (TestServices.WindowHelper.IsXamlIsland) { @@ -78,6 +81,7 @@ public async Task RunAsync(string metadataName) { throw new InvalidOperationException($"Failed to run sample '{metadataName}'"); } +#pragma warning restore CS0162 } QueryResult[] IApp.Query(string marked) => Query(marked); @@ -264,7 +268,7 @@ private Exception NotSupported([CallerMemberName] string operation = "") public async ValueTask TakeScreenshotAsync(string name) { - var screenshot = await UITestHelper.ScreenShot((FrameworkElement)TestServices.WindowHelper.CurrentTestWindow.Content!); + var screenshot = await UITestHelper.ScreenShot((FrameworkElement)TestServices.WindowHelper.XamlRoot.Content!); #if false UITestHelper.Save(screenshot, name); #endif From d82f7fbddb5f34e116f0011973d6fe5daf6702b3 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 26 Jul 2024 13:44:22 +0200 Subject: [PATCH 07/24] chore(reg): Fix CI build - iteration 2 --- .../Tests/Uno_UI_Xaml_Core/Given_InputManager.cs | 2 +- src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs index d503ef2a63f9..eabaca1073d7 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs @@ -1,4 +1,4 @@ -#if HAS_INPUT_INJECTOR +#if HAS_INPUT_INJECTOR && !WINAPPSDK using System; using System.Collections.Generic; using System.Reflection; diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs index 8bb36e429780..e832f1a1bfb7 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs @@ -54,6 +54,7 @@ public async Task RunAsync(string metadataName) #else throw new PlatformNotSupportedException(); #pragma warning disable CS0162 + var assemblyName = ""; #endif if (TestServices.WindowHelper.IsXamlIsland) { From adbe9f557ff94760a14e1eb5253845e212b1acd2 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 26 Jul 2024 10:17:31 -0400 Subject: [PATCH 08/24] chore(reg): Fix CI build - iteration 3: Disable tests that relies on screenshots --- .../SwipeControlTests/SwipeControlTests.cs | 7 + .../Windows_UI_Xaml_Input/Capture_Tests.cs | 2 + src/Uno.CrossTargetting.targets | 15 +- .../Helpers/UITestHelper.cs | 4 + .../UITests/_Engine/RuntimeTestsApp.cs | 1 + ...enderTargetBitmap.UnmanagedArrayOfBytes.cs | 86 +++++++++++ .../Xaml/Media/Imaging/RenderTargetBitmap.cs | 135 ++++-------------- 7 files changed, 135 insertions(+), 115 deletions(-) create mode 100644 src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.UnmanagedArrayOfBytes.cs diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs index 38578810a941..dcdadeb86a3a 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs @@ -72,6 +72,8 @@ public async Task When_MultipleItems() [ActivePlatforms(Platform.iOS, Platform.Android)] #if __SKIA__ [Ignore("Invalid layout of items")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Test relies on screenshots which is not available on this platform.")] #endif public Task When_InListView() => When_InScrollableContainer("UITests.Windows_UI_Xaml_Controls.SwipeControlTests.SwipeControl_ListView"); @@ -79,6 +81,11 @@ public Task When_InListView() [Test] [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] +#if __SKIA__ + [Ignore("Invalid layout of items")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Test relies on screenshots which is not available on this platform.")] +#endif public Task When_InScrollViewer() => When_InScrollableContainer("UITests.Windows_UI_Xaml_Controls.SwipeControlTests.SwipeControl_ScrollViewer"); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs index 00cb26a099bf..165414f207b0 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs @@ -70,7 +70,9 @@ private async Task RunTest(string testName, Action act = null) App.WaitForElement(target); act(target); +#if HAS_RENDER_TARGET_BITMAP await TakeScreenshotAsync("Result"); +#endif result.GetDependencyPropertyValue("Text").Should().Be("SUCCESS"); } diff --git a/src/Uno.CrossTargetting.targets b/src/Uno.CrossTargetting.targets index 2214c7f005fb..f4f819b5a52d 100644 --- a/src/Uno.CrossTargetting.targets +++ b/src/Uno.CrossTargetting.targets @@ -54,6 +54,7 @@ uses render transforms instead of native scroll feature (if any) - UNO_HAS_MANAGED_POINTERS: Determines if the pointer events are dispatched by uno instead of the system (if any). - HAS_NATIVE_IMPLICIT_POINTER_CAPTURE: Indicate if the OS once a pointer is pressed, OS will send all pointer event to the same target (a.k.a. OriginalSource) + - HAS_RENDER_TARGET_BITMAP : Determines if the render target bitmap is implemented (and can be used to take screenshot in runtime tests) - Constants for Xamarin backends and SDK versions: https://docs.microsoft.com/en-us/xamarin/cross-platform/app-fundamentals/building-cross-platform-applications/platform-divergence-abstraction-divergent-implementation#conditional-compilation --> @@ -68,7 +69,7 @@ $(DefineConstants);__SKIA__;UNO_HAS_ENHANCED_HIT_TEST_PROPERTY;UNO_HAS_MANAGED_SCROLL_PRESENTER;UNO_HAS_MANAGED_POINTERS;SUPPORTS_RTL;UNO_HAS_ENHANCED_LIFECYCLE;UNO_HAS_BORDER_VISUAL - $(DefineConstants);UNO_SUPPORTS_NATIVEHOST;HAS_INPUT_INJECTOR + $(DefineConstants);UNO_SUPPORTS_NATIVEHOST;HAS_INPUT_INJECTOR;HAS_RENDER_TARGET_BITMAP @@ -80,21 +81,21 @@ - $(DefineConstants);XAMARIN;UNO_HAS_UIELEMENT_IMPLICIT_PINNING;HAS_NATIVE_IMPLICIT_POINTER_CAPTURE + $(DefineConstants);XAMARIN;UNO_HAS_UIELEMENT_IMPLICIT_PINNING;HAS_NATIVE_IMPLICIT_POINTER_CAPTURE;HAS_RENDER_TARGET_BITMAP - $(DefineConstants);XAMARIN;UNO_HAS_UIELEMENT_IMPLICIT_PINNING;HAS_NATIVE_IMPLICIT_POINTER_CAPTURE + $(DefineConstants);XAMARIN;UNO_HAS_UIELEMENT_IMPLICIT_PINNING;HAS_NATIVE_IMPLICIT_POINTER_CAPTURE;HAS_RENDER_TARGET_BITMAP 13.1 - $(DefineConstants);__MACOS__;XAMARIN;UNO_HAS_UIELEMENT_IMPLICIT_PINNING;UNO_HAS_MANAGED_SCROLL_PRESENTER;UNO_HAS_MANAGED_POINTERS + $(DefineConstants);__MACOS__;XAMARIN;UNO_HAS_UIELEMENT_IMPLICIT_PINNING;UNO_HAS_MANAGED_SCROLL_PRESENTER;UNO_HAS_MANAGED_POINTERS;HAS_RENDER_TARGET_BITMAP 10.15 - $(DefineConstants);__ANDROID__;XAMARIN;HAS_NATIVE_IMPLICIT_POINTER_CAPTURE + $(DefineConstants);__ANDROID__;XAMARIN;HAS_NATIVE_IMPLICIT_POINTER_CAPTURE;HAS_RENDER_TARGET_BITMAP 21.0 @@ -108,13 +109,13 @@ - $(DefineConstants);HAS_INPUT_INJECTOR;WINDOWS_WINUI + $(DefineConstants);HAS_INPUT_INJECTOR;WINDOWS_WINUI;HAS_RENDER_TARGET_BITMAP 10.0.19041.0 10.0.19041.0 - $(DefineConstants);NETFX_CORE;HAS_INPUT_INJECTOR + $(DefineConstants);NETFX_CORE;HAS_INPUT_INJECTOR;HAS_RENDER_TARGET_BITMAP diff --git a/src/Uno.UI.RuntimeTests/Helpers/UITestHelper.cs b/src/Uno.UI.RuntimeTests/Helpers/UITestHelper.cs index 996698afc6cf..42ebadf92f8a 100644 --- a/src/Uno.UI.RuntimeTests/Helpers/UITestHelper.cs +++ b/src/Uno.UI.RuntimeTests/Helpers/UITestHelper.cs @@ -67,6 +67,7 @@ public static async Task Load(T element, Func? isLoaded = null /// public static async Task ScreenShot(FrameworkElement element, bool opaque = false, ScreenShotScalingMode scaling = ScreenShotScalingMode.UsePhysicalPixelsWithImplicitScaling) { +#if HAS_RENDER_TARGET_BITMAP var renderer = new RenderTargetBitmap(); element.UpdateLayout(); await TestServices.WindowHelper.WaitForIdle(); @@ -96,6 +97,9 @@ public static async Task ScreenShot(FrameworkElement element, bool op } return bitmap; +#else + throw new NotSupportedException("Cannot take screenshot on this platform."); +#endif } public enum ScreenShotScalingMode diff --git a/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs index e832f1a1bfb7..24c827211272 100644 --- a/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs +++ b/src/Uno.UI.RuntimeTests/UITests/_Engine/RuntimeTestsApp.cs @@ -60,6 +60,7 @@ public async Task RunAsync(string metadataName) { assemblyName = "UnoIslands" + assemblyName; } + if (Type.GetType($"{metadataName}, {assemblyName}") is { } sampleType && Activator.CreateInstance(sampleType) is FrameworkElement sample) { diff --git a/src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.UnmanagedArrayOfBytes.cs b/src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.UnmanagedArrayOfBytes.cs new file mode 100644 index 000000000000..b6edfc4e1e35 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.UnmanagedArrayOfBytes.cs @@ -0,0 +1,86 @@ +#if !__ANDROID__ +#nullable enable +using System; +using System.Buffers; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Microsoft.UI.Xaml.Media.Imaging; + +public partial class RenderTargetBitmap +{ + private unsafe class UnmanagedArrayOfBytes + { + public nint Pointer; + public int Length { get; } + + public UnmanagedArrayOfBytes(int length) + { + Length = length; + Pointer = Marshal.AllocHGlobal(length); + GC.AddMemoryPressure(length); + } + + public byte this[int index] + { + get + { + return ((byte*)Pointer.ToPointer())[index]; + } + set + { + ((byte*)Pointer.ToPointer())[index] = value; + } + } + + ~UnmanagedArrayOfBytes() + { + Marshal.FreeHGlobal(Pointer); + GC.RemoveMemoryPressure(Length); + } + } + + // This is to avoid LOH array allocations + // https://stackoverflow.com/questions/52190423/c-sharp-access-unmanaged-array-using-memoryt-or-arraysegmentt + private sealed unsafe class UnmanagedMemoryManager : MemoryManager + where T : unmanaged + { + private readonly T* _pointer; + private readonly int _length; + + /// + /// Create a new UnmanagedMemoryManager instance at the given pointer and size + /// + public UnmanagedMemoryManager(T* pointer, int length) + { + if (length < 0) throw new ArgumentOutOfRangeException(nameof(length)); + _pointer = pointer; + _length = length; + } + /// + /// Obtains a span that represents the region + /// + public override Span GetSpan() => new(_pointer, _length); + + /// + /// Provides access to a pointer that represents the data (note: no actual pin occurs) + /// + public override MemoryHandle Pin(int elementIndex = 0) + { + if (elementIndex < 0 || elementIndex >= _length) + throw new ArgumentOutOfRangeException(nameof(elementIndex)); + return new MemoryHandle(_pointer + elementIndex); + } + + /// + /// Has no effect + /// + public override void Unpin() { } + + /// + /// Releases all resources associated with this object + /// + protected override void Dispose(bool disposing) { } + } +} +#endif diff --git a/src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.cs b/src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.cs index 745016074829..04d776da28af 100644 --- a/src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.cs +++ b/src/Uno.UI/UI/Xaml/Media/Imaging/RenderTargetBitmap.cs @@ -1,7 +1,4 @@ #nullable enable -#if !__IOS__ && !__ANDROID__ && !__SKIA__ && !__MACOS__ -#define NOT_IMPLEMENTED -#endif using System; using System.Collections.Generic; @@ -14,107 +11,39 @@ using Uno.UI.Xaml.Media; using Buffer = Windows.Storage.Streams.Buffer; using System.Buffers; -using System.Runtime.InteropServices; - using WinUICoreServices = Uno.UI.Xaml.Core.CoreServices; namespace Microsoft.UI.Xaml.Media.Imaging { -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public partial class RenderTargetBitmap : ImageSource { -#if !__ANDROID__ - // This is to avoid LOH array allocations - private unsafe class UnmanagedArrayOfBytes - { - public nint Pointer; - public int Length { get; } - - public UnmanagedArrayOfBytes(int length) - { - Length = length; - Pointer = Marshal.AllocHGlobal(length); - GC.AddMemoryPressure(length); - } - - public byte this[int index] - { - get - { - return ((byte*)Pointer.ToPointer())[index]; - } - set - { - ((byte*)Pointer.ToPointer())[index] = value; - } - } - - ~UnmanagedArrayOfBytes() - { - Marshal.FreeHGlobal(Pointer); - GC.RemoveMemoryPressure(Length); - } - } - - // https://stackoverflow.com/questions/52190423/c-sharp-access-unmanaged-array-using-memoryt-or-arraysegmentt - private sealed unsafe class UnmanagedMemoryManager : MemoryManager - where T : unmanaged - { - private readonly T* _pointer; - private readonly int _length; - - /// - /// Create a new UnmanagedMemoryManager instance at the given pointer and size - /// - public UnmanagedMemoryManager(T* pointer, int length) - { - if (length < 0) throw new ArgumentOutOfRangeException(nameof(length)); - _pointer = pointer; - _length = length; - } - /// - /// Obtains a span that represents the region - /// - public override Span GetSpan() => new Span(_pointer, _length); - - /// - /// Provides access to a pointer that represents the data (note: no actual pin occurs) - /// - public override MemoryHandle Pin(int elementIndex = 0) - { - if (elementIndex < 0 || elementIndex >= _length) - throw new ArgumentOutOfRangeException(nameof(elementIndex)); - return new MemoryHandle(_pointer + elementIndex); - } - - /// - /// Has no effect - /// - public override void Unpin() { } - - /// - /// Releases all resources associated with this object - /// - protected override void Dispose(bool disposing) { } - } -#endif - -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP internal const bool IsImplemented = false; #else internal const bool IsImplemented = true; #endif +#if !HAS_RENDER_TARGET_BITMAP + // The partial API that has to be implemented in each platform + + private static ImageData Open(UnmanagedArrayOfBytes buffer, int bufferLength, int width, int height) + => default; + + private (int ByteCount, int Width, int Height) RenderAsBgra8_Premul(UIElement element, ref UnmanagedArrayOfBytes? buffer, Size? scaledSize = null) + => throw new NotImplementedException("RenderTargetBitmap is not supported on this platform."); +#endif + #region PixelWidth -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public static DependencyProperty PixelWidthProperty { get; } = DependencyProperty.Register( "PixelWidth", typeof(int), typeof(RenderTargetBitmap), new FrameworkPropertyMetadata(default(int))); -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public int PixelWidth @@ -126,13 +55,13 @@ public int PixelWidth #region PixelHeight -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public static DependencyProperty PixelHeightProperty { get; } = DependencyProperty.Register( "PixelHeight", typeof(int), typeof(RenderTargetBitmap), new FrameworkPropertyMetadata(default(int))); -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public int PixelHeight @@ -142,10 +71,10 @@ public int PixelHeight } #endregion -#if !__ANDROID__ - private UnmanagedArrayOfBytes? _buffer; -#else +#if __ANDROID__ private byte[]? _buffer; +#else + private UnmanagedArrayOfBytes? _buffer; #endif private int _bufferSize; @@ -166,12 +95,7 @@ private protected override bool TryOpenSourceSync(int? targetWidth, int? targetH return image.HasData; } -#if NOT_IMPLEMENTED - private static ImageData Open(UnmanagedArrayOfBytes buffer, int bufferLength, int width, int height) - => default; -#endif - -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public IAsyncAction RenderAsync(UIElement? element, int scaledWidth, int scaledHeight) @@ -199,7 +123,7 @@ public IAsyncAction RenderAsync(UIElement? element, int scaledWidth, int scaledH return Task.CompletedTask; }); -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public IAsyncAction RenderAsync(UIElement? element) @@ -227,7 +151,7 @@ public IAsyncAction RenderAsync(UIElement? element) return Task.CompletedTask; }); -#if NOT_IMPLEMENTED +#if !HAS_RENDER_TARGET_BITMAP [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")] #endif public IAsyncOperation GetPixelsAsync() @@ -235,27 +159,22 @@ public IAsyncOperation GetPixelsAsync() { if (_buffer is null) { - return Task.FromResult(new Buffer(Array.Empty())); + return Task.FromResult(new Buffer([])); } -#if !__ANDROID__ +#if __ANDROID__ + return Task.FromResult(new Buffer(_buffer.AsMemory().Slice(0, _bufferSize))); +#else unsafe { var mem = new UnmanagedMemoryManager((byte*)_buffer.Pointer.ToPointer(), _bufferSize); return Task.FromResult(new Buffer(mem.Memory.Slice(0, _bufferSize))); } -#else - return Task.FromResult(new Buffer(_buffer.AsMemory().Slice(0, _bufferSize))); #endif }); -#if NOT_IMPLEMENTED - private (int ByteCount, int Width, int Height) RenderAsBgra8_Premul(UIElement element, ref UnmanagedArrayOfBytes? buffer, Size? scaledSize = null) - => throw new NotImplementedException("RenderTargetBitmap is not supported on this platform."); -#endif - #region Misc static helpers -#if !NOT_IMPLEMENTED +#if HAS_RENDER_TARGET_BITMAP #if __ANDROID__ private static void EnsureBuffer(ref byte[]? buffer, int length) { From 212d50aee64eb207c87d41e4ade2f183ca0f6b39 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 29 Jul 2024 05:57:50 -0400 Subject: [PATCH 09/24] chore(reg): Fix CI build - iteration 4: Fix UI tests --- src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj | 2 +- .../SwipeControlTests/SwipeControlTests.cs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj b/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj index f7c4c2ece07e..3b26d315785f 100644 --- a/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj +++ b/src/SamplesApp/SamplesApp.UITests/SamplesApp.UITests.csproj @@ -8,7 +8,7 @@ $(DefineConstants);TARGET_FRAMEWORK_OVERRIDE_IOS - $(NoWarn);SYSLIB1045 + $(NoWarn);SYSLIB1045;CS1998 diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs index dcdadeb86a3a..f10527aef787 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs @@ -9,9 +9,12 @@ using SamplesApp.UITests.Extensions; using SamplesApp.UITests.TestFramework; using Uno.Testing; -using Uno.UI.RuntimeTests.Helpers; using Uno.UITest.Helpers.Queries; +#if IS_RUNTIME_UI_TESTS +using Uno.UI.RuntimeTests.Helpers; +#endif + namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.SwipeControlTests { [TestFixture] From b1d77a58d508234436ce7f7d8afa5849ff5f6632 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 29 Jul 2024 09:28:21 -0400 Subject: [PATCH 10/24] chore(reg): Fix CI build - iteration 5: Update exclusion rules for tests --- .../SwipeControlTests/SwipeControlTests.cs | 4 +- src/Uno.CrossTargetting.targets | 12 ++- .../NavigationView/NavigationViewTests.uno.cs | 2 +- .../SplitButtonTests_InteractionTests.cs | 10 +-- .../Given_TabView.cs | 2 +- .../Given_TreeView.cs | 6 +- .../Uno_UI_Xaml_Core/Given_InputManager.cs | 8 +- .../Given_InteractionTracker.cs | 4 +- .../Tests/Windows_UI_Xaml/Given_UIElement.cs | 30 +++++--- .../Windows_UI_Xaml_Controls/Given_Border.cs | 4 +- .../Windows_UI_Xaml_Controls/Given_Button.cs | 4 +- .../Given_ComboBox.cs | 6 +- .../Given_CommandBar.cs | 2 +- .../Given_ContentDialog.cs | 2 +- .../Given_FlipView.cs | 2 +- .../Windows_UI_Xaml_Controls/Given_Grid.cs | 2 +- .../Given_ListViewBase.cs | 10 +-- .../Given_ScrollViewer.cs | 22 +++--- .../Windows_UI_Xaml_Controls/Given_Slider.cs | 7 +- .../Given_TextBlock.cs | 73 ++++++++++++++----- .../Given_Hyperlink.cs | 8 +- 21 files changed, 137 insertions(+), 83 deletions(-) diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs index f10527aef787..cb0166daa1f0 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/SwipeControlTests/SwipeControlTests.cs @@ -76,7 +76,7 @@ public async Task When_MultipleItems() #if __SKIA__ [Ignore("Invalid layout of items")] #elif !HAS_RENDER_TARGET_BITMAP - [Ignore("Test relies on screenshots which is not available on this platform.")] + [Ignore("Cannot take screenshot on this platform.")] #endif public Task When_InListView() => When_InScrollableContainer("UITests.Windows_UI_Xaml_Controls.SwipeControlTests.SwipeControl_ListView"); @@ -87,7 +87,7 @@ public Task When_InListView() #if __SKIA__ [Ignore("Invalid layout of items")] #elif !HAS_RENDER_TARGET_BITMAP - [Ignore("Test relies on screenshots which is not available on this platform.")] + [Ignore("Cannot take screenshot on this platform.")] #endif public Task When_InScrollViewer() => When_InScrollableContainer("UITests.Windows_UI_Xaml_Controls.SwipeControlTests.SwipeControl_ScrollViewer"); diff --git a/src/Uno.CrossTargetting.targets b/src/Uno.CrossTargetting.targets index f4f819b5a52d..a19d815a80f3 100644 --- a/src/Uno.CrossTargetting.targets +++ b/src/Uno.CrossTargetting.targets @@ -55,6 +55,8 @@ - UNO_HAS_MANAGED_POINTERS: Determines if the pointer events are dispatched by uno instead of the system (if any). - HAS_NATIVE_IMPLICIT_POINTER_CAPTURE: Indicate if the OS once a pointer is pressed, OS will send all pointer event to the same target (a.k.a. OriginalSource) - HAS_RENDER_TARGET_BITMAP : Determines if the render target bitmap is implemented (and can be used to take screenshot in runtime tests) + - UNO_HAS_BORDER_VISUAL: Determine if borders are rendered using compostion APIs by Uno (or using native promitives) + - HAS_COMPOSITION_API : Determines if teh composition APIs (i.e. UIElement.Visual) are supported or not. - Constants for Xamarin backends and SDK versions: https://docs.microsoft.com/en-us/xamarin/cross-platform/app-fundamentals/building-cross-platform-applications/platform-divergence-abstraction-divergent-implementation#conditional-compilation --> @@ -68,8 +70,10 @@ - $(DefineConstants);__SKIA__;UNO_HAS_ENHANCED_HIT_TEST_PROPERTY;UNO_HAS_MANAGED_SCROLL_PRESENTER;UNO_HAS_MANAGED_POINTERS;SUPPORTS_RTL;UNO_HAS_ENHANCED_LIFECYCLE;UNO_HAS_BORDER_VISUAL - $(DefineConstants);UNO_SUPPORTS_NATIVEHOST;HAS_INPUT_INJECTOR;HAS_RENDER_TARGET_BITMAP + $(DefineConstants);__SKIA__;SUPPORTS_RTL;UNO_SUPPORTS_NATIVEHOST;UNO_HAS_ENHANCED_LIFECYCLE + $(DefineConstants);UNO_HAS_MANAGED_POINTERS;UNO_HAS_ENHANCED_HIT_TEST_PROPERTY;UNO_HAS_MANAGED_SCROLL_PRESENTER;HAS_INPUT_INJECTOR + $(DefineConstants);HAS_COMPOSITION_API;UNO_HAS_BORDER_VISUAL + $(DefineConstants);HAS_RENDER_TARGET_BITMAP @@ -109,13 +113,13 @@ - $(DefineConstants);HAS_INPUT_INJECTOR;WINDOWS_WINUI;HAS_RENDER_TARGET_BITMAP + $(DefineConstants);HAS_INPUT_INJECTOR;WINDOWS_WINUI;HAS_RENDER_TARGET_BITMAP;HAS_COMPOSITION_API 10.0.19041.0 10.0.19041.0 - $(DefineConstants);NETFX_CORE;HAS_INPUT_INJECTOR;HAS_RENDER_TARGET_BITMAP + $(DefineConstants);NETFX_CORE;HAS_INPUT_INJECTOR;HAS_RENDER_TARGET_BITMAP;HAS_COMPOSITION_API diff --git a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/NavigationView/NavigationViewTests.uno.cs b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/NavigationView/NavigationViewTests.uno.cs index 6d634d757e91..08eb73e4eb15 100644 --- a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/NavigationView/NavigationViewTests.uno.cs +++ b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/NavigationView/NavigationViewTests.uno.cs @@ -16,7 +16,7 @@ public partial class NavigationViewTests : MUXApiTestBase { [TestMethod] #if !HAS_INPUT_INJECTOR || !HAS_UNO_WINUI - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task VerifyNavigationViewItemExpandsCollapsesWhenChevronTapped() { diff --git a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs index 7a2d42f2aa23..033029d7a67b 100644 --- a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs +++ b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/SplitButton/SplitButtonTests_InteractionTests.cs @@ -32,7 +32,7 @@ public partial class SplitButtonTests { [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task BasicInteractionTest() { @@ -71,7 +71,7 @@ public async Task BasicInteractionTest() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task CommandTest() { @@ -124,7 +124,7 @@ public async Task CommandTest() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task TouchTest() { @@ -216,7 +216,7 @@ public async Task AccessibilityTest() [TestMethod] #if !__SKIA__ - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task KeyboardTest() { @@ -266,7 +266,7 @@ public async Task KeyboardTest() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task ToggleTest() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TabView.cs b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TabView.cs index f8caa88ce8e7..1d7155a74ea8 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TabView.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TabView.cs @@ -26,7 +26,7 @@ public class Given_TabView #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_First_Item_Unselected() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TreeView.cs b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TreeView.cs index 07e4a71a11b0..e4d8509aa6ad 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TreeView.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_TreeView.cs @@ -69,7 +69,7 @@ public partial class Given_TreeView #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_TreeViewItem_Dragged_Near_the_Edge() { @@ -240,7 +240,7 @@ public async Task When_TreeViewItem_Collapsed_Children_Removed_From_Tree() // https://github.com/unoplatform/uno/issues/16041 [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #elif HAS_UNO && !HAS_UNO_WINUI [Ignore("Fails on UWP branch as mixing WUX and MUX types causes errors.")] #endif @@ -322,7 +322,7 @@ public async Task When_TreeViewItem_Dragged_NRE() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #elif HAS_UNO && !HAS_UNO_WINUI [Ignore("Fails on UWP branch as mixing WUX and MUX types causes errors.")] #endif diff --git a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs index eabaca1073d7..f7454fe15388 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs @@ -28,7 +28,7 @@ public class Given_InputManager { [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_VisibilityChangesWhileDispatching_Then_RecomputeOriginalSource() { @@ -69,7 +69,7 @@ public async Task When_VisibilityChangesWhileDispatching_Then_RecomputeOriginalS [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_LeaveElementWhileManipulating_Then_CaptureNotLost() { @@ -124,7 +124,7 @@ public async Task When_LeaveElementWhileManipulating_Then_CaptureNotLost() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Hover_No_Delay_For_VisualState_Update() { @@ -147,7 +147,7 @@ public async Task When_Hover_No_Delay_For_VisualState_Update() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Scroll_No_Delay_For_VisualState_Update() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs index d876e0e82eda..f6ce5d2f79bb 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs @@ -177,7 +177,7 @@ public async Task When_TryUpdatePositionWithAdditionalVelocity_TwoCalls() [TestMethod] [RequiresFullWindow] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #elif !HAS_UNO [Ignore("Test fails on Windows. For some reason, Drag isn't doing what we expect it to for an unknown reason.")] #endif @@ -268,7 +268,7 @@ public async Task When_UserInteraction() [TestMethod] [RequiresFullWindow] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_MouseWheel() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs index f29a083d2355..aab845b5ec1b 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs @@ -29,17 +29,16 @@ using Uno.Extensions; using Uno.UI.RuntimeTests.Helpers; using Point = System.Drawing.Point; - -#if __IOS__ -using UIKit; -#elif __MACOS__ -using AppKit; -#else using Uno.UI; using Windows.UI; using Windows.ApplicationModel.Appointments; using Microsoft.UI.Xaml.Hosting; using Uno.UI.Toolkit.Extensions; + +#if __IOS__ +using UIKit; +#elif __MACOS__ +using AppKit; #endif namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml @@ -1320,13 +1319,15 @@ public async Task When_Explicit_Size_Clip_Changes() } #endif -#if HAS_INPUT_INJECTOR || WINAPPSDK [TestMethod] [RunsOnUIThread] [RequiresFullWindow] +#if !HAS_COMPOSITION_API + [Ignore("Composition APIs are not supported on this platform.")] +#endif public async Task When_Visual_Offset_Changes_HitTest() { - var sut = new Button() + var sut = new Button { Content = "Click", }; @@ -1383,9 +1384,12 @@ public async Task When_Visual_Offset_Changes_HitTest() [TestMethod] [RunsOnUIThread] [RequiresFullWindow] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#endif public async Task When_Visual_Offset_Changes_InjectedPointer() { - var sut = new Button() + var sut = new Button { Content = "Click", }; @@ -1553,7 +1557,6 @@ public async Task When_Element_Has_Translation_And_Visual_Has_Offset() #endif } #endif -#endif #if HAS_UNO [TestMethod] @@ -1674,13 +1677,18 @@ public async Task When_ScaleTransform_HitTest(bool addClip) } #endif -#if HAS_UNO && HAS_INPUT_INJECTOR +#if HAS_UNO #region Drag and Drop [TestMethod] [RunsOnUIThread] [DataRow(true)] [DataRow(false)] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif __WASM__ + [Ignore("Failing on WASM: https://github.com/unoplatform/uno/issues/17742")] +#endif public async Task When_DragOver_Fires_Along_DragEnter_Drop(bool waitAfterRelease) { if (TestServices.WindowHelper.IsXamlIsland) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Border.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Border.cs index 8af63367f579..81251999fa6f 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Border.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Border.cs @@ -577,7 +577,7 @@ public async Task Border_LinearGradient() #if HAS_UNO #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #else [TestMethod] [RunsOnUIThread] @@ -616,7 +616,7 @@ public async Task Nested_Element_Tapped() } #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #else [TestMethod] [RunsOnUIThread] diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs index f8efe8ed5fc7..86d4be18d846 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs @@ -178,7 +178,7 @@ public async Task When_Command_Never_Stops() #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_DoubleTap_Timing() { @@ -255,7 +255,7 @@ async Task Release(uint i) #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Tapped_PointerPressed_Is_Not_Raised() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs index 3db3a894edfe..fc07f8cfc3b6 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs @@ -235,7 +235,7 @@ public async Task When_ComboBox_Constrained_By_Parent() #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_PointerWheel() { @@ -1058,7 +1058,7 @@ public async Task When_SelectedItem_Active_VisualState() [RequiresFullWindow] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Mouse_Opened_And_Closed() { @@ -1129,7 +1129,7 @@ public async Task When_Mouse_Opened_And_Closed() [RequiresFullWindow] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Mouse_Opened_And_Closed_Fluent() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CommandBar.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CommandBar.cs index 54d9acfb20b8..b81f9c3a48e3 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CommandBar.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_CommandBar.cs @@ -45,7 +45,7 @@ public async Task TestNativeCommandBarIcon() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Popup_Open_Then_Click_Outside() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentDialog.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentDialog.cs index 84effd8fe43a..b7b1dd2f54df 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentDialog.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentDialog.cs @@ -28,7 +28,7 @@ public class Given_ContentDialog #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Press_Should_Not_Lose_Focus() diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_FlipView.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_FlipView.cs index ac624d3a017f..bfa55b3960a2 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_FlipView.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_FlipView.cs @@ -500,7 +500,7 @@ void UpdateRadioButtonSelection(int selectedIndex) #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_ScrollWheel() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs index 1f4e730f2e00..2656b7a45516 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs @@ -187,7 +187,7 @@ await RunOnUIThread.ExecuteAsync(() => [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Grid_Child_Canvas_ZIndex() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs index 8972b3e4b0a7..9ba6565ac2ae 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs @@ -842,7 +842,7 @@ public async Task When_Different_Selections_IsMultiSelectCheckBoxEnabled() [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Multiple_Selection_Pointer() { @@ -975,7 +975,7 @@ async Task AssertSelected() [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Extended_Selection_Pointer() { @@ -1186,7 +1186,7 @@ async Task AssertSelected() [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Extended_Selection_SelectedIndex_Changed_Mixed() { @@ -1751,7 +1751,7 @@ string RandomString(int length) [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Large_List_Scroll_To_End_Then_Back_Up_TryClick() { @@ -4625,7 +4625,7 @@ public async Task When_ScrollIntoView_Containers_With_Varying_Heights() [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_UpdateLayout_In_DragDropping() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs index fa4bd43cd2f2..41598e1f2b2c 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs @@ -322,7 +322,7 @@ public async Task When_ArrowKeys_Pressed(int width, int height, int horizontalDe [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_ScrollViewer_Pressed() { @@ -598,7 +598,7 @@ public async Task When_Scrolled_ViewportSizeLargerThanContent() #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_WheelChanged_OnlyHorizontallyScrollable() { @@ -651,7 +651,7 @@ public async Task When_WheelChanged_OnlyHorizontallyScrollable() [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Nested_ScrollViewers_WheelChanged() { @@ -751,7 +751,7 @@ public async Task When_Space_Already_Handled() [RunsOnUIThread] [RequiresFullWindow] #if !__SKIA__ - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Pointer_Clicks_Inside_ScrollViewer() { @@ -1262,8 +1262,10 @@ await WindowHelper.WaitFor( [TestMethod] [RunsOnUIThread] -#if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] +#if __WASM__ + [Ignore("Scrolling is handled by native code and InputInjector is not yet able to inject native pointers.")] +#elif !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_TouchScroll_Then_NestedElementReceivePointerEvents() { @@ -1307,7 +1309,7 @@ public async Task When_TouchScroll_Then_NestedElementReceivePointerEvents() [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_TouchTap_Then_NestedElementReceivePointerEvents() { @@ -1348,8 +1350,10 @@ public async Task When_TouchTap_Then_NestedElementReceivePointerEvents() [TestMethod] [RunsOnUIThread] -#if !HAS_INPUT_INJECTOR - [Ignore("Pointer injection supported only on skia for now.")] +#if __WASM__ + [Ignore("Scrolling is handled by native code and InputInjector is not yet able to inject native pointers.")] +#elif !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_ReversedMouseWheel_Then_ScrollInReversedDirection() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Slider.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Slider.cs index c8fc2668ff87..4def1e82f94c 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Slider.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Slider.cs @@ -3,6 +3,7 @@ using System.Text; using System.Threading.Tasks; using Windows.UI.Input.Preview.Injection; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -101,7 +102,7 @@ public async Task When_Value_Decimal() #if HAS_UNO [TestMethod] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Slider_Dragged() { @@ -129,13 +130,13 @@ public async Task When_Slider_Dragged() mouse.Press(slider.GetAbsoluteBounds().GetCenter()); await WindowHelper.WaitForIdle(); - Assert.IsTrue(Math.Abs(50 - slider.Value) < 1); + slider.Value.Should().BeInRange(49, 52, "we dragged the thumb at the center of the slider"); var clickableLength = slider.ActualWidth - slider.FindVisualChildByType().ActualWidth; mouse.MoveBy(clickableLength / 4, 0); - Assert.IsTrue(Math.Abs(75 - slider.Value) < 1); + slider.Value.Should().BeInRange(74, 76, "we dragged the thumb 1/4 of width on right"); mouse.Release(); } diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs index b306c96946ac..5d8dcdc0af8b 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs @@ -9,8 +9,12 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Documents; +using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media.Imaging; +using Windows.ApplicationModel.DataTransfer; +using Windows.System; +using Windows.UI.Input.Preview.Injection; using FluentAssertions; using static Private.Infrastructure.TestServices; using System.Collections.Generic; @@ -24,12 +28,6 @@ using SkiaSharp; using Microsoft.UI.Xaml.Documents.TextFormatting; #endif -#if HAS_INPUT_INJECTOR -using Microsoft.UI.Xaml.Input; -using Windows.ApplicationModel.DataTransfer; -using Windows.System; -using Windows.UI.Input.Preview.Injection; -#endif namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls { @@ -39,6 +37,8 @@ public class Given_TextBlock { #if __ANDROID__ [Ignore("Visually looks good, but fails :(")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] #endif [TestMethod] [DataRow((ushort)400, FontStyle.Italic, FontStretch.Condensed, "ms-appx:///Assets/Fonts/OpenSans/OpenSans_Condensed-MediumItalic.ttf")] @@ -713,16 +713,13 @@ public async Task When_FontFamily_In_AndroidAsset() } [TestMethod] - public async Task When_SolidColorBrush_With_Opacity() - { - if (!ApiInformation.IsTypePresent("Microsoft.UI.Xaml.Media.Imaging.RenderTargetBitmap")) - { - Assert.Inconclusive(); // System.NotImplementedException: RenderTargetBitmap is not supported on this platform.; - } - #if __MACOS__ - Assert.Inconclusive(); + [Ignore("Currently fails on macOS, part of #9282 epic")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] #endif + public async Task When_SolidColorBrush_With_Opacity() + { var SUT = new TextBlock { Text = "••••••••", @@ -905,8 +902,12 @@ public async Task When_TextTrimmingNone() #if HAS_UNO // GetMouse is not available on WinUI #region IsTextSelectionEnabled -#if HAS_INPUT_INJECTOR [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_PointerDrag() { var SUT = new TextBlock @@ -950,6 +951,11 @@ public async Task When_IsTextSelectionEnabled_PointerDrag() } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_DoubleTapped() { var SUT = new TextBlock @@ -995,6 +1001,11 @@ public async Task When_IsTextSelectionEnabled_DoubleTapped() } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_Chunking_DoubleTapped() { var SUT = new TextBlock @@ -1041,6 +1052,11 @@ public async Task When_IsTextSelectionEnabled_Chunking_DoubleTapped() } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_Wrapping_DoubleTapped() { var SUT = new TextBlock @@ -1089,6 +1105,9 @@ public async Task When_IsTextSelectionEnabled_Wrapping_DoubleTapped() } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_SurrogatePair_Copy() { var SUT = new TextBlock @@ -1118,6 +1137,9 @@ public async Task When_IsTextSelectionEnabled_SurrogatePair_Copy() } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_CRLF() { var SUT = new TextBlock @@ -1179,7 +1201,9 @@ public async Task When_IsTextSelectionEnabled_CRLF() } [TestMethod] -#if !__SKIA__ +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif !__SKIA__ [Ignore("The context menu is only implemented on skia.")] #endif [DataRow(true)] @@ -1210,6 +1234,11 @@ public async Task When_TextBlock_RightTapped(bool isTextSelectionEnabled) } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_Keyboard_SelectAll_Copy() { var SUT = new TextBlock @@ -1252,6 +1281,11 @@ public async Task When_IsTextSelectionEnabled_Keyboard_SelectAll_Copy() } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_ContextMenu_SelectAll() { var SUT = new TextBlock @@ -1291,6 +1325,9 @@ public async Task When_IsTextSelectionEnabled_ContextMenu_SelectAll() } [TestMethod] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#endif public async Task When_IsTextSelectionEnabled_ContextMenu_Copy() { var SUT = new TextBlock @@ -1322,9 +1359,8 @@ public async Task When_IsTextSelectionEnabled_ContextMenu_Copy() Assert.AreEqual("world", await Clipboard.GetContent()!.GetTextAsync()); } -#endif - #endregion +#endif #if __SKIA__ [TestMethod] @@ -1339,7 +1375,6 @@ public async Task When_Inside_TextBox_FireDrawingEventsOnEveryRedraw() Assert.IsFalse(textBox.TextBoxView.DisplayBlock.Inlines.FireDrawingEventsOnEveryRedraw); } -#endif #endif } } diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs index 7f4e645e5f93..ae7674d52373 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs @@ -49,7 +49,7 @@ public async Task TestSimpleHyperlink(bool useDark, bool useFluent, string expec [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] + [Ignore("InputInjector is not supported on this platform.")] #endif [DataRow(true, false, "#FF0078D7", "#99FFFFFF")] [DataRow(false, false, "#FF0078D7", "#99000000")] @@ -99,8 +99,10 @@ public async Task TestHoveredHyperlink(bool useDark, bool useFluent, string expe #if HAS_UNO [TestMethod] [RunsOnUIThread] -#if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on skia")] +#if __WASM__ + [Ignore("Visual states/Colors are handled by browser.")] +#elif !HAS_INPUT_INJECTOR + [Ignore("Test needs InputInjector which is not supported on this platform.")] #endif [DataRow(true, false, "#FF0078D7", "#99FFFFFF", "#66FFFFFF")] [DataRow(false, false, "#FF0078D7", "#99000000", "#66000000")] From feceeb6ce5620c0e0bdcb25a148102027bc4cc95 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 29 Jul 2024 14:38:08 -0400 Subject: [PATCH 11/24] chore(reg): Fix CI build - iteration 6 --- .../Tests/Uno_UI_Xaml_Core/Given_InputManager.cs | 4 +++- .../Given_InteractionTracker.cs | 14 ++++++++++++-- .../Tests/Windows_UI_Xaml/Given_UIElement.cs | 4 +++- .../Tests/Windows_UI_Xaml_Controls/Given_Button.cs | 3 +++ .../Windows_UI_Xaml_Controls/Given_ScrollViewer.cs | 4 +++- .../Windows_UI_Xaml_Controls/Given_TextBlock.cs | 2 ++ .../Windows_UI_Xaml_Documents/Given_Hyperlink.cs | 4 +++- 7 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs index f7454fe15388..77972928366f 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Uno_UI_Xaml_Core/Given_InputManager.cs @@ -146,7 +146,9 @@ public async Task When_Hover_No_Delay_For_VisualState_Update() } [TestMethod] -#if !HAS_INPUT_INJECTOR +#if __WASM__ + [Ignore("Scrolling is handled by native code and InputInjector is not yet able to inject native pointers.")] +#elif !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Scroll_No_Delay_For_VisualState_Update() diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs index f6ce5d2f79bb..55a36911e0d6 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Composition/Given_InteractionTracker.cs @@ -52,6 +52,9 @@ private async Task WaitTrackerLogs(TrackerOwner owner) } [TestMethod] +#if !HAS_COMPOSITION_API + [Ignore("Composition APIs are not supported on this platform.")] +#endif public async Task When_TryUpdatePositionWithAdditionalVelocity_SingleCall() { var border = new Border() @@ -113,6 +116,9 @@ public async Task When_TryUpdatePositionWithAdditionalVelocity_SingleCall() } [TestMethod] +#if !HAS_COMPOSITION_API + [Ignore("Composition APIs are not supported on this platform.")] +#endif public async Task When_TryUpdatePositionWithAdditionalVelocity_TwoCalls() { var border = new Border() @@ -176,7 +182,9 @@ public async Task When_TryUpdatePositionWithAdditionalVelocity_TwoCalls() [TestMethod] [RequiresFullWindow] -#if !HAS_INPUT_INJECTOR +#if !HAS_COMPOSITION_API + [Ignore("Composition APIs are not supported on this platform.")] +#elif !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] #elif !HAS_UNO [Ignore("Test fails on Windows. For some reason, Drag isn't doing what we expect it to for an unknown reason.")] @@ -267,7 +275,9 @@ public async Task When_UserInteraction() #if HAS_UNO [TestMethod] [RequiresFullWindow] -#if !HAS_INPUT_INJECTOR +#if !HAS_COMPOSITION_API + [Ignore("Composition APIs are not supported on this platform.")] +#elif !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_MouseWheel() diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs index aab845b5ec1b..fa8acc766dd1 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.cs @@ -1384,7 +1384,9 @@ public async Task When_Visual_Offset_Changes_HitTest() [TestMethod] [RunsOnUIThread] [RequiresFullWindow] -#if !HAS_INPUT_INJECTOR +#if !HAS_COMPOSITION_API + [Ignore("Composition APIs are not supported on this platform.")] +#elif !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Visual_Offset_Changes_InjectedPointer() diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs index 86d4be18d846..418e97659d07 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Button.cs @@ -123,6 +123,9 @@ public async Task When_Command_Executing_With_Delay_IsEnabled() [DataRow(typeof(Button))] [DataRow(typeof(ToggleButton))] [DataRow(typeof(RepeatButton))] +#if !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_BorderThickness_Zero(Type type) { using var fluent = StyleHelper.UseFluentStyles(); diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs index 41598e1f2b2c..da0e7235f4e7 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ScrollViewer.cs @@ -650,7 +650,9 @@ public async Task When_WheelChanged_OnlyHorizontallyScrollable() } [TestMethod] -#if !HAS_INPUT_INJECTOR +#if __WASM__ + [Ignore("Scrolling is handled by native code and InputInjector is not yet able to inject native pointers.")] +#elif !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Nested_ScrollViewers_WheelChanged() diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs index 5d8dcdc0af8b..f8d89dbb6376 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs @@ -1327,6 +1327,8 @@ public async Task When_IsTextSelectionEnabled_ContextMenu_SelectAll() [TestMethod] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif !__SKIA__ + [Ignore("The context menu is only implemented on skia.")] #endif public async Task When_IsTextSelectionEnabled_ContextMenu_Copy() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs index ae7674d52373..fac78e0e747b 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs @@ -48,7 +48,9 @@ public async Task TestSimpleHyperlink(bool useDark, bool useFluent, string expec #if HAS_UNO [TestMethod] [RunsOnUIThread] -#if !HAS_INPUT_INJECTOR +#if __WASM__ + [Ignore("Visual states/Colors are handled by browser.")] +#elif !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] #endif [DataRow(true, false, "#FF0078D7", "#99FFFFFF")] From 104993925be8798484966d79a1505cb98aaa71b5 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 30 Jul 2024 04:17:41 -0400 Subject: [PATCH 12/24] chore(reg): Fix CI build - iteration 7 --- .../Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs | 4 ++++ .../Tests/Windows_UI_Xaml_Controls/Given_Grid.cs | 2 ++ .../Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs | 4 ++++ .../Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs | 4 ++++ .../Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs | 3 +++ .../Windows_UI_Xaml_Controls/Icons/Given_BitmapIcon.cs | 6 ++++++ 6 files changed, 23 insertions(+) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs index fc07f8cfc3b6..ea7da9715b48 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs @@ -1059,6 +1059,8 @@ public async Task When_SelectedItem_Active_VisualState() [RunsOnUIThread] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] #endif public async Task When_Mouse_Opened_And_Closed() { @@ -1130,6 +1132,8 @@ public async Task When_Mouse_Opened_And_Closed() [RunsOnUIThread] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] #endif public async Task When_Mouse_Opened_And_Closed_Fluent() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs index 2656b7a45516..83b86db7d323 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Grid.cs @@ -188,6 +188,8 @@ await RunOnUIThread.ExecuteAsync(() => [RunsOnUIThread] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif __WASM__ + [Ignore("Failing on WASM: https://github.com/unoplatform/uno/issues/17742")] #endif public async Task When_Grid_Child_Canvas_ZIndex() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs index 9ba6565ac2ae..d17f997a6024 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs @@ -1752,6 +1752,8 @@ string RandomString(int length) [RunsOnUIThread] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] #endif public async Task When_Large_List_Scroll_To_End_Then_Back_Up_TryClick() { @@ -4626,6 +4628,8 @@ public async Task When_ScrollIntoView_Containers_With_Varying_Heights() [RunsOnUIThread] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif __WASM__ + [Ignore("Failing on WASM: https://github.com/unoplatform/uno/issues/17742")] #endif public async Task When_UpdateLayout_In_DragDropping() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs index f8d89dbb6376..6d9c46cc6b56 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs @@ -1107,6 +1107,8 @@ public async Task When_IsTextSelectionEnabled_Wrapping_DoubleTapped() [TestMethod] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif __WASM__ + [Ignore("Requires authorization to access to the clipboard on WASM.")] #endif public async Task When_IsTextSelectionEnabled_SurrogatePair_Copy() { @@ -1139,6 +1141,8 @@ public async Task When_IsTextSelectionEnabled_SurrogatePair_Copy() [TestMethod] #if !HAS_INPUT_INJECTOR [Ignore("InputInjector is not supported on this platform.")] +#elif __WASM__ + [Ignore("Requires authorization to access to the clipboard on WASM.")] #endif public async Task When_IsTextSelectionEnabled_CRLF() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs index 5b46b67bdb5d..eaa5528bcd92 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs @@ -107,6 +107,9 @@ public async Task When_TwoWay_Text_Binding(UpdateSourceTrigger trigger) } [TestMethod] +#if !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_BorderThickness_Zero() { using var fluent = StyleHelper.UseFluentStyles(); diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Icons/Given_BitmapIcon.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Icons/Given_BitmapIcon.cs index 9d56447454aa..ef0d27b15016 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Icons/Given_BitmapIcon.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Icons/Given_BitmapIcon.cs @@ -55,6 +55,9 @@ public async Task When_Themed_Fluent() } [TestMethod] +#if !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_Foreground_Set_With_ShowAsMonochrome_False() { var bitmapIcon = new BitmapIcon() @@ -76,6 +79,9 @@ public async Task When_Foreground_Set_With_ShowAsMonochrome_False() } [TestMethod] +#if !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_Foreground_Set_With_ShowAsMonochrome_True() { var bitmapIcon = new BitmapIcon From 9f4eec81f647ee78c3c9fc33a4125f3a8bc6fa23 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 30 Jul 2024 08:31:25 -0400 Subject: [PATCH 13/24] chore(reg): Fix CI build - iteration 8 --- .../Tests/Microsoft_UI_Xaml_Controls/Given_RatingControl.cs | 2 +- .../Tests/Windows_UI_Xaml_Controls/Given_Control_Visibility.cs | 3 +++ .../Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_RatingControl.cs b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_RatingControl.cs index c5e475aa4116..f97750f53c3c 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_RatingControl.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_RatingControl.cs @@ -19,7 +19,7 @@ public class Given_RatingControl [TestMethod] [RunsOnUIThread] #if !HAS_INPUT_INJECTOR - [Ignore("InputInjector is only supported on Skia #14948")] + [Ignore("InputInjector is not supported on this platform.")] #endif public async Task When_Loaded_Then_Unloaded_Tap() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Control_Visibility.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Control_Visibility.cs index 43c87b373e11..14d7ca44b37c 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Control_Visibility.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_Control_Visibility.cs @@ -21,6 +21,9 @@ public class Given_Control_Visibility #if HAS_UNO_WINUI [TestMethod] [UnoWorkItem("https://github.com/unoplatform/uno/issues/16369")] +#if !HAS_RENDER_TARGET_BITMAP + [Ignore("Cannot take screenshot on this platform.")] +#endif public async Task When_Visibility_Changes() { foreach (var type in typeof(Control).Assembly.GetTypes()) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs index fac78e0e747b..af072003c04c 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Documents/Given_Hyperlink.cs @@ -104,7 +104,7 @@ public async Task TestHoveredHyperlink(bool useDark, bool useFluent, string expe #if __WASM__ [Ignore("Visual states/Colors are handled by browser.")] #elif !HAS_INPUT_INJECTOR - [Ignore("Test needs InputInjector which is not supported on this platform.")] + [Ignore("InputInjector is not supported on this platform.")] #endif [DataRow(true, false, "#FF0078D7", "#99FFFFFF", "#66FFFFFF")] [DataRow(false, false, "#FF0078D7", "#99000000", "#66000000")] From b472c0592c7cafcacdeaf828955653d472e3e190 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Thu, 8 Aug 2024 21:22:36 +0300 Subject: [PATCH 14/24] chore: Few fixes --- .../Windows_UI_Input/PointersTests/HitTest_Image.xaml.cs | 8 ++++---- src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs | 6 +++--- src/Uno.UI/UI/Xaml/Controls/Image/HtmlImage.wasm.cs | 4 ++++ src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts | 8 ++++---- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/HitTest_Image.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/HitTest_Image.xaml.cs index 0a34262536bd..f6c7d620a739 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/HitTest_Image.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/HitTest_Image.xaml.cs @@ -17,25 +17,25 @@ public HitTest_Image() { e.Handled = true; LastPressed.Text = Root.Name; - LastPressedSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? "-unknown-"; + LastPressedSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? $"-unknown/{e.OriginalSource?.GetType()}-"; }; Root.PointerMoved += (snd, e) => { e.Handled = true; LastHovered.Text = Root.Name; - LastHoveredSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? "-unknown-"; + LastHoveredSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? $"-unknown/{e.OriginalSource?.GetType()}-"; }; TheImage.PointerPressed += (snd, e) => { e.Handled = true; LastPressed.Text = TheImage.Name; - LastPressedSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? "-unknown-"; + LastPressedSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? $"-unknown/{e.OriginalSource?.GetType()}-"; }; TheImage.PointerMoved += (snd, e) => { e.Handled = true; LastHovered.Text = TheImage.Name; - LastHoveredSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? "-unknown-"; + LastHoveredSrc.Text = (e.OriginalSource as FrameworkElement)?.Name ?? $"-unknown/{e.OriginalSource?.GetType()}-"; }; } } diff --git a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs index a59a8e3a2346..4e9b854d4c1d 100644 --- a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs +++ b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs @@ -111,7 +111,7 @@ private static int OnNativeEvent( that.PointerEntered?.Invoke(that, args); break; - case HtmlPointerEvent.pointerout: + case HtmlPointerEvent.pointerleave: that.PointerExited?.Invoke(that, args); break; @@ -241,7 +241,7 @@ private static VirtualKeyModifiers GetKeyModifiers(bool ctrl, bool shift) private static bool GetIsInRange(byte @event, bool hasRelatedTarget, PointerDeviceType pointerType, bool isInContact) { const int cancel = (int)HtmlPointerEvent.pointercancel; - const int exitOrUp = (int)(HtmlPointerEvent.pointerout | HtmlPointerEvent.pointerup); + const int exitOrUp = (int)(HtmlPointerEvent.pointerleave | HtmlPointerEvent.pointerup); var isInRange = true; if (@event is cancel) @@ -337,7 +337,7 @@ private enum HtmlPointerEvent : byte // Minimal default pointer required to maintain state pointerover = 1, - pointerout = 1 << 1, + pointerleave = 1 << 1, pointerdown = 1 << 2, pointerup = 1 << 3, pointercancel = 1 << 4, diff --git a/src/Uno.UI/UI/Xaml/Controls/Image/HtmlImage.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/Image/HtmlImage.wasm.cs index 8e35da26190a..b24c60de7d67 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Image/HtmlImage.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Image/HtmlImage.wasm.cs @@ -9,4 +9,8 @@ public HtmlImage() : base("img") // Avoid the "drag effect" which is set by default in browsers SetAttribute("draggable", "false"); } + + // We don't want HtmlImage to be the OriginalSource of PointerRoutedEventArgs. + // We want the HitTest call to return Image instead of HtmlImage to match WinUI behavior. + internal override bool IsViewHit() => false; } diff --git a/src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts b/src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts index 307b319df7ca..788a28f9a574 100644 --- a/src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts +++ b/src/Uno.UI/ts/Runtime/BrowserPointerInputSource.ts @@ -10,7 +10,7 @@ export enum HtmlPointerEvent { pointerover = 1, - pointerout = 1 << 1, + pointerleave = 1 << 1, pointerdown = 1 << 2, pointerup = 1 << 3, pointercancel = 1 << 4, @@ -62,7 +62,7 @@ const element = document.body; element.addEventListener("pointerover", this.onPointerEventReceived.bind(this), { capture: false }); - element.addEventListener("pointerout", this.onPointerEventReceived.bind(this), { capture: false }); + element.addEventListener("pointerleave", this.onPointerEventReceived.bind(this), { capture: false }); element.addEventListener("pointerdown", this.onPointerEventReceived.bind(this), { capture: false }); element.addEventListener("pointerup", this.onPointerEventReceived.bind(this), { capture: false }); //element.addEventListener("lostpointercapture", this.onPointerEventReceived.bind(this), { capture: false }); @@ -171,8 +171,8 @@ switch (eventName) { case "pointerover": return HtmlPointerEvent.pointerover; - case "pointerout": - return HtmlPointerEvent.pointerout; + case "pointerleave": + return HtmlPointerEvent.pointerleave; case "pointerdown" : return HtmlPointerEvent.pointerdown; case "pointerup" : From 02c520674ea3f0e32e3fb5f369103b27c1eeaa69 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Fri, 9 Aug 2024 18:55:56 +0300 Subject: [PATCH 15/24] chore: Fix for Hyperlink --- .../PointersTests/EventsSequences.xaml | 2 +- .../PointersTests/EventsSequences.xaml.cs | 2 +- .../UI/Xaml/Controls/TextBlock/TextBlock.cs | 130 ++++++++---------- .../Xaml/Controls/TextBlock/TextBlock.wasm.cs | 1 + .../UI/Xaml/Documents/Hyperlink.wasm.cs | 3 - .../UI/Xaml/Documents/InlineCollection.cs | 57 +++++++- .../Xaml/Documents/InlineCollection.wasm.cs | 77 ----------- .../Xaml/Window/WindowManagerInterop.wasm.cs | 9 ++ src/Uno.UI/ts/WindowManager.ts | 5 + 9 files changed, 125 insertions(+), 161 deletions(-) delete mode 100644 src/Uno.UI/UI/Xaml/Documents/InlineCollection.wasm.cs diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/EventsSequences.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/EventsSequences.xaml index 47742f12b9d5..cace5f594ca4 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/EventsSequences.xaml +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Input/PointersTests/EventsSequences.xaml @@ -76,7 +76,7 @@ - +