Title: [220829] trunk
Revision
220829
Author
[email protected]
Date
2017-08-16 23:17:09 -0700 (Wed, 16 Aug 2017)

Log Message

Add the support for mutating clipboard data via DataTransferItemList
https://bugs.webkit.org/show_bug.cgi?id=175639

Reviewed by Wenson Hsieh.

Source/WebCore:

Added the support for adding plaintext data via dataTransfer.items.add, clearing data via clear,
and removing an entry via remove. When DataTransferItem is removed from DataTransferItemList,
we must put into the disabled mode.

To support the removal of DataTransferItem, this patch replaces a reference to DataTransfer by
a WeakPtr to DataTransferItemList, and stops forwarding ref from DataTransferItem to DataTransfer.
This means that DataTransfer can now be GC'ed before DataTransferItem is GC'ed.

Because the identify and the order of DataTransferItems need to be preserved, we can't simply
re-popluate m_itemList in DataTransferItemList. Instead, whenever the clipboard content is mutated,
we make the parallel modifications to m_itemList. This includes changes made via DataTransfer
methods such as setData and clearData.

Test: editing/pasteboard/datatransfer-items-copy-plaintext.html

* dom/DataTransfer.cpp:
(WebCore::DataTransfer::clearData): Invoke didClearStringData when m_itemList exists.
(WebCore::DataTransfer::setData): Ditto.
(WebCore::DataTransfer::createForInputEvent):
(WebCore::DataTransfer::createForDrag):
(WebCore::DataTransfer::createForDrop):
* dom/DataTransferItem.cpp:
(WebCore::DataTransferItem::create):
(WebCore::DataTransferItem::DataTransferItem):
(WebCore::DataTransferItem::clearListAndPutIntoDisabledMode): Added.
(WebCore::DataTransferItem::type const): Moved from the header.
(WebCore::DataTransferItem::getAsString const):
(WebCore::DataTransferItem::getAsFile const):
* dom/DataTransferItem.h:
(WebCore::DataTransferItem::ref): Deleted.
(WebCore::DataTransferItem::deref): Deleted.
(WebCore::DataTransferItem::isFile const): Added.
(WebCore::DataTransferItem::type const): Move to the cpp file.
* dom/DataTransferItemList.cpp:
(WebCore::isSupportedType): Moved.
(WebCore::DataTransferItemList::DataTransferItemList): Moved from the header.
(WebCore::DataTransferItemList::~DataTransferItemList): Added.
(WebCore::DataTransferItemList::item):
(WebCore::DataTransferItemList::add): Implemented the variant to add string data.
(WebCore::DataTransferItemList::remove): Implemented. For now, we don't have to deal with removing
a file since a writable dataTransfer never contains a File object.
(WebCore::DataTransferItemList::clear): Implemented.
(WebCore::DataTransferItemList::ensureItems const):
(WebCore::removeStringItemOfLowercasedType): Added.
(WebCore::DataTransferItemList::didClearStringData): Called when dataTransfer.clear is called.
(WebCore::DataTransferItemList::didSetStringData): Ditto for 
* dom/DataTransferItemList.h:
(WebCore::DataTransferItemList): Added a WeakPtrFactory. Also use a vector of Ref<DataTransferItem>
instead of unique_ptr<DataTransferItem> since DataTransferItem can outlive DataTransferItemList.
(WebCore::DataTransferItemList::dataTransfer): Added.
* dom/DataTransferItemList.idl:

LayoutTests:

Rebaselined the IDL test which now passes all test cases, and added a regression test for mutating clipboard data
via dataTransfer.items and methods on dataTransfer for plaintext.

* editing/pasteboard/datatransfer-idl-expected.txt:
* editing/pasteboard/datatransfer-items-copy-plaintext-expected.txt: Added.
* editing/pasteboard/datatransfer-items-copy-plaintext.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (220828 => 220829)


