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