Title: [206033] trunk
Revision
206033
Author
wenson_hs...@apple.com
Date
2016-09-16 11:14:04 -0700 (Fri, 16 Sep 2016)

Log Message

Inserting a space after inserting an accepted candidate scrolls the document and causes a flicker
https://bugs.webkit.org/show_bug.cgi?id=162009
<rdar://problem/28086237>

Reviewed by Tim Horton.

Source/WebKit2:

After inserting a text candidate, if the candidate ended with a soft space, the next space we insert should just
replace the soft space. This currently works because we leave the text insertion out of the list of
KeypressCommands sent to the web process and instead replace the soft space via WebPage::InsertTextAsync.
However, this means when the web process handles this keydown event, the current editor will not handle it,
since the list of key commands is empty despite the text and unmodified text being non-empty.

To fix this, when sending keydown or keyup events where we replace a soft space, we set the key event's text to
an empty string instead of a space. This allows us to return early in EventHandler::keyEvent and avoid the
codepath that tries to insert text into the current editor and (in the case of inserting a ' ') scrolls the
document if necessary. Since we've already handled text insertion via WebPage::InsertTextAsync, there is no need
to also dispatch the keypress to the editor.

Additionally, this patch addresses flickering in the candidates UI due to the fact that we're asynchronously
replacing the last soft space. During this operation, we select the range of the soft space and then insert the
new text. This causes a momentary range selection which the web process notifies the UI process about, prompting
us to hide the candidates list. To address this, we suppress the EditorStateChanged message fired from the web
process to the UI process while we're selecting the original range to replace.

This patch adds 3 new WebKit API tests.

* Shared/NativeWebKeyboardEvent.h:
* Shared/mac/NativeWebKeyboardEventMac.mm:
(WebKit::NativeWebKeyboardEvent::NativeWebKeyboardEvent):
* Shared/mac/WebEventFactory.h:
* Shared/mac/WebEventFactory.mm:
(WebKit::textFromEvent):
(WebKit::unmodifiedTextFromEvent):
(WebKit::WebEventFactory::createWebKeyboardEvent):
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _handleAcceptedCandidate:]):
(-[WKWebView _didHandleAcceptedCandidate]):
(-[WKWebView _didUpdateCandidateListVisibility:]):
(-[WKWebView _forceRequestCandidates]):
(-[WKWebView _handleControlledElementIDResponse:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/API/mac/WKView.mm:
(-[WKView _didHandleAcceptedCandidate]):
(-[WKView _didUpdateCandidateListVisibility:]):
* UIProcess/Cocoa/WebViewImpl.h:
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::forceRequestCandidatesForTesting):
(WebKit::WebViewImpl::becomeFirstResponder):
(WebKit::WebViewImpl::didHandleAcceptedCandidate):
(WebKit::WebViewImpl::insertText):
(WebKit::WebViewImpl::performKeyEquivalent):
(WebKit::WebViewImpl::keyUp):
(WebKit::WebViewImpl::keyDown):
(WebKit::WebViewImpl::flagsChanged):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::insertTextAsync):
* UIProcess/WebPageProxy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::insertTextAsync):
(WebKit::WebPage::didChangeSelection):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

Adds 3 new text editing API tests covering candidate insertion, as well as support for testing candidates in
WKWebViews. Refactors common WKWebView helpers across both VideoControlsManager tests and the new
WKWebViewCandidateTests into a new utility class, TestWKWebView in TestWKWebView.mm, which is capable of
simulating mouse and keyboard events as well as waiting for _javascript_ messages sent from the web process and
performing actions in response.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit/ios/audio-only.html:
* TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html:
* TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm:
(TestWebKitAPI::TEST):
(-[MessageHandler initWithMessage:handler:]): Deleted.
(-[MessageHandler userContentController:didReceiveScriptMessage:]): Deleted.
(-[VideoControlsManagerTestWebView mouseDownAtPoint:]): Deleted.
(-[VideoControlsManagerTestWebView performAfterLoading:]): Deleted.
(-[VideoControlsManagerTestWebView callJavascriptFunction:]): Deleted.
(-[VideoControlsManagerTestWebView loadTestPageNamed:]): Deleted.
(-[VideoControlsManagerTestWebView performAfterReceivingMessage:action:]): Deleted.
* TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm: Added.
(-[TestCandidate initWithReplacementString:inRange:]):
(-[TestCandidate replacementString]):
(-[TestCandidate resultType]):
(-[TestCandidate range]):
(-[CandidateTestWebView insertCandidatesAndWaitForResponse:range:]):
(-[CandidateTestWebView _didHandleAcceptedCandidate]):
(-[CandidateTestWebView expectCandidateListVisibilityUpdates:whenPerformingActions:]):
(-[CandidateTestWebView _didUpdateCandidateListVisibility:]):
(TEST):
* TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html: Added.
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html:
* TestWebKitAPI/mac/TestWKWebViewMac.h: Added.
* TestWebKitAPI/mac/TestWKWebViewMac.mm: Added.
(-[TestMessageHandler initWithMessage:handler:]):
(-[TestMessageHandler userContentController:didReceiveScriptMessage:]):
(-[TestWKWebView mouseDownAtPoint:]):
(-[TestWKWebView performAfterReceivingMessage:action:]):
(-[TestWKWebView loadTestPageNamed:]):
(-[TestWKWebView typeCharacter:]):
(-[TestWKWebView stringByEvaluatingJavaScript:]):
(-[TestWKWebView waitForMessage:]):
(-[TestWKWebView performAfterLoading:]):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (206032 => 206033)


--- trunk/Source/WebKit2/ChangeLog	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/ChangeLog	2016-09-16 18:14:04 UTC (rev 206033)
@@ -1,3 +1,68 @@
+2016-09-16  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Inserting a space after inserting an accepted candidate scrolls the document and causes a flicker
+        https://bugs.webkit.org/show_bug.cgi?id=162009
+        <rdar://problem/28086237>
+
+        Reviewed by Tim Horton.
+
+        After inserting a text candidate, if the candidate ended with a soft space, the next space we insert should just
+        replace the soft space. This currently works because we leave the text insertion out of the list of
+        KeypressCommands sent to the web process and instead replace the soft space via WebPage::InsertTextAsync.
+        However, this means when the web process handles this keydown event, the current editor will not handle it,
+        since the list of key commands is empty despite the text and unmodified text being non-empty.
+
+        To fix this, when sending keydown or keyup events where we replace a soft space, we set the key event's text to
+        an empty string instead of a space. This allows us to return early in EventHandler::keyEvent and avoid the
+        codepath that tries to insert text into the current editor and (in the case of inserting a ' ') scrolls the
+        document if necessary. Since we've already handled text insertion via WebPage::InsertTextAsync, there is no need
+        to also dispatch the keypress to the editor.
+
+        Additionally, this patch addresses flickering in the candidates UI due to the fact that we're asynchronously
+        replacing the last soft space. During this operation, we select the range of the soft space and then insert the
+        new text. This causes a momentary range selection which the web process notifies the UI process about, prompting
+        us to hide the candidates list. To address this, we suppress the EditorStateChanged message fired from the web
+        process to the UI process while we're selecting the original range to replace.
+
+        This patch adds 3 new WebKit API tests.
+
+        * Shared/NativeWebKeyboardEvent.h:
+        * Shared/mac/NativeWebKeyboardEventMac.mm:
+        (WebKit::NativeWebKeyboardEvent::NativeWebKeyboardEvent):
+        * Shared/mac/WebEventFactory.h:
+        * Shared/mac/WebEventFactory.mm:
+        (WebKit::textFromEvent):
+        (WebKit::unmodifiedTextFromEvent):
+        (WebKit::WebEventFactory::createWebKeyboardEvent):
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _handleAcceptedCandidate:]):
+        (-[WKWebView _didHandleAcceptedCandidate]):
+        (-[WKWebView _didUpdateCandidateListVisibility:]):
+        (-[WKWebView _forceRequestCandidates]):
+        (-[WKWebView _handleControlledElementIDResponse:]): Deleted.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView _didHandleAcceptedCandidate]):
+        (-[WKView _didUpdateCandidateListVisibility:]):
+        * UIProcess/Cocoa/WebViewImpl.h:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::forceRequestCandidatesForTesting):
+        (WebKit::WebViewImpl::becomeFirstResponder):
+        (WebKit::WebViewImpl::didHandleAcceptedCandidate):
+        (WebKit::WebViewImpl::insertText):
+        (WebKit::WebViewImpl::performKeyEquivalent):
+        (WebKit::WebViewImpl::keyUp):
+        (WebKit::WebViewImpl::keyDown):
+        (WebKit::WebViewImpl::flagsChanged):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::insertTextAsync):
+        * UIProcess/WebPageProxy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::insertTextAsync):
+        (WebKit::WebPage::didChangeSelection):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2016-09-16  Anders Carlsson  <ander...@apple.com>
 
         Add support for enum class parameters in the message generator