--- trunk/LayoutTests/ChangeLog	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/LayoutTests/ChangeLog	2017-08-17 06:17:09 UTC (rev 220829)
@@ -1,3 +1,17 @@
+2017-08-16  Ryosuke Niwa  <[email protected]>
+
+        Add the support for mutating clipboard data via DataTransferItemList
+        https://bugs.webkit.org/show_bug.cgi?id=175639
+
+        Reviewed by Wenson Hsieh.
+
+        Rebaselined the IDL test which now passes all test cases, and added a regression test for mutating clipboard data
+        via dataTransfer.items and methods on dataTransfer for plaintext.
+
+        * editing/pasteboard/datatransfer-idl-expected.txt:
+        * editing/pasteboard/datatransfer-items-copy-plaintext-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-copy-plaintext.html: Added.
+
 2017-08-16  Ryan Haddad  <[email protected]>
 
         Mark fullscreen/full-screen-iframe-legacy.html as flaky on Sierra WK1.

Modified: trunk/LayoutTests/editing/pasteboard/datatransfer-idl-expected.txt (220828 => 220829)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-idl-expected.txt	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-idl-expected.txt	2017-08-17 06:17:09 UTC (rev 220829)
@@ -20,8 +20,8 @@
 PASS DataTransferItemList interface: existence and properties of interface prototype object 
 PASS DataTransferItemList interface: existence and properties of interface prototype object's "constructor" property 
 PASS DataTransferItemList interface: attribute length 
