[iOS] Cmd-C doesn't copy text from WKWebView
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Jun 2017 22:28:25 +0000 (22:28 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Jun 2017 22:28:25 +0000 (22:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173277
<rdar://problem/32396742>

Reviewed by Dan Bernstein.

* UIProcess/API/Cocoa/WKWebView.mm:
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _lookupForWebView:]):
(-[WKContentView _shareForWebView:]):
(-[WKContentView _addShortcutForWebView:]):
(-[WKContentView _promptForReplaceForWebView:]):
(-[WKContentView _transliterateChineseForWebView:]):
(-[WKContentView _reanalyzeForWebView:]):
(-[WKContentView replaceForWebView:]):
(-[WKContentView canPerformAction:withSender:]):
(-[WKContentView copyForWebView:]):
(-[WKContentView cutForWebView:]):
(-[WKContentView pasteForWebView:]):
(-[WKContentView selectForWebView:]):
(-[WKContentView selectAllForWebView:]):
(-[WKContentView toggleBoldfaceForWebView:]):
(-[WKContentView toggleItalicsForWebView:]):
(-[WKContentView toggleUnderlineForWebView:]):
(-[WKContentView _showTextStyleOptionsForWebView:]):
(-[WKContentView _defineForWebView:]):
(-[WKContentView _arrowKeyForWebView:]):
(-[WKContentView _lookup:]): Deleted.
(-[WKContentView _share:]): Deleted.
(-[WKContentView _addShortcut:]): Deleted.
(-[WKContentView _promptForReplace:]): Deleted.
(-[WKContentView _transliterateChinese:]): Deleted.
(-[WKContentView _reanalyze:]): Deleted.
(-[WKContentView replace:]): Deleted.
(-[WKContentView copy:]): Deleted.
(-[WKContentView cut:]): Deleted.
(-[WKContentView paste:]): Deleted.
(-[WKContentView select:]): Deleted.
(-[WKContentView selectAll:]): Deleted.
(-[WKContentView toggleBoldface:]): Deleted.
(-[WKContentView toggleItalics:]): Deleted.
(-[WKContentView toggleUnderline:]): Deleted.
(-[WKContentView _showTextStyleOptions:]): Deleted.
(-[WKContentView _define:]): Deleted.
(-[WKContentView _arrowKey:]): Deleted.
Similar to what r211897 did for canPerformAction, and other patches
have done for other selectors, forward methods for standard editing
commands from WKContentView up to WKWebView, and back down to WKContentView.

This is necessary because these are not treated as normal
responder-chain-respecting methods, so they do not bubble up the view tree.

In 211897, WKContentView (who is usually first responder and thus receives
the actions) stopped claiming to be able to perform these actions, depending
on this non-existent bubbling behavior to keep them working.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* Tests/WebKit2Cocoa/WKContentViewEditingActions.mm:
Add a test ensuring that -copy on WKContentView will cause text to be copied.

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

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKContentViewEditingActions.mm [new file with mode: 0644]