Modified: trunk/Source/WebKit2/Shared/NativeWebKeyboardEvent.h (206032 => 206033)


--- trunk/Source/WebKit2/Shared/NativeWebKeyboardEvent.h	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/NativeWebKeyboardEvent.h	2016-09-16 18:14:04 UTC (rev 206033)
@@ -60,7 +60,7 @@
 class NativeWebKeyboardEvent : public WebKeyboardEvent {
 public:
 #if USE(APPKIT)
-    NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>&);
+    NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, bool replacesSoftSpace, const Vector<WebCore::KeypressCommand>&);
 #elif PLATFORM(GTK)
     NativeWebKeyboardEvent(const NativeWebKeyboardEvent&);
     NativeWebKeyboardEvent(GdkEvent*, const WebCore::CompositionResults&, InputMethodFilter::EventFakedForComposition, Vector<String>&& commands);

Modified: trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm (206032 => 206033)


--- trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -35,8 +35,8 @@
 
 namespace WebKit {
 
-NativeWebKeyboardEvent::NativeWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, const Vector<KeypressCommand>& commands)
-    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event, handledByInputMethod, commands))
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, bool replacesSoftSpace, const Vector<KeypressCommand>& commands)
+    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event, handledByInputMethod, replacesSoftSpace, commands))
     , m_nativeEvent(event)
 {
 }

Modified: trunk/Source/WebKit2/Shared/mac/WebEventFactory.h (206032 => 206033)


--- trunk/Source/WebKit2/Shared/mac/WebEventFactory.h	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/mac/WebEventFactory.h	2016-09-16 18:14:04 UTC (rev 206033)
@@ -44,7 +44,7 @@
 #if USE(APPKIT)
     static WebMouseEvent createWebMouseEvent(NSEvent *, NSEvent *lastPressureEvent, NSView *windowView);
     static WebWheelEvent createWebWheelEvent(NSEvent *, NSView *windowView);
-    static WebKeyboardEvent createWebKeyboardEvent(NSEvent *, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>&);
+    static WebKeyboardEvent createWebKeyboardEvent(NSEvent *, bool handledByInputMethod, bool replacesSoftSpace, const Vector<WebCore::KeypressCommand>&);
     static bool shouldBeHandledAsContextClick(const WebCore::PlatformMouseEvent&);
 #endif // USE(APPKIT)
 };

Modified: trunk/Source/WebKit2/Shared/mac/WebEventFactory.mm (206032 => 206033)


--- trunk/Source/WebKit2/Shared/mac/WebEventFactory.mm	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/mac/WebEventFactory.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -236,8 +236,10 @@
     return static_cast<WebWheelEvent::Phase>(phase);
 }
 
-static inline String textFromEvent(NSEvent* event)
+static inline String textFromEvent(NSEvent* event, bool replacesSoftSpace)
 {
+    if (replacesSoftSpace)
+        return emptyString();
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
     if ([event type] == NSFlagsChanged)
@@ -246,8 +248,10 @@
     return String([event characters]);
 }
 
-static inline String unmodifiedTextFromEvent(NSEvent* event)
+static inline String unmodifiedTextFromEvent(NSEvent* event, bool replacesSoftSpace)
 {
+    if (replacesSoftSpace)
+        return emptyString();
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
     if ([event type] == NSFlagsChanged)
@@ -457,11 +461,11 @@
     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, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands)
+WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, bool replacesSoftSpace, const Vector<WebCore::KeypressCommand>& commands)
 {
     WebEvent::Type type             = isKeyUpEvent(event) ? WebEvent::KeyUp : WebEvent::KeyDown;
-    String text                     = textFromEvent(event);
-    String unmodifiedText           = unmodifiedTextFromEvent(event);
+    String text                     = textFromEvent(event, replacesSoftSpace);
+    String unmodifiedText           = unmodifiedTextFromEvent(event, replacesSoftSpace);
     String keyIdentifier            = keyIdentifierForKeyEvent(event);
     int windowsVirtualKeyCode       = windowsKeyCodeForKeyEvent(event);
     int nativeVirtualKeyCode        = [event keyCode];

Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (206032 => 206033)


--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -4564,6 +4564,28 @@
 {
     // Overridden by subclasses.
 }
+
+- (void)_handleAcceptedCandidate:(NSTextCheckingResult *)candidate
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+    _impl->handleAcceptedCandidate(candidate);
+#endif
+}
+
+- (void)_didHandleAcceptedCandidate
+{
+    // Overridden by subclasses.
+}
+
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible
+{
+    // Overridden by subclasses.
+}
+
+- (void)_forceRequestCandidates
+{
+    _impl->forceRequestCandidatesForTesting();
+}
 #endif // PLATFORM(MAC)
 
 // Execute the supplied block after the next transaction from the WebProcess.

Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h (206032 => 206033)


--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h	2016-09-16 18:14:04 UTC (rev 206033)
@@ -273,6 +273,10 @@
 @property (nonatomic, readonly) BOOL _hasActiveVideoForControlsManager WK_API_AVAILABLE(macosx(10.12));
 - (void)_requestControlledElementID WK_API_AVAILABLE(macosx(WK_MAC_TBA));
 - (void)_handleControlledElementIDResponse:(NSString *)identifier WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_handleAcceptedCandidate:(NSTextCheckingResult *)candidate WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_didHandleAcceptedCandidate WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_forceRequestCandidates WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible WK_API_AVAILABLE(macosx(WK_MAC_TBA));
 #endif
 
 - (void)_doAfterNextPresentationUpdate:(void (^)(void))updateBlock WK_API_AVAILABLE(macosx(10.12), ios(10.0));

Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm (206032 => 206033)


--- trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -969,6 +969,14 @@
     [self _gestureEventWasNotHandledByWebCore:event];
 }
 
+- (void)_didHandleAcceptedCandidate
+{
+}
+
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible
+{
+}
+
 @end
 
 @implementation WKView (Private)

Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h (206032 => 206033)


--- trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h	2016-09-16 18:14:04 UTC (rev 206033)
@@ -84,6 +84,8 @@
 @optional
 - (void)_web_didAddMediaControlsManager:(id)controlsManager;
 - (void)_web_didRemoveMediaControlsManager;
+- (void)_didHandleAcceptedCandidate;
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible;
 
 @end
 
