1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ArrayUtils.h"
8 #include "mozilla/BasePrincipal.h"
9 #include "mozilla/BasicEvents.h"
10 #include "mozilla/CheckedInt.h"
11 #include "mozilla/Span.h"
12 #include "mozilla/StaticPrefs_dom.h"
13 #include "DataTransfer.h"
15 #include "nsISupportsPrimitives.h"
16 #include "nsIScriptSecurityManager.h"
17 #include "mozilla/dom/DOMStringList.h"
20 #include "nsIDragService.h"
21 #include "nsIClipboard.h"
22 #include "nsIXPConnect.h"
23 #include "nsContentUtils.h"
24 #include "nsIContent.h"
25 #include "nsIObjectInputStream.h"
26 #include "nsIObjectOutputStream.h"
27 #include "nsIStorageStream.h"
28 #include "nsStringStream.h"
30 #include "nsIScriptObjectPrincipal.h"
31 #include "nsIScriptContext.h"
32 #include "mozilla/dom/Document.h"
33 #include "nsIScriptGlobalObject.h"
34 #include "nsQueryObject.h"
35 #include "nsVariant.h"
36 #include "mozilla/dom/ContentChild.h"
37 #include "mozilla/dom/DataTransferBinding.h"
38 #include "mozilla/dom/DataTransferItemList.h"
39 #include "mozilla/dom/Directory.h"
40 #include "mozilla/dom/Element.h"
41 #include "mozilla/dom/FileList.h"
42 #include "mozilla/dom/IPCBlobUtils.h"
43 #include "mozilla/dom/BindingUtils.h"
44 #include "mozilla/dom/OSFileSystem.h"
45 #include "mozilla/dom/Promise.h"
46 #include "mozilla/dom/WindowContext.h"
47 #include "mozilla/Unused.h"
48 #include "nsComponentManagerUtils.h"
49 #include "nsNetUtil.h"
50 #include "nsReadableUtils.h"
52 namespace mozilla::dom
{
54 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(DataTransfer
)
56 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer
)
57 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent
)
58 NS_IMPL_CYCLE_COLLECTION_UNLINK(mItems
)
59 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget
)
60 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage
)
61 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
62 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
63 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer
)
64 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent
)
65 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems
)
66 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget
)
67 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage
)
68 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
70 NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer
)
71 NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransfer
)
73 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransfer
)
74 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
75 NS_INTERFACE_MAP_ENTRY(mozilla::dom::DataTransfer
)
76 NS_INTERFACE_MAP_ENTRY(nsISupports
)
79 // the size of the array
80 const char DataTransfer::sEffects
[8][9] = {
81 "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"};
83 // Used for custom clipboard types.
84 enum CustomClipboardTypeId
{
85 eCustomClipboardTypeId_None
,
86 eCustomClipboardTypeId_String
89 static DataTransfer::Mode
ModeForEvent(EventMessage aEventMessage
) {
90 switch (aEventMessage
) {
94 // For these events, we want to be able to add data to the data transfer,
95 // Otherwise, the data is already present.
96 return DataTransfer::Mode::ReadWrite
;
99 case ePasteNoFormatting
:
101 // For these events we want to be able to read the data which is stored in
102 // the DataTransfer, rather than just the type information.
103 return DataTransfer::Mode::ReadOnly
;
105 return StaticPrefs::dom_events_dataTransfer_protected_enabled()
106 ? DataTransfer::Mode::Protected
107 : DataTransfer::Mode::ReadOnly
;
111 DataTransfer::DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
112 bool aIsExternal
, int32_t aClipboardType
)
114 mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE
),
115 mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
),
116 mEventMessage(aEventMessage
),
118 mMode(ModeForEvent(aEventMessage
)),
119 mIsExternal(aIsExternal
),
120 mUserCancelled(false),
121 mIsCrossDomainSubFrameDrop(false),
122 mClipboardType(aClipboardType
),
125 mItems
= new DataTransferItemList(this);
127 // For external usage, cache the data from the native clipboard or drag.
128 if (mIsExternal
&& mMode
!= Mode::ReadWrite
) {
129 if (aEventMessage
== ePasteNoFormatting
) {
130 mEventMessage
= ePaste
;
131 CacheExternalClipboardFormats(true);
132 } else if (aEventMessage
== ePaste
) {
133 CacheExternalClipboardFormats(false);
134 } else if (aEventMessage
>= eDragDropEventFirst
&&
135 aEventMessage
<= eDragDropEventLast
) {
136 CacheExternalDragFormats();
141 DataTransfer::DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
142 nsITransferable
* aTransferable
)
144 mTransferable(aTransferable
),
145 mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE
),
146 mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
),
147 mEventMessage(aEventMessage
),
149 mMode(ModeForEvent(aEventMessage
)),
151 mUserCancelled(false),
152 mIsCrossDomainSubFrameDrop(false),
156 mItems
= new DataTransferItemList(this);
158 // XXX Currently, we cannot make DataTransfer grabs mTransferable for long
159 // time because nsITransferable is not cycle collectable but this may
160 // be grabbed by JS. Additionally, the data initializing path is too
161 // complicated (too optimized) for D&D and clipboard. They are cached
162 // only formats first, then, data of all items will be filled by the
163 // items later and by themselves. However, we shouldn't duplicate such
164 // path for saving the maintenance cost. Therefore, we need to treat
165 // that DataTransfer and its items are in external mode. Finally,
166 // release mTransferable and make them in internal mode.
167 CacheTransferableFormats();
168 FillAllExternalData();
169 // Now, we have all necessary data of mTransferable. So, we can work as
172 // Release mTransferable because it won't be referred anymore.
173 mTransferable
= nullptr;
176 DataTransfer::DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
177 const nsAString
& aString
)
179 mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE
),
180 mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
),
181 mEventMessage(aEventMessage
),
183 mMode(ModeForEvent(aEventMessage
)),
185 mUserCancelled(false),
186 mIsCrossDomainSubFrameDrop(false),
190 mItems
= new DataTransferItemList(this);
192 nsCOMPtr
<nsIPrincipal
> sysPrincipal
= nsContentUtils::GetSystemPrincipal();
194 RefPtr
<nsVariantCC
> variant
= new nsVariantCC();
195 variant
->SetAsAString(aString
);
196 DebugOnly
<nsresult
> rvIgnored
=
197 SetDataWithPrincipal(u
"text/plain"_ns
, variant
, 0, sysPrincipal
, false);
198 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
199 "Failed to set given string to the DataTransfer object");
202 DataTransfer::DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
203 const uint32_t aEffectAllowed
, bool aCursorState
,
204 bool aIsExternal
, bool aUserCancelled
,
205 bool aIsCrossDomainSubFrameDrop
,
206 int32_t aClipboardType
, DataTransferItemList
* aItems
,
207 Element
* aDragImage
, uint32_t aDragImageX
,
208 uint32_t aDragImageY
, bool aShowFailAnimation
)
210 mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE
),
211 mEffectAllowed(aEffectAllowed
),
212 mEventMessage(aEventMessage
),
213 mCursorState(aCursorState
),
214 mMode(ModeForEvent(aEventMessage
)),
215 mIsExternal(aIsExternal
),
216 mUserCancelled(aUserCancelled
),
217 mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop
),
218 mClipboardType(aClipboardType
),
219 mDragImage(aDragImage
),
220 mDragImageX(aDragImageX
),
221 mDragImageY(aDragImageY
),
222 mShowFailAnimation(aShowFailAnimation
) {
226 // We clone the items array after everything else, so that it has a valid
228 mItems
= aItems
->Clone(this);
229 // The items are copied from aItems into mItems. There is no need to copy
230 // the actual data in the items as the data transfer will be read only. The
231 // dragstart event is the only time when items are
232 // modifiable, but those events should have been using the first constructor
234 NS_ASSERTION(aEventMessage
!= eDragStart
,
235 "invalid event type for DataTransfer constructor");
238 DataTransfer::~DataTransfer() = default;
241 already_AddRefed
<DataTransfer
> DataTransfer::Constructor(
242 const GlobalObject
& aGlobal
) {
243 RefPtr
<DataTransfer
> transfer
=
244 new DataTransfer(aGlobal
.GetAsSupports(), eCopy
, /* is external */ false,
245 /* clipboard type */ -1);
246 transfer
->mEffectAllowed
= nsIDragService::DRAGDROP_ACTION_NONE
;
247 return transfer
.forget();
250 JSObject
* DataTransfer::WrapObject(JSContext
* aCx
,
251 JS::Handle
<JSObject
*> aGivenProto
) {
252 return DataTransfer_Binding::Wrap(aCx
, this, aGivenProto
);
255 void DataTransfer::SetDropEffect(const nsAString
& aDropEffect
) {
256 // the drop effect can only be 'none', 'copy', 'move' or 'link'.
257 for (uint32_t e
= 0; e
<= nsIDragService::DRAGDROP_ACTION_LINK
; e
++) {
258 if (aDropEffect
.EqualsASCII(sEffects
[e
])) {
259 // don't allow copyMove
260 if (e
!= (nsIDragService::DRAGDROP_ACTION_COPY
|
261 nsIDragService::DRAGDROP_ACTION_MOVE
)) {
269 void DataTransfer::SetEffectAllowed(const nsAString
& aEffectAllowed
) {
270 if (aEffectAllowed
.EqualsLiteral("uninitialized")) {
271 mEffectAllowed
= nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
;
275 static_assert(nsIDragService::DRAGDROP_ACTION_NONE
== 0,
276 "DRAGDROP_ACTION_NONE constant is wrong");
277 static_assert(nsIDragService::DRAGDROP_ACTION_COPY
== 1,
278 "DRAGDROP_ACTION_COPY constant is wrong");
279 static_assert(nsIDragService::DRAGDROP_ACTION_MOVE
== 2,
280 "DRAGDROP_ACTION_MOVE constant is wrong");
281 static_assert(nsIDragService::DRAGDROP_ACTION_LINK
== 4,
282 "DRAGDROP_ACTION_LINK constant is wrong");
284 for (uint32_t e
= 0; e
< ArrayLength(sEffects
); e
++) {
285 if (aEffectAllowed
.EqualsASCII(sEffects
[e
])) {
292 void DataTransfer::GetMozTriggeringPrincipalURISpec(
293 nsAString
& aPrincipalURISpec
) {
294 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
296 aPrincipalURISpec
.Truncate(0);
300 nsCOMPtr
<nsIPrincipal
> principal
;
301 dragSession
->GetTriggeringPrincipal(getter_AddRefs(principal
));
303 aPrincipalURISpec
.Truncate(0);
308 principal
->GetAsciiSpec(spec
);
309 CopyUTF8toUTF16(spec
, aPrincipalURISpec
);
312 nsIContentSecurityPolicy
* DataTransfer::GetMozCSP() {
313 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
317 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
318 dragSession
->GetCsp(getter_AddRefs(csp
));
322 already_AddRefed
<FileList
> DataTransfer::GetFiles(
323 nsIPrincipal
& aSubjectPrincipal
) {
324 return mItems
->Files(&aSubjectPrincipal
);
327 void DataTransfer::GetTypes(nsTArray
<nsString
>& aTypes
,
328 CallerType aCallerType
) const {
329 // When called from bindings, aTypes will be empty, but since we might have
330 // Gecko-internal callers too, clear it to be safe.
333 return mItems
->GetTypes(aTypes
, aCallerType
);
336 bool DataTransfer::HasType(const nsAString
& aType
) const {
337 return mItems
->HasType(aType
);
340 bool DataTransfer::HasFile() const { return mItems
->HasFile(); }
342 void DataTransfer::GetData(const nsAString
& aFormat
, nsAString
& aData
,
343 nsIPrincipal
& aSubjectPrincipal
,
344 ErrorResult
& aRv
) const {
345 // return an empty string if data for the format was not found
348 nsCOMPtr
<nsIVariant
> data
;
350 GetDataAtInternal(aFormat
, 0, &aSubjectPrincipal
, getter_AddRefs(data
));
352 if (rv
!= NS_ERROR_DOM_INDEX_SIZE_ERR
) {
359 nsAutoString stringdata
;
360 data
->GetAsAString(stringdata
);
362 // for the URL type, parse out the first URI from the list. The URIs are
363 // separated by newlines
364 nsAutoString lowercaseFormat
;
365 nsContentUtils::ASCIIToLower(aFormat
, lowercaseFormat
);
367 if (lowercaseFormat
.EqualsLiteral("url")) {
368 int32_t lastidx
= 0, idx
;
369 int32_t length
= stringdata
.Length();
370 while (lastidx
< length
) {
371 idx
= stringdata
.FindChar('\n', lastidx
);
372 // lines beginning with # are comments
373 if (stringdata
[lastidx
] == '#') {
379 aData
.Assign(Substring(stringdata
, lastidx
));
381 aData
.Assign(Substring(stringdata
, lastidx
, idx
- lastidx
));
384 nsContentUtils::TrimWhitespace
<nsCRT::IsAsciiSpace
>(aData
, true);
395 void DataTransfer::SetData(const nsAString
& aFormat
, const nsAString
& aData
,
396 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
397 RefPtr
<nsVariantCC
> variant
= new nsVariantCC();
398 variant
->SetAsAString(aData
);
400 aRv
= SetDataAtInternal(aFormat
, variant
, 0, &aSubjectPrincipal
);
403 void DataTransfer::ClearData(const Optional
<nsAString
>& aFormat
,
404 nsIPrincipal
& aSubjectPrincipal
,
407 aRv
.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
);
411 if (MozItemCount() == 0) {
415 if (aFormat
.WasPassed()) {
416 MozClearDataAtHelper(aFormat
.Value(), 0, aSubjectPrincipal
, aRv
);
418 MozClearDataAtHelper(u
""_ns
, 0, aSubjectPrincipal
, aRv
);
422 void DataTransfer::SetMozCursor(const nsAString
& aCursorState
) {
423 // Lock the cursor to an arrow during the drag.
424 mCursorState
= aCursorState
.EqualsLiteral("default");
427 already_AddRefed
<nsINode
> DataTransfer::GetMozSourceNode() {
428 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
433 nsCOMPtr
<nsINode
> sourceNode
;
434 dragSession
->GetSourceNode(getter_AddRefs(sourceNode
));
435 if (sourceNode
&& !nsContentUtils::LegacyIsCallerNativeCode() &&
436 !nsContentUtils::CanCallerAccess(sourceNode
)) {
440 return sourceNode
.forget();
443 already_AddRefed
<WindowContext
> DataTransfer::GetSourceTopWindowContext() {
444 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
449 RefPtr
<WindowContext
> sourceTopWindowContext
;
450 dragSession
->GetSourceTopWindowContext(
451 getter_AddRefs(sourceTopWindowContext
));
452 return sourceTopWindowContext
.forget();
455 already_AddRefed
<DOMStringList
> DataTransfer::MozTypesAt(
456 uint32_t aIndex
, ErrorResult
& aRv
) const {
457 // Only the first item is valid for clipboard events
458 if (aIndex
> 0 && (mEventMessage
== eCut
|| mEventMessage
== eCopy
||
459 mEventMessage
== ePaste
)) {
460 aRv
.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR
);
464 RefPtr
<DOMStringList
> types
= new DOMStringList();
465 if (aIndex
< MozItemCount()) {
466 // note that you can retrieve the types regardless of their principal
467 const nsTArray
<RefPtr
<DataTransferItem
>>& items
=
468 *mItems
->MozItemsAt(aIndex
);
470 bool addFile
= false;
471 for (uint32_t i
= 0; i
< items
.Length(); i
++) {
472 // NOTE: The reason why we get the internal type here is because we want
473 // kFileMime to appear in the types list for backwards compatibility
476 items
[i
]->GetInternalType(type
);
477 if (NS_WARN_IF(!types
->Add(type
))) {
478 aRv
.Throw(NS_ERROR_FAILURE
);
482 if (items
[i
]->Kind() == DataTransferItem::KIND_FILE
) {
488 types
->Add(u
"Files"_ns
);
492 return types
.forget();
495 nsresult
DataTransfer::GetDataAtNoSecurityCheck(const nsAString
& aFormat
,
497 nsIVariant
** aData
) const {
498 return GetDataAtInternal(aFormat
, aIndex
,
499 nsContentUtils::GetSystemPrincipal(), aData
);
502 nsresult
DataTransfer::GetDataAtInternal(const nsAString
& aFormat
,
504 nsIPrincipal
* aSubjectPrincipal
,
505 nsIVariant
** aData
) const {
508 if (aFormat
.IsEmpty()) {
512 if (aIndex
>= MozItemCount()) {
513 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
516 // Only the first item is valid for clipboard events
517 if (aIndex
> 0 && (mEventMessage
== eCut
|| mEventMessage
== eCopy
||
518 mEventMessage
== ePaste
)) {
519 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
523 GetRealFormat(aFormat
, format
);
525 MOZ_ASSERT(aSubjectPrincipal
);
527 RefPtr
<DataTransferItem
> item
= mItems
->MozItemByTypeAt(format
, aIndex
);
529 // The index exists but there's no data for the specified format, in this
530 // case we just return undefined
534 // If we have chrome only content, and we aren't chrome, don't allow access
535 if (!aSubjectPrincipal
->IsSystemPrincipal() && item
->ChromeOnly()) {
539 // DataTransferItem::Data() handles the principal checks
541 nsCOMPtr
<nsIVariant
> data
= item
->Data(aSubjectPrincipal
, result
);
542 if (NS_WARN_IF(!data
|| result
.Failed())) {
543 return result
.StealNSResult();
550 void DataTransfer::MozGetDataAt(JSContext
* aCx
, const nsAString
& aFormat
,
552 JS::MutableHandle
<JS::Value
> aRetval
,
553 mozilla::ErrorResult
& aRv
) {
554 nsCOMPtr
<nsIVariant
> data
;
555 aRv
= GetDataAtInternal(aFormat
, aIndex
, nsContentUtils::GetSystemPrincipal(),
556 getter_AddRefs(data
));
566 JS::Rooted
<JS::Value
> result(aCx
);
567 if (!VariantToJsval(aCx
, data
, aRetval
)) {
568 aRv
= NS_ERROR_FAILURE
;
574 bool DataTransfer::PrincipalMaySetData(const nsAString
& aType
,
576 nsIPrincipal
* aPrincipal
) {
577 if (!aPrincipal
->IsSystemPrincipal()) {
578 DataTransferItem::eKind kind
= DataTransferItem::KindFromData(aData
);
579 if (kind
== DataTransferItem::KIND_OTHER
) {
580 NS_WARNING("Disallowing adding non string/file types to DataTransfer");
584 // Don't allow adding internal types of the form */x-moz-*, but
585 // special-case the url types as they are simple variations of urls.
586 // In addition, allow x-moz-place flavors to be added by WebExtensions.
587 if (FindInReadable(kInternal_Mimetype_Prefix
, aType
) &&
588 !StringBeginsWith(aType
, u
"text/x-moz-url"_ns
)) {
589 auto principal
= BasePrincipal::Cast(aPrincipal
);
590 if (!principal
->AddonPolicy() ||
591 !StringBeginsWith(aType
, u
"text/x-moz-place"_ns
)) {
592 NS_WARNING("Disallowing adding this type to DataTransfer");
601 void DataTransfer::TypesListMayHaveChanged() {
602 DataTransfer_Binding::ClearCachedTypesValue(this);
605 already_AddRefed
<DataTransfer
> DataTransfer::MozCloneForEvent(
606 const nsAString
& aEvent
, ErrorResult
& aRv
) {
607 RefPtr
<nsAtom
> atomEvt
= NS_Atomize(aEvent
);
609 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
612 EventMessage eventMessage
= nsContentUtils::GetEventMessage(atomEvt
);
614 RefPtr
<DataTransfer
> dt
;
615 nsresult rv
= Clone(mParent
, eventMessage
, false, false, getter_AddRefs(dt
));
623 // The order of the types matters. `kFileMime` needs to be one of the first two
625 static const char* kNonPlainTextExternalFormats
[] = {
626 kCustomTypesMime
, kFileMime
, kHTMLMime
, kRTFMime
, kURLMime
,
627 kURLDataMime
, kTextMime
, kPNGImageMime
, kPDFJSMime
};
630 void DataTransfer::GetExternalClipboardFormats(const int32_t& aWhichClipboard
,
631 const bool& aPlainTextOnly
,
632 nsTArray
<nsCString
>* aResult
) {
635 // NOTE: When you change this method, you may need to change
636 // GetExternalTransferableFormats() too since those methods should
639 nsCOMPtr
<nsIClipboard
> clipboard
=
640 do_GetService("@mozilla.org/widget/clipboard;1");
641 if (!clipboard
|| aWhichClipboard
< 0) {
645 if (aPlainTextOnly
) {
647 AutoTArray
<nsCString
, 1> textMime
= {nsDependentCString(kTextMime
)};
649 clipboard
->HasDataMatchingFlavors(textMime
, aWhichClipboard
, &hasType
);
652 aResult
->AppendElement(kTextMime
);
657 // If not plain text only, then instead check all the other types
658 for (uint32_t f
= 0; f
< mozilla::ArrayLength(kNonPlainTextExternalFormats
);
661 AutoTArray
<nsCString
, 1> format
= {
662 nsDependentCString(kNonPlainTextExternalFormats
[f
])};
664 clipboard
->HasDataMatchingFlavors(format
, aWhichClipboard
, &hasType
);
667 aResult
->AppendElement(kNonPlainTextExternalFormats
[f
]);
673 void DataTransfer::GetExternalTransferableFormats(
674 nsITransferable
* aTransferable
, bool aPlainTextOnly
,
675 nsTArray
<nsCString
>* aResult
) {
676 MOZ_ASSERT(aTransferable
);
681 // NOTE: When you change this method, you may need to change
682 // GetExternalClipboardFormats() too since those methods should
685 AutoTArray
<nsCString
, 10> flavors
;
686 aTransferable
->FlavorsTransferableCanExport(flavors
);
688 if (aPlainTextOnly
) {
689 auto index
= flavors
.IndexOf(nsLiteralCString(kTextMime
));
690 if (index
!= flavors
.NoIndex
) {
691 aResult
->AppendElement(nsLiteralCString(kTextMime
));
696 // If not plain text only, then instead check all the other types
697 for (const char* format
: kNonPlainTextExternalFormats
) {
698 auto index
= flavors
.IndexOf(nsCString(format
));
699 if (index
!= flavors
.NoIndex
) {
700 aResult
->AppendElement(nsCString(format
));
705 nsresult
DataTransfer::SetDataAtInternal(const nsAString
& aFormat
,
706 nsIVariant
* aData
, uint32_t aIndex
,
707 nsIPrincipal
* aSubjectPrincipal
) {
708 if (aFormat
.IsEmpty()) {
713 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
;
716 // Specifying an index less than the current length will replace an existing
717 // item. Specifying an index equal to the current length will add a new item.
718 if (aIndex
> MozItemCount()) {
719 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
722 // Only the first item is valid for clipboard events
723 if (aIndex
> 0 && (mEventMessage
== eCut
|| mEventMessage
== eCopy
||
724 mEventMessage
== ePaste
)) {
725 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
728 // Don't allow the custom type to be assigned.
729 if (aFormat
.EqualsLiteral(kCustomTypesMime
)) {
730 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
733 if (!PrincipalMaySetData(aFormat
, aData
, aSubjectPrincipal
)) {
734 return NS_ERROR_DOM_SECURITY_ERR
;
737 return SetDataWithPrincipal(aFormat
, aData
, aIndex
, aSubjectPrincipal
);
740 void DataTransfer::MozSetDataAt(JSContext
* aCx
, const nsAString
& aFormat
,
741 JS::Handle
<JS::Value
> aData
, uint32_t aIndex
,
743 nsCOMPtr
<nsIVariant
> data
;
744 aRv
= nsContentUtils::XPConnect()->JSValToVariant(aCx
, aData
,
745 getter_AddRefs(data
));
747 aRv
= SetDataAtInternal(aFormat
, data
, aIndex
,
748 nsContentUtils::GetSystemPrincipal());
752 void DataTransfer::MozClearDataAt(const nsAString
& aFormat
, uint32_t aIndex
,
755 aRv
.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
);
759 if (aIndex
>= MozItemCount()) {
760 aRv
.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR
);
764 // Only the first item is valid for clipboard events
765 if (aIndex
> 0 && (mEventMessage
== eCut
|| mEventMessage
== eCopy
||
766 mEventMessage
== ePaste
)) {
767 aRv
.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR
);
771 MozClearDataAtHelper(aFormat
, aIndex
, *nsContentUtils::GetSystemPrincipal(),
774 // If we just cleared the 0-th index, and there are still more than 1 indexes
775 // remaining, MozClearDataAt should cause the 1st index to become the 0th
776 // index. This should _only_ happen when the MozClearDataAt function is
777 // explicitly called by script, as this behavior is inconsistent with spec.
778 // (however, so is the MozClearDataAt API)
780 if (aIndex
== 0 && mItems
->MozItemCount() > 1 &&
781 mItems
->MozItemsAt(0)->Length() == 0) {
782 mItems
->PopIndexZero();
786 void DataTransfer::MozClearDataAtHelper(const nsAString
& aFormat
,
788 nsIPrincipal
& aSubjectPrincipal
,
790 MOZ_ASSERT(!IsReadOnly());
791 MOZ_ASSERT(aIndex
< MozItemCount());
792 MOZ_ASSERT(aIndex
== 0 || (mEventMessage
!= eCut
&& mEventMessage
!= eCopy
&&
793 mEventMessage
!= ePaste
));
796 GetRealFormat(aFormat
, format
);
798 mItems
->MozRemoveByTypeAt(format
, aIndex
, aSubjectPrincipal
, aRv
);
801 void DataTransfer::SetDragImage(Element
& aImage
, int32_t aX
, int32_t aY
) {
803 mDragImage
= &aImage
;
809 void DataTransfer::UpdateDragImage(Element
& aImage
, int32_t aX
, int32_t aY
) {
810 if (mEventMessage
< eDragDropEventFirst
||
811 mEventMessage
> eDragDropEventLast
) {
815 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
817 dragSession
->UpdateDragImage(&aImage
, aX
, aY
);
821 void DataTransfer::AddElement(Element
& aElement
, ErrorResult
& aRv
) {
823 aRv
.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
);
827 mDragTarget
= &aElement
;
830 nsresult
DataTransfer::Clone(nsISupports
* aParent
, EventMessage aEventMessage
,
832 bool aIsCrossDomainSubFrameDrop
,
833 DataTransfer
** aNewDataTransfer
) {
834 RefPtr
<DataTransfer
> newDataTransfer
= new DataTransfer(
835 aParent
, aEventMessage
, mEffectAllowed
, mCursorState
, mIsExternal
,
836 aUserCancelled
, aIsCrossDomainSubFrameDrop
, mClipboardType
, mItems
,
837 mDragImage
, mDragImageX
, mDragImageY
, mShowFailAnimation
);
839 newDataTransfer
.forget(aNewDataTransfer
);
843 already_AddRefed
<nsIArray
> DataTransfer::GetTransferables(
844 nsINode
* aDragTarget
) {
845 MOZ_ASSERT(aDragTarget
);
847 Document
* doc
= aDragTarget
->GetComposedDoc();
852 return GetTransferables(doc
->GetLoadContext());
855 already_AddRefed
<nsIArray
> DataTransfer::GetTransferables(
856 nsILoadContext
* aLoadContext
) {
857 nsCOMPtr
<nsIMutableArray
> transArray
= nsArray::Create();
862 uint32_t count
= MozItemCount();
863 for (uint32_t i
= 0; i
< count
; i
++) {
864 nsCOMPtr
<nsITransferable
> transferable
= GetTransferable(i
, aLoadContext
);
866 transArray
->AppendElement(transferable
);
870 return transArray
.forget();
873 already_AddRefed
<nsITransferable
> DataTransfer::GetTransferable(
874 uint32_t aIndex
, nsILoadContext
* aLoadContext
) {
875 if (aIndex
>= MozItemCount()) {
879 const nsTArray
<RefPtr
<DataTransferItem
>>& item
= *mItems
->MozItemsAt(aIndex
);
880 uint32_t count
= item
.Length();
885 nsCOMPtr
<nsITransferable
> transferable
=
886 do_CreateInstance("@mozilla.org/widget/transferable;1");
890 transferable
->Init(aLoadContext
);
892 nsCOMPtr
<nsIStorageStream
> storageStream
;
893 nsCOMPtr
<nsIObjectOutputStream
> stream
;
896 bool handlingCustomFormats
= true;
898 // When writing the custom data, we need to ensure that there is sufficient
899 // space for a (uint32_t) data ending type, and the null byte character at
900 // the end of the nsCString. We claim that space upfront and store it in
901 // baseLength. This value will be set to zero if a write error occurs
902 // indicating that the data and length are no longer valid.
903 const uint32_t baseLength
= sizeof(uint32_t) + 1;
904 uint32_t totalCustomLength
= baseLength
;
907 * Two passes are made here to iterate over all of the types. First, look for
908 * any types that are not in the list of known types. For this pass,
909 * handlingCustomFormats will be true. Data that corresponds to unknown types
910 * will be pulled out and inserted into a single type (kCustomTypesMime) by
911 * writing the data into a stream.
913 * The second pass will iterate over the formats looking for known types.
914 * These are added as is. The unknown types are all then inserted as a single
915 * type (kCustomTypesMime) in the same position of the first custom type. This
916 * model is used to maintain the format order as best as possible.
918 * The format of the kCustomTypesMime type is one or more of the following
919 * stored sequentially:
920 * <32-bit> type (only none or string is supported)
921 * <32-bit> length of format
922 * <wide string> format
923 * <32-bit> length of data
925 * A type of eCustomClipboardTypeId_None ends the list, without any following
929 for (uint32_t f
= 0; f
< count
; f
++) {
930 RefPtr
<DataTransferItem
> formatitem
= item
[f
];
931 nsCOMPtr
<nsIVariant
> variant
= formatitem
->DataNoSecurityCheck();
932 if (!variant
) { // skip empty items
937 formatitem
->GetInternalType(type
);
939 // If the data is of one of the well-known formats, use it directly.
940 bool isCustomFormat
= true;
941 for (const char* format
: kKnownFormats
) {
942 if (type
.EqualsASCII(format
)) {
943 isCustomFormat
= false;
948 uint32_t lengthInBytes
;
949 nsCOMPtr
<nsISupports
> convertedData
;
951 if (handlingCustomFormats
) {
952 if (!ConvertFromVariant(variant
, getter_AddRefs(convertedData
),
957 // When handling custom types, add the data to the stream if this is a
958 // custom type. If totalCustomLength is 0, then a write error occurred
959 // on a previous item, so ignore any others.
960 if (isCustomFormat
&& totalCustomLength
> 0) {
961 // If it isn't a string, just ignore it. The dataTransfer is cached in
962 // the drag sesion during drag-and-drop, so non-strings will be
963 // available when dragging locally.
964 nsCOMPtr
<nsISupportsString
> str(do_QueryInterface(convertedData
));
970 // Create a storage stream to write to.
971 NS_NewStorageStream(1024, UINT32_MAX
,
972 getter_AddRefs(storageStream
));
974 nsCOMPtr
<nsIOutputStream
> outputStream
;
975 storageStream
->GetOutputStream(0, getter_AddRefs(outputStream
));
977 stream
= NS_NewObjectOutputStream(outputStream
);
980 CheckedInt
<uint32_t> formatLength
=
981 CheckedInt
<uint32_t>(type
.Length()) *
982 sizeof(nsString::char_type
);
984 // The total size of the stream is the format length, the data
985 // length, two integers to hold the lengths and one integer for
986 // the string flag. Guard against large data by ignoring any that
988 CheckedInt
<uint32_t> newSize
= formatLength
+ totalCustomLength
+
990 (sizeof(uint32_t) * 3);
991 if (newSize
.isValid()) {
992 // If a write error occurs, set totalCustomLength to 0 so that
993 // further processing gets ignored.
994 nsresult rv
= stream
->Write32(eCustomClipboardTypeId_String
);
995 if (NS_WARN_IF(NS_FAILED(rv
))) {
996 totalCustomLength
= 0;
999 rv
= stream
->Write32(formatLength
.value());
1000 if (NS_WARN_IF(NS_FAILED(rv
))) {
1001 totalCustomLength
= 0;
1004 MOZ_ASSERT(formatLength
.isValid() &&
1005 formatLength
.value() ==
1006 type
.Length() * sizeof(nsString::char_type
),
1007 "Why is formatLength off?");
1008 rv
= stream
->WriteBytes(
1009 AsBytes(Span(type
.BeginReading(), type
.Length())));
1010 if (NS_WARN_IF(NS_FAILED(rv
))) {
1011 totalCustomLength
= 0;
1014 rv
= stream
->Write32(lengthInBytes
);
1015 if (NS_WARN_IF(NS_FAILED(rv
))) {
1016 totalCustomLength
= 0;
1019 // XXXbz it's not obvious to me that lengthInBytes is the actual
1020 // length of "data" if the variant contained an nsISupportsString
1021 // as VTYPE_INTERFACE, say. We used lengthInBytes above for
1022 // sizing, so just keep doing that.
1023 rv
= stream
->WriteBytes(
1024 Span(reinterpret_cast<const uint8_t*>(data
.BeginReading()),
1026 if (NS_WARN_IF(NS_FAILED(rv
))) {
1027 totalCustomLength
= 0;
1031 totalCustomLength
= newSize
.value();
1035 } else if (isCustomFormat
&& stream
) {
1036 // This is the second pass of the loop (handlingCustomFormats is false).
1037 // When encountering the first custom format, append all of the stream
1038 // at this position. If totalCustomLength is 0 indicating a write error
1039 // occurred, or no data has been added to it, don't output anything,
1040 if (totalCustomLength
> baseLength
) {
1041 // Write out an end of data terminator.
1042 nsresult rv
= stream
->Write32(eCustomClipboardTypeId_None
);
1043 if (NS_SUCCEEDED(rv
)) {
1044 nsCOMPtr
<nsIInputStream
> inputStream
;
1045 storageStream
->NewInputStream(0, getter_AddRefs(inputStream
));
1047 RefPtr
<nsStringBuffer
> stringBuffer
=
1048 nsStringBuffer::Alloc(totalCustomLength
);
1050 // Subtract off the null terminator when reading.
1051 totalCustomLength
--;
1053 // Read the data from the stream and add a null-terminator as
1054 // ToString needs it.
1055 uint32_t amountRead
;
1056 rv
= inputStream
->Read(static_cast<char*>(stringBuffer
->Data()),
1057 totalCustomLength
, &amountRead
);
1058 if (NS_SUCCEEDED(rv
)) {
1059 static_cast<char*>(stringBuffer
->Data())[amountRead
] = 0;
1062 stringBuffer
->ToString(totalCustomLength
, str
);
1063 nsCOMPtr
<nsISupportsCString
> strSupports(
1064 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID
));
1065 strSupports
->SetData(str
);
1068 transferable
->SetTransferData(kCustomTypesMime
, strSupports
);
1069 if (NS_FAILED(rv
)) {
1078 // Clear the stream so it doesn't get used again.
1081 // This is the second pass of the loop and a known type is encountered.
1083 if (!ConvertFromVariant(variant
, getter_AddRefs(convertedData
),
1088 NS_ConvertUTF16toUTF8
format(type
);
1090 // If a converter is set for a format, set the converter for the
1091 // transferable and don't add the item
1092 nsCOMPtr
<nsIFormatConverter
> converter
=
1093 do_QueryInterface(convertedData
);
1095 transferable
->AddDataFlavor(format
.get());
1096 transferable
->SetConverter(converter
);
1101 transferable
->SetTransferData(format
.get(), convertedData
);
1102 if (NS_FAILED(rv
)) {
1110 handlingCustomFormats
= !handlingCustomFormats
;
1111 } while (!handlingCustomFormats
);
1113 // only return the transferable if data was successfully added to it
1115 return transferable
.forget();
1121 bool DataTransfer::ConvertFromVariant(nsIVariant
* aVariant
,
1122 nsISupports
** aSupports
,
1123 uint32_t* aLength
) const {
1124 *aSupports
= nullptr;
1127 uint16_t type
= aVariant
->GetDataType();
1128 if (type
== nsIDataType::VTYPE_INTERFACE
||
1129 type
== nsIDataType::VTYPE_INTERFACE_IS
) {
1130 nsCOMPtr
<nsISupports
> data
;
1131 if (NS_FAILED(aVariant
->GetAsISupports(getter_AddRefs(data
)))) {
1135 // For flavour data providers, use 0 as the length.
1136 if (nsCOMPtr
<nsIFlavorDataProvider
> fdp
= do_QueryInterface(data
)) {
1137 fdp
.forget(aSupports
);
1142 // Only use the underlying BlobImpl for transferables.
1143 if (RefPtr
<Blob
> blob
= do_QueryObject(data
)) {
1144 RefPtr
<BlobImpl
> blobImpl
= blob
->Impl();
1145 blobImpl
.forget(aSupports
);
1147 data
.forget(aSupports
);
1150 *aLength
= sizeof(nsISupports
*);
1155 nsresult rv
= aVariant
->GetAsAString(str
);
1156 if (NS_FAILED(rv
)) {
1160 nsCOMPtr
<nsISupportsString
> strSupports(
1161 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
));
1166 strSupports
->SetData(str
);
1168 strSupports
.forget(aSupports
);
1170 // each character is two bytes
1171 *aLength
= str
.Length() * 2;
1176 void DataTransfer::Disconnect() {
1177 SetMode(Mode::Protected
);
1178 if (StaticPrefs::dom_events_dataTransfer_protected_enabled()) {
1183 void DataTransfer::ClearAll() { mItems
->ClearAllItems(); }
1185 uint32_t DataTransfer::MozItemCount() const { return mItems
->MozItemCount(); }
1187 nsresult
DataTransfer::SetDataWithPrincipal(const nsAString
& aFormat
,
1188 nsIVariant
* aData
, uint32_t aIndex
,
1189 nsIPrincipal
* aPrincipal
,
1191 nsAutoString format
;
1192 GetRealFormat(aFormat
, format
);
1195 RefPtr
<DataTransferItem
> item
=
1196 mItems
->SetDataWithPrincipal(format
, aData
, aIndex
, aPrincipal
,
1197 /* aInsertOnly = */ false, aHidden
, rv
);
1198 return rv
.StealNSResult();
1201 void DataTransfer::SetDataWithPrincipalFromOtherProcess(
1202 const nsAString
& aFormat
, nsIVariant
* aData
, uint32_t aIndex
,
1203 nsIPrincipal
* aPrincipal
, bool aHidden
) {
1204 if (aFormat
.EqualsLiteral(kCustomTypesMime
)) {
1205 FillInExternalCustomTypes(aData
, aIndex
, aPrincipal
);
1207 nsAutoString format
;
1208 GetRealFormat(aFormat
, format
);
1211 RefPtr
<DataTransferItem
> item
=
1212 mItems
->SetDataWithPrincipal(format
, aData
, aIndex
, aPrincipal
,
1213 /* aInsertOnly = */ false, aHidden
, rv
);
1214 if (NS_WARN_IF(rv
.Failed())) {
1215 rv
.SuppressException();
1220 void DataTransfer::GetRealFormat(const nsAString
& aInFormat
,
1221 nsAString
& aOutFormat
) const {
1222 // For compatibility, treat text/unicode as equivalent to text/plain
1223 nsAutoString lowercaseFormat
;
1224 nsContentUtils::ASCIIToLower(aInFormat
, lowercaseFormat
);
1225 if (lowercaseFormat
.EqualsLiteral("text") ||
1226 lowercaseFormat
.EqualsLiteral("text/unicode")) {
1227 aOutFormat
.AssignLiteral("text/plain");
1231 if (lowercaseFormat
.EqualsLiteral("url")) {
1232 aOutFormat
.AssignLiteral("text/uri-list");
1236 aOutFormat
.Assign(lowercaseFormat
);
1239 nsresult
DataTransfer::CacheExternalData(const char* aFormat
, uint32_t aIndex
,
1240 nsIPrincipal
* aPrincipal
,
1243 RefPtr
<DataTransferItem
> item
;
1245 if (strcmp(aFormat
, kTextMime
) == 0) {
1246 item
= mItems
->SetDataWithPrincipal(u
"text/plain"_ns
, nullptr, aIndex
,
1247 aPrincipal
, false, aHidden
, rv
);
1248 if (NS_WARN_IF(rv
.Failed())) {
1249 return rv
.StealNSResult();
1254 if (strcmp(aFormat
, kURLDataMime
) == 0) {
1255 item
= mItems
->SetDataWithPrincipal(u
"text/uri-list"_ns
, nullptr, aIndex
,
1256 aPrincipal
, false, aHidden
, rv
);
1257 if (NS_WARN_IF(rv
.Failed())) {
1258 return rv
.StealNSResult();
1263 nsAutoString format
;
1264 GetRealFormat(NS_ConvertUTF8toUTF16(aFormat
), format
);
1265 item
= mItems
->SetDataWithPrincipal(format
, nullptr, aIndex
, aPrincipal
,
1266 false, aHidden
, rv
);
1267 if (NS_WARN_IF(rv
.Failed())) {
1268 return rv
.StealNSResult();
1273 void DataTransfer::CacheExternalDragFormats() {
1274 // Called during the constructor to cache the formats available from an
1275 // external drag. The data associated with each format will be set to null.
1276 // This data will instead only be retrieved in FillInExternalDragData when
1277 // asked for, as it may be time consuming for the source application to
1280 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
1285 // make sure that the system principal is used for external drags
1286 nsIScriptSecurityManager
* ssm
= nsContentUtils::GetSecurityManager();
1287 nsCOMPtr
<nsIPrincipal
> sysPrincipal
;
1288 ssm
->GetSystemPrincipal(getter_AddRefs(sysPrincipal
));
1290 // there isn't a way to get a list of the formats that might be available on
1291 // all platforms, so just check for the types that can actually be imported
1292 // XXXndeakin there are some other formats but those are platform specific.
1293 // NOTE: kFileMime must have index 0
1294 // TODO: should this be `kNonPlainTextExternalFormats` instead?
1295 static const char* formats
[] = {kFileMime
, kHTMLMime
, kURLMime
,
1296 kURLDataMime
, kTextMime
, kPNGImageMime
};
1299 dragSession
->GetNumDropItems(&count
);
1300 for (uint32_t c
= 0; c
< count
; c
++) {
1301 bool hasFileData
= false;
1302 dragSession
->IsDataFlavorSupported(kFileMime
, &hasFileData
);
1304 // First, check for the special format that holds custom types.
1306 dragSession
->IsDataFlavorSupported(kCustomTypesMime
, &supported
);
1308 FillInExternalCustomTypes(c
, sysPrincipal
);
1311 for (uint32_t f
= 0; f
< ArrayLength(formats
); f
++) {
1312 // IsDataFlavorSupported doesn't take an index as an argument and just
1313 // checks if any of the items support a particular flavor, even though
1314 // the GetData method does take an index. Here, we just assume that
1315 // every item being dragged has the same set of flavors.
1317 dragSession
->IsDataFlavorSupported(formats
[f
], &supported
);
1318 // if the format is supported, add an item to the array with null as
1319 // the data. When retrieved, GetRealData will read the data.
1321 CacheExternalData(formats
[f
], c
, sysPrincipal
,
1322 /* hidden = */ f
&& hasFileData
);
1328 void DataTransfer::CacheExternalClipboardFormats(bool aPlainTextOnly
) {
1329 // Called during the constructor for paste events to cache the formats
1330 // available on the clipboard. As with CacheExternalDragFormats, the
1331 // data will only be retrieved when needed.
1332 NS_ASSERTION(mEventMessage
== ePaste
,
1333 "caching clipboard data for invalid event");
1335 nsCOMPtr
<nsIPrincipal
> sysPrincipal
= nsContentUtils::GetSystemPrincipal();
1337 nsTArray
<nsCString
> typesArray
;
1339 if (XRE_IsContentProcess()) {
1340 ContentChild::GetSingleton()->SendGetExternalClipboardFormats(
1341 mClipboardType
, aPlainTextOnly
, &typesArray
);
1343 GetExternalClipboardFormats(mClipboardType
, aPlainTextOnly
, &typesArray
);
1346 if (aPlainTextOnly
) {
1347 // The only thing that will be in types is kTextMime
1348 MOZ_ASSERT(typesArray
.IsEmpty() || typesArray
.Length() == 1);
1349 if (typesArray
.Length() == 1) {
1350 CacheExternalData(kTextMime
, 0, sysPrincipal
, false);
1355 CacheExternalData(typesArray
, sysPrincipal
);
1358 void DataTransfer::CacheTransferableFormats() {
1359 nsCOMPtr
<nsIPrincipal
> sysPrincipal
= nsContentUtils::GetSystemPrincipal();
1361 AutoTArray
<nsCString
, 10> typesArray
;
1362 GetExternalTransferableFormats(mTransferable
, false, &typesArray
);
1364 CacheExternalData(typesArray
, sysPrincipal
);
1367 void DataTransfer::CacheExternalData(const nsTArray
<nsCString
>& aTypes
,
1368 nsIPrincipal
* aPrincipal
) {
1369 bool hasFileData
= false;
1370 for (const nsCString
& type
: aTypes
) {
1371 if (type
.EqualsLiteral(kCustomTypesMime
)) {
1372 FillInExternalCustomTypes(0, aPrincipal
);
1373 } else if (type
.EqualsLiteral(kFileMime
) && XRE_IsContentProcess() &&
1374 !StaticPrefs::dom_events_dataTransfer_mozFile_enabled()) {
1375 // We will be ignoring any application/x-moz-file files found in the paste
1376 // datatransfer within e10s, as they will fail top be sent over IPC.
1377 // Because of that, we will unset hasFileData, whether or not it would
1378 // have been set. (bug 1308007)
1379 hasFileData
= false;
1382 // We expect that if kFileMime is supported, then it will be the either at
1383 // index 0 or at index 1 in the aTypes returned by
1384 // GetExternalClipboardFormats
1385 if (type
.EqualsLiteral(kFileMime
)) {
1389 // If we aren't the file data, and we have file data, we want to be hidden
1391 type
.get(), 0, aPrincipal
,
1392 /* hidden = */ !type
.EqualsLiteral(kFileMime
) && hasFileData
);
1397 void DataTransfer::FillAllExternalData() {
1399 for (uint32_t i
= 0; i
< MozItemCount(); ++i
) {
1400 const nsTArray
<RefPtr
<DataTransferItem
>>& items
= *mItems
->MozItemsAt(i
);
1401 for (uint32_t j
= 0; j
< items
.Length(); ++j
) {
1402 MOZ_ASSERT(items
[j
]->Index() == i
);
1404 items
[j
]->FillInExternalData();
1410 void DataTransfer::FillInExternalCustomTypes(uint32_t aIndex
,
1411 nsIPrincipal
* aPrincipal
) {
1412 RefPtr
<DataTransferItem
> item
= new DataTransferItem(
1413 this, NS_LITERAL_STRING_FROM_CSTRING(kCustomTypesMime
),
1414 DataTransferItem::KIND_STRING
);
1415 item
->SetIndex(aIndex
);
1417 nsCOMPtr
<nsIVariant
> variant
= item
->DataNoSecurityCheck();
1422 FillInExternalCustomTypes(variant
, aIndex
, aPrincipal
);
1425 void DataTransfer::FillInExternalCustomTypes(nsIVariant
* aData
, uint32_t aIndex
,
1426 nsIPrincipal
* aPrincipal
) {
1429 nsresult rv
= aData
->GetAsStringWithSize(&len
, &chrs
);
1430 if (NS_FAILED(rv
)) {
1434 CheckedInt
<int32_t> checkedLen(len
);
1435 if (!checkedLen
.isValid()) {
1439 nsCOMPtr
<nsIInputStream
> stringStream
;
1440 NS_NewByteInputStream(getter_AddRefs(stringStream
),
1441 Span(chrs
, checkedLen
.value()), NS_ASSIGNMENT_ADOPT
);
1443 nsCOMPtr
<nsIObjectInputStream
> stream
= NS_NewObjectInputStream(stringStream
);
1447 rv
= stream
->Read32(&type
);
1448 NS_ENSURE_SUCCESS_VOID(rv
);
1449 if (type
== eCustomClipboardTypeId_String
) {
1450 uint32_t formatLength
;
1451 rv
= stream
->Read32(&formatLength
);
1452 NS_ENSURE_SUCCESS_VOID(rv
);
1454 rv
= stream
->ReadBytes(formatLength
, &formatBytes
);
1455 NS_ENSURE_SUCCESS_VOID(rv
);
1456 nsAutoString format
;
1457 format
.Adopt(reinterpret_cast<char16_t
*>(formatBytes
),
1458 formatLength
/ sizeof(char16_t
));
1460 uint32_t dataLength
;
1461 rv
= stream
->Read32(&dataLength
);
1462 NS_ENSURE_SUCCESS_VOID(rv
);
1464 rv
= stream
->ReadBytes(dataLength
, &dataBytes
);
1465 NS_ENSURE_SUCCESS_VOID(rv
);
1467 data
.Adopt(reinterpret_cast<char16_t
*>(dataBytes
),
1468 dataLength
/ sizeof(char16_t
));
1470 RefPtr
<nsVariantCC
> variant
= new nsVariantCC();
1471 rv
= variant
->SetAsAString(data
);
1472 NS_ENSURE_SUCCESS_VOID(rv
);
1474 SetDataWithPrincipal(format
, variant
, aIndex
, aPrincipal
);
1476 } while (type
!= eCustomClipboardTypeId_None
);
1479 void DataTransfer::SetMode(DataTransfer::Mode aMode
) {
1480 if (!StaticPrefs::dom_events_dataTransfer_protected_enabled() &&
1481 aMode
== Mode::Protected
) {
1482 mMode
= Mode::ReadOnly
;
1488 } // namespace mozilla::dom