LCOV - code coverage report
Current view: top level - widget - nsBaseDragService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 9 373 2.4 %
Date: 2017-07-14 16:53:18 Functions: 5 41 12.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsBaseDragService.h"
       7             : #include "nsITransferable.h"
       8             : 
       9             : #include "nsIServiceManager.h"
      10             : #include "nsITransferable.h"
      11             : #include "nsSize.h"
      12             : #include "nsXPCOM.h"
      13             : #include "nsISupportsPrimitives.h"
      14             : #include "nsCOMPtr.h"
      15             : #include "nsIInterfaceRequestorUtils.h"
      16             : #include "nsIFrame.h"
      17             : #include "nsIDocument.h"
      18             : #include "nsIContent.h"
      19             : #include "nsIPresShell.h"
      20             : #include "nsViewManager.h"
      21             : #include "nsIDOMNode.h"
      22             : #include "nsIDOMDragEvent.h"
      23             : #include "nsISelection.h"
      24             : #include "nsISelectionPrivate.h"
      25             : #include "nsPresContext.h"
      26             : #include "nsIDOMDataTransfer.h"
      27             : #include "nsIImageLoadingContent.h"
      28             : #include "imgIContainer.h"
      29             : #include "imgIRequest.h"
      30             : #include "ImageRegion.h"
      31             : #include "nsRegion.h"
      32             : #include "nsXULPopupManager.h"
      33             : #include "nsMenuPopupFrame.h"
      34             : #include "SVGImageContext.h"
      35             : #include "mozilla/MouseEvents.h"
      36             : #include "mozilla/Preferences.h"
      37             : #include "mozilla/dom/DataTransferItemList.h"
      38             : #include "mozilla/gfx/2D.h"
      39             : #include "mozilla/Unused.h"
      40             : #include "nsFrameLoader.h"
      41             : #include "TabParent.h"
      42             : 
      43             : #include "gfxContext.h"
      44             : #include "gfxPlatform.h"
      45             : #include <algorithm>
      46             : 
      47             : using namespace mozilla;
      48             : using namespace mozilla::dom;
      49             : using namespace mozilla::gfx;
      50             : using namespace mozilla::image;
      51             : 
      52             : #define DRAGIMAGES_PREF "nglayout.enable_drag_images"
      53             : 
      54           1 : nsBaseDragService::nsBaseDragService()
      55             :   : mCanDrop(false), mOnlyChromeDrop(false), mDoingDrag(false),
      56             :     mHasImage(false), mUserCancelled(false),
      57             :     mDragEventDispatchedToChildProcess(false),
      58             :     mDragAction(DRAGDROP_ACTION_NONE),
      59             :     mDragActionFromChildProcess(DRAGDROP_ACTION_UNINITIALIZED), mTargetSize(0,0),
      60             :     mContentPolicyType(nsIContentPolicy::TYPE_OTHER),
      61           1 :     mSuppressLevel(0), mInputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE)
      62             : {
      63           1 : }
      64             : 
      65             : nsBaseDragService::~nsBaseDragService() = default;
      66             : 
      67          23 : NS_IMPL_ISUPPORTS(nsBaseDragService, nsIDragService, nsIDragSession)
      68             : 
      69             : //---------------------------------------------------------
      70             : NS_IMETHODIMP
      71           0 : nsBaseDragService::SetCanDrop(bool aCanDrop)
      72             : {
      73           0 :   mCanDrop = aCanDrop;
      74           0 :   return NS_OK;
      75             : }
      76             : 
      77             : //---------------------------------------------------------
      78             : NS_IMETHODIMP
      79           0 : nsBaseDragService::GetCanDrop(bool * aCanDrop)
      80             : {
      81           0 :   *aCanDrop = mCanDrop;
      82           0 :   return NS_OK;
      83             : }
      84             : //---------------------------------------------------------
      85             : NS_IMETHODIMP
      86           0 : nsBaseDragService::SetOnlyChromeDrop(bool aOnlyChrome)
      87             : {
      88           0 :   mOnlyChromeDrop = aOnlyChrome;
      89           0 :   return NS_OK;
      90             : }
      91             : 
      92             : //---------------------------------------------------------
      93             : NS_IMETHODIMP
      94           0 : nsBaseDragService::GetOnlyChromeDrop(bool* aOnlyChrome)
      95             : {
      96           0 :   *aOnlyChrome = mOnlyChromeDrop;
      97           0 :   return NS_OK;
      98             : }
      99             : 
     100             : //---------------------------------------------------------
     101             : NS_IMETHODIMP
     102           0 : nsBaseDragService::SetDragAction(uint32_t anAction)
     103             : {
     104           0 :   mDragAction = anAction;
     105           0 :   return NS_OK;
     106             : }
     107             : 
     108             : //---------------------------------------------------------
     109             : NS_IMETHODIMP
     110           0 : nsBaseDragService::GetDragAction(uint32_t * anAction)
     111             : {
     112           0 :   *anAction = mDragAction;
     113           0 :   return NS_OK;
     114             : }
     115             : 
     116             : //---------------------------------------------------------
     117             : NS_IMETHODIMP
     118           0 : nsBaseDragService::SetTargetSize(nsSize aDragTargetSize)
     119             : {
     120           0 :   mTargetSize = aDragTargetSize;
     121           0 :   return NS_OK;
     122             : }
     123             : 
     124             : //---------------------------------------------------------
     125             : NS_IMETHODIMP
     126           0 : nsBaseDragService::GetTargetSize(nsSize * aDragTargetSize)
     127             : {
     128           0 :   *aDragTargetSize = mTargetSize;
     129           0 :   return NS_OK;
     130             : }
     131             : 
     132             : //-------------------------------------------------------------------------
     133             : 
     134             : NS_IMETHODIMP
     135           0 : nsBaseDragService::GetNumDropItems(uint32_t * aNumItems)
     136             : {
     137           0 :   *aNumItems = 0;
     138           0 :   return NS_ERROR_FAILURE;
     139             : }
     140             : 
     141             : 
     142             : //
     143             : // GetSourceDocument
     144             : //
     145             : // Returns the DOM document where the drag was initiated. This will be
     146             : // nullptr if the drag began outside of our application.
     147             : //
     148             : NS_IMETHODIMP
     149           0 : nsBaseDragService::GetSourceDocument(nsIDOMDocument** aSourceDocument)
     150             : {
     151           0 :   *aSourceDocument = mSourceDocument.get();
     152           0 :   NS_IF_ADDREF(*aSourceDocument);
     153             : 
     154           0 :   return NS_OK;
     155             : }
     156             : 
     157             : //
     158             : // GetSourceNode
     159             : //
     160             : // Returns the DOM node where the drag was initiated. This will be
     161             : // nullptr if the drag began outside of our application.
     162             : //
     163             : NS_IMETHODIMP
     164           0 : nsBaseDragService::GetSourceNode(nsIDOMNode** aSourceNode)
     165             : {
     166           0 :   *aSourceNode = mSourceNode.get();
     167           0 :   NS_IF_ADDREF(*aSourceNode);
     168             : 
     169           0 :   return NS_OK;
     170             : }
     171             : 
     172             : 
     173             : //-------------------------------------------------------------------------
     174             : 
     175             : NS_IMETHODIMP
     176           0 : nsBaseDragService::GetData(nsITransferable * aTransferable,
     177             :                            uint32_t aItemIndex)
     178             : {
     179           0 :   return NS_ERROR_FAILURE;
     180             : }
     181             : 
     182             : //-------------------------------------------------------------------------
     183             : NS_IMETHODIMP
     184           0 : nsBaseDragService::IsDataFlavorSupported(const char *aDataFlavor,
     185             :                                          bool *_retval)
     186             : {
     187           0 :   return NS_ERROR_FAILURE;
     188             : }
     189             : 
     190             : NS_IMETHODIMP
     191           0 : nsBaseDragService::GetDataTransfer(nsIDOMDataTransfer** aDataTransfer)
     192             : {
     193           0 :   *aDataTransfer = mDataTransfer;
     194           0 :   NS_IF_ADDREF(*aDataTransfer);
     195           0 :   return NS_OK;
     196             : }
     197             : 
     198             : NS_IMETHODIMP
     199           0 : nsBaseDragService::SetDataTransfer(nsIDOMDataTransfer* aDataTransfer)
     200             : {
     201           0 :   mDataTransfer = aDataTransfer;
     202           0 :   return NS_OK;
     203             : }
     204             : 
     205             : //-------------------------------------------------------------------------
     206             : NS_IMETHODIMP
     207           0 : nsBaseDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
     208             :                                      nsIArray* aTransferableArray,
     209             :                                      nsIScriptableRegion* aDragRgn,
     210             :                                      uint32_t aActionType,
     211             :                                      nsContentPolicyType aContentPolicyType =
     212             :                                        nsIContentPolicy::TYPE_OTHER)
     213             : {
     214           0 :   AUTO_PROFILER_LABEL("nsBaseDragService::InvokeDragSession", OTHER);
     215             : 
     216           0 :   NS_ENSURE_TRUE(aDOMNode, NS_ERROR_INVALID_ARG);
     217           0 :   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
     218             : 
     219             :   // stash the document of the dom node
     220           0 :   aDOMNode->GetOwnerDocument(getter_AddRefs(mSourceDocument));
     221           0 :   mSourceNode = aDOMNode;
     222           0 :   mContentPolicyType = aContentPolicyType;
     223           0 :   mEndDragPoint = LayoutDeviceIntPoint(0, 0);
     224             : 
     225             :   // When the mouse goes down, the selection code starts a mouse
     226             :   // capture. However, this gets in the way of determining drag
     227             :   // feedback for things like trees because the event coordinates
     228             :   // are in the wrong coord system, so turn off mouse capture.
     229           0 :   nsIPresShell::ClearMouseCapture(nullptr);
     230             : 
     231             :   nsresult rv = InvokeDragSessionImpl(aTransferableArray,
     232           0 :                                       aDragRgn, aActionType);
     233             : 
     234           0 :   if (NS_FAILED(rv)) {
     235           0 :     mSourceNode = nullptr;
     236           0 :     mSourceDocument = nullptr;
     237             :   }
     238             : 
     239           0 :   return rv;
     240             : }
     241             : 
     242             : NS_IMETHODIMP
     243           0 : nsBaseDragService::InvokeDragSessionWithImage(nsIDOMNode* aDOMNode,
     244             :                                               nsIArray* aTransferableArray,
     245             :                                               nsIScriptableRegion* aRegion,
     246             :                                               uint32_t aActionType,
     247             :                                               nsIDOMNode* aImage,
     248             :                                               int32_t aImageX, int32_t aImageY,
     249             :                                               nsIDOMDragEvent* aDragEvent,
     250             :                                               nsIDOMDataTransfer* aDataTransfer)
     251             : {
     252           0 :   NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER);
     253           0 :   NS_ENSURE_TRUE(aDataTransfer, NS_ERROR_NULL_POINTER);
     254           0 :   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
     255             : 
     256           0 :   mDataTransfer = aDataTransfer;
     257           0 :   mSelection = nullptr;
     258           0 :   mHasImage = true;
     259           0 :   mDragPopup = nullptr;
     260           0 :   mImage = aImage;
     261           0 :   mImageOffset = CSSIntPoint(aImageX, aImageY);
     262             : 
     263           0 :   aDragEvent->GetScreenX(&mScreenPosition.x);
     264           0 :   aDragEvent->GetScreenY(&mScreenPosition.y);
     265           0 :   aDragEvent->GetMozInputSource(&mInputSource);
     266             : 
     267             :   nsresult rv = InvokeDragSession(aDOMNode, aTransferableArray,
     268             :                                   aRegion, aActionType,
     269           0 :                                   nsIContentPolicy::TYPE_INTERNAL_IMAGE);
     270             : 
     271           0 :   if (NS_FAILED(rv)) {
     272           0 :     mImage = nullptr;
     273           0 :     mHasImage = false;
     274           0 :     mDataTransfer = nullptr;
     275             :   }
     276             : 
     277           0 :   return rv;
     278             : }
     279             : 
     280             : NS_IMETHODIMP
     281           0 : nsBaseDragService::InvokeDragSessionWithSelection(nsISelection* aSelection,
     282             :                                                   nsIArray* aTransferableArray,
     283             :                                                   uint32_t aActionType,
     284             :                                                   nsIDOMDragEvent* aDragEvent,
     285             :                                                   nsIDOMDataTransfer* aDataTransfer)
     286             : {
     287           0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
     288           0 :   NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER);
     289           0 :   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
     290             : 
     291           0 :   mDataTransfer = aDataTransfer;
     292           0 :   mSelection = aSelection;
     293           0 :   mHasImage = true;
     294           0 :   mDragPopup = nullptr;
     295           0 :   mImage = nullptr;
     296           0 :   mImageOffset = CSSIntPoint();
     297             : 
     298           0 :   aDragEvent->GetScreenX(&mScreenPosition.x);
     299           0 :   aDragEvent->GetScreenY(&mScreenPosition.y);
     300           0 :   aDragEvent->GetMozInputSource(&mInputSource);
     301             : 
     302             :   // just get the focused node from the selection
     303             :   // XXXndeakin this should actually be the deepest node that contains both
     304             :   // endpoints of the selection
     305           0 :   nsCOMPtr<nsIDOMNode> node;
     306           0 :   aSelection->GetFocusNode(getter_AddRefs(node));
     307             : 
     308           0 :   nsresult rv = InvokeDragSession(node, aTransferableArray,
     309             :                                   nullptr, aActionType,
     310           0 :                                   nsIContentPolicy::TYPE_OTHER);
     311             : 
     312           0 :   if (NS_FAILED(rv)) {
     313           0 :     mHasImage = false;
     314           0 :     mSelection = nullptr;
     315           0 :     mDataTransfer = nullptr;
     316             :   }
     317             : 
     318           0 :   return rv;
     319             : }
     320             : 
     321             : //-------------------------------------------------------------------------
     322             : NS_IMETHODIMP
     323           6 : nsBaseDragService::GetCurrentSession(nsIDragSession ** aSession)
     324             : {
     325           6 :   if (!aSession)
     326           0 :     return NS_ERROR_INVALID_ARG;
     327             : 
     328             :   // "this" also implements a drag session, so say we are one but only
     329             :   // if there is currently a drag going on.
     330           6 :   if (!mSuppressLevel && mDoingDrag) {
     331           0 :     *aSession = this;
     332           0 :     NS_ADDREF(*aSession);      // addRef because we're a "getter"
     333             :   }
     334             :   else
     335           6 :     *aSession = nullptr;
     336             : 
     337           6 :   return NS_OK;
     338             : }
     339             : 
     340             : //-------------------------------------------------------------------------
     341             : NS_IMETHODIMP
     342           0 : nsBaseDragService::StartDragSession()
     343             : {
     344           0 :   if (mDoingDrag) {
     345           0 :     return NS_ERROR_FAILURE;
     346             :   }
     347           0 :   mDoingDrag = true;
     348             :   // By default dispatch drop also to content.
     349           0 :   mOnlyChromeDrop = false;
     350             : 
     351           0 :   return NS_OK;
     352             : }
     353             : 
     354             : void
     355           0 : nsBaseDragService::OpenDragPopup()
     356             : {
     357           0 :   if (mDragPopup) {
     358           0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     359           0 :     if (pm) {
     360           0 :       pm->ShowPopupAtScreen(mDragPopup, mScreenPosition.x - mImageOffset.x,
     361           0 :                             mScreenPosition.y - mImageOffset.y, false, nullptr);
     362             :     }
     363             :   }
     364           0 : }
     365             : 
     366             : int32_t
     367           0 : nsBaseDragService::TakeChildProcessDragAction()
     368             : {
     369             :   // If the last event was dispatched to the child process, use the drag action
     370             :   // assigned from it instead and return it. DRAGDROP_ACTION_UNINITIALIZED is
     371             :   // returned otherwise.
     372           0 :   int32_t retval = DRAGDROP_ACTION_UNINITIALIZED;
     373           0 :   if (TakeDragEventDispatchedToChildProcess() &&
     374           0 :       mDragActionFromChildProcess != DRAGDROP_ACTION_UNINITIALIZED) {
     375           0 :     retval = mDragActionFromChildProcess;
     376             :   }
     377             : 
     378           0 :   return retval;
     379             : }
     380             : 
     381             : //-------------------------------------------------------------------------
     382             : NS_IMETHODIMP
     383           0 : nsBaseDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers)
     384             : {
     385           0 :   if (!mDoingDrag) {
     386           0 :     return NS_ERROR_FAILURE;
     387             :   }
     388             : 
     389           0 :   if (aDoneDrag && !mSuppressLevel) {
     390           0 :     FireDragEventAtSource(eDragEnd, aKeyModifiers);
     391             :   }
     392             : 
     393           0 :   if (mDragPopup) {
     394           0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     395           0 :     if (pm) {
     396           0 :       pm->HidePopup(mDragPopup, false, true, false, false);
     397             :     }
     398             :   }
     399             : 
     400           0 :   for (uint32_t i = 0; i < mChildProcesses.Length(); ++i) {
     401           0 :     mozilla::Unused << mChildProcesses[i]->SendEndDragSession(aDoneDrag,
     402             :                                                               mUserCancelled,
     403             :                                                               mEndDragPoint,
     404             :                                                               aKeyModifiers);
     405             :   }
     406           0 :   mChildProcesses.Clear();
     407             : 
     408             :   // mDataTransfer and the items it owns are going to die anyway, but we
     409             :   // explicitly deref the contained data here so that we don't have to wait for
     410             :   // CC to reclaim the memory.
     411           0 :   if (XRE_IsParentProcess()) {
     412           0 :     DiscardInternalTransferData();
     413             :   }
     414             : 
     415           0 :   mDoingDrag = false;
     416           0 :   mCanDrop = false;
     417             : 
     418             :   // release the source we've been holding on to.
     419           0 :   mSourceDocument = nullptr;
     420           0 :   mSourceNode = nullptr;
     421           0 :   mSelection = nullptr;
     422           0 :   mDataTransfer = nullptr;
     423           0 :   mHasImage = false;
     424           0 :   mUserCancelled = false;
     425           0 :   mDragPopup = nullptr;
     426           0 :   mImage = nullptr;
     427           0 :   mImageOffset = CSSIntPoint();
     428           0 :   mScreenPosition = CSSIntPoint();
     429           0 :   mEndDragPoint = LayoutDeviceIntPoint(0, 0);
     430           0 :   mInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
     431             : 
     432           0 :   return NS_OK;
     433             : }
     434             : 
     435             : void
     436           0 : nsBaseDragService::DiscardInternalTransferData()
     437             : {
     438           0 :   if (mDataTransfer && mSourceNode) {
     439           0 :     MOZ_ASSERT(!!DataTransfer::Cast(mDataTransfer));
     440             : 
     441           0 :     DataTransferItemList* items = DataTransfer::Cast(mDataTransfer)->Items();
     442           0 :     for (size_t i = 0; i < items->Length(); i++) {
     443             :       bool found;
     444           0 :       DataTransferItem* item = items->IndexedGetter(i, found);
     445             : 
     446             :       // Non-OTHER items may still be needed by JS. Skip them.
     447           0 :       if (!found || item->Kind() != DataTransferItem::KIND_OTHER) {
     448           0 :         continue;
     449             :       }
     450             : 
     451           0 :       nsCOMPtr<nsIVariant> variant = item->DataNoSecurityCheck();
     452           0 :       nsCOMPtr<nsIWritableVariant> writable = do_QueryInterface(variant);
     453             : 
     454           0 :       if (writable) {
     455           0 :         writable->SetAsEmpty();
     456             :       }
     457             :     }
     458             :   }
     459           0 : }
     460             : 
     461             : NS_IMETHODIMP
     462           0 : nsBaseDragService::FireDragEventAtSource(EventMessage aEventMessage,
     463             :                                          uint32_t aKeyModifiers)
     464             : {
     465           0 :   if (mSourceNode && !mSuppressLevel) {
     466           0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
     467           0 :     if (doc) {
     468           0 :       nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
     469           0 :       if (presShell) {
     470           0 :         nsEventStatus status = nsEventStatus_eIgnore;
     471           0 :         WidgetDragEvent event(true, aEventMessage, nullptr);
     472           0 :         event.inputSource = mInputSource;
     473           0 :         if (aEventMessage == eDragEnd) {
     474           0 :           event.mRefPoint = mEndDragPoint;
     475           0 :           event.mUserCancelled = mUserCancelled;
     476             :         }
     477           0 :         event.mModifiers = aKeyModifiers;
     478             :         // Send the drag event to APZ, which needs to know about them to be
     479             :         // able to accurately detect the end of a drag gesture.
     480           0 :         if (nsPresContext* presContext = presShell->GetPresContext()) {
     481           0 :           if (nsCOMPtr<nsIWidget> widget = presContext->GetRootWidget()) {
     482           0 :             widget->DispatchEventToAPZOnly(&event);
     483             :           }
     484             :         }
     485             : 
     486           0 :         nsCOMPtr<nsIContent> content = do_QueryInterface(mSourceNode);
     487           0 :         return presShell->HandleDOMEventWithTarget(content, &event, &status);
     488             :       }
     489             :     }
     490             :   }
     491             : 
     492           0 :   return NS_OK;
     493             : }
     494             : 
     495             : /* This is used by Windows and Mac to update the position of a popup being
     496             :  * used as a drag image during the drag. This isn't used on GTK as it manages
     497             :  * the drag popup itself.
     498             :  */
     499             : NS_IMETHODIMP
     500           0 : nsBaseDragService::DragMoved(int32_t aX, int32_t aY)
     501             : {
     502           0 :   if (mDragPopup) {
     503           0 :     nsIFrame* frame = mDragPopup->GetPrimaryFrame();
     504           0 :     if (frame && frame->IsMenuPopupFrame()) {
     505           0 :       CSSIntPoint cssPos = RoundedToInt(LayoutDeviceIntPoint(aX, aY) /
     506           0 :           frame->PresContext()->CSSToDevPixelScale()) - mImageOffset;
     507           0 :       (static_cast<nsMenuPopupFrame *>(frame))->MoveTo(cssPos, true);
     508             :     }
     509             :   }
     510             : 
     511           0 :   return NS_OK;
     512             : }
     513             : 
     514             : static nsIPresShell*
     515           0 : GetPresShellForContent(nsIDOMNode* aDOMNode)
     516             : {
     517           0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aDOMNode);
     518           0 :   if (!content)
     519           0 :     return nullptr;
     520             : 
     521           0 :   nsCOMPtr<nsIDocument> document = content->GetUncomposedDoc();
     522           0 :   if (document) {
     523           0 :     document->FlushPendingNotifications(FlushType::Display);
     524             : 
     525           0 :     return document->GetShell();
     526             :   }
     527             : 
     528           0 :   return nullptr;
     529             : }
     530             : 
     531             : nsresult
     532           0 : nsBaseDragService::DrawDrag(nsIDOMNode* aDOMNode,
     533             :                             nsIScriptableRegion* aRegion,
     534             :                             CSSIntPoint aScreenPosition,
     535             :                             LayoutDeviceIntRect* aScreenDragRect,
     536             :                             RefPtr<SourceSurface>* aSurface,
     537             :                             nsPresContext** aPresContext)
     538             : {
     539           0 :   *aSurface = nullptr;
     540           0 :   *aPresContext = nullptr;
     541             : 
     542             :   // use a default size, in case of an error.
     543           0 :   aScreenDragRect->MoveTo(aScreenPosition.x - mImageOffset.x,
     544           0 :                           aScreenPosition.y - mImageOffset.y);
     545           0 :   aScreenDragRect->SizeTo(1, 1);
     546             : 
     547             :   // if a drag image was specified, use that, otherwise, use the source node
     548           0 :   nsCOMPtr<nsIDOMNode> dragNode = mImage ? mImage.get() : aDOMNode;
     549             : 
     550             :   // get the presshell for the node being dragged. If the drag image is not in
     551             :   // a document or has no frame, get the presshell from the source drag node
     552           0 :   nsIPresShell* presShell = GetPresShellForContent(dragNode);
     553           0 :   if (!presShell && mImage)
     554           0 :     presShell = GetPresShellForContent(aDOMNode);
     555           0 :   if (!presShell)
     556           0 :     return NS_ERROR_FAILURE;
     557             : 
     558           0 :   *aPresContext = presShell->GetPresContext();
     559             : 
     560           0 :   nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(dragNode);
     561           0 :   if (flo) {
     562           0 :     RefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
     563           0 :     if (fl) {
     564           0 :       auto* tp = static_cast<mozilla::dom::TabParent*>(fl->GetRemoteBrowser());
     565           0 :       if (tp && tp->TakeDragVisualization(*aSurface, aScreenDragRect)) {
     566           0 :         if (mImage) {
     567             :           // Just clear the surface if chrome has overridden it with an image.
     568           0 :           *aSurface = nullptr;
     569             :         }
     570             : 
     571           0 :         return NS_OK;
     572             :       }
     573             :     }
     574             :   }
     575             : 
     576             :   // convert mouse position to dev pixels of the prescontext
     577           0 :   CSSIntPoint screenPosition(aScreenPosition);
     578           0 :   screenPosition.x -= mImageOffset.x;
     579           0 :   screenPosition.y -= mImageOffset.y;
     580           0 :   LayoutDeviceIntPoint screenPoint = ConvertToUnscaledDevPixels(*aPresContext, screenPosition);
     581           0 :   aScreenDragRect->x = screenPoint.x;
     582           0 :   aScreenDragRect->y = screenPoint.y;
     583             : 
     584             :   // check if drag images are disabled
     585           0 :   bool enableDragImages = Preferences::GetBool(DRAGIMAGES_PREF, true);
     586             : 
     587             :   // didn't want an image, so just set the screen rectangle to the frame size
     588           0 :   if (!enableDragImages || !mHasImage) {
     589             :     // if a region was specified, set the screen rectangle to the area that
     590             :     // the region occupies
     591           0 :     CSSIntRect dragRect;
     592           0 :     if (aRegion) {
     593             :       // the region's coordinates are relative to the root frame
     594           0 :       aRegion->GetBoundingBox(&dragRect.x, &dragRect.y, &dragRect.width, &dragRect.height);
     595             : 
     596           0 :       nsIFrame* rootFrame = presShell->GetRootFrame();
     597           0 :       CSSIntRect screenRect = rootFrame->GetScreenRect();
     598           0 :       dragRect.MoveBy(screenRect.TopLeft());
     599             :     }
     600             :     else {
     601             :       // otherwise, there was no region so just set the rectangle to
     602             :       // the size of the primary frame of the content.
     603           0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(dragNode);
     604           0 :       nsIFrame* frame = content->GetPrimaryFrame();
     605           0 :       if (frame) {
     606           0 :         dragRect = frame->GetScreenRect();
     607             :       }
     608             :     }
     609             : 
     610             :     nsIntRect dragRectDev =
     611           0 :       ToAppUnits(dragRect, nsPresContext::AppUnitsPerCSSPixel()).
     612           0 :       ToOutsidePixels((*aPresContext)->AppUnitsPerDevPixel());
     613           0 :     aScreenDragRect->SizeTo(dragRectDev.width, dragRectDev.height);
     614           0 :     return NS_OK;
     615             :   }
     616             : 
     617             :   // draw the image for selections
     618           0 :   if (mSelection) {
     619           0 :     LayoutDeviceIntPoint pnt(aScreenDragRect->TopLeft());
     620           0 :     *aSurface = presShell->RenderSelection(mSelection, pnt, aScreenDragRect,
     621           0 :         mImage ? 0 : nsIPresShell::RENDER_AUTO_SCALE);
     622           0 :     return NS_OK;
     623             :   }
     624             : 
     625             :   // if a custom image was specified, check if it is an image node and draw
     626             :   // using the source rather than the displayed image. But if mImage isn't
     627             :   // an image or canvas, fall through to RenderNode below.
     628           0 :   if (mImage) {
     629           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(dragNode);
     630           0 :     HTMLCanvasElement *canvas = HTMLCanvasElement::FromContentOrNull(content);
     631           0 :     if (canvas) {
     632           0 :       return DrawDragForImage(*aPresContext, nullptr, canvas, aScreenDragRect, aSurface);
     633             :     }
     634             : 
     635           0 :     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(dragNode);
     636             :     // for image nodes, create the drag image from the actual image data
     637           0 :     if (imageLoader) {
     638           0 :       return DrawDragForImage(*aPresContext, imageLoader, nullptr, aScreenDragRect, aSurface);
     639             :     }
     640             : 
     641             :     // If the image is a popup, use that as the image. This allows custom drag
     642             :     // images that can change during the drag, but means that any platform
     643             :     // default image handling won't occur.
     644             :     // XXXndeakin this should be chrome-only
     645             : 
     646           0 :     nsIFrame* frame = content->GetPrimaryFrame();
     647           0 :     if (frame && frame->IsMenuPopupFrame()) {
     648           0 :       mDragPopup = content;
     649             :     }
     650             :   }
     651             : 
     652           0 :   if (!mDragPopup) {
     653             :     // otherwise, just draw the node
     654           0 :     nsIntRegion clipRegion;
     655           0 :     uint32_t renderFlags = mImage ? 0 : nsIPresShell::RENDER_AUTO_SCALE;
     656           0 :     if (aRegion) {
     657           0 :       aRegion->GetRegion(&clipRegion);
     658             :     }
     659             : 
     660           0 :     if (renderFlags) {
     661           0 :       nsCOMPtr<nsIDOMNode> child;
     662           0 :       nsCOMPtr<nsIDOMNodeList> childList;
     663             :       uint32_t length;
     664           0 :       uint32_t count = 0;
     665           0 :       nsAutoString childNodeName;
     666             : 
     667           0 :       if (NS_SUCCEEDED(dragNode->GetChildNodes(getter_AddRefs(childList))) &&
     668           0 :           NS_SUCCEEDED(childList->GetLength(&length))) {
     669             :         // check every childnode for being a img-tag
     670           0 :         while (count < length) {
     671           0 :           if (NS_FAILED(childList->Item(count, getter_AddRefs(child))) ||
     672           0 :               NS_FAILED(child->GetNodeName(childNodeName))) {
     673           0 :             break;
     674             :           }
     675             :           // here the node is checked for being a img-tag
     676           0 :           if (childNodeName.LowerCaseEqualsLiteral("img")) {
     677             :             // if the dragnnode contains a image, set RENDER_IS_IMAGE flag
     678           0 :             renderFlags = renderFlags | nsIPresShell::RENDER_IS_IMAGE;
     679           0 :             break;
     680             :           }
     681           0 :           count++;
     682             :         }
     683             :       }
     684             :     }
     685           0 :     LayoutDeviceIntPoint pnt(aScreenDragRect->TopLeft());
     686           0 :     *aSurface = presShell->RenderNode(dragNode, aRegion ? &clipRegion : nullptr,
     687             :                                       pnt, aScreenDragRect,
     688           0 :                                       renderFlags);
     689             :   }
     690             : 
     691             :   // If an image was specified, reset the position from the offset that was supplied.
     692           0 :   if (mImage) {
     693           0 :     aScreenDragRect->x = screenPoint.x;
     694           0 :     aScreenDragRect->y = screenPoint.y;
     695             :   }
     696             : 
     697           0 :   return NS_OK;
     698             : }
     699             : 
     700             : nsresult
     701           0 : nsBaseDragService::DrawDragForImage(nsPresContext* aPresContext,
     702             :                                     nsIImageLoadingContent* aImageLoader,
     703             :                                     HTMLCanvasElement* aCanvas,
     704             :                                     LayoutDeviceIntRect* aScreenDragRect,
     705             :                                     RefPtr<SourceSurface>* aSurface)
     706             : {
     707           0 :   nsCOMPtr<imgIContainer> imgContainer;
     708           0 :   if (aImageLoader) {
     709           0 :     nsCOMPtr<imgIRequest> imgRequest;
     710           0 :     nsresult rv = aImageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
     711           0 :                                           getter_AddRefs(imgRequest));
     712           0 :     NS_ENSURE_SUCCESS(rv, rv);
     713           0 :     if (!imgRequest)
     714           0 :       return NS_ERROR_NOT_AVAILABLE;
     715             : 
     716           0 :     rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
     717           0 :     NS_ENSURE_SUCCESS(rv, rv);
     718           0 :     if (!imgContainer)
     719           0 :       return NS_ERROR_NOT_AVAILABLE;
     720             : 
     721             :     // use the size of the image as the size of the drag image
     722             :     int32_t imageWidth, imageHeight;
     723           0 :     rv = imgContainer->GetWidth(&imageWidth);
     724           0 :     NS_ENSURE_SUCCESS(rv, rv);
     725             : 
     726           0 :     rv = imgContainer->GetHeight(&imageHeight);
     727           0 :     NS_ENSURE_SUCCESS(rv, rv);
     728             : 
     729           0 :     aScreenDragRect->width = aPresContext->CSSPixelsToDevPixels(imageWidth);
     730           0 :     aScreenDragRect->height = aPresContext->CSSPixelsToDevPixels(imageHeight);
     731             :   }
     732             :   else {
     733             :     // XXX The canvas size should be converted to dev pixels.
     734           0 :     NS_ASSERTION(aCanvas, "both image and canvas are null");
     735           0 :     nsIntSize sz = aCanvas->GetSize();
     736           0 :     aScreenDragRect->width = sz.width;
     737           0 :     aScreenDragRect->height = sz.height;
     738             :   }
     739             : 
     740           0 :   nsIntSize destSize;
     741           0 :   destSize.width = aScreenDragRect->width;
     742           0 :   destSize.height = aScreenDragRect->height;
     743           0 :   if (destSize.width == 0 || destSize.height == 0)
     744           0 :     return NS_ERROR_FAILURE;
     745             : 
     746           0 :   nsresult result = NS_OK;
     747           0 :   if (aImageLoader) {
     748             :     RefPtr<DrawTarget> dt =
     749             :       gfxPlatform::GetPlatform()->
     750           0 :         CreateOffscreenContentDrawTarget(destSize,
     751           0 :                                          SurfaceFormat::B8G8R8A8);
     752           0 :     if (!dt || !dt->IsValid())
     753           0 :       return NS_ERROR_FAILURE;
     754             : 
     755           0 :     RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
     756           0 :     if (!ctx)
     757           0 :       return NS_ERROR_FAILURE;
     758             : 
     759             :     DrawResult res =
     760           0 :       imgContainer->Draw(ctx, destSize, ImageRegion::Create(destSize),
     761             :                          imgIContainer::FRAME_CURRENT,
     762           0 :                          SamplingFilter::GOOD, /* no SVGImageContext */ Nothing(),
     763           0 :                          imgIContainer::FLAG_SYNC_DECODE, 1.0);
     764           0 :     if (res == DrawResult::BAD_IMAGE || res == DrawResult::BAD_ARGS) {
     765           0 :       return NS_ERROR_FAILURE;
     766             :     }
     767           0 :     *aSurface = dt->Snapshot();
     768             :   } else {
     769           0 :     *aSurface = aCanvas->GetSurfaceSnapshot();
     770             :   }
     771             : 
     772           0 :   return result;
     773             : }
     774             : 
     775             : LayoutDeviceIntPoint
     776           0 : nsBaseDragService::ConvertToUnscaledDevPixels(nsPresContext* aPresContext,
     777             :                                               CSSIntPoint aScreenPosition)
     778             : {
     779           0 :   int32_t adj = aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
     780           0 :   return LayoutDeviceIntPoint(nsPresContext::CSSPixelsToAppUnits(aScreenPosition.x) / adj,
     781           0 :                               nsPresContext::CSSPixelsToAppUnits(aScreenPosition.y) / adj);
     782             : }
     783             : 
     784             : NS_IMETHODIMP
     785           0 : nsBaseDragService::Suppress()
     786             : {
     787           0 :   EndDragSession(false, 0);
     788           0 :   ++mSuppressLevel;
     789           0 :   return NS_OK;
     790             : }
     791             : 
     792             : NS_IMETHODIMP
     793           0 : nsBaseDragService::Unsuppress()
     794             : {
     795           0 :   --mSuppressLevel;
     796           0 :   return NS_OK;
     797             : }
     798             : 
     799             : NS_IMETHODIMP
     800           0 : nsBaseDragService::UserCancelled()
     801             : {
     802           0 :   mUserCancelled = true;
     803           0 :   return NS_OK;
     804             : }
     805             : 
     806             : NS_IMETHODIMP
     807           0 : nsBaseDragService::UpdateDragEffect()
     808             : {
     809           0 :   mDragActionFromChildProcess = mDragAction;
     810           0 :   return NS_OK;
     811             : }
     812             : 
     813             : NS_IMETHODIMP
     814           0 : nsBaseDragService::UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY)
     815             : {
     816             :   // Don't change the image if this is a drag from another source or if there
     817             :   // is a drag popup.
     818           0 :   if (!mSourceNode || mDragPopup)
     819           0 :     return NS_OK;
     820             : 
     821           0 :   mImage = aImage;
     822           0 :   mImageOffset = CSSIntPoint(aImageX, aImageY);
     823           0 :   return NS_OK;
     824             : }
     825             : 
     826             : NS_IMETHODIMP
     827           0 : nsBaseDragService::DragEventDispatchedToChildProcess()
     828             : {
     829           0 :   mDragEventDispatchedToChildProcess = true;
     830           0 :   return NS_OK;
     831             : }
     832             : 
     833             : bool
     834           0 : nsBaseDragService::MaybeAddChildProcess(mozilla::dom::ContentParent* aChild)
     835             : {
     836           0 :   if (!mChildProcesses.Contains(aChild)) {
     837           0 :     mChildProcesses.AppendElement(aChild);
     838           0 :     return true;
     839             :   }
     840           0 :   return false;
     841             : }

Generated by: LCOV version 1.13