-FAIL DataTransferItemList interface: operation add(DOMString,DOMString) assert_equals: property has wrong .length expected 1 but got 0
-FAIL DataTransferItemList interface: operation add(File) assert_equals: property has wrong .length expected 1 but got 0
+PASS DataTransferItemList interface: operation add(DOMString,DOMString) 
+PASS DataTransferItemList interface: operation add(File) 
 PASS DataTransferItemList interface: operation remove(unsigned long) 
 PASS DataTransferItemList interface: operation clear() 
 PASS DataTransferItem interface: existence and properties of interface object 

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-copy-plaintext-expected.txt (0 => 220829)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-copy-plaintext-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-copy-plaintext-expected.txt	2017-08-17 06:17:09 UTC (rev 220829)
@@ -0,0 +1,43 @@
+This tests copying plain text using dataTransfer.items. To manually test, click on "Copy text" and paste (Command+V on Mac Control+V elsewhere).
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS clipboardData.items.length is 0
+PASS clipboardData.setData("text/plain", "rock"); clipboardData.items.length is 1
+PASS initialItem = clipboardData.items[0]; initialItem.kind is "string"
+PASS initialItem.type is "text/plain"
+PASS initialItem.getAsFile() is null
+PASS initialItem.getAsString(checkContent(1, "rock")) is undefined
+PASS clipboardData.items.add("paper", "text/plain") threw exception NotSupportedError: The operation is not supported..
+PASS clipboardData.items[0] is initialItem
+PASS clipboardData.clearData(); clipboardData.items.length is 0
+PASS clipboardData.items.add("scissors", "text/plain"); clipboardData.items.length is 1
+PASS clipboardData.items[0] is not initialItem
+PASS initialItem.kind is "string"
+PASS initialItem.type is ""
+PASS initialItem.getAsFile() is null
+PASS initialItem.getAsString(() => testFailed("getAsString should exit immeidately if item is disabled")) is undefined
+PASS clipboardData.getData("text/plain") is "scissors"
+PASS clipboardData.items[0].kind is "string"
+PASS clipboardData.items[0].type is "text/plain"
+PASS clipboardData.items[0].getAsFile() is null
+PASS clipboardData.items[0].getAsString(checkContent(2, "scissors")) is undefined
+PASS clipboardData.items.clear(); clipboardData.items.length is 0
+PASS clipboardData.getData("text/plain") is ""
+PASS clipboardData.items.add("WebKit", "text/plain"); clipboardData.items.length is 1
+PASS clipboardData.items[0].kind is "string"
+PASS clipboardData.items[0].type is "text/plain"
+PASS clipboardData.items[0].getAsFile() is null
+PASS clipboardData.items[0].getAsString(checkContent(3, "WebKit")) is undefined
+PASS clipboardData.items.remove(1) threw exception IndexSizeError: The index is not in the allowed range..
+PASS clipboardData.items.length is 1
+PASS clipboardData.items.remove(0); clipboardData.items.length is 0
+PASS clipboardData.getData("text/plain") is ""
+PASS actualContent1 is "rock"
+PASS actualContent2 is "scissors"
+PASS actualContent3 is "WebKit"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-copy-plaintext.html (0 => 220829)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-copy-plaintext.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-copy-plaintext.html	2017-08-17 06:17:09 UTC (rev 220829)
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+
+description('This tests copying plain text using dataTransfer.items. To manually test, click on "Copy text" and paste (Command+V on Mac Control+V elsewhere).');
+
+function copyText()
+{
+    document.getElementById('source').focus();
+    document.execCommand('SelectAll', false, null);
+    document.execCommand('Copy', false, null);
+}
+
+function copy(event)
+{
+    clipboardData = event.clipboardData;
+    shouldBe('clipboardData.items.length', '0');
+    shouldBe('clipboardData.setData("text/plain", "rock"); clipboardData.items.length', '1');
+    shouldBeEqualToString('initialItem = clipboardData.items[0]; initialItem.kind', 'string');
+    shouldBeEqualToString('initialItem.type', 'text/plain');
+    shouldBe('initialItem.getAsFile()', 'null');
+    shouldBe('initialItem.getAsString(checkContent(1, "rock"))', 'undefined');
+
+    shouldThrowErrorName('clipboardData.items.add("paper", "text/plain")', 'NotSupportedError');
+    shouldBe('clipboardData.items[0]', 'initialItem');
+    shouldBe('clipboardData.clearData(); clipboardData.items.length', '0');
+
+    shouldBe('clipboardData.items.add("scissors", "text/plain"); clipboardData.items.length', '1');
+    shouldNotBe('clipboardData.items[0]', 'initialItem');
+    shouldBeEqualToString('initialItem.kind', 'string');
+    shouldBeEqualToString('initialItem.type', '');
+    shouldBe('initialItem.getAsFile()', 'null');
+    shouldBe('initialItem.getAsString(() => testFailed("getAsString should exit immeidately if item is disabled"))', 'undefined');
+
+    shouldBeEqualToString('clipboardData.getData("text/plain")', 'scissors');
+    shouldBeEqualToString('clipboardData.items[0].kind', 'string');
+    shouldBeEqualToString('clipboardData.items[0].type', 'text/plain');
+    shouldBe('clipboardData.items[0].getAsFile()', 'null');
+    shouldBe('clipboardData.items[0].getAsString(checkContent(2, "scissors"))', 'undefined');
+
+    shouldBe('clipboardData.items.clear(); clipboardData.items.length', '0');
+    shouldBeEqualToString('clipboardData.getData("text/plain")', '');
+
+    shouldBe('clipboardData.items.add("WebKit", "text/plain"); clipboardData.items.length', '1');
+    shouldBeEqualToString('clipboardData.items[0].kind', 'string');
+    shouldBeEqualToString('clipboardData.items[0].type', 'text/plain');
+    shouldBe('clipboardData.items[0].getAsFile()', 'null');
+    shouldBe('clipboardData.items[0].getAsString(checkContent(3, "WebKit"))', 'undefined');
+
+    shouldThrowErrorName('clipboardData.items.remove(1)', 'IndexSizeError');
+    shouldBe('clipboardData.items.length', '1');
+    shouldBe('clipboardData.items.remove(0); clipboardData.items.length', '0');
+    shouldBeEqualToString('clipboardData.getData("text/plain")', '');
+}
+
+let count = 0;
+function checkContent(number, expectedContent)
+{
+    count++;
+    return (content) => {
+        const variableName = 'actualContent' + number;
+        window[variableName] = content;
+        shouldBeEqualToString(variableName, expectedContent);
+        count--;
+        if (!count) {
+            document.getElementById('container').style.display = 'none';
+            finishJSTest();
+        }
+    }
+}
+
+if (window.testRunner)
+    window._onload_ = copyText;
+jsTestIsAsync = true;
+successfullyParsed = true;
+
+</script>
+<div id="container">
+    <button _onclick_="copyText();">Copy text</button>
+    <div id="source" _oncopy_="copy(event)" contenteditable="true">hello, world</div>
+</div>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (220828 => 220829)