@@ -478,6 +480,7 @@
     void rightMouseUp(NSEvent *);
 
     void updateWebViewImplAdditions();
+    void forceRequestCandidatesForTesting();
     bool shouldRequestCandidates() const;
     void showCandidates(NSArray *candidates, NSString *, NSRect rectOfTypedString, NSRange selectedRange, NSView *, void (^completionHandler)(NSTextCheckingResult *acceptedCandidate));
     void webViewImplAdditionsWillDestroyView();
@@ -649,6 +652,7 @@
     bool m_isHandlingAcceptedCandidate { false };
     bool m_requiresUserActionForEditingControlsManager { false };
     bool m_editableElementIsFocused { false };
+    bool m_isTextInsertionReplacingSoftSpace { false };
 };
     
 } // namespace WebKit

Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm (206032 => 206033)


--- trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -441,6 +441,10 @@
 {
 }
 
+void WebViewImpl::forceRequestCandidatesForTesting()
+{
+}
+
 bool WebViewImpl::shouldRequestCandidates() const
 {
     return false;
@@ -620,7 +624,7 @@
         if ([event type] == NSKeyDown || [event type] == NSKeyUp)
             keyboardEvent = event;
 #pragma clang diagnostic pop
-        m_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, { }), [](WebKit::CallbackBase::Error) { });
+        m_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, false, { }), [](WebKit::CallbackBase::Error) { });
     }
     return true;
 }
@@ -2436,6 +2440,8 @@
 void WebViewImpl::didHandleAcceptedCandidate()
 {
     m_isHandlingAcceptedCandidate = false;
+
+    [m_view _didHandleAcceptedCandidate];
 }
 
 void WebViewImpl::videoControlsManagerDidChange()
@@ -3567,11 +3573,11 @@
     } else
         text = string;
 
-    BOOL needToRemoveSoftSpace = NO;
+    m_isTextInsertionReplacingSoftSpace = false;
 #if HAVE(ADVANCED_SPELL_CHECKING)
     if (m_softSpaceRange.location != NSNotFound && (replacementRange.location == NSMaxRange(m_softSpaceRange) || replacementRange.location == NSNotFound) && replacementRange.length == 0 && [[NSSpellChecker sharedSpellChecker] deletesAutospaceBeforeString:text language:nil]) {
         replacementRange = m_softSpaceRange;
-        needToRemoveSoftSpace = YES;
+        m_isTextInsertionReplacingSoftSpace = true;
     }
 #endif
     m_softSpaceRange = NSMakeRange(NSNotFound, 0);
@@ -3582,7 +3588,7 @@
     // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
     // then we also execute it immediately, as there will be no other chance.
     Vector<WebCore::KeypressCommand>* keypressCommands = m_collectedKeypressCommands;
-    if (keypressCommands && !needToRemoveSoftSpace) {
+    if (keypressCommands && !m_isTextInsertionReplacingSoftSpace) {
         ASSERT(replacementRange.location == NSNotFound);
         WebCore::KeypressCommand command("insertText:", text);
         keypressCommands->append(command);
@@ -3596,7 +3602,7 @@
     if (!dictationAlternatives.isEmpty())
         m_page->insertDictatedTextAsync(eventText, replacementRange, dictationAlternatives, registerUndoGroup);
     else
-        m_page->insertTextAsync(eventText, replacementRange, registerUndoGroup, needToRemoveSoftSpace ? EditingRangeIsRelativeTo::Paragraph : EditingRangeIsRelativeTo::EditableRoot);
+        m_page->insertTextAsync(eventText, replacementRange, registerUndoGroup, m_isTextInsertionReplacingSoftSpace ? EditingRangeIsRelativeTo::Paragraph : EditingRangeIsRelativeTo::EditableRoot, m_isTextInsertionReplacingSoftSpace);
 }
 
 void WebViewImpl::selectedRangeWithCompletionHandler(void(^completionHandlerPtr)(NSRange selectedRange))
@@ -3870,7 +3876,7 @@
     // FIXME: Why is the firstResponder check needed?
     if (m_view == m_view.window.firstResponder) {
         interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
-            m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+            m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, false, commands));
         });
         return YES;
     }
@@ -3885,9 +3891,10 @@
 
     LOG(TextInput, "keyUp:%p %@", event, event);
 
+    m_isTextInsertionReplacingSoftSpace = false;
     interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
         ASSERT(!handledByInputMethod || commands.isEmpty());
-        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, m_isTextInsertionReplacingSoftSpace, commands));
     });
 }
 
@@ -3912,9 +3919,10 @@
         return;
     }
 
+    m_isTextInsertionReplacingSoftSpace = false;
     interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
         ASSERT(!handledByInputMethod || commands.isEmpty());
-        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, m_isTextInsertionReplacingSoftSpace, commands));
     });
 }
 
@@ -3930,7 +3938,7 @@
         return;
 
     interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
-        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, false, commands));
     });
 }
 

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (206032 => 206033)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2016-09-16 18:14:04 UTC (rev 206033)
@@ -6145,12 +6145,12 @@
 
 #if PLATFORM(COCOA)
 
-void WebPageProxy::insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup, EditingRangeIsRelativeTo editingRangeIsRelativeTo)
+void WebPageProxy::insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup, EditingRangeIsRelativeTo editingRangeIsRelativeTo, bool suppressSelectionUpdate)
 {
     if (!isValid())
         return;
 
-    process().send(Messages::WebPage::InsertTextAsync(text, replacementRange, registerUndoGroup, static_cast<uint32_t>(editingRangeIsRelativeTo)), m_pageID);
+    process().send(Messages::WebPage::InsertTextAsync(text, replacementRange, registerUndoGroup, static_cast<uint32_t>(editingRangeIsRelativeTo), suppressSelectionUpdate), m_pageID);
 }
 
 void WebPageProxy::getMarkedRangeAsync(std::function<void (EditingRange, CallbackBase::Error)> callbackFunction)

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (206032 => 206033)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2016-09-16 18:14:04 UTC (rev 206033)
@@ -564,7 +564,7 @@
     void setAcceleratedCompositingRootLayer(LayerOrView*);
     LayerOrView* acceleratedCompositingRootLayer() const;
 
-    void insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup = false, EditingRangeIsRelativeTo = EditingRangeIsRelativeTo::EditableRoot);
+    void insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup = false, EditingRangeIsRelativeTo = EditingRangeIsRelativeTo::EditableRoot, bool suppressSelectionUpdate = false);
     void getMarkedRangeAsync(std::function<void (EditingRange, CallbackBase::Error)>);
     void getSelectedRangeAsync(std::function<void (EditingRange, CallbackBase::Error)>);
     void characterIndexForPointAsync(const WebCore::IntPoint&, std::function<void (uint64_t, CallbackBase::Error)>);

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (206032 => 206033)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2016-09-16 18:14:04 UTC (rev 206033)
@@ -4610,14 +4610,16 @@
 
 #if PLATFORM(COCOA)
 
-void WebPage::insertTextAsync(const String& text, const EditingRange& replacementEditingRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo)
+void WebPage::insertTextAsync(const String& text, const EditingRange& replacementEditingRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo, bool suppressSelectionUpdate)
 {
     Frame& frame = m_page->focusController().focusedOrMainFrame();
 
     if (replacementEditingRange.location != notFound) {
         RefPtr<Range> replacementRange = rangeFromEditingRange(frame, replacementEditingRange, static_cast<EditingRangeIsRelativeTo>(editingRangeIsRelativeTo));
-        if (replacementRange)
+        if (replacementRange) {
+            TemporaryChange<bool> isSelectingTextWhileInsertingAsynchronously(m_isSelectingTextWhileInsertingAsynchronously, suppressSelectionUpdate);
             frame.selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY));
+        }
     }
     
     if (registerUndoGroup)
