Title: [235011] trunk
Revision
235011
Author
[email protected]
Date
2018-08-18 15:59:20 -0700 (Sat, 18 Aug 2018)

Log Message

[iOS] Paste is missing from callout bar when pasteboard only contains custom data
https://bugs.webkit.org/show_bug.cgi?id=184271
<rdar://problem/39256708>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Export a couple of WebCore functions for use in WebKit.

* dom/Document.h:
* platform/Pasteboard.h:

Source/WebKit:

Currently, the "paste:" selector action cannot be performed during editing if the pasteboard only contains
custom pasteboard data. This is because logic in -[WKContentView canPerformActionForWebView:withSender:] only
checks against a list of pasteboard types which does not include the type identifier for custom pasteboard data.
To fix this, we allow pasting only in the case where none of the other type identifiers exist in the pasteboard,
as long as the custom pasteboard data type identifier is present, and the custom pasteboard data's origin
matches the origin of the focused frame's document.

Test: PasteMixedContent.CopyAndPasteWithCustomPasteboardDataOnly

* Shared/EditorState.cpp:
(WebKit::EditorState::encode const):
(WebKit::EditorState::decode):
* Shared/EditorState.h:

Add a originIdentifierForPasteboard field, and add support for encoding it when propagating EditorState via IPC.

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView canPerformActionForWebView:withSender:]):

If none of the conventional pasteboard type identifiers for rich or plain text editing are present, check to see
if we have custom pasteboard data; if so, only allow pasting if the custom pasteboard data's origin matches that
of the focused frame's document origin.

Additionally refactor a bit of logic by pulling out `_page->editorState()` into a separate local variable, used
throughout the rest of the method.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::editorState const):

Send the focused frame's document origin to the UI process via EditorState.

Tools:

Add a new API test to verify that on both iOS and macOS, copied custom pasteboard data can only be pasted in a
matching origin. Additionally verify that on iOS, the web view is capable of performing the "paste:" selector.

* TestWebKitAPI/Tests/WebKitCocoa/PasteMixedContent.mm:
(TestWebKitAPI::TEST):
(imagePath): Deleted.
(writeTypesAndDataToPasteboard): Deleted.
(setUpWebView): Deleted.
(markupString): Deleted.

Make this test file no longer exclusive to macOS.

* TestWebKitAPI/cocoa/TestWKWebView.h:
* TestWebKitAPI/cocoa/TestWKWebView.mm:
(-[TestWKWebView synchronouslyLoadHTMLString:baseURL:]):

Tweak this helper to also take in a `baseURL`. Defaults to using the TestWebKitAPI bundle resource URL.

(-[TestWKWebView synchronouslyLoadHTMLString:]):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (235010 => 235011)


--- trunk/Source/WebCore/ChangeLog	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebCore/ChangeLog	2018-08-18 22:59:20 UTC (rev 235011)
@@ -1,3 +1,16 @@
+2018-08-18  Wenson Hsieh  <[email protected]>
+
+        [iOS] Paste is missing from callout bar when pasteboard only contains custom data
+        https://bugs.webkit.org/show_bug.cgi?id=184271
+        <rdar://problem/39256708>
+
+        Reviewed by Ryosuke Niwa.
+
+        Export a couple of WebCore functions for use in WebKit.
+
+        * dom/Document.h:
+        * platform/Pasteboard.h:
+
 2018-08-17  Ryosuke Niwa  <[email protected]>
 
         Pack booleans in Event into a bitfield

Modified: trunk/Source/WebCore/dom/Document.h (235010 => 235011)


--- trunk/Source/WebCore/dom/Document.h	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebCore/dom/Document.h	2018-08-18 22:59:20 UTC (rev 235011)
@@ -1006,7 +1006,7 @@
     void incDOMTreeVersion() { m_domTreeVersion = ++s_globalTreeVersion; }
     uint64_t domTreeVersion() const { return m_domTreeVersion; }
 
-    String originIdentifierForPasteboard();
+    WEBCORE_EXPORT String originIdentifierForPasteboard();
 
     // XPathEvaluator methods
     WEBCORE_EXPORT ExceptionOr<Ref<XPathExpression>> createExpression(const String& _expression_, RefPtr<XPathNSResolver>&&);