--- trunk/Source/WebCore/ChangeLog	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/Source/WebCore/ChangeLog	2017-08-17 06:17:09 UTC (rev 220829)
@@ -1,3 +1,62 @@
+2017-08-16  Ryosuke Niwa  <[email protected]>
+
+        Add the support for mutating clipboard data via DataTransferItemList
+        https://bugs.webkit.org/show_bug.cgi?id=175639
+
+        Reviewed by Wenson Hsieh.
+
+        Added the support for adding plaintext data via dataTransfer.items.add, clearing data via clear,
+        and removing an entry via remove. When DataTransferItem is removed from DataTransferItemList,
+        we must put into the disabled mode.
+
+        To support the removal of DataTransferItem, this patch replaces a reference to DataTransfer by
+        a WeakPtr to DataTransferItemList, and stops forwarding ref from DataTransferItem to DataTransfer.
+        This means that DataTransfer can now be GC'ed before DataTransferItem is GC'ed.
+
+        Because the identify and the order of DataTransferItems need to be preserved, we can't simply
+        re-popluate m_itemList in DataTransferItemList. Instead, whenever the clipboard content is mutated,
+        we make the parallel modifications to m_itemList. This includes changes made via DataTransfer
+        methods such as setData and clearData.
+
+        Test: editing/pasteboard/datatransfer-items-copy-plaintext.html
+
+        * dom/DataTransfer.cpp:
+        (WebCore::DataTransfer::clearData): Invoke didClearStringData when m_itemList exists.
+        (WebCore::DataTransfer::setData): Ditto.
+        (WebCore::DataTransfer::createForInputEvent):
+        (WebCore::DataTransfer::createForDrag):
+        (WebCore::DataTransfer::createForDrop):
+        * dom/DataTransferItem.cpp:
+        (WebCore::DataTransferItem::create):
+        (WebCore::DataTransferItem::DataTransferItem):
+        (WebCore::DataTransferItem::clearListAndPutIntoDisabledMode): Added.
+        (WebCore::DataTransferItem::type const): Moved from the header.
+        (WebCore::DataTransferItem::getAsString const):
+        (WebCore::DataTransferItem::getAsFile const):
+        * dom/DataTransferItem.h:
+        (WebCore::DataTransferItem::ref): Deleted.
+        (WebCore::DataTransferItem::deref): Deleted.
+        (WebCore::DataTransferItem::isFile const): Added.
+        (WebCore::DataTransferItem::type const): Move to the cpp file.
+        * dom/DataTransferItemList.cpp:
+        (WebCore::isSupportedType): Moved.
+        (WebCore::DataTransferItemList::DataTransferItemList): Moved from the header.
+        (WebCore::DataTransferItemList::~DataTransferItemList): Added.
+        (WebCore::DataTransferItemList::item):
+        (WebCore::DataTransferItemList::add): Implemented the variant to add string data.
+        (WebCore::DataTransferItemList::remove): Implemented. For now, we don't have to deal with removing
+        a file since a writable dataTransfer never contains a File object.
+        (WebCore::DataTransferItemList::clear): Implemented.
+        (WebCore::DataTransferItemList::ensureItems const):
+        (WebCore::removeStringItemOfLowercasedType): Added.
+        (WebCore::DataTransferItemList::didClearStringData): Called when dataTransfer.clear is called.
+        (WebCore::DataTransferItemList::didSetStringData): Ditto for 
+        * dom/DataTransferItemList.h:
+        (WebCore::DataTransferItemList): Added a WeakPtrFactory. Also use a vector of Ref<DataTransferItem>
+        instead of unique_ptr<DataTransferItem> since DataTransferItem can outlive DataTransferItemList.
+        (WebCore::DataTransferItemList::dataTransfer): Added.
+        * dom/DataTransferItemList.idl:
+
 2017-08-16  Andy Estes  <[email protected]>
 
         [Apple Pay] Rename PaymentRequest to ApplePaySessionPaymentRequest

