Bug 936092, initial DnD support for e10s, r=enndeakin,karlt
☠☠ backed out by cfea20361c1e ☠ ☠
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 08 Apr 2015 18:30:03 +0300
changeset 238181 55524bdeb708cca0f7b128fbe3e1e58cbece899d
parent 238180 75c81639d67a44f111c7126ab85f3766f952b7e3
child 238182 7fbf03927859971b3cf07c7663cd4c000eaadb73
push id28557
push userkwierso@gmail.com
push dateThu, 09 Apr 2015 00:04:16 +0000
treeherdermozilla-central@9a29065e2311 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenndeakin, karlt
bugs936092
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 936092, initial DnD support for e10s, r=enndeakin,karlt
dom/base/nsContentAreaDragDrop.cpp
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/events/DataTransfer.cpp
dom/events/DataTransfer.h
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/DOMTypes.ipdlh
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/moz.build
embedding/browser/nsDocShellTreeOwner.cpp
toolkit/content/tests/browser/browser.ini
toolkit/content/widgets/browser.xml
widget/MouseEvents.h
widget/gtk/nsDragService.cpp
widget/gtk/nsDragService.h
widget/moz.build
widget/nsBaseDragService.cpp
widget/nsBaseDragService.h
widget/nsContentProcessWidgetFactory.cpp
widget/nsDragServiceProxy.cpp
widget/nsDragServiceProxy.h
widget/nsGUIEventIPC.h
widget/nsIDragService.idl
widget/nsIDragSession.idl
widget/nsPrintSettingsImpl.cpp
--- a/dom/base/nsContentAreaDragDrop.cpp
+++ b/dom/base/nsContentAreaDragDrop.cpp
@@ -27,16 +27,17 @@
 #include "nsIDOMHTMLAnchorElement.h"
 #include "nsITransferable.h"
 #include "nsComponentManagerUtils.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsServiceManagerUtils.h"
 #include "nsNetUtil.h"
 #include "nsIFile.h"
+#include "nsFrameLoader.h"
 #include "nsIWebNavigation.h"
 #include "nsIDocShell.h"
 #include "nsIContent.h"
 #include "nsIImageLoadingContent.h"
 #include "nsITextControlElement.h"
 #include "nsUnicharUtils.h"
 #include "nsIURL.h"
 #include "nsIDocument.h"
@@ -47,16 +48,17 @@
 #include "nsEscape.h"
 #include "nsContentUtils.h"
 #include "nsIMIMEService.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "nsIMIMEInfo.h"
 #include "nsRange.h"