@@ -4842,6 +4844,11 @@
     if (m_isGettingDictionaryPopupInfo)
         return;
 
+    // Similarly, we don't want to propagate changes to the web process when inserting text asynchronously, since we will
+    // end up with a range selection very briefly right before inserting the text.
+    if (m_isSelectingTextWhileInsertingAsynchronously)
+        return;
+
     Frame& frame = m_page->focusController().focusedOrMainFrame();
     FrameView* view = frame.view();
 

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (206032 => 206033)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h	2016-09-16 18:14:04 UTC (rev 206033)
@@ -666,7 +666,7 @@
     
     void sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput);
 
-    void insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup = false, uint32_t editingRangeIsRelativeTo = (uint32_t)EditingRangeIsRelativeTo::EditableRoot);
+    void insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup = false, uint32_t editingRangeIsRelativeTo = (uint32_t)EditingRangeIsRelativeTo::EditableRoot, bool suppressSelectionUpdate = false);
     void getMarkedRangeAsync(uint64_t callbackID);
     void getSelectedRangeAsync(uint64_t callbackID);
     void characterIndexForPointAsync(const WebCore::IntPoint&, uint64_t callbackID);
@@ -1488,6 +1488,7 @@
     bool m_shouldDispatchFakeMouseMoveEvents;
     bool m_isEditorStateMissingPostLayoutData { false };
     bool m_isGettingDictionaryPopupInfo { false };
+    bool m_isSelectingTextWhileInsertingAsynchronously { false };
 
     enum class EditorStateIsContentEditable { No, Yes, Unset };
     mutable EditorStateIsContentEditable m_lastEditorStateWasContentEditable { EditorStateIsContentEditable::Unset };

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in (206032 => 206033)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in	2016-09-16 18:14:04 UTC (rev 206033)
@@ -366,7 +366,7 @@
     ShouldDelayWindowOrderingEvent(WebKit::WebMouseEvent event) -> (bool result)
     AcceptsFirstMouse(int eventNumber, WebKit::WebMouseEvent event) -> (bool result)
 
-    InsertTextAsync(String text, struct WebKit::EditingRange replacementRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo)
+    InsertTextAsync(String text, struct WebKit::EditingRange replacementRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo, bool suppressSelectionUpdate)
     GetMarkedRangeAsync(uint64_t callbackID)
     GetSelectedRangeAsync(uint64_t callbackID)
     CharacterIndexForPointAsync(WebCore::IntPoint point, uint64_t callbackID);

Modified: trunk/Tools/ChangeLog (206032 => 206033)


--- trunk/Tools/ChangeLog	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/ChangeLog	2016-09-16 18:14:04 UTC (rev 206033)
@@ -1,3 +1,73 @@
+2016-09-16  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Inserting a space after inserting an accepted candidate scrolls the document and causes a flicker
+        https://bugs.webkit.org/show_bug.cgi?id=162009
+        <rdar://problem/28086237>
+
+        Reviewed by Tim Horton.
+
+        Adds 3 new text editing API tests covering candidate insertion, as well as support for testing candidates in
+        WKWebViews. Refactors common WKWebView helpers across both VideoControlsManager tests and the new
+        WKWebViewCandidateTests into a new utility class, TestWKWebView in TestWKWebView.mm, which is capable of
+        simulating mouse and keyboard events as well as waiting for _javascript_ messages sent from the web process and
+        performing actions in response.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit/ios/audio-only.html:
+        * TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm:
+        (TestWebKitAPI::TEST):
+        (-[MessageHandler initWithMessage:handler:]): Deleted.
+        (-[MessageHandler userContentController:didReceiveScriptMessage:]): Deleted.
+        (-[VideoControlsManagerTestWebView mouseDownAtPoint:]): Deleted.
+        (-[VideoControlsManagerTestWebView performAfterLoading:]): Deleted.
+        (-[VideoControlsManagerTestWebView callJavascriptFunction:]): Deleted.
+        (-[VideoControlsManagerTestWebView loadTestPageNamed:]): Deleted.
+        (-[VideoControlsManagerTestWebView performAfterReceivingMessage:action:]): Deleted.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm: Added.
+        (-[TestCandidate initWithReplacementString:inRange:]):
+        (-[TestCandidate replacementString]):
+        (-[TestCandidate resultType]):
+        (-[TestCandidate range]):
+        (-[CandidateTestWebView insertCandidatesAndWaitForResponse:range:]):
+        (-[CandidateTestWebView _didHandleAcceptedCandidate]):
+        (-[CandidateTestWebView expectCandidateListVisibilityUpdates:whenPerformingActions:]):
+        (-[CandidateTestWebView _didUpdateCandidateListVisibility:]):
+        (TEST):
+        * TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html: Added.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html:
+        * TestWebKitAPI/mac/TestWKWebViewMac.h: Added.
+        * TestWebKitAPI/mac/TestWKWebViewMac.mm: Added.
+        (-[TestMessageHandler initWithMessage:handler:]):
+        (-[TestMessageHandler userContentController:didReceiveScriptMessage:]):
+        (-[TestWKWebView mouseDownAtPoint:]):
+        (-[TestWKWebView performAfterReceivingMessage:action:]):
+        (-[TestWKWebView loadTestPageNamed:]):
+        (-[TestWKWebView typeCharacter:]):
+        (-[TestWKWebView stringByEvaluatingJavaScript:]):
+        (-[TestWKWebView waitForMessage:]):
+        (-[TestWKWebView performAfterLoading:]):
+
 2016-09-14  Jer Noble  <jer.no...@apple.com>
 
         [media-source] fix imported/w3c/web-platform-tests/media-source/mediasource-duration.html

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2016-09-16 18:14:04 UTC (rev 206033)
@@ -78,6 +78,9 @@
 		2EFF06C31D88621E0004BB30 /* large-video-offscreen.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06C21D8862120004BB30 /* large-video-offscreen.html */; };
 		2EFF06C51D8867760004BB30 /* change-video-source-on-click.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06C41D8867700004BB30 /* change-video-source-on-click.html */; };
 		2EFF06C71D886A580004BB30 /* change-video-source-on-end.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */; };
+		2EFF06CD1D8A429A0004BB30 /* input-field-in-scrollable-document.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06CC1D8A42910004BB30 /* input-field-in-scrollable-document.html */; };
+		2EFF06D41D8AEDBB0004BB30 /* TestWKWebViewMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2EFF06D31D8AEDBB0004BB30 /* TestWKWebViewMac.mm */; };
+		2EFF06D71D8AF34A0004BB30 /* WKWebViewCandidateTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2EFF06D61D8AF34A0004BB30 /* WKWebViewCandidateTests.mm */; };
 		33BE5AF9137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33BE5AF8137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp */; };
 		33DC8912141955FE00747EF7 /* simple-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 33DC890E1419539300747EF7 /* simple-iframe.html */; };
 		33DC89141419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33DC89131419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp */; };
