[Mac] Don't perform a round-trip through WebProcess before interpreting key events
authorap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 9 Mar 2014 22:56:08 +0000 (22:56 +0000)
committerap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 9 Mar 2014 22:56:08 +0000 (22:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=129812

Reviewed by Darin Adler.

Source/WebCore:

No significant behavior changes expected, except for Esc key processing, which now
dispatches a keypress before executing its default action.

* platform/KeypressCommand.h: Added.
(WebCore::KeypressCommand::KeypressCommand):
* GNUmakefile.list.am:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.xcodeproj/project.pbxproj:
Moved KeypressCommand from dom/KeyboardEvent.h to its own header, as it needed
in platform/ directory now.

* dom/KeyboardEvent.cpp:
(WebCore::KeyboardEvent::KeyboardEvent):
* dom/KeyboardEvent.h:
(WebCore::KeyboardEvent::handledByInputMethod):
(WebCore::KeyboardEvent::keypressCommands):
* platform/PlatformKeyboardEvent.h:
(WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent):
(WebCore::PlatformKeyboardEvent::handledByInputMethod):
(WebCore::PlatformKeyboardEvent::commands):
PlatformKeyboardEvent now carries results of interpreting the event by AppKit. This
is logically not much different from carrying charcode, and is similar to what Gtk
does for input methods.
KeyboardEvent already had keypress commands, which were added to it after construction.
It's still possible for WebKit1, while with WebKit2, they are provided at construction
time. The event now also has a boolean for whether IM handled it already.

Source/WebKit/mac:

* WebCoreSupport/WebEditorClient.mm: (WebEditorClient::handleInputMethodKeydown):
Added a FIXME. WebKit1/mac is the only port that uses this roundabout way to
interpret events, so it would simplify code if we switched it to WebKit2/mac model.

Source/WebKit2:

* Shared/NativeWebKeyboardEvent.h:
* Shared/WebEvent.h:
(WebKit::WebKeyboardEvent::handledByInputMethod):
(WebKit::WebKeyboardEvent::commands):
* Shared/WebEventConversion.cpp:
(WebKit::WebKit2PlatformKeyboardEvent::WebKit2PlatformKeyboardEvent):
* Shared/WebKeyboardEvent.cpp:
(WebKit::WebKeyboardEvent::WebKeyboardEvent):
(WebKit::WebKeyboardEvent::~WebKeyboardEvent):
(WebKit::WebKeyboardEvent::encode):
(WebKit::WebKeyboardEvent::decode):
* Shared/mac/NativeWebKeyboardEventMac.mm:
(WebKit::NativeWebKeyboardEvent::NativeWebKeyboardEvent):
* Shared/mac/WebEventFactory.h:
* Shared/mac/WebEventFactory.mm:
(WebKit::WebEventFactory::createWebKeyboardEvent):
Keyboard events now carry results of interpretation with them.
Ideally, mouse events should also have a handledByInputMethod member, because IMs
can handle events, but that can wait until we have actual bugs caused by not diabling
default processing for these.

* UIProcess/API/mac/WKView.mm:
(-[WKView becomeFirstResponder]): Updated for new NativeWebKeyboardEvent contructor
signature. We don't interpret the event in this code path.
(-[WKView doCommandBySelector:]): Added logging.
(-[WKView performKeyEquivalent:]): Reimplemented Esc and Cmd+period handling to avoid
infinite loops and re-entrancy. These two work in a unique way in AppKit.
Interpret key event before sending it down to WebProcess.
(-[WKView keyUp:]): Interpret key event before sending it down to WebProcess.
We need to tell IMs about the event, but key binding processing is moot, all commands
are executed on keydown.
(-[WKView keyDown:]): Interpret the event.
(-[WKView flagsChanged:]): Ditto.
(-[WKView _interpretKeyEvent:savingCommandsTo:WebCore::]): Added an assertion in
consumedByIM code path.
(-[WKView _executeSavedCommandBySelector:]): Added logging.

* UIProcess/PageClient.h:
* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
* UIProcess/mac/PageClientImpl.h:
* UIProcess/mac/PageClientImpl.mm:
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/ios/WebPageProxyIOS.mm:
* UIProcess/mac/WebPageProxyMac.mm:
Removed interpretQueuedKeyEvent/interpretKeyEvent, WebProcess no longer asks UIProcess to do this.

* WebProcess/WebCoreSupport/ios/WebEditorClientIOS.mm:
(WebKit::WebEditorClient::handleKeyboardEvent):
* WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm:
(WebKit::WebEditorClient::handleKeyboardEvent):
(WebKit::WebEditorClient::handleInputMethodKeydown):
WebPage::handleEditingKeyboardEvent is now one function instead of two with a boolean
switch between two behaviors.

* WebProcess/WebPage/WebPage.cpp:(WebKit::WebPage::WebPage):
* WebProcess/WebPage/WebPage.h:
Removed m_keyboardEventBeingInterpreted, as we no longer send the event for interpretation.
This means that we sometimes have to pass a null event down to WebCore, but I wasn't
able to find any behavior differences from us doing so.

* WebProcess/WebPage/ios/WebPageIOS.mm: (WebKit::WebPage::handleEditingKeyboardEvent):
Added a FIXME.

* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::executeKeypressCommandsInternal): When we don't have an event,
use current frame as a target, just like input method messages do.
(WebKit::WebPage::handleEditingKeyboardEvent): This function no longer saves commands,
it only interprets them.
Added a check for Esc, as we don't want to handle it in keydown event handler.
(WebKit::WebPage::insertText): Pass 0 instead of m_keyboardEventBeingInterpreted.
(WebKit::WebPage::insertDictatedText): Ditto.
(WebKit::WebPage::executeKeypressCommands): Ditto.

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

35 files changed:
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/KeyboardEvent.cpp
Source/WebCore/dom/KeyboardEvent.h
Source/WebCore/platform/KeypressCommand.h [new file with mode: 0644]
Source/WebCore/platform/PlatformKeyboardEvent.h
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebEditorClient.mm
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/NativeWebKeyboardEvent.h
Source/WebKit2/Shared/WebEvent.h
Source/WebKit2/Shared/WebEventConversion.cpp
Source/WebKit2/Shared/WebKeyboardEvent.cpp
Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm
Source/WebKit2/Shared/mac/WebEventFactory.h
Source/WebKit2/Shared/mac/WebEventFactory.mm
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/PageClient.h
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/UIProcess/ios/PageClientImplIOS.h
Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm
Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit2/UIProcess/mac/PageClientImpl.h
Source/WebKit2/UIProcess/mac/PageClientImpl.mm
Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm
Source/WebKit2/WebProcess/WebCoreSupport/ios/WebEditorClientIOS.mm
Source/WebKit2/WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm
Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm

index 3fc66b4..0636f56 100644 (file)
@@ -1,3 +1,38 @@
+2014-03-06  Alexey Proskuryakov  <ap@apple.com>
+
+        [Mac] Don't perform a round-trip through WebProcess before interpreting key events
+        https://bugs.webkit.org/show_bug.cgi?id=129812
+
+        Reviewed by Darin Adler.
+
+        No significant behavior changes expected, except for Esc key processing, which now
+        dispatches a keypress before executing its default action.
+
+        * platform/KeypressCommand.h: Added.
+        (WebCore::KeypressCommand::KeypressCommand):
+        * GNUmakefile.list.am:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        * WebCore.xcodeproj/project.pbxproj:
+        Moved KeypressCommand from dom/KeyboardEvent.h to its own header, as it needed
+        in platform/ directory now.
+
+        * dom/KeyboardEvent.cpp:
+        (WebCore::KeyboardEvent::KeyboardEvent):
+        * dom/KeyboardEvent.h:
+        (WebCore::KeyboardEvent::handledByInputMethod):
+        (WebCore::KeyboardEvent::keypressCommands):
+        * platform/PlatformKeyboardEvent.h:
+        (WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent):
+        (WebCore::PlatformKeyboardEvent::handledByInputMethod):
+        (WebCore::PlatformKeyboardEvent::commands):
+        PlatformKeyboardEvent now carries results of interpreting the event by AppKit. This
+        is logically not much different from carrying charcode, and is similar to what Gtk
+        does for input methods.
+        KeyboardEvent already had keypress commands, which were added to it after construction.
+        It's still possible for WebKit1, while with WebKit2, they are provided at construction
+        time. The event now also has a boolean for whether IM handled it already.
+
 2014-03-09  Zalan Bujtas  <zalan@apple.com>
 
         Subpixel rendering: Pass FloatSize boxsize to transform animations to support device pixel sizing.
index 82fc531..304a041 100644 (file)
@@ -6007,6 +6007,7 @@ platform_sources += \
        Source/WebCore/platform/URL.h \
        Source/WebCore/platform/URLHash.h \
        Source/WebCore/platform/KeyedCoding.h \
+       Source/WebCore/platform/KeypressCommand.h \
        Source/WebCore/platform/KillRing.h \
        Source/WebCore/platform/KillRingNone.cpp \
        Source/WebCore/platform/Language.cpp \
index 1962110..ea30304 100644 (file)
     <ClInclude Include="..\platform\graphics\win\SharedGDIObject.h" />
     <ClInclude Include="..\platform\HistogramSupport.h" />
     <ClInclude Include="..\platform\HostWindow.h" />
+    <ClInclude Include="..\platform\KeypressCommand.h" />
     <ClInclude Include="..\platform\KillRing.h" />
     <ClInclude Include="..\platform\URL.h" />
     <ClInclude Include="..\platform\URLHash.h" />
index cf6da5a..1eb9fad 100644 (file)
     <ClInclude Include="..\platform\URLHash.h">
       <Filter>platform</Filter>
     </ClInclude>
+    <ClInclude Include="..\platform\KeypressCommand.h">
+      <Filter>platform</Filter>
+    </ClInclude>
     <ClInclude Include="..\platform\Language.h">
       <Filter>platform</Filter>
     </ClInclude>
index 43d2351..d490f1e 100644 (file)
                E157A8F118185425009F821D /* JSCryptoAlgorithmBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = E157A8EF18185425009F821D /* JSCryptoAlgorithmBuilder.h */; };
                E15A36D71104572000B7B639 /* XMLNSNames.h in Headers */ = {isa = PBXBuildFile; fileRef = E15A36D61104572000B7B639 /* XMLNSNames.h */; };
                E15A36D91104572700B7B639 /* XMLNSNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E15A36D81104572700B7B639 /* XMLNSNames.cpp */; };
+               E15FF7D518C9553800FE4C87 /* KeypressCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = E15FF7D418C9553800FE4C87 /* KeypressCommand.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E164FAA318315BF400DB4E61 /* CryptoKeyRSA.h in Headers */ = {isa = PBXBuildFile; fileRef = E164FAA218315BF400DB4E61 /* CryptoKeyRSA.h */; };
                E164FAA518315E1A00DB4E61 /* CryptoKeyRSAMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E164FAA418315E1A00DB4E61 /* CryptoKeyRSAMac.cpp */; };
                E169803D1133542D00894115 /* CRuntimeObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E169803C1133542D00894115 /* CRuntimeObject.h */; };
                E157A8EF18185425009F821D /* JSCryptoAlgorithmBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCryptoAlgorithmBuilder.h; sourceTree = "<group>"; };
                E15A36D61104572000B7B639 /* XMLNSNames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XMLNSNames.h; sourceTree = "<group>"; };
                E15A36D81104572700B7B639 /* XMLNSNames.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XMLNSNames.cpp; sourceTree = "<group>"; };
+               E15FF7D418C9553800FE4C87 /* KeypressCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeypressCommand.h; sourceTree = "<group>"; };
                E164FAA218315BF400DB4E61 /* CryptoKeyRSA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoKeyRSA.h; path = keys/CryptoKeyRSA.h; sourceTree = "<group>"; };
                E164FAA418315E1A00DB4E61 /* CryptoKeyRSAMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoKeyRSAMac.cpp; path = mac/CryptoKeyRSAMac.cpp; sourceTree = "<group>"; };
                E169803C1133542D00894115 /* CRuntimeObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRuntimeObject.h; sourceTree = "<group>"; };
                                D630E2AB149BF344005B2F93 /* HistogramSupport.h */,
                                BC3BC29B0E91AB0F00835588 /* HostWindow.h */,
                                862F129F18C1DCE4005C54AF /* HysteresisActivity.h */,
+                               E15FF7D418C9553800FE4C87 /* KeypressCommand.h */,
                                1AE00D57182DAC8D00087DD7 /* KeyedCoding.h */,
                                521D46F711AEC9B100514613 /* KillRing.h */,
                                4306E4E514955543007F17AC /* KillRingNone.cpp */,
                                85E711930AC5D5350053270F /* DOMCSSStyleDeclarationInternal.h in Headers */,
                                85032DE70AA8C9BE007D3B7D /* DOMCSSStyleRule.h in Headers */,
                                85909CE20ACC7A7E00DF01F1 /* DOMCSSStyleRuleInternal.h in Headers */,
+                               E15FF7D518C9553800FE4C87 /* KeypressCommand.h in Headers */,
                                858C39280AA8FF9D00B187A4 /* DOMCSSStyleSheet.h in Headers */,
                                85909CE30ACC7A7E00DF01F1 /* DOMCSSStyleSheetInternal.h in Headers */,
                                FCD8832A16A49F8200962227 /* DOMCSSSupportsRule.h in Headers */,
index c011b42..2ae08d8 100644 (file)
@@ -102,6 +102,9 @@ KeyboardEventInit::KeyboardEventInit()
 KeyboardEvent::KeyboardEvent()
     : m_location(DOM_KEY_LOCATION_STANDARD)
     , m_altGraphKey(false)
