Bug 1295272 - Discard internal DataTransferItem data in nsBaseDragService::EndDragSession. r=enndeakin, a=jcristau
authorEdwin Flores <eflores@mozilla.com>
Mon, 28 Nov 2016 11:39:22 +0000
changeset 352803 5e17b3d541189991000429d69b22d80d0f6f716f
parent 352802 df4d31969686336bdfbc6d4fe876af5bc4619183
child 352804 d59e82481c869123324aa0f25fb03f3dd9c60aad
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenndeakin, jcristau
bugs1295272
milestone52.0a2
Bug 1295272 - Discard internal DataTransferItem data in nsBaseDragService::EndDragSession. r=enndeakin, a=jcristau
widget/nsBaseDragService.cpp
widget/nsBaseDragService.h
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -29,16 +29,17 @@
 #include "imgIRequest.h"
 #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/dom/DataTransferItemList.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/Unused.h"
 #include "nsFrameLoader.h"
 #include "TabParent.h"
 
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include <algorithm>
@@ -400,16 +401,23 @@ nsBaseDragService::EndDragSession(bool a
 
   for (uint32_t i = 0; i < mChildProcesses.Length(); ++i) {
     mozilla::Unused << mChildProcesses[i]->SendEndDragSession(aDoneDrag,
                                                               mUserCancelled,
                                                               mEndDragPoint);
   }
   mChildProcesses.Clear();
 
+  // mDataTransfer and the items it owns are going to die anyway, but we
+  // explicitly deref the contained data here so that we don't have to wait for
+  // CC to reclaim the memory.
+  if (XRE_IsParentProcess()) {
+    DiscardInternalTransferData();
+  }
+
   mDoingDrag = false;
   mCanDrop = false;
 
   // release the source we've been holding on to.
   mSourceDocument = nullptr;
   mSourceNode = nullptr;
   mSelection = nullptr;
   mDataTransfer = nullptr;
@@ -420,16 +428,42 @@ nsBaseDragService::EndDragSession(bool a
   mImageOffset = CSSIntPoint();
   mScreenPosition = CSSIntPoint();
   mEndDragPoint = LayoutDeviceIntPoint(0, 0);
   mInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
 
   return NS_OK;
 }
 
+void
+nsBaseDragService::DiscardInternalTransferData()
+{
+  if (mDataTransfer && mSourceNode) {
+    MOZ_ASSERT(!!DataTransfer::Cast(mDataTransfer));
+
+    DataTransferItemList* items = DataTransfer::Cast(mDataTransfer)->Items();
+    for (size_t i = 0; i < items->Length(); i++) {
+      bool found;
+      DataTransferItem* item = items->IndexedGetter(i, found);
+
+      // Non-OTHER items may still be needed by JS. Skip them.
+      if (!found || item->Kind() != DataTransferItem::KIND_OTHER) {
+        continue;
+      }
+
+      nsCOMPtr<nsIVariant> variant = item->DataNoSecurityCheck();
+      nsCOMPtr<nsIWritableVariant> writable = do_QueryInterface(variant);
+
+      if (writable) {
+        writable->SetAsEmpty();
+      }
+    }
+  }
+}
+
 NS_IMETHODIMP
 nsBaseDragService::FireDragEventAtSource(EventMessage aEventMessage)
 {
   if (mSourceNode && !mSuppressLevel) {
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
     if (doc) {
       nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
       if (presShell) {
--- a/widget/nsBaseDragService.h
+++ b/widget/nsBaseDragService.h
@@ -125,16 +125,21 @@ protected:
   ConvertToUnscaledDevPixels(nsPresContext* aPresContext,
                              mozilla::CSSIntPoint aScreenPosition);
 
   /**
    * If the drag image is a popup, open the popup when the drag begins.
    */
   void OpenDragPopup();
 
+  /**
+   * Free resources contained in DataTransferItems that aren't needed by JS.
+   */
+  void DiscardInternalTransferData();
+
   // 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;
   }