Title: [225311] trunk
Revision
225311
Author
wenson_hs...@apple.com
Date
2017-11-29 18:23:44 -0800 (Wed, 29 Nov 2017)

Log Message

[Attachment Support] Implement SPI for clients to make an attachment element display in-place
https://bugs.webkit.org/show_bug.cgi?id=180153
<rdar://problem/35735252>

Reviewed by Tim Horton.

Source/WebCore:

Adds SPI support for inserting attachments using in-place display style, and updating display options for
existing attachments. See comments below for more detail.

Tests: WKAttachmentTests.InPlaceImageAttachmentToggleDisplayMode
       WKAttachmentTests.InPlaceImageAttachmentParagraphInsertion
       WKAttachmentTests.InPlaceVideoAttachmentInsertionWithinList
       WKAttachmentTests.InPlacePDFAttachmentCutAndPaste

* WebCore.xcodeproj/project.pbxproj:
* editing/Editor.cpp:
(WebCore::Editor::insertAttachment):
(WebCore::Editor::insertAttachmentFromFile):

Update display options for the attachment before inserting into the document.

* editing/Editor.h:
* html/AttachmentTypes.h: Added.

Add a new header to define the new attachment display types. This lets us avoid importing HTMLAttachmentElement.h
and instead just import AttachmentTypes.h in some places in WebKit that only deal with plumbing
AttachmentDisplayOptions to the web process.

(WebCore::AttachmentDisplayOptions::encode const):
(WebCore::AttachmentDisplayOptions::decode):

Support serializing and deserializing attachment display options.

* html/HTMLAttachmentElement.cpp:
(WebCore::HTMLAttachmentElement::setFile):

Regenerate the shadow root if needed when setting the file.

(WebCore::HTMLAttachmentElement::updateDisplayMode):

Introduce a new method to update the display mode of an attachment element. This builds up the shadow root of
the attachment if it is displayed in-place.

(WebCore::HTMLAttachmentElement::ensureInnerImage):
(WebCore::HTMLAttachmentElement::ensureInnerVideo):

Helpers to insert image and video elements into the shadow root if needed, and return the image or video element.

(WebCore::HTMLAttachmentElement::innerImage const):
(WebCore::HTMLAttachmentElement::innerVideo const):

Helpers to retrieve existing image and video elements in the shadow root.

(WebCore::HTMLAttachmentElement::populateShadowRootIfNecessary):

Appends and configures the attachment element's shadow root for inline display, initializing an image or video
element or neither, depending on the attachment type.

* html/HTMLAttachmentElement.h:

Introduce an AttachmentDisplayOptions struct which mirrors _WKAttachmentDisplayOptions in the WebKit layer. For
now, this only contains a display mode enum.

* platform/audio/ios/AudioSessionIOS.mm:

Avoid this AVAudioSession assertion when targeting iOS simulator. AVAudioSession always throws this error when
setting an audio session category in the simulator, even in a basic test app, since AVFoundation doesn't support
audio sessions in the simulator.

(WebCore::AudioSession::setCategory):

Source/WebKit:

Add new WebKit SPI, -[_WKAttachment setDisplayOptions:completion:], and add plumbing for attachment display
options to the web content process. Changes covered by 4 new API tests.

* Scripts/webkit/messages.py:
(headers_for_type):
* UIProcess/API/APIAttachment.cpp:
(API::Attachment::setDisplayOptions):
* UIProcess/API/APIAttachment.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _insertAttachmentWithFilename:contentType:data:options:completion:]):

Respect given display options when inserting a new attachment.

* UIProcess/API/Cocoa/_WKAttachment.h:
* UIProcess/API/Cocoa/_WKAttachment.mm:
(-[_WKAttachmentDisplayOptions coreDisplayOptions]):

Introduce a helper to convert from the Cocoa _WKAttachmentDisplayOptions object to platform-agnostic
AttachmentDisplayOptions.

(-[_WKAttachment setDisplayOptions:completion:]):
(WebKit::if): Deleted.
* UIProcess/API/Cocoa/_WKAttachmentInternal.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::insertAttachment):
(WebKit::WebPageProxy::setAttachmentDisplayOptions):
* UIProcess/WebPageProxy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::insertAttachment):
(WebKit::WebPage::requestAttachmentData):
(WebKit::WebPage::setAttachmentDisplayOptions):
(WebKit::WebPage::attachmentElementWithIdentifier const):

Pull common logic to retrieve an attachment element matching a given identifier out into a helper.

* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

Adds new API tests to cover inserting in-place attachments and updating the display mode of existing attachments,
as well as performing a few editing operations (paragraph insertion, cut/paste, list insertion) on attachment
elements.

* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
(platformAttachmentIconElementSize):
(testVideoData):
(testPDFData):
(displayOptionsWithMode):
(-[TestWKWebView waitForAttachmentElementSizeToBecome:]):
(-[_WKAttachment synchronouslySetDisplayOptions:error:]):
(TestWebKitAPI::TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (225310 => 225311)


--- trunk/Source/WebCore/ChangeLog	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebCore/ChangeLog	2017-11-30 02:23:44 UTC (rev 225311)
@@ -1,3 +1,76 @@
+2017-11-29  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Attachment Support] Implement SPI for clients to make an attachment element display in-place
+        https://bugs.webkit.org/show_bug.cgi?id=180153
+        <rdar://problem/35735252>
+
+        Reviewed by Tim Horton.
+
+        Adds SPI support for inserting attachments using in-place display style, and updating display options for
+        existing attachments. See comments below for more detail.
+
+        Tests: WKAttachmentTests.InPlaceImageAttachmentToggleDisplayMode
+               WKAttachmentTests.InPlaceImageAttachmentParagraphInsertion
+               WKAttachmentTests.InPlaceVideoAttachmentInsertionWithinList
+               WKAttachmentTests.InPlacePDFAttachmentCutAndPaste
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * editing/Editor.cpp:
+        (WebCore::Editor::insertAttachment):
+        (WebCore::Editor::insertAttachmentFromFile):
+
+        Update display options for the attachment before inserting into the document.
+
+        * editing/Editor.h:
+        * html/AttachmentTypes.h: Added.
+
+        Add a new header to define the new attachment display types. This lets us avoid importing HTMLAttachmentElement.h
+        and instead just import AttachmentTypes.h in some places in WebKit that only deal with plumbing
+        AttachmentDisplayOptions to the web process.
+
+        (WebCore::AttachmentDisplayOptions::encode const):
+        (WebCore::AttachmentDisplayOptions::decode):
+
+        Support serializing and deserializing attachment display options.
+
+        * html/HTMLAttachmentElement.cpp:
+        (WebCore::HTMLAttachmentElement::setFile):
+
+        Regenerate the shadow root if needed when setting the file.
+
+        (WebCore::HTMLAttachmentElement::updateDisplayMode):
+
+        Introduce a new method to update the display mode of an attachment element. This builds up the shadow root of
+        the attachment if it is displayed in-place.
+
+        (WebCore::HTMLAttachmentElement::ensureInnerImage):
+        (WebCore::HTMLAttachmentElement::ensureInnerVideo):
+
+        Helpers to insert image and video elements into the shadow root if needed, and return the image or video element.
+
+        (WebCore::HTMLAttachmentElement::innerImage const):
+        (WebCore::HTMLAttachmentElement::innerVideo const):
+
+        Helpers to retrieve existing image and video elements in the shadow root.
+
+        (WebCore::HTMLAttachmentElement::populateShadowRootIfNecessary):
+
+        Appends and configures the attachment element's shadow root for inline display, initializing an image or video
+        element or neither, depending on the attachment type.
+
+        * html/HTMLAttachmentElement.h:
+
+        Introduce an AttachmentDisplayOptions struct which mirrors _WKAttachmentDisplayOptions in the WebKit layer. For
+        now, this only contains a display mode enum.
+
+        * platform/audio/ios/AudioSessionIOS.mm:
+
+        Avoid this AVAudioSession assertion when targeting iOS simulator. AVAudioSession always throws this error when
+        setting an audio session category in the simulator, even in a basic test app, since AVFoundation doesn't support
+        audio sessions in the simulator.
+
+        (WebCore::AudioSession::setCategory):
+
 2017-11-29  Simon Fraser  <simon.fra...@apple.com>
 
         Missing layer content when animating elements on-screen

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (225310 => 225311)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-11-30 02:23:44 UTC (rev 225311)
@@ -4613,6 +4613,7 @@
 		F3ABFE0C130E9DA000E7F7D1 /* InstrumentingAgents.h in Headers */ = {isa = PBXBuildFile; fileRef = F3ABFE0B130E9DA000E7F7D1 /* InstrumentingAgents.h */; };
 		F3D461491161D53200CA0D09 /* JSErrorHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D461471161D53200CA0D09 /* JSErrorHandler.h */; };
 		F433E9031DBBDBA200EF0D14 /* StaticPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F433E9021DBBDBA200EF0D14 /* StaticPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		F43759B41FCF48FA00100706 /* AttachmentTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = F43759B31FCF48FA00100706 /* AttachmentTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F44EBBD91DB5D21400277334 /* StaticRange.h in Headers */ = {isa = PBXBuildFile; fileRef = F44EBBD81DB5D21400277334 /* StaticRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F45C231E1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h in Headers */ = {isa = PBXBuildFile; fileRef = F45C231C1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F46729281E0DE68500ACC3D8 /* ScrollSnapOffsetsInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F46729251E0DE5AB00ACC3D8 /* ScrollSnapOffsetsInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -13963,6 +13964,7 @@
 		F3D461471161D53200CA0D09 /* JSErrorHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSErrorHandler.h; sourceTree = "<group>"; };
 		F433E9021DBBDBA200EF0D14 /* StaticPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticPasteboard.h; sourceTree = "<group>"; };
 		F433E9041DBBDBC200EF0D14 /* StaticPasteboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StaticPasteboard.cpp; sourceTree = "<group>"; };
+		F43759B31FCF48FA00100706 /* AttachmentTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AttachmentTypes.h; sourceTree = "<group>"; };
 		F44EBBD61DB5D1B600277334 /* StaticRange.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = StaticRange.idl; sourceTree = "<group>"; };
 		F44EBBD81DB5D21400277334 /* StaticRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticRange.h; sourceTree = "<group>"; };
 		F44EBBDA1DB5DD9D00277334 /* StaticRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticRange.cpp; sourceTree = "<group>"; };
@@ -19453,6 +19455,7 @@
 				97C1F5511228558800EDE616 /* parser */,
 				4150F9ED12B6E0990008C860 /* shadow */,
 				B1AD4E7713A12A7200846B27 /* track */,
+				F43759B31FCF48FA00100706 /* AttachmentTypes.h */,
 				A5F6E16C132ED46E008EDAE3 /* Autocapitalize.cpp */,
 				A501920C132EBF2E008BFE55 /* Autocapitalize.h */,
 				A5A7AA42132F0ECC00D3A3C2 /* AutocapitalizeTypes.h */,
@@ -26053,6 +26056,7 @@
 				FD5686CA13AC180200B69C68 /* AsyncAudioDecoder.h in Headers */,
 				E1CDE9221501916900862CC5 /* AsyncFileStream.h in Headers */,
 				0FFD4D6118651FA300512F6E /* AsyncScrollingCoordinator.h in Headers */,
+				F43759B41FCF48FA00100706 /* AttachmentTypes.h in Headers */,
 				A8C4A80D09D563270003AC8D /* Attr.h in Headers */,
 				A8C4A80B09D563270003AC8D /* Attribute.h in Headers */,
 				E4A814DA1C70E10D00BF85AC /* AttributeChangeInvalidation.h in Headers */,

Modified: trunk/Source/WebCore/editing/Editor.cpp (225310 => 225311)


--- trunk/Source/WebCore/editing/Editor.cpp	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebCore/editing/Editor.cpp	2017-11-30 02:23:44 UTC (rev 225311)
@@ -3791,21 +3791,21 @@
     m_insertedAttachmentIdentifiers.clear();
 }
 
-void Editor::insertAttachment(const String& identifier, const String& filename, const String& filepath, std::optional<String> contentType)
+void Editor::insertAttachment(const String& identifier, const AttachmentDisplayOptions& options, const String& filename, const String& filepath, std::optional<String> contentType)
 {
     if (!contentType)
         contentType = File::contentTypeForFile(filename);
-    insertAttachmentFromFile(identifier, filename, *contentType, File::create(filepath));
+    insertAttachmentFromFile(identifier, options, filename, *contentType, File::create(filepath));
 }
 
-void Editor::insertAttachment(const String& identifier, const String& filename, Ref<SharedBuffer>&& data, std::optional<String> contentType)
+void Editor::insertAttachment(const String& identifier, const AttachmentDisplayOptions& options, const String& filename, Ref<SharedBuffer>&& data, std::optional<String> contentType)
 {
     if (!contentType)
         contentType = File::contentTypeForFile(filename);
-    insertAttachmentFromFile(identifier, filename, *contentType, File::create(Blob::create(data, *contentType), filename));
+    insertAttachmentFromFile(identifier, options, filename, *contentType, File::create(Blob::create(data, *contentType), filename));
 }
 
-void Editor::insertAttachmentFromFile(const String& identifier, const String& filename, const String& contentType, Ref<File>&& file)
+void Editor::insertAttachmentFromFile(const String& identifier, const AttachmentDisplayOptions& options, const String& filename, const String& contentType, Ref<File>&& file)
 {
     auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document());
     attachment->setAttribute(HTMLNames::titleAttr, filename);
@@ -3813,6 +3813,7 @@
     attachment->setAttribute(HTMLNames::typeAttr, contentType);
     attachment->setUniqueIdentifier(identifier);
     attachment->setFile(WTFMove(file));
+    attachment->updateDisplayMode(options.mode);
 
     auto fragmentToInsert = document().createDocumentFragment();
     fragmentToInsert->appendChild(attachment.get());

Modified: trunk/Source/WebCore/editing/Editor.h (225310 => 225311)


--- trunk/Source/WebCore/editing/Editor.h	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebCore/editing/Editor.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -67,7 +67,6 @@
 class EditorInternalCommand;
 class File;
 class Frame;
-class HTMLAttachmentElement;
 class HTMLElement;
 class HitTestResult;
 class KeyboardEvent;
@@ -96,6 +95,11 @@
     IgnoreBlockquote,
 };
 