index 859925c..0b5fcf7 100644 (file)
@@ -1,3 +1,63 @@
+2017-06-12  Tim Horton  <timothy_horton@apple.com>
+
+        [iOS] Cmd-C doesn't copy text from WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=173277
+        <rdar://problem/32396742>
+
+        Reviewed by Dan Bernstein.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        * UIProcess/API/Cocoa/WKWebViewInternal.h:
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView _lookupForWebView:]):
+        (-[WKContentView _shareForWebView:]):
+        (-[WKContentView _addShortcutForWebView:]):
+        (-[WKContentView _promptForReplaceForWebView:]):
+        (-[WKContentView _transliterateChineseForWebView:]):
+        (-[WKContentView _reanalyzeForWebView:]):
+        (-[WKContentView replaceForWebView:]):
+        (-[WKContentView canPerformAction:withSender:]):
+        (-[WKContentView copyForWebView:]):
+        (-[WKContentView cutForWebView:]):
+        (-[WKContentView pasteForWebView:]):
+        (-[WKContentView selectForWebView:]):
+        (-[WKContentView selectAllForWebView:]):
+        (-[WKContentView toggleBoldfaceForWebView:]):
+        (-[WKContentView toggleItalicsForWebView:]):
+        (-[WKContentView toggleUnderlineForWebView:]):
+        (-[WKContentView _showTextStyleOptionsForWebView:]):
+        (-[WKContentView _defineForWebView:]):
+        (-[WKContentView _arrowKeyForWebView:]):
+        (-[WKContentView _lookup:]): Deleted.
+        (-[WKContentView _share:]): Deleted.
+        (-[WKContentView _addShortcut:]): Deleted.
+        (-[WKContentView _promptForReplace:]): Deleted.
+        (-[WKContentView _transliterateChinese:]): Deleted.
+        (-[WKContentView _reanalyze:]): Deleted.
+        (-[WKContentView replace:]): Deleted.
+        (-[WKContentView copy:]): Deleted.
+        (-[WKContentView cut:]): Deleted.
+        (-[WKContentView paste:]): Deleted.
+        (-[WKContentView select:]): Deleted.
+        (-[WKContentView selectAll:]): Deleted.
+        (-[WKContentView toggleBoldface:]): Deleted.
+        (-[WKContentView toggleItalics:]): Deleted.
+        (-[WKContentView toggleUnderline:]): Deleted.
+        (-[WKContentView _showTextStyleOptions:]): Deleted.
+        (-[WKContentView _define:]): Deleted.
+        (-[WKContentView _arrowKey:]): Deleted.
+        Similar to what r211897 did for canPerformAction, and other patches
+        have done for other selectors, forward methods for standard editing
+        commands from WKContentView up to WKWebView, and back down to WKContentView.
+
+        This is necessary because these are not treated as normal
+        responder-chain-respecting methods, so they do not bubble up the view tree.
+        
+        In 211897, WKContentView (who is usually first responder and thus receives
+        the actions) stopped claiming to be able to perform these actions, depending
+        on this non-existent bubbling behavior to keep them working.
+
 2017-06-12  Chris Dumez  <cdumez@apple.com>
 
         Null dereference under WebProcessPool::pageRemovedFromProcess()
index 17405ee..445609d 100644 (file)
@@ -1149,31 +1149,11 @@ static WKErrorCode callbackErrorCode(WebKit::CallbackBase::Error error)
     return [super resignFirstResponder];
 }
 
-#define FOR_EACH_WKCONTENTVIEW_ACTION(M) \
-    M(_addShortcut) \
-    M(_arrowKey) \
-    M(_define) \
-    M(_lookup) \
-    M(_promptForReplace) \
-    M(_reanalyze) \
-    M(_share) \
-    M(_showTextStyleOptions) \
-    M(_transliterateChinese) \
-    M(copy) \
-    M(cut) \
-    M(paste) \
-    M(replace) \
-    M(select) \
-    M(selectAll) \
-    M(toggleBoldface) \
-    M(toggleItalics) \
-    M(toggleUnderline) \
-
 #define FORWARD_ACTION_TO_WKCONTENTVIEW(_action) \
     - (void)_action:(id)sender \
     { \
         if (self.usesStandardContentView) \
-            [_contentView _action:sender]; \
+            [_contentView _action ## ForWebView:sender]; \
     }
 
 FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKCONTENTVIEW)
@@ -1193,8 +1173,6 @@ FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKCONTENTVIEW)
     return [super canPerformAction:action withSender:sender];
 }
 
