Changeset 226396 in webkit


Ignore:
Timestamp:
Jan 3, 2018 11:44:55 PM (6 years ago)
Author:
Wenson Hsieh
Message:

[Attachment Support] Create attachment elements when dropping files on iOS
https://bugs.webkit.org/show_bug.cgi?id=181192
<rdar://problem/36280945>

Reviewed by Tim Horton.

Source/WebCore:

Implements support for dropping data as attachment elements on iOS. See comments below for more detail.

Tests: WKAttachmentTests.InsertDroppedRichAndPlainTextFilesAsAttachments

WKAttachmentTests.InsertDroppedZipArchiveAsAttachment
WKAttachmentTests.InsertDroppedItemProvidersInOrder

  • WebCore.xcodeproj/project.pbxproj:
  • editing/WebContentReader.cpp:

(WebCore::WebContentReader::ensureFragment):

Add a new helper to create the WebContentReader's fragment, if it hasn't already been created.

  • editing/WebContentReader.h:
  • editing/cocoa/WebContentReaderCocoa.mm:

(WebCore::WebContentReader::readFilePaths):

Rename readFilenames to readFilePaths (which better reflects its parameters, which are file paths). Also, move
the implementation of readFilePaths to shared iOS/macOS code in WebContentReaderCocoa, and remove the stub
implementation on iOS.

There's a bit of code here that I kept macOS-only which deals with inserting file paths as plain text in
editable areas, but it's unclear to me why and if WebKit clients currently find this useful, so I left a FIXME
to investigate removing this altogether. Code for handling this plain text insertion of file paths on Mac was
introduced in r67403.

  • editing/ios/WebContentReaderIOS.mm:

(WebCore::WebContentReader::readFilenames): Deleted.

  • editing/mac/WebContentReaderMac.mm:

(WebCore::WebContentReader::readFilenames): Deleted.

  • page/mac/DragControllerMac.mm:

(WebCore::DragController::updateSupportedTypeIdentifiersForDragHandlingMethod const):

Teach DragController to accept all types conforming to "public.item" and "public.content" on iOS, only when
attachment elements are enabled. This allows us to load content from item providers that we otherwise would not
have loaded, since we now have the ability to fall back to attachment element insertion if the type is not have
a default representation using standard web content.

  • platform/Pasteboard.h:
  • platform/PasteboardItemInfo.h: Added.

(WebCore::PasteboardItemInfo::encode const):
(WebCore::PasteboardItemInfo::decode):

Add PasteboardItemInfo, a struct that describes an item on the pasteboard. Also, implement encoding and decoding
support for PasteboardItemInfo. So far, the item info only describes file information about the pasteboard item,
and flags indicating whether the item prefers attachment or inline presentation.

  • platform/PasteboardStrategy.h:

Replace getFilenamesForDataInteraction with informationForItemAtIndex. Instead of returning all of the file
paths associated with any item on the pasteboard, fetch a PasteboardItemInfo at a given item index, which
includes information about the file path as well as some other metadata we'll need when deciding how to read
pasteboard contents as a document fragment.

  • platform/PlatformPasteboard.h:
  • platform/cocoa/PasteboardCocoa.mm:

(WebCore::Pasteboard::read):

  • platform/ios/AbstractPasteboard.h:
  • platform/ios/PasteboardIOS.mm:

(WebCore::Pasteboard::read):
(WebCore::Pasteboard::readRespectingUTIFidelities):

Teach the iOS Pasteboard to read web content using attachment elements, if enabled. There are two scenarios in
which we would want to insert an attachment element:
(1) The item provider uses a preferred presentation style of attachment, in which case we bail out of trying to

handle the drop using the default mechanisms, and simply insert it as an attachment. We need this to deal
with the case where we drop text or HTML files from the Files app, so that we don't try and insert the
contents of the text or HTML as inline web content.

(2) The item provider doesn't have a preferred attachment presentation style, but there's nothing WebKit would

otherwise do with the dropped content, so insert an attachment element as a fallback. Examples where this is
relevant are dropping a PDF or ZIP archive without attachment presentation style explicitly set.

We first check if we fall into case (1). If so, we can bail early by inserting an attachment; otherwise, we
proceed normally and see if we can read the contents of the drop as web content. If, at the end of default drop
handling, we don't still have a way to represent the dropped content, enter case (2).

(WebCore::Pasteboard::readFilePaths):
(WebCore::Pasteboard::readFilenames): Deleted.

Rename readFilenames to readFilePaths, and reimplement it using informationForItemAtIndex.

  • platform/ios/PlatformPasteboardIOS.mm:

(WebCore::pasteboardItemPresentationStyle):
(WebCore::PlatformPasteboard::informationForItemAtIndex):
(WebCore::PlatformPasteboard::filenamesForDataInteraction): Deleted.

Implement informationForItemAtIndex and remove filenamesForDataInteraction. As before, we ask the pasteboard
(i.e. WebItemProviderPasteboard) for information about dropped file URLs. This time, we limit this to a single
file, so we don't end up creating multiple attachment elements for each representation of a single item
provider. See below for -preferredFileUploadURLAtIndex:fileType: for more detail.

  • platform/ios/WebItemProviderPasteboard.h:
  • platform/ios/WebItemProviderPasteboard.mm:

(-[WebItemProviderLoadResult initWithItemProvider:typesToLoad:]):
(-[WebItemProviderLoadResult canBeRepresentedAsFileUpload]):

Remove this synthesized instance variable and instead just check the item provider's preferredPresentationStyle.

(-[WebItemProviderLoadResult description]):

Add a verbose -description to the load result object. Useful for debugging what was content was loaded from an
item provider on drop.

(-[WebItemProviderPasteboard preferredFileUploadURLAtIndex:fileType:]):

Return the highest fidelity loaded type identifier for a given item.

(-[WebItemProviderPasteboard allDroppedFileURLs]):
(-[WebItemProviderPasteboard typeIdentifiersToLoadForRegisteredTypeIdentfiers:]):

Prefer flat RTFD to RTFD. In the case where attachments are enabled and we're accepting all types of content
using attachment elements as a fallback representation, if the source writes attributed strings to the
pasteboard with com.apple.rtfd at a higher fidelity than com.apple.flat-rtfd, we'll end up loading only
com.apple.rtfd and dropping the text as an attachment element because we cannot convert the dropped content to
markup. Instead, if flat RTFD is present in the item provider, always prefer that over RTFD so that dropping as
regular web content isn't overridden when attachment elements are enabled.

(-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):
(-[WebItemProviderPasteboard droppedFileURLs]): Deleted.

  • platform/mac/DragDataMac.mm:

(WebCore::DragData::containsCompatibleContent const):

DragData::containsCompatibleContent should be true when attachment elements are enabled, and there are files we
can drop as attachment elements.

  • platform/mac/PasteboardMac.mm:

(WebCore::Pasteboard::read):
(WebCore::Pasteboard::readFilePaths):
(WebCore::Pasteboard::readFilenames): Deleted.

Source/WebKit:

Make some minor adjustments for changes to the pasteboard in WebCore. See WebCore/ChangeLog for more detail.
Teaches WebPasteboardProxy et. al. to plumb PasteboardItemInfo from the UI process to the web process via the
new InformationForItemAtIndex codepath.

  • UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:

(WebKit::WebPasteboardProxy::informationForItemAtIndex):
(WebKit::WebPasteboardProxy::getFilenamesForDataInteraction): Deleted.

  • UIProcess/WebPasteboardProxy.h:
  • UIProcess/WebPasteboardProxy.messages.in:
  • WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:

(WebKit::WebPlatformStrategies::informationForItemAtIndex):
(WebKit::WebPlatformStrategies::getFilenamesForDataInteraction): Deleted.

  • WebProcess/WebCoreSupport/WebPlatformStrategies.h:

Source/WebKitLegacy/mac:

Make some minor adjustments for changes to the pasteboard in WebCore. See WebCore/ChangeLog for more detail.

  • WebCoreSupport/WebPlatformStrategies.h:
  • WebCoreSupport/WebPlatformStrategies.mm:

(WebPlatformStrategies::informationForItemAtIndex):
(WebPlatformStrategies::getFilenamesForDataInteraction): Deleted.

Tools:

Adds 3 new API tests to exercise different use cases of dropping content as attachment elements when the runtime
switch is enabled. See below for more details.

  • TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:

(-[NSItemProvider registerData:type:]):
(platformCopyPNG):
(TestWebKitAPI::TEST):

  • TestWebKitAPI/Tests/ios/DataInteractionTests.mm:

Fix some currently failing iOS drag and drop tests. In this case, there's no reason RTFD should appear in the
source item provider when dragging rich text *without* attachments, so this should have been a check for just
kUTTypeRTF instead.

(TestWebKitAPI::TEST):

Tests a few cases of inserting attachment elements via drop:

  1. We should distinguish between drops containing rich/plain text files from just dropping rich/plain text.

Instead of inserting the contents as inline web content, this should generate attachment elements.

  1. Test the fallback mechanism for inserting attachment elements. If the preferred presentation style is not

explicitly set, but there's nothing WebKit would otherwise do with the dropped content, then we should fall
back to inserting the content as an attachment.

  1. Test that if multiple attachments and inline item providers are present, WebKit will respect the order in

which they were inserted by the source (as opposed to, for instance, putting all of the attachments in front
or at the end).

  • TestWebKitAPI/cocoa/TestWKWebView.h:
  • TestWebKitAPI/cocoa/TestWKWebView.mm:

(-[TestWKWebView objectByEvaluatingJavaScript:]):

Add a helper method to return an object that represents the result of evaluating some given script, and rewrite
-stringByEvaluatingJavaScript to just turn around and call this.

(-[TestWKWebView stringByEvaluatingJavaScript:]):