+#if ENABLE(ATTACHMENT_ELEMENT)
+class HTMLAttachmentElement;
+struct AttachmentDisplayOptions;
+#endif
+
 enum TemporarySelectionOption : uint8_t {
     // By default, no additional options are enabled.
     TemporarySelectionOptionDefault = 0,
@@ -503,8 +507,8 @@
     bool isGettingDictionaryPopupInfo() const { return m_isGettingDictionaryPopupInfo; }
 
 #if ENABLE(ATTACHMENT_ELEMENT)
-    WEBCORE_EXPORT void insertAttachment(const String& identifier, const String& filename, const String& filepath, std::optional<String> contentType = std::nullopt);
-    WEBCORE_EXPORT void insertAttachment(const String& identifier, const String& filename, Ref<SharedBuffer>&& data, std::optional<String> contentType = std::nullopt);
+    WEBCORE_EXPORT void insertAttachment(const String& identifier, const AttachmentDisplayOptions&, const String& filename, const String& filepath, std::optional<String> contentType = std::nullopt);
+    WEBCORE_EXPORT void insertAttachment(const String& identifier, const AttachmentDisplayOptions&, const String& filename, Ref<SharedBuffer>&& data, std::optional<String> contentType = std::nullopt);
     void didInsertAttachmentElement(HTMLAttachmentElement&);
     void didRemoveAttachmentElement(HTMLAttachmentElement&);
 #endif
@@ -524,7 +528,7 @@
     Document& document() const;
 
 #if ENABLE(ATTACHMENT_ELEMENT)
-    void insertAttachmentFromFile(const String& identifier, const String& filename, const String& contentType, Ref<File>&&);
+    void insertAttachmentFromFile(const String& identifier, const AttachmentDisplayOptions&, const String& filename, const String& contentType, Ref<File>&&);
 #endif
 
     bool canDeleteRange(Range*) const;

Copied: trunk/Source/WebCore/html/AttachmentTypes.h (from rev 225310, trunk/Source/WebKit/UIProcess/API/APIAttachment.h) (0 => 225311)


--- trunk/Source/WebCore/html/AttachmentTypes.h	                        (rev 0)
+++ trunk/Source/WebCore/html/AttachmentTypes.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ATTACHMENT_ELEMENT)
+
+namespace WebCore {
+
+enum class AttachmentDisplayMode {
+    Auto,
+    InPlace,
+    AsIcon
+};
+
+struct AttachmentDisplayOptions {
+    AttachmentDisplayMode mode { AttachmentDisplayMode::Auto };
+
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static std::optional<AttachmentDisplayOptions> decode(Decoder&);
+};
+
+template<class Encoder> inline void AttachmentDisplayOptions::encode(Encoder& encoder) const
+{
+    encoder.encodeEnum(mode);
+}
+
+template<class Decoder> inline std::optional<AttachmentDisplayOptions> AttachmentDisplayOptions::decode(Decoder& decoder)
+{
+    AttachmentDisplayMode mode;
+    if (!decoder.decodeEnum(mode))
+        return std::nullopt;
+
+    return {{ mode }};
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ATTACHMENT_ELEMENT)

Modified: trunk/Source/WebCore/html/HTMLAttachmentElement.cpp (225310 => 225311)


--- trunk/Source/WebCore/html/HTMLAttachmentElement.cpp	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebCore/html/HTMLAttachmentElement.cpp	2017-11-30 02:23:44 UTC (rev 225311)
@@ -28,14 +28,20 @@
 
 #if ENABLE(ATTACHMENT_ELEMENT)
 
+#include "DOMURL.h"
+#include "Document.h"
 #include "Editor.h"
 #include "File.h"
 #include "FileReaderLoader.h"
 #include "FileReaderLoaderClient.h"
 #include "Frame.h"
+#include "HTMLImageElement.h"
 #include "HTMLNames.h"
+#include "HTMLVideoElement.h"
+#include "MIMETypeRegistry.h"
 #include "RenderAttachment.h"
 #include "RenderBlockFlow.h"
+#include "ShadowRoot.h"
 #include "SharedBuffer.h"
 
 namespace WebCore {
@@ -113,6 +119,12 @@
 
     if (auto* renderAttachment = attachmentRenderer())
         renderAttachment->invalidate();
+
+    if (auto image = innerImage())
+        image->setAttributeWithoutSynchronization(srcAttr, emptyString());
+    if (auto video = innerVideo())
+        video->setAttributeWithoutSynchronization(srcAttr, emptyString());
+    populateShadowRootIfNecessary();
 }
 
 RenderAttachment* HTMLAttachmentElement::attachmentRenderer() const
@@ -174,6 +186,82 @@
     return attributeWithoutSynchronization(webkitattachmentpathAttr);
 }
 
