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 CallerType aCallerType
,
246 mozilla::ErrorResult
& aRv
) const;
248 void MozClearDataAt(const nsAString
& aFormat
, uint32_t aIndex
,
249 nsIPrincipal
& aSubjectPrincipal
,
250 mozilla::ErrorResult
& aRv
);
252 void MozSetDataAt(JSContext
* aCx
, const nsAString
& aFormat
,
253 JS::Handle
<JS::Value
> aData
, uint32_t aIndex
,
254 nsIPrincipal
& aSubjectPrincipal
, mozilla::ErrorResult
& aRv
);
256 void MozGetDataAt(JSContext
* aCx
, const nsAString
& aFormat
, uint32_t aIndex
,
257 JS::MutableHandle
<JS::Value
> aRetval
,
258 nsIPrincipal
& aSubjectPrincipal
, mozilla::ErrorResult
& aRv
);
260 bool MozUserCancelled() const { return mUserCancelled
; }
262 already_AddRefed
<nsINode
> GetMozSourceNode();
265 * Integer version of dropEffect, set to one of the constants in
268 uint32_t DropEffectInt() const { return mDropEffect
; }
269 void SetDropEffectInt(uint32_t aDropEffectInt
) {
270 MOZ_RELEASE_ASSERT(aDropEffectInt
< ArrayLength(sEffects
),
271 "Bogus drop effect value");
272 mDropEffect
= aDropEffectInt
;
276 * Integer version of effectAllowed, set to one or a combination of the
277 * constants in nsIDragService.
279 uint32_t EffectAllowedInt() const { return mEffectAllowed
; }
281 void GetMozTriggeringPrincipalURISpec(nsAString
& aPrincipalURISpec
);
283 nsIContentSecurityPolicy
* GetMozCSP();
285 mozilla::dom::Element
* GetDragTarget() const { return mDragTarget
; }
287 nsresult
GetDataAtNoSecurityCheck(const nsAString
& aFormat
, uint32_t aIndex
,
288 nsIVariant
** aData
) const;
290 DataTransferItemList
* Items() const { return mItems
; }
292 // Returns the current "Drag Data Store Mode" of the DataTransfer. This
293 // determines what modifications may be performed on the DataTransfer, and
294 // what data may be read from it.
295 Mode
GetMode() const { return mMode
; }
296 void SetMode(Mode aMode
);
298 // Helper method. Is true if the DataTransfer's mode is ReadOnly or Protected,
299 // which means that the DataTransfer cannot be modified.
300 bool IsReadOnly() const { return mMode
!= Mode::ReadWrite
; }
301 // Helper method. Is true if the DataTransfer's mode is Protected, which means
302 // that DataTransfer type information may be read, but data may not be.
303 bool IsProtected() const { return mMode
== Mode::Protected
; }
305 nsITransferable
* GetTransferable() const { return mTransferable
; }
306 int32_t ClipboardType() const { return mClipboardType
; }
307 EventMessage
GetEventMessage() const { return mEventMessage
; }
308 bool IsCrossDomainSubFrameDrop() const { return mIsCrossDomainSubFrameDrop
; }
310 // converts the data into an array of nsITransferable objects to be used for
311 // drag and drop or clipboard operations.
312 already_AddRefed
<nsIArray
> GetTransferables(nsINode
* aDragTarget
);
314 already_AddRefed
<nsIArray
> GetTransferables(nsILoadContext
* aLoadContext
);
316 // converts the data for a single item at aIndex into an nsITransferable
318 already_AddRefed
<nsITransferable
> GetTransferable(
319 uint32_t aIndex
, nsILoadContext
* aLoadContext
);
321 // converts the data in the variant to an nsISupportString if possible or
322 // an nsISupports or null otherwise.
323 bool ConvertFromVariant(nsIVariant
* aVariant
, nsISupports
** aSupports
,
324 uint32_t* aLength
) const;
326 // Disconnects the DataTransfer from the Drag Data Store. If the
327 // dom.dataTransfer.disconnect pref is enabled, this will clear the
328 // DataTransfer and set it to the `Protected` state, otherwise this method is
332 // clears all of the data
335 // Similar to SetData except also specifies the principal to store.
336 // aData may be null when called from CacheExternalDragFormats or
337 // CacheExternalClipboardFormats.
338 nsresult
SetDataWithPrincipal(const nsAString
& aFormat
, nsIVariant
* aData
,
339 uint32_t aIndex
, nsIPrincipal
* aPrincipal
,
340 bool aHidden
= false);
342 // Variation of SetDataWithPrincipal with handles extracting
343 // kCustomTypesMime data into separate types.
344 void SetDataWithPrincipalFromOtherProcess(const nsAString
& aFormat
,
345 nsIVariant
* aData
, uint32_t aIndex
,
346 nsIPrincipal
* aPrincipal
,
349 // returns a weak reference to the drag image
350 Element
* GetDragImage(int32_t* aX
, int32_t* aY
) const {
356 // This method makes a copy of the DataTransfer object, with a few properties
357 // changed, and the mode updated to reflect the correct mode for the given
358 // event. This method is used during the drag operation to generate the
359 // DataTransfer objects for each event after `dragstart`. Event objects will
360 // lazily clone the DataTransfer stored in the DragSession (which is a clone
361 // of the DataTransfer used in the `dragstart` event) when requested.
362 nsresult
Clone(nsISupports
* aParent
, EventMessage aEventMessage
,
363 bool aUserCancelled
, bool aIsCrossDomainSubFrameDrop
,
364 DataTransfer
** aResult
);
366 // converts some formats used for compatibility in aInFormat into aOutFormat.
367 // Text and text/unicode become text/plain, and URL becomes text/uri-list
368 void GetRealFormat(const nsAString
& aInFormat
, nsAString
& aOutFormat
) const;
370 static bool PrincipalMaySetData(const nsAString
& aFormat
, nsIVariant
* aData
,
371 nsIPrincipal
* aPrincipal
);
373 // Notify the DataTransfer that the list returned from GetTypes may have
374 // changed. This can happen due to items we care about for purposes of
375 // GetTypes being added or removed or changing item kinds.
376 void TypesListMayHaveChanged();
378 // Testing method used to emulate internal DataTransfer management.
379 // NOTE: Please don't use this. See the comments in the webidl for more.
380 already_AddRefed
<DataTransfer
> MozCloneForEvent(const nsAString
& aEvent
,
383 // Retrieve a list of clipboard formats supported
385 // If kFileMime is supported, then it will be placed either at
386 // index 0 or at index 1 in aResult
387 static void GetExternalClipboardFormats(const int32_t& aWhichClipboard
,
388 const bool& aPlainTextOnly
,
389 nsTArray
<nsCString
>* aResult
);
391 // Retrieve a list of supporting formats in aTransferable.
393 // If kFileMime is supported, then it will be placed either at
394 // index 0 or at index 1 in aResult
395 static void GetExternalTransferableFormats(nsITransferable
* aTransferable
,
397 nsTArray
<nsCString
>* aResult
);
400 // caches text and uri-list data formats that exist in the drag service or
401 // clipboard for retrieval later.
402 nsresult
CacheExternalData(const char* aFormat
, uint32_t aIndex
,
403 nsIPrincipal
* aPrincipal
, bool aHidden
);
405 // caches the formats that exist in the drag service that were added by an
407 void CacheExternalDragFormats();
409 // caches the formats that exist in the clipboard
410 void CacheExternalClipboardFormats(bool aPlainTextOnly
);
412 // caches the formats that exist in mTransferable
413 void CacheTransferableFormats();
415 // caches the formats specified by aTypes.
416 void CacheExternalData(const nsTArray
<nsCString
>& aTypes
,
417 nsIPrincipal
* aPrincipal
);
419 FileList
* GetFilesInternal(ErrorResult
& aRv
, nsIPrincipal
* aSubjectPrincipal
);
420 nsresult
GetDataAtInternal(const nsAString
& aFormat
, uint32_t aIndex
,
421 nsIPrincipal
* aSubjectPrincipal
,
422 nsIVariant
** aData
) const;
424 nsresult
SetDataAtInternal(const nsAString
& aFormat
, nsIVariant
* aData
,
425 uint32_t aIndex
, nsIPrincipal
* aSubjectPrincipal
);
427 friend class ContentParent
;
428 friend class Clipboard
;
430 void FillAllExternalData();
432 void FillInExternalCustomTypes(uint32_t aIndex
, nsIPrincipal
* aPrincipal
);
434 void FillInExternalCustomTypes(nsIVariant
* aData
, uint32_t aIndex
,
435 nsIPrincipal
* aPrincipal
);
437 void MozClearDataAtHelper(const nsAString
& aFormat
, uint32_t aIndex
,
438 nsIPrincipal
& aSubjectPrincipal
,
439 mozilla::ErrorResult
& aRv
);
441 nsCOMPtr
<nsISupports
> mParent
;
443 // If DataTransfer is initialized with an instance of nsITransferable, it's
444 // grabbed with this member **until** the constructor fills all data of all
446 nsCOMPtr
<nsITransferable
> mTransferable
;
448 // the drop effect and effect allowed
449 uint32_t mDropEffect
;
450 uint32_t mEffectAllowed
;
452 // the event message this data transfer is for. This will correspond to an
453 // event->mMessage value.
454 EventMessage mEventMessage
;
456 // Indicates the behavior of the cursor during drag operations
459 // The current "Drag Data Store Mode" which the DataTransfer is in.
462 // true for drags started without a data transfer, for example, those from
463 // another application.
466 // true if the user cancelled the drag. Used only for the dragend event.
469 // true if this is a cross-domain drop from a subframe where access to the
470 // data should be prevented
471 bool mIsCrossDomainSubFrameDrop
;
473 // Indicates which clipboard type to use for clipboard operations. Ignored for
475 int32_t mClipboardType
;
477 // The items contained with the DataTransfer
478 RefPtr
<DataTransferItemList
> mItems
;
480 // the target of the drag. The drag and dragend events will fire at this.
481 nsCOMPtr
<mozilla::dom::Element
> mDragTarget
;
483 // the custom drag image and coordinates within the image. If mDragImage is
484 // null, the default image is created from the drag target.
485 nsCOMPtr
<mozilla::dom::Element
> mDragImage
;
486 uint32_t mDragImageX
;
487 uint32_t mDragImageY
;
490 NS_DEFINE_STATIC_IID_ACCESSOR(DataTransfer
, NS_DATATRANSFER_IID
)
493 } // namespace mozilla
495 #endif /* mozilla_dom_DataTransfer_h */