Changeset 226093 in webkit


Ignore:
Timestamp:
Dec 18, 2017 8:03:21 PM (6 years ago)
Author:
Wenson Hsieh
Message:

[Attachment Support] Support representing pasted or dropped content using attachment elements
https://bugs.webkit.org/show_bug.cgi?id=180892
<rdar://problem/36064210>

Reviewed by Tim Horton.

Source/WebCore:

Support dropping and pasting attributed strings that contain NSTextAttachments. Teaches
replaceRichContentWithAttachmentsIfNecessary to replace object elements with attachments; see comments below for
more details.

Test: WKAttachmentTests.InsertPastedAttributedStringContainingMultipleAttachments

  • editing/WebContentReader.h:

Add BlobReplacementInfo, which contains a map of blob URLs to replacement Blobs, as well as a map of blob URLs
to replaced subresource URLs.

(WebCore::BlobReplacementInfo::isEmpty const):

  • editing/cocoa/EditorCocoa.mm:

(WebCore::Editor::replaceSelectionWithAttributedString):

  • editing/cocoa/WebArchiveResourceFromNSAttributedString.h:
  • editing/cocoa/WebArchiveResourceFromNSAttributedString.mm:

Implement -[WebArchiveResourceFromNSAttributedString MIMEType]. UIFoundation asks for -MIMEType in the process
of generating markup from NSTextAttachments; this currently causes the web process to crash on an unrecognized
selector.

Additionally, work around <rdar://problem/36074429>, a UIFoundation bug in which all but a few hard-coded file
extensions actually yield MIME types that are more specific than "application/octet-stream". This can safely be
removed once <rdar://problem/36074429> is addressed.

(-[WebArchiveResourceFromNSAttributedString MIMEType]):

  • editing/cocoa/WebContentReaderCocoa.mm:

(WebCore::replaceRichContentWithAttachmentsIfNecessary):

Try to replace object elements with attachments, and also tweak the title of the attachment's File to use the
replaced subresource's filename if possible. Additionally, abstracts out information for replacing object or
image elements (formerly a pair of { File, Element }) into a separate struct, and add a AttachmentDisplayMode
parameter to determine whether the attachment should be presented in-line (in the case of images), or as an icon.

(WebCore::attributesForAttributedStringConversion):

Only exclude object elements from being generated from NSTextAttachments if the attachment element runtime
feature is disabled, or !ENABLE(ATTACHMENT_ELEMENT).

(WebCore::createFragmentAndAddResources):

Additionally keep track of a mapping from blob URL => replaced subresource URL. In all the places where we
previously only plumbed a map of blob URL => Blob, use a BlobReplacementInfo struct instead, which now includes
a map from blob URL => replaced URL.

(WebCore::sanitizeMarkupWithArchive):
(WebCore::WebContentReader::readWebArchive):
(WebCore::WebContentMarkupReader::readWebArchive):
(WebCore::WebContentReader::readRTFD):
(WebCore::WebContentMarkupReader::readRTFD):
(WebCore::WebContentReader::readRTF):
(WebCore::WebContentMarkupReader::readRTF):
(WebCore::WebContentReader::readImage):

Tools:

Adds a new API test to exercise pasting an attributed string with multiple attachments of different types.

  • TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:

(testZIPData):
(platformCopyRichTextWithMultipleAttachments):
(TestWebKitAPI::TEST):

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r226090 r226093  
     12017-12-18  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Attachment Support] Support representing pasted or dropped content using attachment elements
     4        https://bugs.webkit.org/show_bug.cgi?id=180892
     5        <rdar://problem/36064210>
     6
     7        Reviewed by Tim Horton.
     8
     9        Support dropping and pasting attributed strings that contain NSTextAttachments. Teaches
     10        replaceRichContentWithAttachmentsIfNecessary to replace object elements with attachments; see comments below for
     11        more details.
     12
     13        Test: WKAttachmentTests.InsertPastedAttributedStringContainingMultipleAttachments
     14
     15        * editing/WebContentReader.h:
     16
     17        Add BlobReplacementInfo, which contains a map of blob URLs to replacement Blobs, as well as a map of blob URLs
     18        to replaced subresource URLs.
     19
     20        (WebCore::BlobReplacementInfo::isEmpty const):
     21        * editing/cocoa/EditorCocoa.mm:
     22        (WebCore::Editor::replaceSelectionWithAttributedString):
     23        * editing/cocoa/WebArchiveResourceFromNSAttributedString.h:
     24        * editing/cocoa/WebArchiveResourceFromNSAttributedString.mm:
     25
     26        Implement -[WebArchiveResourceFromNSAttributedString MIMEType]. UIFoundation asks for -MIMEType in the process
     27        of generating markup from NSTextAttachments; this currently causes the web process to crash on an unrecognized
     28        selector.
     29
     30        Additionally, work around <rdar://problem/36074429>, a UIFoundation bug in which all but a few hard-coded file
     31        extensions actually yield MIME types that are more specific than "application/octet-stream". This can safely be
     32        removed once <rdar://problem/36074429> is addressed.
     33
     34        (-[WebArchiveResourceFromNSAttributedString MIMEType]):
     35        * editing/cocoa/WebContentReaderCocoa.mm:
     36        (WebCore::replaceRichContentWithAttachmentsIfNecessary):
     37
     38        Try to replace object elements with attachments, and also tweak the title of the attachment's File to use the
     39        replaced subresource's filename if possible. Additionally, abstracts out information for replacing object or
     40        image elements (formerly a pair of { File, Element }) into a separate struct, and add a AttachmentDisplayMode
     41        parameter to determine whether the attachment should be presented in-line (in the case of images), or as an icon.
     42
     43        (WebCore::attributesForAttributedStringConversion):
     44
     45        Only exclude object elements from being generated from NSTextAttachments if the attachment element runtime
     46        feature is disabled, or !ENABLE(ATTACHMENT_ELEMENT).
     47
     48        (WebCore::createFragmentAndAddResources):
     49
     50        Additionally keep track of a mapping from blob URL => replaced subresource URL. In all the places where we
     51        previously only plumbed a map of blob URL => Blob, use a BlobReplacementInfo struct instead, which now includes
     52        a map from blob URL => replaced URL.
     53
     54        (WebCore::sanitizeMarkupWithArchive):
     55        (WebCore::WebContentReader::readWebArchive):
     56        (WebCore::WebContentMarkupReader::readWebArchive):
     57        (WebCore::WebContentReader::readRTFD):
     58        (WebCore::WebContentMarkupReader::readRTFD):
     59        (WebCore::WebContentReader::readRTF):
     60        (WebCore::WebContentMarkupReader::readRTF):
     61        (WebCore::WebContentReader::readImage):
     62
    1632017-12-18  Youenn Fablet  <youenn@apple.com>
    264
  • trunk/Source/WebCore/editing/WebContentReader.h

    r226085 r226093  
    107107};
    108108
    109 void replaceRichContentWithAttachmentsIfNecessary(DocumentFragment&, HashMap<AtomicString, RefPtr<Blob>>&& urlToBlobMap);
    110 RefPtr<DocumentFragment> createFragmentAndAddResources(Frame&, NSAttributedString*, HashMap<AtomicString, RefPtr<Blob>>& urlToBlobMap);
     109struct BlobReplacementInfo {
     110    HashMap<AtomicString, RefPtr<Blob>> blobURLToBlobMap;
     111    HashMap<AtomicString, AtomicString> blobURLToReplacedURLMap;
     112    bool isEmpty() const { return blobURLToBlobMap.isEmpty(); }
     113};
     114
     115void replaceRichContentWithAttachmentsIfNecessary(DocumentFragment&, BlobReplacementInfo&&);
     116RefPtr<DocumentFragment> createFragmentAndAddResources(Frame&, NSAttributedString*, BlobReplacementInfo&);
    111117#endif
    112118
  • trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm

    r226085 r226093  
    223223
    224224    if (m_frame.selection().selection().isContentRichlyEditable()) {
    225         HashMap<AtomicString, RefPtr<Blob>> urlToBlobMap;
    226         if (auto fragment = createFragmentAndAddResources(m_frame, attributedString, urlToBlobMap)) {
    227             replaceRichContentWithAttachmentsIfNecessary(*fragment, WTFMove(urlToBlobMap));
     225        BlobReplacementInfo replacementInfo;
     226        if (auto fragment = createFragmentAndAddResources(m_frame, attributedString, replacementInfo)) {
     227            replaceRichContentWithAttachmentsIfNecessary(*fragment, WTFMove(replacementInfo));
    228228            if (shouldInsertFragment(*fragment, selectedRange().get(), EditorInsertAction::Pasted))
    229229                pasteAsFragment(fragment.releaseNonNull(), false, false, mailBlockquoteHandling);
  • trunk/Source/WebCore/editing/cocoa/WebArchiveResourceFromNSAttributedString.h

    r222239 r226093  
    3737}
    3838- (instancetype)initWithData:(NSData *)data URL:(NSURL *)URL MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName frameName:(NSString *)frameName;
     39- (NSString *)MIMEType;
    3940- (NSURL *)URL;
    4041
  • trunk/Source/WebCore/editing/cocoa/WebArchiveResourceFromNSAttributedString.mm

    r224267 r226093  
    2828
    2929#import "ArchiveResource.h"
     30#import "MIMETypeRegistry.h"
    3031
    3132using namespace WebCore;
     
    4344    }
    4445
     46    if ([MIMEType isEqualToString:@"application/octet-stream"]) {
     47        // FIXME: This is a workaround for <rdar://problem/36074429>, and can be removed once that is fixed.
     48        auto mimeTypeFromURL = MIMETypeRegistry::getMIMETypeForExtension(URL.pathExtension);
     49        if (!mimeTypeFromURL.isEmpty())
     50            MIMEType = mimeTypeFromURL;
     51    }
     52
    4553    resource = ArchiveResource::create(SharedBuffer::create(adoptNS([data copy]).get()), URL, MIMEType, textEncodingName, frameName, { });
    4654    if (!resource) {
     
    5260}
    5361
     62- (NSString *)MIMEType
     63{
     64    return resource->mimeType();
     65}
     66
    5467- (NSURL *)URL
    5568{
  • trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm

    r226089 r226093  
    4343#import "HTMLIFrameElement.h"
    4444#import "HTMLImageElement.h"
     45#import "HTMLObjectElement.h"
    4546#import "LegacyWebArchive.h"
    4647#import "MainFrame.h"
     
    5152#import "SocketProvider.h"
    5253#import "TypedElementDescendantIterator.h"
     54#import "URLParser.h"
    5355#import "WebArchiveResourceFromNSAttributedString.h"
    5456#import "WebArchiveResourceWebResourceHandler.h"
     
    7779#if ENABLE(ATTACHMENT_ELEMENT)
    7880
    79 void replaceRichContentWithAttachmentsIfNecessary(DocumentFragment& fragment, HashMap<AtomicString, RefPtr<Blob>>&& urlToBlobMap)
    80 {
    81     if (!RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled() || urlToBlobMap.isEmpty())
     81struct AttachmentReplacementInfo {
     82    AttachmentDisplayMode displayMode;
     83    Ref<File> file;
     84    Ref<Element> elementToReplace;
     85};
     86
     87void replaceRichContentWithAttachmentsIfNecessary(DocumentFragment& fragment, BlobReplacementInfo&& replacementInfo)
     88{
     89    if (!RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled() || replacementInfo.isEmpty())
    8290        return;
    8391
    8492    Vector<Ref<Element>> elementsToRemove;
    85     Vector<std::pair<Ref<File>, Ref<Element>>> filesForElementsToReplace;
     93    Vector<AttachmentReplacementInfo> attachmentReplacementInfo;
    8694    for (auto& image : descendantsOfType<HTMLImageElement>(fragment)) {
    8795        auto url = image.attributeWithoutSynchronization(HTMLNames::srcAttr);
    88 
    89         if (url.isEmpty()) {
    90             elementsToRemove.append(image);
    91             continue;
    92         }
    93 
    94         auto blob = urlToBlobMap.get(url);
    95         if (!blob) {
    96             elementsToRemove.append(image);
    97             continue;
    98         }
    99 
    100         auto title = image.attributeWithoutSynchronization(HTMLNames::titleAttr);
     96        if (url.isEmpty())
     97            continue;
     98
     99        auto blob = replacementInfo.blobURLToBlobMap.get(url);
     100        if (!blob)
     101            continue;
     102
     103        auto title = URLParser { replacementInfo.blobURLToReplacedURLMap.get(url) }.result().lastPathComponent();
    101104        if (title.isEmpty())
    102105            title = AtomicString("media");
    103106
    104         filesForElementsToReplace.append({ File::create(*blob, title), image });
    105     }
    106 
    107     for (auto& fileAndElement : filesForElementsToReplace) {
    108         auto& file = fileAndElement.first;
    109         auto& elementToReplace = fileAndElement.second;
     107        attachmentReplacementInfo.append({ AttachmentDisplayMode::InPlace, File::create(*blob, title), image });
     108    }
     109
     110    for (auto& object : descendantsOfType<HTMLObjectElement>(fragment)) {
     111        auto url = object.attributeWithoutSynchronization(HTMLNames::dataAttr);
     112        if (url.isEmpty()) {
     113            elementsToRemove.append(object);
     114            continue;
     115        }
     116
     117        auto blob = replacementInfo.blobURLToBlobMap.get(url);
     118        if (!blob) {
     119            elementsToRemove.append(object);
     120            continue;
     121        }
     122
     123        auto title = URLParser { replacementInfo.blobURLToReplacedURLMap.get(url) }.result().lastPathComponent();
     124        if (title.isEmpty())
     125            title = AtomicString("file");
     126
     127        attachmentReplacementInfo.append({ AttachmentDisplayMode::AsIcon, File::create(*blob, title), object });
     128    }
     129
     130    for (auto& info : attachmentReplacementInfo) {
     131        auto file = WTFMove(info.file);
     132        auto elementToReplace = WTFMove(info.elementToReplace);
    110133        auto parent = makeRefPtr(elementToReplace->parentNode());
    111134        if (!parent)
     
    115138        attachment->setUniqueIdentifier(createCanonicalUUIDString());
    116139        attachment->setFile(WTFMove(file), HTMLAttachmentElement::UpdateDisplayAttributes::Yes);
    117         attachment->updateDisplayMode(AttachmentDisplayMode::InPlace);
     140        attachment->updateDisplayMode(info.displayMode);
    118141        parent->replaceChild(attachment, elementToReplace);
    119142    }
     
    136159{
    137160    // This function needs to be kept in sync with identically named one in WebKitLegacy, which is used on older OS versions.
    138     RetainPtr<NSArray> excludedElements = adoptNS([[NSArray alloc] initWithObjects:
     161    RetainPtr<NSMutableArray> excludedElements = adoptNS([[NSMutableArray alloc] initWithObjects:
    139162        // Omit style since we want style to be inline so the fragment can be easily inserted.
    140163        @"style",
     
    145168        // Omit deprecated tags.
    146169        @"applet", @"basefont", @"center", @"dir", @"font", @"menu", @"s", @"strike", @"u",
     170#if !ENABLE(ATTACHMENT_ELEMENT)
    147171        // Omit object so no file attachments are part of the fragment.
    148         @"object", nil]);
     172        @"object",
     173#endif
     174        nil]);
     175
     176#if ENABLE(ATTACHMENT_ELEMENT)
     177    if (!RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled())
     178        [excludedElements addObject:@"object"];
     179#endif
    149180
    150181#if PLATFORM(IOS)
     
    221252};
    222253
    223 RefPtr<DocumentFragment> createFragmentAndAddResources(Frame& frame, NSAttributedString *string, HashMap<AtomicString, RefPtr<Blob>>& urlToBlobMap)
     254RefPtr<DocumentFragment> createFragmentAndAddResources(Frame& frame, NSAttributedString *string, BlobReplacementInfo& replacementInfo)
    224255{
    225256    if (!frame.page() || !frame.document())
     
    240271        String blobURL = DOMURL::createObjectURL(document, blob);
    241272        blobURLMap.set(subresource->url().string(), blobURL);
    242         urlToBlobMap.set(blobURL, WTFMove(blob));
     273        replacementInfo.blobURLToBlobMap.set(blobURL, WTFMove(blob));
     274        replacementInfo.blobURLToReplacedURLMap.set(blobURL, subresource->url().string());
    243275    }
    244276    replaceSubresourceURLs(*fragmentAndResources.fragment, WTFMove(blobURLMap));
     
    270302}
    271303
    272 static String sanitizeMarkupWithArchive(Document& destinationDocument, MarkupAndArchive& markupAndArchive, const std::function<bool(const String)>& canShowMIMETypeAsHTML, HashMap<AtomicString, RefPtr<Blob>>& urlToBlobMap)
     304static String sanitizeMarkupWithArchive(Document& destinationDocument, MarkupAndArchive& markupAndArchive, const std::function<bool(const String)>& canShowMIMETypeAsHTML, BlobReplacementInfo& replacementInfo)
    273305{
    274306    auto page = createPageForSanitizingWebContent();
     
    282314        String blobURL = DOMURL::createObjectURL(destinationDocument, blob);
    283315        blobURLMap.set(subresource->url().string(), blobURL);
    284         urlToBlobMap.set(blobURL, WTFMove(blob));
     316        replacementInfo.blobURLToBlobMap.set(blobURL, WTFMove(blob));
     317        replacementInfo.blobURLToReplacedURLMap.set(blobURL, subresource->url().string());
    285318    }
    286319
     
    298331        MarkupAndArchive subframeContent = { String::fromUTF8(subframeMainResource->data().data(), subframeMainResource->data().size()),
    299332            subframeMainResource.releaseNonNull(), subframeArchive.copyRef() };
    300         auto subframeMarkup = sanitizeMarkupWithArchive(destinationDocument, subframeContent, canShowMIMETypeAsHTML, urlToBlobMap);
     333        auto subframeMarkup = sanitizeMarkupWithArchive(destinationDocument, subframeContent, canShowMIMETypeAsHTML, replacementInfo);
    301334
    302335        CString utf8 = subframeMarkup.utf8();
     
    308341        String subframeBlobURL = DOMURL::createObjectURL(destinationDocument, blob);
    309342        blobURLMap.set(subframeURL.string(), subframeBlobURL);
    310         urlToBlobMap.set(subframeBlobURL, WTFMove(blob));
     343        replacementInfo.blobURLToBlobMap.set(subframeBlobURL, WTFMove(blob));
     344        replacementInfo.blobURLToReplacedURLMap.set(subframeBlobURL, subframeURL.string());
    311345    }
    312346
     
    339373    }
    340374
    341     HashMap<AtomicString, RefPtr<Blob>> urlToBlobMap;
     375    BlobReplacementInfo replacementInfo;
    342376    String sanitizedMarkup = sanitizeMarkupWithArchive(*frame.document(), *result, [&] (const String& type) {
    343377        return frame.loader().client().canShowMIMETypeAsHTML(type);
    344     }, urlToBlobMap);
     378    }, replacementInfo);
    345379    fragment = createFragmentFromMarkup(*frame.document(), sanitizedMarkup, blankURL(), DisallowScriptingAndPluginContent);
    346380
     
    348382        return false;
    349383
    350     replaceRichContentWithAttachmentsIfNecessary(*fragment, WTFMove(urlToBlobMap));
     384    replaceRichContentWithAttachmentsIfNecessary(*fragment, WTFMove(replacementInfo));
    351385    return true;
    352386}
     
    368402    }
    369403
    370     HashMap<AtomicString, RefPtr<Blob>> urlToBlobMap;
     404    BlobReplacementInfo replacementInfo;
    371405    markup = sanitizeMarkupWithArchive(*frame.document(), *result, [&] (const String& type) {
    372406        return frame.loader().client().canShowMIMETypeAsHTML(type);
    373     }, urlToBlobMap);
     407    }, replacementInfo);
    374408
    375409    return true;
     
    421455static RefPtr<DocumentFragment> createFragmentFromAttributedString(Frame& frame, NSAttributedString *string)
    422456{
    423     HashMap<AtomicString, RefPtr<Blob>> urlToBlobMap;
    424     auto fragment = createFragmentAndAddResources(frame, string, urlToBlobMap);
     457    BlobReplacementInfo replacementInfo;
     458    auto fragment = createFragmentAndAddResources(frame, string, replacementInfo);
    425459    if (!fragment)
    426460        return nullptr;
    427461
    428     replaceRichContentWithAttachmentsIfNecessary(*fragment, WTFMove(urlToBlobMap));
     462    replaceRichContentWithAttachmentsIfNecessary(*fragment, WTFMove(replacementInfo));
    429463    return fragment;
    430464}
     
    505539        return false;
    506540
    507     replaceRichContentWithAttachmentsIfNecessary(*fragment, {{ blobURL, WTFMove(blob) }});
    508     return true;
    509 }
    510 
    511 }
     541    replaceRichContentWithAttachmentsIfNecessary(*fragment, {{{ blobURL, WTFMove(blob) }}, { }});
     542    return true;
     543}
     544
     545}
  • trunk/Tools/ChangeLog

    r226088 r226093  
     12017-12-18  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Attachment Support] Support representing pasted or dropped content using attachment elements
     4        https://bugs.webkit.org/show_bug.cgi?id=180892
     5        <rdar://problem/36064210>
     6
     7        Reviewed by Tim Horton.
     8
     9        Adds a new API test to exercise pasting an attributed string with multiple attachments of different types.
     10
     11        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
     12        (testZIPData):
     13        (platformCopyRichTextWithMultipleAttachments):
     14        (TestWebKitAPI::TEST):
     15
    1162017-12-18  Brady Eidson  <beidson@apple.com>
    217
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm

    r226085 r226093  
    137137}
    138138
     139static NSData *testZIPData()
     140{
     141    NSURL *zipFileURL = [[NSBundle mainBundle] URLForResource:@"compressed-files" withExtension:@"zip" subdirectory:@"TestWebKitAPI.resources"];
     142    return [NSData dataWithContentsOfURL:zipFileURL];
     143}
     144
    139145static NSData *testHTMLData()
    140146{
     
    308314
    309315#pragma mark - Platform testing helper functions
     316
     317void platformCopyRichTextWithMultipleAttachments()
     318{
     319    auto image = adoptNS([[NSTextAttachment alloc] initWithData:testImageData() ofType:(NSString *)kUTTypePNG]);
     320    auto pdf = adoptNS([[NSTextAttachment alloc] initWithData:testPDFData() ofType:(NSString *)kUTTypePDF]);
     321    auto zip = adoptNS([[NSTextAttachment alloc] initWithData:testZIPData() ofType:(NSString *)kUTTypeZipArchive]);
     322
     323    auto richText = adoptNS([[NSMutableAttributedString alloc] init]);
     324    [richText appendAttributedString:[NSAttributedString attributedStringWithAttachment:image.get()]];
     325    [richText appendAttributedString:[NSAttributedString attributedStringWithAttachment:pdf.get()]];
     326    [richText appendAttributedString:[NSAttributedString attributedStringWithAttachment:zip.get()]];
     327
     328#if PLATFORM(MAC)
     329    NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
     330    [pasteboard clearContents];
     331    [pasteboard writeObjects:@[ richText.get() ]];
     332#elif PLATFORM(IOS)
     333    auto item = adoptNS([[NSItemProvider alloc] init]);
     334    [item registerObject:richText.get() visibility:NSItemProviderRepresentationVisibilityAll];
     335    [UIPasteboard generalPasteboard].itemProviders = @[ item.get() ];
     336#endif
     337}
    310338
    311339void platformCopyRichTextWithImage()
     
    801829}
    802830
     831TEST(WKAttachmentTests, InsertPastedAttributedStringContainingMultipleAttachments)
     832{
     833    platformCopyRichTextWithMultipleAttachments();
     834
     835    RetainPtr<_WKAttachment> imageAttachment;
     836    RetainPtr<_WKAttachment> zipAttachment;
     837    RetainPtr<_WKAttachment> pdfAttachment;
     838    auto webView = webViewForTestingAttachments();
     839    {
     840        ObserveAttachmentUpdatesForScope observer(webView.get());
     841        [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil];
     842        EXPECT_EQ(0U, observer.observer().removed.count);
     843        EXPECT_EQ(3U, observer.observer().inserted.count);
     844        for (_WKAttachment *attachment in observer.observer().inserted) {
     845            NSData *data = [attachment synchronouslyRequestData:nil];
     846            if ([data isEqualToData:testZIPData()])
     847                zipAttachment = attachment;
     848            else if ([data isEqualToData:testPDFData()])
     849                pdfAttachment = attachment;
     850            else if ([data isEqualToData:testImageData()])
     851                imageAttachment = attachment;
     852        }
     853    }
     854
     855    EXPECT_TRUE(zipAttachment && imageAttachment && pdfAttachment);
     856    EXPECT_EQ(3, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment').length"].integerValue);
     857    EXPECT_WK_STREQ("image/png", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
     858    EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]);
     859    EXPECT_WK_STREQ("application/zip", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[2].getAttribute('type')"]);
     860
     861    {
     862        ObserveAttachmentUpdatesForScope observer(webView.get());
     863        [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil];
     864        [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil];
     865        NSArray<_WKAttachment *> *removedAttachments = [observer.observer() removed];
     866        EXPECT_EQ(3U, removedAttachments.count);
     867        EXPECT_TRUE([removedAttachments containsObject:zipAttachment.get()]);
     868        EXPECT_TRUE([removedAttachments containsObject:imageAttachment.get()]);
     869        EXPECT_TRUE([removedAttachments containsObject:pdfAttachment.get()]);
     870    }
     871}
     872
    803873#pragma mark - Platform-specific tests
    804874
Note: See TracChangeset for help on using the changeset viewer.