+#if PLATFORM(COCOA)
+    , m_handledByInputMethod(false)
+#endif
 {
 }
 
@@ -112,6 +115,10 @@ KeyboardEvent::KeyboardEvent(const PlatformKeyboardEvent& key, AbstractView* vie
     , m_keyIdentifier(key.keyIdentifier())
     , m_location(keyLocationCode(key))
     , m_altGraphKey(false)
+#if PLATFORM(COCOA)
+    , m_handledByInputMethod(key.handledByInputMethod())
+    , m_keypressCommands(key.commands())
+#endif
 {
 }
 
@@ -120,6 +127,9 @@ KeyboardEvent::KeyboardEvent(const AtomicString& eventType, const KeyboardEventI
     , m_keyIdentifier(initializer.keyIdentifier)
     , m_location(initializer.location)
     , m_altGraphKey(false)
+#if PLATFORM(COCOA)
+    , m_handledByInputMethod(false)
+#endif
 {
 }
 
index 216a634..07413b0 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef KeyboardEvent_h
 #define KeyboardEvent_h
 
+#include "KeypressCommand.h"
 #include "UIEventWithKeyState.h"
 #include <memory>
 #include <wtf/Vector.h>
@@ -33,17 +34,6 @@ namespace WebCore {
 class Node;
 class PlatformKeyboardEvent;
 
-#if PLATFORM(COCOA)
-struct KeypressCommand {
-    KeypressCommand() { }
-    explicit KeypressCommand(const String& commandName) : commandName(commandName) { ASSERT(isASCIILower(commandName[0U])); }
-    KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { ASSERT(commandName == "insertText:"); }
-
-    String commandName; // Actually, a selector name - it may have a trailing colon, and a name that can be different from an editor command name.
-    String text;
-};
-#endif
-
 struct KeyboardEventInit : public UIEventInit {
     KeyboardEventInit();
 
@@ -105,7 +95,10 @@ public:
     virtual int which() const override;
 
 #if PLATFORM(COCOA)
-    // We only have this need to store keypress command info on the Mac.
+    bool handledByInputMethod() const { return m_handledByInputMethod; }
+    const Vector<KeypressCommand>& keypressCommands() const { return m_keypressCommands; }
+
+    // The non-const version is still needed for WebKit1, which doesn't construct a complete KeyboardEvent with interpreted commands yet.
     Vector<KeypressCommand>& keypressCommands() { return m_keypressCommands; }
 #endif
 
@@ -121,6 +114,7 @@ private:
 
 #if PLATFORM(COCOA)
     // Commands that were sent by AppKit when interpreting the event. Doesn't include input method commands.
+    bool m_handledByInputMethod;
     Vector<KeypressCommand> m_keypressCommands;
 #endif
 };
diff --git a/Source/WebCore/platform/KeypressCommand.h b/Source/WebCore/platform/KeypressCommand.h
new file mode 100644 (file)
index 0000000..f5ca147
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef KeypressCommand_h
+#define KeypressCommand_h
+
+#include <wtf/Assertions.h>
+#include <wtf/text/WTFString.h>
+
+#if PLATFORM(COCOA)
+
+namespace WebCore {
+
+struct KeypressCommand {
+    KeypressCommand() { }
+    explicit KeypressCommand(const String& commandName) : commandName(commandName) { ASSERT(isASCIILower(commandName[0U])); }
+    KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { ASSERT(commandName == "insertText:"); }
+
+    String commandName; // Actually, a selector name - it may have a trailing colon, and a name that can be different from an editor command name.
+    String text;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // KeypressCommand_h
index 00bfb85..c0a58f7 100644 (file)
@@ -27,6 +27,7 @@
 #ifndef PlatformKeyboardEvent_h
 #define PlatformKeyboardEvent_h
 
+#include "KeypressCommand.h"
 #include "PlatformEvent.h"
 #include <wtf/WindowsExtras.h>
 #include <wtf/text/WTFString.h>
@@ -60,6 +61,9 @@ namespace WebCore {
             , m_windowsVirtualKeyCode(0)
             , m_nativeVirtualKeyCode(0)
             , m_macCharCode(0)
+#if USE(APPKIT)
+            , m_handledByInputMethod(false)
+#endif
             , m_autoRepeat(false)
             , m_isKeypad(false)
             , m_isSystemKey(false)
@@ -77,6 +81,9 @@ namespace WebCore {
             , m_windowsVirtualKeyCode(windowsVirtualKeyCode)
             , m_nativeVirtualKeyCode(nativeVirtualKeyCode)
             , m_macCharCode(macCharCode)
+#if USE(APPKIT)
+            , m_handledByInputMethod(false)
+#endif
             , m_autoRepeat(isAutoRepeat)
             , m_isKeypad(isKeypad)
             , m_isSystemKey(isSystemKey)
@@ -108,6 +115,11 @@ namespace WebCore {
         int nativeVirtualKeyCode() const { return m_nativeVirtualKeyCode; }
         int macCharCode() const { return m_macCharCode; }
 
+#if USE(APPKIT)
+        bool handledByInputMethod() const { return m_handledByInputMethod; }
+        const Vector<KeypressCommand>& commands() const { return m_commands; }
+#endif
+
         bool isAutoRepeat() const { return m_autoRepeat; }
         bool isKeypad() const { return m_isKeypad; }
         bool isSystemKey() const { return m_isSystemKey; }
@@ -150,6 +162,10 @@ namespace WebCore {
         int m_windowsVirtualKeyCode;
         int m_nativeVirtualKeyCode;
         int m_macCharCode;
+#if USE(APPKIT)
+        bool m_handledByInputMethod;
+        Vector<KeypressCommand> m_commands;
+#endif
         bool m_autoRepeat;
         bool m_isKeypad;
         bool m_isSystemKey;
index 1d000dd..ecbd20b 100644 (file)
@@ -1,3 +1,14 @@
+2014-03-06  Alexey Proskuryakov  <ap@apple.com>
+
+        [Mac] Don't perform a round-trip through WebProcess before interpreting key events
+        https://bugs.webkit.org/show_bug.cgi?id=129812
+
+        Reviewed by Darin Adler.
+
+        * WebCoreSupport/WebEditorClient.mm: (WebEditorClient::handleInputMethodKeydown):
+        Added a FIXME. WebKit1/mac is the only port that uses this roundabout way to
+        interpret events, so it would simplify code if we switched it to WebKit2/mac model.
+
 2014-03-08  Simon Fraser  <simon.fraser@apple.com>
 
         [iOS Wk2] Can't scroll after going back to page in page cache
index 8a07c84..afd4220 100644 (file)
@@ -693,6 +693,7 @@ void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event)
 {
 #if !PLATFORM(IOS)
+    // FIXME: Switch to WebKit2 model, interpreting the event before it's sent down to WebCore.
     Frame* frame = event->target()->toNode()->document().frame();
     WebHTMLView *webHTMLView = [[kit(frame) frameView] documentView];
     if ([webHTMLView _interpretKeyEvent:event savingCommands:YES])
index 16282ca..d326cdb 100644 (file)
@@ -1,3 +1,85 @@
+2014-03-06  Alexey Proskuryakov  <ap@apple.com>
+
+        [Mac] Don't perform a round-trip through WebProcess before interpreting key events
+        https://bugs.webkit.org/show_bug.cgi?id=129812
+
+        Reviewed by Darin Adler.
+
+        * Shared/NativeWebKeyboardEvent.h:
+        * Shared/WebEvent.h:
+        (WebKit::WebKeyboardEvent::handledByInputMethod):
+        (WebKit::WebKeyboardEvent::commands):
+        * Shared/WebEventConversion.cpp:
+        (WebKit::WebKit2PlatformKeyboardEvent::WebKit2PlatformKeyboardEvent):
+        * Shared/WebKeyboardEvent.cpp:
+        (WebKit::WebKeyboardEvent::WebKeyboardEvent):
+        (WebKit::WebKeyboardEvent::~WebKeyboardEvent):
+        (WebKit::WebKeyboardEvent::encode):
+        (WebKit::WebKeyboardEvent::decode):
+        * Shared/mac/NativeWebKeyboardEventMac.mm:
+        (WebKit::NativeWebKeyboardEvent::NativeWebKeyboardEvent):
+        * Shared/mac/WebEventFactory.h:
+        * Shared/mac/WebEventFactory.mm:
+        (WebKit::WebEventFactory::createWebKeyboardEvent):
+        Keyboard events now carry results of interpretation with them.
+        Ideally, mouse events should also have a handledByInputMethod member, because IMs
+        can handle events, but that can wait until we have actual bugs caused by not diabling
+        default processing for these.
+
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView becomeFirstResponder]): Updated for new NativeWebKeyboardEvent contructor
+        signature. We don't interpret the event in this code path.
+        (-[WKView doCommandBySelector:]): Added logging.
+        (-[WKView performKeyEquivalent:]): Reimplemented Esc and Cmd+period handling to avoid
+        infinite loops and re-entrancy. These two work in a unique way in AppKit.
+        Interpret key event before sending it down to WebProcess.
+        (-[WKView keyUp:]): Interpret key event before sending it down to WebProcess.
+        We need to tell IMs about the event, but key binding processing is moot, all commands
+        are executed on keydown.
+        (-[WKView keyDown:]): Interpret the event.
+        (-[WKView flagsChanged:]): Ditto.
+        (-[WKView _interpretKeyEvent:savingCommandsTo:WebCore::]): Added an assertion in
+        consumedByIM code path.
+        (-[WKView _executeSavedCommandBySelector:]): Added logging.
+
+        * UIProcess/PageClient.h:
+        * UIProcess/ios/PageClientImplIOS.h:
+        * UIProcess/ios/PageClientImplIOS.mm:
+        * UIProcess/mac/PageClientImpl.h:
+        * UIProcess/mac/PageClientImpl.mm:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        * UIProcess/mac/WebPageProxyMac.mm:
+        Removed interpretQueuedKeyEvent/interpretKeyEvent, WebProcess no longer asks UIProcess to do this.
+
+        * WebProcess/WebCoreSupport/ios/WebEditorClientIOS.mm:
+        (WebKit::WebEditorClient::handleKeyboardEvent):
+        * WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm:
+        (WebKit::WebEditorClient::handleKeyboardEvent):
+        (WebKit::WebEditorClient::handleInputMethodKeydown):
+        WebPage::handleEditingKeyboardEvent is now one function instead of two with a boolean
+        switch between two behaviors.
+
+        * WebProcess/WebPage/WebPage.cpp:(WebKit::WebPage::WebPage):
+        * WebProcess/WebPage/WebPage.h:
+        Removed m_keyboardEventBeingInterpreted, as we no longer send the event for interpretation.
+        This means that we sometimes have to pass a null event down to WebCore, but I wasn't
+        able to find any behavior differences from us doing so.
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm: (WebKit::WebPage::handleEditingKeyboardEvent):
+        Added a FIXME.
+
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::WebPage::executeKeypressCommandsInternal): When we don't have an event,
+        use current frame as a target, just like input method messages do.
+        (WebKit::WebPage::handleEditingKeyboardEvent): This function no longer saves commands,
+        it only interprets them.
+        Added a check for Esc, as we don't want to handle it in keydown event handler.
+        (WebKit::WebPage::insertText): Pass 0 instead of m_keyboardEventBeingInterpreted.
+        (WebKit::WebPage::insertDictatedText): Ditto.
+        (WebKit::WebPage::executeKeypressCommands): Ditto.
+
 2014-03-09  Zalan Bujtas  <zalan@apple.com>
 
         Subpixel rendering: Pass FloatSize boxsize to transform animations to support device pixel sizing.
index 47c1dfd..2773170 100644 (file)
 #if USE(APPKIT)
 #include <wtf/RetainPtr.h>
 OBJC_CLASS NSView;
+
+namespace WebCore {
+struct KeypressCommand;
+}
 #endif
 
 #if PLATFORM(EFL)
@@ -56,7 +60,7 @@ namespace WebKit {
 class NativeWebKeyboardEvent : public WebKeyboardEvent {
 public:
 #if USE(APPKIT)
-    NativeWebKeyboardEvent(NSEvent *, NSView *);
+    NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>&);
 #elif PLATFORM(GTK)
     NativeWebKeyboardEvent(const NativeWebKeyboardEvent&);
     NativeWebKeyboardEvent(GdkEvent*, const WebCore::CompositionResults&, WebCore::GtkInputMethodFilter::EventFakedForComposition);
index b7a198e..48b6376 100644 (file)
@@ -41,6 +41,12 @@ namespace IPC {
     class ArgumentEncoder;
 }
 
+#if USE(APPKIT)
+namespace WebCore {
+struct KeypressCommand;
+}
+#endif
+
 namespace WebKit {
 
 class WebEvent {
@@ -207,9 +213,14 @@ private:
 // FIXME: Move this class to its own header file.
 class WebKeyboardEvent : public WebEvent {
 public:
-    WebKeyboardEvent() { }
+    WebKeyboardEvent();
+    ~WebKeyboardEvent();
 
+#if USE(APPKIT)
+    WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>&, bool isAutoRepeat, bool isKeypad, bool isSystemKey, Modifiers, double timestamp);
+#else
     WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, Modifiers, double timestamp);
+#endif
 
     const String& text() const { return m_text; }
     const String& unmodifiedText() const { return m_unmodifiedText; }
@@ -217,6 +228,10 @@ public:
     int32_t windowsVirtualKeyCode() const { return m_windowsVirtualKeyCode; }
     int32_t nativeVirtualKeyCode() const { return m_nativeVirtualKeyCode; }
     int32_t macCharCode() const { return m_macCharCode; }
+#if USE(APPKIT)
+    bool handledByInputMethod() const { return m_handledByInputMethod; }
+    const Vector<WebCore::KeypressCommand>& commands() const { return m_commands; }
+#endif
     bool isAutoRepeat() const { return m_isAutoRepeat; }
     bool isKeypad() const { return m_isKeypad; }
     bool isSystemKey() const { return m_isSystemKey; }
@@ -233,6 +248,10 @@ private:
     int32_t m_windowsVirtualKeyCode;
     int32_t m_nativeVirtualKeyCode;
     int32_t m_macCharCode;
+#if USE(APPKIT)
+    bool m_handledByInputMethod;
+    Vector<WebCore::KeypressCommand> m_commands;
+#endif
     bool m_isAutoRepeat;
     bool m_isKeypad;
     bool m_isSystemKey;
index 9e05656..275e270 100644 (file)
@@ -185,6 +185,10 @@ public:
         m_windowsVirtualKeyCode = webEvent.windowsVirtualKeyCode();
         m_nativeVirtualKeyCode = webEvent.nativeVirtualKeyCode();
         m_macCharCode = webEvent.macCharCode();
+#if USE(APPKIT)
+        m_handledByInputMethod = webEvent.handledByInputMethod();
+        m_commands = webEvent.commands();
+#endif
         m_autoRepeat = webEvent.isAutoRepeat();
         m_isKeypad = webEvent.isKeypad();
         m_isSystemKey = webEvent.isSystemKey();
index 8aef309..0ac67e3 100644 (file)
 #include "WebEvent.h"
 
 #include "WebCoreArgumentCoders.h"
+#include <WebCore/KeypressCommand.h>
 
 namespace WebKit {
 
+WebKeyboardEvent::WebKeyboardEvent()
+{
+}
+
+#if USE(APPKIT)
+
+WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands, bool isAutoRepeat, bool isKeypad, bool isSystemKey, Modifiers modifiers, double timestamp)
+    : WebEvent(type, modifiers, timestamp)
+    , m_text(text)
+    , m_unmodifiedText(unmodifiedText)
+    , m_keyIdentifier(keyIdentifier)
+    , m_windowsVirtualKeyCode(windowsVirtualKeyCode)
+    , m_nativeVirtualKeyCode(nativeVirtualKeyCode)
+    , m_macCharCode(macCharCode)
+    , m_handledByInputMethod(handledByInputMethod)
+    , m_commands(commands)
+    , m_isAutoRepeat(isAutoRepeat)
+    , m_isKeypad(isKeypad)
+    , m_isSystemKey(isSystemKey)
+{
+    ASSERT(isKeyboardEventType(type));
+}
+
+#else
+
 WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, Modifiers modifiers, double timestamp)
     : WebEvent(type, modifiers, timestamp)
     , m_text(text)
@@ -45,6 +71,12 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String&
     ASSERT(isKeyboardEventType(type));
 }
 
+#endif
+
+WebKeyboardEvent::~WebKeyboardEvent()
+{
+}
+
 void WebKeyboardEvent::encode(IPC::ArgumentEncoder& encoder) const
 {
     WebEvent::encode(encoder);
@@ -55,6 +87,10 @@ void WebKeyboardEvent::encode(IPC::ArgumentEncoder& encoder) const
     encoder << m_windowsVirtualKeyCode;
     encoder << m_nativeVirtualKeyCode;
     encoder << m_macCharCode;
+#if USE(APPKIT)
+    encoder << m_handledByInputMethod;
+    encoder << m_commands;
+#endif
     encoder << m_isAutoRepeat;
     encoder << m_isKeypad;
     encoder << m_isSystemKey;
@@ -77,6 +113,12 @@ bool WebKeyboardEvent::decode(IPC::ArgumentDecoder& decoder, WebKeyboardEvent& r
         return false;
     if (!decoder.decode(result.m_macCharCode))
         return false;
+#if USE(APPKIT)
+    if (!decoder.decode(result.m_handledByInputMethod))
+        return false;
+    if (!decoder.decode(result.m_commands))
+        return false;
+#endif
     if (!decoder.decode(result.m_isAutoRepeat))
         return false;
     if (!decoder.decode(result.m_isKeypad))
index 2702654..afb3b60 100644 (file)
 #if USE(APPKIT)
 
 #import "WebEventFactory.h"
+#import <WebCore/KeyboardEvent.h>
+
+using namespace WebCore;
 
 namespace WebKit {
 
-NativeWebKeyboardEvent::NativeWebKeyboardEvent(NSEvent *event, NSView *view)
-    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event, view))
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, const Vector<KeypressCommand>& commands)
+    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event, handledByInputMethod, commands))
     , m_nativeEvent(event)
 {
 }
index 4e79102..df16fc6 100644 (file)
@@ -36,9 +36,9 @@ namespace WebKit {
 class WebEventFactory {
 public:
 #if USE(APPKIT)
-    static WebMouseEvent createWebMouseEvent(NSEvent *event, NSView *windowView);
-    static WebWheelEvent createWebWheelEvent(NSEvent *event, NSView *windowView);
-    static WebKeyboardEvent createWebKeyboardEvent(NSEvent *event, NSView *windowView);
+    static WebMouseEvent createWebMouseEvent(NSEvent *, NSView *windowView);
+    static WebWheelEvent createWebWheelEvent(NSEvent *, NSView *windowView);
+    static WebKeyboardEvent createWebKeyboardEvent(NSEvent *, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>&);
 #endif // USE(APPKIT)
 };
 
index fcf6b18..f70db1c 100644 (file)
@@ -29,6 +29,7 @@
 #if USE(APPKIT)
 
 #import "WebKitSystemInterface.h"
+#import <WebCore/KeyboardEvent.h>
 #import <WebCore/PlatformEventFactoryMac.h>
 #import <WebCore/Scrollbar.h>
 #import <WebCore/WindowsKeyboardCodes.h>
@@ -405,7 +406,7 @@ WebWheelEvent WebEventFactory::createWebWheelEvent(NSEvent *event, NSView *windo
     return WebWheelEvent(WebEvent::Wheel, IntPoint(position), IntPoint(globalPosition), FloatSize(deltaX, deltaY), FloatSize(wheelTicksX, wheelTicksY), granularity, directionInvertedFromDevice, phase, momentumPhase, hasPreciseScrollingDeltas, scrollCount, unacceleratedScrollingDelta, modifiers, timestamp);
 }
 
-WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, NSView *)
+WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands)
 {
     WebEvent::Type type             = isKeyUpEvent(event) ? WebEvent::KeyUp : WebEvent::KeyDown;
     String text                     = textFromEvent(event);
@@ -438,7 +439,7 @@ WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, NSView
         unmodifiedText = "\x9";
     }
 
-    return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, autoRepeat, isKeypad, isSystemKey, modifiers, timestamp);
+    return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, handledByInputMethod, commands, autoRepeat, isKeypad, isSystemKey, modifiers, timestamp);
 }
 
 } // namespace WebKit