+#include "TabParent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLAreaElement.h"
 
 using namespace mozilla::dom;
 
 class MOZ_STACK_CLASS DragDataProducer
 {
 public:
@@ -409,18 +411,31 @@ DragDataProducer::Produce(DataTransfer* 
   // if set, serialize the content under this node
   nsCOMPtr<nsIContent> nodeToSerialize;
 
   nsCOMPtr<nsIDocShellTreeItem> dsti = mWindow->GetDocShell();
   const bool isChromeShell =
     dsti && dsti->ItemType() == nsIDocShellTreeItem::typeChrome;
 
   // In chrome shells, only allow dragging inside editable areas.
-  if (isChromeShell && !editingElement)
+  if (isChromeShell && !editingElement) {
+    nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mTarget);
+    if (flo) {
+      nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
+      if (fl) {
+        TabParent* tp = static_cast<TabParent*>(fl->GetRemoteBrowser());
+        if (tp) {
+          // We have a TabParent, so it may have data for dnd in case the child
+          // process started a dnd session.
+          tp->AddInitialDnDDataTo(aDataTransfer);
+        }
+      }
+    }
     return NS_OK;
+  }
 
   if (isChromeShell && textControl) {
     // Only use the selection if the target node is in the selection.
     bool selectionContainsTarget = false;
     nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(mSelectionTargetNode);
     selection->ContainsNode(targetNode, false, &selectionContainsTarget);
     if (!selectionContainsTarget)
       return NS_OK;
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -30,21 +30,24 @@
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/dom/DocumentFragment.h"
+#include "mozilla/dom/DOMTypes.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/HTMLContentElement.h"
 #include "mozilla/dom/HTMLShadowElement.h"
+#include "mozilla/dom/ipc/BlobChild.h"
+#include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/TextDecoder.h"
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
@@ -7192,8 +7195,99 @@ nsContentUtils::CallOnAllRemoteChildren(
     nsCOMPtr<nsIMessageBroadcaster> windowMM;
     chromeWindow->GetMessageManager(getter_AddRefs(windowMM));
     if (windowMM) {
       CallOnAllRemoteChildren(windowMM, aCallback, aArg);
     }
   }
 }
 
+void
+nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
+                                                nsTArray<IPCDataTransfer>& aIPC,
+                                                mozilla::dom::nsIContentChild* aChild,
+                                                mozilla::dom::nsIContentParent* aParent)
+{
+  aIPC.Clear();
+  MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
+  if (aTransferables) {
+    uint32_t transferableCount = 0;
+    aTransferables->Count(&transferableCount);
+    for (uint32_t i = 0; i < transferableCount; ++i) {
+      IPCDataTransfer* dt = aIPC.AppendElement();
+      nsCOMPtr<nsISupports> genericItem;
+      aTransferables->GetElementAt(i, getter_AddRefs(genericItem));
+      nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem));
+      if (item) {
+        nsCOMPtr<nsISupportsArray> flavorList;
+        item->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
+        if (flavorList) {
+          uint32_t flavorCount = 0;
+          flavorList->Count(&flavorCount);
+          for (uint32_t j = 0; j < flavorCount; ++j) {
+            nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
+            if (!flavor) {
+              continue;
+            }
+
+            nsAutoCString flavorStr;
+            flavor->GetData(flavorStr);
+            if (!flavorStr.Length()) {
+              continue;
+            }
+
+            nsCOMPtr<nsISupports> data;
+            uint32_t dataLen = 0;
+            item->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
+
+            nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
+            if (text) {
+              nsAutoString dataAsString;
+              text->GetData(dataAsString);
+              IPCDataTransferItem* item = dt->items().AppendElement();
+              item->flavor() = nsCString(flavorStr);
+              item->data() = nsString(dataAsString);
+            } else {
+              nsCOMPtr<nsISupportsInterfacePointer> sip =
+                do_QueryInterface(data);
+              if (sip) {
+                sip->GetData(getter_AddRefs(data));
+              }
+              nsCOMPtr<FileImpl> fileImpl;
+              nsCOMPtr<nsIFile> file = do_QueryInterface(data);
+              if (file) {
+                fileImpl = new FileImplFile(file, false);
+                ErrorResult rv;
+                fileImpl->GetSize(rv);
+                fileImpl->GetLastModified(rv);
+              } else {
+                fileImpl = do_QueryInterface(data);
+              }
+              if (fileImpl) {
+                IPCDataTransferItem* item = dt->items().AppendElement();
+                item->flavor() = nsCString(flavorStr);
+                if (aChild) {
+                  item->data() =
+                    mozilla::dom::BlobChild::GetOrCreate(aChild,
+                      static_cast<FileImpl*>(fileImpl.get()));
+                } else if (aParent) {
+                  item->data() =
+                    mozilla::dom::BlobParent::GetOrCreate(aParent,
+                      static_cast<FileImpl*>(fileImpl.get()));
+                }
+              } else {
+                // This is a hack to support kFilePromiseMime.
+                // On Windows there just needs to be an entry for it, 
+                // and for OSX we need to create
+                // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
+                if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
+                  IPCDataTransferItem* item = dt->items().AppendElement();
+                  item->flavor() = nsCString(flavorStr);
+                  item->data() = NS_ConvertUTF8toUTF16(flavorStr);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -82,16 +82,17 @@ class nsIPresShell;
 class nsIPrincipal;
 class nsIRequest;
 class nsIRunnable;
 class nsIScriptContext;
 class nsIScriptGlobalObject;
 class nsIScriptSecurityManager;
 class nsIStringBundle;
 class nsIStringBundleService;
+class nsISupportsArray;
 class nsISupportsHashKey;
 class nsIURI;
 class nsIWidget;
 class nsIWordBreaker;
 class nsIXPConnect;
 class nsNodeInfoManager;
 class nsPIDOMWindow;
 class nsPresContext;
@@ -115,17 +116,20 @@ template<class T> class nsReadingIterato
 namespace mozilla {
 class ErrorResult;
 class EventListenerManager;
 
 namespace dom {
 class DocumentFragment;
 class Element;
 class EventTarget;
+class IPCDataTransfer;
 class NodeInfo;
+class nsIContentChild;
+class nsIContentParent;
 class Selection;
 class TabParent;
 } // namespace dom
 
 namespace layers {
 class LayerManager;
 } // namespace layers
 
@@ -2282,16 +2286,20 @@ public:
   /*
    * Call the given callback on all remote children of the given top-level
    * window.
    */
   static void CallOnAllRemoteChildren(nsIDOMWindow* aWindow,
                                       CallOnRemoteChildFunction aCallback,
                                       void* aArg);
 
+  static void TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
+                                              nsTArray<mozilla::dom::IPCDataTransfer>& aIPC,
+                                              mozilla::dom::nsIContentChild* aChild,
+                                              mozilla::dom::nsIContentParent* aParent);
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -19,16 +19,17 @@
 #include "nsIClipboard.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsCRT.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIDocument.h"
 #include "nsIScriptGlobalObject.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/DataTransferBinding.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/BindingUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
@@ -77,17 +78,16 @@ DataTransfer::DataTransfer(nsISupports* 
     mReadOnly(true),
     mIsExternal(aIsExternal),
     mUserCancelled(false),
     mIsCrossDomainSubFrameDrop(false),
     mClipboardType(aClipboardType),
     mDragImageX(0),
     mDragImageY(0)
 {
-  MOZ_ASSERT(mParent);
   // For these events, we want to be able to add data to the data transfer, so
   // clear the readonly state. Otherwise, the data is already present. For
   // external usage, cache the data from the native clipboard or drag.
   if (aEventType == NS_CUT ||
       aEventType == NS_COPY ||
       aEventType == NS_DRAGDROP_START ||
       aEventType == NS_DRAGDROP_GESTURE) {
     mReadOnly = false;
@@ -295,20 +295,26 @@ DataTransfer::GetFiles(ErrorResult& aRv)
       nsCOMPtr<nsISupports> supports;
       nsresult rv = variant->GetAsISupports(getter_AddRefs(supports));
 
       if (NS_FAILED(rv))
         continue;
 
       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
-      if (!file)
-        continue;
-
-      nsRefPtr<File> domFile = File::CreateFromFile(GetParentObject(), file);
+      nsRefPtr<File> domFile;
+      if (file) {
+        domFile = File::CreateFromFile(GetParentObject(), file);
+      } else {
+        nsCOMPtr<FileImpl> fileImpl = do_QueryInterface(supports);
+        if (!fileImpl) {
+          continue;
+        }
+        domFile = new File(GetParentObject(), static_cast<FileImpl*>(fileImpl.get()));
+      }
 
       if (!mFiles->Append(domFile)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
     }
   }
 
@@ -850,38 +856,42 @@ DataTransfer::Clone(nsISupports* aParent
   return NS_OK;
 }
 
 already_AddRefed<nsISupportsArray>
 DataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
 {
   MOZ_ASSERT(aDragTarget);
 
-  nsCOMPtr<nsISupportsArray> transArray =
-    do_CreateInstance("@mozilla.org/supports-array;1");
-  if (!transArray) {
-    return nullptr;
-  }
-    
-
   nsCOMPtr<nsINode> dragNode = do_QueryInterface(aDragTarget);
   if (!dragNode) {
     return nullptr;
   }
     
   nsIDocument* doc = dragNode->GetCurrentDoc();
   if (!doc) {
     return nullptr;
   }
-    
-  nsILoadContext* loadContext = doc->GetLoadContext();
+
+  return GetTransferables(doc->GetLoadContext());
+}
+
+already_AddRefed<nsISupportsArray>
+DataTransfer::GetTransferables(nsILoadContext* aLoadContext)
+{
+
+  nsCOMPtr<nsISupportsArray> transArray =
+    do_CreateInstance("@mozilla.org/supports-array;1");
+  if (!transArray) {
+    return nullptr;
+  }
 
   uint32_t count = mItems.Length();
   for (uint32_t i = 0; i < count; i++) {
-    nsCOMPtr<nsITransferable> transferable = GetTransferable(i, loadContext);
+    nsCOMPtr<nsITransferable> transferable = GetTransferable(i, aLoadContext);
     if (transferable) {
       transArray->AppendElement(transferable);
     }
   }
 
   return transArray.forget();
 }
 
@@ -1248,10 +1258,25 @@ DataTransfer::FillInExternalData(Transfe
     }
     else {
       variant->SetAsISupports(data);
     }
 
     aItem.mData = variant;
   }
 
+void
+DataTransfer::FillAllExternalData()
+{
+  if (mIsExternal) {
+    for (uint32_t i = 0; i < mItems.Length(); ++i) {
+      nsTArray<TransferItem>& itemArray = mItems[i];
+      for (uint32_t j = 0; j < itemArray.Length(); ++j) {
+        if (!itemArray[j].mData) {
+          FillInExternalData(itemArray[j], i);
+        }
+      }
+    }
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/events/DataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -180,16 +180,17 @@ public:
 
   // a readonly dataTransfer cannot have new data added or existing data removed.
   // Only the dropEffect and effectAllowed may be modified.
   void SetReadOnly() { mReadOnly = true; }
 
   // converts the data into an array of nsITransferable objects to be used for
   // drag and drop or clipboard operations.
   already_AddRefed<nsISupportsArray> GetTransferables(nsIDOMNode* aDragTarget);
+  already_AddRefed<nsISupportsArray> GetTransferables(nsILoadContext* aLoadContext);
 
   // converts the data for a single item at aIndex into an nsITransferable object.
   already_AddRefed<nsITransferable> GetTransferable(uint32_t aIndex,
                                                     nsILoadContext* aLoadContext);
 
   // converts the data in the variant to an nsISupportString if possible or
   // an nsISupports or null otherwise.
   bool ConvertFromVariant(nsIVariant* aVariant,
@@ -234,16 +235,19 @@ protected:
 
   // caches the formats that exist in the clipboard
   void CacheExternalClipboardFormats();
 
   // fills in the data field of aItem with the data from the drag service or
   // clipboard for a given index.
   void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
 
+  friend class ContentParent;
+  void FillAllExternalData();
+
   void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
                             mozilla::ErrorResult& aRv);
 
   nsCOMPtr<nsISupports> mParent;
 
   // the event type this data transfer is for. This will correspond to an
   // event->message value.
   uint32_t mEventType;
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/EventStates.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/UIEvent.h"
 
 #include "ContentEventHandler.h"
 #include "IMEContentObserver.h"
 #include "WheelHandlingHelper.h"
 
@@ -76,16 +77,17 @@
 #include "mozilla/dom/DataTransfer.h"
 #include "nsContentAreaDragDrop.h"
 #ifdef MOZ_XUL
 #include "nsTreeBodyFrame.h"
 #endif
 #include "nsIController.h"
 #include "nsICommandParams.h"
 #include "mozilla/Services.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/HTMLLabelElement.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "GeckoProfiler.h"
 #include "Units.h"
 #include "mozilla/layers/APZCTreeManager.h"
 
@@ -1104,16 +1106,39 @@ EventStateManager::DispatchCrossProcessE
     return remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
   }
   case eTouchEventClass: {
     // Let the child process synthesize a mouse event if needed, and
     // ensure we don't synthesize one in this process.
     *aStatus = nsEventStatus_eConsumeNoDefault;
     return remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
   }
+  case eDragEventClass: {
+    if (remote->Manager()->IsContentParent()) {
+      remote->Manager()->AsContentParent()->MaybeInvokeDragSession(remote);
+    }
+
+    nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+    uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
+    uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
+    if (dragSession) {
+      dragSession->DragEventDispatchedToChildProcess();
+      dragSession->GetDragAction(&action);
+      nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
+      dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
+      if (initialDataTransfer) {
+        initialDataTransfer->GetDropEffectInt(&dropEffect);
+      }
+    }
+
+    bool retval = remote->SendRealDragEvent(*aEvent->AsDragEvent(),
+                                            action, dropEffect);
+
+    return retval;
+  }
   default: {
     MOZ_CRASH("Attempt to send non-whitelisted event?");
   }
   }
 }
 
 bool
 EventStateManager::IsRemoteTarget(nsIContent* target) {
@@ -1160,16 +1185,23 @@ CrossProcessSafeEvent(const WidgetEvent&
     case NS_TOUCH_START:
     case NS_TOUCH_MOVE:
     case NS_TOUCH_END:
     case NS_TOUCH_CANCEL:
       return true;
     default:
       return false;
     }
+  case eDragEventClass:
+    switch (aEvent.message) {
+    case NS_DRAGDROP_OVER:
+    case NS_DRAGDROP_EXIT:
+    case NS_DRAGDROP_DROP:
+      return true;
+    }
   default:
     return false;
   }
 }
 
 bool
 EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
                                            nsEventStatus *aStatus) {
@@ -1491,16 +1523,22 @@ EventStateManager::BeginTrackingDragGest
   mGestureDownButtons = inDownEvent->buttons;
 
   if (Prefs::ClickHoldContextMenu()) {
     // fire off a timer to track click-hold
     CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
   }
 }
 
+void
+EventStateManager::BeginTrackingRemoteDragGesture(nsIContent* aContent)
+{
+  mGestureDownContent = aContent;
+  mGestureDownFrameOwner = aContent;
+}
 
 //
 // StopTrackingDragGesture
 //
 // Record that the mouse has gone back up so that we should leave the TRACKING
 // state of d&d gesture tracker and return to the START state.
 //
 void
@@ -1592,18 +1630,19 @@ EventStateManager::GenerateDragGesture(n
 
       nsRefPtr<DataTransfer> dataTransfer =
         new DataTransfer(window, NS_DRAGDROP_START, false, -1);
 
       nsCOMPtr<nsISelection> selection;
       nsCOMPtr<nsIContent> eventContent, targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
       if (eventContent)
-        DetermineDragTarget(window, eventContent, dataTransfer,
-                            getter_AddRefs(selection), getter_AddRefs(targetContent));
+        DetermineDragTargetAndDefaultData(window, eventContent, dataTransfer,
+                                          getter_AddRefs(selection),
+                                          getter_AddRefs(targetContent));
 
       // Stop tracking the drag gesture now. This should stop us from
       // reentering GenerateDragGesture inside DOM event processing.
       StopTrackingDragGesture();
 
       if (!targetContent)
         return;
 
@@ -1689,21 +1728,21 @@ EventStateManager::GenerateDragGesture(n
 
     // Now flush all pending notifications, for better responsiveness
     // while dragging.
     FlushPendingEvents(aPresContext);
   }
 } // GenerateDragGesture
 
 void
-EventStateManager::DetermineDragTarget(nsPIDOMWindow* aWindow,
-                                       nsIContent* aSelectionTarget,
-                                       DataTransfer* aDataTransfer,
-                                       nsISelection** aSelection,
-                                       nsIContent** aTargetNode)
+EventStateManager::DetermineDragTargetAndDefaultData(nsPIDOMWindow* aWindow,
+                                                     nsIContent* aSelectionTarget,
+                                                     DataTransfer* aDataTransfer,
+                                                     nsISelection** aSelection,
+                                                     nsIContent** aTargetNode)
 {
   *aTargetNode = nullptr;
 
   // GetDragData determines if a selection, link or image in the content
   // should be dragged, and places the data associated with the drag in the
   // data transfer.
   // mGestureDownContent is the node where the mousedown event for the drag
   // occurred, and aSelectionTarget is the node to use when a selection is used
@@ -3146,16 +3185,17 @@ EventStateManager::PostHandleEvent(nsPre
       // that a drag is allowed. If the event isn't cancelled, a drop won't be
       // allowed. Essentially, to allow a drop somewhere, specify the effects
       // using the effectAllowed and dropEffect properties in a dragenter or
       // dragover event and cancel the event. To not allow a drop somewhere,
       // don't cancel the event or set the effectAllowed or dropEffect to
       // "none". This way, if the event is just ignored, no drop will be
       // allowed.
       uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
+      uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
       if (nsEventStatus_eConsumeNoDefault == *aStatus) {
         // if the event has a dataTransfer set, use it.
         if (dragEvent->dataTransfer) {
           // get the dataTransfer and the dropEffect that was set on it
           dataTransfer = do_QueryInterface(dragEvent->dataTransfer);
           dataTransfer->GetDropEffectInt(&dropEffect);
         }
         else {
@@ -3163,17 +3203,16 @@ EventStateManager::PostHandleEvent(nsPre
           // made to access the dataTransfer during the event, yet the event
           // was cancelled. Instead, use the initial data transfer available
           // from the drag session. The drop effect would not have been
           // initialized (which is done in DragEvent::GetDataTransfer),
           // so set it from the drag action. We'll still want to filter it
           // based on the effectAllowed below.
           dataTransfer = initialDataTransfer;
 
-          uint32_t action;
           dragSession->GetDragAction(&action);
 
           // filter the drop effect based on the action. Use UNINITIALIZED as
           // any effect is allowed.
           dropEffect = nsContentUtils::FilterDropEffect(action,
                          nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
         }
 
@@ -3185,17 +3224,16 @@ EventStateManager::PostHandleEvent(nsPre
           dataTransfer->GetEffectAllowedInt(&effectAllowed);
 
         // set the drag action based on the drop effect and effect allowed.
         // The drop effect field on the drag transfer object specifies the
         // desired current drop effect. However, it cannot be used if the
         // effectAllowed state doesn't include that type of action. If the
         // dropEffect is "none", then the action will be 'none' so a drop will
         // not be allowed.
-        uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
         if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
             dropEffect & effectAllowed)
           action = dropEffect;
 
         if (action == nsIDragService::DRAGDROP_ACTION_NONE)
           dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
 
         // inform the drag session that a drop is allowed on this node.
@@ -3209,16 +3247,22 @@ EventStateManager::PostHandleEvent(nsPre
           // content or chrome.
           dragSession->SetOnlyChromeDrop(
             !dragEvent->mDefaultPreventedOnContent);
         }
       } else if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) {
         // No one called preventDefault(), so handle drop only in chrome.
         dragSession->SetOnlyChromeDrop(true);
       }
+      if (ContentChild* child = ContentChild::GetSingleton()) {
+        child->SendUpdateDropEffect(action, dropEffect);
+      }
+      if (dispatchedToContentProcess) {
+        dragSession->SetCanDrop(true);
+      }
 
       // now set the drop effect in the initial dataTransfer. This ensures
       // that we can get the desired drop effect in the drop event.
       if (initialDataTransfer)
         initialDataTransfer->SetDropEffectInt(dropEffect);
     }
     break;
 
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -750,35 +750,38 @@ protected:
    */
   void DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
                           nsIFrame* targetFrame);
 
   // routines for the d&d gesture tracking state machine
   void BeginTrackingDragGesture(nsPresContext* aPresContext,
                                 WidgetMouseEvent* aDownEvent,
                                 nsIFrame* aDownFrame);
+
+  friend class mozilla::dom::TabParent;
+  void BeginTrackingRemoteDragGesture(nsIContent* aContent);
   void StopTrackingDragGesture();
   void GenerateDragGesture(nsPresContext* aPresContext,
                            WidgetMouseEvent* aEvent);
 
   /**
    * Determine which node the drag should be targeted at.
    * This is either the node clicked when there is a selection, or, for HTML,
    * the element with a draggable property set to true.
    *
    * aSelectionTarget - target to check for selection
    * aDataTransfer - data transfer object that will contain the data to drag
    * aSelection - [out] set to the selection to be dragged
    * aTargetNode - [out] the draggable node, or null if there isn't one
    */
-  void DetermineDragTarget(nsPIDOMWindow* aWindow,
-                           nsIContent* aSelectionTarget,
-                           dom::DataTransfer* aDataTransfer,
-                           nsISelection** aSelection,
-                           nsIContent** aTargetNode);
+  void DetermineDragTargetAndDefaultData(nsPIDOMWindow* aWindow,
+                                         nsIContent* aSelectionTarget,
+                                         dom::DataTransfer* aDataTransfer,
+                                         nsISelection** aSelection,
+                                         nsIContent** aTargetNode);
 
   /*
    * Perform the default handling for the dragstart/draggesture event and set up a
    * drag for aDataTransfer if it contains any data. Returns true if a drag has
    * started.
    *
    * aDragEvent - the dragstart/draggesture event
    * aDataTransfer - the data transfer that holds the data to be dragged
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -24,16 +24,17 @@
 #include "mozilla/a11y/DocAccessibleChild.h"
 #endif
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
 #include "mozilla/dom/nsIContentChild.h"
@@ -64,16 +65,17 @@
 #endif
 #endif
 
 #include "mozilla/unused.h"
 
 #include "mozInlineSpellChecker.h"
 #include "nsIConsoleListener.h"
 #include "nsICycleCollectorListener.h"
+#include "nsIDragService.h"
 #include "nsIIPCBackgroundChildCreateCallback.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsScreenManagerProxy.h"
@@ -2723,16 +2725,74 @@ NextWindowID()
   uint64_t windowID = ++gNextWindowID;
 
   MOZ_RELEASE_ASSERT(windowID < (uint64_t(1) << kWindowIDWindowBits));
   uint64_t windowBits = windowID & ((uint64_t(1) << kWindowIDWindowBits) - 1);
 
   return (processBits << kWindowIDWindowBits) | windowBits;
 }
 
+bool
+ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
+                                    const uint32_t& aAction)
+{
+  nsCOMPtr<nsIDragService> dragService =
+    do_GetService("@mozilla.org/widget/dragservice;1");
+  if (dragService) {
+    dragService->StartDragSession();
+    nsCOMPtr<nsIDragSession> session;
+    dragService->GetCurrentSession(getter_AddRefs(session));
+    if (session) {
+      session->SetDragAction(aAction);
+      nsCOMPtr<DataTransfer> dataTransfer =
+        new DataTransfer(nullptr, NS_DRAGDROP_START, false, -1);
+      for (uint32_t i = 0; i < aTransfers.Length(); ++i) {
+        auto& items = aTransfers[i].items();
+        for (uint32_t j = 0; j < items.Length(); ++j) {
+          const IPCDataTransferItem& item = items[j];
+          nsCOMPtr<nsIWritableVariant> variant =
+             do_CreateInstance(NS_VARIANT_CONTRACTID);
+          NS_ENSURE_TRUE(variant, false);
+          if (item.data().type() == IPCDataTransferData::TnsString) {
+            const nsString& data = item.data().get_nsString();
+            variant->SetAsAString(data);
+          } else if (item.data().type() == IPCDataTransferData::TPBlobChild) {
+            BlobChild* blob = static_cast<BlobChild*>(item.data().get_PBlobChild());
+            nsRefPtr<FileImpl> fileImpl = blob->GetBlobImpl();
+            variant->SetAsISupports(fileImpl);
+          }
+          dataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.flavor()),
+                                             variant, i,
+                                             nsContentUtils::GetSystemPrincipal());
+        }
+      }
+      session->SetDataTransfer(dataTransfer);
+    }
+  }
+  return true;
+}
+
+bool
+ContentChild::RecvEndDragSession(const bool& aDoneDrag,
+                                 const bool& aUserCancelled)
+{
+  nsCOMPtr<nsIDragService> dragService =
+    do_GetService("@mozilla.org/widget/dragservice;1");
+  if (dragService) {
+    if (aUserCancelled) {
+      nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+      if (dragSession) {
+        dragSession->UserCancelled();
+      }
+    }
+    dragService->EndDragSession(aDoneDrag);
+  }
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
 
 extern "C" {
 
 #if defined(MOZ_NUWA_PROCESS)
 NS_EXPORT void
 GetProtoFdInfos(NuwaProtoFdInfo* aInfoList,
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -391,16 +391,21 @@ public:
                                    nsTArray<nsCString>&& aFeatures,
                                    nsTArray<nsCString>&& aThreadNameFilters) override;
     virtual bool RecvStopProfiler() override;
     virtual bool RecvGetProfile(nsCString* aProfile) override;
     virtual bool RecvDomainSetChanged(const uint32_t& aSetType, const uint32_t& aChangeType,
                                       const OptionalURIParams& aDomain) override;
     virtual bool RecvShutdown() override;
 
+    virtual bool
+    RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
+                          const uint32_t& aAction) override;
+    virtual bool RecvEndDragSession(const bool& aDoneDrag,
+                                    const bool& aUserCancelled) override;
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
 
     // Get the directory for IndexedDB files. We query the parent for this and
     // cache the value
     nsString &GetIndexedDBPath();
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -33,16 +33,17 @@
 #include "mozIApplication.h"
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/DocAccessibleParent.h"
 #include "nsAccessibilityService.h"
 #endif
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/docshell/OfflineCacheUpdateParent.h"
 #include "mozilla/dom/DataStoreService.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/FileSystemRequestParent.h"
 #include "mozilla/dom/GeolocationBinding.h"
 #include "mozilla/dom/PContentBridgeParent.h"
 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
@@ -98,16 +99,17 @@
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIAppsService.h"
 #include "nsIClipboard.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIDocument.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMGeoPositionError.h"
+#include "nsIDragService.h"
 #include "mozilla/dom/WakeLock.h"
 #include "nsIDOMWindow.h"
 #include "nsIExternalProtocolService.h"
 #include "nsIFormProcessor.h"
 #include "nsIGfxInfo.h"
 #include "nsIIdleService.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIMemoryInfoDumper.h"
@@ -4802,16 +4804,72 @@ ContentParent::DeallocPOfflineCacheUpdat
 bool
 ContentParent::RecvSetOfflinePermission(const Principal& aPrincipal)
 {
     nsIPrincipal* principal = aPrincipal;
     nsContentUtils::MaybeAllowOfflineAppByDefault(principal, nullptr);
     return true;
 }
 
+void
+ContentParent::MaybeInvokeDragSession(TabParent* aParent)
+{
+  nsCOMPtr<nsIDragService> dragService =
+    do_GetService("@mozilla.org/widget/dragservice;1");
+  if (dragService && dragService->MaybeAddChildProcess(this)) {
+    // We need to send transferable data to child process.
+    nsCOMPtr<nsIDragSession> session;
+    dragService->GetCurrentSession(getter_AddRefs(session));
+    if (session) {
+      nsTArray<IPCDataTransfer> dataTransfers;
+      nsCOMPtr<nsIDOMDataTransfer> domTransfer;
+      session->GetDataTransfer(getter_AddRefs(domTransfer));
+      nsCOMPtr<DataTransfer> transfer = do_QueryInterface(domTransfer);
+      if (!transfer) {
+        // Pass NS_DRAGDROP_DROP to get DataTransfer with external
+        // drag formats cached.
+        transfer = new DataTransfer(nullptr, NS_DRAGDROP_DROP, true, -1);
+        session->SetDataTransfer(transfer);
+      }
+      // Note, even though this fills the DataTransfer object with
+      // external data, the data is usually transfered over IPC lazily when
+      // needed.
+      transfer->FillAllExternalData();
+      nsCOMPtr<nsILoadContext> lc = aParent ?
+                                     aParent->GetLoadContext() : nullptr;
+      nsCOMPtr<nsISupportsArray> transferables =
+        transfer->GetTransferables(lc);
+      nsContentUtils::TransferablesToIPCTransferables(transferables,
+                                                      dataTransfers,
+                                                      nullptr,
+                                                      this);
+      uint32_t action;
+      session->GetDragAction(&action);
+      mozilla::unused << SendInvokeDragSession(dataTransfers, action);
+    }
+  }
+}
+
+bool
+ContentParent::RecvUpdateDropEffect(const uint32_t& aDragAction,
+                                    const uint32_t& aDropEffect)
+{
+  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+  if (dragSession) {
+    dragSession->SetDragAction(aDragAction);
+    nsCOMPtr<nsIDOMDataTransfer> dt;
+    dragSession->GetDataTransfer(getter_AddRefs(dt));
+    if (dt) {
+      dt->SetDropEffectInt(aDropEffect);
+    }
+    dragSession->UpdateDragEffect();
+  }
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
     mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -366,16 +366,17 @@ public:
                                        const TabId& aTabId) override;
     virtual bool
     DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* aActor) override;
 
     virtual bool RecvSetOfflinePermission(const IPC::Principal& principal) override;
 
     virtual bool RecvFinishShutdown() override;
 
+    void MaybeInvokeDragSession(TabParent* aParent);
 protected:
     void OnChannelConnected(int32_t pid) override;
     virtual void ActorDestroy(ActorDestroyReason why) override;
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() override;
 
 private:
@@ -817,16 +818,18 @@ private:
                           int32_t* aSliceRefCnt,
                           bool* aResult) override;
 
     virtual PDocAccessibleParent* AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&) override;
     virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) override;
     virtual bool RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
                                                PDocAccessibleParent* aParentDoc, const uint64_t& aParentID) override;
 
+    virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
+                                      const uint32_t& aDropEffect) override;
     // If you add strong pointers to cycle collected objects here, be sure to
     // release these objects in ShutDownProcess.  See the comment there for more
     // details.
 
     GeckoChildProcessHost* mSubprocess;
     ContentParent* mOpener;
 
     ContentParentId mChildID;
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -130,10 +130,27 @@ struct ParentBlobConstructorParams
 };
 
 union BlobConstructorParams
 {
   ChildBlobConstructorParams;
   ParentBlobConstructorParams;
 };
 
+union IPCDataTransferData
+{
+  nsString;
+  PBlob;
+};
+
+struct IPCDataTransferItem
+{
+  nsCString flavor;
+  IPCDataTransferData data;
+};
+
+struct IPCDataTransfer
+{
+  IPCDataTransferItem[] items;
+};
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -40,16 +40,17 @@ using class mozilla::WidgetCompositionEv
 using struct mozilla::widget::IMENotification from "nsIWidget.h";
 using struct nsIMEUpdatePreference from "nsIWidget.h";
 using struct nsIntPoint from "nsPoint.h";
 using struct nsIntRect from "nsRect.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
 using class mozilla::WidgetKeyboardEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetMouseEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetWheelEvent from "ipc/nsGUIEventIPC.h";
+using class mozilla::WidgetDragEvent from "ipc/nsGUIEventIPC.h";
 using struct nsRect from "nsRect.h";
 using class mozilla::WidgetSelectionEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetTouchEvent from "ipc/nsGUIEventIPC.h";
 using struct mozilla::dom::RemoteDOMEvent from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using mozilla::CSSPoint from "Units.h";
 using mozilla::CSSToScreenScale from "Units.h";
@@ -500,16 +501,19 @@ parent:
      * dimensions has been requested, likely through win.moveTo or resizeTo
      */
     async SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy);
 
     prio(high) sync DispatchWheelEvent(WidgetWheelEvent event);
     prio(high) sync DispatchMouseEvent(WidgetMouseEvent event);
     prio(high) sync DispatchKeyboardEvent(WidgetKeyboardEvent event);
 
+    InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action,
+                      nsCString visualData, uint32_t width, uint32_t height,
+                      uint32_t stride, uint8_t format, int32_t dragAreaX, int32_t dragAreaY);
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
      * |Show()| and |Move()| take IntSizes rather than Rects because
      * content processes always render to a virtual <0, 0> top-left
@@ -567,16 +571,17 @@ child:
      * they are 'compressed' by dumping the oldest one.
      */
     RealMouseMoveEvent(WidgetMouseEvent event) compress;
     RealMouseButtonEvent(WidgetMouseEvent event);
     RealKeyEvent(WidgetKeyboardEvent event, MaybeNativeKeyBinding keyBinding);
     MouseWheelEvent(WidgetWheelEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
     RealTouchEvent(WidgetTouchEvent aEvent, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
     RealTouchMoveEvent(WidgetTouchEvent aEvent, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
+    RealDragEvent(WidgetDragEvent aEvent, uint32_t aDragAction, uint32_t aDropEffect);
 
     /**
      * @see nsIDOMWindowUtils sendKeyEvent.
      */
     KeyEvent(nsString aType,
              int32_t aKeyCode,
              int32_t aCharCode,
              int32_t aModifiers,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -565,16 +565,19 @@ child:
      * Control the Gecko Profiler in the child process.
      */
     async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures,
                         nsCString[] aThreadNameFilters);
     async StopProfiler();
     prio(high) sync GetProfile()
       returns (nsCString aProfile);
 
+    InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action);
+
+    EndDragSession(bool aDoneDrag, bool aUserCancelled);
     NuwaFreeze();
 
     async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, OptionalURIParams aDomain);
 
     /**
      * Notify the child to shutdown. The child will in turn call FinishShutdown
      * and let the parent close the channel.
      */
@@ -936,15 +939,16 @@ parent:
     SetOfflinePermission(Principal principal);
 
     /**
      * Notifies the parent to continue shutting down after the child performs
      * its shutdown tasks.
      */
     async FinishShutdown();
 
+    UpdateDropEffect(uint32_t aDragAction, uint32_t aDropEffect);
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2404,16 +2404,54 @@ TabChild::RecvRealTouchEvent(const Widge
 bool
 TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
                                  const ScrollableLayerGuid& aGuid,
                                  const uint64_t& aInputBlockId)
 {
   return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId);
 }
 
+bool
+TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent,
+                            const uint32_t& aDragAction,
+                            const uint32_t& aDropEffect)
+{
+  WidgetDragEvent localEvent(aEvent);
+  localEvent.widget = mWidget;
+
+  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+  if (dragSession) {
+    dragSession->SetDragAction(aDragAction);
+    nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
+    dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
+    if (initialDataTransfer) {
+      initialDataTransfer->SetDropEffectInt(aDropEffect);
+    }
+  }
+
+  if (aEvent.message == NS_DRAGDROP_DROP) {
+    bool canDrop = true;
+    if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) ||
+        !canDrop) {
+      localEvent.message = NS_DRAGDROP_EXIT;
+    }
+  } else if (aEvent.message == NS_DRAGDROP_OVER) {
+    nsCOMPtr<nsIDragService> dragService =
+      do_GetService("@mozilla.org/widget/dragservice;1");
+    if (dragService) {
+      // This will dispatch 'drag' event at the source if the
+      // drag transaction started in this process.
+      dragService->FireDragEventAtSource(NS_DRAGDROP_DRAG);
+    }
+  }
+
+  APZCCallbackHelper::DispatchWidgetEvent(localEvent);
+  return true;
+}
+
 void
 TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache,
                                    WidgetKeyboardEvent* aEvent)
 {
   MaybeNativeKeyBinding maybeBindings;
   if (!SendRequestNativeKeyBindings(*aEvent, &maybeBindings)) {
     return;
   }
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -345,16 +345,19 @@ public:
                                 const float&    aX,
                                 const float&    aY,
                                 const int32_t&  aButton,
                                 const int32_t&  aClickCount,
                                 const int32_t&  aModifiers,
                                 const bool&     aIgnoreRootScrollFrame) override;
     virtual bool RecvRealMouseMoveEvent(const mozilla::WidgetMouseEvent& event) override;
     virtual bool RecvRealMouseButtonEvent(const mozilla::WidgetMouseEvent& event) override;
