Turning off custom pasteboard data doesn't actually turn it off in WK2
[WebKit-https.git] / Source / WebCore / dom / DataTransferItemList.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "DataTransferItemList.h"
28
29 #include "DataTransferItem.h"
30 #include "FileList.h"
31 #include "Pasteboard.h"
32 #include "RuntimeEnabledFeatures.h"
33 #include "Settings.h"
34
35 namespace WebCore {
36
37 DataTransferItemList::DataTransferItemList(DataTransfer& dataTransfer)
38     : m_dataTransfer(dataTransfer)
39 {
40 }
41
42 DataTransferItemList::~DataTransferItemList() = default;
43
44 unsigned DataTransferItemList::length() const
45 {
46     return ensureItems().size();
47 }
48
49 RefPtr<DataTransferItem> DataTransferItemList::item(unsigned index)
50 {
51     auto& items = ensureItems();
52     if (items.size() <= index)
53         return nullptr;
54     return items[index].copyRef();
55 }
56
57 static bool shouldExposeTypeInItemList(const String& type)
58 {
59     return RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled() || Pasteboard::isSafeTypeForDOMToReadAndWrite(type);
60 }
61
62 ExceptionOr<RefPtr<DataTransferItem>> DataTransferItemList::add(const String& data, const String& type)
63 {
64     if (!m_dataTransfer.canWriteData())
65         return nullptr;
66
67     for (auto& item : ensureItems()) {
68         if (!item->isFile() && equalIgnoringASCIICase(item->type(), type))
69             return Exception { NotSupportedError };
70     }
71
72     String lowercasedType = type.convertToASCIILowercase();
73
74     if (!shouldExposeTypeInItemList(lowercasedType))
75         return nullptr;
76
77     m_dataTransfer.setDataFromItemList(lowercasedType, data);
78     ASSERT(m_items);
79     m_items->append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(*this), lowercasedType));
80     return m_items->last().ptr();
81 }
82
83 RefPtr<DataTransferItem> DataTransferItemList::add(Ref<File>&& file)
84 {
85     if (!m_dataTransfer.canWriteData())
86         return nullptr;
87
88     ensureItems().append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(*this), file->type(), file.copyRef()));
89     m_dataTransfer.didAddFileToItemList();
90     return m_items->last().ptr();
91 }
92
93 ExceptionOr<void> DataTransferItemList::remove(unsigned index)
94 {
95     if (!m_dataTransfer.canWriteData())
96         return Exception { InvalidStateError };
97
98     auto& items = ensureItems();
99     if (items.size() <= index)
100         return Exception { IndexSizeError }; // Matches Gecko. See https://github.com/whatwg/html/issues/2925
101
102     // FIXME: Remove the file from the pasteboard object once we add support for it.
103     Ref<DataTransferItem> removedItem = items[index].copyRef();
104     if (!removedItem->isFile())
105         m_dataTransfer.pasteboard().clear(removedItem->type());
106     removedItem->clearListAndPutIntoDisabledMode();
107     items.remove(index);
108     if (removedItem->isFile())
109         m_dataTransfer.updateFileList();
110
111     return { };
112 }
113
114 void DataTransferItemList::clear()
115 {
116     m_dataTransfer.pasteboard().clear();
117     bool removedItemContainingFile = false;
118     if (m_items) {
119         for (auto& item : *m_items) {
120             removedItemContainingFile |= item->isFile();
121             item->clearListAndPutIntoDisabledMode();
122         }
123         m_items->clear();
124     }
125
126     if (removedItemContainingFile)
127         m_dataTransfer.updateFileList();
128 }
129
130 Vector<Ref<DataTransferItem>>& DataTransferItemList::ensureItems() const
131 {
132     if (m_items)
133         return *m_items;
134
135     Vector<Ref<DataTransferItem>> items;
136     for (auto& type : m_dataTransfer.typesForItemList()) {
137         auto lowercasedType = type.convertToASCIILowercase();
138         if (shouldExposeTypeInItemList(lowercasedType))
139             items.append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(*const_cast<DataTransferItemList*>(this)), lowercasedType));
140     }
141
142     for (auto& file : m_dataTransfer.files().files())
143         items.append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(*const_cast<DataTransferItemList*>(this)), file->type(), file.copyRef()));
144
145     m_items = WTFMove(items);
146
147     return *m_items;
148 }
149
150 static void removeStringItemOfLowercasedType(Vector<Ref<DataTransferItem>>& items, const String& lowercasedType)
151 {
152     auto index = items.findMatching([lowercasedType](auto& item) {
153         return !item->isFile() && item->type() == lowercasedType;
154     });
155     if (index == notFound)
156         return;
157     items[index]->clearListAndPutIntoDisabledMode();
158     items.remove(index);
159 }
160
161 void DataTransferItemList::didClearStringData(const String& type)
162 {
163     if (!m_items)
164         return;
165
166     auto& items = *m_items;
167     if (!type.isNull())
168         return removeStringItemOfLowercasedType(items, type.convertToASCIILowercase());
169
170     for (auto& item : items) {
171         if (!item->isFile())
172             item->clearListAndPutIntoDisabledMode();
173     }
174     items.removeAllMatching([](auto& item) {
175         return !item->isFile();
176     });
177 }
178
179 // https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-setdata
180 void DataTransferItemList::didSetStringData(const String& type)
181 {
182     if (!m_items)
183         return;
184
185     String lowercasedType = type.convertToASCIILowercase();
186     removeStringItemOfLowercasedType(*m_items, type.convertToASCIILowercase());
187
188     m_items->append(DataTransferItem::create(m_weakPtrFactory.createWeakPtr(*this), lowercasedType));
189 }
190
191 }
192