index 51c838c..87c67f5 100644 (file)
@@ -345,7 +345,7 @@ struct WKViewInterpretKeyEventsParameters {
         NSEvent *keyboardEvent = nil;
         if ([event type] == NSKeyDown || [event type] == NSKeyUp)
             keyboardEvent = event;
-        _data->_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, self));
+        _data->_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, Vector<KeypressCommand>()));
     }
     return YES;
 }
@@ -1225,6 +1225,7 @@ NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp)
     if (parameters && !isFromInputMethod) {
         KeypressCommand command(NSStringFromSelector(selector));
         parameters->commands->append(command);
+        LOG(TextInput, "...stored");
         _data->_page->registerKeypressCommandName(command.commandName);
     } else {
         // FIXME: Send the command to Editor synchronously and only send it along the
@@ -1301,18 +1302,29 @@ NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp)
     // fetching a new event might release the old one. Retaining and then autoreleasing
     // the current event prevents that from causing a problem inside WebKit or AppKit code.
     [[event retain] autorelease];
-    
+
+    // We get Esc key here after processing either Esc or Cmd+period. The former starts as a keyDown, and the latter starts as a key equivalent,
+    // but both get transformed to a cancelOperation: command, executing which passes an Esc key event to -performKeyEquivalent:.
+    // Don't interpret this event again, avoiding re-entrancy and infinite loops.
+    if ([[event charactersIgnoringModifiers] isEqualToString:@"\e"] && !([event modifierFlags] & NSDeviceIndependentModifierFlagsMask))
+        return [super performKeyEquivalent:event];
+
+    // If we are already re-sending the event, then WebCore has already seen it, no need for custom processing.
     BOOL eventWasSentToWebCore = (_data->_keyDownEventBeingResent == event);