+    virtual bool RecvRealDragEvent(const WidgetDragEvent& aEvent,
+                                   const uint32_t& aDragAction,
+                                   const uint32_t& aDropEffect) override;
     virtual bool RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& event,
                                   const MaybeNativeKeyBinding& aBindings) override;
     virtual bool RecvMouseWheelEvent(const mozilla::WidgetWheelEvent& event,
                                      const ScrollableLayerGuid& aGuid,
                                      const uint64_t& aInputBlockId) override;
     virtual bool RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
                                     const ScrollableLayerGuid& aGuid,
                                     const uint64_t& aInputBlockId) override;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -7,34 +7,38 @@
 #include "base/basictypes.h"
 
 #include "TabParent.h"
 
 #include "AppProcessChecker.h"
 #include "mozIApplication.h"
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/PContentPermissionRequestParent.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/plugins/PluginWidgetParent.h"
 #include "mozilla/EventStateManager.h"
+#include "mozilla/gfx/2D.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/unused.h"
+#include "BlobParent.h"
 #include "nsCOMPtr.h"
+#include "nsContentAreaDragDrop.h"
 #include "nsContentPermissionHelper.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsFocusManager.h"
 #include "nsFrameLoader.h"
 #include "nsIBaseWindow.h"
 #include "nsIContent.h"
 #include "nsIDocShell.h"