Modified: trunk/Source/WebCore/dom/DataTransfer.cpp (220828 => 220829)


--- trunk/Source/WebCore/dom/DataTransfer.cpp	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/Source/WebCore/dom/DataTransfer.cpp	2017-08-17 06:17:09 UTC (rev 220829)
@@ -118,6 +118,8 @@
         m_pasteboard->clear();
     else
         m_pasteboard->clear(type);
+    if (m_itemList)
+        m_itemList->didClearStringData(type);
 }
 
 String DataTransfer::getData(const String& type) const
@@ -144,6 +146,8 @@
 #endif
 
     m_pasteboard->writeString(type, data);
+    if (m_itemList)
+        m_itemList->didSetStringData(type);
 }
 
 DataTransferItemList& DataTransfer::items()

Modified: trunk/Source/WebCore/dom/DataTransferItem.cpp (220828 => 220829)


--- trunk/Source/WebCore/dom/DataTransferItem.cpp	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/Source/WebCore/dom/DataTransferItem.cpp	2017-08-17 06:17:09 UTC (rev 220829)
@@ -32,6 +32,7 @@
 #include "config.h"
 #include "DataTransferItem.h"
 
+#include "DataTransferItemList.h"
 #include "File.h"
 #include "ScriptExecutionContext.h"
 #include "StringCallback.h"