@@ -541,6 +544,7 @@
 			dstPath = TestWebKitAPI.resources;
 			dstSubfolderSpec = 7;
 			files = (
+				2EFF06CD1D8A429A0004BB30 /* input-field-in-scrollable-document.html in Copy Resources */,
 				2EFF06C71D886A580004BB30 /* change-video-source-on-end.html in Copy Resources */,
 				2EFF06C51D8867760004BB30 /* change-video-source-on-click.html in Copy Resources */,
 				2EFF06C31D88621E0004BB30 /* large-video-offscreen.html in Copy Resources */,
@@ -789,6 +793,10 @@
 		2EFF06C21D8862120004BB30 /* large-video-offscreen.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-offscreen.html"; sourceTree = "<group>"; };
 		2EFF06C41D8867700004BB30 /* change-video-source-on-click.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "change-video-source-on-click.html"; sourceTree = "<group>"; };
 		2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "change-video-source-on-end.html"; sourceTree = "<group>"; };
+		2EFF06CC1D8A42910004BB30 /* input-field-in-scrollable-document.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "input-field-in-scrollable-document.html"; sourceTree = "<group>"; };
+		2EFF06D21D8AEDBB0004BB30 /* TestWKWebViewMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestWKWebViewMac.h; sourceTree = "<group>"; };
+		2EFF06D31D8AEDBB0004BB30 /* TestWKWebViewMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestWKWebViewMac.mm; sourceTree = "<group>"; };
+		2EFF06D61D8AF34A0004BB30 /* WKWebViewCandidateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewCandidateTests.mm; sourceTree = "<group>"; };
 		333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreventEmptyUserAgent.cpp; sourceTree = "<group>"; };
 		33BE5AF4137B5A6C00705813 /* MouseMoveAfterCrash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseMoveAfterCrash.cpp; sourceTree = "<group>"; };
 		33BE5AF8137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseMoveAfterCrash_Bundle.cpp; sourceTree = "<group>"; };
@@ -1375,6 +1383,7 @@
 				37B47E2E1D64E7CA005F4EFF /* WKObject.mm */,
 				2D00065D1C1F58940088E6A7 /* WKPDFViewResizeCrash.mm */,
 				5E4B1D2C1D404C6100053621 /* WKScrollViewDelegateCrash.mm */,
+				2EFF06D61D8AF34A0004BB30 /* WKWebViewCandidateTests.mm */,
 				7C417F311D19E14800B8EF53 /* WKWebViewDefaultNavigationDelegate.mm */,
 				0F3B94A51A77266C00DE3272 /* WKWebViewEvaluateJavaScript.mm */,
 				9984FACA1CFFAEEE008D198C /* WKWebViewTextInput.mm */,
@@ -1464,6 +1473,7 @@
 		A16F66B81C40E9E100BD4D24 /* Resources */ = {
 			isa = PBXGroup;
 			children = (
+				2EFF06CC1D8A42910004BB30 /* input-field-in-scrollable-document.html */,
 				2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */,
 				2EFF06C41D8867700004BB30 /* change-video-source-on-click.html */,
 				2EFF06C21D8862120004BB30 /* large-video-offscreen.html */,
@@ -1819,6 +1829,8 @@
 				C081224413FC19EC00DC39AE /* SyntheticBackingScaleFactorWindow.m */,
 				29AB8AA3164C7A9300D49BEC /* TestBrowsingContextLoadDelegate.h */,
 				29AB8AA2164C7A9300D49BEC /* TestBrowsingContextLoadDelegate.mm */,
+				2EFF06D21D8AEDBB0004BB30 /* TestWKWebViewMac.h */,
+				2EFF06D31D8AEDBB0004BB30 /* TestWKWebViewMac.mm */,
 				C08587BE13FE956C001EF4E5 /* WebKitAgnosticTest.h */,
 				C08587BD13FE956C001EF4E5 /* WebKitAgnosticTest.mm */,
 			);
@@ -2342,6 +2354,7 @@
 				7CCE7EFB1A411AE600447C4C /* InjectedBundleBasic.cpp in Sources */,
 				7CCE7EFC1A411AE600447C4C /* InjectedBundleFrameHitTest.cpp in Sources */,
 				7CCE7EFD1A411AE600447C4C /* InjectedBundleInitializationUserDataCallbackWins.cpp in Sources */,
+				2EFF06D41D8AEDBB0004BB30 /* TestWKWebViewMac.mm in Sources */,
 				7C83E0B81D0A64BD00FEBCF3 /* InjectedBundleMakeAllShadowRootsOpen.cpp in Sources */,
 				7CCE7EC31A411A7E00447C4C /* InspectorBar.mm in Sources */,
 				7CCE7EDA1A411A8700447C4C /* InstanceMethodSwizzler.mm in Sources */,
@@ -2461,6 +2474,7 @@
 				7CCE7ED81A411A7E00447C4C /* WillSendSubmitEvent.mm in Sources */,
 				7CCE7ED91A411A7E00447C4C /* WindowlessWebViewWithMedia.mm in Sources */,
 				1F83571B1D3FFB2300E3967B /* WKBackForwardList.mm in Sources */,
+				2EFF06D71D8AF34A0004BB30 /* WKWebViewCandidateTests.mm in Sources */,
 				7CCE7F2E1A411B1000447C4C /* WKBrowsingContextGroupTest.mm in Sources */,
 				7CCE7F2F1A411B1000447C4C /* WKBrowsingContextLoadDelegateTest.mm in Sources */,
 				7C54A4BE1AA11CCA00380F78 /* WKBundleFileHandle.cpp in Sources */,

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/audio-only.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/audio-only.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/audio-only.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -12,7 +12,7 @@
     function playing() {
         window.clearTimeout(timeout);
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
+            window.webkit.messageHandlers.testHandler.postMessage('playing');
         } catch(e) {
             window.location = 'callback:playing';
         }
@@ -20,7 +20,7 @@
 
     function notPlaying() {
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
         } catch(e) { }
     }
     </script>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -14,7 +14,7 @@
     function playing() {
         window.clearTimeout(timeout);
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
+            window.webkit.messageHandlers.testHandler.postMessage('playing');
         } catch(e) {
             window.location = 'callback:playing';
         }
@@ -22,7 +22,7 @@
 
     function notPlaying() {
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
         } catch(e) { }
     }
    </script>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -12,7 +12,7 @@
     function playing() {
         window.clearTimeout(timeout);
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
+            window.webkit.messageHandlers.testHandler.postMessage('playing');
         } catch(e) {
             window.location = 'callback:playing';
         }
@@ -20,7 +20,7 @@
 
     function notPlaying() {
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
         } catch(e) { }
     }
     </script>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -26,11 +26,8 @@
 #include "config.h"
 
 #import "PlatformUtilities.h"
+#import "TestWKWebViewMac.h"
 
-#if PLATFORM(MAC)
-#import <Carbon/Carbon.h>
-#endif
-
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <wtf/RetainPtr.h>
@@ -43,67 +40,14 @@
 
 @end
 
-@interface MessageHandler : NSObject <WKScriptMessageHandler>
+@interface VideoControlsManagerTestWebView : TestWKWebView
 @end
 
-@implementation MessageHandler {
-    dispatch_block_t _handler;
-    NSString *_message;
-}
-
-- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler
-{
-    if (!(self = [super init]))
-        return nil;
-
-    _handler = [handler copy];
-    _message = message;
-
-    return self;
-}
-
-- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
-{
-    if ([(NSString *)[message body] isEqualToString:_message] && _handler)
-        _handler();
-}
-
-@end
-
-@interface VideoControlsManagerTestWebView : WKWebView
-@end
-
 @implementation VideoControlsManagerTestWebView {
     bool _isDoneQueryingControlledElementID;
     NSString *_controlledElementID;
 }
 
