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 #ifndef mozilla_dom_DataTransfer_h
8 #define mozilla_dom_DataTransfer_h
12 #include "nsIVariant.h"
13 #include "nsIPrincipal.h"
14 #include "nsIDragService.h"
15 #include "nsITransferable.h"
16 #include "nsCycleCollectionParticipant.h"
18 #include "mozilla/ArrayUtils.h"
19 #include "mozilla/Assertions.h"
20 #include "mozilla/Attributes.h"
21 #include "mozilla/EventForwards.h"
22 #include "mozilla/dom/BindingDeclarations.h"
23 #include "mozilla/dom/DataTransferItemList.h"
24 #include "mozilla/dom/File.h"
27 class nsITransferable
;
32 class EventStateManager
;
36 class DataTransferItem
;
37 class DataTransferItemList
;
45 #define NS_DATATRANSFER_IID \
47 0x6c5f90d1, 0xa886, 0x42c8, { \
48 0x85, 0x06, 0x10, 0xbe, 0x5c, 0x0d, 0xc6, 0x77 \
53 * See <https://html.spec.whatwg.org/multipage/dnd.html#datatransfer>.
55 class DataTransfer final
: public nsISupports
, public nsWrapperCache
{
57 NS_DECLARE_STATIC_IID_ACCESSOR(NS_DATATRANSFER_IID
)
59 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
61 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DataTransfer
)
63 friend class mozilla::EventStateManager
;
65 /// An enum which represents which "Drag Data Store Mode" the DataTransfer is
66 /// in according to the spec.
67 enum class Mode
: uint8_t {
74 // hide the default constructor
77 // this constructor is used only by the Clone method to copy the fields as
78 // needed to a new data transfer.
79 // NOTE: Do not call this method directly.
80 DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
81 const uint32_t aEffectAllowed
, bool aCursorState
,
82 bool aIsExternal
, bool aUserCancelled
,
83 bool aIsCrossDomainSubFrameDrop
, int32_t aClipboardType
,
84 DataTransferItemList
* aItems
, Element
* aDragImage
,
85 uint32_t aDragImageX
, uint32_t aDragImageY
);
89 static const char sEffects
[8][9];
92 // Constructor for DataTransfer.
94 // aIsExternal must only be true when used to create a dataTransfer for a
95 // paste, a drag or an input that was started without using a data transfer.
96 // The case of a drag will occur when an external drag occurs, that is, a
97 // drag where the source is another application, or a drag is started by
98 // calling the drag service directly. For clipboard operations,
99 // aClipboardType indicates which clipboard to use, from nsIClipboard, or -1
100 // for non-clipboard operations, or if access to the system clipboard should
102 DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
103 bool aIsExternal
, int32_t aClipboardType
);
104 DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
105 nsITransferable
* aTransferable
);
106 DataTransfer(nsISupports
* aParent
, EventMessage aEventMessage
,
107 const nsAString
& aString
);
109 virtual JSObject
* WrapObject(JSContext
* aCx
,
110 JS::Handle
<JSObject
*> aGivenProto
) override
;
112 nsISupports
* GetParentObject() const { return mParent
; }
114 void SetParentObject(nsISupports
* aNewParent
) {
115 MOZ_ASSERT(aNewParent
);
116 // Setting the parent after we've been wrapped is pointless, so
117 // make sure we aren't wrapped yet.
118 MOZ_ASSERT(!GetWrapperPreserveColor());
119 mParent
= aNewParent
;
122 static already_AddRefed
<DataTransfer
> Constructor(
123 const GlobalObject
& aGlobal
);
126 * The actual effect that will be used, and should always be one of the
127 * possible values of effectAllowed.
129 * For dragstart, drag and dragleave events, the dropEffect is initialized
130 * to none. Any value assigned to the dropEffect will be set, but the value
131 * isn't used for anything.
133 * For the dragenter and dragover events, the dropEffect will be initialized
134 * based on what action the user is requesting. How this is determined is
135 * platform specific, but typically the user can press modifier keys to
136 * adjust which action is desired. Within an event handler for the dragenter
137 * and dragover events, the dropEffect should be modified if the action the
138 * user is requesting is not the one that is desired.
140 * For the drop and dragend events, the dropEffect will be initialized to
141 * the action that was desired, which will be the value that the dropEffect
142 * had after the last dragenter or dragover event.
145 * copy - a copy of the source item is made at the new location
146 * move - an item is moved to a new location
147 * link - a link is established to the source at the new location
148 * none - the item may not be dropped
150 * Assigning any other value has no effect and retains the old value.
152 void GetDropEffect(nsAString
& aDropEffect
) {
153 aDropEffect
.AssignASCII(sEffects
[mDropEffect
]);
155 void SetDropEffect(const nsAString
& aDropEffect
);
158 * Specifies the effects that are allowed for this drag. You may set this in
159 * the dragstart event to set the desired effects for the source, and within
160 * the dragenter and dragover events to set the desired effects for the
161 * target. The value is not used for other events.
164 * copy - a copy of the source item is made at the new location
165 * move - an item is moved to a new location
166 * link - a link is established to the source at the new location
167 * copyLink, copyMove, linkMove, all - combinations of the above
168 * none - the item may not be dropped
169 * uninitialized - the default value when the effect has not been set,
172 * Assigning any other value has no effect and retains the old value.
174 void GetEffectAllowed(nsAString
& aEffectAllowed
) {
175 if (mEffectAllowed
== nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
) {
176 aEffectAllowed
.AssignLiteral("uninitialized");
178 aEffectAllowed
.AssignASCII(sEffects
[mEffectAllowed
]);
181 void SetEffectAllowed(const nsAString
& aEffectAllowed
);
184 * Set the image to be used for dragging if a custom one is desired. Most of
185 * the time, this would not be set, as a default image is created from the
186 * node that was dragged.
188 * If the node is an HTML img element, an HTML canvas element or a XUL image
189 * element, the image data is used. Otherwise, image should be a visible
190 * node and the drag image will be created from this. If image is null, any
191 * custom drag image is cleared and the default is used instead.
193 * The coordinates specify the offset into the image where the mouse cursor
194 * should be. To center the image for instance, use values that are half the
197 * @param image a node to use
198 * @param x the horizontal offset
199 * @param y the vertical offset
201 void SetDragImage(Element
& aElement
, int32_t aX
, int32_t aY
);
202 void UpdateDragImage(Element
& aElement
, int32_t aX
, int32_t aY
);
204 void GetTypes(nsTArray
<nsString
>& aTypes
, CallerType aCallerType
) const;
205 bool HasType(const nsAString
& aType
) const;
206 bool HasFile() const;
208 void GetData(const nsAString
& aFormat
, nsAString
& aData
,
209 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) const;
211 void SetData(const nsAString
& aFormat
, const nsAString
& aData
,
212 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
);
214 void ClearData(const mozilla::dom::Optional
<nsAString
>& aFormat
,
215 nsIPrincipal
& aSubjectPrincipal
, mozilla::ErrorResult
& aRv
);
218 * Holds a list of all the local files available on this data transfer.
219 * A dataTransfer containing no files will return an empty list, and an
220 * invalid index access on the resulting file list will return null.
222 already_AddRefed
<FileList
> GetFiles(nsIPrincipal
& aSubjectPrincipal
);
224 already_AddRefed
<Promise
> GetFilesAndDirectories(
225 nsIPrincipal
& aSubjectPrincipal
, mozilla::ErrorResult
& aRv
);
227 already_AddRefed
<Promise
> GetFiles(bool aRecursiveFlag
,
228 nsIPrincipal
& aSubjectPrincipal
,
231 void AddElement(Element
& aElement
, mozilla::ErrorResult
& aRv
);
233 uint32_t MozItemCount() const;
235 void GetMozCursor(nsAString
& aCursor
) {
237 aCursor
.AssignLiteral("default");
239 aCursor
.AssignLiteral("auto");
242 void SetMozCursor(const nsAString
& aCursor
);
244 already_AddRefed
<DOMStringList
> MozTypesAt(uint32_t aIndex
,
245 mozilla::ErrorResult
& aRv
) const;
247 void MozClearDataAt(const nsAString
& aFormat
, uint32_t aIndex
,
248 mozilla::ErrorResult
& aRv
);
250 void MozSetDataAt(JSContext
* aCx
, const nsAString
& aFormat
,
251 JS::Handle
<JS::Value
> aData
, uint32_t aIndex
,
252 mozilla::ErrorResult
& aRv
);
254 void MozGetDataAt(JSContext
* aCx
, const nsAString
& aFormat
, uint32_t aIndex
,
255 JS::MutableHandle
<JS::Value
> aRetval
,
256 mozilla::ErrorResult
& aRv
);
258 bool MozUserCancelled() const { return mUserCancelled
; }
260 already_AddRefed
<nsINode
> GetMozSourceNode();
263 * Integer version of dropEffect, set to one of the constants in
266 uint32_t DropEffectInt() const { return mDropEffect
; }
267 void SetDropEffectInt(uint32_t aDropEffectInt
) {
268 MOZ_RELEASE_ASSERT(aDropEffectInt
< ArrayLength(sEffects
),
269 "Bogus drop effect value");
270 mDropEffect
= aDropEffectInt
;
274 * Integer version of effectAllowed, set to one or a combination of the
275 * constants in nsIDragService.
277 uint32_t EffectAllowedInt() const { return mEffectAllowed
; }
279 void GetMozTriggeringPrincipalURISpec(nsAString
& aPrincipalURISpec
);
281 nsIContentSecurityPolicy
* GetMozCSP();
283 mozilla::dom::Element
* GetDragTarget() const { return mDragTarget
; }
285 nsresult
GetDataAtNoSecurityCheck(const nsAString
& aFormat
, uint32_t aIndex
,
286 nsIVariant
** aData
) const;
288 DataTransferItemList
* Items() const { return mItems
; }
290 // Returns the current "Drag Data Store Mode" of the DataTransfer. This
291 // determines what modifications may be performed on the DataTransfer, and
292 // what data may be read from it.
293 Mode
GetMode() const { return mMode
; }
294 void SetMode(Mode aMode
);
296 // Helper method. Is true if the DataTransfer's mode is ReadOnly or Protected,
297 // which means that the DataTransfer cannot be modified.
298 bool IsReadOnly() const { return mMode
!= Mode::ReadWrite
; }
299 // Helper method. Is true if the DataTransfer's mode is Protected, which means
300 // that DataTransfer type information may be read, but data may not be.
301 bool IsProtected() const { return mMode
== Mode::Protected
; }
303 nsITransferable
* GetTransferable() const { return mTransferable
; }
304 int32_t ClipboardType() const { return mClipboardType
; }
305 EventMessage
GetEventMessage() const { return mEventMessage
; }
306 bool IsCrossDomainSubFrameDrop() const { return mIsCrossDomainSubFrameDrop
; }
308 // converts the data into an array of nsITransferable objects to be used for
309 // drag and drop or clipboard operations.
310 already_AddRefed
<nsIArray
> GetTransferables(nsINode
* aDragTarget
);
312 already_AddRefed
<nsIArray
> GetTransferables(nsILoadContext
* aLoadContext
);
314 // converts the data for a single item at aIndex into an nsITransferable
316 already_AddRefed
<nsITransferable
> GetTransferable(
317 uint32_t aIndex
, nsILoadContext
* aLoadContext
);
319 // converts the data in the variant to an nsISupportString if possible or
320 // an nsISupports or null otherwise.
321 bool ConvertFromVariant(nsIVariant
* aVariant
, nsISupports
** aSupports
,
322 uint32_t* aLength
) const;
324 // Disconnects the DataTransfer from the Drag Data Store. If the
325 // dom.dataTransfer.disconnect pref is enabled, this will clear the
326 // DataTransfer and set it to the `Protected` state, otherwise this method is
330 // clears all of the data
333 // Similar to SetData except also specifies the principal to store.
334 // aData may be null when called from CacheExternalDragFormats or
335 // CacheExternalClipboardFormats.
336 nsresult
SetDataWithPrincipal(const nsAString
& aFormat
, nsIVariant
* aData
,
337 uint32_t aIndex
, nsIPrincipal
* aPrincipal
,
338 bool aHidden
= false);
340 // Variation of SetDataWithPrincipal with handles extracting
341 // kCustomTypesMime data into separate types.
343 // @param aHidden if true and `aFormat != kCustomTypesMime`, the data will be
344 // hidden from non-chrome code.
345 // TODO: unclear, whether `aHidden` should be considered for
347 void SetDataWithPrincipalFromOtherProcess(const nsAString
& aFormat
,
348 nsIVariant
* aData
, uint32_t aIndex
,
349 nsIPrincipal
* aPrincipal
,
352 // returns a weak reference to the drag image
353 Element
* GetDragImage(int32_t* aX
, int32_t* aY
) const {
359 // This method makes a copy of the DataTransfer object, with a few properties
360 // changed, and the mode updated to reflect the correct mode for the given
361 // event. This method is used during the drag operation to generate the
362 // DataTransfer objects for each event after `dragstart`. Event objects will
363 // lazily clone the DataTransfer stored in the DragSession (which is a clone
364 // of the DataTransfer used in the `dragstart` event) when requested.
365 nsresult
Clone(nsISupports
* aParent
, EventMessage aEventMessage
,
366 bool aUserCancelled
, bool aIsCrossDomainSubFrameDrop
,
367 DataTransfer
** aResult
);
369 // converts some formats used for compatibility in aInFormat into aOutFormat.
370 // Text and text/unicode become text/plain, and URL becomes text/uri-list
371 void GetRealFormat(const nsAString
& aInFormat
, nsAString
& aOutFormat
) const;
373 static bool PrincipalMaySetData(const nsAString
& aFormat
, nsIVariant
* aData
,
374 nsIPrincipal
* aPrincipal
);
376 // Notify the DataTransfer that the list returned from GetTypes may have
377 // changed. This can happen due to items we care about for purposes of
378 // GetTypes being added or removed or changing item kinds.
379 void TypesListMayHaveChanged();
381 // Testing method used to emulate internal DataTransfer management.
382 // NOTE: Please don't use this. See the comments in the webidl for more.
383 already_AddRefed
<DataTransfer
> MozCloneForEvent(const nsAString
& aEvent
,
386 // Retrieve a list of clipboard formats supported
388 // If kFileMime is supported, then it will be placed either at
389 // index 0 or at index 1 in aResult
390 static void GetExternalClipboardFormats(const int32_t& aWhichClipboard
,
391 const bool& aPlainTextOnly
,
392 nsTArray
<nsCString
>* aResult
);
394 // Retrieve a list of supporting formats in aTransferable.
396 // If kFileMime is supported, then it will be placed either at
397 // index 0 or at index 1 in aResult
398 static void GetExternalTransferableFormats(nsITransferable
* aTransferable
,
400 nsTArray
<nsCString
>* aResult
);
403 // caches text and uri-list data formats that exist in the drag service or
404 // clipboard for retrieval later.
405 nsresult
CacheExternalData(const char* aFormat
, uint32_t aIndex
,
406 nsIPrincipal
* aPrincipal
, bool aHidden
);
408 // caches the formats that exist in the drag service that were added by an
410 void CacheExternalDragFormats();
412 // caches the formats that exist in the clipboard
413 void CacheExternalClipboardFormats(bool aPlainTextOnly
);
415 // caches the formats that exist in mTransferable
416 void CacheTransferableFormats();
418 // caches the formats specified by aTypes.
419 void CacheExternalData(const nsTArray
<nsCString
>& aTypes
,
420 nsIPrincipal
* aPrincipal
);
422 FileList
* GetFilesInternal(ErrorResult
& aRv
, nsIPrincipal
* aSubjectPrincipal
);
423 nsresult
GetDataAtInternal(const nsAString
& aFormat
, uint32_t aIndex
,
424 nsIPrincipal
* aSubjectPrincipal
,
425 nsIVariant
** aData
) const;
427 nsresult
SetDataAtInternal(const nsAString
& aFormat
, nsIVariant
* aData
,
428 uint32_t aIndex
, nsIPrincipal
* aSubjectPrincipal
);
430 friend class ContentParent
;
431 friend class Clipboard
;
433 void FillAllExternalData();
435 void FillInExternalCustomTypes(uint32_t aIndex
, nsIPrincipal
* aPrincipal
);
437 void FillInExternalCustomTypes(nsIVariant
* aData
, uint32_t aIndex
,
438 nsIPrincipal
* aPrincipal
);
440 void MozClearDataAtHelper(const nsAString
& aFormat
, uint32_t aIndex
,
441 nsIPrincipal
& aSubjectPrincipal
,
442 mozilla::ErrorResult
& aRv
);
444 nsCOMPtr
<nsISupports
> mParent
;
446 // If DataTransfer is initialized with an instance of nsITransferable, it's
447 // grabbed with this member **until** the constructor fills all data of all
449 nsCOMPtr
<nsITransferable
> mTransferable
;
451 // the drop effect and effect allowed
452 uint32_t mDropEffect
;
453 uint32_t mEffectAllowed
;
455 // the event message this data transfer is for. This will correspond to an
456 // event->mMessage value.
457 EventMessage mEventMessage
;
459 // Indicates the behavior of the cursor during drag operations
462 // The current "Drag Data Store Mode" which the DataTransfer is in.
465 // true for drags started without a data transfer, for example, those from
466 // another application.
469 // true if the user cancelled the drag. Used only for the dragend event.
472 // true if this is a cross-domain drop from a subframe where access to the
473 // data should be prevented
474 bool mIsCrossDomainSubFrameDrop
;
476 // Indicates which clipboard type to use for clipboard operations. Ignored for
478 int32_t mClipboardType
;
480 // The items contained with the DataTransfer
481 RefPtr
<DataTransferItemList
> mItems
;
483 // the target of the drag. The drag and dragend events will fire at this.
484 nsCOMPtr
<mozilla::dom::Element
> mDragTarget
;
486 // the custom drag image and coordinates within the image. If mDragImage is
487 // null, the default image is created from the drag target.
488 nsCOMPtr
<mozilla::dom::Element
> mDragImage
;
489 uint32_t mDragImageX
;
490 uint32_t mDragImageY
;
493 NS_DEFINE_STATIC_IID_ACCESSOR(DataTransfer
, NS_DATATRANSFER_IID
)
496 } // namespace mozilla
498 #endif /* mozilla_dom_DataTransfer_h */