+void HTMLAttachmentElement::updateDisplayMode(AttachmentDisplayMode mode)
+{
+    mode = mode == AttachmentDisplayMode::Auto ? defaultDisplayMode() : mode;
+
+    switch (mode) {
+    case AttachmentDisplayMode::InPlace:
+        populateShadowRootIfNecessary();
+        setInlineStyleProperty(CSSPropertyWebkitAppearance, CSSValueNone, true);
+        setInlineStyleProperty(CSSPropertyDisplay, CSSValueInlineBlock, true);
+        break;
+    case AttachmentDisplayMode::AsIcon:
+        removeInlineStyleProperty(CSSPropertyWebkitAppearance);
+        removeInlineStyleProperty(CSSPropertyDisplay);
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+
+    invalidateStyleAndRenderersForSubtree();
+}
+
+Ref<HTMLImageElement> HTMLAttachmentElement::ensureInnerImage()
+{
+    if (auto image = innerImage())
+        return *image;
+
+    auto image = HTMLImageElement::create(document());
+    ensureUserAgentShadowRoot().appendChild(image);
+    return image;
+}
+
+Ref<HTMLVideoElement> HTMLAttachmentElement::ensureInnerVideo()
+{
+    if (auto video = innerVideo())
+        return *video;
+
+    auto video = HTMLVideoElement::create(document());
+    ensureUserAgentShadowRoot().appendChild(video);
+    return video;
+}
+
+RefPtr<HTMLImageElement> HTMLAttachmentElement::innerImage() const
+{
+    if (auto root = userAgentShadowRoot())
+        return childrenOfType<HTMLImageElement>(*root).first();
+    return nullptr;
+}
+
+RefPtr<HTMLVideoElement> HTMLAttachmentElement::innerVideo() const
+{
+    if (auto root = userAgentShadowRoot())
+        return childrenOfType<HTMLVideoElement>(*root).first();
+    return nullptr;
+}
+
+void HTMLAttachmentElement::populateShadowRootIfNecessary()
+{
+    auto mimeType = attachmentType();
+    if (!m_file || mimeType.isEmpty())
+        return;
+
+    if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType) || MIMETypeRegistry::isPDFMIMEType(mimeType)) {
+        auto image = ensureInnerImage();
+        if (image->attributeWithoutSynchronization(srcAttr).isEmpty())
+            image->setAttributeWithoutSynchronization(srcAttr, DOMURL::createObjectURL(document(), *m_file));
+
+    } else if (MIMETypeRegistry::isSupportedMediaMIMEType(mimeType)) {
+        auto video = ensureInnerVideo();
+        if (video->attributeWithoutSynchronization(srcAttr).isEmpty()) {
+            video->setAttributeWithoutSynchronization(srcAttr, DOMURL::createObjectURL(document(), *m_file));
+            video->setAttributeWithoutSynchronization(controlsAttr, emptyString());
+        }
+    }
+}
+
 void HTMLAttachmentElement::requestData(Function<void(RefPtr<SharedBuffer>&&)>&& callback)
 {
     if (m_file)

Modified: trunk/Source/WebCore/html/HTMLAttachmentElement.h (225310 => 225311)


--- trunk/Source/WebCore/html/HTMLAttachmentElement.h	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebCore/html/HTMLAttachmentElement.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -27,6 +27,7 @@
 
 #if ENABLE(ATTACHMENT_ELEMENT)
 
+#include "AttachmentTypes.h"
 #include "HTMLElement.h"
 
 namespace WebCore {
@@ -33,6 +34,8 @@
 
 class AttachmentDataReader;
 class File;
+class HTMLImageElement;
+class HTMLVideoElement;
 class RenderAttachment;
 class SharedBuffer;
 
@@ -47,6 +50,8 @@
     WEBCORE_EXPORT String uniqueIdentifier() const;
     void setUniqueIdentifier(const String&);
 
+    WEBCORE_EXPORT void updateDisplayMode(AttachmentDisplayMode);
+
     InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
     void removedFromAncestor(RemovalType, ContainerNode&) final;
 
@@ -64,7 +69,21 @@
     virtual ~HTMLAttachmentElement();
 
     RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+    Ref<HTMLImageElement> ensureInnerImage();
+    Ref<HTMLVideoElement> ensureInnerVideo();
+    RefPtr<HTMLImageElement> innerImage() const;
+    RefPtr<HTMLVideoElement> innerVideo() const;
 
+    void populateShadowRootIfNecessary();
+
+    AttachmentDisplayMode defaultDisplayMode() const
+    {
+        // FIXME: For now, all attachment elements automatically display using a file icon.
+        // In a followup patch, we'll change the default behavior to use in-place presentation
+        // for certain image MIME types.
+        return AttachmentDisplayMode::AsIcon;
+    }
+
     bool shouldSelectOnMouseDown() final {
 #if PLATFORM(IOS)
         return false;

Modified: trunk/Source/WebCore/platform/audio/ios/AudioSessionIOS.mm (225310 => 225311)


--- trunk/Source/WebCore/platform/audio/ios/AudioSessionIOS.mm	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebCore/platform/audio/ios/AudioSessionIOS.mm	2017-11-30 02:23:44 UTC (rev 225311)
@@ -141,7 +141,9 @@
 
     NSError *error = nil;
     [[AVAudioSession sharedInstance] setCategory:categoryString mode:categoryMode options:options error:&error];
+#if !PLATFORM(IOS_SIMULATOR)
     ASSERT(!error);
+#endif
 }
 
 AudioSession::CategoryType AudioSession::category() const

Modified: trunk/Source/WebKit/ChangeLog (225310 => 225311)


--- trunk/Source/WebKit/ChangeLog	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/ChangeLog	2017-11-30 02:23:44 UTC (rev 225311)
@@ -1,3 +1,49 @@
+2017-11-29  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Attachment Support] Implement SPI for clients to make an attachment element display in-place
+        https://bugs.webkit.org/show_bug.cgi?id=180153
+        <rdar://problem/35735252>
+
+        Reviewed by Tim Horton.
+
+        Add new WebKit SPI, -[_WKAttachment setDisplayOptions:completion:], and add plumbing for attachment display
+        options to the web content process. Changes covered by 4 new API tests.
+
+        * Scripts/webkit/messages.py:
+        (headers_for_type):
+        * UIProcess/API/APIAttachment.cpp:
+        (API::Attachment::setDisplayOptions):
+        * UIProcess/API/APIAttachment.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _insertAttachmentWithFilename:contentType:data:options:completion:]):
+
+        Respect given display options when inserting a new attachment.
+
+        * UIProcess/API/Cocoa/_WKAttachment.h:
+        * UIProcess/API/Cocoa/_WKAttachment.mm:
+        (-[_WKAttachmentDisplayOptions coreDisplayOptions]):
+
+        Introduce a helper to convert from the Cocoa _WKAttachmentDisplayOptions object to platform-agnostic
+        AttachmentDisplayOptions.
+
+        (-[_WKAttachment setDisplayOptions:completion:]):
+        (WebKit::if): Deleted.
+        * UIProcess/API/Cocoa/_WKAttachmentInternal.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::insertAttachment):
+        (WebKit::WebPageProxy::setAttachmentDisplayOptions):
+        * UIProcess/WebPageProxy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::insertAttachment):
+        (WebKit::WebPage::requestAttachmentData):
+        (WebKit::WebPage::setAttachmentDisplayOptions):
+        (WebKit::WebPage::attachmentElementWithIdentifier const):
+
+        Pull common logic to retrieve an attachment element matching a given identifier out into a helper.
+
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2017-11-29  Brent Fulgham  <bfulg...@apple.com>
 
         Part 2: Adopt updated NSKeyed[Un]Archiver API when available

