WebKit Bugzilla
Attachment 361421 Details for
Bug 191446
: [iOS] Mouse/Touch/Pointer events are missing modifier keys
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Now with an untested test!
bug-191446-20190207111617.patch (text/plain), 48.19 KB, created by
Daniel Bates
on 2019-02-07 11:16:18 PST
(
hide
)
Description:
Now with an untested test!
Filename:
MIME Type:
Creator:
Daniel Bates
Created:
2019-02-07 11:16:18 PST
Size:
48.19 KB
patch
obsolete
>Subversion Revision: 241028 >diff --git a/Source/WebCore/platform/ios/PlatformEventFactoryIOS.mm b/Source/WebCore/platform/ios/PlatformEventFactoryIOS.mm >index be23f54c059324603a139d96b53db3d7448b285a..a171b9db1fd4f503454d46b4e87fc1f2fb046029 100644 >--- a/Source/WebCore/platform/ios/PlatformEventFactoryIOS.mm >+++ b/Source/WebCore/platform/ios/PlatformEventFactoryIOS.mm >@@ -95,6 +95,7 @@ public: > m_globalPosition = globalPointForEvent(event); > m_button = LeftButton; // This has always been the LeftButton on iOS. > m_clickCount = 1; // This has always been 1 on iOS. >+ m_modifiers = modifiersForEvent(event); > } > }; > >diff --git a/Source/WebKit/Platform/spi/ios/UIKitSPI.h b/Source/WebKit/Platform/spi/ios/UIKitSPI.h >index 1190812e718eaaf4d2aebdbf589a3320dbc89814..d9fef25345829e464fb74341d2615797787ef060 100644 >--- a/Source/WebKit/Platform/spi/ios/UIKitSPI.h >+++ b/Source/WebKit/Platform/spi/ios/UIKitSPI.h >@@ -358,6 +358,10 @@ typedef NS_ENUM(NSInteger, UIScrollViewIndicatorInsetAdjustmentBehavior) { > - (CGSize)_legacy_sizeWithFont:(UIFont *)font minFontSize:(CGFloat)minFontSize actualFontSize:(CGFloat *)actualFontSize forWidth:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode; > @end > >+@interface UIGestureRecognizer () >+@property (nonatomic, readonly, getter=_modifierFlags) UIKeyModifierFlags modifierFlags; >+@end >+ > @interface UITapGestureRecognizer () > @property (nonatomic, getter=_allowableSeparation, setter=_setAllowableSeparation:) CGFloat allowableSeparation; > @property (nonatomic, readonly) CGPoint location; >diff --git a/Source/WebKit/Shared/NativeWebTouchEvent.h b/Source/WebKit/Shared/NativeWebTouchEvent.h >index 3b7cedb15f6d6946375e8dd1c57cf71c698899a6..f1b6016b21fde668ae579a5337619b58ca170f9e 100644 >--- a/Source/WebKit/Shared/NativeWebTouchEvent.h >+++ b/Source/WebKit/Shared/NativeWebTouchEvent.h >@@ -23,15 +23,17 @@ > * THE POSSIBILITY OF SUCH DAMAGE. > */ > >-#ifndef NativeWebTouchEvent_h >-#define NativeWebTouchEvent_h >+#pragma once > > #if ENABLE(TOUCH_EVENTS) > > #include "WebEvent.h" > > #if PLATFORM(IOS_FAMILY) >+#if defined(__OBJC__) >+#include <UIKit/UIKit.h> > struct _UIWebTouchEvent; >+#endif > #elif PLATFORM(GTK) > #include <WebCore/GUniquePtrGtk.h> > #elif USE(LIBWPE) >@@ -43,7 +45,9 @@ namespace WebKit { > class NativeWebTouchEvent : public WebTouchEvent { > public: > #if PLATFORM(IOS_FAMILY) >- explicit NativeWebTouchEvent(const _UIWebTouchEvent*); >+#if defined(__OBJC__) >+ explicit NativeWebTouchEvent(const _UIWebTouchEvent*, UIKeyModifierFlags); >+#endif > #elif PLATFORM(GTK) > NativeWebTouchEvent(GdkEvent*, Vector<WebPlatformTouchPoint>&&); > NativeWebTouchEvent(const NativeWebTouchEvent&); >@@ -56,7 +60,7 @@ public: > #endif > > private: >-#if PLATFORM(IOS_FAMILY) >+#if PLATFORM(IOS_FAMILY) && defined(__OBJC__) > Vector<WebPlatformTouchPoint> extractWebTouchPoint(const _UIWebTouchEvent*); > #endif > >@@ -67,8 +71,10 @@ private: > #endif > }; > >+#if PLATFORM(IOS_FAMILY) && defined(__OBJC__) >+OptionSet<WebEvent::Modifier> webEventModifierFlags(UIKeyModifierFlags); >+#endif >+ > } // namespace WebKit > > #endif // ENABLE(TOUCH_EVENTS) >- >-#endif // NativeWebTouchEvent_h >diff --git a/Source/WebKit/Shared/ios/NativeWebTouchEventIOS.mm b/Source/WebKit/Shared/ios/NativeWebTouchEventIOS.mm >index 995f640cf7365fa26ac9c3e517cf3be8f24c2681..cc5fd3103aa47b5f0dcf38c67fd8f7e3981bbbf2 100644 >--- a/Source/WebKit/Shared/ios/NativeWebTouchEventIOS.mm >+++ b/Source/WebKit/Shared/ios/NativeWebTouchEventIOS.mm >@@ -89,6 +89,22 @@ static inline WebCore::IntPoint positionForCGPoint(CGPoint position) > return WebCore::IntPoint(position); > } > >+OptionSet<WebEvent::Modifier> webEventModifierFlags(UIKeyModifierFlags flags) >+{ >+ OptionSet<WebEvent::Modifier> modifiers; >+ if (flags & UIKeyModifierShift) >+ modifiers.add(WebEvent::Modifier::ShiftKey); >+ if (flags & UIKeyModifierControl) >+ modifiers.add(WebEvent::Modifier::ControlKey); >+ if (flags & UIKeyModifierAlternate) >+ modifiers.add(WebEvent::Modifier::AltKey); >+ if (flags & UIKeyModifierCommand) >+ modifiers.add(WebEvent::Modifier::MetaKey); >+ if (flags & UIKeyModifierAlphaShift) >+ modifiers.add(WebEvent::Modifier::CapsLockKey); >+ return modifiers; >+} >+ > Vector<WebPlatformTouchPoint> NativeWebTouchEvent::extractWebTouchPoint(const _UIWebTouchEvent* event) > { > unsigned touchCount = event->touchPointCount; >@@ -117,10 +133,10 @@ Vector<WebPlatformTouchPoint> NativeWebTouchEvent::extractWebTouchPoint(const _U > return touchPointList; > } > >-NativeWebTouchEvent::NativeWebTouchEvent(const _UIWebTouchEvent* event) >+NativeWebTouchEvent::NativeWebTouchEvent(const _UIWebTouchEvent* event, UIKeyModifierFlags flags) > : WebTouchEvent( > webEventTypeForUIWebTouchEventType(event->type), >- OptionSet<Modifier> { }, >+ webEventModifierFlags(flags), > WallTime::fromRawSeconds(event->timestamp), > extractWebTouchPoint(event), > positionForCGPoint(event->locationInDocumentCoordinates), >diff --git a/Source/WebKit/Shared/ios/WebIOSEventFactory.h b/Source/WebKit/Shared/ios/WebIOSEventFactory.h >index ab98d8fc0d8e1b2d84a3ebd71baf7dab0ee21d9a..8579c334fac22707079af2fa3fd94413532396a3 100644 >--- a/Source/WebKit/Shared/ios/WebIOSEventFactory.h >+++ b/Source/WebKit/Shared/ios/WebIOSEventFactory.h >@@ -23,20 +23,20 @@ > * THE POSSIBILITY OF SUCH DAMAGE. > */ > >-#ifndef WebIOSEventFactory_h >-#define WebIOSEventFactory_h >+#pragma once > > #if PLATFORM(IOS_FAMILY) > > #import "WebEvent.h" >+#import <UIKit/UIKit.h> > #import <WebCore/WebEvent.h> > > class WebIOSEventFactory { > public: > static WebKit::WebKeyboardEvent createWebKeyboardEvent(::WebEvent *); > static WebKit::WebMouseEvent createWebMouseEvent(::WebEvent *); >+ >+ static UIKeyModifierFlags toUIKeyModifierFlags(OptionSet<WebKit::WebEvent::Modifier>); > }; > > #endif // PLATFORM(IOS_FAMILY) >- >-#endif // WebIOSEventFactory_h >diff --git a/Source/WebKit/Shared/ios/WebIOSEventFactory.mm b/Source/WebKit/Shared/ios/WebIOSEventFactory.mm >index 84a7a5a4dbf012e222bd386eae01c6f6d24d15ad..25c16ec2252d450694cc823749571ed20fbd0a47 100644 >--- a/Source/WebKit/Shared/ios/WebIOSEventFactory.mm >+++ b/Source/WebKit/Shared/ios/WebIOSEventFactory.mm >@@ -31,6 +31,22 @@ > #import <WebCore/KeyEventCodesIOS.h> > #import <WebCore/PlatformEventFactoryIOS.h> > >+UIKeyModifierFlags WebIOSEventFactory::toUIKeyModifierFlags(OptionSet<WebKit::WebEvent::Modifier> modifiers) >+{ >+ UIKeyModifierFlags modifierFlags = 0; >+ if (modifiers.contains(WebKit::WebEvent::Modifier::ShiftKey)) >+ modifierFlags |= UIKeyModifierShift; >+ if (modifiers.contains(WebKit::WebEvent::Modifier::ControlKey)) >+ modifierFlags |= UIKeyModifierControl; >+ if (modifiers.contains(WebKit::WebEvent::Modifier::AltKey)) >+ modifierFlags |= UIKeyModifierAlternate; >+ if (modifiers.contains(WebKit::WebEvent::Modifier::MetaKey)) >+ modifierFlags |= UIKeyModifierCommand; >+ if (modifiers.contains(WebKit::WebEvent::Modifier::CapsLockKey)) >+ modifierFlags |= UIKeyModifierAlphaShift; >+ return modifierFlags; >+} >+ > static OptionSet<WebKit::WebEvent::Modifier> modifiersForEvent(::WebEvent *event) > { > OptionSet<WebKit::WebEvent::Modifier> modifiers; >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKNavigationAction.mm b/Source/WebKit/UIProcess/API/Cocoa/WKNavigationAction.mm >index 44c8bb6092edaa12ca3ecc9c47de510d6cfb6d73..8ebba1f5bc53c697498b514bbb4e6d6a8d838570 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKNavigationAction.mm >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKNavigationAction.mm >@@ -36,6 +36,10 @@ > #import <WebCore/FloatPoint.h> > #import <wtf/RetainPtr.h> > >+#if PLATFORM(IOS_FAMILY) >+#import "WebIOSEventFactory.h" >+#endif >+ > @implementation WKNavigationAction > > static WKNavigationType toWKNavigationType(WebCore::NavigationType navigationType) >@@ -127,6 +131,7 @@ - (CGPoint)_clickLocationInRootViewCoordinates > #endif > > #if PLATFORM(MAC) >+ > - (NSEventModifierFlags)modifierFlags > { > return WebKit::WebEventFactory::toNSEventModifierFlags(_navigationAction->modifiers()); >@@ -136,6 +141,14 @@ - (NSInteger)buttonNumber > { > return WebKit::WebEventFactory::toNSButtonNumber(_navigationAction->mouseButton()); > } >+ >+#else >+ >+- (UIKeyModifierFlags)modifierFlags >+{ >+ return WebIOSEventFactory::toUIKeyModifierFlags(_navigationAction->modifiers()); >+} >+ > #endif > > #pragma mark WKObject protocol implementation >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKNavigationActionPrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKNavigationActionPrivate.h >index 5df7ae0d509155870fbb8e1066f3ffcd22a197ba..ad7422f2b75715a4cdec89c826efd6707b6e75ee 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKNavigationActionPrivate.h >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKNavigationActionPrivate.h >@@ -31,6 +31,8 @@ > @class _WKUserInitiatedAction; > > #if TARGET_OS_IPHONE >+#include <UIKit/UIKit.h> >+ > typedef NS_ENUM(NSInteger, WKSyntheticClickType) { > WKSyntheticClickTypeNoTap, > WKSyntheticClickTypeOneFingerTap, >@@ -53,6 +55,8 @@ typedef NS_ENUM(NSInteger, WKSyntheticClickType) { > #if TARGET_OS_IPHONE > @property (nonatomic, readonly) WKSyntheticClickType _syntheticClickType WK_API_AVAILABLE(ios(10.0)); > @property (nonatomic, readonly) CGPoint _clickLocationInRootViewCoordinates WK_API_AVAILABLE(ios(11.0)); >+ >+@property (nonatomic, readonly) UIKeyModifierFlags modifierFlags WK_API_AVAILABLE(ios(WK_IOS_TBA)); > #endif > > @property (nonatomic, readonly) BOOL _isRedirect WK_API_AVAILABLE(macosx(10.13), ios(11.0)); >diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h >index 7be91943890b75d0e28ca3701f5b467ec08747a2..6cf3469c3b3ce492abaaa3b3697f573d025d3091 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.h >+++ b/Source/WebKit/UIProcess/WebPageProxy.h >@@ -80,6 +80,7 @@ > #include <WebCore/LayoutSize.h> > #include <WebCore/MediaPlaybackTargetContext.h> > #include <WebCore/MediaProducer.h> >+#include <WebCore/PlatformEvent.h> > #include <WebCore/PlatformScreen.h> > #include <WebCore/PointerID.h> > #include <WebCore/ScrollTypes.h> >@@ -666,7 +667,7 @@ public: > void disableDoubleTapGesturesDuringTapIfNecessary(uint64_t requestID); > void contentSizeCategoryDidChange(const String& contentSizeCategory); > void getSelectionContext(WTF::Function<void(const String&, const String&, const String&, CallbackBase::Error)>&&); >- void handleTwoFingerTapAtPoint(const WebCore::IntPoint&, uint64_t requestID); >+ void handleTwoFingerTapAtPoint(const WebCore::IntPoint&, OptionSet<WebKit::WebEvent::Modifier>, uint64_t requestID); > void handleStylusSingleTapAtPoint(const WebCore::IntPoint&, uint64_t requestID); > void setForceAlwaysUserScalable(bool); > bool forceAlwaysUserScalable() const { return m_forceAlwaysUserScalable; } >@@ -1165,10 +1166,10 @@ public: > void willStartUserTriggeredZooming(); > > void potentialTapAtPosition(const WebCore::FloatPoint&, uint64_t& requestID); >- void commitPotentialTap(uint64_t layerTreeTransactionIdAtLastTouchStart); >+ void commitPotentialTap(OptionSet<WebKit::WebEvent::Modifier>, uint64_t layerTreeTransactionIdAtLastTouchStart); > void cancelPotentialTap(); > void tapHighlightAtPosition(const WebCore::FloatPoint&, uint64_t& requestID); >- void handleTap(const WebCore::FloatPoint&, uint64_t layerTreeTransactionIdAtLastTouchStart); >+ void handleTap(const WebCore::FloatPoint&, OptionSet<WebKit::WebEvent::Modifier>, uint64_t layerTreeTransactionIdAtLastTouchStart); > > void inspectorNodeSearchMovedToPosition(const WebCore::FloatPoint&); > void inspectorNodeSearchEndedAtPosition(const WebCore::FloatPoint&); >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >index 38be0d0e2acfc46a2f969ceddbf021b016ed9a6c..e6ce727156ae9daf31af8e5bdd4a47dbdba262c6 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >@@ -408,7 +408,7 @@ FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW) > - (void)_updateChangedSelection; > - (BOOL)_interpretKeyEvent:(::WebEvent *)theEvent isCharEvent:(BOOL)isCharEvent; > - (void)_positionInformationDidChange:(const WebKit::InteractionInformationAtPosition&)info; >-- (void)_attemptClickAtLocation:(CGPoint)location; >+- (void)_attemptClickAtLocation:(CGPoint)location modifierFlags:(UIKeyModifierFlags)modifierFlags; > - (void)_willStartScrollingOrZooming; > - (void)_didScroll; > - (void)_didEndScrollingOrZooming; >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >index 4d8e3604a8ea88f516f6743c3af8d47474185689..0cb2c76d5ab3fc672b1c1ec06fdeb4648b9d8d46 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >@@ -1171,7 +1171,7 @@ - (void)_webTouchEventsRecognized:(UIWebTouchEventsGestureRecognizer *)gestureRe > _layerTreeTransactionIdAtLastTouchStart = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).lastCommittedLayerTreeTransactionID(); > > #if ENABLE(TOUCH_EVENTS) >- WebKit::NativeWebTouchEvent nativeWebTouchEvent(lastTouchEvent); >+ WebKit::NativeWebTouchEvent nativeWebTouchEvent { lastTouchEvent, gestureRecognizer.modifierFlags }; > nativeWebTouchEvent.setCanPreventNativeGestures(!_canSendTouchEventsAsynchronously || [gestureRecognizer isDefaultPrevented]); > > #if ENABLE(POINTER_EVENTS) >@@ -2051,7 +2051,7 @@ - (void)_highlightLongPressRecognized:(UILongPressGestureRecognizer *)gestureRec > break; > case UIGestureRecognizerStateEnded: > if (_highlightLongPressCanClick && _positionInformation.isElement) { >- [self _attemptClickAtLocation:[gestureRecognizer startPoint]]; >+ [self _attemptClickAtLocation:gestureRecognizer.startPoint modifierFlags:gestureRecognizer.modifierFlags]; > [self _finishInteraction]; > } else > [self _cancelInteraction]; >@@ -2070,7 +2070,7 @@ - (void)_twoFingerSingleTapGestureRecognized:(UITapGestureRecognizer *)gestureRe > { > _isTapHighlightIDValid = YES; > _isExpectingFastSingleTapCommit = YES; >- _page->handleTwoFingerTapAtPoint(WebCore::roundedIntPoint(gestureRecognizer.centroid), ++_latestTapID); >+ _page->handleTwoFingerTapAtPoint(WebCore::roundedIntPoint(gestureRecognizer.centroid), WebKit::webEventModifierFlags(gestureRecognizer.modifierFlags), ++_latestTapID); > } > > - (void)_stylusSingleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer >@@ -2194,7 +2194,7 @@ - (void)_singleTapCommited:(UITapGestureRecognizer *)gestureRecognizer > } > > [_inputPeripheral endEditing]; >- _page->commitPotentialTap(_layerTreeTransactionIdAtLastTouchStart); >+ _page->commitPotentialTap(WebKit::webEventModifierFlags(gestureRecognizer.modifierFlags), _layerTreeTransactionIdAtLastTouchStart); > > if (!_isExpectingFastSingleTapCommit) > [self _finishInteraction]; >@@ -2227,7 +2227,7 @@ - (void)_twoFingerDoubleTapRecognized:(UITapGestureRecognizer *)gestureRecognize > _smartMagnificationController->handleResetMagnificationGesture(gestureRecognizer.location); > } > >-- (void)_attemptClickAtLocation:(CGPoint)location >+- (void)_attemptClickAtLocation:(CGPoint)location modifierFlags:(UIKeyModifierFlags)modifierFlags > { > if (![self isFirstResponder]) { > if (!_inputViewUpdateDeferrer) >@@ -2236,7 +2236,7 @@ - (void)_attemptClickAtLocation:(CGPoint)location > } > > [_inputPeripheral endEditing]; >- _page->handleTap(location, _layerTreeTransactionIdAtLastTouchStart); >+ _page->handleTap(location, WebKit::webEventModifierFlags(modifierFlags), _layerTreeTransactionIdAtLastTouchStart); > } > > - (void)setUpTextSelectionAssistant >@@ -5424,7 +5424,7 @@ - (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant performAction:( > > - (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant openElementAtLocation:(CGPoint)location > { >- [self _attemptClickAtLocation:location]; >+ [self _attemptClickAtLocation:location modifierFlags:0]; > } > > - (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant shareElementWithURL:(NSURL *)url rect:(CGRect)boundingRect >diff --git a/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm b/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm >index 4726894a93a787190746fd53c67d92820eab7ddf..4c1a087eef006126f1bcb51286dfc4f45db79faf 100644 >--- a/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm >+++ b/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm >@@ -593,9 +593,9 @@ void WebPageProxy::getSelectionContext(WTF::Function<void(const String&, const S > m_process->send(Messages::WebPage::GetSelectionContext(callbackID), m_pageID); > } > >-void WebPageProxy::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID) >+void WebPageProxy::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, OptionSet<WebEvent::Modifier> modifiers, uint64_t requestID) > { >- process().send(Messages::WebPage::HandleTwoFingerTapAtPoint(point, requestID), m_pageID); >+ process().send(Messages::WebPage::HandleTwoFingerTapAtPoint(point, modifiers, requestID), m_pageID); > } > > void WebPageProxy::handleStylusSingleTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID) >@@ -824,9 +824,9 @@ void WebPageProxy::potentialTapAtPosition(const WebCore::FloatPoint& position, u > process().send(Messages::WebPage::PotentialTapAtPosition(requestID, position), m_pageID); > } > >-void WebPageProxy::commitPotentialTap(uint64_t layerTreeTransactionIdAtLastTouchStart) >+void WebPageProxy::commitPotentialTap(OptionSet<WebEvent::Modifier> modifiers, uint64_t layerTreeTransactionIdAtLastTouchStart) > { >- process().send(Messages::WebPage::CommitPotentialTap(layerTreeTransactionIdAtLastTouchStart), m_pageID); >+ process().send(Messages::WebPage::CommitPotentialTap(modifiers, layerTreeTransactionIdAtLastTouchStart), m_pageID); > } > > void WebPageProxy::cancelPotentialTap() >@@ -839,9 +839,9 @@ void WebPageProxy::tapHighlightAtPosition(const WebCore::FloatPoint& position, u > process().send(Messages::WebPage::TapHighlightAtPosition(requestID, position), m_pageID); > } > >-void WebPageProxy::handleTap(const FloatPoint& location, uint64_t layerTreeTransactionIdAtLastTouchStart) >+void WebPageProxy::handleTap(const FloatPoint& location, OptionSet<WebEvent::Modifier> modifiers, uint64_t layerTreeTransactionIdAtLastTouchStart) > { >- process().send(Messages::WebPage::HandleTap(roundedIntPoint(location), layerTreeTransactionIdAtLastTouchStart), m_pageID); >+ process().send(Messages::WebPage::HandleTap(roundedIntPoint(location), modifiers, layerTreeTransactionIdAtLastTouchStart), m_pageID); > } > > void WebPageProxy::inspectorNodeSearchMovedToPosition(const WebCore::FloatPoint& position) >diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h >index a1a0294aa5a6d5af92380413dddc4e33a2ff3ff8..0659a0758d3f03a7018317babda7d8c8933b258a 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebPage.h >+++ b/Source/WebKit/WebProcess/WebPage/WebPage.h >@@ -613,9 +613,9 @@ public: > bool allowsUserScaling() const; > bool hasStablePageScaleFactor() const { return m_hasStablePageScaleFactor; } > >- void handleTap(const WebCore::IntPoint&, uint64_t lastLayerTreeTransactionId); >+ void handleTap(const WebCore::IntPoint&, OptionSet<WebKit::WebEvent::Modifier>, uint64_t lastLayerTreeTransactionId); > void potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint&); >- void commitPotentialTap(uint64_t lastLayerTreeTransactionId); >+ void commitPotentialTap(OptionSet<WebKit::WebEvent::Modifier>, uint64_t lastLayerTreeTransactionId); > void commitPotentialTapFailed(); > void cancelPotentialTap(); > void cancelPotentialTapInFrame(WebFrame&); >@@ -661,7 +661,7 @@ public: > WebCore::IntRect rectForElementAtInteractionLocation(); > void updateSelectionAppearance(); > void getSelectionContext(CallbackID); >- void handleTwoFingerTapAtPoint(const WebCore::IntPoint&, uint64_t requestID); >+ void handleTwoFingerTapAtPoint(const WebCore::IntPoint&, OptionSet<WebKit::WebEvent::Modifier>, uint64_t requestID); > void handleStylusSingleTapAtPoint(const WebCore::IntPoint&, uint64_t requestID); > void getRectsForGranularityWithSelectionOffset(uint32_t, int32_t, CallbackID); > void getRectsAtSelectionOffsetWithText(int32_t, const String&, CallbackID); >@@ -1180,8 +1180,8 @@ private: > RefPtr<WebCore::Range> rangeForWebSelectionAtPosition(const WebCore::IntPoint&, const WebCore::VisiblePosition&, SelectionFlags&); > void getFocusedElementInformation(FocusedElementInformation&); > void platformInitializeAccessibility(); >- void handleSyntheticClick(WebCore::Node* nodeRespondingToClick, const WebCore::FloatPoint& location); >- void completeSyntheticClick(WebCore::Node* nodeRespondingToClick, const WebCore::FloatPoint& location, WebCore::SyntheticClickType); >+ void handleSyntheticClick(WebCore::Node* nodeRespondingToClick, const WebCore::FloatPoint& location, OptionSet<WebKit::WebEvent::Modifier>); >+ void completeSyntheticClick(WebCore::Node* nodeRespondingToClick, const WebCore::FloatPoint& location, OptionSet<WebKit::WebEvent::Modifier>, WebCore::SyntheticClickType); > void sendTapHighlightForNodeIfNecessary(uint64_t requestID, WebCore::Node*); > void resetTextAutosizing(); > WebCore::VisiblePosition visiblePositionInFocusedNodeForPoint(const WebCore::Frame&, const WebCore::IntPoint&, bool isInteractingWithFocusedElement); >@@ -1757,6 +1757,7 @@ private: > RefPtr<WebCore::Node> m_pendingSyntheticClickNode; > WebCore::FloatPoint m_pendingSyntheticClickLocation; > WebCore::FloatRect m_previousExposedContentRect; >+ OptionSet<WebKit::WebEvent::Modifier> m_pendingSyntheticClickModifiers; > FocusedElementIdentifier m_currentFocusedElementIdentifier { 0 }; > Optional<DynamicViewportSizeUpdateID> m_pendingDynamicViewportSizeUpdateID; > double m_lastTransactionPageScaleFactor { 0 }; >diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in >index 776ed755639356dc50e04f3acabbbc89aabb566d..608a6c2aa279fb203198e7fa470ebcff7a9380e7 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in >+++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in >@@ -51,9 +51,9 @@ messages -> WebPage LegacyReceiver { > SetOverrideViewportArguments(Optional<WebCore::ViewportArguments> arguments) > DynamicViewportSizeUpdate(WebCore::FloatSize viewLayoutSize, WebCore::FloatSize maximumUnobscuredSize, WebCore::FloatRect targetExposedContentRect, WebCore::FloatRect targetUnobscuredRect, WebCore::FloatRect targetUnobscuredRectInScrollViewCoordinates, WebCore::RectEdges<float> targetUnobscuredSafeAreaInsets, double scale, int32_t deviceOrientation, uint64_t dynamicViewportSizeUpdateID) > >- HandleTap(WebCore::IntPoint point, uint64_t lastLayerTreeTransactionId) >+ HandleTap(WebCore::IntPoint point, OptionSet<WebKit::WebEvent::Modifier> modifiers, uint64_t lastLayerTreeTransactionId) > PotentialTapAtPosition(uint64_t requestID, WebCore::FloatPoint point) >- CommitPotentialTap(uint64_t lastLayerTreeTransactionId) >+ CommitPotentialTap(OptionSet<WebKit::WebEvent::Modifier> modifiers, uint64_t lastLayerTreeTransactionId) > CancelPotentialTap() > TapHighlightAtPosition(uint64_t requestID, WebCore::FloatPoint point) > InspectorNodeSearchMovedToPosition(WebCore::FloatPoint point) >@@ -98,7 +98,7 @@ messages -> WebPage LegacyReceiver { > ContentSizeCategoryDidChange(String contentSizeCategory) > GetSelectionContext(WebKit::CallbackID callbackID) > SetAllowsMediaDocumentInlinePlayback(bool allows) >- HandleTwoFingerTapAtPoint(WebCore::IntPoint point, uint64_t requestID) >+ HandleTwoFingerTapAtPoint(WebCore::IntPoint point, OptionSet<WebKit::WebEvent::Modifier> modifiers, uint64_t requestID) > HandleStylusSingleTapAtPoint(WebCore::IntPoint point, uint64_t requestID) > SetForceAlwaysUserScalable(bool userScalable) > GetRectsForGranularityWithSelectionOffset(uint32_t granularity, int32_t offset, WebKit::CallbackID callbackID) >diff --git a/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm b/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm >index 5d1b1dd90697cf80c4819a2a3e6964041b8eb825..8e473030c21a433d2d8068c59bb388494c29da2b 100644 >--- a/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm >+++ b/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm >@@ -533,7 +533,7 @@ void WebPage::updateSelectionAppearance() > didChangeSelection(); > } > >-void WebPage::handleSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location) >+void WebPage::handleSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location, OptionSet<WebEvent::Modifier> modifiers) > { > IntPoint roundedAdjustedPoint = roundedIntPoint(location); > Frame& mainframe = m_page->mainFrame(); >@@ -542,7 +542,12 @@ void WebPage::handleSyntheticClick(Node* nodeRespondingToClick, const WebCore::F > WKStartObservingContentChanges(); > WKStartObservingDOMTimerScheduling(); > >- mainframe.eventHandler().mouseMoved(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, WebCore::NoTap)); >+ // FIXME: Pass caps lock state. >+ bool shiftKey = modifiers.contains(WebEvent::Modifier::ShiftKey); >+ bool ctrlKey = modifiers.contains(WebEvent::Modifier::ControlKey); >+ bool altKey = modifiers.contains(WebEvent::Modifier::AltKey); >+ bool metaKey = modifiers.contains(WebEvent::Modifier::MetaKey); >+ mainframe.eventHandler().mouseMoved(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), WebCore::ForceAtClick, WebCore::NoTap)); > mainframe.document()->updateStyleIfNeeded(); > > WKStopObservingDOMTimerScheduling(); >@@ -550,6 +555,7 @@ void WebPage::handleSyntheticClick(Node* nodeRespondingToClick, const WebCore::F > > m_pendingSyntheticClickNode = nullptr; > m_pendingSyntheticClickLocation = FloatPoint(); >+ m_pendingSyntheticClickModifiers = { }; > > if (m_isClosed) > return; >@@ -559,15 +565,16 @@ void WebPage::handleSyntheticClick(Node* nodeRespondingToClick, const WebCore::F > // The move event caused new contents to appear. Don't send the click event. > LOG(ContentObservation, "handleSyntheticClick: Observed meaningful visible change -> hover."); > return; >- case WKContentIndeterminateChange: >+ case WKContentIndeterminateChange: { > // Wait for callback to completePendingSyntheticClickForContentChangeObserver() to decide whether to send the click event. > m_pendingSyntheticClickNode = nodeRespondingToClick; > m_pendingSyntheticClickLocation = location; >+ m_pendingSyntheticClickModifiers = modifiers; > LOG(ContentObservation, "handleSyntheticClick: Observed some change, but can't decide it yet -> wait."); > return; >- case WKContentNoChange: >+ } case WKContentNoChange: > LOG(ContentObservation, "handleSyntheticClick: No change was observed -> click."); >- completeSyntheticClick(nodeRespondingToClick, location, WebCore::OneFingerTap); >+ completeSyntheticClick(nodeRespondingToClick, location, modifiers, WebCore::OneFingerTap); > return; > } > ASSERT_NOT_REACHED(); >@@ -581,15 +588,16 @@ void WebPage::completePendingSyntheticClickForContentChangeObserver() > // Only dispatch the click if the document didn't get changed by any timers started by the move event. > if (WKObservedContentChange() == WKContentNoChange) { > LOG(ContentObservation, "No chage was observed -> click."); >- completeSyntheticClick(m_pendingSyntheticClickNode.get(), m_pendingSyntheticClickLocation, WebCore::OneFingerTap); >+ completeSyntheticClick(m_pendingSyntheticClickNode.get(), m_pendingSyntheticClickLocation, m_pendingSyntheticClickModifiers, WebCore::OneFingerTap); > } else > LOG(ContentObservation, "Observed meaningful visible change -> hover."); > > m_pendingSyntheticClickNode = nullptr; > m_pendingSyntheticClickLocation = FloatPoint(); >+ m_pendingSyntheticClickModifiers = { }; > } > >-void WebPage::completeSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location, SyntheticClickType syntheticClickType) >+void WebPage::completeSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location, OptionSet<WebEvent::Modifier> modifiers, SyntheticClickType syntheticClickType) > { > IntPoint roundedAdjustedPoint = roundedIntPoint(location); > Frame& mainframe = m_page->mainFrame(); >@@ -602,11 +610,17 @@ void WebPage::completeSyntheticClick(Node* nodeRespondingToClick, const WebCore: > bool tapWasHandled = false; > m_lastInteractionLocation = roundedAdjustedPoint; > >- tapWasHandled |= mainframe.eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, syntheticClickType)); >+ // FIXME: Pass caps lock state. >+ bool shiftKey = modifiers.contains(WebEvent::Modifier::ShiftKey); >+ bool ctrlKey = modifiers.contains(WebEvent::Modifier::ControlKey); >+ bool altKey = modifiers.contains(WebEvent::Modifier::AltKey); >+ bool metaKey = modifiers.contains(WebEvent::Modifier::MetaKey); >+ >+ tapWasHandled |= mainframe.eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), WebCore::ForceAtClick, syntheticClickType)); > if (m_isClosed) > return; > >- tapWasHandled |= mainframe.eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MouseReleased, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, syntheticClickType)); >+ tapWasHandled |= mainframe.eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MouseReleased, 1, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), WebCore::ForceAtClick, syntheticClickType)); > if (m_isClosed) > return; > >@@ -626,7 +640,7 @@ void WebPage::completeSyntheticClick(Node* nodeRespondingToClick, const WebCore: > send(Messages::WebPageProxy::DidCompleteSyntheticClick()); > } > >-void WebPage::handleTap(const IntPoint& point, uint64_t lastLayerTreeTransactionId) >+void WebPage::handleTap(const IntPoint& point, OptionSet<WebEvent::Modifier> modifiers, uint64_t lastLayerTreeTransactionId) > { > FloatPoint adjustedPoint; > Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint); >@@ -643,7 +657,7 @@ void WebPage::handleTap(const IntPoint& point, uint64_t lastLayerTreeTransaction > } > #endif > else >- handleSyntheticClick(nodeRespondingToClick, adjustedPoint); >+ handleSyntheticClick(nodeRespondingToClick, adjustedPoint, modifiers); > } > > void WebPage::requestFocusedElementInformation(WebKit::CallbackID callbackID) >@@ -738,7 +752,7 @@ void WebPage::sendTapHighlightForNodeIfNecessary(uint64_t requestID, Node* node) > #endif > } > >-void WebPage::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID) >+void WebPage::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, OptionSet<WebKit::WebEvent::Modifier> modifiers, uint64_t requestID) > { > FloatPoint adjustedPoint; > Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint); >@@ -754,7 +768,7 @@ void WebPage::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, uint64_t > send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(adjustedPoint))); > } else > #endif >- completeSyntheticClick(nodeRespondingToClick, adjustedPoint, WebCore::TwoFingerTap); >+ completeSyntheticClick(nodeRespondingToClick, adjustedPoint, modifiers, WebCore::TwoFingerTap); > } > > void WebPage::handleStylusSingleTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID) >@@ -799,7 +813,7 @@ void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoi > #endif > } > >-void WebPage::commitPotentialTap(uint64_t lastLayerTreeTransactionId) >+void WebPage::commitPotentialTap(OptionSet<WebEvent::Modifier> modifiers, uint64_t lastLayerTreeTransactionId) > { > if (!m_potentialTapNode || (!m_potentialTapNode->renderer() && !is<HTMLAreaElement>(m_potentialTapNode.get()))) { > commitPotentialTapFailed(); >@@ -823,7 +837,7 @@ void WebPage::commitPotentialTap(uint64_t lastLayerTreeTransactionId) > commitPotentialTapFailed(); > } else > #endif >- handleSyntheticClick(nodeRespondingToClick, adjustedPoint); >+ handleSyntheticClick(nodeRespondingToClick, adjustedPoint, modifiers); > } else > commitPotentialTapFailed(); > >diff --git a/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm b/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm >index db11ad641562d1d3a3164294b65446df8f53a39c..9fc83b844474ae739339e085627cc0a5e7a6c0dd 100644 >--- a/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm >+++ b/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm >@@ -155,6 +155,10 @@ void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef characte > { > } > >+void UIScriptController::performWithModifiers(JSValueRef, JSValueRef) >+{ >+} >+ > void UIScriptController::keyDown(JSStringRef, JSValueRef) > { > } >diff --git a/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl b/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl >index e54467ff448a0a7c37070e9b7d0f18825c943143..d565f7ff1f64800142afde595ca97d9a7ca62643 100644 >--- a/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl >+++ b/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl >@@ -66,6 +66,8 @@ interface UIScriptController { > void stylusUpAtPoint(long x, long y, object callback); > void stylusTapAtPoint(long x, long y, float azimuthAngle, float altitudeAngle, float pressure, object callback); > >+ void performWithModifiers(object callback, object modifierArray); >+ > void enterText(DOMString text); > void typeCharacterUsingHardwareKeyboard(DOMString character, object callback); > >diff --git a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp >index 4b45d56fdc2cb2ca4dae0f66dd1f527eefe7c39e..6d5417d7bed3273c6ea8e195b6e87eb87cbd9d23 100644 >--- a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp >+++ b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp >@@ -305,6 +305,10 @@ void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef, JSValue > { > } > >+void UIScriptController::performWithModifiers(JSValueRef, JSValueRef) >+{ >+} >+ > void UIScriptController::keyDown(JSStringRef, JSValueRef) > { > } >diff --git a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h >index 956c345c32f61351cfede1143f4a61c00e66c740..aedb014ac3ae38c4afee0075a7efd0ea115fe554 100644 >--- a/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h >+++ b/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h >@@ -93,6 +93,7 @@ public: > void enterText(JSStringRef); > void typeCharacterUsingHardwareKeyboard(JSStringRef character, JSValueRef callback); > >+ void performWithModifiers(JSValueRef callback, JSValueRef modifierArray); > void keyDown(JSStringRef character, JSValueRef modifierArray); > void toggleCapsLock(JSValueRef callback); > >diff --git a/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm b/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm >index 4952765a0acfd3de3f182be28e2fe8e19395683b..8f5330c3b1e79f8e9c1ec1461e64677035deb43e 100644 >--- a/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm >+++ b/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm >@@ -387,6 +387,27 @@ static Vector<String> parseModifierArray(JSContextRef context, JSValueRef arrayV > return modifiers; > } > >+void UIScriptController::performWithModifiers(JSValueRef callback, JSValueRef modifierArray) >+{ >+ if (JSValueIsUndefined(m_context->jsContext(), callback)) >+ return; >+ >+ auto modifierFlags = parseModifierArray(m_context->jsContext(), modifierArray); >+ for (auto& modifierFlag : modifierFlags) >+ [[HIDEventGenerator sharedHIDEventGenerator] keyDown:modifierFlag]; >+ >+ // Invoke the callback >+ JSValueRef exception = nullptr; >+ JSObjectRef callbackObject = JSValueToObject(m_context->jsContext(), callback, &exception); >+ if (!exception) >+ JSObjectCallAsFunction(m_context->jsContext(), callbackObject, JSContextGetGlobalObject(m_context->jsContext()), 0, nullptr /* arguments */, &exception); >+ >+ for (size_t i = modifierFlags.size(); i; ) { >+ --i; >+ [[HIDEventGenerator sharedHIDEventGenerator] keyUp:modifierFlags[i]]; >+ } >+} >+ > static UIPhysicalKeyboardEvent *createUIPhysicalKeyboardEvent(NSString *hidInputString, NSString *uiEventInputString, UIKeyModifierFlags modifierFlags, UIKeyboardInputFlags inputFlags, bool isKeyDown) > { > auto* keyboardEvent = [getUIPhysicalKeyboardEventClass() _eventWithInput:uiEventInputString inputFlags:inputFlags]; >diff --git a/LayoutTests/fast/events/ios/key-events-meta-alt-combinations.html b/LayoutTests/fast/events/ios/key-events-meta-alt-combinations.html >index fe88d341ebdba1d87410f0979c83f364f616c260..4f0e5af797c1d555c1b57d5f961a05cff438710f 100644 >--- a/LayoutTests/fast/events/ios/key-events-meta-alt-combinations.html >+++ b/LayoutTests/fast/events/ios/key-events-meta-alt-combinations.html >@@ -2,11 +2,12 @@ > <html> > <head> > <script src="../../../resources/ui-helper.js"></script> >+<script src="../resources/compute-subsets.js"></script> > <script src="resources/key-tester.js"></script> > <script> > const modiferKeySubsetsToTest = computeSubsets(["metaKey", "altKey"]); > for (const k of keysExcludingDeadAndSkippedKeys) { >- for (const modifiers of modiferKeySubsetsToTest) >+ for (const modifiers of computeSubsets(modifierKeys)) > tests.push(new KeyCommand(k, modifiers)); > } > </script> >diff --git a/LayoutTests/fast/events/ios/resources/key-tester.js b/LayoutTests/fast/events/ios/resources/key-tester.js >index 5748070b3b8fa3b6fb80be7ebb844537c6cdba40..60dbe9ece7dd6e3cace83fd5649a44ec3ed2b35c 100644 >--- a/LayoutTests/fast/events/ios/resources/key-tester.js >+++ b/LayoutTests/fast/events/ios/resources/key-tester.js >@@ -53,43 +53,6 @@ function keyCommandsHasCommand(keyCommands, command) > return !!keyCommands.find((k) => areKeyCommandsEqual(k, command)); > } > >-// This algorithm runs in O(2^N). >-function computeSubsets(anArray) >-{ >- function compareByModifierOrder(a, b) { >- if (a.length < b.length) >- return -1; >- if (a.length > b.length) >- return 1; >- for (let i = 0; i < a.length; ++i) { >- let rankA = anArray.indexOf(a[i]); >- let rankB = anArray.indexOf(b[i]); >- if (rankA < rankB) >- return -1; >- if (rankA > rankB) >- return 1; >- } >- return 0; >- } >- let result = []; >- const numberOfNonEmptyPermutations = (1 << anArray.length) - 1; >- // For each ordinal 1, 2, ... numberOfNonEmptyPermutations we look at its binary representation >- // and generate a permutation that consists of the entries in anArray at the indices where there >- // is a one bit in the binary representation. For example, suppose anArray = ["metaKey", "altKey", "ctrlKey"]. >- // To generate the 5th permutation we look at the binary representation of i = 5 => 0b101. And >- // compute the permutation to be [ anArray[0], anArray[2] ] = [ "metaKey", "ctrlKey" ] because >- // the 0th and 2nd bits are ones in the binary representation. >- for (let i = 1; i <= numberOfNonEmptyPermutations; ++i) { >- let temp = []; >- for (let bitmask = i, j = 0; bitmask; bitmask = Math.floor(bitmask / 2), ++j) { >- if (bitmask % 2) >- temp.push(anArray[j]); >- } >- result.push(temp); >- } >- return result.sort(compareByModifierOrder); >-} >- > const keys = new Set("abcdefghijklmnopqrstuvwxyz0123456789-=[]\\;',./".split("")); > const deadKeys = new Set("`euin".split("")); > const keysExcludingDeadKeys = computeDifference(keys, deadKeys); >@@ -117,7 +80,6 @@ for (let i = 1; i <= 9; ++i) > disallowedKeyCommands.push(new KeyCommand(i, ["metaKey"])); > > const modifierKeys = ["metaKey", "altKey", "ctrlKey", "shiftKey"]; >-const modiferKeySubsets = computeSubsets(modifierKeys); > > let tests = []; > >diff --git a/LayoutTests/fast/events/resources/compute-subsets.js b/LayoutTests/fast/events/resources/compute-subsets.js >new file mode 100644 >index 0000000000000000000000000000000000000000..a0f92876ea604b648de787d3e7723f1a2cc12a6b >--- /dev/null >+++ b/LayoutTests/fast/events/resources/compute-subsets.js >@@ -0,0 +1,36 @@ >+// This algorithm runs in O(2^N). >+function computeSubsets(anArray) >+{ >+ function compareByOriginalArrayOrder(a, b) { >+ if (a.length < b.length) >+ return -1; >+ if (a.length > b.length) >+ return 1; >+ for (let i = 0; i < a.length; ++i) { >+ let rankA = anArray.indexOf(a[i]); >+ let rankB = anArray.indexOf(b[i]); >+ if (rankA < rankB) >+ return -1; >+ if (rankA > rankB) >+ return 1; >+ } >+ return 0; >+ } >+ let result = []; >+ const numberOfNonEmptyPermutations = (1 << anArray.length) - 1; >+ // For each ordinal 1, 2, ... numberOfNonEmptyPermutations we look at its binary representation >+ // and generate a permutation that consists of the entries in anArray at the indices where there >+ // is a one bit in the binary representation. For example, suppose anArray = ["metaKey", "altKey", "ctrlKey"]. >+ // To generate the 5th permutation we look at the binary representation of i = 5 => 0b101. And >+ // compute the permutation to be [ anArray[0], anArray[2] ] = [ "metaKey", "ctrlKey" ] because >+ // the 0th and 2nd bits are ones in the binary representation. >+ for (let i = 1; i <= numberOfNonEmptyPermutations; ++i) { >+ let temp = []; >+ for (let bitmask = i, j = 0; bitmask; bitmask = Math.floor(bitmask / 2), ++j) { >+ if (bitmask % 2) >+ temp.push(anArray[j]); >+ } >+ result.push(temp); >+ } >+ return result.sort(compareByOriginalArrayOrder); >+} >diff --git a/LayoutTests/fast/events/touch/ios/touch-event-with-modifiers.html b/LayoutTests/fast/events/touch/ios/touch-event-with-modifiers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..3d4e03371f79a92cdf1f850d0b14a0c59ba571e5 >--- /dev/null >+++ b/LayoutTests/fast/events/touch/ios/touch-event-with-modifiers.html >@@ -0,0 +1,145 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../../../resources/ui-helper.js"></script> >+<script src="../../resources/compute-subsets.js"></script> >+<script> >+if (window.testRunner) { >+ testRunner.dumpAsText(); >+ testRunner.waitUntilDone(); >+} >+ >+const TouchType = { >+ "SingleTap": "Single Tap", >+ "DoubleTap": "Double Tap", >+}; >+ >+class TouchTest { >+ constructor(elementToTouch, touchType, modifiers = []) >+ { >+ this.elementToTouch = elementToTouch; >+ this.touchType = touchType; >+ this.modifiers = modifiers; >+ } >+ >+ toString() >+ { >+ return `{ ${this.touchType}, ${this.elementToTouch}, [${this.modifiers}] }`; >+ } >+ >+ run() >+ { >+ let centerX = this.elementToTouch.offsetLeft + this.elementToTouch.offsetWidth / 2; >+ let centerY = this.elementToTouch.offsetTop + this.elementToTouch.offsetHeight / 2; >+ if (this.touchType === TouchType.SingleTap) >+ UIHelper.tapAt(centerX, centerY, this.modifiers); >+ else >+ UIHelper.doubleTapAt(centerX, centerY, this.modifiers); >+ } >+} >+ >+const modifierKeys = ["metaKey", "altKey", "ctrlKey", "shiftKey"]; >+ >+let currentTest; >+let tests = []; >+ >+function handleTouchDown(event) >+{ >+ logTouchEvent(event); >+} >+ >+function handleTouchUp(event) >+{ >+ logTouchEvent(event); >+ nextTouchPress(); >+} >+ >+function log(message) >+{ >+ document.getElementById("console").appendChild(document.createTextNode(message + "\n")); >+} >+ >+function logTouchEvent(event) >+{ >+ let pieces = []; >+ for (let propertyName of ["type", "screenX", "screenY", "clientX", "clientY", "scale", "rotation", "altKey", "ctrlKey", "metaKey", "shiftKey"]) >+ pieces.push(`${propertyName}: ${event[propertyName]}`); >+ log(pieces.join(", ")); >+} >+ >+const modifierDisplayNameMap = { >+ "altKey": "Option", >+ "ctrlKey": "Control", >+ "metaKey": "Command", >+ "shiftKey": "Shift", >+ "capsLockKey": "Caps Lock", >+} >+ >+function displayNameForTest(test) >+{ >+ let displayNamesOfModifiers = []; >+ for (const modifier of test.modifiers) >+ displayNamesOfModifiers.push(modifierDisplayNameMap[modifier]); >+ let result = ""; >+ if (displayNamesOfModifiers.length) >+ result += displayNamesOfModifiers.join(" + ") + " + "; >+ result += test.touchType; >+ return result; >+} >+ >+function nextTouchPress() >+{ >+ if (!tests.length) { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ return; >+ } >+ currentTest = tests.shift(); >+ log(`\nTest ${displayNameForTest(currentTest)}:`); >+ if (window.testRunner) >+ currentTest.run(); >+} >+ >+function runTest() >+{ >+ if (!window.testRunner) >+ return; >+ nextTouchPress(); >+} >+ >+function setUp() >+{ >+ let square = document.getElementById("square"); >+ square.addEventListener("touchdown", handleTouchDown, true); >+ square.addEventListener("touchup", handleTouchUp, true); >+ >+ for (const touchType in TouchType) { >+ for (const modifiers of computeSubsets(modifierKeys)) >+ tests.push(new TouchTest(square, touchType, modifiers)); >+ } >+ >+ runTest(); >+} >+ >+window.addEventListener("load", setUp, true); >+</script> >+<style> >+#square { >+ background-color: blue; >+ color: white; >+ height: 128px; >+ width: 128px; >+ display: flex; >+ align-items: center; >+ justify-content: center; >+ user-select: none; >+ -webkit-user-select: none; >+} >+</style> >+</head> >+<body> >+<p>This logs DOM touchdown and touchup events that are dispatched when single tapping and double tapping an element while holding modifier keys. Must be run in WebKitTestRunner.</p> >+<div id="square">Touch Me</div> >+<pre id="console"></pre> >+</body> >+</html> >diff --git a/LayoutTests/resources/ui-helper.js b/LayoutTests/resources/ui-helper.js >index fe546a8c865013de4ed045ecc6acd0e23bbbeac3..17b5cb63a77744453f04b771ed456ad4b100c3f2 100644 >--- a/LayoutTests/resources/ui-helper.js >+++ b/LayoutTests/resources/ui-helper.js >@@ -29,11 +29,12 @@ window.UIHelper = class UIHelper { > eventSender.mouseUp(); > } > >- static tapAt(x, y) >+ static tapAt(x, y, modifiers=[]) > { > console.assert(this.isIOS()); > > if (!this.isWebKit2()) { >+ console.assert(!modifiers || !modifiers.length); > eventSender.addTouchPoint(x, y); > eventSender.touchStart(); > eventSender.releaseTouchPoint(0); >@@ -43,17 +44,20 @@ window.UIHelper = class UIHelper { > > return new Promise((resolve) => { > testRunner.runUIScript(` >- uiController.singleTapAtPoint(${x}, ${y}, function() { >- uiController.uiScriptComplete(); >- });`, resolve); >+ uiController.performWithModifiers(() => { >+ uiController.singleTapAtPoint(${x}, ${y}, function() { >+ uiController.uiScriptComplete(); >+ }); >+ }, ${JSON.stringify(modifiers)});`, resolve); > }); > } > >- static doubleTapAt(x, y) >+ static doubleTapAt(x, y, modifiers=[]) > { > console.assert(this.isIOS()); > > if (!this.isWebKit2()) { >+ console.assert(!modifiers || !modifiers.length); > eventSender.addTouchPoint(x, y); > eventSender.touchStart(); > eventSender.releaseTouchPoint(0); >@@ -67,9 +71,11 @@ window.UIHelper = class UIHelper { > > return new Promise((resolve) => { > testRunner.runUIScript(` >- uiController.doubleTapAtPoint(${x}, ${y}, function() { >- uiController.uiScriptComplete(); >- });`, resolve); >+ uiController.performWithModifiers(() => { >+ uiController.doubleTapAtPoint(${x}, ${y}, function() { >+ uiController.uiScriptComplete(); >+ }); >+ }, ${JSON.stringify(modifiers)});`, resolve); > }); > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 191446
:
361342
|
361421
|
361427
|
361435
|
361447
|
361455
|
361456
|
361458
|
361538
|
361551
|
361553
|
361556
|
361575
|
361637
|
361639
|
361641
|
361642
|
361646
|
361696