BlobRegistry no longer needs SessionIDs
[WebKit-https.git] / Source / WebCore / dom / DataTransfer.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2013 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 "DataTransfer.h"
28
29 #include "CachedImage.h"
30 #include "CachedImageClient.h"
31 #include "DataTransferItem.h"
32 #include "DataTransferItemList.h"
33 #include "DocumentFragment.h"
34 #include "DragData.h"
35 #include "Editor.h"
36 #include "FileList.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "HTMLImageElement.h"
40 #include "HTMLParserIdioms.h"
41 #include "Image.h"
42 #include "Pasteboard.h"
43 #include "RuntimeEnabledFeatures.h"
44 #include "Settings.h"
45 #include "StaticPasteboard.h"
46 #include "WebContentReader.h"
47 #include "WebCorePasteboardFileReader.h"
48 #include "markup.h"
49 #include <wtf/URLParser.h>
50 #include <wtf/unicode/CharacterNames.h>
51
52 namespace WebCore {
53
54 #if ENABLE(DRAG_SUPPORT)
55
56 class DragImageLoader final : private CachedImageClient {
57     WTF_MAKE_NONCOPYABLE(DragImageLoader); WTF_MAKE_FAST_ALLOCATED;
58 public:
59     explicit DragImageLoader(DataTransfer*);
60     void startLoading(CachedResourceHandle<CachedImage>&);
61     void stopLoading(CachedResourceHandle<CachedImage>&);
62     void moveToDataTransfer(DataTransfer&);
63
64 private:
65     void imageChanged(CachedImage*, const IntRect*) override;
66     DataTransfer* m_dataTransfer;
67 };
68
69 #endif
70
71 DataTransfer::DataTransfer(StoreMode mode, std::unique_ptr<Pasteboard> pasteboard, Type type)
72     : m_storeMode(mode)
73     , m_pasteboard(WTFMove(pasteboard))
74 #if ENABLE(DRAG_SUPPORT)
75     , m_type(type)
76     , m_dropEffect("uninitialized"_s)
77     , m_effectAllowed("uninitialized"_s)
78     , m_shouldUpdateDragImage(false)
79 #endif
80 {
81 #if !ENABLE(DRAG_SUPPORT)
82     ASSERT_UNUSED(type, type != Type::DragAndDropData && type != Type::DragAndDropFiles);
83 #endif
84 }
85
86 Ref<DataTransfer> DataTransfer::createForCopyAndPaste(const Document& document, StoreMode storeMode, std::unique_ptr<Pasteboard>&& pasteboard)
87 {
88     auto dataTransfer = adoptRef(*new DataTransfer(storeMode, WTFMove(pasteboard)));
89     dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard();
90     return dataTransfer;
91 }
92
93 DataTransfer::~DataTransfer()
94 {
95 #if ENABLE(DRAG_SUPPORT)
96     if (m_dragImageLoader && m_dragImage)
97         m_dragImageLoader->stopLoading(m_dragImage);
98 #endif
99 }
100
101 bool DataTransfer::canReadTypes() const
102 {
103     return m_storeMode == StoreMode::Readonly || m_storeMode == StoreMode::Protected || m_storeMode == StoreMode::ReadWrite;
104 }
105
106 bool DataTransfer::canReadData() const
107 {
108     return m_storeMode == StoreMode::Readonly || m_storeMode == StoreMode::ReadWrite;
109 }
110
111 bool DataTransfer::canWriteData() const
112 {
113     return m_storeMode == StoreMode::ReadWrite;
114 }
115
116 static String normalizeType(const String& type)
117 {
118     if (type.isNull())
119         return type;
120
121     String lowercaseType = stripLeadingAndTrailingHTMLSpaces(type).convertToASCIILowercase();
122     if (lowercaseType == "text" || lowercaseType.startsWith("text/plain;"))
123         return "text/plain";
124     if (lowercaseType == "url" || lowercaseType.startsWith("text/uri-list;"))
125         return "text/uri-list";
126     if (lowercaseType.startsWith("text/html;"))
127         return "text/html";
128
129     return lowercaseType;
130 }
131
132 void DataTransfer::clearData(const String& type)
133 {
134     if (!canWriteData())
135         return;
136
137     String normalizedType = normalizeType(type);
138     if (normalizedType.isNull())
139         m_pasteboard->clear();
140     else
141         m_pasteboard->clear(normalizedType);
142     if (m_itemList)
143         m_itemList->didClearStringData(normalizedType);
144 }
145
146 static String readURLsFromPasteboardAsString(Pasteboard& pasteboard, Function<bool(const String&)>&& shouldIncludeURL)
147 {
148     StringBuilder urlList;
149     for (const auto& urlString : pasteboard.readAllStrings("text/uri-list"_s)) {
150         if (!shouldIncludeURL(urlString))
151             continue;
152         if (!urlList.isEmpty())
153             urlList.append(newlineCharacter);
154         urlList.append(urlString);
155     }
156     return urlList.toString();
157 }
158
159 String DataTransfer::getDataForItem(Document& document, const String& type) const
160 {
161     if (!canReadData())
162         return { };
163
164     auto lowercaseType = stripLeadingAndTrailingHTMLSpaces(type).convertToASCIILowercase();
165     if (shouldSuppressGetAndSetDataToAvoidExposingFilePaths()) {
166         if (lowercaseType == "text/uri-list") {
167             return readURLsFromPasteboardAsString(*m_pasteboard, [] (auto& urlString) {
168                 return Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(urlString);
169             });
170         }
171
172         if (lowercaseType == "text/html" && RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
173             // If the pasteboard contains files and the page requests 'text/html', we only read from rich text types to prevent file
174             // paths from leaking (e.g. from plain text data on the pasteboard) since we sanitize cross-origin markup. However, if
175             // custom pasteboard data is disabled, then we can't ensure that the markup we deliver is sanitized, so we fall back to
176             // current behavior and return an empty string.
177             return readStringFromPasteboard(document, lowercaseType, WebContentReadingPolicy::OnlyRichTextTypes);
178         }
179
180         return { };
181     }
182
183     return readStringFromPasteboard(document, lowercaseType, WebContentReadingPolicy::AnyType);
184 }
185
186 String DataTransfer::readStringFromPasteboard(Document& document, const String& lowercaseType, WebContentReadingPolicy policy) const
187 {
188     if (!RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled())
189         return m_pasteboard->readString(lowercaseType);
190
191     // StaticPasteboard is only used to stage data written by websites before being committed to the system pasteboard.
192     bool isSameOrigin = is<StaticPasteboard>(*m_pasteboard) || (!m_originIdentifier.isNull() && m_originIdentifier == m_pasteboard->readOrigin());
193     if (isSameOrigin) {
194         String value = m_pasteboard->readStringInCustomData(lowercaseType);
195         if (!value.isNull())
196             return value;
197     }
198     if (!Pasteboard::isSafeTypeForDOMToReadAndWrite(lowercaseType))
199         return { };
200
201     if (!is<StaticPasteboard>(*m_pasteboard) && lowercaseType == "text/html") {
202         if (!document.frame())
203             return { };
204         WebContentMarkupReader reader { *document.frame() };
205         m_pasteboard->read(reader, policy);
206         return reader.markup;
207     }
208
209     if (!is<StaticPasteboard>(*m_pasteboard) && lowercaseType == "text/uri-list") {
210         return readURLsFromPasteboardAsString(*m_pasteboard, [] (auto&) {
211             return true;
212         });
213     }
214
215     return m_pasteboard->readString(lowercaseType);
216 }
217
218 String DataTransfer::getData(Document& document, const String& type) const
219 {
220     return getDataForItem(document, normalizeType(type));
221 }
222
223 bool DataTransfer::shouldSuppressGetAndSetDataToAvoidExposingFilePaths() const
224 {
225     if (!forFileDrag() && !RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled())
226         return false;
227     return m_pasteboard->fileContentState() == Pasteboard::FileContentState::MayContainFilePaths;
228 }
229
230 void DataTransfer::setData(const String& type, const String& data)
231 {
232     if (!canWriteData())
233         return;
234
235     if (shouldSuppressGetAndSetDataToAvoidExposingFilePaths())
236         return;
237
238     auto normalizedType = normalizeType(type);
239     setDataFromItemList(normalizedType, data);
240     if (m_itemList)
241         m_itemList->didSetStringData(normalizedType);
242 }
243
244 void DataTransfer::setDataFromItemList(const String& type, const String& data)
245 {
246     ASSERT(canWriteData());
247     RELEASE_ASSERT(is<StaticPasteboard>(*m_pasteboard));
248
249     if (!RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
250         m_pasteboard->writeString(type, data);
251         return;
252     }
253
254     String sanitizedData;
255     if (type == "text/html")
256         sanitizedData = sanitizeMarkup(data);
257     else if (type == "text/uri-list") {
258         auto url = URL({ }, data);
259         if (url.isValid())
260             sanitizedData = url.string();
261     } else if (type == "text/plain")
262         sanitizedData = data; // Nothing to sanitize.
263
264     if (sanitizedData != data)
265         downcast<StaticPasteboard>(*m_pasteboard).writeStringInCustomData(type, data);
266
267     if (Pasteboard::isSafeTypeForDOMToReadAndWrite(type) && !sanitizedData.isNull())
268         m_pasteboard->writeString(type, sanitizedData);
269 }
270
271 void DataTransfer::updateFileList()
272 {
273     ASSERT(canWriteData());
274
275     m_fileList->m_files = filesFromPasteboardAndItemList();
276 }
277
278 void DataTransfer::didAddFileToItemList()
279 {
280     ASSERT(canWriteData());
281     if (!m_fileList)
282         return;
283
284     auto& newItem = m_itemList->items().last();
285     ASSERT(newItem->isFile());
286     m_fileList->append(*newItem->file());
287 }
288
289 DataTransferItemList& DataTransfer::items()
290 {
291     if (!m_itemList)
292         m_itemList = makeUnique<DataTransferItemList>(*this);
293     return *m_itemList;
294 }
295
296 Vector<String> DataTransfer::types() const
297 {
298     return types(AddFilesType::Yes);
299 }
300
301 Vector<String> DataTransfer::typesForItemList() const
302 {
303     return types(AddFilesType::No);
304 }
305
306 Vector<String> DataTransfer::types(AddFilesType addFilesType) const
307 {
308     if (!canReadTypes())
309         return { };
310     
311     if (!RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
312         auto types = m_pasteboard->typesForLegacyUnsafeBindings();
313         ASSERT(!types.contains("Files"));
314         if (m_pasteboard->fileContentState() != Pasteboard::FileContentState::NoFileOrImageData && addFilesType == AddFilesType::Yes)
315             types.append("Files");
316         return types;
317     }
318
319     auto safeTypes = m_pasteboard->typesSafeForBindings(m_originIdentifier);
320     bool hasFileBackedItem = m_itemList && m_itemList->hasItems() && notFound != m_itemList->items().findMatching([] (const auto& item) {
321         return item->isFile();
322     });
323
324     auto fileContentState = m_pasteboard->fileContentState();
325     if (hasFileBackedItem || fileContentState != Pasteboard::FileContentState::NoFileOrImageData) {
326         Vector<String> types;
327         if (addFilesType == AddFilesType::Yes)
328             types.append("Files"_s);
329
330         if (fileContentState != Pasteboard::FileContentState::MayContainFilePaths) {
331             types.appendVector(WTFMove(safeTypes));
332             return types;
333         }
334
335         if (safeTypes.contains("text/uri-list"))
336             types.append("text/uri-list"_s);
337         if (safeTypes.contains("text/html") && RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled())
338             types.append("text/html"_s);
339         return types;
340     }
341
342     ASSERT(!safeTypes.contains("Files"));
343     return safeTypes;
344 }
345
346 Vector<Ref<File>> DataTransfer::filesFromPasteboardAndItemList() const
347 {
348     bool addedFilesFromPasteboard = false;
349     Vector<Ref<File>> files;
350     if ((!forDrag() || forFileDrag()) && m_pasteboard->fileContentState() != Pasteboard::FileContentState::NoFileOrImageData) {
351         WebCorePasteboardFileReader reader;
352         m_pasteboard->read(reader);
353         files = WTFMove(reader.files);
354         addedFilesFromPasteboard = !files.isEmpty();
355     }
356
357     bool itemListContainsItems = false;
358     if (m_itemList && m_itemList->hasItems()) {
359         for (auto& item : m_itemList->items()) {
360             if (auto file = item->file())
361                 files.append(file.releaseNonNull());
362         }
363         itemListContainsItems = true;
364     }
365
366     bool containsItemsAndFiles = itemListContainsItems && addedFilesFromPasteboard;
367     ASSERT_UNUSED(containsItemsAndFiles, !containsItemsAndFiles);
368     return files;
369 }
370
371 FileList& DataTransfer::files() const
372 {
373     if (!canReadData()) {
374         if (m_fileList)
375             m_fileList->clear();
376         else
377             m_fileList = FileList::create();
378         return *m_fileList;
379     }
380
381     if (!m_fileList)
382         m_fileList = FileList::create(filesFromPasteboardAndItemList());
383
384     return *m_fileList;
385 }
386
387 struct PasteboardFileTypeReader final : PasteboardFileReader {
388     void readFilename(const String& filename)
389     {
390         types.add(File::contentTypeForFile(filename));
391     }
392
393     void readBuffer(const String&, const String& type, Ref<SharedBuffer>&&)
394     {
395         types.add(type);
396     }
397
398     HashSet<String, ASCIICaseInsensitiveHash> types;
399 };
400
401 bool DataTransfer::hasFileOfType(const String& type)
402 {
403     ASSERT_WITH_SECURITY_IMPLICATION(canReadTypes());
404     PasteboardFileTypeReader reader;
405     m_pasteboard->read(reader);
406     return reader.types.contains(type);
407 }
408
409 bool DataTransfer::hasStringOfType(const String& type)
410 {
411     ASSERT_WITH_SECURITY_IMPLICATION(canReadTypes());
412
413     return !type.isNull() && types().contains(type);
414 }
415
416 Ref<DataTransfer> DataTransfer::createForInputEvent(const String& plainText, const String& htmlText)
417 {
418     auto pasteboard = makeUnique<StaticPasteboard>();
419     pasteboard->writeString("text/plain"_s, plainText);
420     pasteboard->writeString("text/html"_s, htmlText);
421     return adoptRef(*new DataTransfer(StoreMode::Readonly, WTFMove(pasteboard), Type::InputEvent));
422 }
423
424 void DataTransfer::commitToPasteboard(Pasteboard& nativePasteboard)
425 {
426     ASSERT(is<StaticPasteboard>(*m_pasteboard) && !is<StaticPasteboard>(nativePasteboard));
427     PasteboardCustomData customData = downcast<StaticPasteboard>(*m_pasteboard).takeCustomData();
428     if (RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
429         customData.origin = m_originIdentifier;
430         nativePasteboard.writeCustomData(customData);
431         return;
432     }
433
434     for (auto& entry : customData.platformData)
435         nativePasteboard.writeString(entry.key, entry.value);
436     for (auto& entry : customData.sameOriginCustomData)
437         nativePasteboard.writeString(entry.key, entry.value);
438 }
439
440 #if !ENABLE(DRAG_SUPPORT)
441
442 String DataTransfer::dropEffect() const
443 {
444     return "none"_s;
445 }
446
447 void DataTransfer::setDropEffect(const String&)
448 {
449 }
450
451 String DataTransfer::effectAllowed() const
452 {
453     return "uninitialized"_s;
454 }
455
456 void DataTransfer::setEffectAllowed(const String&)
457 {
458 }
459
460 void DataTransfer::setDragImage(Element*, int, int)
461 {
462 }
463
464 #else
465
466 Ref<DataTransfer> DataTransfer::createForDrag()
467 {
468     return adoptRef(*new DataTransfer(StoreMode::ReadWrite, Pasteboard::createForDragAndDrop(), Type::DragAndDropData));
469 }
470
471 Ref<DataTransfer> DataTransfer::createForDragStartEvent(const Document& document)
472 {
473     auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique<StaticPasteboard>(), Type::DragAndDropData));
474     dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard();
475     return dataTransfer;
476 }
477
478 Ref<DataTransfer> DataTransfer::createForDrop(const Document& document, std::unique_ptr<Pasteboard>&& pasteboard, DragOperation sourceOperation, bool draggingFiles)
479 {
480     auto dataTransfer = adoptRef(*new DataTransfer(DataTransfer::StoreMode::Readonly, WTFMove(pasteboard), draggingFiles ? Type::DragAndDropFiles : Type::DragAndDropData));
481     dataTransfer->setSourceOperation(sourceOperation);
482     dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard();
483     return dataTransfer;
484 }
485
486 Ref<DataTransfer> DataTransfer::createForUpdatingDropTarget(const Document& document, std::unique_ptr<Pasteboard>&& pasteboard, DragOperation sourceOperation, bool draggingFiles)
487 {
488     auto dataTransfer = adoptRef(*new DataTransfer(DataTransfer::StoreMode::Protected, WTFMove(pasteboard), draggingFiles ? Type::DragAndDropFiles : Type::DragAndDropData));
489     dataTransfer->setSourceOperation(sourceOperation);
490     dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard();
491     return dataTransfer;
492 }
493
494 void DataTransfer::setDragImage(Element* element, int x, int y)
495 {
496     if (!forDrag() || !canWriteData())
497         return;
498
499     CachedImage* image = nullptr;
500     if (is<HTMLImageElement>(element) && !element->isConnected())
501         image = downcast<HTMLImageElement>(*element).cachedImage();
502
503     m_dragLocation = IntPoint(x, y);
504
505     if (m_dragImageLoader && m_dragImage)
506         m_dragImageLoader->stopLoading(m_dragImage);
507     m_dragImage = image;
508     if (m_dragImage) {
509         if (!m_dragImageLoader)
510             m_dragImageLoader = makeUnique<DragImageLoader>(this);
511         m_dragImageLoader->startLoading(m_dragImage);
512     }
513
514     m_dragImageElement = image ? nullptr : element;
515
516     updateDragImage();
517 }
518
519 void DataTransfer::updateDragImage()
520 {
521     // Don't allow setting the image if we haven't started dragging yet; we'll rely on the dragging code
522     // to install this drag image as part of getting the drag kicked off.
523     if (!m_shouldUpdateDragImage)
524         return;
525
526     IntPoint computedHotSpot;
527     auto computedImage = DragImage { createDragImage(computedHotSpot) };
528     if (!computedImage)
529         return;
530
531     m_pasteboard->setDragImage(WTFMove(computedImage), computedHotSpot);
532 }
533
534 RefPtr<Element> DataTransfer::dragImageElement() const
535 {
536     return m_dragImageElement;
537 }
538
539 #if !PLATFORM(MAC)
540
541 DragImageRef DataTransfer::createDragImage(IntPoint& location) const
542 {
543     location = m_dragLocation;
544
545     if (m_dragImage)
546         return createDragImageFromImage(m_dragImage->image(), ImageOrientation::None);
547
548     if (m_dragImageElement) {
549         if (Frame* frame = m_dragImageElement->document().frame())
550             return createDragImageForNode(*frame, *m_dragImageElement);
551     }
552
553     // We do not have enough information to create a drag image, use the default icon.
554     return nullptr;
555 }
556
557 #endif
558
559 DragImageLoader::DragImageLoader(DataTransfer* dataTransfer)
560     : m_dataTransfer(dataTransfer)
561 {
562 }
563
564 void DragImageLoader::moveToDataTransfer(DataTransfer& newDataTransfer)
565 {
566     m_dataTransfer = &newDataTransfer;
567 }
568
569 void DragImageLoader::startLoading(CachedResourceHandle<WebCore::CachedImage>& image)
570 {
571     // FIXME: Does this really trigger a load? Does it need to?
572     image->addClient(*this);
573 }
574
575 void DragImageLoader::stopLoading(CachedResourceHandle<WebCore::CachedImage>& image)
576 {
577     image->removeClient(*this);
578 }
579
580 void DragImageLoader::imageChanged(CachedImage*, const IntRect*)
581 {
582     m_dataTransfer->updateDragImage();
583 }
584
585 static DragOperation dragOpFromIEOp(const String& operation)
586 {
587     if (operation == "uninitialized")
588         return DragOperationEvery;
589     if (operation == "none")
590         return DragOperationNone;
591     if (operation == "copy")
592         return DragOperationCopy;
593     if (operation == "link")
594         return DragOperationLink;
595     if (operation == "move")
596         return (DragOperation)(DragOperationGeneric | DragOperationMove);
597     if (operation == "copyLink")
598         return (DragOperation)(DragOperationCopy | DragOperationLink);
599     if (operation == "copyMove")
600         return (DragOperation)(DragOperationCopy | DragOperationGeneric | DragOperationMove);
601     if (operation == "linkMove")
602         return (DragOperation)(DragOperationLink | DragOperationGeneric | DragOperationMove);
603     if (operation == "all")
604         return DragOperationEvery;
605     return DragOperationPrivate; // really a marker for "no conversion"
606 }
607
608 static const char* IEOpFromDragOp(DragOperation operation)
609 {
610     bool isGenericMove = operation & (DragOperationGeneric | DragOperationMove);
611
612     if ((isGenericMove && (operation & DragOperationCopy) && (operation & DragOperationLink)) || operation == DragOperationEvery)
613         return "all";
614     if (isGenericMove && (operation & DragOperationCopy))
615         return "copyMove";
616     if (isGenericMove && (operation & DragOperationLink))
617         return "linkMove";
618     if ((operation & DragOperationCopy) && (operation & DragOperationLink))
619         return "copyLink";
620     if (isGenericMove)
621         return "move";
622     if (operation & DragOperationCopy)
623         return "copy";
624     if (operation & DragOperationLink)
625         return "link";
626     return "none";
627 }
628
629 DragOperation DataTransfer::sourceOperation() const
630 {
631     DragOperation operation = dragOpFromIEOp(m_effectAllowed);
632     ASSERT(operation != DragOperationPrivate);
633     return operation;
634 }
635
636 DragOperation DataTransfer::destinationOperation() const
637 {
638     DragOperation operation = dragOpFromIEOp(m_dropEffect);
639     ASSERT(operation == DragOperationCopy || operation == DragOperationNone || operation == DragOperationLink || operation == (DragOperation)(DragOperationGeneric | DragOperationMove) || operation == DragOperationEvery);
640     return operation;
641 }
642
643 void DataTransfer::setSourceOperation(DragOperation operation)
644 {
645     ASSERT_ARG(operation, operation != DragOperationPrivate);
646     m_effectAllowed = IEOpFromDragOp(operation);
647 }
648
649 void DataTransfer::setDestinationOperation(DragOperation operation)
650 {
651     ASSERT_ARG(operation, operation == DragOperationCopy || operation == DragOperationNone || operation == DragOperationLink || operation == DragOperationGeneric || operation == DragOperationMove || operation == (DragOperation)(DragOperationGeneric | DragOperationMove));
652     m_dropEffect = IEOpFromDragOp(operation);
653 }
654
655 String DataTransfer::dropEffect() const
656 {
657     return m_dropEffect == "uninitialized" ? "none"_s : m_dropEffect;
658 }
659
660 void DataTransfer::setDropEffect(const String& effect)
661 {
662     if (!forDrag())
663         return;
664
665     if (effect != "none" && effect != "copy" && effect != "link" && effect != "move")
666         return;
667
668     // FIXME: The spec allows this in all circumstances. There is probably no value
669     // in ignoring attempts to change it.
670     if (!canReadTypes())
671         return;
672
673     m_dropEffect = effect;
674 }
675
676 String DataTransfer::effectAllowed() const
677 {
678     return m_effectAllowed;
679 }
680
681 void DataTransfer::setEffectAllowed(const String& effect)
682 {
683     if (!forDrag())
684         return;
685
686     // Ignore any attempts to set it to an unknown value.
687     if (dragOpFromIEOp(effect) == DragOperationPrivate)
688         return;
689
690     if (!canWriteData())
691         return;
692
693     m_effectAllowed = effect;
694 }
695
696 void DataTransfer::moveDragState(Ref<DataTransfer>&& other)
697 {
698     RELEASE_ASSERT(is<StaticPasteboard>(other->pasteboard()));
699     // We clear the platform pasteboard here to ensure that the pasteboard doesn't contain any data
700     // that may have been written before starting the drag, and after ending the last drag session.
701     // After pushing the static pasteboard's contents to the platform, the pasteboard should only
702     // contain data that was in the static pasteboard.
703     m_pasteboard->clear();
704     other->commitToPasteboard(*m_pasteboard);
705
706     m_dropEffect = other->m_dropEffect;
707     m_effectAllowed = other->m_effectAllowed;
708     m_dragLocation = other->m_dragLocation;
709     m_dragImage = other->m_dragImage;
710     m_dragImageElement = WTFMove(other->m_dragImageElement);
711     m_dragImageLoader = WTFMove(other->m_dragImageLoader);
712     if (m_dragImageLoader)
713         m_dragImageLoader->moveToDataTransfer(*this);
714     m_fileList = WTFMove(other->m_fileList);
715 }
716
717 bool DataTransfer::hasDragImage() const
718 {
719     return m_dragImage || m_dragImageElement;
720 }
721
722 #endif // ENABLE(DRAG_SUPPORT)
723
724 } // namespace WebCore