Modified: trunk/Source/WebKit/Scripts/webkit/messages.py (225310 => 225311)


--- trunk/Source/WebKit/Scripts/webkit/messages.py	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/Scripts/webkit/messages.py	2017-11-30 02:23:44 UTC (rev 225311)
@@ -361,6 +361,7 @@
     special_cases = {
         'String': ['<wtf/text/WTFString.h>'],
         'PAL::SessionID': ['<pal/SessionID.h>'],
+        'WebCore::AttachmentDisplayOptions': ['<WebCore/AttachmentTypes.h>'],
         'WebCore::AutoplayEventFlags': ['<WebCore/AutoplayEvent.h>'],
         'WebCore::ExceptionDetails': ['<WebCore/JSDOMExceptionHandling.h>'],
         'WebCore::FileChooserSettings': ['<WebCore/FileChooser.h>'],

Modified: trunk/Source/WebKit/UIProcess/API/APIAttachment.cpp (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/API/APIAttachment.cpp	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/API/APIAttachment.cpp	2017-11-30 02:23:44 UTC (rev 225311)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "APIAttachment.h"
 
+#include <WebCore/AttachmentTypes.h>
 #include <WebCore/SharedBuffer.h>
 #include <wtf/BlockPtr.h>
 #include <wtf/text/WTFString.h>
@@ -55,4 +56,12 @@
         callback(nullptr, WebKit::CallbackBase::Error::OwnerWasInvalidated);
 }
 
+void Attachment::setDisplayOptions(WebCore::AttachmentDisplayOptions options, Function<void(WebKit::CallbackBase::Error)>&& callback)
+{
+    if (m_webPage)
+        m_webPage->setAttachmentDisplayOptions(m_identifier, options, WTFMove(callback));
+    else
+        callback(WebKit::CallbackBase::Error::OwnerWasInvalidated);
 }
+
+}

Modified: trunk/Source/WebKit/UIProcess/API/APIAttachment.h (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/API/APIAttachment.h	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/API/APIAttachment.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -34,6 +34,7 @@
 
 namespace WebCore {
 class SharedBuffer;
+struct AttachmentDisplayOptions;
 }
 
 namespace WebKit {
@@ -49,6 +50,7 @@
 
     const WTF::String& identifier() const { return m_identifier; }
     void requestData(Function<void(RefPtr<WebCore::SharedBuffer>, WebKit::CallbackBase::Error)>&&);
+    void setDisplayOptions(WebCore::AttachmentDisplayOptions, Function<void(WebKit::CallbackBase::Error)>&&);
 
 private:
     explicit Attachment(const WTF::String& identifier, WebKit::WebPageProxy&);

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2017-11-30 02:23:44 UTC (rev 225311)
@@ -90,6 +90,7 @@
 #import "_WKSessionStateInternal.h"
 #import "_WKVisitedLinkStoreInternal.h"
 #import "_WKWebsitePoliciesInternal.h"
+#import <WebCore/AttachmentTypes.h>
 #import <WebCore/GraphicsContextCG.h>
 #import <WebCore/IOSurface.h>
 #import <WebCore/JSDOMBinding.h>
@@ -4193,8 +4194,9 @@
 #if ENABLE(ATTACHMENT_ELEMENT)
     auto identifier = createCanonicalUUIDString();
 
+    auto coreOptions = options ? options.coreDisplayOptions : WebCore::AttachmentDisplayOptions { };
     auto buffer = WebCore::SharedBuffer::create(data);
-    _page->insertAttachment(identifier, filename, contentType.length ? std::optional<String> { contentType } : std::nullopt, buffer.get(), [capturedHandler = makeBlockPtr(completionHandler), capturedBuffer = buffer.copyRef()] (WebKit::CallbackBase::Error error) {
+    _page->insertAttachment(identifier, coreOptions, filename, contentType.length ? std::optional<String> { contentType } : std::nullopt, buffer.get(), [capturedHandler = makeBlockPtr(completionHandler), capturedBuffer = buffer.copyRef()] (WebKit::CallbackBase::Error error) {
         if (capturedHandler)
             capturedHandler(error == WebKit::CallbackBase::Error::None);
     });

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.h (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.h	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -38,12 +38,12 @@
 WK_CLASS_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA))
 @interface _WKAttachmentDisplayOptions : NSObject
 @property (nonatomic) _WKAttachmentDisplayMode mode;
-@property (nonatomic) BOOL expandsImageToMaximumWidth;
 @end
 
 WK_CLASS_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA))
 @interface _WKAttachment : NSObject
 - (void)requestData:(void(^)(NSData *, NSError *))completionHandler;
+- (void)setDisplayOptions:(_WKAttachmentDisplayOptions *)options completion:(void(^)(NSError *))completionHandler;
 @end
 
 #endif

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.mm (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.mm	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.mm	2017-11-30 02:23:44 UTC (rev 225311)
@@ -31,6 +31,7 @@
 #import "APIAttachment.h"
 #import "WKErrorPrivate.h"
 #import "_WKAttachmentInternal.h"
+#import <WebCore/AttachmentTypes.h>
 #import <WebCore/SharedBuffer.h>
 #import <wtf/BlockPtr.h>
 
@@ -40,13 +41,32 @@
 
 - (instancetype)init
 {
-    if (self = [super init]) {
+    if (self = [super init])
         _mode = _WKAttachmentDisplayModeAuto;
-        _expandsImageToMaximumWidth = NO;
-    }
+
     return self;
 }
 
+- (WebCore::AttachmentDisplayOptions)coreDisplayOptions
+{
+    WebCore::AttachmentDisplayMode mode;
+    switch (self.mode) {
+    case _WKAttachmentDisplayModeAuto:
+        mode = WebCore::AttachmentDisplayMode::Auto;
+        break;
+    case _WKAttachmentDisplayModeAsIcon:
+        mode = WebCore::AttachmentDisplayMode::AsIcon;
+        break;
+    case _WKAttachmentDisplayModeInPlace:
+        mode = WebCore::AttachmentDisplayMode::InPlace;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        mode = WebCore::AttachmentDisplayMode::Auto;
+    }
+    return { mode };
+}
+
 @end
 
 @implementation _WKAttachment
@@ -74,6 +94,20 @@
     });
 }
 