-#undef FOR_EACH_WKCONTENTVIEW_ACTION
-
 static inline CGFloat floorToDevicePixel(CGFloat input, float deviceScaleFactor)
 {
     return CGFloor(input * deviceScaleFactor) / deviceScaleFactor;
index 5293807..c60cc63 100644 (file)
@@ -121,6 +121,17 @@ struct PrintInfo;
 
 - (void)_didChangeAvoidsUnsafeArea:(BOOL)avoidsUnsafeArea;
 
+- (void)_addShortcut:(id)sender;
+- (void)_arrowKey:(id)sender;
+- (void)_define:(id)sender;
+- (void)_lookup:(id)sender;
+- (void)_reanalyze:(id)sender;
+- (void)_share:(id)sender;
+- (void)_showTextStyleOptions:(id)sender;
+- (void)_promptForReplace:(id)sender;
+- (void)_transliterateChinese:(id)sender;
+- (void)replace:(id)sender;
+
 @property (nonatomic, readonly) WKPasswordView *_passwordView;
 
 @property (nonatomic, readonly) BOOL _isBackground;
index e82b573..fc94e52 100644 (file)
@@ -89,6 +89,26 @@ typedef void (^UIWKKeyWebEventCompletionHandler)(::WebEvent *theEvent, BOOL wasH
 typedef BlockPtr<void(WebKit::InteractionInformationAtPosition)> InteractionInformationCallback;
 typedef std::pair<WebKit::InteractionInformationRequest, InteractionInformationCallback> InteractionInformationRequestAndCallback;
 
+#define FOR_EACH_WKCONTENTVIEW_ACTION(M) \
+    M(_addShortcut) \
+    M(_arrowKey) \
+    M(_define) \
+    M(_lookup) \
+    M(_promptForReplace) \
+    M(_reanalyze) \
+    M(_share) \
+    M(_showTextStyleOptions) \
+    M(_transliterateChinese) \
+    M(copy) \
+    M(cut) \
+    M(paste) \
+    M(replace) \
+    M(select) \
+    M(selectAll) \
+    M(toggleBoldface) \
+    M(toggleItalics) \
+    M(toggleUnderline)
+
 namespace WebKit {
 
 struct WKSelectionDrawingInfo {
@@ -236,16 +256,10 @@ struct WKAutoCorrectionData {
 - (BOOL)resignFirstResponderForWebView;
 - (BOOL)canPerformActionForWebView:(SEL)action withSender:(id)sender;
 
-- (void)_addShortcut:(id)sender;
-- (void)_arrowKey:(id)sender;
-- (void)_define:(id)sender;
-- (void)_lookup:(id)sender;
-- (void)_reanalyze:(id)sender;
-- (void)_share:(id)sender;
-- (void)_showTextStyleOptions:(id)sender;
-- (void)_promptForReplace:(id)sender;
-- (void)_transliterateChinese:(id)sender;
-- (void)replace:(id)sender;
+#define DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW(_action) \
+    - (void)_action ## ForWebView:(id)sender;
+FOR_EACH_WKCONTENTVIEW_ACTION(DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW)
+#undef DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW
 
 #if ENABLE(TOUCH_EVENTS)
 - (void)_webTouchEvent:(const WebKit::NativeWebTouchEvent&)touchEvent preventsNativeGestures:(BOOL)preventsDefault;
index 415a65c..b64ab35 100644 (file)
@@ -1902,7 +1902,17 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     return (_page->editorState().isContentRichlyEditable) ? richTypes : plainTextTypes;
 }
 
-- (void)_lookup:(id)sender
+#define FORWARD_ACTION_TO_WKWEBVIEW(_action) \
+    - (void)_action:(id)sender \
+    { \
+        [_webView _action:sender]; \
+    }
+
+FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKWEBVIEW)
+
+#undef FORWARD_ACTION_TO_WKWEBVIEW
+
+- (void)_lookupForWebView:(id)sender
 {
     RetainPtr<WKContentView> view = self;
     _page->getSelectionContext([view](const String& selectedText, const String& textBefore, const String& textAfter, CallbackBase::Error error) {
@@ -1922,7 +1932,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     });
 }
 
-- (void)_share:(id)sender
+- (void)_shareForWebView:(id)sender
 {
     RetainPtr<WKContentView> view = self;
     _page->getSelectionOrContentsAsString([view](const String& string, CallbackBase::Error error) {
@@ -1940,7 +1950,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     });
 }
 
-- (void)_addShortcut:(id)sender
+- (void)_addShortcutForWebView:(id)sender
 {
     if (_textSelectionAssistant)
         [_textSelectionAssistant showTextServiceFor:[self selectedText] fromRect:_page->editorState().postLayoutData().selectionRects[0].rect()];
@@ -1968,7 +1978,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     _page->selectWordBackward();
 }
 
-- (void)_promptForReplace:(id)sender
+- (void)_promptForReplaceForWebView:(id)sender
 {
     const auto& wordAtSelection = _page->editorState().postLayoutData().wordAtSelection;
     if (wordAtSelection.isEmpty())
@@ -1977,17 +1987,17 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     [_textSelectionAssistant scheduleReplacementsForText:wordAtSelection];
 }
 
-- (void)_transliterateChinese:(id)sender
+- (void)_transliterateChineseForWebView:(id)sender
 {
     [_textSelectionAssistant scheduleChineseTransliterationForText:_page->editorState().postLayoutData().wordAtSelection];
 }
 
-- (void)_reanalyze:(id)sender
+- (void)_reanalyzeForWebView:(id)sender
 {
     [_textSelectionAssistant scheduleReanalysis];
 }
 
-- (void)replace:(id)sender
+- (void)replaceForWebView:(id)sender
 {
     [[UIKeyboardImpl sharedInstance] replaceText:sender];
 }
@@ -2030,7 +2040,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
 
 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
 {
-    return NO;
+    return [_webView canPerformAction:action withSender:sender];
 }
 
 - (BOOL)canPerformActionForWebView:(SEL)action withSender:(id)sender
@@ -2166,35 +2176,35 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     [_textSelectionAssistant hideTextStyleOptions];
 }
 
-- (void)copy:(id)sender
+- (void)copyForWebView:(id)sender
 {
     _page->executeEditCommand(ASCIILiteral("copy"));
 }
 
-- (void)cut:(id)sender
+- (void)cutForWebView:(id)sender
 {
     _page->executeEditCommand(ASCIILiteral("cut"));
 }
 
-- (void)paste:(id)sender
+- (void)pasteForWebView:(id)sender
 {
     _page->executeEditCommand(ASCIILiteral("paste"));
 }
 
-- (void)select:(id)sender
+- (void)selectForWebView:(id)sender
 {
     [_textSelectionAssistant selectWord];
     // We cannot use selectWord command, because we want to be able to select the word even when it is the last in the paragraph.
     _page->extendSelection(WordGranularity);
 }
 
-- (void)selectAll:(id)sender
+- (void)selectAllForWebView:(id)sender
 {
     [_textSelectionAssistant selectAll:sender];
     _page->executeEditCommand(ASCIILiteral("selectAll"));
 }
 
-- (void)toggleBoldface:(id)sender
+- (void)toggleBoldfaceForWebView:(id)sender
 {
     if (!_page->editorState().isContentRichlyEditable)
         return;
@@ -2202,7 +2212,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     [self executeEditCommandWithCallback:@"toggleBold"];
 }
 
-- (void)toggleItalics:(id)sender
+- (void)toggleItalicsForWebView:(id)sender
 {
     if (!_page->editorState().isContentRichlyEditable)
         return;
@@ -2210,7 +2220,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     [self executeEditCommandWithCallback:@"toggleItalic"];
 }
 
-- (void)toggleUnderline:(id)sender
+- (void)toggleUnderlineForWebView:(id)sender
 {
     if (!_page->editorState().isContentRichlyEditable)
         return;
@@ -2218,7 +2228,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
     [self executeEditCommandWithCallback:@"toggleUnderline"];
 }
 
-- (void)_showTextStyleOptions:(id)sender
+- (void)_showTextStyleOptionsForWebView:(id)sender
 {
     _showingTextStyleOptions = YES;
     [_textSelectionAssistant showTextStyleOptions];
@@ -2233,7 +2243,7 @@ static void cancelPotentialTapIfNecessary(WKContentView* contentView)
         [_webSelectionAssistant showDictionaryFor:text fromRect:presentationRect];
 }
 
-- (void)_define:(id)sender
+- (void)_defineForWebView:(id)sender
 {
     if ([[getMCProfileConnectionClass() sharedConnection] effectiveBoolValueForSetting:MCFeatureDefinitionLookupAllowed] == MCRestrictedBoolExplicitNo)
         return;
@@ -2829,7 +2839,7 @@ static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoi
     return (_page->editorState().isContentEditable) ? editableKeyCommands : nonEditableKeyCommands;
 }
 
-- (void)_arrowKey:(id)sender
+- (void)_arrowKeyForWebView:(id)sender
 {
     UIKeyCommand* command = sender;
     [self handleKeyEvent:command._triggeringEvent];
index 3044229..45ffb2a 100644 (file)
@@ -1,3 +1,15 @@
+2017-06-12  Tim Horton  <timothy_horton@apple.com>
+
+        [iOS] Cmd-C doesn't copy text from WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=173277
+        <rdar://problem/32396742>
+
+        Reviewed by Dan Bernstein.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * Tests/WebKit2Cocoa/WKContentViewEditingActions.mm:
+        Add a test ensuring that -copy on WKContentView will cause text to be copied.
+
 2017-06-12  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebCrypto] Remove experimental feature flag of SubtleCrypto
index 32e3ad8..7c28d40 100644 (file)
@@ -67,6 +67,7 @@
                2D1C04A71D76298B000A6816 /* TestNavigationDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D1C04A61D76298B000A6816 /* TestNavigationDelegate.mm */; };
                2D4CF8BD1D8360CC0001CE8D /* WKThumbnailView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D4CF8BC1D8360CC0001CE8D /* WKThumbnailView.mm */; };
                2D51A0C71C8BF00C00765C45 /* DOMHTMLVideoElementWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D51A0C51C8BF00400765C45 /* DOMHTMLVideoElementWrapper.mm */; };