Modified: trunk/Source/WebCore/platform/Pasteboard.h (235010 => 235011)


--- trunk/Source/WebCore/platform/Pasteboard.h	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebCore/platform/Pasteboard.h	2018-08-18 22:59:20 UTC (rev 235011)
@@ -170,7 +170,7 @@
     WEBCORE_EXPORT static PasteboardCustomData fromSharedBuffer(const SharedBuffer&);
 
 #if PLATFORM(COCOA)
-    static const char* cocoaType();
+    WEBCORE_EXPORT static const char* cocoaType();
 #endif
 };
 

Modified: trunk/Source/WebKit/ChangeLog (235010 => 235011)


--- trunk/Source/WebKit/ChangeLog	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebKit/ChangeLog	2018-08-18 22:59:20 UTC (rev 235011)
@@ -1,3 +1,42 @@
+2018-08-18  Wenson Hsieh  <[email protected]>
+
+        [iOS] Paste is missing from callout bar when pasteboard only contains custom data
+        https://bugs.webkit.org/show_bug.cgi?id=184271
+        <rdar://problem/39256708>
+
+        Reviewed by Ryosuke Niwa.
+
+        Currently, the "paste:" selector action cannot be performed during editing if the pasteboard only contains
+        custom pasteboard data. This is because logic in -[WKContentView canPerformActionForWebView:withSender:] only
+        checks against a list of pasteboard types which does not include the type identifier for custom pasteboard data.
+        To fix this, we allow pasting only in the case where none of the other type identifiers exist in the pasteboard,
+        as long as the custom pasteboard data type identifier is present, and the custom pasteboard data's origin
+        matches the origin of the focused frame's document.
+
+        Test: PasteMixedContent.CopyAndPasteWithCustomPasteboardDataOnly
+
+        * Shared/EditorState.cpp:
+        (WebKit::EditorState::encode const):
+        (WebKit::EditorState::decode):
+        * Shared/EditorState.h:
+
+        Add a originIdentifierForPasteboard field, and add support for encoding it when propagating EditorState via IPC.
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView canPerformActionForWebView:withSender:]):
+
+        If none of the conventional pasteboard type identifiers for rich or plain text editing are present, check to see
+        if we have custom pasteboard data; if so, only allow pasting if the custom pasteboard data's origin matches that
+        of the focused frame's document origin.
+
+        Additionally refactor a bit of logic by pulling out `_page->editorState()` into a separate local variable, used
+        throughout the rest of the method.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::editorState const):
+
+        Send the focused frame's document origin to the UI process via EditorState.
+
 2018-08-17  Tim Horton  <[email protected]>
 
         Start bringing up Unified Sources in WebKit2

Modified: trunk/Source/WebKit/Shared/EditorState.cpp (235010 => 235011)


--- trunk/Source/WebKit/Shared/EditorState.cpp	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebKit/Shared/EditorState.cpp	2018-08-18 22:59:20 UTC (rev 235011)
@@ -53,6 +53,8 @@
     encoder << lastMarkedRect;
     encoder << markedText;
 #endif
+
+    encoder << originIdentifierForPasteboard;
 }
 
 bool EditorState::decode(IPC::Decoder& decoder, EditorState& result)
@@ -98,6 +100,9 @@
         return false;
 #endif
 
+    if (!decoder.decode(result.originIdentifierForPasteboard))
+        return false;
+
     return true;
 }
 

Modified: trunk/Source/WebKit/Shared/EditorState.h (235010 => 235011)


--- trunk/Source/WebKit/Shared/EditorState.h	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebKit/Shared/EditorState.h	2018-08-18 22:59:20 UTC (rev 235011)
@@ -80,6 +80,8 @@
     String markedText;
 #endif
 