+    if (eventWasSentToWebCore)
+        return [super performKeyEquivalent:event];
 
-    if (!eventWasSentToWebCore)
-        [self _disableComplexTextInputIfNecessary];
+    ASSERT(event == [NSApp currentEvent]);
+
+    [self _disableComplexTextInputIfNecessary];
 
     // Pass key combos through WebCore if there is a key binding available for
     // this event. This lets web pages have a crack at intercepting key-modified keypresses.
-    // But don't do it if we have already handled the event.
-    // Pressing Esc results in a fake event being sent - don't pass it to WebCore.
-    if (!eventWasSentToWebCore && event == [NSApp currentEvent] && self == [[self window] firstResponder]) {
-        _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, self));
+    // FIXME: Why is the firstResponder check needed?
+    if (self == [[self window] firstResponder]) {
+        Vector<KeypressCommand> commands;
+        BOOL handledByInputMethod = [self _interpretKeyEvent:event savingCommandsTo:commands];
+        _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
         return YES;
     }
     
@@ -1322,7 +1334,11 @@ NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp)
 - (void)keyUp:(NSEvent *)theEvent
 {
     LOG(TextInput, "keyUp:%p %@", theEvent, theEvent);
-    _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self));
+
+    Vector<KeypressCommand> commands;
+    BOOL handledByInputMethod = [self _interpretKeyEvent:theEvent savingCommandsTo:commands];
+
+    _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
 }
 
 - (void)_disableComplexTextInputIfNecessary
