[Mac] WebKit is not honoring OS preferences for secondary click behaviors
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Apr 2015 02:41:31 +0000 (02:41 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Apr 2015 02:41:31 +0000 (02:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=143452
<rdar://problem/20437483>

Reviewed by Tim Horton.

Source/WebCore:

We cannot rely on the event's button number to decide behavior. The OS settings might have
mapped middle button to context menu, etc. Instead, we should ask the OS (via NSMenu) what
the proper button press behavior is.

* platform/mac/PlatformEventFactoryMac.mm:
(WebCore::mouseButtonForEvent): Ask NSMenu what kind of button press we have received.

Source/WebKit/mac:

We were improperly intercepting contextual menu clicks and passing them through
the mouseDown handler, rather than processing via NSView's menu handling code.

* WebView/WebHTMLView.mm:
(-[WebHTMLView otherMouseDown:]): Treat context menu events the same as the action
menu case, and pass it to AppKit for normal menu processing.

Source/WebKit2:

We cannot rely on the event's button number to decide behavior. The OS settings might have
mapped middle button to context menu, etc. Instead, we should ask the OS (via NSMenu) what
the proper button press behavior is.

* Shared/mac/WebEventFactory.mm:
(WebKit::mouseButtonForEvent): Ask NSMenu what kind of button press we have received.

Tools:

Add a new API test to confirm that Cocoa mouse button press events are properly
tagged with the desired menu behavior (i.e., 'None', 'Context', or 'Action'.)

The WK2 test dispatches mouse down events to a PlatformWebView, and checks with
some registered event handlers that the expected button press and context menu
events are received.

The WK1 unit test creates an NSEvent with the desired button press state, and then
uses WebCore::PlatformEventFactory::createPlatformMouseEvent to create a WebCore event.
We check the resulting PlatformMouseEvent for proper state.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Add new test files.
* TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp: Added.
(TestWebKitAPI::buildAndPerformTest): Helper function to build/run an individual test.
* TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html: Added.
* TestWebKitAPI/Tests/mac/MenuTypesForMouseEvents.mm: Added.
(TestWebKitAPI::canCallMenuTypeForEvent): Helper function.
(TestWebKitAPI::buildAndPerformTest): Helper function to build/run an individual test.
* TestWebKitAPI/mac/PlatformWebViewMac.mm:
(TestWebKitAPI::PlatformWebView::simulateButtonClick): Added method to support firing
mouse down events.
* TestWebKitAPI/mac/PlatformWebViewMac.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@182581 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/PlatformMouseEvent.h
Source/WebCore/platform/mac/PlatformEventFactoryMac.mm
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebHTMLView.mm
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebEvent.h
Source/WebKit2/Shared/WebEventConversion.cpp
Source/WebKit2/Shared/WebMouseEvent.cpp
Source/WebKit2/Shared/mac/WebEventFactory.h
Source/WebKit2/Shared/mac/WebEventFactory.mm
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/PlatformWebView.h
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/mac/MenuTypesForMouseEvents.mm [new file with mode: 0644]
Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm

index 0fb1c6d..c5da5ba 100644 (file)
@@ -1,3 +1,18 @@
+2015-04-08  Brent Fulgham  <bfulgham@apple.com>
+
+        [Mac] WebKit is not honoring OS preferences for secondary click behaviors
+        https://bugs.webkit.org/show_bug.cgi?id=143452
+        <rdar://problem/20437483>
+
+        Reviewed by Tim Horton.
+
+        We cannot rely on the event's button number to decide behavior. The OS settings might have
+        mapped middle button to context menu, etc. Instead, we should ask the OS (via NSMenu) what
+        the proper button press behavior is.
+
+        * platform/mac/PlatformEventFactoryMac.mm:
+        (WebCore::mouseButtonForEvent): Ask NSMenu what kind of button press we have received.
+
 2015-04-08  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         Fix -Wformat in AnimationBase.cpp
index 4da6319..d417d3a 100644 (file)
@@ -55,6 +55,7 @@ namespace WebCore {
             , m_modifierFlags(0)
 #if PLATFORM(MAC)
             , m_eventNumber(0)
+            , m_menuTypeForEvent(0)
 #elif PLATFORM(WIN)
             , m_didActivateWebView(false)
 #endif
@@ -71,6 +72,7 @@ namespace WebCore {
             , m_modifierFlags(0)
 #if PLATFORM(MAC)
             , m_eventNumber(0)
+            , m_menuTypeForEvent(0)
 #elif PLATFORM(WIN)
             , m_didActivateWebView(false)
 #endif
@@ -103,6 +105,7 @@ namespace WebCore {
 
 #if PLATFORM(MAC)
         int eventNumber() const { return m_eventNumber; }
+        int menuTypeForEvent() const { return m_menuTypeForEvent; }
 #endif
 
 #if PLATFORM(WIN)
@@ -123,6 +126,7 @@ namespace WebCore {
 
 #if PLATFORM(MAC)
         int m_eventNumber;
+        int m_menuTypeForEvent;
 #elif PLATFORM(WIN)
         bool m_didActivateWebView;
 #endif
index d5649af..314fb1d 100644 (file)
@@ -28,6 +28,7 @@
 
 #import "KeyEventCocoa.h"
 #import "Logging.h"
+#import "NSMenuSPI.h"
 #import "PlatformScreen.h"
 #import "Scrollbar.h"
 #import "WebCoreSystemInterface.h"
@@ -394,7 +395,20 @@ static inline PlatformEvent::Modifiers modifiersForEvent(NSEvent *event)
     return (PlatformEvent::Modifiers)modifiers;
 }
 
+static int typeForEvent(NSEvent *event)
+{
+    if ([NSMenu respondsToSelector:@selector(menuTypeForEvent:)])
+        return static_cast<int>([NSMenu menuTypeForEvent:event]);
+
+    if (mouseButtonForEvent(event) == RightButton)
+        return static_cast<int>(NSMenuTypeContextMenu);
+
+    if (mouseButtonForEvent(event) == LeftButton && (modifiersForEvent(event) & NSControlKeyMask))
+        return static_cast<int>(NSMenuTypeContextMenu);
 
+    return static_cast<int>(NSMenuTypeNone);
+}
+    
 class PlatformMouseEventBuilder : public PlatformMouseEvent {
 public:
     PlatformMouseEventBuilder(NSEvent *event, NSView *windowView)
@@ -413,6 +427,7 @@ public:
         // Mac specific
         m_modifierFlags                     = [event modifierFlags];
         m_eventNumber                       = [event eventNumber];
+        m_menuTypeForEvent                  = typeForEvent(event);
     }
 };
 
index 9a219f2..66cf723 100644 (file)
@@ -1,3 +1,18 @@
+2015-04-08  Brent Fulgham  <bfulgham@apple.com>
+
+        [Mac] WebKit is not honoring OS preferences for secondary click behaviors
+        https://bugs.webkit.org/show_bug.cgi?id=143452
+        <rdar://problem/20437483>
+
+        Reviewed by Tim Horton.
+
+        We were improperly intercepting contextual menu clicks and passing them through
+        the mouseDown handler, rather than processing via NSView's menu handling code.
+
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView otherMouseDown:]): Treat context menu events the same as the action
+        menu case, and pass it to AppKit for normal menu processing. 
+
 2015-04-08  Brady Eidson  <beidson@apple.com>
 
         Expose the "Share" menu for links, images, and media.
index 73ba4e1..6dd4c4c 100644 (file)
@@ -5392,7 +5392,8 @@ static BOOL writingDirectionKeyBindingsEnabled()
 #if !PLATFORM(IOS)
 - (void)otherMouseDown:(NSEvent *)event
 {
-    if ([event buttonNumber] != 2 || ([NSMenu respondsToSelector:@selector(menuTypeForEvent:)] && [NSMenu menuTypeForEvent:event] == NSMenuTypeActionMenu)) {
+    if ([event buttonNumber] != 2 || ([NSMenu respondsToSelector:@selector(menuTypeForEvent:)]
+        && ([NSMenu menuTypeForEvent:event] == NSMenuTypeActionMenu || [NSMenu menuTypeForEvent:event] == NSMenuTypeContextMenu))) {
         [super otherMouseDown:event];
         return;
     }
index 097140c..f460e52 100644 (file)
@@ -1,3 +1,18 @@
+2015-04-08  Brent Fulgham  <bfulgham@apple.com>
+
+        [Mac] WebKit is not honoring OS preferences for secondary click behaviors
+        https://bugs.webkit.org/show_bug.cgi?id=143452
+        <rdar://problem/20437483>
+
+        Reviewed by Tim Horton.
+
+        We cannot rely on the event's button number to decide behavior. The OS settings might have
+        mapped middle button to context menu, etc. Instead, we should ask the OS (via NSMenu) what
+        the proper button press behavior is.
+
+        * Shared/mac/WebEventFactory.mm:
+        (WebKit::mouseButtonForEvent): Ask NSMenu what kind of button press we have received.
+
 2015-04-08  Brady Eidson  <beidson@apple.com>
 
         Expose the "Share" menu for links, images, and media.
index 705ed5e..ada49a7 100644 (file)
@@ -124,7 +124,7 @@ public:
     WebMouseEvent();
 
 #if PLATFORM(MAC)
-    WebMouseEvent(Type, Button, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, Modifiers, double timestamp, int eventNumber = -1);
+    WebMouseEvent(Type, Button, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, Modifiers, double timestamp, int eventNumber = -1, int menuType = 0);
 #else
     WebMouseEvent(Type, Button, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, Modifiers, double timestamp);
 #endif
@@ -138,6 +138,7 @@ public:
     int32_t clickCount() const { return m_clickCount; }
 #if PLATFORM(MAC)
     int32_t eventNumber() const { return m_eventNumber; }
+    int32_t menuTypeForEvent() const { return m_menuTypeForEvent; }
 #endif
 
     void encode(IPC::ArgumentEncoder&) const;
@@ -155,6 +156,7 @@ private:
     int32_t m_clickCount;
 #if PLATFORM(MAC)
     int32_t m_eventNumber;
+    int32_t m_menuTypeForEvent;
 #endif
 };
 
index 329287c..422e0c7 100644 (file)
@@ -84,6 +84,7 @@ public:
         m_clickCount = webEvent.clickCount();
 #if PLATFORM(MAC)
         m_eventNumber = webEvent.eventNumber();
+        m_menuTypeForEvent = webEvent.menuTypeForEvent();
 #endif
 
         m_modifierFlags = 0;
index b599fbc..791f709 100644 (file)
@@ -42,12 +42,13 @@ WebMouseEvent::WebMouseEvent()
     , m_clickCount(0)
 #if PLATFORM(MAC)
     , m_eventNumber(-1)
+    , m_menuTypeForEvent(0)
 #endif
 {
 }
 
 #if PLATFORM(MAC)
-WebMouseEvent::WebMouseEvent(Type type, Button button, const IntPoint& position, const IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, Modifiers modifiers, double timestamp, int eventNumber)
+WebMouseEvent::WebMouseEvent(Type type, Button button, const IntPoint& position, const IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, Modifiers modifiers, double timestamp, int eventNumber, int menuType)
 #else
 WebMouseEvent::WebMouseEvent(Type type, Button button, const IntPoint& position, const IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, Modifiers modifiers, double timestamp)
 #endif
@@ -61,6 +62,7 @@ WebMouseEvent::WebMouseEvent(Type type, Button button, const IntPoint& position,
     , m_clickCount(clickCount)
 #if PLATFORM(MAC)
     , m_eventNumber(eventNumber)
+    , m_menuTypeForEvent(menuType)
 #endif
 {
     ASSERT(isMouseEventType(type));
@@ -79,6 +81,7 @@ void WebMouseEvent::encode(IPC::ArgumentEncoder& encoder) const
     encoder << m_clickCount;
 #if PLATFORM(MAC)
     encoder << m_eventNumber;
+    encoder << m_menuTypeForEvent;
 #endif
 }
 
@@ -104,6 +107,8 @@ bool WebMouseEvent::decode(IPC::ArgumentDecoder& decoder, WebMouseEvent& result)
 #if PLATFORM(MAC)
     if (!decoder.decode(result.m_eventNumber))
         return false;
+    if (!decoder.decode(result.m_menuTypeForEvent))
+        return false;
 #endif
 
     return true;
index df16fc6..71b93fc 100644 (file)
 
 #import "WebEvent.h"
 
+#if USE(APPKIT)
+namespace WebCore {
+class PlatformMouseEvent;
+}
+#endif
+
 namespace WebKit {
 
 // FIXME: This is not needed in the WebProcess and should be moved to be a peer
@@ -39,6 +45,7 @@ public:
     static WebMouseEvent createWebMouseEvent(NSEvent *, NSView *windowView);
     static WebWheelEvent createWebWheelEvent(NSEvent *, NSView *windowView);
     static WebKeyboardEvent createWebKeyboardEvent(NSEvent *, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>&);
+    static bool shouldBeHandledAsContextClick(const WebCore::PlatformMouseEvent&);
 #endif // USE(APPKIT)
 };
 
index 2b3c5a3..04fc472 100644 (file)
@@ -30,6 +30,7 @@
 
 #import "WebKitSystemInterface.h"
 #import <WebCore/KeyboardEvent.h>
+#import <WebCore/NSMenuSPI.h>
 #import <WebCore/PlatformEventFactoryMac.h>
 #import <WebCore/Scrollbar.h>
 #import <WebCore/WindowsKeyboardCodes.h>
@@ -338,6 +339,25 @@ static inline WebEvent::Modifiers modifiersForEvent(NSEvent *event)
     return (WebEvent::Modifiers)modifiers;
 }
 
+static int typeForEvent(NSEvent *event)
+{
+    if ([NSMenu respondsToSelector:@selector(menuTypeForEvent:)])
+        return static_cast<int>([NSMenu menuTypeForEvent:event]);
+    
+    if (mouseButtonForEvent(event) == WebMouseEvent::RightButton)
+        return static_cast<int>(NSMenuTypeContextMenu);
+    
+    if (mouseButtonForEvent(event) == WebMouseEvent::LeftButton && (modifiersForEvent(event) & NSControlKeyMask))
+        return static_cast<int>(NSMenuTypeContextMenu);
+    
+    return static_cast<int>(NSMenuTypeNone);
+}
+
+bool WebEventFactory::shouldBeHandledAsContextClick(const WebCore::PlatformMouseEvent& event)
+{
+    return (static_cast<NSMenuType>(event.menuTypeForEvent()) == NSMenuTypeContextMenu);
+}
+
 WebMouseEvent WebEventFactory::createWebMouseEvent(NSEvent *event, NSView *windowView)
 {
     NSPoint position = pointForEvent(event, windowView);
@@ -352,8 +372,9 @@ WebMouseEvent WebEventFactory::createWebMouseEvent(NSEvent *event, NSView *windo
     WebEvent::Modifiers modifiers           = modifiersForEvent(event);
     double timestamp                        = eventTimeStampSince1970(event);
     int eventNumber                         = [event eventNumber];
+    int menuTypeForEvent                    = typeForEvent(event);
 
-    return WebMouseEvent(type, button, IntPoint(position), IntPoint(globalPosition), deltaX, deltaY, deltaZ, clickCount, modifiers, timestamp, eventNumber);
+    return WebMouseEvent(type, button, IntPoint(position), IntPoint(globalPosition), deltaX, deltaY, deltaZ, clickCount, modifiers, timestamp, eventNumber, menuTypeForEvent);
 }
 
 WebWheelEvent WebEventFactory::createWebWheelEvent(NSEvent *event, NSView *windowView)
index 5bd73a7..9716263 100644 (file)
@@ -71,6 +71,7 @@
 #include "WebEditorClient.h"
 #include "WebEvent.h"
 #include "WebEventConversion.h"
+#include "WebEventFactory.h"
 #include "WebFrame.h"
 #include "WebFrameLoaderClient.h"
 #include "WebFullScreenManager.h"
@@ -1822,16 +1823,11 @@ private:
 #if ENABLE(CONTEXT_MENUS)
 static bool isContextClick(const PlatformMouseEvent& event)
 {
-    if (event.button() == WebCore::RightButton)
-        return true;
-
 #if PLATFORM(COCOA)
-    // FIXME: this really should be about OSX-style UI, not about the Mac port
-    if (event.button() == WebCore::LeftButton && event.ctrlKey())
-        return true;
+    return WebEventFactory::shouldBeHandledAsContextClick(event);
+#else
+    return event.button() == WebCore::RightButton;
 #endif
-
-    return false;
 }
 
 static bool handleContextMenuEvent(const PlatformMouseEvent& platformMouseEvent, WebPage* page)
index 4ca9b4e..86f25ec 100644 (file)
@@ -1,3 +1,34 @@
+2015-04-08  Brent Fulgham  <bfulgham@apple.com>
+
+        [Mac] WebKit is not honoring OS preferences for secondary click behaviors
+        https://bugs.webkit.org/show_bug.cgi?id=143452
+        <rdar://problem/20437483>
+
+        Reviewed by Tim Horton.
+
+        Add a new API test to confirm that Cocoa mouse button press events are properly
+        tagged with the desired menu behavior (i.e., 'None', 'Context', or 'Action'.)
+
+        The WK2 test dispatches mouse down events to a PlatformWebView, and checks with
+        some registered event handlers that the expected button press and context menu
+        events are received.
+
+        The WK1 unit test creates an NSEvent with the desired button press state, and then
+        uses WebCore::PlatformEventFactory::createPlatformMouseEvent to create a WebCore event.
+        We check the resulting PlatformMouseEvent for proper state.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Add new test files.
+        * TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp: Added.
+        (TestWebKitAPI::buildAndPerformTest): Helper function to build/run an individual test.
+        * TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html: Added.
+        * TestWebKitAPI/Tests/mac/MenuTypesForMouseEvents.mm: Added.
+        (TestWebKitAPI::canCallMenuTypeForEvent): Helper function.
+        (TestWebKitAPI::buildAndPerformTest): Helper function to build/run an individual test.
+        * TestWebKitAPI/mac/PlatformWebViewMac.mm:
+        (TestWebKitAPI::PlatformWebView::simulateButtonClick): Added method to support firing
+        mouse down events.
+        * TestWebKitAPI/mac/PlatformWebViewMac.h:
+
 2015-04-08  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         [GTK] Add pango to jhbuild-optional.modules
index 1f65814..2e11cf7 100644 (file)
@@ -73,6 +73,9 @@ public:
     void simulateAltKeyPress();
     void simulateRightClick(unsigned x, unsigned y);
     void simulateMouseMove(unsigned x, unsigned y);
+#if PLATFORM(MAC)
+    void simulateButtonClick(WKEventMouseButton, unsigned x, unsigned y, WKEventModifiers);
+#endif
 
 private:
 #if PLATFORM(MAC)
index 0d67b2c..b5039a2 100644 (file)
@@ -57,6 +57,9 @@
                7673499D1930C5BB00E44DF9 /* StopLoadingDuringDidFailProvisionalLoad_bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7673499A1930182E00E44DF9 /* StopLoadingDuringDidFailProvisionalLoad_bundle.cpp */; };
                76E182DD1547569100F1FADD /* WillSendSubmitEvent_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76E182DC1547569100F1FADD /* WillSendSubmitEvent_Bundle.cpp */; };
                76E182DF154767E600F1FADD /* auto-submitting-form.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 76E182DE15475A8300F1FADD /* auto-submitting-form.html */; };
+               7A1458FC1AD5C07000E06772 /* mouse-button-listener.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7A1458FB1AD5C03500E06772 /* mouse-button-listener.html */; };
+               7A5623111AD5AF3E0096B920 /* MenuTypesForMouseEvents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A5623101AD5AF3E0096B920 /* MenuTypesForMouseEvents.cpp */; };
+               7A99D9941AD4A29D00373141 /* MenuTypesForMouseEvents.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A99D9931AD4A29D00373141 /* MenuTypesForMouseEvents.mm */; };
                7AA021BB1AB09EA70052953F /* DateMath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA021BA1AB09EA70052953F /* DateMath.cpp */; };
                7AA6A1521AAC0B31002B2ED3 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA6A1511AAC0B31002B2ED3 /* WorkQueue.cpp */; };
                7C486BA11AA12567003F6F9B /* bundle-file.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7C486BA01AA1254B003F6F9B /* bundle-file.html */; };
                        dstPath = TestWebKitAPI.resources;
                        dstSubfolderSpec = 7;
                        files = (
+                               7A1458FC1AD5C07000E06772 /* mouse-button-listener.html in Copy Resources */,
                                7C486BA11AA12567003F6F9B /* bundle-file.html in Copy Resources */,
                                1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
                                379028B914FAC24C007E6B43 /* acceptsFirstMouse.html in Copy Resources */,
                76E182D91547550100F1FADD /* WillSendSubmitEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WillSendSubmitEvent.cpp; sourceTree = "<group>"; };
                76E182DC1547569100F1FADD /* WillSendSubmitEvent_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WillSendSubmitEvent_Bundle.cpp; sourceTree = "<group>"; };
                76E182DE15475A8300F1FADD /* auto-submitting-form.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "auto-submitting-form.html"; sourceTree = "<group>"; };
+               7A1458FB1AD5C03500E06772 /* mouse-button-listener.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "mouse-button-listener.html"; sourceTree = "<group>"; };
+               7A5623101AD5AF3E0096B920 /* MenuTypesForMouseEvents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MenuTypesForMouseEvents.cpp; sourceTree = "<group>"; };
+               7A99D9931AD4A29D00373141 /* MenuTypesForMouseEvents.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MenuTypesForMouseEvents.mm; sourceTree = "<group>"; };
                7AA021BA1AB09EA70052953F /* DateMath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DateMath.cpp; sourceTree = "<group>"; };
                7AA6A1511AAC0B31002B2ED3 /* WorkQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkQueue.cpp; sourceTree = "<group>"; };
                7C486BA01AA1254B003F6F9B /* bundle-file.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "bundle-file.html"; sourceTree = "<group>"; };
                                7C54A4BC1AA11CCA00380F78 /* WKBundleFileHandle.cpp */,
                                7C54A4BF1AA11CE400380F78 /* WKBundleFileHandle_Bundle.cpp */,
                                A1FDFD2E19C288BB005148A4 /* WKImageCreateCGImageCrash.cpp */,
+                               7A5623101AD5AF3E0096B920 /* MenuTypesForMouseEvents.cpp */,
                                7C89D2AA1A69B80D003A5FDE /* WKPageConfiguration.cpp */,
                                51E93016156B13E1004C99DF /* WKPageGetScaleFactorNotZero.cpp */,
                                524BBC9C19DF377A002F1AF1 /* WKPageIsPlayingAudio.cpp */,
                BC90977B125571AE00083756 /* Resources */ = {
                        isa = PBXGroup;
                        children = (
+                               7A1458FB1AD5C03500E06772 /* mouse-button-listener.html */,
                                C045F9461385C2F800C0F3CD /* 18-characters.html */,
                                2D950FBF1A230C1E00012434 /* action-menu-targets.html */,
                                93D3D19B17B1A7B000C7C415 /* all-content-in-one-iframe.html */,
                                4BB4160116815B2600824238 /* JSWrapperForNodeInWebFrame.mm */,
                                E1220D9F155B25480013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.mm */,
                                517E7DFB15110EA600D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.mm */,
+                               7A99D9931AD4A29D00373141 /* MenuTypesForMouseEvents.mm */,
                                A57A34EF16AF677200C2501F /* PageVisibilityStateWithWindowChanges.mm */,
                                00BC16851680FE810065F1E5 /* PublicSuffix.mm */,
                                37C784DE197C8F2E0010A496 /* RenderedImageFromDOMNode.mm */,
                                2E7765CD16C4D80A00BA2BB1 /* mainIOS.mm in Sources */,
                                7AA6A1521AAC0B31002B2ED3 /* WorkQueue.cpp in Sources */,
                                2E7765CF16C4D81100BA2BB1 /* mainMac.mm in Sources */,
+                               7A5623111AD5AF3E0096B920 /* MenuTypesForMouseEvents.cpp in Sources */,
+                               7A99D9941AD4A29D00373141 /* MenuTypesForMouseEvents.mm in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp
new file mode 100644 (file)
index 0000000..f77a11a
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "JavaScriptTest.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+    didFinishLoad = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+    WKPageLoaderClientV0 loaderClient;
+    memset(&loaderClient, 0, sizeof(loaderClient));
+
+    loaderClient.base.version = 0;
+    loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+    WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+static void buildAndPerformTest(WKEventMouseButton button, WKEventModifiers modifiers, const char* expectedButton, const char* expectedMenuType)
+{
+    WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+    PlatformWebView webView(context.get());
+    setPageLoaderClient(webView.page());
+
+    WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("mouse-button-listener", "html"));
+    WKPageLoadURL(webView.page(), url.get());
+    Util::run(&didFinishLoad);
+
+    didFinishLoad = false;
+
+    webView.simulateButtonClick(button, 10, 10, modifiers);
+
+    EXPECT_JS_EQ(webView.page(), "pressedMouseButton()", expectedButton);
+    EXPECT_JS_EQ(webView.page(), "displayedMenu()", expectedMenuType);
+}
+
+TEST(WebKit2, MenuAndButtonForNormalLeftClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonLeftButton, 0, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForNormalRightClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonRightButton, 0, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForNormalMiddleClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonMiddleButton, 0, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForControlLeftClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersControlKey, "0", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForControlRightClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersControlKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForControlMiddleClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersControlKey, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForShiftLeftClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersShiftKey, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForShiftRightClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersShiftKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForShiftMiddleClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersShiftKey, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForCommandLeftClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersMetaKey, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForCommandRightClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersMetaKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForCommandMiddleClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersMetaKey, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForAltLeftClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersAltKey, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForAltRightClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersAltKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForAltMiddleClick)
+{
+    buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersAltKey, "1", "none");
+}
+    
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html b/Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html
new file mode 100644 (file)
index 0000000..1fdbb1a
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<script>
+    var mouseButton = -1;
+    var menuType = "none";
+
+    function mouseDownHandler(event)
+    {
+        mouseButton = event.button;
+        event.preventDefault();
+    }
+    
+    function pressedMouseButton()
+    {
+        return mouseButton;
+    }
+    function contextMenuHandler(event)
+    {
+        menuType = "context";
+        event.preventDefault();
+    }
+  
+    function displayedMenu()
+    {
+        return menuType;
+    }
+
+    addEventListener("mousedown", mouseDownHandler);
+    addEventListener("contextmenu", contextMenuHandler);
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/mac/MenuTypesForMouseEvents.mm b/Tools/TestWebKitAPI/Tests/mac/MenuTypesForMouseEvents.mm
new file mode 100644 (file)
index 0000000..03f0f74
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "PlatformUtilities.h"
+#import <Carbon/Carbon.h> // For GetCurrentEventTime
+#import <WebCore/NSMenuSPI.h>
+#import <WebCore/PlatformEventFactoryMac.h>
+#import <wtf/AutodrainedPool.h>
+#import <wtf/RetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool canCallMenuTypeForEvent()
+{
+    return [NSMenu respondsToSelector:@selector(menuTypeForEvent:)];
+}
+
+static void buildAndPerformTest(NSEventType buttonEvent, NSEventModifierFlags modifierFlags, WebCore::MouseButton expectedButton, NSMenuType expectedMenu)
+{
+    AutodrainedPool pool;
+    RetainPtr<WebView> webView = adoptNS([[WebView alloc] init]);
+    NSEvent *event = [NSEvent mouseEventWithType:buttonEvent
+                                        location:NSMakePoint(100, 100)
+                                   modifierFlags:modifierFlags
+                                       timestamp:GetCurrentEventTime()
+                                    windowNumber:[[webView window] windowNumber]
+                                         context:[NSGraphicsContext currentContext]
+                                     eventNumber:0
+                                      clickCount:0
+                                        pressure:0];
+    
+    auto pme = WebCore::PlatformEventFactory::createPlatformMouseEvent(event, webView.get());
+    
+    EXPECT_EQ(expectedButton, pme.button());
+    EXPECT_TRUE(!modifierFlags || pme.modifierFlags() & modifierFlags);
+    EXPECT_EQ(expectedMenu, pme.menuTypeForEvent());
+    if (canCallMenuTypeForEvent())
+        EXPECT_EQ(expectedMenu, [NSMenu menuTypeForEvent:event]);
+}
+
+TEST(WebKit1, MenuAndButtonForNormalLeftClick)
+{
+    buildAndPerformTest(NSLeftMouseDown, 0, WebCore::LeftButton, NSMenuTypeNone);
+}
+
+TEST(WebKit1, MenuAndButtonForNormalRightClick)
+{
+    buildAndPerformTest(NSRightMouseDown, 0, WebCore::RightButton, NSMenuTypeContextMenu);
+}
+
+TEST(WebKit1, MenuAndButtonForNormalMiddleClick)
+{
+    buildAndPerformTest(NSOtherMouseDown, 0, WebCore::MiddleButton, NSMenuTypeNone);
+}
+
+TEST(WebKit1, MenuAndButtonForControlLeftClick)
+{
+    buildAndPerformTest(NSLeftMouseDown, NSControlKeyMask, WebCore::LeftButton, NSMenuTypeContextMenu);
+}
+
+TEST(WebKit1, MenuAndButtonForControlRightClick)
+{
+    buildAndPerformTest(NSRightMouseDown, NSControlKeyMask, WebCore::RightButton, NSMenuTypeContextMenu);
+}
+
+TEST(WebKit1, MenuAndButtonForControlMiddleClick)
+{
+    buildAndPerformTest(NSOtherMouseDown, NSControlKeyMask, WebCore::MiddleButton, NSMenuTypeNone);
+}
+    
+TEST(WebKit1, MenuAndButtonForShiftLeftClick)
+{
+    buildAndPerformTest(NSLeftMouseDown, NSShiftKeyMask, WebCore::LeftButton, NSMenuTypeNone);
+}
+
+TEST(WebKit1, MenuAndButtonForShiftRightClick)
+{
+    buildAndPerformTest(NSRightMouseDown, NSShiftKeyMask, WebCore::RightButton, NSMenuTypeContextMenu);
+}
+
+TEST(WebKit1, MenuAndButtonForShiftMiddleClick)
+{
+    buildAndPerformTest(NSOtherMouseDown, NSShiftKeyMask, WebCore::MiddleButton, NSMenuTypeNone);
+}
+
+TEST(WebKit1, MenuAndButtonForCommandLeftClick)
+{
+    buildAndPerformTest(NSLeftMouseDown, NSCommandKeyMask, WebCore::LeftButton, NSMenuTypeNone);
+}
+
+TEST(WebKit1, MenuAndButtonForCommandRightClick)
+{
+    buildAndPerformTest(NSRightMouseDown, NSCommandKeyMask, WebCore::RightButton, NSMenuTypeContextMenu);
+}
+
+TEST(WebKit1, MenuAndButtonForCommandMiddleClick)
+{
+    buildAndPerformTest(NSOtherMouseDown, NSCommandKeyMask, WebCore::MiddleButton, NSMenuTypeNone);
+}
+
+TEST(WebKit1, MenuAndButtonForAltLeftClick)
+{
+    buildAndPerformTest(NSLeftMouseDown, NSAlternateKeyMask, WebCore::LeftButton, NSMenuTypeNone);
+}
+
+TEST(WebKit1, MenuAndButtonForAltRightClick)
+{
+    buildAndPerformTest(NSRightMouseDown, NSAlternateKeyMask, WebCore::RightButton, NSMenuTypeContextMenu);
+}
+
+TEST(WebKit1, MenuAndButtonForAltMiddleClick)
+{
+    buildAndPerformTest(NSOtherMouseDown, NSAlternateKeyMask, WebCore::MiddleButton, NSMenuTypeNone);
+}
+
+
+} // namespace TestWebKitAPI
index 0bcbb14..3159cec 100644 (file)
@@ -193,4 +193,50 @@ void PlatformWebView::simulateMouseMove(unsigned x, unsigned y)
     
 }
 
+static NSEventType eventTypeForButton(WKEventMouseButton button)
+{
+    switch (button) {
+    case kWKEventMouseButtonLeftButton:
+        return NSLeftMouseDown;
+    case kWKEventMouseButtonRightButton:
+        return NSRightMouseDown;
+    case kWKEventMouseButtonMiddleButton:
+        return NSOtherMouseDown;
+    case kWKEventMouseButtonNoButton:
+        return NSLeftMouseDown;
+    }
+
+    return NSLeftMouseDown;
+}
+
+static NSEventModifierFlags modifierFlagsForWKModifiers(WKEventModifiers modifiers)
+{
+    NSEventModifierFlags returnVal = 0;
+    if (modifiers & kWKEventModifiersShiftKey)
+        returnVal |= NSShiftKeyMask;
+    if (modifiers & kWKEventModifiersControlKey)
+        returnVal |= NSControlKeyMask;
+    if (modifiers & kWKEventModifiersAltKey)
+        returnVal |= NSAlternateKeyMask;
+    if (modifiers & kWKEventModifiersMetaKey)
+        returnVal |= NSCommandKeyMask;
+
+    return returnVal;
+}
+    
+void PlatformWebView::simulateButtonClick(WKEventMouseButton button, unsigned x, unsigned y, WKEventModifiers modifiers)
+{
+    NSEvent *event = [NSEvent mouseEventWithType:eventTypeForButton(button)
+                                        location:NSMakePoint(x, y)
+                                   modifierFlags:modifierFlagsForWKModifiers(modifiers)
+                                       timestamp:GetCurrentEventTime()
+                                    windowNumber:[m_window windowNumber]
+                                         context:[NSGraphicsContext currentContext]
+                                     eventNumber:0
+                                      clickCount:0
+                                        pressure:0];
+
+    [m_view mouseDown:event];
+}
+
 } // namespace TestWebKitAPI