-- (void)mouseDownAtPoint:(NSPoint)point {
-    [self mouseDown:[NSEvent mouseEventWithType:NSEventTypeLeftMouseDown location:NSMakePoint(point.x, point.y) modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:[NSGraphicsContext currentContext] eventNumber:0 clickCount:0 pressure:0]];
-}
-
-- (void)performAfterLoading:(dispatch_block_t)actions {
-    MessageHandler *handler = [[MessageHandler alloc] initWithMessage:@"loaded" handler:actions];
-    NSString *_onloadScript_ = @"window._onload_ = function() { window.webkit.messageHandlers.onloadHandler.postMessage('loaded'); }";
-    WKUserScript *script = [[WKUserScript alloc] initWithSource:onloadScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
-
-    WKUserContentController* contentController = [[self configuration] userContentController];
-    [contentController addUserScript:script];
-    [contentController addScriptMessageHandler:handler name:@"onloadHandler"];
-}
-
-- (void)callJavascriptFunction:(NSString *)functionName
-{
-    NSString *command = [NSString stringWithFormat:@"%@()", functionName];
-    [self evaluateJavaScript:command completionHandler:nil];
-}
-
-- (void)loadTestPageNamed:(NSString *)pageName
-{
-    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:pageName withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
-    [self loadRequest:request];
-}
-
 - (void)expectControlsManager:(BOOL)expectControlsManager afterReceivingMessage:(NSString *)message
 {
     __block bool doneWaiting = false;
@@ -131,14 +75,6 @@
         [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
 }
 
-- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action
-{
-    RetainPtr<MessageHandler> handler = adoptNS([[MessageHandler alloc] initWithMessage:message handler:action]);
-    WKUserContentController* contentController = [[self configuration] userContentController];
-    [contentController removeScriptMessageHandlerForName:@"playingHandler"];
-    [contentController addScriptMessageHandler:handler.get() name:@"playingHandler"];
-}
-
 - (void)waitForPageToLoadWithAutoplayingVideos:(int)numberOfAutoplayingVideos
 {
     __block int remainingAutoplayedCount = numberOfAutoplayingVideos;
@@ -240,7 +176,7 @@
     [webView loadTestPageNamed:@"large-videos-paused-video-hides-controls"];
     [webView waitForPageToLoadWithAutoplayingVideos:1];
 
-    [webView callJavascriptFunction:@"pauseFirstVideoAndScrollToSecondVideo"];
+    [webView stringByEvaluatingJavaScript:@"pauseFirstVideoAndScrollToSecondVideo()"];
     [webView expectControlsManager:NO afterReceivingMessage:@"paused"];
 }
 
@@ -251,7 +187,7 @@
     [webView loadTestPageNamed:@"large-videos-playing-video-keeps-controls"];
     [webView waitForPageToLoadWithAutoplayingVideos:1];
 
-    [webView callJavascriptFunction:@"scrollToSecondVideo"];
+    [webView stringByEvaluatingJavaScript:@"scrollToSecondVideo()"];
     [webView expectControlsManager:YES afterReceivingMessage:@"scrolled"];
 }
 
@@ -262,7 +198,7 @@
     [webView loadTestPageNamed:@"large-videos-playing-muted-video-hides-controls"];
     [webView waitForPageToLoadWithAutoplayingVideos:1];
 
-    [webView callJavascriptFunction:@"muteFirstVideoAndScrollToSecondVideo"];
+    [webView stringByEvaluatingJavaScript:@"muteFirstVideoAndScrollToSecondVideo()"];
     [webView expectControlsManager:NO afterReceivingMessage:@"playing"];
 }
 
@@ -300,7 +236,7 @@
     [webView loadTestPageNamed:@"large-videos-autoplaying-scroll-to-video"];
     [webView waitForPageToLoadWithAutoplayingVideos:2];
 
-    [webView callJavascriptFunction:@"scrollToSecondView"];
+    [webView stringByEvaluatingJavaScript:@"scrollToSecondView()"];
     [webView expectControlsManager:YES afterReceivingMessage:@"scrolled"];
 
     EXPECT_TRUE([[webView controlledElementID] isEqualToString:@"second"]);
@@ -312,7 +248,7 @@
 
     [webView loadTestPageNamed:@"large-video-playing-scroll-away"];
     [webView waitForPageToLoadWithAutoplayingVideos:1];
-    [webView callJavascriptFunction:@"scrollVideoOutOfView"];
+    [webView stringByEvaluatingJavaScript:@"scrollVideoOutOfView()"];
     [webView expectControlsManager:YES afterReceivingMessage:@"scrolled"];
 }
 

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm (0 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2016 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"
+
+#if WK_API_ENABLED && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+
+#import "PlatformUtilities.h"
+#import "TestWKWebViewMac.h"
+
+#import <WebKit/WebKitPrivate.h>
+
+static NSString *GetInputValueJSExpression = @"document.querySelector('input').value";
+static NSString *GetDocumentScrollTopJSExpression = @"document.body.scrollTop";
+
+@interface TestCandidate : NSTextCheckingResult
+@end
+
+@implementation TestCandidate {
+    NSString *_string;
+    NSRange _range;
+}
+
+- (instancetype)initWithReplacementString:(NSString *)string inRange:(NSRange)range
+{
+    if (self = [super init]) {
+        _string = string;
+        _range = range;
+    }
+    return self;
+}
+
+- (NSString *)replacementString
+{
+    return _string;
+}
+
+- (NSTextCheckingType)resultType
+{
+    return NSTextCheckingTypeReplacement;
+}
+
+- (NSRange)range
+{
+    return _range;
+}
+
+@end
+
+@interface CandidateTestWebView : TestWKWebView
+@property (nonatomic, readonly, getter=isCandidateListVisible) BOOL candidateListVisible;
+@end
+
+@implementation CandidateTestWebView {
+    bool _isDoneWaitingForCandidate;
+    bool _isListeningForCandidateListVisibilityChanges;
+    NSUInteger _candidateListVisibilityChangeCount;
+}
+
+- (void)insertCandidatesAndWaitForResponse:(NSString *)replacementString range:(NSRange)range
+{
+    _isDoneWaitingForCandidate = false;
+    [self _handleAcceptedCandidate:[[TestCandidate alloc] initWithReplacementString:replacementString inRange:range]];
+    TestWebKitAPI::Util::run(&_isDoneWaitingForCandidate);
+}
+
+- (void)_didHandleAcceptedCandidate
+{
+    _isDoneWaitingForCandidate = true;
+}
+
+- (void)expectCandidateListVisibilityUpdates:(NSUInteger)expectedUpdateCount whenPerformingActions:(dispatch_block_t)actions
+{
+    _candidateListVisibilityChangeCount = 0;
+    _isListeningForCandidateListVisibilityChanges = YES;
+
+    actions();
+
+    _isListeningForCandidateListVisibilityChanges = NO;
+    EXPECT_EQ(expectedUpdateCount, _candidateListVisibilityChangeCount);
+}
+
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible
+{
+    if (_candidateListVisible == visible)
+        return;
+
+    _candidateListVisible = visible;
+    if (_isListeningForCandidateListVisibilityChanges)
+        _candidateListVisibilityChangeCount++;
+}
+
+@end
+
+TEST(WKWebViewCandidateTests, SoftSpaceReplacementAfterCandidateInsertionWithoutReplacement)
+{
+    CandidateTestWebView *wkWebView = [[CandidateTestWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)];
+
+    NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@"input-field-in-scrollable-document" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [wkWebView loadRequest:[NSURLRequest requestWithURL:contentURL]];
+
+    [wkWebView waitForMessage:@"focused"];
+    [wkWebView _forceRequestCandidates];
+    [wkWebView insertCandidatesAndWaitForResponse:@"apple " range:NSMakeRange(0, 0)];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@"apple "]);
+
+    [wkWebView expectCandidateListVisibilityUpdates:0 whenPerformingActions:^()
+    {
+        [wkWebView typeCharacter:' '];
+        [wkWebView waitForMessage:@"input"];
+    }];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@"apple "]);
+    EXPECT_EQ([[wkWebView stringByEvaluatingJavaScript:GetDocumentScrollTopJSExpression] doubleValue], 0);
+}
+
+TEST(WKWebViewCandidateTests, InsertCharactersAfterCandidateInsertionWithSoftSpace)
+{
+    CandidateTestWebView *wkWebView = [[CandidateTestWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)];
+
+    NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@"input-field-in-scrollable-document" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [wkWebView loadRequest:[NSURLRequest requestWithURL:contentURL]];
+
+    [wkWebView waitForMessage:@"focused"];
+    [wkWebView _forceRequestCandidates];
+    [wkWebView insertCandidatesAndWaitForResponse:@"foo " range:NSMakeRange(0, 0)];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@"foo "]);
+
+    [wkWebView typeCharacter:'a'];
+    [wkWebView waitForMessage:@"input"];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@"foo a"]);
+}
+
+TEST(WKWebViewCandidateTests, InsertCandidateFromPartiallyTypedPhraseWithSoftSpace)
+{
+    CandidateTestWebView *wkWebView = [[CandidateTestWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)];
+
+    NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@"input-field-in-scrollable-document" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [wkWebView loadRequest:[NSURLRequest requestWithURL:contentURL]];
+
+    [wkWebView waitForMessage:@"focused"];
+    [wkWebView _forceRequestCandidates];
+
+    NSString *initialValue = @"hel";
+    for (uint64_t i = 0; i < initialValue.length; ++i) {
+        [wkWebView typeCharacter:[initialValue characterAtIndex:i]];
+        [wkWebView waitForMessage:@"input"];
+    }
+
+    [wkWebView insertCandidatesAndWaitForResponse:@"hello " range:NSMakeRange(0, 3)];
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@"hello "]);
+
+    [wkWebView expectCandidateListVisibilityUpdates:0 whenPerformingActions:^()
+    {
+        [wkWebView typeCharacter:' '];
+        [wkWebView waitForMessage:@"input"];
+        EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@"hello "]);
+        EXPECT_EQ([[wkWebView stringByEvaluatingJavaScript:GetDocumentScrollTopJSExpression] doubleValue], 0);
+
+        [wkWebView typeCharacter:' '];
+        [wkWebView waitForMessage:@"input"];
+        EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@"hello  "]);
+        EXPECT_EQ([[wkWebView stringByEvaluatingJavaScript:GetDocumentScrollTopJSExpression] doubleValue], 0);
+    }];
+}
+
+#endif /* WK_API_ENABLED && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 */

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -12,7 +12,7 @@
         // Wait until the next runloop to allow media controls to update.
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("paused");
+                window.webkit.messageHandlers.testHandler.postMessage("paused");
             } catch(e) { }
         }, 0);
     }
