Bug 1309596, add an updateDragImage method to modify the drag feedback image during the drag, r=smaug
authorNeil Deakin <neil@mozilla.com>
Fri, 23 Dec 2016 18:09:44 -0500
changeset 453779 03fd23542c4fb4503e635f4b185f2795a3c61a97
parent 453718 275c894ee97095e64df89b6a575754e4949c21ae
child 453780 096a4d18d3bc46b6be9b9753a94a7d4e48b31ae5
push id39738
push userbmo:jacheng@mozilla.com
push dateSun, 25 Dec 2016 03:58:33 +0000
reviewerssmaug
bugs1309596
milestone53.0a1
Bug 1309596, add an updateDragImage method to modify the drag feedback image during the drag, r=smaug
dom/events/DataTransfer.cpp
dom/events/DataTransfer.h
dom/events/test/test_dragstart.html
dom/webidl/DataTransfer.webidl
widget/nsBaseDragService.cpp
widget/nsIDragSession.idl
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -753,38 +753,46 @@ DataTransfer::MozClearDataAtHelper(const
 
   nsAutoString format;
   GetRealFormat(aFormat, format);
 
   mItems->MozRemoveByTypeAt(format, aIndex, aSubjectPrincipal, aRv);
 }
 
 void
-DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY,
-                           ErrorResult& aRv)
+DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY)
 {
-  if (mReadOnly) {
-    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
-    return;
+  if (!mReadOnly) {
+    mDragImage = &aImage;
+    mDragImageX = aX;
+    mDragImageY = aY;
   }
-
-  mDragImage = &aImage;
-  mDragImageX = aX;
-  mDragImageY = aY;
 }
 
 NS_IMETHODIMP
 DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
 {
-  ErrorResult rv;
   nsCOMPtr<Element> image = do_QueryInterface(aImage);
   if (image) {
-    SetDragImage(*image, aX, aY, rv);
+    SetDragImage(*image, aX, aY);
   }
-  return rv.StealNSResult();
+  return NS_OK;
+}
+
+void
+DataTransfer::UpdateDragImage(Element& aImage, int32_t aX, int32_t aY)
+{
+  if (mEventMessage < eDragDropEventFirst || mEventMessage > eDragDropEventLast) {
+    return;
+  }
+
+  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+  if (dragSession) {
+    dragSession->UpdateDragImage(aImage.AsDOMNode(), aX, aY);
+  }
 }
 
 already_AddRefed<Promise>
 DataTransfer::GetFilesAndDirectories(nsIPrincipal& aSubjectPrincipal,
                                      ErrorResult& aRv)
 {
   nsCOMPtr<nsINode> parentNode = do_QueryInterface(mParent);
   if (!parentNode) {
--- a/dom/events/DataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -128,18 +128,18 @@ public:
   {
     if (mEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
       aEffectAllowed.AssignLiteral("uninitialized");
     } else {
       aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]);
     }
   }
 
-  void SetDragImage(Element& aElement, int32_t aX, int32_t aY,
-                    ErrorResult& aRv);
+  void SetDragImage(Element& aElement, int32_t aX, int32_t aY);
+  void UpdateDragImage(Element& aElement, int32_t aX, int32_t aY);
 
   void GetTypes(nsTArray<nsString>& aTypes, CallerType aCallerType) const;
 
   void GetData(const nsAString& aFormat, nsAString& aData,
                nsIPrincipal& aSubjectPrincipal,
                ErrorResult& aRv);
 
   void SetData(const nsAString& aFormat, const nsAString& aData,
--- a/dom/events/test/test_dragstart.html
+++ b/dom/events/test/test_dragstart.html
@@ -40,18 +40,16 @@ function afterDragTests()
   expectError(() => gDataTransfer.setData("text/plain", "Some Text"),
               "NoModificationAllowedError", "setData when read only");
   expectError(() => gDataTransfer.clearData("text/plain"),
               "NoModificationAllowedError", "clearData when read only");
   expectError(() => gDataTransfer.mozSetDataAt("text/plain", "Some Text", 0),
               "NoModificationAllowedError", "setDataAt when read only");
   expectError(() => gDataTransfer.mozClearDataAt("text/plain", 0),
               "NoModificationAllowedError", "clearDataAt when read only");
-  expectError(() => gDataTransfer.setDragImage(draggable, 10, 10),
-              "NoModificationAllowedError", "setDragImage when read only");
   expectError(() => gDataTransfer.addElement(draggable),
               "NoModificationAllowedError", "addElement when read only");
 
   var evt = document.createEvent("dragevent");
   ok(evt instanceof DragEvent, "synthetic dragevent class")
   ok(evt instanceof MouseEvent, "synthetic event inherits from MouseEvent")
   evt.initDragEvent("dragstart", true, true, window, 1, 40, 35, 20, 15,
                     false, true, false, false, 0, null, null);
--- a/dom/webidl/DataTransfer.webidl
+++ b/dom/webidl/DataTransfer.webidl
@@ -9,17 +9,16 @@
 
 [ChromeConstructor(DOMString eventType, boolean isExternal)]
 interface DataTransfer {
            attribute DOMString dropEffect;
            attribute DOMString effectAllowed;
 
   readonly attribute DataTransferItemList items;
 
-  [Throws]
   void setDragImage(Element image, long x, long y);
 
   // ReturnValueNeedsContainsHack on .types because lots of extension
   // code was expecting .contains() back when it was a DOMStringList.
   [Pure, Cached, Frozen, NeedsCallerType, ReturnValueNeedsContainsHack]
   readonly attribute sequence<DOMString> types;
   [Throws, NeedsSubjectPrincipal]
   DOMString getData(DOMString format);
@@ -128,16 +127,23 @@ partial interface DataTransfer {
    * @param format the format of the data to look up
    * @returns the data of the given format, or null if it doesn't exist.
    * @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount
    */
   [Throws, NeedsSubjectPrincipal]
   any mozGetDataAt(DOMString format, unsigned long index);
 
   /**
+   * Update the drag image. Arguments are the same as setDragImage. This is only
+   * valid within the parent chrome process.
+   */
+  [ChromeOnly]
+  void updateDragImage(Element image, long x, long y);
+
+  /**
    * Will be true when the user has cancelled the drag (typically by pressing
    * Escape) and when the drag has been cancelled unexpectedly.  This will be
    * false otherwise, including when the drop has been rejected by its target.
    * This property is only relevant for the dragend event.
    */
   readonly attribute boolean mozUserCancelled;
 
   /**
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -803,16 +803,29 @@ nsBaseDragService::UserCancelled()
 NS_IMETHODIMP
 nsBaseDragService::UpdateDragEffect()
 {
   mDragActionFromChildProcess = mDragAction;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsBaseDragService::UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY)
+{
+  // Don't change the image if this is a drag from another source or if there
+  // is a drag popup.
+  if (!mSourceNode || mDragPopup)
+    return NS_OK;
+
+  mImage = aImage;
+  mImageOffset = CSSIntPoint(aImageX, aImageY);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsBaseDragService::DragEventDispatchedToChildProcess()
 {
   mDragEventDispatchedToChildProcess = true;
   return NS_OK;
 }
 
 bool
 nsBaseDragService::MaybeAddChildProcess(mozilla::dom::ContentParent* aChild)
--- a/widget/nsIDragSession.idl
+++ b/widget/nsIDragSession.idl
@@ -84,14 +84,18 @@ interface nsIDragSession : nsISupports
   void userCancelled();
 
   void dragEventDispatchedToChildProcess();
 
   // Called when nsIDragSession implementation should update the UI for the
   // drag-and-drop based on the data got from the child process in response to
   // NS_DRAGDROP_OVER sent from parent process to child process.
   void updateDragEffect();
+
+  // Change the drag image, using similar arguments as
+  // nsIDragService::InvokeDragSessionWithImage.
+  void updateDragImage(in nsIDOMNode aImage, in long aImageX, in long aImageY);
 };
 
 
 %{ C++
 
 %}