@@ -71,16 +75,17 @@
 #include "StructuredCloneUtils.h"
 #include "ColorPickerParent.h"
 #include "FilePickerParent.h"
 #include "TabChild.h"
 #include "LoadContext.h"
 #include "nsNetCID.h"
 #include "nsIAuthInformation.h"
 #include "nsIAuthPromptCallback.h"
+#include "SourceSurfaceRawData.h"
 #include "nsAuthInformationHolder.h"
 #include "nsICancelable.h"
 #include "gfxPrefs.h"
 #include "nsILoginManagerPrompter.h"
 #include "nsPIWindowRoot.h"
 #include <algorithm>
 
 using namespace mozilla::dom;
@@ -269,16 +274,18 @@ TabParent::TabParent(nsIContentParent* a
   , mUpdatedDimensions(false)
   , mChromeOffset(0, 0)
   , mManager(aManager)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mAppPackageFileDescriptorSent(false)
   , mSendOfflineStatus(true)
   , mChromeFlags(aChromeFlags)
+  , mDragAreaX(0)
+  , mDragAreaY(0)
   , mInitedByParent(false)
   , mTabId(aTabId)
   , mCreatingWindow(false)
   , mNeedLayerTreeReadyNotification(false)
 {
   MOZ_ASSERT(aManager);
 }
 
@@ -1197,16 +1204,27 @@ TabParent::GetLayoutDeviceToCSSScale()
   nsIDocument* doc = (content ? content->OwnerDoc() : nullptr);
   nsIPresShell* shell = (doc ? doc->GetShell() : nullptr);
   nsPresContext* ctx = (shell ? shell->GetPresContext() : nullptr);
   return LayoutDeviceToCSSScale(ctx
     ? (float)ctx->AppUnitsPerDevPixel() / nsPresContext::AppUnitsPerCSSPixel()
     : 0.0f);
 }
 