@@ -1396,7 +1412,17 @@ NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp)
         [super keyDown:theEvent];
         return;
     }
-    _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self));
+
+    Vector<KeypressCommand> commands;
+    BOOL handledByInputMethod = [self _interpretKeyEvent:theEvent savingCommandsTo:commands];
+    if (!commands.isEmpty()) {
+        // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline.
+        // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that
+        // should be handled like normal text input after DOM event dispatch.
+        handledByInputMethod = NO;
+    }
+
+    _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
 }
 
 - (void)flagsChanged:(NSEvent *)theEvent
@@ -1414,7 +1440,10 @@ NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp)
     if (!keyCode || keyCode == 10 || keyCode == 63)
         return;
 
-    _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self));
+    Vector<KeypressCommand> commands;
+    BOOL handledByInputMethod = [self _interpretKeyEvent:theEvent savingCommandsTo:commands];
+
+    _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
 }
 
 - (void)_executeSavedKeypressCommands
@@ -2310,11 +2339,12 @@ static void createSandboxExtensionsForFileUpload(NSPasteboard *pasteboard, Sandb
     LOG(TextInput, "-> interpretKeyEvents:%p %@", event, event);
     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
 
-    _data->_interpretKeyEventsParameters = 0;
+    _data->_interpretKeyEventsParameters = nullptr;
 
     // An input method may consume an event and not tell us (e.g. when displaying a candidate window),
     // in which case we should not bubble the event up the DOM.
     if (parameters.consumedByIM) {
+        ASSERT(commands.isEmpty());
         LOG(TextInput, "...event %p was consumed by an input method", event);
         return YES;
     }
@@ -2823,6 +2853,7 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
 
 - (bool)_executeSavedCommandBySelector:(SEL)selector
 {
+    LOG(TextInput, "Executing previously saved command %s", sel_getName(selector));
     // The sink does two things: 1) Tells us if the responder went unhandled, and
     // 2) prevents any NSBeep; we don't ever want to beep here.
     RetainPtr<WKResponderChainSink> sink = adoptNS([[WKResponderChainSink alloc] initWithResponderChain:self]);
index 89fc407..9ffbc31 100644 (file)
@@ -168,7 +168,6 @@ public:
     virtual void executeUndoRedo(WebPageProxy::UndoOrRedo) = 0;
 #if PLATFORM(COCOA)
     virtual void accessibilityWebProcessTokenReceived(const IPC::DataReference&) = 0;
-    virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&, Vector<WebCore::KeypressCommand>&) = 0;
     virtual bool executeSavedCommandBySelector(const String& selector) = 0;
     virtual void setDragImage(const WebCore::IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag) = 0;
     virtual void updateSecureInputState() = 0;
index 9516450..cf7952b 100644 (file)
@@ -1070,7 +1070,6 @@ private:
 
     // Keyboard handling
 #if PLATFORM(COCOA)
-    void interpretQueuedKeyEvent(const EditorState&, bool& handled, Vector<WebCore::KeypressCommand>&);
     void executeSavedCommandBySelector(const String& selector, bool& handled);
 #endif
 
index 8d34b91..ee859e8 100644 (file)
@@ -261,7 +261,6 @@ messages -> WebPageProxy {
     DidPerformDictionaryLookup(WebKit::AttributedString text, WebKit::DictionaryPopupInfo dictionaryPopupInfo)
 
     # Keyboard input support messages
-    InterpretQueuedKeyEvent(WebKit::EditorState state) -> (bool handled, Vector<WebCore::KeypressCommand> savedCommands)
     ExecuteSavedCommandBySelector(String selector) -> (bool handled)
 
     # Remote accessibility messages
index 56de354..28998aa 100644 (file)
@@ -73,7 +73,6 @@ private:
     virtual bool canUndoRedo(WebPageProxy::UndoOrRedo) override;
     virtual void executeUndoRedo(WebPageProxy::UndoOrRedo) override;
     virtual void accessibilityWebProcessTokenReceived(const IPC::DataReference&) override;
-    virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&, Vector<WebCore::KeypressCommand>&) override;
     virtual bool executeSavedCommandBySelector(const String& selector) override;
     virtual void setDragImage(const WebCore::IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag) override;
     virtual void updateSecureInputState() override;
index 931ab8c..3b5cd22 100644 (file)
@@ -196,12 +196,6 @@ void PageClientImpl::accessibilityWebProcessTokenReceived(const IPC::DataReferen
     [m_contentView _setAccessibilityWebProcessToken:remoteToken];
 }
 
-bool PageClientImpl::interpretKeyEvent(const NativeWebKeyboardEvent&, Vector<KeypressCommand>&)
-{
-    notImplemented();
-    return false;
-}
-
 bool PageClientImpl::interpretKeyEvent(const NativeWebKeyboardEvent& event, bool isCharEvent)
 {
     return [m_contentView _interpretKeyEvent:event.nativeEvent() isCharEvent:isCharEvent];
index 83c4070..d0259fe 100644 (file)
@@ -410,11 +410,6 @@ void WebPageProxy::extendSelection(WebCore::TextGranularity granularity)
     m_process->send(Messages::WebPage::ExtendSelection(static_cast<uint32_t>(granularity)), m_pageID);
 }
 
-void WebPageProxy::interpretQueuedKeyEvent(const EditorState&, bool&, Vector<WebCore::KeypressCommand>&)
-{
-    notImplemented();
-}
-
 void WebPageProxy::interpretKeyEvent(const EditorState& state, bool isCharEvent, bool& handled)
 {
     m_editorState = state;
index aab1810..b043846 100644 (file)
@@ -89,7 +89,6 @@ private:
     virtual void clearAllEditCommands();
     virtual bool canUndoRedo(WebPageProxy::UndoOrRedo);
     virtual void executeUndoRedo(WebPageProxy::UndoOrRedo);
-    virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&, Vector<WebCore::KeypressCommand>&);
     virtual bool executeSavedCommandBySelector(const String& selector);
     virtual void setDragImage(const WebCore::IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag);
     virtual void setPromisedData(const String& pasteboardName, PassRefPtr<WebCore::SharedBuffer> imageBuffer, const String& filename, const String& extension, const String& title,
index 8662c79..b3ef040 100644 (file)
@@ -336,11 +336,6 @@ void PageClientImpl::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
     return (undoOrRedo == WebPageProxy::Undo) ? [[m_wkView undoManager] undo] : [[m_wkView undoManager] redo];
 }
 
-bool PageClientImpl::interpretKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commands)
-{
-    return [m_wkView _interpretKeyEvent:event.nativeEvent() savingCommandsTo:commands];
-}
-
 void PageClientImpl::setDragImage(const IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag)
 {
     RetainPtr<CGImageRef> dragCGImage = dragImage->makeCGImage();
index 1a99531..080255c 100644 (file)
@@ -348,12 +348,6 @@ void WebPageProxy::performDictionaryLookupAtLocation(const WebCore::FloatPoint&
     process().send(Messages::WebPage::PerformDictionaryLookupAtLocation(point), m_pageID);
 }
 
-void WebPageProxy::interpretQueuedKeyEvent(const EditorState& state, bool& handled, Vector<WebCore::KeypressCommand>& commands)
-{
-    m_editorState = state;
-    handled = m_pageClient.interpretKeyEvent(m_keyEventQueue.first(), commands);
-}
-
 // Complex text input support for plug-ins.
 void WebPageProxy::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
 {
index d497f55..5a82f69 100644 (file)
@@ -38,7 +38,7 @@ namespace WebKit {
     
 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
 {
-    if (m_page->handleEditingKeyboardEvent(event, false))
+    if (m_page->handleEditingKeyboardEvent(event))
         event->setDefaultHandled();
 }
 
index ef4a574..4ba4396 100644 (file)
@@ -62,13 +62,13 @@ namespace WebKit {
     
 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
 {
-    if (m_page->handleEditingKeyboardEvent(event, false))
+    if (m_page->handleEditingKeyboardEvent(event))
         event->setDefaultHandled();
 }
 
 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event)
 {
-    if (m_page->handleEditingKeyboardEvent(event, true))
+    if (event->handledByInputMethod())
         event->setDefaultHandled();
 }
     
index eb0830d..a0f30b7 100644 (file)
@@ -253,7 +253,6 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
 #if PLATFORM(COCOA)
     , m_pdfPluginEnabled(false)
     , m_hasCachedWindowFrame(false)
-    , m_keyboardEventBeingInterpreted(0)
     , m_viewGestureGeometryCollector(*this)
 #elif PLATFORM(GTK) && HAVE(ACCESSIBILITY)
     , m_accessibilityObject(0)
index 74cf89a..9244e5a 100644 (file)
@@ -237,11 +237,7 @@ public:
     void layoutIfNeeded();
 
     // -- Called from WebCore clients.
-#if PLATFORM(COCOA)
-    bool handleEditingKeyboardEvent(WebCore::KeyboardEvent*, bool saveCommands);
-#elif !PLATFORM(GTK)
     bool handleEditingKeyboardEvent(WebCore::KeyboardEvent*);
-#endif
 
     void didStartPageTransition();
     void didCompletePageTransition();
@@ -1000,8 +996,6 @@ private:
     
     RetainPtr<WKAccessibilityWebPageObject> m_mockAccessibilityElement;
 
-    WebCore::KeyboardEvent* m_keyboardEventBeingInterpreted;
-
     ViewGestureGeometryCollector m_viewGestureGeometryCollector;
 
 #elif HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL))
index fbf57c5..9dbc751 100644 (file)
@@ -142,8 +142,9 @@ bool WebPage::allowsUserScaling() const
     return m_viewportConfiguration.allowsUserScaling();
 }
 
-bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event, bool)
+bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event)
 {
+    // FIXME: Interpret the event immediately upon receiving it in UI process, without sending to WebProcess first.
     bool eventWasHandled = false;
     bool sendResult = WebProcess::shared().parentProcessConnection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(editorState(), event->keyEvent()->type() == PlatformKeyboardEvent::Char),
                                                                                Messages::WebPageProxy::InterpretKeyEvent::Reply(eventWasHandled), m_pageID);