+    String originIdentifierForPasteboard;
+
     struct PostLayoutData {
         uint32_t typingAttributes { AttributeNone };
 #if PLATFORM(IOS) || PLATFORM(GTK)

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (235010 => 235011)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-08-18 22:59:20 UTC (rev 235011)
@@ -2276,35 +2276,49 @@
     if (action == @selector(_arrowKey:))
         return [self isFirstResponder];
         
+    auto editorState = _page->editorState();
     if (action == @selector(_showTextStyleOptions:))
-        return _page->editorState().isContentRichlyEditable && _page->editorState().selectionIsRange && !_showingTextStyleOptions;
+        return editorState.isContentRichlyEditable && editorState.selectionIsRange && !_showingTextStyleOptions;
     if (_showingTextStyleOptions)
         return (action == @selector(toggleBoldface:) || action == @selector(toggleItalics:) || action == @selector(toggleUnderline:));
     if (action == @selector(toggleBoldface:) || action == @selector(toggleItalics:) || action == @selector(toggleUnderline:))
-        return _page->editorState().isContentRichlyEditable;
+        return editorState.isContentRichlyEditable;
     if (action == @selector(cut:))
-        return !_page->editorState().isInPasswordField && _page->editorState().isContentEditable && _page->editorState().selectionIsRange;
+        return !editorState.isInPasswordField && editorState.isContentEditable && editorState.selectionIsRange;
     
     if (action == @selector(paste:)) {
-        if (_page->editorState().selectionIsNone || !_page->editorState().isContentEditable)
+        if (editorState.selectionIsNone || !editorState.isContentEditable)
             return NO;
         UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
         NSArray *types = [self supportedPasteboardTypesForCurrentSelection];
         NSIndexSet *indices = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pasteboard numberOfItems])];