+bool
+TabParent::SendRealDragEvent(WidgetDragEvent& event, uint32_t aDragAction,
+                             uint32_t aDropEffect)
+{
+  if (mIsDestroyed) {
+    return false;
+  }
+  event.refPoint += GetChildProcessOffset();
+  return PBrowserParent::SendRealDragEvent(event, aDragAction, aDropEffect);
+}
+
 CSSPoint TabParent::AdjustTapToChildWidget(const CSSPoint& aPoint)
 {
   return aPoint + (LayoutDevicePoint(mChildProcessOffsetAtTouchStart) * GetLayoutDeviceToCSSScale());
 }
 
 bool TabParent::SendHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
 {
   if (mIsDestroyed) {
@@ -2923,16 +2941,119 @@ TabParent::RecvAsyncAuthPrompt(const nsC
   nsCOMPtr<nsICancelable> dummy;
   nsresult rv =
     authPrompt->AsyncPromptAuth(channel, channel, nullptr,
                                 level, holder, getter_AddRefs(dummy));
 
   return rv == NS_OK;
 }
 
+bool
+TabParent::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
+                                 const uint32_t& aAction,
+                                 const nsCString& aVisualDnDData,
+                                 const uint32_t& aWidth, const uint32_t& aHeight,
+                                 const uint32_t& aStride, const uint8_t& aFormat,
+                                 const int32_t& aDragAreaX, const int32_t& aDragAreaY)
+{
+  mInitialDataTransferItems.Clear();
+  nsPresContext* pc = mFrameElement->OwnerDoc()->GetShell()->GetPresContext();
+  EventStateManager* esm = pc->EventStateManager();
+
+  for (uint32_t i = 0; i < aTransfers.Length(); ++i) {
+    auto& items = aTransfers[i].items();
+    nsTArray<DataTransferItem>* itemArray = mInitialDataTransferItems.AppendElement();
+    for (uint32_t j = 0; j < items.Length(); ++j) {
+      const IPCDataTransferItem& item = items[j];
+      DataTransferItem* localItem = itemArray->AppendElement();
+      localItem->mFlavor = item.flavor();
+      if (item.data().type() == IPCDataTransferData::TnsString) {
+        localItem->mType = DataTransferItem::DataType::eString;
+        localItem->mStringData = item.data().get_nsString();
+      } else {
+        localItem->mType = DataTransferItem::DataType::eBlob;
+        BlobParent* blobParent =
+          static_cast<BlobParent*>(item.data().get_PBlobParent());
+        if (blobParent) {
+          localItem->mBlobData = blobParent->GetBlobImpl();
+        }
+      }
+    }
+  }
+  if (Manager()->IsContentParent()) {
+    nsCOMPtr<nsIDragService> dragService =
+      do_GetService("@mozilla.org/widget/dragservice;1");
+    if (dragService) {
+      dragService->MaybeAddChildProcess(Manager()->AsContentParent());
+    }
+  }
+
+  if (aVisualDnDData.IsEmpty()) {
+    mDnDVisualization = nullptr;
+  } else {
+    mDnDVisualization =
+      new mozilla::gfx::SourceSurfaceRawData();
+    mozilla::gfx::SourceSurfaceRawData* raw =
+      static_cast<mozilla::gfx::SourceSurfaceRawData*>(mDnDVisualization.get());
+    raw->InitWrappingData(
+      reinterpret_cast<uint8_t*>(const_cast<nsCString&>(aVisualDnDData).BeginWriting()),
+      mozilla::gfx::IntSize(aWidth, aHeight), aStride,
+      static_cast<mozilla::gfx::SurfaceFormat>(aFormat), false);
+    raw->GuaranteePersistance();
+  }
+  mDragAreaX = aDragAreaX;
+  mDragAreaY = aDragAreaY;
+  
+  esm->BeginTrackingRemoteDragGesture(mFrameElement);
+
+  return true;
+}
+
+void
+TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer)
+{
+  for (uint32_t i = 0; i < mInitialDataTransferItems.Length(); ++i) {
+    nsTArray<DataTransferItem>& itemArray = mInitialDataTransferItems[i];
+    for (uint32_t j = 0; j < itemArray.Length(); ++j) {
+      DataTransferItem& item = itemArray[j];
+      nsCOMPtr<nsIWritableVariant> variant =
+        do_CreateInstance(NS_VARIANT_CONTRACTID);
+      if (!variant) {
+        break;
+      }
+      // Special case kFilePromiseMime so that we get the right
+      // nsIFlavorDataProvider for it.
+      if (item.mFlavor.EqualsLiteral(kFilePromiseMime)) {
+        nsRefPtr<nsISupports> flavorDataProvider =
+          new nsContentAreaDragDropDataProvider();
+        variant->SetAsISupports(flavorDataProvider);
+      } else if (item.mType == DataTransferItem::DataType::eString) {
+        variant->SetAsAString(item.mStringData);
+      } else if (item.mType == DataTransferItem::DataType::eBlob) {
+        variant->SetAsISupports(item.mBlobData);
+      }
+      // Using system principal here, since once the data is on parent process
+      // side, it can be handled as being from browser chrome or OS.
+      aDataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.mFlavor),
+                                          variant, i,
+                                          nsContentUtils::GetSystemPrincipal());
+    }
+  }
+  mInitialDataTransferItems.Clear();
+}
+
+void
+TabParent::TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
+                                 int32_t& aDragAreaX, int32_t& aDragAreaY)
+{
+  aSurface = mDnDVisualization.forget();
+  aDragAreaX = mDragAreaX;
+  aDragAreaY = mDragAreaY;
+}
+
 NS_IMETHODIMP
 FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
 {
   nsAuthInformationHolder* holder =
     static_cast<nsAuthInformationHolder*>(aAuthInfo);
 
   if (!net::gNeckoChild->SendOnAuthAvailable(mCallbackId,
                                              holder->User(),
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -8,17 +8,19 @@
 #define mozilla_tabs_TabParent_h
 
 #include "js/TypeDecls.h"
 #include "mozilla/dom/ipc/IdType.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/EventForwards.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/WritingModes.h"
+#include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDOMEventListener.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsWeakReference.h"
@@ -47,21 +49,27 @@ struct TextureFactoryIdentifier;
 namespace layout {
 class RenderFrameParent;
 }
 
 namespace widget {
 struct IMENotification;
 }
 
+namespace gfx {
+class SourceSurface;
+class DataSourceSurface;
+}
+
 namespace dom {
 
 class ClonedMessageData;
 class nsIContentParent;
 class Element;
+class DataTransfer;
 struct StructuredCloneData;
 
 class TabParent final : public PBrowserParent
                       , public nsIDOMEventListener
                       , public nsITabParent
                       , public nsIAuthPromptProvider
                       , public nsISecureBrowserUI
                       , public nsSupportsWeakReference
@@ -264,16 +272,18 @@ public:
 
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
                         int32_t aButton, int32_t aClickCount,
                         int32_t aModifiers, bool aIgnoreRootScrollFrame);
     void SendKeyEvent(const nsAString& aType, int32_t aKeyCode,
                       int32_t aCharCode, int32_t aModifiers,
                       bool aPreventDefault);
     bool SendRealMouseEvent(mozilla::WidgetMouseEvent& event);
+    bool SendRealDragEvent(mozilla::WidgetDragEvent& aEvent, uint32_t aDragAction,
+                           uint32_t aDropEffect);
     bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& event);
     bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& event);
     bool SendRealTouchEvent(WidgetTouchEvent& event);
     bool SendHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
     bool SendHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId);
     bool SendHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
 
     virtual PDocumentRendererParent*