@@ -206,7 +207,7 @@ void WebPage::insertText(const String& text, uint64_t replacementRangeStart, uin
     if (!frame.editor().hasComposition()) {
         // An insertText: might be handled by other responders in the chain if we don't handle it.
         // One example is space bar that results in scrolling down the page.
-        frame.editor().insertText(text, 0);
+        frame.editor().insertText(text, nullptr);
     } else
         frame.editor().confirmComposition(text);
 }
index 773fe77..35024e8 100644 (file)
@@ -166,22 +166,25 @@ static Frame* frameForEvent(KeyboardEvent* event)
 
 bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>& commands, KeyboardEvent* event)
 {
-    Frame* frame = frameForEvent(event);
-    ASSERT(frame->page() == corePage());
+    Frame& frame = event ? *frameForEvent(event) : m_page->focusController().focusedOrMainFrame();
+    ASSERT(frame.page() == corePage());
 
     bool eventWasHandled = false;
     for (size_t i = 0; i < commands.size(); ++i) {
         if (commands[i].commandName == "insertText:") {
-            ASSERT(!frame->editor().hasComposition());
-
-            if (!frame->editor().canEdit())
-                continue;
+            if (frame.editor().hasComposition()) {
+                eventWasHandled = true;
+                frame.editor().confirmComposition(commands[i].text);
+            } else {
+                if (!frame.editor().canEdit())
+                    continue;
 
-            // An insertText: might be handled by other responders in the chain if we don't handle it.
-            // One example is space bar that results in scrolling down the page.
-            eventWasHandled |= frame->editor().insertText(commands[i].text, event);
+                // An insertText: might be handled by other responders in the chain if we don't handle it.
+                // One example is space bar that results in scrolling down the page.
+                eventWasHandled |= frame.editor().insertText(commands[i].text, event);
+            }
         } else {
-            Editor::Command command = frame->editor().command(commandNameForSelectorName(commands[i].commandName));
+            Editor::Command command = frame.editor().command(commandNameForSelectorName(commands[i].commandName));
             if (command.isSupported()) {
                 bool commandExecutedByEditor = command.execute(event);
                 eventWasHandled |= commandExecutedByEditor;
@@ -200,53 +203,39 @@ bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressComm
     return eventWasHandled;
 }
 
-bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event, bool saveCommands)
+bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event)
 {
-    ASSERT(!saveCommands || event->keypressCommands().isEmpty()); // Save commands once for each event.
-
     Frame* frame = frameForEvent(event);
     
     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
     if (!platformEvent)
         return false;
-    Vector<KeypressCommand>& commands = event->keypressCommands();
+    const Vector<KeypressCommand>& commands = event->keypressCommands();
+
+    ASSERT(!platformEvent->macEvent()); // Cannot have a native event in WebProcess.
 
-    if ([platformEvent->macEvent() type] == NSFlagsChanged)
+    // Don't handle Esc while handling keydown event, we need to dispatch a keypress first.
+    if (platformEvent->type() != PlatformEvent::Char && platformEvent->windowsVirtualKeyCode() == VK_ESCAPE && commands.size() == 1 && commandNameForSelectorName(commands[0].commandName) == "cancelOperation")
         return false;
 
     bool eventWasHandled = false;
-    
-    if (saveCommands) {
-        KeyboardEvent* oldEvent = m_keyboardEventBeingInterpreted;
-        m_keyboardEventBeingInterpreted = event;
-        bool sendResult = WebProcess::shared().parentProcessConnection()->sendSync(Messages::WebPageProxy::InterpretQueuedKeyEvent(editorState()), 
-            Messages::WebPageProxy::InterpretQueuedKeyEvent::Reply(eventWasHandled, commands), m_pageID);
-        m_keyboardEventBeingInterpreted = oldEvent;
-        if (!sendResult)
-            return false;
-
-        // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline.
-        // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that
-        // should be handled like normal text input after DOM event dispatch.
-        if (!event->keypressCommands().isEmpty())
-            return false;
-    } else {
-        // Are there commands that could just cause text insertion if executed via Editor?
-        // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
-        // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
-        // (e.g. Tab that inserts a Tab character, or Enter).
-        bool haveTextInsertionCommands = false;
-        for (size_t i = 0; i < commands.size(); ++i) {
-            if (frame->editor().command(commandNameForSelectorName(commands[i].commandName)).isTextInsertion())
-                haveTextInsertionCommands = true;
-        }
-        // If there are no text insertion commands, default keydown handler is the right time to execute the commands.
-        // Keypress (Char event) handler is the latest opportunity to execute.
-        if (!haveTextInsertionCommands || platformEvent->type() == PlatformEvent::Char) {
-            eventWasHandled = executeKeypressCommandsInternal(event->keypressCommands(), event);
-            event->keypressCommands().clear();
-        }
+
+    // Are there commands that could just cause text insertion if executed via Editor?
+    // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
+    // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
+    // (e.g. Tab that inserts a Tab character, or Enter).
+    bool haveTextInsertionCommands = false;
+    for (auto& command : commands) {
+        if (frame->editor().command(commandNameForSelectorName(command.commandName)).isTextInsertion())
+            haveTextInsertionCommands = true;
+    }
+    // If there are no text insertion commands, default keydown handler is the right time to execute the commands.
+    // Keypress (Char event) handler is the latest opportunity to execute.
+    if (!haveTextInsertionCommands || platformEvent->type() == PlatformEvent::Char) {
+        eventWasHandled = executeKeypressCommandsInternal(event->keypressCommands(), event);
+        event->keypressCommands().clear();
     }
+
     return eventWasHandled;
 }
 
@@ -302,7 +291,7 @@ void WebPage::insertText(const String& text, uint64_t replacementRangeStart, uin
     if (!frame.editor().hasComposition()) {
         // An insertText: might be handled by other responders in the chain if we don't handle it.
         // One example is space bar that results in scrolling down the page.
-        handled = frame.editor().insertText(text, m_keyboardEventBeingInterpreted);
+        handled = frame.editor().insertText(text, nullptr);
     } else {
         handled = true;
         frame.editor().confirmComposition(text);
@@ -322,7 +311,7 @@ void WebPage::insertDictatedText(const String& text, uint64_t replacementRangeSt
     }
 
     ASSERT(!frame.editor().hasComposition());
-    handled = frame.editor().insertDictatedText(text, dictationAlternativeLocations, m_keyboardEventBeingInterpreted);
+    handled = frame.editor().insertDictatedText(text, dictationAlternativeLocations, nullptr);
     newState = editorState();
 }
 
@@ -436,7 +425,7 @@ void WebPage::firstRectForCharacterRange(uint64_t location, uint64_t length, Web
 
 void WebPage::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands, bool& handled, EditorState& newState)
 {
-    handled = executeKeypressCommandsInternal(commands, m_keyboardEventBeingInterpreted);
+    handled = executeKeypressCommandsInternal(commands, nullptr);
     newState = editorState();
 }