@@ -20,7 +20,7 @@
     function beganAutoplaying() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
             } catch(e) {
             }
         }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -12,7 +12,7 @@
             video.play();
             setTimeout(function() {
                 try {
-                    window.webkit.messageHandlers.playingHandler.postMessage("changed");
+                    window.webkit.messageHandlers.testHandler.postMessage("changed");
                 } catch(e) {
                 }
             });
@@ -21,7 +21,7 @@
         function handlePlaying() {
             setTimeout(function() {
                 try {
-                    window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                    window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
                 } catch(e) {
                 }
             }, 0);

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -14,7 +14,7 @@
             video.play();
             setTimeout(function() {
                 try {
-                    window.webkit.messageHandlers.playingHandler.postMessage("changed");
+                    window.webkit.messageHandlers.testHandler.postMessage("changed");
                 } catch(e) {
                 }
             });

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -11,7 +11,7 @@
     function finishTest() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("playing");
+                window.webkit.messageHandlers.testHandler.postMessage("playing");
             } catch(e) { }
         }, 0);
     }

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html (0 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -0,0 +1,36 @@
+<html>
+
+<head>
+    <style>
+        body {
+            margin: 0;
+        }
+
+        input {
+            width: 100%;
+            height: 400px;
+            margin-bottom: 5000px;
+        }
+    </style>
+    <script type="text/_javascript_">
+        function loaded() {
+            var input = document.querySelector("input");
+            input.setSelectionRange(0, 0);
+            input.focus();
+        }
+
+        function focused() {
+            setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("focused"), 0);
+        }
+
+        function input() {
+            setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("input"), 0);
+        }
+    </script>
+</head>
+
+<body _onload_=loaded()>
+    <input _onfocus_=focused() _oninput_=input()></input>
+</body>
+
+</html>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -7,7 +7,7 @@
         // The media controls should be updated on the next runloop.
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("ended");
+                window.webkit.messageHandlers.testHandler.postMessage("ended");
             } catch(e) { }
         }, 0);
     }
@@ -26,7 +26,7 @@
     function beganAutoplaying() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
             } catch(e) {
             }
         }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -3,7 +3,7 @@
 <script>
     function handlePlaying() {
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage("playing");
+            window.webkit.messageHandlers.testHandler.postMessage("playing");
         } catch(e) {
         }
         document.querySelector("video").muted = true;

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -16,7 +16,7 @@
             document.querySelector("video").classList.add("offscreen");
             setTimeout(function() {
                 try {
-                    window.webkit.messageHandlers.playingHandler.postMessage("moved");
+                    window.webkit.messageHandlers.testHandler.postMessage("moved");
                 } catch(e) {
                 }
             }, 0);

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -14,7 +14,7 @@
             function scrollVideoOutOfView() {
                 document.querySelector("div").scrollIntoView();
                 setTimeout(function() {
-                    window.webkit.messageHandlers.playingHandler.postMessage("scrolled");
+                    window.webkit.messageHandlers.testHandler.postMessage("scrolled");
                 }, 0);
             }
 
@@ -21,7 +21,7 @@
             function beganAutoplaying() {
                 setTimeout(function() {
                     try {
-                        window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                        window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
                     } catch(e) {
                     }
                 }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -6,7 +6,7 @@
             document.querySelector("#test-video").currentTime = 0;
             // The media controls should be updated on the next runloop.
             setTimeout(function() {
-                window.webkit.messageHandlers.playingHandler.postMessage("ended");
+                window.webkit.messageHandlers.testHandler.postMessage("ended");
             }, 0);
         }
 

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -8,7 +8,7 @@
             video.play();
             // The media controls should be updated on the next runloop.
             setTimeout(function() {
-                window.webkit.messageHandlers.playingHandler.postMessage("replaying");
+                window.webkit.messageHandlers.testHandler.postMessage("replaying");
             }, 0);
         }
 

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -14,7 +14,7 @@
         window.clearTimeout(timeout);
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage('playing');
+                window.webkit.messageHandlers.testHandler.postMessage('playing');
             } catch(e) {
                 window.location = 'callback:playing';
             }
@@ -23,7 +23,7 @@
 
     function notPlaying() {
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
         } catch(e) { }
     }
 </script>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -13,7 +13,7 @@
     function playing() {
         window.clearTimeout(timeout);
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
+            window.webkit.messageHandlers.testHandler.postMessage('playing');
         } catch(e) {
             window.location = 'callback:playing';
         }
@@ -21,7 +21,7 @@
 
     function notPlaying() {
         try {
-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
         } catch(e) { }
     }
 </script>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -17,7 +17,7 @@
             function handleFirstPause() {
                 setTimeout(function() {
                     try {
-                        window.webkit.messageHandlers.playingHandler.postMessage("paused");
+                        window.webkit.messageHandlers.testHandler.postMessage("paused");
                     } catch(e) { }
                 }, 0);
             }