@@ -38,14 +39,24 @@
 
 namespace WebCore {
 
-DataTransferItem::DataTransferItem(DataTransfer& dataTransfer, const String& type)
-    : m_dataTransfer(dataTransfer)
+Ref<DataTransferItem> DataTransferItem::create(WeakPtr<DataTransferItemList>&& list, const String& type)
+{
+    return adoptRef(*new DataTransferItem(WTFMove(list), type));
+}
+
+Ref<DataTransferItem> DataTransferItem::create(WeakPtr<DataTransferItemList>&& list, const String& type, Ref<File>&& file)
+{
+    return adoptRef(*new DataTransferItem(WTFMove(list), type, WTFMove(file)));
+}
+
+DataTransferItem::DataTransferItem(WeakPtr<DataTransferItemList>&& list, const String& type)
+    : m_list(WTFMove(list))
     , m_type(type)
 {
 }
 
-DataTransferItem::DataTransferItem(DataTransfer& dataTransfer, const String& type, Ref<File>&& file)
-    : m_dataTransfer(dataTransfer)
+DataTransferItem::DataTransferItem(WeakPtr<DataTransferItemList>&& list, const String& type, Ref<File>&& file)
+    : m_list(WTFMove(list))
     , m_type(type)
     , m_file(WTFMove(file))
 {
@@ -55,23 +66,37 @@
 {
 }
 
+void DataTransferItem::clearListAndPutIntoDisabledMode()
+{
+    m_list.clear();
+}
+
 String DataTransferItem::kind() const
 {
     return m_file ? ASCIILiteral("file") : ASCIILiteral("string");
 }
 
+String DataTransferItem::type() const
+{
+    return isInDisabledMode() ? String() : m_type;
+}
+
 void DataTransferItem::getAsString(ScriptExecutionContext& context, RefPtr<StringCallback>&& callback) const
 {
-    if (!callback || !m_dataTransfer.canReadData() || m_file)
+    if (!callback || !m_list || m_file)
         return;
 
+    auto& dataTransfer = m_list->dataTransfer();
+    if (!dataTransfer.canReadData())
+        return;
+
     // FIXME: Make this async.
-    callback->scheduleCallback(context, m_dataTransfer.getData(m_type));
+    callback->scheduleCallback(context, dataTransfer.getData(m_type));
 }
 
 RefPtr<File> DataTransferItem::getAsFile() const
 {
-    if (!m_dataTransfer.canReadData())
+    if (!m_list || !m_list->dataTransfer().canReadData())
         return nullptr;
     return m_file.copyRef();
 }

Modified: trunk/Source/WebCore/dom/DataTransferItem.h (220828 => 220829)


--- trunk/Source/WebCore/dom/DataTransferItem.h	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/Source/WebCore/dom/DataTransferItem.h	2017-08-17 06:17:09 UTC (rev 220829)
@@ -35,32 +35,38 @@
 #include "ScriptWrappable.h"
 #include <wtf/Forward.h>
 #include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/AtomicString.h>
 
 namespace WebCore {
 
+class DataTransferListItem;
 class File;
 class ScriptExecutionContext;
 class StringCallback;
 
-class DataTransferItem : public ScriptWrappable {
-    WTF_MAKE_NONCOPYABLE(DataTransferItem); WTF_MAKE_FAST_ALLOCATED;
+class DataTransferItem : public RefCounted<DataTransferItem> {
 public:
-    DataTransferItem(DataTransfer&, const String&);
-    DataTransferItem(DataTransfer&, const String&, Ref<File>&&);
+    static Ref<DataTransferItem> create(WeakPtr<DataTransferItemList>&&, const String&);
+    static Ref<DataTransferItem> create(WeakPtr<DataTransferItemList>&&, const String&, Ref<File>&&);
+
     ~DataTransferItem();
 
-    // DataTransfer owns DataTransferItem, and DataTransfer is kept alive as long as DataTransferItem is alive.
-    void ref() { m_dataTransfer.ref(); }
-    void deref() { m_dataTransfer.deref(); }
+    void clearListAndPutIntoDisabledMode();
 
+    bool isFile() const { return m_file; }
     String kind() const;
-    const String& type() const { return m_type; }
+    String type() const;
     void getAsString(ScriptExecutionContext&, RefPtr<StringCallback>&&) const;
     RefPtr<File> getAsFile() const;
 
 private:
-    DataTransfer& m_dataTransfer;
+    DataTransferItem(WeakPtr<DataTransferItemList>&&, const String&);
+    DataTransferItem(WeakPtr<DataTransferItemList>&&, const String&, Ref<File>&&);
+
+    bool isInDisabledMode() const { return !m_list; }
+
+    WeakPtr<DataTransferItemList> m_list;
     const String m_type;
     RefPtr<File> m_file;
 };

Modified: trunk/Source/WebCore/dom/DataTransferItemList.cpp (220828 => 220829)


--- trunk/Source/WebCore/dom/DataTransferItemList.cpp	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/Source/WebCore/dom/DataTransferItemList.cpp	2017-08-17 06:17:09 UTC (rev 220829)
@@ -28,9 +28,26 @@
 
 #include "DataTransferItem.h"
 #include "FileList.h"
+#include "Pasteboard.h"
 
 namespace WebCore {
 
+// FIXME: DataTransfer should filter types itself.
+static bool isSupportedType(const String& type)
+{
+    return type == "text/plain";
+}
+
+DataTransferItemList::DataTransferItemList(DataTransfer& dataTransfer)
+    : m_weakPtrFactory(this)
+    , m_dataTransfer(dataTransfer)
+{
+}
+
+DataTransferItemList::~DataTransferItemList()
+{
+}
+
 unsigned DataTransferItemList::length() const
 {
     return ensureItems().size();
@@ -41,56 +58,131 @@
     auto& items = ensureItems();
     if (items.size() <= index)
         return nullptr;
-    return items[index].get();
+    return items[index].copyRef();
 }
 
-ExceptionOr<void> DataTransferItemList::add(const String&, const String&)
+ExceptionOr<RefPtr<DataTransferItem>> DataTransferItemList::add(const String& data, const String& type)
 {
-    return { };
+    if (!m_dataTransfer.canWriteData())
+        return nullptr;
+
+    for (auto& item : ensureItems()) {
+        if (!item->isFile() && equalIgnoringASCIICase(item->type(), type))
+            return Exception { NotSupportedError };
+    }
+
+    String lowercasedType = type.convertToASCIILowercase();
+
+    // FIXME: Allow writing & reading of any types to clipboard / drag data store.
+    if (!isSupportedType(lowercasedType))
+        return nullptr;
+
+    m_dataTransfer.pasteboard().writeString(lowercasedType, data);
+    ASSERT(m_items);
+    m_items->append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(), type));
+    return RefPtr<DataTransferItem> { m_items->last().copyRef() };
 }
 
-void DataTransferItemList::add(RefPtr<File>&&)
+RefPtr<DataTransferItem> DataTransferItemList::add(Ref<File>&&)
 {
+    return nullptr;
 }
 
-void DataTransferItemList::remove(unsigned)
+ExceptionOr<void> DataTransferItemList::remove(unsigned index)
 {
+    if (!m_dataTransfer.canWriteData())
+        return Exception { InvalidStateError };
+
+    auto& items = ensureItems();
+    if (items.size() <= index)
+        return Exception { IndexSizeError }; // Matches Gecko. See https://github.com/whatwg/html/issues/2925
+
+    // FIXME: Handle the removal of files once we added the support for writing a File.
+    ASSERT(!items[index]->isFile());
+
+    auto& removedItem = items[index].get();
+    m_dataTransfer.pasteboard().clear(removedItem.type());
+    removedItem.clearListAndPutIntoDisabledMode();
+    items.remove(index);
+
+    return { };
 }
 
 void DataTransferItemList::clear()
 {
+    m_dataTransfer.pasteboard().clear();
+    if (m_items) {
+        for (auto& item : *m_items)
+            item->clearListAndPutIntoDisabledMode();
+        m_items->clear();
+    }
 }
 
-// FIXME: DataTransfer should filter types itself.
-static bool isSupportedType(const String& type)
+Vector<Ref<DataTransferItem>>& DataTransferItemList::ensureItems() const
 {
-    return equalIgnoringASCIICase(type, "text/plain");
-}
-
-Vector<std::unique_ptr<DataTransferItem>>& DataTransferItemList::ensureItems() const
-{
     if (m_items)
         return *m_items;
 
-    Vector<std::unique_ptr<DataTransferItem>> items;
+    Vector<Ref<DataTransferItem>> items;
     for (String& type : m_dataTransfer.types()) {
-        if (isSupportedType(type))
-            items.append(std::make_unique<DataTransferItem>(m_dataTransfer, type));
+        String lowercasedType = type.convertToASCIILowercase();
+        if (isSupportedType(lowercasedType))
+            items.append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(), lowercasedType));
     }
 
     FileList& files = m_dataTransfer.files();
     for (unsigned i = 0, length = files.length(); i < length; ++i) {
         File& file = *files.item(i);
-        String type = File::contentTypeForFile(file.path());
+        String type = File::contentTypeForFile(file.path()).convertToASCIILowercase();
         if (isSupportedType(type))
-            items.append(std::make_unique<DataTransferItem>(m_dataTransfer, type, file));
+            items.append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(), type, file));
     }
 