Location:
trunk
Files:
1 added
33 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r226395 r226396  
     12018-01-03  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Attachment Support] Create attachment elements when dropping files on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=181192
     5        <rdar://problem/36280945>
     6
     7        Reviewed by Tim Horton.
     8
     9        Implements support for dropping data as attachment elements on iOS. See comments below for more detail.
     10
     11        Tests:  WKAttachmentTests.InsertDroppedRichAndPlainTextFilesAsAttachments
     12                WKAttachmentTests.InsertDroppedZipArchiveAsAttachment
     13                WKAttachmentTests.InsertDroppedItemProvidersInOrder
     14
     15        * WebCore.xcodeproj/project.pbxproj:
     16        * editing/WebContentReader.cpp:
     17        (WebCore::WebContentReader::ensureFragment):
     18
     19        Add a new helper to create the WebContentReader's fragment, if it hasn't already been created.
     20
     21        * editing/WebContentReader.h:
     22        * editing/cocoa/WebContentReaderCocoa.mm:
     23        (WebCore::WebContentReader::readFilePaths):
     24
     25        Rename readFilenames to readFilePaths (which better reflects its parameters, which are file paths). Also, move
     26        the implementation of readFilePaths to shared iOS/macOS code in WebContentReaderCocoa, and remove the stub
     27        implementation on iOS.
     28
     29        There's a bit of code here that I kept macOS-only which deals with inserting file paths as plain text in
     30        editable areas, but it's unclear to me why and if WebKit clients currently find this useful, so I left a FIXME
     31        to investigate removing this altogether. Code for handling this plain text insertion of file paths on Mac was
     32        introduced in r67403.
     33
     34        * editing/ios/WebContentReaderIOS.mm:
     35        (WebCore::WebContentReader::readFilenames): Deleted.
     36        * editing/mac/WebContentReaderMac.mm:
     37        (WebCore::WebContentReader::readFilenames): Deleted.
     38        * page/mac/DragControllerMac.mm:
     39        (WebCore::DragController::updateSupportedTypeIdentifiersForDragHandlingMethod const):
     40
     41        Teach DragController to accept all types conforming to "public.item" and "public.content" on iOS, only when
     42        attachment elements are enabled. This allows us to load content from item providers that we otherwise would not
     43        have loaded, since we now have the ability to fall back to attachment element insertion if the type is not have
     44        a default representation using standard web content.
     45
     46        * platform/Pasteboard.h:
     47        * platform/PasteboardItemInfo.h: Added.
     48        (WebCore::PasteboardItemInfo::encode const):
     49        (WebCore::PasteboardItemInfo::decode):
     50
     51        Add PasteboardItemInfo, a struct that describes an item on the pasteboard. Also, implement encoding and decoding
     52        support for PasteboardItemInfo. So far, the item info only describes file information about the pasteboard item,
     53        and flags indicating whether the item prefers attachment or inline presentation.
     54
     55        * platform/PasteboardStrategy.h:
     56
     57        Replace getFilenamesForDataInteraction with informationForItemAtIndex. Instead of returning all of the file
     58        paths associated with any item on the pasteboard, fetch a PasteboardItemInfo at a given item index, which
     59        includes information about the file path as well as some other metadata we'll need when deciding how to read
     60        pasteboard contents as a document fragment.
     61
     62        * platform/PlatformPasteboard.h:
     63        * platform/cocoa/PasteboardCocoa.mm:
     64        (WebCore::Pasteboard::read):
     65        * platform/ios/AbstractPasteboard.h:
     66        * platform/ios/PasteboardIOS.mm:
     67        (WebCore::Pasteboard::read):
     68        (WebCore::Pasteboard::readRespectingUTIFidelities):
     69
     70        Teach the iOS Pasteboard to read web content using attachment elements, if enabled. There are two scenarios in
     71        which we would want to insert an attachment element:
     72        (1) The item provider uses a preferred presentation style of attachment, in which case we bail out of trying to
     73            handle the drop using the default mechanisms, and simply insert it as an attachment. We need this to deal
     74            with the case where we drop text or HTML files from the Files app, so that we don't try and insert the
     75            contents of the text or HTML as inline web content.
     76        (2) The item provider doesn't have a preferred attachment presentation style, but there's nothing WebKit would
     77            otherwise do with the dropped content, so insert an attachment element as a fallback. Examples where this is
     78            relevant are dropping a PDF or ZIP archive without attachment presentation style explicitly set.
     79        We first check if we fall into case (1). If so, we can bail early by inserting an attachment; otherwise, we
     80        proceed normally and see if we can read the contents of the drop as web content. If, at the end of default drop
     81        handling, we don't still have a way to represent the dropped content, enter case (2).
     82
     83        (WebCore::Pasteboard::readFilePaths):
     84        (WebCore::Pasteboard::readFilenames): Deleted.
     85
     86        Rename readFilenames to readFilePaths, and reimplement it using informationForItemAtIndex.
     87
     88        * platform/ios/PlatformPasteboardIOS.mm:
     89        (WebCore::pasteboardItemPresentationStyle):
     90        (WebCore::PlatformPasteboard::informationForItemAtIndex):
     91        (WebCore::PlatformPasteboard::filenamesForDataInteraction): Deleted.
     92
     93        Implement informationForItemAtIndex and remove filenamesForDataInteraction. As before, we ask the pasteboard
     94        (i.e. WebItemProviderPasteboard) for information about dropped file URLs. This time, we limit this to a single
     95        file, so we don't end up creating multiple attachment elements for each representation of a single item
     96        provider. See below for -preferredFileUploadURLAtIndex:fileType: for more detail.
     97
     98        * platform/ios/WebItemProviderPasteboard.h:
     99        * platform/ios/WebItemProviderPasteboard.mm:
     100        (-[WebItemProviderLoadResult initWithItemProvider:typesToLoad:]):
     101        (-[WebItemProviderLoadResult canBeRepresentedAsFileUpload]):
     102
     103        Remove this synthesized instance variable and instead just check the item provider's preferredPresentationStyle.
     104
     105        (-[WebItemProviderLoadResult description]):
     106
     107        Add a verbose -description to the load result object. Useful for debugging what was content was loaded from an
     108        item provider on drop.
     109
     110        (-[WebItemProviderPasteboard preferredFileUploadURLAtIndex:fileType:]):
     111
     112        Return the highest fidelity loaded type identifier for a given item.
     113
     114        (-[WebItemProviderPasteboard allDroppedFileURLs]):
     115        (-[WebItemProviderPasteboard typeIdentifiersToLoadForRegisteredTypeIdentfiers:]):
     116
     117        Prefer flat RTFD to RTFD. In the case where attachments are enabled and we're accepting all types of content
     118        using attachment elements as a fallback representation, if the source writes attributed strings to the
     119        pasteboard with com.apple.rtfd at a higher fidelity than com.apple.flat-rtfd, we'll end up loading only
     120        com.apple.rtfd and dropping the text as an attachment element because we cannot convert the dropped content to
     121        markup. Instead, if flat RTFD is present in the item provider, always prefer that over RTFD so that dropping as
     122        regular web content isn't overridden when attachment elements are enabled.
     123
     124        (-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):
     125        (-[WebItemProviderPasteboard droppedFileURLs]): Deleted.
     126        * platform/mac/DragDataMac.mm:
     127        (WebCore::DragData::containsCompatibleContent const):
     128
     129        DragData::containsCompatibleContent should be true when attachment elements are enabled, and there are files we
     130        can drop as attachment elements.
     131
     132        * platform/mac/PasteboardMac.mm:
     133        (WebCore::Pasteboard::read):
     134        (WebCore::Pasteboard::readFilePaths):
     135        (WebCore::Pasteboard::readFilenames): Deleted.
     136
    11372018-01-03  Ting-Wei Lan  <lantw44@gmail.com>
    2138
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r226348 r226396  
    46544654                F48223111E3869B80066FC79 /* WebItemProviderPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F482230F1E3869B80066FC79 /* WebItemProviderPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
    46554655                F48223131E386E240066FC79 /* AbstractPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F48223121E386E240066FC79 /* AbstractPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
     4656                F49786881FF45FA500E060AB /* PasteboardItemInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F49786871FF45FA500E060AB /* PasteboardItemInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
    46564657                F4BFB9851E1DDF9B00862C24 /* DumpEditingHistory.js in Copy Scripts */ = {isa = PBXBuildFile; fileRef = F48389831E1DDF2B0076B7EA /* DumpEditingHistory.js */; };
    46574658                F4BFB9861E1DDF9B00862C24 /* EditingHistoryUtil.js in Copy Scripts */ = {isa = PBXBuildFile; fileRef = F48389841E1DDF2B0076B7EA /* EditingHistoryUtil.js */; };
     
    1408714088                F48389831E1DDF2B0076B7EA /* DumpEditingHistory.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = DumpEditingHistory.js; path = Scripts/DumpEditingHistory.js; sourceTree = "<group>"; };
    1408814089                F48389841E1DDF2B0076B7EA /* EditingHistoryUtil.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EditingHistoryUtil.js; path = Scripts/EditingHistoryUtil.js; sourceTree = "<group>"; };
     14090                F49786871FF45FA500E060AB /* PasteboardItemInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PasteboardItemInfo.h; sourceTree = "<group>"; };
    1408914091                F50664F5157F52DC00AC226F /* FormController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormController.cpp; sourceTree = "<group>"; };
    1409014092                F50664F6157F52DC00AC226F /* FormController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormController.h; sourceTree = "<group>"; };
     
    2369223694                                2EE02A1E1F7324280006AF72 /* Pasteboard.cpp */,
    2369323695                                4B2708C50AF19EE40065127F /* Pasteboard.h */,
     23696                                F49786871FF45FA500E060AB /* PasteboardItemInfo.h */,
    2369423697                                C5F765B414E1D414006C899B /* PasteboardStrategy.h */,
    2369523698                                1AF5E4D21E56735A004A1F01 /* PasteboardWriterData.cpp */,
     
    2869128694                                F55B3DCA1251F12D003EF269 /* PasswordInputType.h in Headers */,
    2869228695                                4B2708C70AF19EE40065127F /* Pasteboard.h in Headers */,
     28696                                F49786881FF45FA500E060AB /* PasteboardItemInfo.h in Headers */,
    2869328697                                C598905714E9C28000E8D18B /* PasteboardStrategy.h in Headers */,
    2869428698                                1AF5E4E31E5779B1004A1F01 /* PasteboardWriter.h in Headers */,
  • trunk/Source/WebCore/editing/WebContentReader.cpp

    r223678 r226396  
    3232namespace WebCore {
    3333
     34DocumentFragment& WebContentReader::ensureFragment()
     35{
     36    ASSERT(frame.document());
     37    if (!fragment)
     38        fragment = frame.document()->createDocumentFragment();
     39    return *fragment;
     40}
     41
    3442void WebContentReader::addFragment(Ref<DocumentFragment>&& newFragment)
    3543{
  • trunk/Source/WebCore/editing/WebContentReader.h

    r226213 r226396  
    6464    }
    6565
     66    DocumentFragment& ensureFragment();
    6667    void addFragment(Ref<DocumentFragment>&&);
    6768
     
    6970#if PLATFORM(COCOA)
    7071    bool readWebArchive(SharedBuffer&) override;
    71     bool readFilenames(const Vector<String>&) override;
     72    bool readFilePaths(const Vector<String>&) override;
    7273    bool readHTML(const String&) override;
    7374    bool readRTFD(SharedBuffer&) override;
     
    9192#if PLATFORM(COCOA)
    9293    bool readWebArchive(SharedBuffer&) override;
    93     bool readFilenames(const Vector<String>&) override { return false; }
     94    bool readFilePaths(const Vector<String>&) override { return false; }
    9495    bool readHTML(const String&) override;
    9596    bool readRTFD(SharedBuffer&) override;
  • trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm

    r226340 r226396  
    597597}
    598598
    599 }
     599bool WebContentReader::readFilePaths(const Vector<String>& paths)
     600{
     601    if (paths.isEmpty() || !frame.document())
     602        return false;
     603
     604    auto& document = *frame.document();
     605    bool readAnyFilePath = false;
     606    for (auto& path : paths) {
     607#if ENABLE(ATTACHMENT_ELEMENT)
     608        if (RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled()) {
     609            auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
     610            attachment->setUniqueIdentifier(createCanonicalUUIDString());
     611            attachment->setFile(File::create(path), HTMLAttachmentElement::UpdateDisplayAttributes::Yes);
     612            ensureFragment().appendChild(attachment);
     613            readAnyFilePath = true;
     614            continue;
     615        }
     616#endif
     617#if PLATFORM(MAC)
     618        // FIXME: Does (and should) any macOS client depend on inserting file paths as plain text in web content?
     619        // If not, we should just remove this.
     620        auto paragraph = createDefaultParagraphElement(document);
     621        paragraph->appendChild(document.createTextNode(userVisibleString([NSURL fileURLWithPath:path])));
     622        ensureFragment().appendChild(paragraph);
     623        readAnyFilePath = true;
     624#endif
     625    }
     626    return readAnyFilePath;
     627}
     628
     629}
  • trunk/Source/WebCore/editing/ios/WebContentReaderIOS.mm

    r223020 r226396  
    4848namespace WebCore {
    4949
    50 bool WebContentReader::readFilenames(const Vector<String>&)
    51 {
    52     return false;
    53 }
    54 
    5550bool WebContentReader::readURL(const URL& url, const String& title)
    5651{
  • trunk/Source/WebCore/editing/mac/WebContentReaderMac.mm

    r226085 r226396  
    3939#import "FrameLoaderClient.h"
    4040#import "HTMLAnchorElement.h"
    41 #import "HTMLAttachmentElement.h"
    4241#import "HTMLNames.h"
    4342#import "LegacyWebArchive.h"
    44 #import "MIMETypeRegistry.h"
    45 #import "RuntimeEnabledFeatures.h"
    4643#import "Settings.h"
    4744#import "Text.h"
    4845#import "WebCoreNSURLExtras.h"
    4946#import "markup.h"
    50 #import <wtf/UUID.h>
    5147
    5248namespace WebCore {
    53 
    54 bool WebContentReader::readFilenames(const Vector<String>& paths)
    55 {
    56     if (paths.isEmpty())
    57         return false;
    58 
    59     if (!frame.document())
    60         return false;
    61     Document& document = *frame.document();
    62 
    63     fragment = document.createDocumentFragment();
    64 
    65     for (auto& text : paths) {
    66 #if ENABLE(ATTACHMENT_ELEMENT)
    67         if (RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled()) {
    68             auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
    69             attachment->setUniqueIdentifier(createCanonicalUUIDString());
    70             attachment->setFile(File::create([NSURL fileURLWithPath:text].path), HTMLAttachmentElement::UpdateDisplayAttributes::Yes);
    71             fragment->appendChild(attachment);
    72             continue;
    73         }
    74 #else
    75         auto paragraph = createDefaultParagraphElement(document);
    76         paragraph->appendChild(document.createTextNode(userVisibleString([NSURL fileURLWithPath:text])));
    77         fragment->appendChild(paragraph);
    78 #endif
    79     }
    80 
    81     return true;
    82 }
    8349
    8450bool WebContentReader::readURL(const URL& url, const String& title)
  • trunk/Source/WebCore/page/mac/DragControllerMac.mm

    r226312 r226396  
    4646#import "PlatformStrategies.h"
    4747#import "Range.h"
     48#import "RuntimeEnabledFeatures.h"
    4849
    4950#if ENABLE(DATA_INTERACTION)
     
    126127        break;
    127128    case DragHandlingMethod::EditRichText:
    128         for (NSString *type in Pasteboard::supportedWebContentPasteboardTypes())
    129             supportedTypes.append(type);
     129        if (RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled()) {
     130            supportedTypes.append(WebArchivePboardType);
     131            supportedTypes.append(kUTTypeContent);
     132            supportedTypes.append(kUTTypeItem);
     133        } else {
     134            for (NSString *type in Pasteboard::supportedWebContentPasteboardTypes())
     135                supportedTypes.append(type);
     136        }
    130137        break;
    131138    default:
  • trunk/Source/WebCore/platform/Pasteboard.h

    r223728 r226396  
    2727
    2828#include "DragImage.h"
     29#include "PasteboardItemInfo.h"
    2930#include "URL.h"
    3031#include <wtf/HashMap.h>
     
    135136#if PLATFORM(COCOA)
    136137    virtual bool readWebArchive(SharedBuffer&) = 0;
    137     virtual bool readFilenames(const Vector<String>&) = 0;
     138    virtual bool readFilePaths(const Vector<String>&) = 0;
    138139    virtual bool readHTML(const String&) = 0;
    139140    virtual bool readRTFD(SharedBuffer&) = 0;
     
    291292
    292293#if PLATFORM(COCOA)
    293     Vector<String> readFilenames();
     294    Vector<String> readFilePaths();
    294295    String readPlatformValueAsString(const String& domType, long changeCount, const String& pasteboardName);
    295296    static void addHTMLClipboardTypesForCocoaType(ListHashSet<String>& resultTypes, const String& cocoaType);
  • trunk/Source/WebCore/platform/PasteboardStrategy.h

    r223195 r226396  
    3636class URL;
    3737struct PasteboardImage;
     38struct PasteboardItemInfo;
    3839struct PasteboardURL;
    3940struct PasteboardWebContent;
     
    5152    virtual RefPtr<SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) = 0;
    5253    virtual URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName, String& title) = 0;
    53     virtual void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) = 0;
     54    virtual PasteboardItemInfo informationForItemAtIndex(int index, const String& pasteboardName) = 0;
    5455    virtual void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) = 0;
    5556    virtual void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) = 0;
  • trunk/Source/WebCore/platform/PlatformPasteboard.h

    r223340 r226396  
    5252struct PasteboardCustomData;
    5353struct PasteboardImage;
     54struct PasteboardItemInfo;
    5455struct PasteboardURL;
    5556struct PasteboardWebContent;
     
    6061#if PLATFORM(IOS) || PLATFORM(WPE)
    6162    WEBCORE_EXPORT PlatformPasteboard();
    62     WEBCORE_EXPORT Vector<String> filenamesForDataInteraction();
     63    WEBCORE_EXPORT PasteboardItemInfo informationForItemAtIndex(int index);
    6364    WEBCORE_EXPORT void getTypesByFidelityForItemAtIndex(Vector<String>& types, int index);
    6465    WEBCORE_EXPORT void updateSupportedTypeIdentifiers(const Vector<String>& types);
  • trunk/Source/WebCore/platform/cocoa/PasteboardCocoa.mm

    r226277 r226396  
    192192void Pasteboard::read(PasteboardFileReader& reader)
    193193{
    194     auto filenames = readFilenames();
     194    auto filenames = readFilePaths();
    195195    if (!filenames.isEmpty()) {
    196196        for (auto& filename : filenames)
  • trunk/Source/WebCore/platform/ios/AbstractPasteboard.h

    r222595 r226396  
    5757- (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index;
    5858@property (readonly, nonatomic) NSInteger numberOfFiles;
    59 @property (readonly, nonatomic) NSArray<NSURL *> *droppedFileURLs;
     59@property (readonly, nonatomic) NSArray<NSURL *> *allDroppedFileURLs;
     60- (nullable NSURL *)preferredFileUploadURLAtIndex:(NSUInteger)index fileType:(NSString *_Nullable *_Nullable)outFileType;
    6061- (void)updateSupportedTypeIdentifiers:(NSArray<NSString *> *)types;
    6162
  • trunk/Source/WebCore/platform/ios/PasteboardIOS.mm

    r223678 r226396  
    3232#import "PlatformPasteboard.h"
    3333#import "PlatformStrategies.h"
     34#import "RuntimeEnabledFeatures.h"
    3435#import "SharedBuffer.h"
    3536#import "URL.h"
     
    245246    for (int i = 0; i < numberOfItems; i++) {
    246247        for (int typeIndex = 0; typeIndex < numberOfTypes; typeIndex++) {
    247             auto result = readPasteboardWebContentDataForType(reader, strategy, [types objectAtIndex:typeIndex], i);
     248            auto itemResult = readPasteboardWebContentDataForType(reader, strategy, [types objectAtIndex:typeIndex], i);
     249            if (itemResult == ReaderResult::PasteboardWasChangedExternally)
     250                return;
     251            if (itemResult == ReaderResult::ReadType)
     252                break;
     253        }
     254    }
     255}
     256
     257bool Pasteboard::respectsUTIFidelities() const
     258{
     259    // For now, data interaction is the only feature that uses item-provider-based pasteboard representations.
     260    // In the future, we may need to consult the client layer to determine whether or not the pasteboard supports
     261    // item types ranked by fidelity.
     262    return m_pasteboardName == "data interaction pasteboard";
     263}
     264
     265void Pasteboard::readRespectingUTIFidelities(PasteboardWebContentReader& reader)
     266{
     267    ASSERT(respectsUTIFidelities());
     268    auto& strategy = *platformStrategies()->pasteboardStrategy();
     269    for (NSUInteger index = 0, numberOfItems = strategy.getPasteboardItemsCount(m_pasteboardName); index < numberOfItems; ++index) {
     270#if ENABLE(ATTACHMENT_ELEMENT)
     271        auto info = strategy.informationForItemAtIndex(index, m_pasteboardName);
     272        bool canReadAttachment = RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled() && !info.pathForFileUpload.isEmpty();
     273        if (canReadAttachment && info.preferredPresentationStyle == PasteboardItemPresentationStyle::Attachment) {
     274            reader.readFilePaths({ info.pathForFileUpload });
     275            continue;
     276        }
     277#endif
     278        // Try to read data from each type identifier that this pasteboard item supports, and WebKit also recognizes. Type identifiers are
     279        // read in order of fidelity, as specified by each pasteboard item.
     280        Vector<String> typesForItemInOrderOfFidelity;
     281        strategy.getTypesByFidelityForItemAtIndex(typesForItemInOrderOfFidelity, index, m_pasteboardName);
     282        ReaderResult result = ReaderResult::DidNotReadType;
     283        for (auto& type : typesForItemInOrderOfFidelity) {
     284            result = readPasteboardWebContentDataForType(reader, strategy, type, index);
    248285            if (result == ReaderResult::PasteboardWasChangedExternally)
    249286                return;
     
    251288                break;
    252289        }
    253     }
    254 }
    255 
    256 bool Pasteboard::respectsUTIFidelities() const
    257 {
    258     // For now, data interaction is the only feature that uses item-provider-based pasteboard representations.
    259     // In the future, we may need to consult the client layer to determine whether or not the pasteboard supports
    260     // item types ranked by fidelity.
    261     return m_pasteboardName == "data interaction pasteboard";
    262 }
    263 
    264 void Pasteboard::readRespectingUTIFidelities(PasteboardWebContentReader& reader)
    265 {
    266     ASSERT(respectsUTIFidelities());
    267     auto& strategy = *platformStrategies()->pasteboardStrategy();
    268     for (NSUInteger index = 0, numberOfItems = strategy.getPasteboardItemsCount(m_pasteboardName); index < numberOfItems; ++index) {
    269         // Try to read data from each type identifier that this pasteboard item supports, and WebKit also recognizes. Type identifiers are
    270         // read in order of fidelity, as specified by each pasteboard item.
    271         Vector<String> typesForItemInOrderOfFidelity;
    272         strategy.getTypesByFidelityForItemAtIndex(typesForItemInOrderOfFidelity, index, m_pasteboardName);
    273         for (auto& type : typesForItemInOrderOfFidelity) {
    274             auto result = readPasteboardWebContentDataForType(reader, strategy, type, index);
    275             if (result == ReaderResult::PasteboardWasChangedExternally)
    276                 return;
    277             if (result == ReaderResult::ReadType)
    278                 break;
    279         }
     290#if ENABLE(ATTACHMENT_ELEMENT)
     291        if (canReadAttachment && result == ReaderResult::DidNotReadType)
     292            reader.readFilePaths({ info.pathForFileUpload });
     293#endif
    280294    }
    281295}
     
    406420}
    407421
    408 Vector<String> Pasteboard::readFilenames()
    409 {
    410     Vector<String> filenames;
    411     // Currently, data interaction is the only case on iOS where the pasteboard may contain relevant filenames.
    412     platformStrategies()->pasteboardStrategy()->getFilenamesForDataInteraction(filenames, m_pasteboardName);
    413     return filenames;
    414 }
    415 
    416 }
     422Vector<String> Pasteboard::readFilePaths()
     423{
     424    Vector<String> filePaths;
     425    auto& strategy = *platformStrategies()->pasteboardStrategy();
     426    for (NSUInteger index = 0, numberOfItems = strategy.getPasteboardItemsCount(m_pasteboardName); index < numberOfItems; ++index) {
     427        // Currently, drag and drop is the only case on iOS where the "pasteboard" may contain file paths.
     428        auto filePath = strategy.informationForItemAtIndex(index, m_pasteboardName).pathForFileUpload;
     429        if (!filePath.isEmpty())
     430            filePaths.append(WTFMove(filePath));
     431    }
     432    return filePaths;
     433}
     434
     435}
  • trunk/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm

    r226248 r226396  
    103103}
    104104
    105 Vector<String> PlatformPasteboard::filenamesForDataInteraction()
    106 {
    107     if (![m_pasteboard respondsToSelector:@selector(droppedFileURLs)])
     105#if PASTEBOARD_SUPPORTS_ITEM_PROVIDERS
     106
     107static PasteboardItemPresentationStyle pasteboardItemPresentationStyle(UIPreferredPresentationStyle style)
     108{
     109    switch (style) {
     110    case UIPreferredPresentationStyleUnspecified:
     111        return PasteboardItemPresentationStyle::Unspecified;
     112    case UIPreferredPresentationStyleInline:
     113        return PasteboardItemPresentationStyle::Inline;
     114    case UIPreferredPresentationStyleAttachment:
     115        return PasteboardItemPresentationStyle::Attachment;
     116    default:
     117        ASSERT_NOT_REACHED();
     118        return PasteboardItemPresentationStyle::Unspecified;
     119    }
     120}
     121
     122PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int index)
     123{
     124    if (index >= [m_pasteboard numberOfItems])
    108125        return { };
    109126
    110     Vector<String> filenames;
    111     for (NSURL *fileURL in [m_pasteboard droppedFileURLs])
    112         filenames.append(fileURL.path);
    113 
    114     return filenames;
    115 }
     127    PasteboardItemInfo info;
     128    if ([m_pasteboard respondsToSelector:@selector(preferredFileUploadURLAtIndex:fileType:)]) {
     129        NSString *fileType = nil;
     130        info.pathForFileUpload = [m_pasteboard preferredFileUploadURLAtIndex:index fileType:&fileType].path;
     131        info.contentTypeForFileUpload = fileType;
     132    }
     133
     134    NSItemProvider *itemProvider = [[m_pasteboard itemProviders] objectAtIndex:index];
     135    info.preferredPresentationStyle = pasteboardItemPresentationStyle(itemProvider.preferredPresentationStyle);
     136    return info;
     137}
     138
     139#else
     140
     141PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int)
     142{
     143    return { };
     144}
     145
     146#endif
    116147
    117148static bool pasteboardMayContainFilePaths(id<AbstractPasteboard> pasteboard)
  • trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.h

    r222595 r226396  
    9191
    9292// This will only be non-empty when an operation is being performed.
    93 @property (readonly, nonatomic) NSArray<NSURL *> *droppedFileURLs;
     93@property (readonly, nonatomic) NSArray<NSURL *> *allDroppedFileURLs;
     94
     95// The preferred file URL corresponds to the highest fidelity non-private UTI that was loaded.
     96- (nullable NSURL *)preferredFileUploadURLAtIndex:(NSUInteger)index fileType:(NSString *_Nullable *_Nullable)outFileType;
    9497
    9598@property (readonly, nonatomic) BOOL hasPendingOperation;
  • trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm

    r224371 r226396  
    244244    _itemProvider = itemProvider;
    245245    _typesToLoad = typesToLoad;
    246     _canBeRepresentedAsFileUpload = itemProvider.preferredPresentationStyle != UIPreferredPresentationStyleInline;
    247246
    248247    return self;
    249248}
    250249
     250- (BOOL)canBeRepresentedAsFileUpload
     251{
     252    return [_itemProvider preferredPresentationStyle] != UIPreferredPresentationStyleInline;
     253}
     254
    251255- (NSArray<NSString *> *)typesToLoad
    252256{
     
    277281{
    278282    return _itemProvider.get();
     283}
     284
     285- (NSString *)description
     286{
     287    __block NSMutableString *description = [NSMutableString string];
     288    [description appendFormat:@"<%@: %p typesToLoad: [ ", [self class], self];
     289    [_typesToLoad enumerateObjectsUsingBlock:^(NSString *type, NSUInteger index, BOOL *) {
     290        [description appendString:type];
     291        if (index + 1 < [_typesToLoad count])
     292            [description appendString:@", "];
     293    }];
     294    [description appendFormat:@" ] fileURLs: { "];
     295    __block NSUInteger index = 0;
     296    [_fileURLs enumerateKeysAndObjectsUsingBlock:^(NSString *type, NSURL *url, BOOL *) {
     297        [description appendFormat:@"%@ => \"%@\"", type, url.path];
     298        if (++index < [_fileURLs count])
     299            [description appendString:@", "];
     300    }];
     301    [description appendFormat:@" }>"];
     302    return description;
    279303}
    280304
     
    471495}
    472496
    473 - (NSArray<NSURL *> *)droppedFileURLs
     497- (NSURL *)preferredFileUploadURLAtIndex:(NSUInteger)index fileType:(NSString **)outFileType
     498{
     499    if (outFileType)
     500        *outFileType = nil;
     501
     502    if (index >= _loadResults.size())
     503        return nil;
     504
     505    auto result = _loadResults[index];
     506    if (![result canBeRepresentedAsFileUpload])
     507        return nil;
     508
     509    NSItemProvider *itemProvider = [result itemProvider];
     510    for (NSString *registeredTypeIdentifier in itemProvider.registeredTypeIdentifiers) {
     511        // Search for the highest fidelity non-private type identifier we loaded from the item provider.
     512        if (!UTTypeIsDeclared((CFStringRef)registeredTypeIdentifier) && !UTTypeIsDynamic((CFStringRef)registeredTypeIdentifier))
     513            continue;
     514
     515        for (NSString *loadedTypeIdentifier in [result loadedTypeIdentifiers]) {
     516            if (!UTTypeConformsTo((CFStringRef)registeredTypeIdentifier, (CFStringRef)loadedTypeIdentifier))
     517                continue;
     518
     519            if (outFileType)
     520                *outFileType = loadedTypeIdentifier;
     521            return [result fileURLForType:loadedTypeIdentifier];
     522        }
     523    }
     524
     525    return nil;
     526}
     527
     528- (NSArray<NSURL *> *)allDroppedFileURLs
    474529{
    475530    NSMutableArray<NSURL *> *fileURLs = [NSMutableArray array];
     
    540595    NSString *highestFidelityContentType = nil;
    541596
     597    BOOL containsFlatRTFD = [registeredTypeIdentifiers containsObject:(NSString *)kUTTypeFlatRTFD];
    542598    // First, we want to either load the highest fidelity supported type or the highest fidelity generic content type.
    543599    for (NSString *registeredTypeIdentifier in registeredTypeIdentifiers) {
     600        if (containsFlatRTFD && [registeredTypeIdentifier isEqualToString:(NSString *)kUTTypeRTFD]) {
     601            // In the case where attachments are enabled and we're accepting all types of content using attachment
     602            // elements as a fallback representation, if the source writes attributed strings to the pasteboard with
     603            // com.apple.rtfd at a higher fidelity than com.apple.flat-rtfd, we'll end up loading only com.apple.rtfd
     604            // and dropping the text as an attachment element because we cannot convert the dropped content to markup.
     605            // Instead, if flat RTFD is present in the item provider, always prefer that over RTFD so that dropping as
     606            // regular web content isn't overridden by enabling attachment elements.
     607            continue;
     608        }
     609
    544610        if (typeConformsToTypes(registeredTypeIdentifier, _supportedTypeIdentifiers.get())) {
    545611            [typesToLoad addObject:registeredTypeIdentifier];
     
    627693        }
    628694
    629         completionBlock([retainedSelf droppedFileURLs]);
     695        completionBlock([retainedSelf allDroppedFileURLs]);
    630696    };
    631697
  • trunk/Source/WebCore/platform/mac/DragDataMac.mm

    r226277 r226396  
    3535#import "PlatformPasteboard.h"
    3636#import "PlatformStrategies.h"
     37#import "RuntimeEnabledFeatures.h"
    3738#import "WebCoreNSURLExtras.h"
    3839
     
    220221    if (purpose == DraggingPurpose::ForFileUpload)
    221222        return containsFiles();
     223
     224    if (purpose == DraggingPurpose::ForEditing && RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled() && containsFiles())
     225        return true;
    222226
    223227    Vector<String> types;
  • trunk/Source/WebCore/platform/mac/PasteboardMac.mm

    r226277 r226396  
    351351        Vector<String> paths;
    352352        strategy.getPathnamesForType(paths, legacyFilenamesPasteboardType(), m_pasteboardName);
    353         if (m_changeCount != changeCount() || reader.readFilenames(paths))
     353        if (m_changeCount != changeCount() || reader.readFilePaths(paths))
    354354            return;
    355355    }
     
    555555}
    556556
    557 Vector<String> Pasteboard::readFilenames()
     557Vector<String> Pasteboard::readFilePaths()
    558558{
    559559    // FIXME: Seems silly to convert paths to URLs and then back to paths. Does that do anything helpful?
  • trunk/Source/WebKit/ChangeLog

    r226395 r226396  
     12018-01-03  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Attachment Support] Create attachment elements when dropping files on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=181192
     5        <rdar://problem/36280945>
     6
     7        Reviewed by Tim Horton.
     8
     9        Make some minor adjustments for changes to the pasteboard in WebCore. See WebCore/ChangeLog for more detail.
     10        Teaches WebPasteboardProxy et. al. to plumb PasteboardItemInfo from the UI process to the web process via the
     11        new `InformationForItemAtIndex` codepath.
     12
     13        * UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
     14        (WebKit::WebPasteboardProxy::informationForItemAtIndex):
     15        (WebKit::WebPasteboardProxy::getFilenamesForDataInteraction): Deleted.
     16        * UIProcess/WebPasteboardProxy.h:
     17        * UIProcess/WebPasteboardProxy.messages.in:
     18        * WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
     19        (WebKit::WebPlatformStrategies::informationForItemAtIndex):
     20        (WebKit::WebPlatformStrategies::getFilenamesForDataInteraction): Deleted.
     21        * WebProcess/WebCoreSupport/WebPlatformStrategies.h:
     22
    1232018-01-03  Ting-Wei Lan  <lantw44@gmail.com>
    224
  • trunk/Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm

    r223195 r226396  
    3030#import "WebProcessProxy.h"
    3131#import <WebCore/Color.h>
     32#import <WebCore/PasteboardItemInfo.h>
    3233#import <WebCore/PlatformPasteboard.h>
    3334#import <WebCore/SharedBuffer.h>
     
    226227}
    227228
    228 void WebPasteboardProxy::getFilenamesForDataInteraction(const String& pasteboardName, Vector<String>& filenames)
    229 {
    230     filenames = PlatformPasteboard(pasteboardName).filenamesForDataInteraction();
     229void WebPasteboardProxy::informationForItemAtIndex(int index, const String& pasteboardName, PasteboardItemInfo& info)
     230{
     231    info = PlatformPasteboard(pasteboardName).informationForItemAtIndex(index);
    231232}
    232233
  • trunk/Source/WebKit/UIProcess/WebPasteboardProxy.h

    r223195 r226396  
    3636struct PasteboardCustomData;
    3737struct PasteboardImage;
     38struct PasteboardItemInfo;
    3839struct PasteboardURL;
    3940struct PasteboardWebContent;
     
    7879    void readBufferFromPasteboard(uint64_t index, const String& pasteboardType, const String& pasteboardName, SharedMemory::Handle&, uint64_t& size);
    7980    void getPasteboardItemsCount(const String& pasteboardName, uint64_t& itemsCount);
    80     void getFilenamesForDataInteraction(const String& pasteboardName, Vector<String>& filenames);
     81    void informationForItemAtIndex(int index, const String& pasteboardName, WebCore::PasteboardItemInfo& filename);
    8182    void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName);
    8283#endif
  • trunk/Source/WebKit/UIProcess/WebPasteboardProxy.messages.in

    r223195 r226396  
    3131    ReadBufferFromPasteboard(uint64_t index, String pasteboardType, String pasteboardName) -> (WebKit::SharedMemory::Handle handle, uint64_t size)
    3232    GetPasteboardItemsCount(String pasteboardName) -> (uint64_t itemsCount)
    33     GetFilenamesForDataInteraction(String pasteboardName) -> (Vector<String> filenames)
     33    InformationForItemAtIndex(uint64_t index, String pasteboardName) -> (struct WebCore::PasteboardItemInfo info)
    3434    UpdateSupportedTypeIdentifiers(Vector<String> identifiers, String pasteboardName)
    3535    GetPasteboardTypesByFidelityForItemAtIndex(uint64_t index, String pasteboardName) -> (Vector<String> types)
  • trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPlatformStrategies.cpp

    r225934 r226396  
    5656#include <WebCore/Page.h>
    5757#include <WebCore/PageGroup.h>
     58#include <WebCore/PasteboardItemInfo.h>
    5859#include <WebCore/PlatformCookieJar.h>
    5960#include <WebCore/PlatformPasteboard.h>
     
    323324}
    324325
    325 void WebPlatformStrategies::getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName)
    326 {
    327     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetFilenamesForDataInteraction(pasteboardName), Messages::WebPasteboardProxy::GetFilenamesForDataInteraction::Reply(filenames), 0);
     326PasteboardItemInfo WebPlatformStrategies::informationForItemAtIndex(int index, const String& pasteboardName)
     327{
     328    PasteboardItemInfo info;
     329    WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::InformationForItemAtIndex(index, pasteboardName), Messages::WebPasteboardProxy::InformationForItemAtIndex::Reply(info), 0);
     330    return info;
    328331}
    329332
  • trunk/Source/WebKit/WebProcess/WebCoreSupport/WebPlatformStrategies.h

    r225934 r226396  
    6666    RefPtr<WebCore::SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
    6767    WebCore::URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName, String& title) override;
    68     void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) override;
     68    WebCore::PasteboardItemInfo informationForItemAtIndex(int index, const String& pasteboardName) override;
    6969    void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) override;
    7070    void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) override;
  • trunk/Source/WebKitLegacy/mac/ChangeLog

    r226393 r226396  
     12018-01-03  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Attachment Support] Create attachment elements when dropping files on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=181192
     5        <rdar://problem/36280945>
     6
     7        Reviewed by Tim Horton.
     8
     9        Make some minor adjustments for changes to the pasteboard in WebCore. See WebCore/ChangeLog for more detail.
     10
     11        * WebCoreSupport/WebPlatformStrategies.h:
     12        * WebCoreSupport/WebPlatformStrategies.mm:
     13        (WebPlatformStrategies::informationForItemAtIndex):
     14        (WebPlatformStrategies::getFilenamesForDataInteraction): Deleted.
     15
    1162018-01-03  Wenson Hsieh  <wenson_hsieh@apple.com>
    217
  • trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.h

    r225934 r226396  
    6767    RefPtr<WebCore::SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
    6868    WebCore::URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName, String& title) override;
    69     void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) override;
     69    WebCore::PasteboardItemInfo informationForItemAtIndex(int index, const String& pasteboardName) override;
    7070    void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) override;
    7171    void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) override;
  • trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.mm

    r225934 r226396  
    3333#import <WebCore/MainFrame.h>
    3434#import <WebCore/NetworkStorageSession.h>
     35#import <WebCore/PasteboardItemInfo.h>
    3536#import <WebCore/PlatformCookieJar.h>
    3637#import <WebCore/PlatformPasteboard.h>
     
    240241}
    241242
    242 void WebPlatformStrategies::getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName)
    243 {
    244     filenames = PlatformPasteboard(pasteboardName).filenamesForDataInteraction();
     243WebCore::PasteboardItemInfo WebPlatformStrategies::informationForItemAtIndex(int index, const String& pasteboardName)
     244{
     245    return PlatformPasteboard(pasteboardName).informationForItemAtIndex(index);
    245246}
    246247#endif // PLATFORM(IOS)
  • trunk/Tools/ChangeLog

    r226395 r226396  
     12018-01-03  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Attachment Support] Create attachment elements when dropping files on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=181192
     5        <rdar://problem/36280945>
     6
     7        Reviewed by Tim Horton.
     8
     9        Adds 3 new API tests to exercise different use cases of dropping content as attachment elements when the runtime
     10        switch is enabled. See below for more details.
     11
     12        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
     13        (-[NSItemProvider registerData:type:]):
     14        (platformCopyPNG):
     15        (TestWebKitAPI::TEST):
     16        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
     17
     18        Fix some currently failing iOS drag and drop tests. In this case, there's no reason RTFD should appear in the
     19        source item provider when dragging rich text *without* attachments, so this should have been a check for just
     20        kUTTypeRTF instead.
     21
     22        (TestWebKitAPI::TEST):
     23
     24        Tests a few cases of inserting attachment elements via drop:
     25        1.  We should distinguish between drops containing rich/plain text files from just dropping rich/plain text.
     26            Instead of inserting the contents as inline web content, this should generate attachment elements.
     27        2.  Test the fallback mechanism for inserting attachment elements. If the preferred presentation style is not
     28            explicitly set, but there's nothing WebKit would otherwise do with the dropped content, then we should fall
     29            back to inserting the content as an attachment.
     30        3.  Test that if multiple attachments and inline item providers are present, WebKit will respect the order in
     31            which they were inserted by the source (as opposed to, for instance, putting all of the attachments in front
     32            or at the end).
     33
     34        * TestWebKitAPI/cocoa/TestWKWebView.h:
     35        * TestWebKitAPI/cocoa/TestWKWebView.mm:
     36        (-[TestWKWebView objectByEvaluatingJavaScript:]):
     37
     38        Add a helper method to return an object that represents the result of evaluating some given script, and rewrite
     39        -stringByEvaluatingJavaScript to just turn around and call this.
     40
     41        (-[TestWKWebView stringByEvaluatingJavaScript:]):
     42
    1432018-01-03  Ting-Wei Lan  <lantw44@gmail.com>
    244
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm

    r226342 r226396  
    322322#pragma mark - Platform testing helper functions
    323323
     324#if PLATFORM(IOS)
     325
     326typedef void(^ItemProviderDataLoadHandler)(NSData *, NSError *);
     327
     328@implementation NSItemProvider (AttachmentTesting)
     329
     330- (void)registerData:(NSData *)data type:(NSString *)type
     331{
     332    [self registerDataRepresentationForTypeIdentifier:type visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[protectedData = retainPtr(data)] (ItemProviderDataLoadHandler completionHandler) -> NSProgress * {
     333        completionHandler(protectedData.get(), nil);
     334        return nil;
     335    }];
     336}
     337
     338@end
     339
     340#endif // PLATFORM(IOS)
     341
    324342void platformCopyRichTextWithMultipleAttachments()
    325343{
     
    364382}
    365383
    366 typedef void(^ItemProviderDataLoadHandler)(NSData *, NSError *);
    367 
    368384void platformCopyPNG()
    369385{
     
    376392    auto item = adoptNS([[UIItemProvider alloc] init]);
    377393    [item setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
    378     [item registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypePNG visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[] (ItemProviderDataLoadHandler completionHandler) -> NSProgress * {
    379         completionHandler(testImageData(), nil);
    380         return nil;
    381     }];
     394    [item registerData:testImageData() type:(NSString *)kUTTypePNG];
    382395    pasteboard.itemProviders = @[ item.get() ];
    383396#endif
     
    961974    auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
    962975    auto item = adoptNS([[NSItemProvider alloc] init]);
    963     [item setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
    964     [item registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypePNG visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[] (ItemProviderDataLoadHandler completionHandler) -> NSProgress * {
    965         completionHandler(testImageData(), nil);
    966         return nil;
    967     }];
     976    [item registerData:testImageData() type:(NSString *)kUTTypePNG];
    968977    [draggingSimulator setExternalItemProviders:@[ item.get() ]];
    969978    [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)];
     
    10111020}
    10121021
     1022TEST(WKAttachmentTestsIOS, InsertDroppedRichAndPlainTextFilesAsAttachments)
     1023{
     1024    // Here, both rich text and plain text are content types that WebKit already understands how to insert in editable
     1025    // areas in the absence of attachment elements. However, due to the explicitly set attachment presentation style
     1026    // on the item providers, we should instead treat them as dropped files and insert attachment elements.
     1027    // This exercises the scenario of dragging rich and plain text files from Files to Mail.
     1028    auto richTextItem = adoptNS([[NSItemProvider alloc] init]);
     1029    auto richText = adoptNS([[NSAttributedString alloc] initWithString:@"Hello world" attributes:@{ NSFontAttributeName: [UIFont boldSystemFontOfSize:12] }]);
     1030    [richTextItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
     1031    [richTextItem registerObject:richText.get() visibility:NSItemProviderRepresentationVisibilityAll];
     1032    [richTextItem setSuggestedName:@"hello.rtf"];
     1033
     1034    auto plainTextItem = adoptNS([[NSItemProvider alloc] init]);
     1035    [plainTextItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
     1036    [plainTextItem registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll];
     1037    [plainTextItem setSuggestedName:@"world.txt"];
     1038
     1039    auto webView = webViewForTestingAttachments();
     1040    auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
     1041    [draggingSimulator setExternalItemProviders:@[ richTextItem.get(), plainTextItem.get() ]];
     1042    [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)];
     1043
     1044    EXPECT_EQ(2U, [draggingSimulator insertedAttachments].count);
     1045    EXPECT_EQ(0U, [draggingSimulator removedAttachments].count);
     1046
     1047    for (_WKAttachment *attachment in [draggingSimulator insertedAttachments]) {
     1048        NSError *error = nil;
     1049        EXPECT_GT([attachment synchronouslyRequestData:&error].length, 0U);
     1050        EXPECT_TRUE(!error);
     1051        if (error)
     1052            NSLog(@"Error: %@", error);
     1053    }
     1054
     1055    EXPECT_EQ(2, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment').length"].intValue);
     1056    EXPECT_WK_STREQ("hello.rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]);
     1057    EXPECT_WK_STREQ("text/rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
     1058    EXPECT_WK_STREQ("world.txt", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]);
     1059    EXPECT_WK_STREQ("text/plain", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]);
     1060}
     1061
     1062TEST(WKAttachmentTestsIOS, InsertDroppedZipArchiveAsAttachment)
     1063{
     1064    // Since WebKit doesn't have any default DOM representation for ZIP archives, we should fall back to inserting
     1065    // attachment elements. This exercises the flow of dragging a ZIP file from an app that doesn't specify a preferred
     1066    // presentation style (e.g. Notes) into Mail.
     1067    auto item = adoptNS([[NSItemProvider alloc] init]);
     1068    NSData *data = testZIPData();
     1069    [item registerData:data type:(NSString *)kUTTypeZipArchive];
     1070    [item setSuggestedName:@"archive.zip"];
     1071
     1072    auto webView = webViewForTestingAttachments();
     1073    auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
     1074    [draggingSimulator setExternalItemProviders:@[ item.get() ]];
     1075    [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)];
     1076
     1077    EXPECT_EQ(1U, [draggingSimulator insertedAttachments].count);
     1078    EXPECT_EQ(0U, [draggingSimulator removedAttachments].count);
     1079    [[draggingSimulator insertedAttachments].firstObject expectRequestedDataToBe:data];
     1080    EXPECT_EQ(1, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment').length"].intValue);
     1081    EXPECT_WK_STREQ("archive.zip", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]);
     1082    EXPECT_WK_STREQ("application/zip", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]);
     1083}
     1084
     1085TEST(WKAttachmentTestsIOS, InsertDroppedItemProvidersInOrder)
     1086{
     1087    // Tests that item providers are inserted in the order they are specified. In this case, the two inserted attachments
     1088    // should be separated by a link.
     1089    auto firstAttachmentItem = adoptNS([[NSItemProvider alloc] init]);
     1090    [firstAttachmentItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
     1091    [firstAttachmentItem registerObject:@"FIRST" visibility:NSItemProviderRepresentationVisibilityAll];
     1092    [firstAttachmentItem setSuggestedName:@"first.txt"];
     1093
     1094    auto inlineTextItem = adoptNS([[NSItemProvider alloc] init]);
     1095    auto appleURL = retainPtr([NSURL URLWithString:@"https://www.apple.com/"]);
     1096    [inlineTextItem registerObject:appleURL.get() visibility:NSItemProviderRepresentationVisibilityAll];
     1097
     1098    auto secondAttachmentItem = adoptNS([[NSItemProvider alloc] init]);
     1099    [secondAttachmentItem registerData:testPDFData() type:(NSString *)kUTTypePDF];
     1100    [secondAttachmentItem setSuggestedName:@"second.pdf"];
     1101
     1102    auto webView = webViewForTestingAttachments();
     1103    auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
     1104    [draggingSimulator setExternalItemProviders:@[ firstAttachmentItem.get(), inlineTextItem.get(), secondAttachmentItem.get() ]];
     1105    [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)];
     1106
     1107    EXPECT_EQ(2U, [draggingSimulator insertedAttachments].count);
     1108    EXPECT_EQ(0U, [draggingSimulator removedAttachments].count);
     1109
     1110    for (_WKAttachment *attachment in [draggingSimulator insertedAttachments]) {
     1111        NSError *error = nil;
     1112        EXPECT_GT([attachment synchronouslyRequestData:&error].length, 0U);
     1113        EXPECT_TRUE(!error);
     1114        if (error)
     1115            NSLog(@"Error: %@", error);
     1116    }
     1117
     1118    NSArray *observedElementTags = (NSArray *)[webView objectByEvaluatingJavaScript:@"Array.from(document.body.children).map(e => e.tagName)"];
     1119    NSArray *expectedElementTags = @[ @"ATTACHMENT", @"A", @"ATTACHMENT" ];
     1120    EXPECT_TRUE([observedElementTags isEqualToArray:expectedElementTags]);
     1121    if (![observedElementTags isEqualToArray:expectedElementTags])
     1122        NSLog(@"Observed elements: %@ did not match expectations: %@", observedElementTags, expectedElementTags);
     1123
     1124    EXPECT_WK_STREQ("first.txt", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]);
     1125    EXPECT_WK_STREQ("text/plain", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
     1126    EXPECT_WK_STREQ([appleURL absoluteString], [webView valueOfAttribute:@"href" forQuerySelector:@"a"]);
     1127    EXPECT_WK_STREQ("second.pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]);
     1128    EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]);
     1129}
     1130
    10131131#endif // PLATFORM(IOS)
    10141132
  • trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm

    r223440 r226396  
    345345    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
    346346    checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 961, 227) ], [dataInteractionSimulator finalSelectionRects]);
    347     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
     347    checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTF, (NSString *)kUTTypeUTF8PlainText);
    348348}
    349349
     
    365365    EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
    366366    checkSelectionRectsWithLogging(@[ makeCGRectValue(6, 203, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
    367     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
     367    checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTF, (NSString *)kUTTypeUTF8PlainText);
    368368}
    369369
  • trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h

    r222654 r226396  
    4646- (void)synchronouslyLoadHTMLString:(NSString *)html;
    4747- (void)synchronouslyLoadTestPageNamed:(NSString *)pageName;
     48- (id)objectByEvaluatingJavaScript:(NSString *)script;
    4849- (NSString *)stringByEvaluatingJavaScript:(NSString *)script;
    4950- (void)waitForMessage:(NSString *)message;
  • trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm

    r222654 r226396  
    239239}
    240240
    241 - (NSString *)stringByEvaluatingJavaScript:(NSString *)script
    242 {
    243     __block bool isWaitingForJavaScript = false;
    244     __block NSString *evalResult = nil;
    245     [self _evaluateJavaScriptWithoutUserGesture:script completionHandler:^(id result, NSError *error)
    246     {
    247         evalResult = [[NSString alloc] initWithFormat:@"%@", result];
     241- (id)objectByEvaluatingJavaScript:(NSString *)script
     242{
     243    bool isWaitingForJavaScript = false;
     244    RetainPtr<id> evalResult;
     245    [self _evaluateJavaScriptWithoutUserGesture:script completionHandler:[&] (id result, NSError *error) {
     246        evalResult = result;
    248247        isWaitingForJavaScript = true;
    249248        EXPECT_TRUE(!error);
     
    251250            NSLog(@"Encountered error: %@ while evaluating script: %@", error, script);
    252251    }];
    253 
    254252    TestWebKitAPI::Util::run(&isWaitingForJavaScript);
    255     return [evalResult autorelease];
     253    return evalResult.autorelease();
     254}
     255
     256- (NSString *)stringByEvaluatingJavaScript:(NSString *)script
     257{
     258    return [NSString stringWithFormat:@"%@", [self objectByEvaluatingJavaScript:script]];
    256259}
    257260
Note: See TracChangeset for help on using the changeset viewer.