+               2D838B1F1EEF3A5C009B980E /* WKContentViewEditingActions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D838B1E1EEF3A5B009B980E /* WKContentViewEditingActions.mm */; };
                2DB0232F1E4E871800707123 /* InteractionDeadlockAfterCrash.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DB0232E1E4E871800707123 /* InteractionDeadlockAfterCrash.mm */; };
                2DC4CF771D2D9DD800ECCC94 /* DataDetection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DC4CF761D2D9DD800ECCC94 /* DataDetection.mm */; };
                2DC60E231E79F88C00FA6C7D /* DoAfterNextPresentationUpdateAfterCrash.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DC60E221E79F88C00FA6C7D /* DoAfterNextPresentationUpdateAfterCrash.mm */; };
                2D51A0C51C8BF00400765C45 /* DOMHTMLVideoElementWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMHTMLVideoElementWrapper.mm; sourceTree = "<group>"; };
                2D640B5417875DFF00BFAF99 /* ScrollPinningBehaviors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollPinningBehaviors.cpp; sourceTree = "<group>"; };
                2D8104CB1BEC13E70020DA46 /* FindInPage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FindInPage.mm; sourceTree = "<group>"; };
+               2D838B1E1EEF3A5B009B980E /* WKContentViewEditingActions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKContentViewEditingActions.mm; sourceTree = "<group>"; };
                2D9A53AE1B31FA8D0074D5AA /* ShrinkToFit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ShrinkToFit.mm; sourceTree = "<group>"; };
                2DB0232E1E4E871800707123 /* InteractionDeadlockAfterCrash.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InteractionDeadlockAfterCrash.mm; sourceTree = "<group>"; };
                2DC4CF761D2D9DD800ECCC94 /* DataDetection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DataDetection.mm; sourceTree = "<group>"; };
                                5120C83C1E6750790025B250 /* WebsiteDataStoreCustomPaths.mm */,
                                5C9E56841DF9143D00C9EE33 /* WebsitePolicies.mm */,
                                1F83571A1D3FFB0E00E3967B /* WKBackForwardList.mm */,