-
     m_items = WTFMove(items);
 
     return *m_items;
 }
 
+static void removeStringItemOfLowercasedType(Vector<Ref<DataTransferItem>>& items, const String& lowercasedType)
+{
+    auto index = items.findMatching([lowercasedType](auto& item) {
+        return !item->isFile() && item->type() == lowercasedType;
+    });
+    if (index == notFound)
+        return;
+    items[index]->clearListAndPutIntoDisabledMode();
+    items.remove(index);
 }
 
+void DataTransferItemList::didClearStringData(const String& type)
+{
+    if (!m_items)
+        return;
+
+    auto& items = *m_items;
+    if (!type.isNull())
+        return removeStringItemOfLowercasedType(items, type.convertToASCIILowercase());
+
+    for (auto& item : items) {
+        if (!item->isFile())
+            item->clearListAndPutIntoDisabledMode();
+    }
+    items.removeAllMatching([](auto& item) {
+        return !item->isFile();
+    });
+}
+
+// https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-setdata
+void DataTransferItemList::didSetStringData(const String& type)
+{
+    if (!m_items)
+        return;
+
+    String lowercasedType = type.convertToASCIILowercase();
+    removeStringItemOfLowercasedType(*m_items, type.convertToASCIILowercase());
+
+    m_items->append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(), lowercasedType));
+}
+
+}
+