@@ -360,16 +370,28 @@ public:
     bool SendLoadRemoteScript(const nsString& aURL,
                               const bool& aRunInGlobalScope);
 
     // See nsIFrameLoader requestNotifyLayerTreeReady.
     bool RequestNotifyLayerTreeReady();
     bool RequestNotifyLayerTreeCleared();
     bool LayerTreeUpdate(bool aActive);
 
+    virtual bool
+    RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
+                          const uint32_t& aAction,
+                          const nsCString& aVisualDnDData,
+                          const uint32_t& aWidth, const uint32_t& aHeight,
+                          const uint32_t& aStride, const uint8_t& aFormat,
+                          const int32_t& aDragAreaX, const int32_t& aDragAreaY) override;
+
+    void AddInitialDnDDataTo(DataTransfer* aDataTransfer);
+
+    void TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
+                               int32_t& aDragAreaX, int32_t& aDragAreaY);
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         bool aSync,
                         const StructuredCloneData* aCloneData,
                         mozilla::jsipc::CpowHolder* aCpows,
                         nsIPrincipal* aPrincipal,
                         InfallibleTArray<nsString>* aJSONRetVal = nullptr);
 
@@ -465,16 +487,34 @@ private:
     bool mAppPackageFileDescriptorSent;
 
     // Whether we need to send the offline status to the TabChild
     // This is true, until the first call of LoadURL
     bool mSendOfflineStatus;
 
     uint32_t mChromeFlags;
 
+    struct DataTransferItem
+    {
+      nsCString mFlavor;
+      nsString mStringData;
+      nsRefPtr<mozilla::dom::FileImpl> mBlobData;
+      enum DataType
+      {
+        eString,
+        eBlob
+      };
+      DataType mType;
+    };
+    nsTArray<nsTArray<DataTransferItem>> mInitialDataTransferItems;
+
+    mozilla::RefPtr<gfx::DataSourceSurface> mDnDVisualization;
+    int32_t mDragAreaX;
+    int32_t mDragAreaY;
+
     // When true, the TabParent is initialized without child side's request.
     // When false, the TabParent is initialized by window.open() from child side.
     bool mInitedByParent;
 
     nsCOMPtr<nsILoadContext> mLoadContext;
 
     // We keep a strong reference to the frameloader after we've sent the
     // Destroy message and before we've received __delete__. This allows us to
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -131,16 +131,17 @@ LOCAL_INCLUDES += [
     '/dom/media/webspeech/synth/ipc',
     '/dom/mobilemessage/ipc',
     '/dom/storage',
     '/dom/workers',
     '/editor/libeditor',
     '/embedding/components/printingui/ipc',
     '/extensions/cookie',
     '/extensions/spellcheck/src',
+    '/gfx/2d',
     '/hal/sandbox',
     '/layout/base',
     '/netwerk/base',
     '/toolkit/xre',
     '/uriloader/exthandler',
     '/widget',
     '/xpcom/base',
     '/xpcom/threads',
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -905,17 +905,17 @@ nsDocShellTreeOwner::HandleEvent(nsIDOME
       handler->CanDropLink(dragEvent, false, &canDropLink);
       if (canDropLink)
         aEvent->PreventDefault();
     }
     else if (eventType.EqualsLiteral("drop")) {
       nsIWebNavigation* webnav = static_cast<nsIWebNavigation *>(mWebBrowser);
 
       nsAutoString link, name;
-      if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, false, name))) {
+      if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, name, true, link))) {
         if (!link.IsEmpty()) {
           webnav->LoadURI(link.get(), 0, nullptr, nullptr, nullptr);
         }
       } else {
         aEvent->StopPropagation();
         aEvent->PreventDefault();
       }
     }
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -1,14 +1,14 @@
 [DEFAULT]
 support-files = head.js
 [browser_autoscroll_disabled.js]
 skip-if = e10s # Bug ?????? - test touches content (getElementById on the content document)
 [browser_browserDrop.js]