+- (void)setDisplayOptions:(_WKAttachmentDisplayOptions *)options completion:(void(^)(NSError *))completionHandler
+{
+    auto coreOptions = options ? options.coreDisplayOptions : WebCore::AttachmentDisplayOptions { };
+    _attachment->setDisplayOptions(coreOptions, [capturedBlock = makeBlockPtr(completionHandler)] (CallbackBase::Error error) {
+        if (!capturedBlock)
+            return;
+
+        if (error == CallbackBase::Error::None)
+            capturedBlock(nil);
+        else
+            capturedBlock([NSError errorWithDomain:WKErrorDomain code:1 userInfo:nil]);
+    });
+}
+
 - (NSString *)uniqueIdentifier
 {
     return _attachment->identifier();

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachmentInternal.h (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachmentInternal.h	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKAttachmentInternal.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -38,6 +38,10 @@
 
 }
 
+@interface _WKAttachmentDisplayOptions ()
+@property (nonatomic, readonly) WebCore::AttachmentDisplayOptions coreDisplayOptions;
+@end
+
 @interface _WKAttachment () <WKObject> {
 @package
     API::ObjectStorage<API::Attachment> _attachment;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2017-11-30 02:23:44 UTC (rev 225311)
@@ -28,6 +28,7 @@
 #include "WebPageProxy.h"
 
 #include "APIArray.h"
+#include "APIAttachment.h"
 #include "APIContextMenuClient.h"
 #include "APIFindClient.h"
 #include "APIFindMatchesClient.h"
@@ -113,6 +114,7 @@
 #include "WebURLSchemeHandler.h"
 #include "WebUserContentControllerProxy.h"
 #include "WebsiteDataStore.h"
+#include <WebCore/AttachmentTypes.h>
 #include <WebCore/BitmapImage.h>
 #include <WebCore/DiagnosticLoggingClient.h>
 #include <WebCore/DiagnosticLoggingKeys.h>
@@ -7147,7 +7149,7 @@
 
 #if ENABLE(ATTACHMENT_ELEMENT)
 
-void WebPageProxy::insertAttachment(const String& identifier, const String& filename, std::optional<String> contentType, SharedBuffer& data, Function<void(CallbackBase::Error)>&& callback)
+void WebPageProxy::insertAttachment(const String& identifier, const AttachmentDisplayOptions& options, const String& filename, std::optional<String> contentType, SharedBuffer& data, Function<void(CallbackBase::Error)>&& callback)
 {
     if (!isValid()) {
         callback(CallbackBase::Error::OwnerWasInvalidated);
@@ -7155,7 +7157,7 @@
     }
 
     auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
-    m_process->send(Messages::WebPage::InsertAttachment(identifier, filename, contentType, IPC::SharedBufferDataReference { &data }, callbackID), m_pageID);
+    m_process->send(Messages::WebPage::InsertAttachment(identifier, options, filename, contentType, IPC::SharedBufferDataReference { &data }, callbackID), m_pageID);
 }
 
 void WebPageProxy::requestAttachmentData(const String& identifier, Function<void(RefPtr<SharedBuffer>, CallbackBase::Error)>&& callback)
@@ -7169,6 +7171,17 @@
     m_process->send(Messages::WebPage::RequestAttachmentData(identifier, callbackID), m_pageID);
 }
 
+void WebPageProxy::setAttachmentDisplayOptions(const String& identifier, AttachmentDisplayOptions options, Function<void(CallbackBase::Error)>&& callback)
+{
+    if (!isValid()) {
+        callback(CallbackBase::Error::OwnerWasInvalidated);
+        return;
+    }
+
+    auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
+    m_process->send(Messages::WebPage::SetAttachmentDisplayOptions(identifier, options, callbackID), m_pageID);
+}
+
 void WebPageProxy::didInsertAttachment(const String& identifier)
 {
     m_pageClient.didInsertAttachment(identifier);

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (225310 => 225311)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -176,6 +176,12 @@
 using FloatBoxExtent = RectEdges<float>;
 }
 
+#if ENABLE(ATTACHMENT_ELEMENT)
+namespace WebCore {
+struct AttachmentDisplayOptions;
+}
+#endif
+
 #if PLATFORM(GTK)
 typedef GtkWidget* PlatformWidget;
 #endif
@@ -1216,8 +1222,9 @@
     void requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t webProcessContextId);
 
 #if ENABLE(ATTACHMENT_ELEMENT)
-    void insertAttachment(const String& identifier, const String& filename, std::optional<String> contentType, WebCore::SharedBuffer& data, Function<void(CallbackBase::Error)>&&);
+    void insertAttachment(const String& identifier, const WebCore::AttachmentDisplayOptions&, const String& filename, std::optional<String> contentType, WebCore::SharedBuffer& data, Function<void(CallbackBase::Error)>&&);
     void requestAttachmentData(const String& identifier, Function<void(RefPtr<WebCore::SharedBuffer>, CallbackBase::Error)>&&);
+    void setAttachmentDisplayOptions(const String& identifier, WebCore::AttachmentDisplayOptions, Function<void(CallbackBase::Error)>&&);
 #endif
 
 private:

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (225310 => 225311)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2017-11-30 02:23:44 UTC (rev 225311)
@@ -5767,23 +5767,16 @@
 
 #if ENABLE(ATTACHMENT_ELEMENT)
 
-void WebPage::insertAttachment(const String& identifier, const String& filename, std::optional<String> contentType, const IPC::DataReference& data, CallbackID callbackID)
+void WebPage::insertAttachment(const String& identifier, const AttachmentDisplayOptions& options, const String& filename, std::optional<String> contentType, const IPC::DataReference& data, CallbackID callbackID)
 {
     auto& frame = m_page->focusController().focusedOrMainFrame();
-    frame.editor().insertAttachment(identifier, filename, SharedBuffer::create(data.data(), data.size()), contentType);
+    frame.editor().insertAttachment(identifier, options, filename, SharedBuffer::create(data.data(), data.size()), contentType);
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
 
 void WebPage::requestAttachmentData(const String& identifier, CallbackID callbackID)
 {
-    // FIXME: We don't currently handle attachment data requests for attachment elements in subframes.
-    auto* frame = mainFrame();
-    if (!frame || !frame->document()) {
-        invokeSharedBufferCallback({ }, callbackID);
-        return;
-    }
-
-    auto attachment = frame->document()->attachmentForIdentifier(identifier);
+    auto attachment = attachmentElementWithIdentifier(identifier);
     if (!attachment) {
         invokeSharedBufferCallback({ }, callbackID);
         return;
@@ -5797,6 +5790,25 @@
     });
 }
 