Modified: trunk/Source/WebCore/dom/DataTransferItemList.h (220828 => 220829)


--- trunk/Source/WebCore/dom/DataTransferItemList.h	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/Source/WebCore/dom/DataTransferItemList.h	2017-08-17 06:17:09 UTC (rev 220829)
@@ -32,40 +32,46 @@
 #pragma once
 
 #include "DataTransfer.h"
-#include "DataTransferItem.h"
 #include "ExceptionOr.h"
 #include "ScriptWrappable.h"
 #include <wtf/Forward.h>
+#include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
+class DataTransferItem;
 class File;
 
 class DataTransferItemList : public ScriptWrappable {
     WTF_MAKE_NONCOPYABLE(DataTransferItemList); WTF_MAKE_FAST_ALLOCATED;
 public:
-    DataTransferItemList(DataTransfer& dataTransfer)
-        : m_dataTransfer(dataTransfer)
-    {
-    }
+    DataTransferItemList(DataTransfer&);
+    ~DataTransferItemList();
 
     // DataTransfer owns DataTransferItemList, and DataTransfer is kept alive as long as DataTransferItemList is alive.
     void ref() { m_dataTransfer.ref(); }
     void deref() { m_dataTransfer.deref(); }
+    DataTransfer& dataTransfer() { return m_dataTransfer; }
 
+    // DOM API
     unsigned length() const;
     RefPtr<DataTransferItem> item(unsigned index);
-    ExceptionOr<void> add(const String& data, const String& type);
-    void add(RefPtr<File>&&);
-    void remove(unsigned index);
+    ExceptionOr<RefPtr<DataTransferItem>> add(const String& data, const String& type);
+    RefPtr<DataTransferItem> add(Ref<File>&&);
+    ExceptionOr<void> remove(unsigned index);
     void clear();
 
+    void didClearStringData(const String& type);
+    void didSetStringData(const String& type);
+
 private:
-    Vector<std::unique_ptr<DataTransferItem>>& ensureItems() const;
+    Vector<Ref<DataTransferItem>>& ensureItems() const;
 
+    WeakPtrFactory<DataTransferItemList> m_weakPtrFactory;
     DataTransfer& m_dataTransfer;
-    mutable std::optional<Vector<std::unique_ptr<DataTransferItem>>> m_items;
+    mutable std::optional<Vector<Ref<DataTransferItem>>> m_items;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/DataTransferItemList.idl (220828 => 220829)


--- trunk/Source/WebCore/dom/DataTransferItemList.idl	2017-08-17 06:11:21 UTC (rev 220828)
+++ trunk/Source/WebCore/dom/DataTransferItemList.idl	2017-08-17 06:17:09 UTC (rev 220829)
@@ -38,10 +38,10 @@
     readonly attribute long length;
     getter DataTransferItem item(unsigned long index);
 
-    [MayThrowException] void add(optional DOMString data = "" optional DOMString type = "undefined");
-    void add(File? file);
+    [MayThrowException] DataTransferItem? add(DOMString data, DOMString type);
+    DataTransferItem? add(File file);
 
-    void remove(unsigned long index);
+    [MayThrowException] void remove(unsigned long index);
 
     void clear();
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to