-skip-if = buildapp == 'mulet'
+skip-if = buildapp == 'mulet' || e10s # Relies on drop to be handled in the parent process
 [browser_bug295977_autoscroll_overflow.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s
 [browser_bug594509.js]
 skip-if = e10s # Bug ?????? - intermittent crash of child process reported when run under e10s
 [browser_bug982298.js]
 skip-if = e10s # Bug 1064580
 [browser_default_image_filename.js]
 skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1255,17 +1255,19 @@
         let linkHandler = Components.classes["@mozilla.org/content/dropped-link-handler;1"].
                             getService(Components.interfaces.nsIDroppedLinkHandler);
         if (linkHandler.canDropLink(event, false))
           event.preventDefault();
       ]]>
       </handler>
       <handler event="drop" group="system">
       <![CDATA[
-        if (!this.droppedLinkHandler || event.defaultPrevented)
+        // No need to handle "drop" in e10s, since nsDocShellTreeOwner.cpp in the child process
+        // handles that case using "@mozilla.org/content/dropped-link-handler;1" service.
+        if (!this.droppedLinkHandler || event.defaultPrevented || this.isRemoteBrowser)
           return;
 
         let name = { };
         let linkHandler = Components.classes["@mozilla.org/content/dropped-link-handler;1"].
                             getService(Components.interfaces.nsIDroppedLinkHandler);
         try {
           // Pass true to prevent the dropping of javascript:/data: URIs
           var uri = linkHandler.dropLink(event, name, true);
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -301,16 +301,23 @@ public:
 };
 
 /******************************************************************************
  * mozilla::WidgetDragEvent
  ******************************************************************************/
 
 class WidgetDragEvent : public WidgetMouseEvent
 {
+private:
+  friend class mozilla::dom::PBrowserParent;
+  friend class mozilla::dom::PBrowserChild;
+protected:
+  WidgetDragEvent()
+  {
+  }
 public:
   virtual WidgetDragEvent* AsDragEvent() override { return this; }
 
   WidgetDragEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget)
     : WidgetMouseEvent(aIsTrusted, aMessage, aWidget, eDragEventClass, eReal)
     , userCancelled(false)
     , mDefaultPreventedOnContent(false)
   {
--- a/widget/gtk/nsDragService.cpp
+++ b/widget/gtk/nsDragService.cpp
@@ -480,16 +480,20 @@ nsDragService::EndDragSession(bool aDone
         if (sMotionEvent) {
             gdk_event_free(sMotionEvent);
             sMotionEvent = nullptr;
         }
     }
 
     // unset our drag action
     SetDragAction(DRAGDROP_ACTION_NONE);
+    
+    // We're done with the drag context.
+    mTargetDragContextForRemote = nullptr;
+
     return nsBaseDragService::EndDragSession(aDoneDrag);
 }
 
 // nsIDragSession
 NS_IMETHODIMP
 nsDragService::SetCanDrop(bool aCanDrop)
 {
     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::SetCanDrop %d",
@@ -1032,38 +1036,41 @@ nsDragService::IsDataFlavorSupported(con
             *_retval = true;
         }
         g_free(name);
     }
     return NS_OK;
 }
 
 void
-nsDragService::ReplyToDragMotion()
+nsDragService::ReplyToDragMotion(GdkDragContext* aDragContext)
 {
     PR_LOG(sDragLm, PR_LOG_DEBUG,
            ("nsDragService::ReplyToDragMotion %d", mCanDrop));
 
     GdkDragAction action = (GdkDragAction)0;
     if (mCanDrop) {
         // notify the dragger if we can drop
         switch (mDragAction) {
         case DRAGDROP_ACTION_COPY:
           action = GDK_ACTION_COPY;
           break;
         case DRAGDROP_ACTION_LINK:
           action = GDK_ACTION_LINK;
           break;
+        case DRAGDROP_ACTION_NONE:
+          action = (GdkDragAction)0;
+          break;
         default:
           action = GDK_ACTION_MOVE;
           break;
         }
     }
 
-    gdk_drag_status(mTargetDragContext, action, mTargetTime);
+    gdk_drag_status(aDragContext, action, mTargetTime);
 }
 
 void
 nsDragService::TargetDataReceived(GtkWidget         *aWidget,
                                   GdkDragContext    *aContext,
                                   gint               aX,
                                   gint               aY,
                                   GtkSelectionData  *aSelectionData,
@@ -1880,22 +1887,26 @@ nsDragService::RunScheduledTask()
     // When the Xdnd protocol is used for source/destination communication (as
     // should be the case with GTK source applications) a dragover event
     // should have already been sent during the drag-motion signal, which
     // would have already been received because XdndDrop messages do not
     // contain a position.  However, we can't assume the same when the Motif
     // protocol is used.
     if (task == eDragTaskMotion || positionHasChanged) {
         UpdateDragAction();
+        TakeDragEventDispatchedToChildProcess(); // Clear the old value.
         DispatchMotionEvents();
-
         if (task == eDragTaskMotion) {
-            // Reply to tell the source whether we can drop and what
-            // action would be taken.
-            ReplyToDragMotion();
+          if (TakeDragEventDispatchedToChildProcess()) {
+              mTargetDragContextForRemote = mTargetDragContext;
+          } else {
+              // Reply to tell the source whether we can drop and what
+              // action would be taken.
+              ReplyToDragMotion(mTargetDragContext);
+          }
         }
     }
 
     if (task == eDragTaskDrop) {
         gboolean success = DispatchDropEvent();
 
         // Perhaps we should set the del parameter to TRUE when the drag
         // action is move, but we don't know whether the data was successfully
@@ -1960,16 +1971,26 @@ nsDragService::UpdateDragAction()
     // copy is ctrl
     else if (gdkAction & GDK_ACTION_COPY)
         action = nsIDragService::DRAGDROP_ACTION_COPY;
 
     // update the drag information
     SetDragAction(action);
 }
 
+NS_IMETHODIMP
+nsDragService::UpdateDragEffect()
+{
+  if (mTargetDragContextForRemote) {
+    ReplyToDragMotion(mTargetDragContextForRemote);
+    mTargetDragContextForRemote = nullptr;
+  }
+  return NS_OK;
+}
+
 void
 nsDragService::DispatchMotionEvents()
 {
     mCanDrop = false;
 
     FireDragEventAtSource(NS_DRAGDROP_DRAG);
 
     mTargetWindow->
--- a/widget/gtk/nsDragService.h
+++ b/widget/gtk/nsDragService.h
@@ -70,16 +70,18 @@ public:
     NS_IMETHOD SetCanDrop            (bool             aCanDrop) override;
     NS_IMETHOD GetCanDrop            (bool            *aCanDrop) override;
     NS_IMETHOD GetNumDropItems       (uint32_t * aNumItems) override;
     NS_IMETHOD GetData               (nsITransferable * aTransferable,
                                       uint32_t aItemIndex) override;
     NS_IMETHOD IsDataFlavorSupported (const char *aDataFlavor,
                                       bool *_retval) override;
 
+     NS_IMETHOD UpdateDragEffect() override;
+
     // Methods called from nsWindow to handle responding to GTK drag
     // destination signals
 
     static nsDragService* GetInstance();
 
     void TargetDataReceived          (GtkWidget         *aWidget,
                                       GdkDragContext    *aContext,
                                       gint               aX,
@@ -156,16 +158,19 @@ private:
     // eDragTaskMotion or eDragTaskDrop task that was run or is still running.
     // mTargetWindow is cleared once the drag has completed or left.
     nsRefPtr<nsWindow> mTargetWindow;
     nsIntPoint mTargetWindowPoint;
     // mTargetWidget and mTargetDragContext are set only while dispatching
     // motion or drop events.  mTime records the corresponding timestamp.
     nsCountedRef<GtkWidget> mTargetWidget;
     nsCountedRef<GdkDragContext> mTargetDragContext;
+    // mTargetDragContextForRemote is set while waiting for a reply from
+    // a child process.
+    nsCountedRef<GdkDragContext> mTargetDragContextForRemote;
     guint           mTargetTime;
 
     // is it OK to drop on us?
     bool            mCanDrop;
 
     // have we received our drag data?
     bool            mTargetDragDataReceived;
     // last data received and its length
@@ -203,14 +208,14 @@ private:
                       GdkDragContext *aDragContext,
                       nsIntPoint aWindowPoint, guint aTime);
 
     // Callback for g_idle_add_full() to run mScheduledTask.
     static gboolean TaskDispatchCallback(gpointer data);
     gboolean RunScheduledTask();
     void UpdateDragAction();
     void DispatchMotionEvents();
-    void ReplyToDragMotion();
+    void ReplyToDragMotion(GdkDragContext* aDragContext);
     gboolean DispatchDropEvent();
 };
 
 #endif // nsDragService_h__
 
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -140,16 +140,17 @@ UNIFIED_SOURCES += [
     'InputData.cpp',
     'nsBaseAppShell.cpp',
     'nsBaseDragService.cpp',
     'nsBaseScreen.cpp',
     'nsClipboardHelper.cpp',
     'nsClipboardProxy.cpp',
     'nsColorPickerProxy.cpp',
     'nsContentProcessWidgetFactory.cpp',
+    'nsDragServiceProxy.cpp',
     'nsFilePickerProxy.cpp',
     'nsHTMLFormatConverter.cpp',
     'nsIdleService.cpp',
     'nsIWidgetListener.cpp',
     'nsPrimitiveHelpers.cpp',
     'nsPrintSession.cpp',
     'nsPrintSettingsImpl.cpp',
     'nsScreenManagerProxy.cpp',
@@ -213,16 +214,18 @@ if not CONFIG['MOZ_B2G']:
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
+    '/dom/base',
+    '/dom/ipc',
     '/layout/base',
     '/layout/forms',
     '/layout/generic',
     '/layout/xul',
     '/view',
     '/widget',
 ]
 
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -31,31 +31,35 @@
 #include "ImageRegion.h"
 #include "nsRegion.h"
 #include "nsXULPopupManager.h"
 #include "nsMenuPopupFrame.h"
 #include "SVGImageContext.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/unused.h"
+#include "nsFrameLoader.h"
+#include "TabParent.h"
 
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 
 #define DRAGIMAGES_PREF "nglayout.enable_drag_images"
 
 nsBaseDragService::nsBaseDragService()
   : mCanDrop(false), mOnlyChromeDrop(false), mDoingDrag(false),
     mHasImage(false), mUserCancelled(false),
+    mDragEventDispatchedToChildProcess(false),
     mDragAction(DRAGDROP_ACTION_NONE), mTargetSize(0,0),
     mImageX(0), mImageY(0), mScreenX(-1), mScreenY(-1), mSuppressLevel(0),
     mInputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE)
 {
 }
 
 nsBaseDragService::~nsBaseDragService()
 {
@@ -341,31 +345,39 @@ nsBaseDragService::EndDragSession(bool a
 
   if (mDragPopup) {
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     if (pm) {
       pm->HidePopup(mDragPopup, false, true, false, false);
     }
   }
 
+  for (uint32_t i = 0; i < mChildProcesses.Length(); ++i) {
+    mozilla::unused << mChildProcesses[i]->SendEndDragSession(aDoneDrag,
+                                                              mUserCancelled);
+  }
+  mChildProcesses.Clear();
+
   mDoingDrag = false;
+  mCanDrop = false;
 
   // release the source we've been holding on to.
   mSourceDocument = nullptr;
   mSourceNode = nullptr;
   mSelection = nullptr;
   mDataTransfer = nullptr;
   mHasImage = false;
   mUserCancelled = false;
   mDragPopup = nullptr;
   mImage = nullptr;
   mImageX = 0;
   mImageY = 0;
   mScreenX = -1;
   mScreenY = -1;
+  mEndDragPoint = nsIntPoint(0, 0);
   mInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseDragService::FireDragEventAtSource(uint32_t aMsg)
 {
@@ -451,16 +463,44 @@ nsBaseDragService::DrawDrag(nsIDOMNode* 
   nsIPresShell* presShell = GetPresShellForContent(dragNode);
   if (!presShell && mImage)
     presShell = GetPresShellForContent(aDOMNode);
   if (!presShell)
     return NS_ERROR_FAILURE;
 
   *aPresContext = presShell->GetPresContext();
 
+  nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(dragNode);
+  if (flo) {
+    nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
+    if (fl) {
+      mozilla::dom::TabParent* tp =
+        static_cast<mozilla::dom::TabParent*>(fl->GetRemoteBrowser());
+      if (tp) {
+        int32_t x, y;
+        tp->TakeDragVisualization(*aSurface, x, y);
+        if (*aSurface) {
+          if (mImage) {
+            // Just clear the surface if chrome has overridden it with an image.
+            *aSurface = nullptr;
+          } else {
+            nsIFrame* f = fl->GetOwnerContent()->GetPrimaryFrame();
+            if (f) {
+              aScreenDragRect->x = x;
+              aScreenDragRect->y = y;
+              aScreenDragRect->width = (*aSurface)->GetSize().width;
+              aScreenDragRect->height = (*aSurface)->GetSize().height;
+            }
+            return NS_OK;
+          }
+        }
+      }
+    }
+  }
+
   // convert mouse position to dev pixels of the prescontext
   int32_t sx = aScreenX, sy = aScreenY;
   ConvertToUnscaledDevPixels(*aPresContext, &sx, &sy);
 
   aScreenDragRect->x = sx - mImageX;
   aScreenDragRect->y = sy - mImageY;
 
   // check if drag images are disabled
@@ -664,8 +704,38 @@ nsBaseDragService::Suppress()
 }
 
 NS_IMETHODIMP
 nsBaseDragService::Unsuppress()
 {
   --mSuppressLevel;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsBaseDragService::UserCancelled()
+{
+  mUserCancelled = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBaseDragService::UpdateDragEffect()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBaseDragService::DragEventDispatchedToChildProcess()
+{
+  mDragEventDispatchedToChildProcess = true;
+  return NS_OK;
+}
+
+bool
+nsBaseDragService::MaybeAddChildProcess(mozilla::dom::ContentParent* aChild)
+{
+  if (!mChildProcesses.Contains(aChild)) {
+    mChildProcesses.AppendElement(aChild);
+    return true;
+  }
+  return false;
+}
--- a/widget/nsBaseDragService.h
+++ b/widget/nsBaseDragService.h
@@ -10,17 +10,19 @@
 #include "nsIDragSession.h"
 #include "nsITransferable.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDataTransfer.h"
 #include "nsCOMPtr.h"
 #include "nsRect.h"
 #include "nsPoint.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
+#include "nsTArray.h"
 
 // translucency level for drag images
 #define DRAG_TRANSLUCENCY 0.65
 
 class nsIContent;
 class nsIDOMNode;
 class nsIFrame;
 class nsPresContext;
@@ -107,24 +109,35 @@ protected:
   ConvertToUnscaledDevPixels(nsPresContext* aPresContext,
                              int32_t* aScreenX, int32_t* aScreenY);
 
   /**
    * If the drag image is a popup, open the popup when the drag begins.
    */
   void OpenDragPopup();
 
+  // Returns true if a drag event was dispatched to a child process after
+  // the previous TakeDragEventDispatchedToChildProcess() call.
+  bool TakeDragEventDispatchedToChildProcess()
+  {
+    bool retval = mDragEventDispatchedToChildProcess;
+    mDragEventDispatchedToChildProcess = false;
+    return retval;
+  }
+
   bool mCanDrop;
   bool mOnlyChromeDrop;
   bool mDoingDrag;
   // true if mImage should be used to set a drag image
   bool mHasImage;
   // true if the user cancelled the drag operation
   bool mUserCancelled;
 
+  bool mDragEventDispatchedToChildProcess;
+
   uint32_t mDragAction;
   nsSize mTargetSize;
   nsCOMPtr<nsIDOMNode> mSourceNode;
   nsCOMPtr<nsIDOMDocument> mSourceDocument;       // the document at the drag source. will be null
                                                   //  if it came from outside the app.
   nsCOMPtr<nsIDOMDataTransfer> mDataTransfer;
 
   // used to determine the image to appear on the cursor while dragging
@@ -148,11 +161,13 @@ protected:
 
   // the screen position where the drag ended
   nsIntPoint mEndDragPoint;
 
   uint32_t mSuppressLevel;
 
   // The input source of the drag event. Possible values are from nsIDOMMouseEvent.
   uint16_t mInputSource;
+
+  nsTArray<nsRefPtr<mozilla::dom::ContentParent>> mChildProcesses;
 };
 
 #endif // nsBaseDragService_h__
--- a/widget/nsContentProcessWidgetFactory.cpp
+++ b/widget/nsContentProcessWidgetFactory.cpp
@@ -4,50 +4,56 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ModuleUtils.h"
 #include "nsWidgetsCID.h"
 #include "nsClipboardProxy.h"
 #include "nsColorPickerProxy.h"
+#include "nsDragServiceProxy.h"
 #include "nsFilePickerProxy.h"
 #include "nsScreenManagerProxy.h"
 
 using namespace mozilla;
 
 #ifndef MOZ_B2G
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsColorPickerProxy)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragServiceProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePickerProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerProxy)
 
 NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID);
 NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID);
+NS_DEFINE_NAMED_CID(NS_DRAGSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
 NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID);
 
 static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
     { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_COLORPICKER_CID, false, nullptr, nsColorPickerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
+    { &kNS_DRAGSERVICE_CID, false, nullptr, nsDragServiceProxyConstructor,
+      Module::CONTENT_PROCESS_ONLY },
     { &kNS_FILEPICKER_CID, false, nullptr, nsFilePickerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
     { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, Module::CONTENT_PROCESS_ONLY },
+    { "@mozilla.org/widget/dragservice;1", &kNS_DRAGSERVICE_CID, Module::CONTENT_PROCESS_ONLY },
     { nullptr }
 };
 
 static const mozilla::Module kWidgetModule = {
     mozilla::Module::kVersion,
     kWidgetCIDs,
     kWidgetContracts
 };
new file mode 100644
--- /dev/null
+++ b/widget/nsDragServiceProxy.cpp
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDragServiceProxy.h"
+#include "nsIDocument.h"
+#include "nsISupportsPrimitives.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/unused.h"
+#include "nsContentUtils.h"
+
+NS_IMPL_ISUPPORTS_INHERITED0(nsDragServiceProxy, nsBaseDragService)
+
+nsDragServiceProxy::nsDragServiceProxy()
+{
+}
+
+nsDragServiceProxy::~nsDragServiceProxy()
+{
+}
+
+NS_IMETHODIMP
+nsDragServiceProxy::InvokeDragSession(nsIDOMNode* aDOMNode,
+                                      nsISupportsArray* aArrayTransferables,
+                                      nsIScriptableRegion* aRegion,
+                                      uint32_t aActionType)
+{
+  nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
+                                                     aArrayTransferables,
+                                                     aRegion,
+                                                     aActionType);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIDOMDocument> sourceDocument;
+  aDOMNode->GetOwnerDocument(getter_AddRefs(sourceDocument));
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(sourceDocument);
+  NS_ENSURE_STATE(doc->GetDocShell());
+  mozilla::dom::TabChild* child =
+    mozilla::dom::TabChild::GetFrom(doc->GetDocShell());
+  NS_ENSURE_STATE(child);
+  nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers;
+  nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables,
+                                                  dataTransfers,
+                                                  child->Manager(),
+                                                  nullptr);
+
+  if (mHasImage || mSelection) {
+    nsIntRect dragRect;
+    nsPresContext* pc;
+    mozilla::RefPtr<mozilla::gfx::SourceSurface> surface;
+    DrawDrag(mSourceNode, aRegion, mScreenX, mScreenY,
+             &dragRect, &surface, &pc);
+
+    if (surface) {
+      mozilla::RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
+        surface->GetDataSurface();
+      mozilla::gfx::DataSourceSurface::MappedSurface map;
+      dataSurface->Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map);
+      mozilla::gfx::IntSize size = dataSurface->GetSize();
+      mozilla::CheckedInt32 requiredBytes =
+        mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height);
+      size_t bufLen = requiredBytes.isValid() ? requiredBytes.value() : 0;
+      mozilla::gfx::SurfaceFormat format = dataSurface->GetFormat();
+      // Surface data handling is totally nuts. This is the magic one needs to
+      // know to access the data.
+      bufLen = bufLen - map.mStride + (size.width * BytesPerPixel(format));
+      nsDependentCString dragImage(reinterpret_cast<char*>(map.mData), bufLen);
+      mozilla::unused <<
+        child->SendInvokeDragSession(dataTransfers, aActionType, dragImage,
+                                     size.width, size.height, map.mStride,
+                                     static_cast<uint8_t>(format),
+                                     dragRect.x, dragRect.y);
+      dataSurface->Unmap();
+      StartDragSession();
+      return NS_OK;
+    }
+  }
+
+  mozilla::unused << child->SendInvokeDragSession(dataTransfers, aActionType,
+                                                  nsCString(),
+                                                  0, 0, 0, 0, 0, 0);
+  StartDragSession();
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/widget/nsDragServiceProxy.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef NSDRAGSERVICEPROXY_H
+#define NSDRAGSERVICEPROXY_H
+
+#include "nsBaseDragService.h"
+
+class nsDragServiceProxy : public nsBaseDragService
+{
+public:
+  nsDragServiceProxy();
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDragService
+  NS_IMETHOD InvokeDragSession(nsIDOMNode* aDOMNode,
+                               nsISupportsArray* anArrayTransferables,
+                               nsIScriptableRegion* aRegion,
+                               uint32_t aActionType);
+private:
+  virtual ~nsDragServiceProxy();
+};
+
+#endif // NSDRAGSERVICEPROXY_H
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -210,16 +210,39 @@ struct ParamTraits<mozilla::WidgetMouseE
       static_cast<mozilla::WidgetMouseEvent::reasonType>(reason);
     aResult->context =
       static_cast<mozilla::WidgetMouseEvent::contextType>(context);
     aResult->exit = static_cast<mozilla::WidgetMouseEvent::exitType>(exit);
     return rv;
   }
 };
 