+void WebPage::setAttachmentDisplayOptions(const String& identifier, const AttachmentDisplayOptions& options, CallbackID callbackID)
+{
+    if (auto attachment = attachmentElementWithIdentifier(identifier)) {
+        attachment->document().updateLayout();
+        attachment->updateDisplayMode(options.mode);
+    }
+    send(Messages::WebPageProxy::VoidCallback(callbackID));
+}
+
+RefPtr<HTMLAttachmentElement> WebPage::attachmentElementWithIdentifier(const String& identifier) const
+{
+    // FIXME: Handle attachment elements in subframes too as well.
+    auto* frame = mainFrame();
+    if (!frame || !frame->document())
+        return nullptr;
+
+    return frame->document()->attachmentForIdentifier(identifier);
+}
+
 #endif // ENABLE(ATTACHMENT_ELEMENT)
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (225310 => 225311)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2017-11-30 02:23:44 UTC (rev 225311)
@@ -152,6 +152,10 @@
 
 enum class TextIndicatorPresentationTransition : uint8_t;
 
+#if ENABLE(ATTACHMENT_ELEMENT)
+class HTMLAttachmentElement;
+struct AttachmentDisplayOptions;
+#endif
 }
 
 namespace WebKit {
@@ -1011,8 +1015,9 @@
     void storageAccessResponse(bool wasGranted, uint64_t contextId);
 
 #if ENABLE(ATTACHMENT_ELEMENT)
-    void insertAttachment(const String& identifier, const String& filename, std::optional<String> contentType, const IPC::DataReference&, CallbackID);
+    void insertAttachment(const String& identifier, const WebCore::AttachmentDisplayOptions&, const String& filename, std::optional<String> contentType, const IPC::DataReference&, CallbackID);
     void requestAttachmentData(const String& identifier, CallbackID);
+    void setAttachmentDisplayOptions(const String& identifier, const WebCore::AttachmentDisplayOptions&, CallbackID);
 #endif
 
 private:
@@ -1327,6 +1332,10 @@
     RetainPtr<CFDataRef> pdfSnapshotAtSize(const WebCore::IntRect&, const WebCore::IntSize& bitmapSize, SnapshotOptions);
 #endif
 
+#if ENABLE(ATTACHMENT_ELEMENT)
+    RefPtr<WebCore::HTMLAttachmentElement> attachmentElementWithIdentifier(const String& identifier) const;
+#endif
+
     uint64_t m_pageID;
 
     std::unique_ptr<WebCore::Page> m_page;

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (225310 => 225311)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2017-11-30 02:23:44 UTC (rev 225311)
@@ -486,7 +486,8 @@
     StorageAccessResponse(bool wasGranted, uint64_t contextId)
 
 #if ENABLE(ATTACHMENT_ELEMENT)
-    InsertAttachment(String identifier, String filename, std::optional<String> contentType, IPC::DataReference data, WebKit::CallbackID callbackID)
+    InsertAttachment(String identifier, struct WebCore::AttachmentDisplayOptions options, String filename, std::optional<String> contentType, IPC::DataReference data, WebKit::CallbackID callbackID)
     RequestAttachmentData(String identifier, WebKit::CallbackID callbackID)
+    SetAttachmentDisplayOptions(String identifier, struct WebCore::AttachmentDisplayOptions options, WebKit::CallbackID callbackID)
 #endif
 }

Modified: trunk/Tools/ChangeLog (225310 => 225311)


--- trunk/Tools/ChangeLog	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Tools/ChangeLog	2017-11-30 02:23:44 UTC (rev 225311)
@@ -1,3 +1,24 @@
+2017-11-29  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Attachment Support] Implement SPI for clients to make an attachment element display in-place
+        https://bugs.webkit.org/show_bug.cgi?id=180153
+        <rdar://problem/35735252>
+
+        Reviewed by Tim Horton.
+
+        Adds new API tests to cover inserting in-place attachments and updating the display mode of existing attachments,
+        as well as performing a few editing operations (paragraph insertion, cut/paste, list insertion) on attachment
+        elements.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
+        (platformAttachmentIconElementSize):
+        (testVideoData):
+        (testPDFData):
+        (displayOptionsWithMode):
+        (-[TestWKWebView waitForAttachmentElementSizeToBecome:]):
+        (-[_WKAttachment synchronouslySetDisplayOptions:error:]):
+        (TestWebKitAPI::TEST):
+
 2017-11-29  Simon Fraser  <simon.fra...@apple.com>
 
         API test fix after r225288.

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm (225310 => 225311)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2017-11-30 01:50:14 UTC (rev 225310)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2017-11-30 02:23:44 UTC (rev 225311)
@@ -27,6 +27,7 @@
 
 #import "PlatformUtilities.h"
 #import "TestWKWebView.h"
+#import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/WebKit.h>
 #import <WebKit/WebKitPrivate.h>
 #import <wtf/RetainPtr.h>
@@ -33,6 +34,15 @@
 
 #if WK_API_ENABLED
 
+CGSize platformAttachmentIconElementSize()
+{
+#if PLATFORM(IOS)
+    return CGSizeMake(160, 119);
+#else
+    return CGSizeMake(61, 89);
+#endif
+}
+
 @interface AttachmentUpdateObserver : NSObject <WKUIDelegatePrivate>
 @property (nonatomic, readonly) NSArray *inserted;
 @property (nonatomic, readonly) NSArray *removed;
@@ -139,6 +149,25 @@
     return [NSData dataWithContentsOfURL:url];
 }
 
+static NSData *testVideoData()
+{
+    NSURL *url = "" mainBundle] URLForResource:@"test" withExtension:@"mp4" subdirectory:@"TestWebKitAPI.resources"];
+    return [NSData dataWithContentsOfURL:url];
+}
+
+static NSData *testPDFData()
+{
+    NSURL *url = "" mainBundle] URLForResource:@"test" withExtension:@"pdf" subdirectory:@"TestWebKitAPI.resources"];
+    return [NSData dataWithContentsOfURL:url];
+}
+
+static _WKAttachmentDisplayOptions *displayOptionsWithMode(_WKAttachmentDisplayMode mode)
+{
+    _WKAttachmentDisplayOptions *options = [[[_WKAttachmentDisplayOptions alloc] init] autorelease];
+    options.mode = mode;
+    return options;
+}
+
 @implementation TestWKWebView (AttachmentTesting)
 
 - (BOOL)_synchronouslyExecuteEditCommand:(NSString *)command argument:(NSString *)argument