-        return [pasteboard containsPasteboardTypes:types inItemSet:indices];
+        if ([pasteboard containsPasteboardTypes:types inItemSet:indices])
+            return YES;
+
+        auto focusedDocumentOrigin = editorState.originIdentifierForPasteboard;
+        if (focusedDocumentOrigin.isEmpty())
+            return NO;
+
+        NSArray *allCustomPasteboardData = [pasteboard dataForPasteboardType:@(PasteboardCustomData::cocoaType()) inItemSet:indices];
+        for (NSData *data in allCustomPasteboardData) {
+            auto buffer = SharedBuffer::create(data);
+            if (PasteboardCustomData::fromSharedBuffer(buffer.get()).origin == focusedDocumentOrigin)
+                return YES;
+        }
+        return NO;
     }
 
     if (action == @selector(copy:)) {
-        if (_page->editorState().isInPasswordField)
+        if (editorState.isInPasswordField)
             return NO;
-        return _page->editorState().selectionIsRange;
+        return editorState.selectionIsRange;
     }
 
     if (action == @selector(_define:)) {
-        if (_page->editorState().isInPasswordField || !_page->editorState().selectionIsRange)
+        if (editorState.isInPasswordField || !editorState.selectionIsRange)
             return NO;
 
-        NSUInteger textLength = _page->editorState().postLayoutData().selectedTextLength;
+        NSUInteger textLength = editorState.postLayoutData().selectedTextLength;
         // FIXME: We should be calling UIReferenceLibraryViewController to check if the length is
         // acceptable, but the interface takes a string.
         // <rdar://problem/15254406>
@@ -2320,7 +2334,7 @@
     }
 
     if (action == @selector(_lookup:)) {
-        if (_page->editorState().isInPasswordField)
+        if (editorState.isInPasswordField)
             return NO;
 
 #if !PLATFORM(IOSMAC)
@@ -2328,18 +2342,18 @@
             return NO;
 #endif
 
-        return _page->editorState().selectionIsRange;
+        return editorState.selectionIsRange;
     }
 
     if (action == @selector(_share:)) {
-        if (_page->editorState().isInPasswordField || !_page->editorState().selectionIsRange)
+        if (editorState.isInPasswordField || !editorState.selectionIsRange)
             return NO;
 
-        return _page->editorState().postLayoutData().selectedTextLength > 0;
+        return editorState.postLayoutData().selectedTextLength > 0;
     }
 
     if (action == @selector(_addShortcut:)) {
-        if (_page->editorState().isInPasswordField || !_page->editorState().selectionIsRange)
+        if (editorState.isInPasswordField || !editorState.selectionIsRange)
             return NO;
 
         NSString *selectedText = [self selectedText];
@@ -2354,7 +2368,7 @@
     }
 
     if (action == @selector(_promptForReplace:)) {
-        if (!_page->editorState().selectionIsRange || !_page->editorState().postLayoutData().isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
+        if (!editorState.selectionIsRange || !editorState.postLayoutData().isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
             return NO;
         if ([[self selectedText] _containsCJScriptsOnly])
             return NO;
@@ -2362,7 +2376,7 @@
     }
 
     if (action == @selector(_transliterateChinese:)) {
-        if (!_page->editorState().selectionIsRange || !_page->editorState().postLayoutData().isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
+        if (!editorState.selectionIsRange || !editorState.postLayoutData().isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
             return NO;
         return UIKeyboardEnabledInputModesAllowChineseTransliterationForText([self selectedText]);
     }
@@ -2369,17 +2383,17 @@
 
     if (action == @selector(select:)) {
         // Disable select in password fields so that you can't see word boundaries.
-        return !_page->editorState().isInPasswordField && [self hasContent] && !_page->editorState().selectionIsNone && !_page->editorState().selectionIsRange;
+        return !editorState.isInPasswordField && [self hasContent] && !editorState.selectionIsNone && !editorState.selectionIsRange;
     }
 
     if (action == @selector(selectAll:)) {
-        if (!_page->editorState().selectionIsNone && !_page->editorState().selectionIsRange)
+        if (!editorState.selectionIsNone && !editorState.selectionIsRange)
             return YES;
         return NO;
     }
 
     if (action == @selector(replace:))
-        return _page->editorState().isContentEditable && !_page->editorState().isInPasswordField;
+        return editorState.isContentEditable && !editorState.isInPasswordField;
 
     return [super canPerformAction:action withSender:sender];
 }

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (235010 => 235011)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-08-18 22:59:20 UTC (rev 235011)
@@ -921,6 +921,9 @@
     result.hasComposition = editor.hasComposition();
     result.shouldIgnoreSelectionChanges = editor.ignoreSelectionChanges();
 
+    if (auto* document = frame.document())
+        result.originIdentifierForPasteboard = document->originIdentifierForPasteboard();
+
     bool canIncludePostLayoutData = frame.view() && !frame.view()->needsLayout();
     if (shouldIncludePostLayoutData == IncludePostLayoutDataHint::Yes && canIncludePostLayoutData) {
         auto& postLayoutData = result.postLayoutData();

Modified: trunk/Tools/ChangeLog (235010 => 235011)


--- trunk/Tools/ChangeLog	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Tools/ChangeLog	2018-08-18 22:59:20 UTC (rev 235011)
@@ -1,3 +1,31 @@
+2018-08-18  Wenson Hsieh  <[email protected]>
+
+        [iOS] Paste is missing from callout bar when pasteboard only contains custom data
+        https://bugs.webkit.org/show_bug.cgi?id=184271
+        <rdar://problem/39256708>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add a new API test to verify that on both iOS and macOS, copied custom pasteboard data can only be pasted in a
+        matching origin. Additionally verify that on iOS, the web view is capable of performing the "paste:" selector.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/PasteMixedContent.mm:
+        (TestWebKitAPI::TEST):
+        (imagePath): Deleted.
+        (writeTypesAndDataToPasteboard): Deleted.
+        (setUpWebView): Deleted.
+        (markupString): Deleted.
+
+        Make this test file no longer exclusive to macOS.
+
+        * TestWebKitAPI/cocoa/TestWKWebView.h:
+        * TestWebKitAPI/cocoa/TestWKWebView.mm:
+        (-[TestWKWebView synchronouslyLoadHTMLString:baseURL:]):
+
+        Tweak this helper to also take in a `baseURL`. Defaults to using the TestWebKitAPI bundle resource URL.
+
+        (-[TestWKWebView synchronouslyLoadHTMLString:]):
+
 2018-08-17  Jonathan Bedard  <[email protected]>
 
         Add back --wtf-only to run-api-tests

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteMixedContent.mm (235010 => 235011)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteMixedContent.mm	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteMixedContent.mm	2018-08-18 22:59:20 UTC (rev 235011)
@@ -25,15 +25,21 @@
 
 #include "config.h"
 
-#if PLATFORM(MAC) && WK_API_ENABLED
+#if WK_API_ENABLED
 
 #import "PlatformUtilities.h"
+#import "TestURLSchemeHandler.h"
 #import "TestWKWebView.h"
 #import <WebKit/WKPreferencesRef.h>
 #import <WebKit/WKPreferencesRefPrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
 #import <wtf/RetainPtr.h>
 #import <wtf/text/WTFString.h>
 
+namespace TestWebKitAPI {
+
+#if PLATFORM(MAC)
+
 static NSString *imagePath()
 {
     return [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png" inDirectory:@"TestWebKitAPI.resources"];
@@ -96,8 +102,6 @@
     return @"<script>foo()</script><strong _onmouseover_='_javascript_:void(0)'>HELLO WORLD</strong>";
 }
 
-namespace TestWebKitAPI {
-
 TEST(PasteMixedContent, ImageFileAndPlainText)
 {
     auto webView = setUpWebView();
@@ -251,6 +255,39 @@
     EXPECT_WK_STREQ([webView stringByEvaluatingJavaScript:@"document.querySelector('a').textContent"], urlToCopy);
 }
 
+#endif // PLATFORM(MAC)
+
+TEST(PasteMixedContent, CopyAndPasteWithCustomPasteboardDataOnly)
+{
+    NSString *markupForSource = @"<body _oncopy_=\"event.preventDefault(); event.clipboardData.setData('foo', 'bar')\">hello</body>";
+    NSString *markupForDestination = @"<input autofocus _onpaste_=\"event.preventDefault(); this.value = event.clipboardData.getData('foo')\">";
+
+    auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"same"];
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"different"];
+
+    auto source = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]);
+    [source synchronouslyLoadHTMLString:markupForSource baseURL:[NSURL URLWithString:@"same://"]];
+    [source selectAll:nil];
+    [source _executeEditCommand:@"copy" argument:nil completion:nil];
+
+    auto destination = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]);
+    [destination synchronouslyLoadHTMLString:markupForDestination baseURL:[NSURL URLWithString:@"same://"]];
+    [destination paste:nil];
+    EXPECT_WK_STREQ("bar", [destination stringByEvaluatingJavaScript:@"document.querySelector('input').value"]);
+#if PLATFORM(IOS)
+    EXPECT_TRUE([destination canPerformAction:@selector(paste:) withSender:nil]);
+#endif
+
+    [destination synchronouslyLoadHTMLString:markupForDestination baseURL:[NSURL URLWithString:@"different://"]];
+    [destination paste:nil];
+    EXPECT_WK_STREQ("", [destination stringByEvaluatingJavaScript:@"document.querySelector('input').value"]);
+#if PLATFORM(IOS)
+    EXPECT_FALSE([destination canPerformAction:@selector(paste:) withSender:nil]);
+#endif
+}
+
 } // namespace TestWebKitAPI
 