+
+template<>
+struct ParamTraits<mozilla::WidgetDragEvent>
+{
+  typedef mozilla::WidgetDragEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam));
+    WriteParam(aMsg, aParam.userCancelled);
+    WriteParam(aMsg, aParam.mDefaultPreventedOnContent);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    bool rv =
+      ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEvent*>(aResult)) &&
+      ReadParam(aMsg, aIter, &aResult->userCancelled) &&
+      ReadParam(aMsg, aIter, &aResult->mDefaultPreventedOnContent);
+    return rv;
+  }
+};
+
 template<>
 struct ParamTraits<mozilla::WidgetPointerEvent>
 {
   typedef mozilla::WidgetPointerEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam));
--- a/widget/nsIDragService.idl
+++ b/widget/nsIDragService.idl
@@ -10,17 +10,27 @@
 #include "nsIScriptableRegion.idl"
 
 
 interface nsIDOMNode;
 interface nsIDOMDragEvent;
 interface nsIDOMDataTransfer;
 interface nsISelection;
 
-[scriptable, uuid(82B58ADA-F490-4C3D-B737-1057C4F1D052), builtinclass]
+%{C++
+namespace mozilla {
+namespace dom {
+class ContentParent;
+} // namespace dom
+} // namespace mozilla
+%}
+
+[ptr] native ContentParentPtr(mozilla::dom::ContentParent);
+
+[scriptable, uuid(009d4489-4568-4896-9442-19717dd00f15), builtinclass]
 interface nsIDragService : nsISupports
 {
   const long DRAGDROP_ACTION_NONE = 0;
   const long DRAGDROP_ACTION_COPY = 1;
   const long DRAGDROP_ACTION_MOVE = 2;
   const long DRAGDROP_ACTION_LINK = 4;
   const long DRAGDROP_ACTION_UNINITIALIZED = 64;
 
@@ -109,14 +119,16 @@ interface nsIDragService : nsISupports
   /**
    * Increase/decrease dragging suppress level by one.
    * If level is greater than one, dragging is disabled.
    */
   void suppress();
   void unsuppress();
 
   [noscript] void dragMoved(in long aX, in long aY);
+
+  [notxpcom, nostdcall] boolean maybeAddChildProcess(in ContentParentPtr aChild);
 };
 
 
 %{ C++
 
 %}
--- a/widget/nsIDragSession.idl
+++ b/widget/nsIDragSession.idl
@@ -14,17 +14,17 @@
 
 native nsSize (nsSize);
 
 
 interface nsIDOMDocument;
 interface nsIDOMNode;
 interface nsIDOMDataTransfer;
 
-[scriptable, uuid(fde41f6a-c710-46f8-a0a8-1ff76ca4ff57)]
+[scriptable, uuid(25bce737-73f0-43c7-bc20-c71044a73c5a)]
 interface nsIDragSession : nsISupports
 {
   /**
     * Set the current state of the drag, whether it can be dropped or not.
     * usually the target "frame" sets this so the native system can render the correct feedback
     */
   attribute boolean canDrop;
 
@@ -75,15 +75,23 @@ interface nsIDragSession : nsISupports
     * @param  aItemIndex which of multiple drag items, zero-based
     */
   void getData ( in nsITransferable aTransferable, in unsigned long aItemIndex ) ;
 
    /**
     * Check to set if any of the native data on the clipboard matches this data flavor
     */
   boolean isDataFlavorSupported ( in string aDataFlavor ) ;
-  
+
+  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();
 };
 
 
 %{ C++
 
 %}
--- a/widget/nsPrintSettingsImpl.cpp
+++ b/widget/nsPrintSettingsImpl.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrintSettingsImpl.h"
 #include "nsReadableUtils.h"
 #include "nsIPrintSession.h"
+#include "nsRefPtr.h"
 
 #define DEFAULT_MARGIN_WIDTH 0.5
 
 NS_IMPL_ISUPPORTS(nsPrintSettings, nsIPrintSettings)
 
 /** ---------------------------------------------------
  *  See documentation in nsPrintSettingsImpl.h
  *	@update 6/21/00 dwc