@@ -163,6 +192,22 @@
     return attachment.autorelease();
 }
 
+- (void)waitForAttachmentElementSizeToBecome:(CGSize)expectedSize
+{
+    while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]) {
+        __block bool doneEvaluatingScript = false;
+        __block BOOL sizeIsEqual = NO;
+        [self evaluateJavaScript:@"r = document.querySelector('attachment').getBoundingClientRect(); [r.width, r.height]" completionHandler:^(NSArray<NSNumber *> *sizeResult, NSError *) {
+            CGSize observedSize { sizeResult.firstObject.floatValue, sizeResult.lastObject.floatValue };
+            sizeIsEqual = CGSizeEqualToSize(expectedSize, observedSize);
+            doneEvaluatingScript = true;
+        }];
+        TestWebKitAPI::Util::run(&doneEvaluatingScript);
+        if (sizeIsEqual)
+            break;
+    }
+}
+
 - (NSString *)valueOfAttribute:(NSString *)attributeName forQuerySelector:(NSString *)querySelector
 {
     return [self stringByEvaluatingJavaScript:[NSString stringWithFormat:@"document.querySelector('%@').getAttribute('%@')", querySelector, attributeName]];
@@ -188,6 +233,21 @@
 
 @implementation _WKAttachment (AttachmentTesting)
 
+- (void)synchronouslySetDisplayOptions:(_WKAttachmentDisplayOptions *)options error:(NSError **)error
+{
+    __block RetainPtr<NSError> resultError;
+    __block bool done = false;
+    [self setDisplayOptions:options completion:^(NSError *error) {
+        resultError = retainPtr(error);
+        done = true;
+    }];
+
+    TestWebKitAPI::Util::run(&done);
+
+    if (error)
+        *error = resultError.autorelease();
+}
+
 - (NSData *)synchronouslyRequestData:(NSError **)error
 {
     __block RetainPtr<NSData> result;
@@ -432,6 +492,92 @@
     EXPECT_TRUE([dataForSecondRequest isEqualToData:htmlData.get()]);
 }
 
+TEST(WKAttachmentTests, InPlaceImageAttachmentToggleDisplayMode)
+{
+    auto webView = webViewForTestingAttachments();
+    RetainPtr<NSData> imageData = testImageData();
+    RetainPtr<_WKAttachment> attachment;
+    {
+        ObserveAttachmentUpdatesForScope observer(webView.get());
+        attachment = retainPtr([webView synchronouslyInsertAttachmentWithFilename:@"icon.png" contentType:@"image/png" data:imageData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]);
+        observer.expectAttachmentUpdates(@[], @[attachment.get()]);
+        [attachment expectRequestedDataToBe:imageData.get()];
+        [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)];
+    }
+
+    [attachment synchronouslySetDisplayOptions:displayOptionsWithMode(_WKAttachmentDisplayModeAsIcon) error:nil];
+    [attachment expectRequestedDataToBe:imageData.get()];
+    [webView waitForAttachmentElementSizeToBecome:platformAttachmentIconElementSize()];
+
+    [attachment synchronouslySetDisplayOptions:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace) error:nil];
+    [attachment expectRequestedDataToBe:imageData.get()];
+    [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)];
+}
+
+TEST(WKAttachmentTests, InPlaceImageAttachmentParagraphInsertion)
+{
+    auto webView = webViewForTestingAttachments();
+    RetainPtr<NSData> imageData = testImageData();
+    RetainPtr<_WKAttachment> attachment;
+    {
+        ObserveAttachmentUpdatesForScope observer(webView.get());
+        attachment = retainPtr([webView synchronouslyInsertAttachmentWithFilename:@"icon.png" contentType:@"image/png" data:imageData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]);
+        observer.expectAttachmentUpdates(@[], @[attachment.get()]);
+    }
+    [webView expectUpdatesAfterCommand:@"InsertParagraph" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]];
+    [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]];
+    [webView stringByEvaluatingJavaScript:@"getSelection().collapse(document.body)"];
+    [webView expectUpdatesAfterCommand:@"InsertParagraph" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]];
+    [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]];
+
+    [attachment expectRequestedDataToBe:imageData.get()];
+    [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)];
+
+    [webView expectUpdatesAfterCommand:@"DeleteForward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]];
+}
+
+TEST(WKAttachmentTests, InPlaceVideoAttachmentInsertionWithinList)
+{
+    auto webView = webViewForTestingAttachments();
+    RetainPtr<NSData> videoData = testVideoData();
+    RetainPtr<_WKAttachment> attachment;
+
+    [webView _synchronouslyExecuteEditCommand:@"InsertOrderedList" argument:nil];
+    {
+        ObserveAttachmentUpdatesForScope observer(webView.get());
+        attachment = retainPtr([webView synchronouslyInsertAttachmentWithFilename:@"test.mp4" contentType:@"video/mp4" data:videoData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]);
+        observer.expectAttachmentUpdates(@[], @[attachment.get()]);
+    }
+    [webView waitForAttachmentElementSizeToBecome:CGSizeMake(320, 240)];
+
+    [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]];
+    [webView expectUpdatesAfterCommand:@"Undo" withArgument:nil expectedRemovals:@[] expectedInsertions:@[attachment.get()]];
+    [webView expectUpdatesAfterCommand:@"InsertOrderedList" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]];
+
+    [webView waitForAttachmentElementSizeToBecome:CGSizeMake(320, 240)];
+    [attachment expectRequestedDataToBe:videoData.get()];
+}
+
+TEST(WKAttachmentTests, InPlacePDFAttachmentCutAndPaste)
+{
+    auto webView = webViewForTestingAttachments();
+    RetainPtr<NSData> pdfData = testPDFData();
+    RetainPtr<_WKAttachment> attachment;
+    {
+        ObserveAttachmentUpdatesForScope observer(webView.get());
+        attachment = retainPtr([webView synchronouslyInsertAttachmentWithFilename:@"test.pdf" contentType:@"application/pdf" data:pdfData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]);
+        observer.expectAttachmentUpdates(@[], @[attachment.get()]);
+        [webView waitForAttachmentElementSizeToBecome:CGSizeMake(130, 29)];
+    }
+
+    [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil];
+    [webView expectUpdatesAfterCommand:@"Cut" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]];
+
+    [webView expectUpdatesAfterCommand:@"Paste" withArgument:nil expectedRemovals:@[] expectedInsertions:@[attachment.get()]];
+    [webView waitForAttachmentElementSizeToBecome:CGSizeMake(130, 29)];
+    [attachment expectRequestedDataToBe:pdfData.get()];
+}
+
 } // namespace TestWebKitAPI
 
 #endif // WK_API_ENABLED
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to