-#endif // PLATFORM(MAC) && WK_API_ENABLED
+#endif // WK_API_ENABLED

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (235010 => 235011)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2018-08-18 22:59:20 UTC (rev 235011)
@@ -51,6 +51,7 @@
 - (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action;
 - (void)loadTestPageNamed:(NSString *)pageName;
 - (void)synchronouslyLoadHTMLString:(NSString *)html;
+- (void)synchronouslyLoadHTMLString:(NSString *)html baseURL:(NSURL *)url;
 - (void)synchronouslyLoadTestPageNamed:(NSString *)pageName;
 - (id)objectByEvaluatingJavaScript:(NSString *)script;
 - (NSString *)stringByEvaluatingJavaScript:(NSString *)script;

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (235010 => 235011)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2018-08-18 15:00:12 UTC (rev 235010)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2018-08-18 22:59:20 UTC (rev 235011)
@@ -246,13 +246,17 @@
     [self loadRequest:request];
 }
 
-- (void)synchronouslyLoadHTMLString:(NSString *)html
+- (void)synchronouslyLoadHTMLString:(NSString *)html baseURL:(NSURL *)url
 {
-    NSURL *testResourceURL = [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"TestWebKitAPI.resources"];
-    [self loadHTMLString:html baseURL:testResourceURL];
+    [self loadHTMLString:html baseURL:url];
     [self _test_waitForDidFinishNavigation];
 }
 
+- (void)synchronouslyLoadHTMLString:(NSString *)html
+{
+    [self synchronouslyLoadHTMLString:html baseURL:[[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"TestWebKitAPI.resources"]];
+}
+
 - (void)synchronouslyLoadTestPageNamed:(NSString *)pageName
 {
     [self loadTestPageNamed:pageName];
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to