+                               2D838B1E1EEF3A5B009B980E /* WKContentViewEditingActions.mm */,
                                51D124971E763AF8002B2820 /* WKHTTPCookieStore.mm */,
                                375E0E151D66674400EFEC2C /* WKNSNumber.mm */,
                                37B47E2E1D64E7CA005F4EFF /* WKObject.mm */,
                                2D51A0C71C8BF00C00765C45 /* DOMHTMLVideoElementWrapper.mm in Sources */,
                                46397B951DC2C850009A78AE /* DOMNode.mm in Sources */,
                                5198A2401EA7E59F008910B7 /* InitialWarmedProcessUsed.mm in Sources */,
+                               2D838B1F1EEF3A5C009B980E /* WKContentViewEditingActions.mm in Sources */,
                                7CCE7EBC1A411A7E00447C4C /* DOMNodeFromJSObject.mm in Sources */,
                                7CCE7EBD1A411A7E00447C4C /* DOMRangeOfString.mm in Sources */,
                                115EB3431EE0BA03003C2C0A /* ViewportSizeForViewportUnits.mm in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKContentViewEditingActions.mm b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKContentViewEditingActions.mm
new file mode 100644 (file)
index 0000000..3424945
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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 PLATFORM(IOS)
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import "TestNavigationDelegate.h"
+#import "TestWKWebView.h"
+#import <WebKit/WebKit.h>
+#import <wtf/RetainPtr.h>
+
+static UIView *recursiveFindWKContentView(UIView *view)
+{
+    if ([view isKindOfClass:NSClassFromString(@"WKContentView")])
+        return view;
+
+    for (UIView *subview in view.subviews) {
+        UIView *contentView = recursiveFindWKContentView(subview);
+        if (contentView)
+            return contentView;
+    }
+
+    return nil;
+}
+
+TEST(WebKit2, WKContentViewEditingActions)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+
+    [webView synchronouslyLoadTestPageNamed:@"simple"];
+
+    UIView *contentView = recursiveFindWKContentView(webView.get());
+
+    if ([contentView canPerformAction:@selector(selectAll:) withSender:nil])
+        [contentView selectAll:nil];
+    [webView _doAfterNextPresentationUpdate:^ {
+        if ([contentView canPerformAction:@selector(copy:) withSender:nil])
+            [contentView copy:nil];
+    }];
+
+    while (1) {
+        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+        if ([[[UIPasteboard generalPasteboard] string] isEqualToString:@"Simple HTML file."])
+            break;
+        TestWebKitAPI::Util::sleep(0.01);
+    }
+}
+
+#endif