Bug 1756164: part 1) Document "hidden" `DataTransferItem`s. r=mccr8
[gecko.git] / dom / events / DataTransfer.h
blob43605a40498a6d29e6672d68df9654ffb00ce9cf
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
10 #include "nsString.h"
11 #include "nsTArray.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"
26 class nsINode;
27 class nsITransferable;
28 class nsILoadContext;
30 namespace mozilla {
32 class EventStateManager;
34 namespace dom {
36 class DataTransferItem;
37 class DataTransferItemList;
38 class DOMStringList;
39 class Element;
40 class FileList;
41 class Promise;
42 template <typename T>
43 class Optional;
45 #define NS_DATATRANSFER_IID \
46 { \
47 0x6c5f90d1, 0xa886, 0x42c8, { \
48 0x85, 0x06, 0x10, 0xbe, 0x5c, 0x0d, 0xc6, 0x77 \
49 } \
52 /**
53 * See <https://html.spec.whatwg.org/multipage/dnd.html#datatransfer>.
55 class DataTransfer final : public nsISupports, public nsWrapperCache {
56 public:
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 {
68 ReadWrite,
69 ReadOnly,
70 Protected,
73 protected:
74 // hide the default constructor
75 DataTransfer();
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);
87 ~DataTransfer();
89 static const char sEffects[8][9];
91 public:
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
101 // not be allowed.
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.
144 * Possible values:
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.
163 * Possible values:
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,
170 * equivalent to all.
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");
177 } else {
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
195 * width and height.
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,
229 ErrorResult& aRv);
231 void AddElement(Element& aElement, mozilla::ErrorResult& aRv);
233 uint32_t MozItemCount() const;
235 void GetMozCursor(nsAString& aCursor) {
236 if (mCursorState) {
237 aCursor.AssignLiteral("default");
238 } else {
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
264 * nsIDragService.
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
315 // object.
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
327 // a no-op.
328 void Disconnect();
330 // clears all of the data
331 void ClearAll();
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
346 // the custom types.
347 void SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
348 nsIVariant* aData, uint32_t aIndex,
349 nsIPrincipal* aPrincipal,
350 bool aHidden);
352 // returns a weak reference to the drag image
353 Element* GetDragImage(int32_t* aX, int32_t* aY) const {
354 *aX = mDragImageX;
355 *aY = mDragImageY;
356 return mDragImage;
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,
384 ErrorResult& aRv);
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,
399 bool aPlainTextOnly,
400 nsTArray<nsCString>* aResult);
402 protected:
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
409 // external drag
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
448 // items.
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
460 bool mCursorState;
462 // The current "Drag Data Store Mode" which the DataTransfer is in.
463 Mode mMode;
465 // true for drags started without a data transfer, for example, those from
466 // another application.
467 bool mIsExternal;
469 // true if the user cancelled the drag. Used only for the dragend event.
470 bool mUserCancelled;
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
477 // drag and drop.
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)
495 } // namespace dom
496 } // namespace mozilla
498 #endif /* mozilla_dom_DataTransfer_h */