@@ -25,7 +25,7 @@
             function handleSecondPause() {
                 setTimeout(function() {
                     try {
-                        window.webkit.messageHandlers.playingHandler.postMessage("paused");
+                        window.webkit.messageHandlers.testHandler.postMessage("paused");
                     } catch(e) { }
                 }, 0);
             }
@@ -33,7 +33,7 @@
             function beganAutoplaying() {
                 setTimeout(function() {
                     try {
-                        window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                        window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
                     } catch(e) {
                     }
                 }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -14,13 +14,13 @@
             function scrollToSecondView() {
                 document.querySelector("#second").scrollIntoView();
                 setTimeout(function() {
-                    window.webkit.messageHandlers.playingHandler.postMessage("scrolled");
+                    window.webkit.messageHandlers.testHandler.postMessage("scrolled");
                 }, 0);
             }
             function beganAutoplaying() {
                 setTimeout(function() {
                     try {
-                        window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                        window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
                     } catch(e) {
                     }
                 }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -17,7 +17,7 @@
     function handlePaused() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("paused");
+                window.webkit.messageHandlers.testHandler.postMessage("paused");
             } catch(e) { }
         }, 0);
     }
@@ -24,7 +24,7 @@
     function beganAutoplaying() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
             } catch(e) {
             }
         }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -15,7 +15,7 @@
         document.querySelector("#bar").scrollIntoView();
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("playing");
+                window.webkit.messageHandlers.testHandler.postMessage("playing");
             } catch(e) { }
         }, 0);
     }
@@ -22,7 +22,7 @@
     function beganAutoplaying() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
             } catch(e) {
             }
         }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -14,7 +14,7 @@
         document.querySelector("#bar").scrollIntoView();
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("scrolled");
+                window.webkit.messageHandlers.testHandler.postMessage("scrolled");
             } catch(e) { }
         }, 0);
     }
@@ -21,7 +21,7 @@
     function beganAutoplaying() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
             } catch(e) {
             }
         }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -4,7 +4,7 @@
     function beganAutoplaying() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("autoplayed");
+                window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
             } catch(e) {
             }
         }, 0)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -11,7 +11,7 @@
     function finishTest() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("playing");
+                window.webkit.messageHandlers.testHandler.postMessage("playing");
             } catch(e) { }
         }, 0);
     }

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html (206032 => 206033)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html	2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html	2016-09-16 18:14:04 UTC (rev 206033)
@@ -11,7 +11,7 @@
     function finishTest() {
         setTimeout(function() {
             try {
-                window.webkit.messageHandlers.playingHandler.postMessage("playing");
+                window.webkit.messageHandlers.testHandler.postMessage("playing");
             } catch(e) { }
         }, 0);
     }

Copied: trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.h (from rev 206032, trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm) (0 => 206033)


--- trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.h	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.h	2016-09-16 18:14:04 UTC (rev 206033)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 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 TestWKWebViewMac_h
+#define TestWKWebViewMac_h
+
+#import <WebKit/WebKit.h>
+
+#if WK_API_ENABLED && PLATFORM(MAC)
+
+@interface TestMessageHandler : NSObject <WKScriptMessageHandler>
+- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler;
+@end
+
+@interface TestWKWebView : WKWebView
+- (void)mouseDownAtPoint:(NSPoint)point;
+- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action;
+- (void)loadTestPageNamed:(NSString *)pageName;
+- (void)typeCharacter:(char)character;
+- (NSString *)stringByEvaluatingJavaScript:(NSString *)script;
+- (void)waitForMessage:(NSString *)message;
+- (void)performAfterLoading:(dispatch_block_t)actions;
+@end
+
+#endif /* WK_API_ENABLED && PLATFORM(MAC) */
+
+#endif /* TestWKWebViewMac_h */

Added: trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.mm (0 => 206033)


--- trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.mm	2016-09-16 18:14:04 UTC (rev 206033)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 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 "TestWKWebViewMac.h"
+
+#if WK_API_ENABLED && PLATFORM(MAC)
+
+#import "Utilities.h"
+
+#import <AppKit/AppKit.h>
+#import <Carbon/Carbon.h>
+#import <WebKit/WebKitPrivate.h>
+#import <wtf/RetainPtr.h>
+
+@implementation TestMessageHandler {
+    dispatch_block_t _handler;
+    NSString *_message;
+}
+
+- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _handler = [handler copy];
+    _message = message;
+
+    return self;
+}
+
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    if ([(NSString *)[message body] isEqualToString:_message] && _handler)
+        _handler();
+}
+
+@end
+
+@implementation TestWKWebView
+
+- (void)mouseDownAtPoint:(NSPoint)point
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+    NSEventType mouseEventType = NSEventTypeLeftMouseDown;
+#else
+    NSEventType mouseEventType = NSLeftMouseDown;
+#endif
+    [self mouseDown:[NSEvent mouseEventWithType:mouseEventType location:NSMakePoint(point.x, point.y) modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:[NSGraphicsContext currentContext] eventNumber:0 clickCount:0 pressure:0]];
+}
+
+- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action
+{
+    RetainPtr<TestMessageHandler> handler = adoptNS([[TestMessageHandler alloc] initWithMessage:message handler:action]);
+    WKUserContentController* contentController = [[self configuration] userContentController];
+    [contentController removeScriptMessageHandlerForName:@"testHandler"];
+    [contentController addScriptMessageHandler:handler.get() name:@"testHandler"];
+}
+
+- (void)loadTestPageNamed:(NSString *)pageName
+{
+    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:pageName withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    [self loadRequest:request];
+}
+
+- (void)typeCharacter:(char)character {
+    NSString *characterAsString = [NSString stringWithFormat:@"%c" , character];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+    NSEventType keyDownEventType = NSEventTypeKeyDown;
+    NSEventType keyUpEventType = NSEventTypeKeyUp;
+#else
+    NSEventType keyDownEventType = NSKeyDown;
+    NSEventType keyUpEventType = NSKeyUp;
+#endif
+    [self keyDown:[NSEvent keyEventWithType:keyDownEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
+    [self keyUp:[NSEvent keyEventWithType:keyUpEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
+}
+
+- (NSString *)stringByEvaluatingJavaScript:(NSString *)script
+{
+    __block bool isWaitingForJavaScript = false;
+    __block NSString *evalResult = nil;
+    [self evaluateJavaScript:script completionHandler:^(id result, NSError *error)
+    {
+        evalResult = [NSString stringWithFormat:@"%@", result];
+        isWaitingForJavaScript = true;
+        EXPECT_TRUE(!error);
+    }];
+
+    TestWebKitAPI::Util::run(&isWaitingForJavaScript);
+    return evalResult;
+}
+
+- (void)waitForMessage:(NSString *)message
+{
+    __block bool isDoneWaiting = false;
+    [self performAfterReceivingMessage:message action:^()
+    {
+        isDoneWaiting = true;
+    }];
+    TestWebKitAPI::Util::run(&isDoneWaiting);
+}
+
+- (void)performAfterLoading:(dispatch_block_t)actions {
+    TestMessageHandler *handler = [[TestMessageHandler alloc] initWithMessage:@"loaded" handler:actions];
+    NSString *_onloadScript_ = @"window._onload_ = () => window.webkit.messageHandlers.onloadHandler.postMessage('loaded')";
+    WKUserScript *script = [[WKUserScript alloc] initWithSource:onloadScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
+
+    WKUserContentController* contentController = [[self configuration] userContentController];
+    [contentController addUserScript:script];
+    [contentController addScriptMessageHandler:handler name:@"onloadHandler"];
+}
+
+@end
+
+#endif /* WK_API_ENABLED && PLATFORM(MAC) */
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to