LCOV - code coverage report
Current view: directory - widget/xpwidgets - nsBaseDragService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 296 0 0.0 %
Date: 2012-06-02 Functions: 36 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsBaseDragService.h"
      40                 : #include "nsITransferable.h"
      41                 : 
      42                 : #include "nsIServiceManager.h"
      43                 : #include "nsITransferable.h"
      44                 : #include "nsISupportsArray.h"
      45                 : #include "nsSize.h"
      46                 : #include "nsXPCOM.h"
      47                 : #include "nsISupportsPrimitives.h"
      48                 : #include "nsCOMPtr.h"
      49                 : #include "nsIInterfaceRequestorUtils.h"
      50                 : #include "nsIFrame.h"
      51                 : #include "nsIDocument.h"
      52                 : #include "nsIContent.h"
      53                 : #include "nsIPresShell.h"
      54                 : #include "nsIViewManager.h"
      55                 : #include "nsIDOMNode.h"
      56                 : #include "nsIDOMDragEvent.h"
      57                 : #include "nsISelection.h"
      58                 : #include "nsISelectionPrivate.h"
      59                 : #include "nsPresContext.h"
      60                 : #include "nsIDOMDataTransfer.h"
      61                 : #include "nsICanvasElementExternal.h"
      62                 : #include "nsIImageLoadingContent.h"
      63                 : #include "imgIContainer.h"
      64                 : #include "imgIRequest.h"
      65                 : #include "nsRegion.h"
      66                 : #include "nsGUIEvent.h"
      67                 : #include "nsXULPopupManager.h"
      68                 : #include "nsMenuPopupFrame.h"
      69                 : #include "mozilla/Preferences.h"
      70                 : 
      71                 : #include "gfxContext.h"
      72                 : #include "gfxPlatform.h"
      73                 : 
      74                 : using namespace mozilla;
      75                 : 
      76                 : #define DRAGIMAGES_PREF "nglayout.enable_drag_images"
      77                 : 
      78               0 : nsBaseDragService::nsBaseDragService()
      79                 :   : mCanDrop(false), mOnlyChromeDrop(false), mDoingDrag(false),
      80                 :     mHasImage(false), mUserCancelled(false),
      81                 :     mDragAction(DRAGDROP_ACTION_NONE), mTargetSize(0,0),
      82                 :     mImageX(0), mImageY(0), mScreenX(-1), mScreenY(-1), mSuppressLevel(0),
      83               0 :     mInputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE)
      84                 : {
      85               0 : }
      86                 : 
      87               0 : nsBaseDragService::~nsBaseDragService()
      88                 : {
      89               0 : }
      90                 : 
      91               0 : NS_IMPL_ISUPPORTS2(nsBaseDragService, nsIDragService, nsIDragSession)
      92                 : 
      93                 : //---------------------------------------------------------
      94                 : NS_IMETHODIMP
      95               0 : nsBaseDragService::SetCanDrop(bool aCanDrop)
      96                 : {
      97               0 :   mCanDrop = aCanDrop;
      98               0 :   return NS_OK;
      99                 : }
     100                 : 
     101                 : //---------------------------------------------------------
     102                 : NS_IMETHODIMP
     103               0 : nsBaseDragService::GetCanDrop(bool * aCanDrop)
     104                 : {
     105               0 :   *aCanDrop = mCanDrop;
     106               0 :   return NS_OK;
     107                 : }
     108                 : //---------------------------------------------------------
     109                 : NS_IMETHODIMP
     110               0 : nsBaseDragService::SetOnlyChromeDrop(bool aOnlyChrome)
     111                 : {
     112               0 :   mOnlyChromeDrop = aOnlyChrome;
     113               0 :   return NS_OK;
     114                 : }
     115                 : 
     116                 : //---------------------------------------------------------
     117                 : NS_IMETHODIMP
     118               0 : nsBaseDragService::GetOnlyChromeDrop(bool* aOnlyChrome)
     119                 : {
     120               0 :   *aOnlyChrome = mOnlyChromeDrop;
     121               0 :   return NS_OK;
     122                 : }
     123                 : 
     124                 : //---------------------------------------------------------
     125                 : NS_IMETHODIMP
     126               0 : nsBaseDragService::SetDragAction(PRUint32 anAction)
     127                 : {
     128               0 :   mDragAction = anAction;
     129               0 :   return NS_OK;
     130                 : }
     131                 : 
     132                 : //---------------------------------------------------------
     133                 : NS_IMETHODIMP
     134               0 : nsBaseDragService::GetDragAction(PRUint32 * anAction)
     135                 : {
     136               0 :   *anAction = mDragAction;
     137               0 :   return NS_OK;
     138                 : }
     139                 : 
     140                 : //---------------------------------------------------------
     141                 : NS_IMETHODIMP
     142               0 : nsBaseDragService::SetTargetSize(nsSize aDragTargetSize)
     143                 : {
     144               0 :   mTargetSize = aDragTargetSize;
     145               0 :   return NS_OK;
     146                 : }
     147                 : 
     148                 : //---------------------------------------------------------
     149                 : NS_IMETHODIMP
     150               0 : nsBaseDragService::GetTargetSize(nsSize * aDragTargetSize)
     151                 : {
     152               0 :   *aDragTargetSize = mTargetSize;
     153               0 :   return NS_OK;
     154                 : }
     155                 : 
     156                 : //-------------------------------------------------------------------------
     157                 : 
     158                 : NS_IMETHODIMP
     159               0 : nsBaseDragService::GetNumDropItems(PRUint32 * aNumItems)
     160                 : {
     161               0 :   *aNumItems = 0;
     162               0 :   return NS_ERROR_FAILURE;
     163                 : }
     164                 : 
     165                 : 
     166                 : //
     167                 : // GetSourceDocument
     168                 : //
     169                 : // Returns the DOM document where the drag was initiated. This will be
     170                 : // nsnull if the drag began outside of our application.
     171                 : //
     172                 : NS_IMETHODIMP
     173               0 : nsBaseDragService::GetSourceDocument(nsIDOMDocument** aSourceDocument)
     174                 : {
     175               0 :   *aSourceDocument = mSourceDocument.get();
     176               0 :   NS_IF_ADDREF(*aSourceDocument);
     177                 : 
     178               0 :   return NS_OK;
     179                 : }
     180                 : 
     181                 : //
     182                 : // GetSourceNode
     183                 : //
     184                 : // Returns the DOM node where the drag was initiated. This will be
     185                 : // nsnull if the drag began outside of our application.
     186                 : //
     187                 : NS_IMETHODIMP
     188               0 : nsBaseDragService::GetSourceNode(nsIDOMNode** aSourceNode)
     189                 : {
     190               0 :   *aSourceNode = mSourceNode.get();
     191               0 :   NS_IF_ADDREF(*aSourceNode);
     192                 : 
     193               0 :   return NS_OK;
     194                 : }
     195                 : 
     196                 : 
     197                 : //-------------------------------------------------------------------------
     198                 : 
     199                 : NS_IMETHODIMP
     200               0 : nsBaseDragService::GetData(nsITransferable * aTransferable,
     201                 :                            PRUint32 aItemIndex)
     202                 : {
     203               0 :   return NS_ERROR_FAILURE;
     204                 : }
     205                 : 
     206                 : //-------------------------------------------------------------------------
     207                 : NS_IMETHODIMP
     208               0 : nsBaseDragService::IsDataFlavorSupported(const char *aDataFlavor,
     209                 :                                          bool *_retval)
     210                 : {
     211               0 :   return NS_ERROR_FAILURE;
     212                 : }
     213                 : 
     214                 : NS_IMETHODIMP
     215               0 : nsBaseDragService::GetDataTransfer(nsIDOMDataTransfer** aDataTransfer)
     216                 : {
     217               0 :   *aDataTransfer = mDataTransfer;
     218               0 :   NS_IF_ADDREF(*aDataTransfer);
     219               0 :   return NS_OK;
     220                 : }
     221                 : 
     222                 : NS_IMETHODIMP
     223               0 : nsBaseDragService::SetDataTransfer(nsIDOMDataTransfer* aDataTransfer)
     224                 : {
     225               0 :   mDataTransfer = aDataTransfer;
     226               0 :   return NS_OK;
     227                 : }
     228                 : 
     229                 : //-------------------------------------------------------------------------
     230                 : NS_IMETHODIMP
     231               0 : nsBaseDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
     232                 :                                      nsISupportsArray* aTransferableArray,
     233                 :                                      nsIScriptableRegion* aDragRgn,
     234                 :                                      PRUint32 aActionType)
     235                 : {
     236               0 :   NS_ENSURE_TRUE(aDOMNode, NS_ERROR_INVALID_ARG);
     237               0 :   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
     238                 : 
     239                 :   // stash the document of the dom node
     240               0 :   aDOMNode->GetOwnerDocument(getter_AddRefs(mSourceDocument));
     241               0 :   mSourceNode = aDOMNode;
     242               0 :   mEndDragPoint = nsIntPoint(0, 0);
     243                 : 
     244                 :   // When the mouse goes down, the selection code starts a mouse
     245                 :   // capture. However, this gets in the way of determining drag
     246                 :   // feedback for things like trees because the event coordinates
     247                 :   // are in the wrong coord system, so turn off mouse capture.
     248               0 :   nsIPresShell::ClearMouseCapture(nsnull);
     249                 : 
     250               0 :   return NS_OK;
     251                 : }
     252                 : 
     253                 : NS_IMETHODIMP
     254               0 : nsBaseDragService::InvokeDragSessionWithImage(nsIDOMNode* aDOMNode,
     255                 :                                               nsISupportsArray* aTransferableArray,
     256                 :                                               nsIScriptableRegion* aRegion,
     257                 :                                               PRUint32 aActionType,
     258                 :                                               nsIDOMNode* aImage,
     259                 :                                               PRInt32 aImageX, PRInt32 aImageY,
     260                 :                                               nsIDOMDragEvent* aDragEvent,
     261                 :                                               nsIDOMDataTransfer* aDataTransfer)
     262                 : {
     263               0 :   NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER);
     264               0 :   NS_ENSURE_TRUE(aDataTransfer, NS_ERROR_NULL_POINTER);
     265               0 :   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
     266                 : 
     267               0 :   mDataTransfer = aDataTransfer;
     268               0 :   mSelection = nsnull;
     269               0 :   mHasImage = true;
     270               0 :   mDragPopup = nsnull;
     271               0 :   mImage = aImage;
     272               0 :   mImageX = aImageX;
     273               0 :   mImageY = aImageY;
     274                 : 
     275               0 :   aDragEvent->GetScreenX(&mScreenX);
     276               0 :   aDragEvent->GetScreenY(&mScreenY);
     277               0 :   aDragEvent->GetMozInputSource(&mInputSource);
     278                 : 
     279               0 :   return InvokeDragSession(aDOMNode, aTransferableArray, aRegion, aActionType);
     280                 : }
     281                 : 
     282                 : NS_IMETHODIMP
     283               0 : nsBaseDragService::InvokeDragSessionWithSelection(nsISelection* aSelection,
     284                 :                                                   nsISupportsArray* aTransferableArray,
     285                 :                                                   PRUint32 aActionType,
     286                 :                                                   nsIDOMDragEvent* aDragEvent,
     287                 :                                                   nsIDOMDataTransfer* aDataTransfer)
     288                 : {
     289               0 :   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
     290               0 :   NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER);
     291               0 :   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
     292                 : 
     293               0 :   mDataTransfer = aDataTransfer;
     294               0 :   mSelection = aSelection;
     295               0 :   mHasImage = true;
     296               0 :   mDragPopup = nsnull;
     297               0 :   mImage = nsnull;
     298               0 :   mImageX = 0;
     299               0 :   mImageY = 0;
     300                 : 
     301               0 :   aDragEvent->GetScreenX(&mScreenX);
     302               0 :   aDragEvent->GetScreenY(&mScreenY);
     303               0 :   aDragEvent->GetMozInputSource(&mInputSource);
     304                 : 
     305                 :   // just get the focused node from the selection
     306                 :   // XXXndeakin this should actually be the deepest node that contains both
     307                 :   // endpoints of the selection
     308               0 :   nsCOMPtr<nsIDOMNode> node;
     309               0 :   aSelection->GetFocusNode(getter_AddRefs(node));
     310                 : 
     311               0 :   return InvokeDragSession(node, aTransferableArray, nsnull, aActionType);
     312                 : }
     313                 : 
     314                 : //-------------------------------------------------------------------------
     315                 : NS_IMETHODIMP
     316               0 : nsBaseDragService::GetCurrentSession(nsIDragSession ** aSession)
     317                 : {
     318               0 :   if (!aSession)
     319               0 :     return NS_ERROR_INVALID_ARG;
     320                 : 
     321                 :   // "this" also implements a drag session, so say we are one but only
     322                 :   // if there is currently a drag going on.
     323               0 :   if (!mSuppressLevel && mDoingDrag) {
     324               0 :     *aSession = this;
     325               0 :     NS_ADDREF(*aSession);      // addRef because we're a "getter"
     326                 :   }
     327                 :   else
     328               0 :     *aSession = nsnull;
     329                 : 
     330               0 :   return NS_OK;
     331                 : }
     332                 : 
     333                 : //-------------------------------------------------------------------------
     334                 : NS_IMETHODIMP
     335               0 : nsBaseDragService::StartDragSession()
     336                 : {
     337               0 :   if (mDoingDrag) {
     338               0 :     return NS_ERROR_FAILURE;
     339                 :   }
     340               0 :   mDoingDrag = true;
     341                 :   // By default dispatch drop also to content.
     342               0 :   mOnlyChromeDrop = false;
     343                 : 
     344               0 :   return NS_OK;
     345                 : }
     346                 : 
     347                 : void
     348               0 : nsBaseDragService::OpenDragPopup()
     349                 : {
     350               0 :   if (mDragPopup) {
     351               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     352               0 :     if (pm) {
     353               0 :       pm->ShowPopupAtScreen(mDragPopup, mScreenX - mImageX, mScreenY - mImageY, false, nsnull);
     354                 :     }
     355                 :   }
     356               0 : }
     357                 : 
     358                 : //-------------------------------------------------------------------------
     359                 : NS_IMETHODIMP
     360               0 : nsBaseDragService::EndDragSession(bool aDoneDrag)
     361                 : {
     362               0 :   if (!mDoingDrag) {
     363               0 :     return NS_ERROR_FAILURE;
     364                 :   }
     365                 : 
     366               0 :   if (aDoneDrag && !mSuppressLevel)
     367               0 :     FireDragEventAtSource(NS_DRAGDROP_END);
     368                 : 
     369               0 :   if (mDragPopup) {
     370               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     371               0 :     if (pm) {
     372               0 :       pm->HidePopup(mDragPopup, false, true, false);
     373                 :     }
     374                 :   }
     375                 : 
     376               0 :   mDoingDrag = false;
     377                 : 
     378                 :   // release the source we've been holding on to.
     379               0 :   mSourceDocument = nsnull;
     380               0 :   mSourceNode = nsnull;
     381               0 :   mSelection = nsnull;
     382               0 :   mDataTransfer = nsnull;
     383               0 :   mHasImage = false;
     384               0 :   mUserCancelled = false;
     385               0 :   mDragPopup = nsnull;
     386               0 :   mImage = nsnull;
     387               0 :   mImageX = 0;
     388               0 :   mImageY = 0;
     389               0 :   mScreenX = -1;
     390               0 :   mScreenY = -1;
     391               0 :   mInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
     392                 : 
     393               0 :   return NS_OK;
     394                 : }
     395                 : 
     396                 : NS_IMETHODIMP
     397               0 : nsBaseDragService::FireDragEventAtSource(PRUint32 aMsg)
     398                 : {
     399               0 :   if (mSourceNode && !mSuppressLevel) {
     400               0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
     401               0 :     if (doc) {
     402               0 :       nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
     403               0 :       if (presShell) {
     404               0 :         nsEventStatus status = nsEventStatus_eIgnore;
     405               0 :         nsDragEvent event(true, aMsg, nsnull);
     406               0 :         event.inputSource = mInputSource;
     407               0 :         if (aMsg == NS_DRAGDROP_END) {
     408               0 :           event.refPoint.x = mEndDragPoint.x;
     409               0 :           event.refPoint.y = mEndDragPoint.y;
     410               0 :           event.userCancelled = mUserCancelled;
     411                 :         }
     412                 : 
     413               0 :         nsCOMPtr<nsIContent> content = do_QueryInterface(mSourceNode);
     414               0 :         return presShell->HandleDOMEventWithTarget(content, &event, &status);
     415                 :       }
     416                 :     }
     417                 :   }
     418                 : 
     419               0 :   return NS_OK;
     420                 : }
     421                 : 
     422                 : /* This is used by Windows and Mac to update the position of a popup being
     423                 :  * used as a drag image during the drag. This isn't used on GTK as it manages
     424                 :  * the drag popup itself.
     425                 :  */
     426                 : NS_IMETHODIMP
     427               0 : nsBaseDragService::DragMoved(PRInt32 aX, PRInt32 aY)
     428                 : {
     429               0 :   if (mDragPopup) {
     430               0 :     nsIFrame* frame = mDragPopup->GetPrimaryFrame();
     431               0 :     if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame) {
     432               0 :       (static_cast<nsMenuPopupFrame *>(frame))->MoveTo(aX - mImageX, aY - mImageY, true);
     433                 :     }
     434                 :   }
     435                 : 
     436               0 :   return NS_OK;
     437                 : }
     438                 : 
     439                 : static nsIPresShell*
     440               0 : GetPresShellForContent(nsIDOMNode* aDOMNode)
     441                 : {
     442               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aDOMNode);
     443               0 :   if (!content)
     444               0 :     return nsnull;
     445                 : 
     446               0 :   nsCOMPtr<nsIDocument> document = content->GetCurrentDoc();
     447               0 :   if (document) {
     448               0 :     document->FlushPendingNotifications(Flush_Display);
     449                 : 
     450               0 :     return document->GetShell();
     451                 :   }
     452                 : 
     453               0 :   return nsnull;
     454                 : }
     455                 : 
     456                 : nsresult
     457               0 : nsBaseDragService::DrawDrag(nsIDOMNode* aDOMNode,
     458                 :                             nsIScriptableRegion* aRegion,
     459                 :                             PRInt32 aScreenX, PRInt32 aScreenY,
     460                 :                             nsIntRect* aScreenDragRect,
     461                 :                             gfxASurface** aSurface,
     462                 :                             nsPresContext** aPresContext)
     463                 : {
     464               0 :   *aSurface = nsnull;
     465               0 :   *aPresContext = nsnull;
     466                 : 
     467                 :   // use a default size, in case of an error.
     468               0 :   aScreenDragRect->x = aScreenX - mImageX;
     469               0 :   aScreenDragRect->y = aScreenY - mImageY;
     470               0 :   aScreenDragRect->width = 1;
     471               0 :   aScreenDragRect->height = 1;
     472                 : 
     473                 :   // if a drag image was specified, use that, otherwise, use the source node
     474               0 :   nsCOMPtr<nsIDOMNode> dragNode = mImage ? mImage.get() : aDOMNode;
     475                 : 
     476                 :   // get the presshell for the node being dragged. If the drag image is not in
     477                 :   // a document or has no frame, get the presshell from the source drag node
     478               0 :   nsIPresShell* presShell = GetPresShellForContent(dragNode);
     479               0 :   if (!presShell && mImage)
     480               0 :     presShell = GetPresShellForContent(aDOMNode);
     481               0 :   if (!presShell)
     482               0 :     return NS_ERROR_FAILURE;
     483                 : 
     484               0 :   *aPresContext = presShell->GetPresContext();
     485                 : 
     486                 :   // check if drag images are disabled
     487               0 :   bool enableDragImages = Preferences::GetBool(DRAGIMAGES_PREF, true);
     488                 : 
     489                 :   // didn't want an image, so just set the screen rectangle to the frame size
     490               0 :   if (!enableDragImages || !mHasImage) {
     491                 :     // if a region was specified, set the screen rectangle to the area that
     492                 :     // the region occupies
     493               0 :     if (aRegion) {
     494                 :       // the region's coordinates are relative to the root frame
     495               0 :       nsIFrame* rootFrame = presShell->GetRootFrame();
     496               0 :       if (rootFrame && *aPresContext) {
     497               0 :         nsIntRect dragRect;
     498               0 :         aRegion->GetBoundingBox(&dragRect.x, &dragRect.y, &dragRect.width, &dragRect.height);
     499               0 :         dragRect = dragRect.ToAppUnits(nsPresContext::AppUnitsPerCSSPixel()).
     500               0 :                             ToOutsidePixels((*aPresContext)->AppUnitsPerDevPixel());
     501                 : 
     502               0 :         nsIntRect screenRect = rootFrame->GetScreenRectExternal();
     503                 :         aScreenDragRect->SetRect(screenRect.x + dragRect.x, screenRect.y + dragRect.y,
     504               0 :                                  dragRect.width, dragRect.height);
     505                 :       }
     506                 :     }
     507                 :     else {
     508                 :       // otherwise, there was no region so just set the rectangle to
     509                 :       // the size of the primary frame of the content.
     510               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(dragNode);
     511               0 :       nsIFrame* frame = content->GetPrimaryFrame();
     512               0 :       if (frame) {
     513               0 :         nsIntRect screenRect = frame->GetScreenRectExternal();
     514                 :         aScreenDragRect->SetRect(screenRect.x, screenRect.y,
     515               0 :                                  screenRect.width, screenRect.height);
     516                 :       }
     517                 :     }
     518                 : 
     519               0 :     return NS_OK;
     520                 :   }
     521                 : 
     522                 :   // draw the image for selections
     523               0 :   if (mSelection) {
     524               0 :     nsIntPoint pnt(aScreenDragRect->x, aScreenDragRect->y);
     525               0 :     nsRefPtr<gfxASurface> surface = presShell->RenderSelection(mSelection, pnt, aScreenDragRect);
     526               0 :     *aSurface = surface;
     527               0 :     NS_IF_ADDREF(*aSurface);
     528               0 :     return NS_OK;
     529                 :   }
     530                 : 
     531                 :   // if a custom image was specified, check if it is an image node and draw
     532                 :   // using the source rather than the displayed image. But if mImage isn't
     533                 :   // an image or canvas, fall through to RenderNode below.
     534               0 :   if (mImage) {
     535               0 :     nsCOMPtr<nsICanvasElementExternal> canvas = do_QueryInterface(dragNode);
     536               0 :     if (canvas) {
     537                 :       return DrawDragForImage(*aPresContext, nsnull, canvas, aScreenX,
     538               0 :                               aScreenY, aScreenDragRect, aSurface);
     539                 :     }
     540                 : 
     541               0 :     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(dragNode);
     542                 :     // for image nodes, create the drag image from the actual image data
     543               0 :     if (imageLoader) {
     544                 :       return DrawDragForImage(*aPresContext, imageLoader, nsnull, aScreenX,
     545               0 :                               aScreenY, aScreenDragRect, aSurface);
     546                 :     }
     547                 : 
     548                 :     // If the image is a popup, use that as the image. This allows custom drag
     549                 :     // images that can change during the drag, but means that any platform
     550                 :     // default image handling won't occur.
     551                 :     // XXXndeakin this should be chrome-only
     552                 : 
     553               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(dragNode);
     554               0 :     nsIFrame* frame = content->GetPrimaryFrame();
     555               0 :     if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame) {
     556               0 :       mDragPopup = content;
     557                 :     }
     558                 :   }
     559                 : 
     560               0 :   nsRefPtr<gfxASurface> surface;
     561               0 :   if (!mDragPopup) {
     562                 :     // otherwise, just draw the node
     563               0 :     nsIntRegion clipRegion;
     564               0 :     if (aRegion) {
     565               0 :       aRegion->GetRegion(&clipRegion);
     566                 :     }
     567                 : 
     568               0 :     nsIntPoint pnt(aScreenDragRect->x, aScreenDragRect->y);
     569                 :     surface = presShell->RenderNode(dragNode, aRegion ? &clipRegion : nsnull,
     570               0 :                                     pnt, aScreenDragRect);
     571                 :   }
     572                 : 
     573                 :   // if an image was specified, reposition the drag rectangle to
     574                 :   // the supplied offset in mImageX and mImageY.
     575               0 :   if (mImage) {
     576               0 :     aScreenDragRect->x = aScreenX - mImageX;
     577               0 :     aScreenDragRect->y = aScreenY - mImageY;
     578                 :   }
     579                 : 
     580               0 :   *aSurface = surface;
     581               0 :   NS_IF_ADDREF(*aSurface);
     582                 : 
     583               0 :   return NS_OK;
     584                 : }
     585                 : 
     586                 : nsresult
     587               0 : nsBaseDragService::DrawDragForImage(nsPresContext* aPresContext,
     588                 :                                     nsIImageLoadingContent* aImageLoader,
     589                 :                                     nsICanvasElementExternal* aCanvas,
     590                 :                                     PRInt32 aScreenX, PRInt32 aScreenY,
     591                 :                                     nsIntRect* aScreenDragRect,
     592                 :                                     gfxASurface** aSurface)
     593                 : {
     594               0 :   nsCOMPtr<imgIContainer> imgContainer;
     595               0 :   if (aImageLoader) {
     596               0 :     nsCOMPtr<imgIRequest> imgRequest;
     597                 :     nsresult rv = aImageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
     598               0 :                                           getter_AddRefs(imgRequest));
     599               0 :     NS_ENSURE_SUCCESS(rv, rv);
     600               0 :     if (!imgRequest)
     601               0 :       return NS_ERROR_NOT_AVAILABLE;
     602                 : 
     603               0 :     rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
     604               0 :     NS_ENSURE_SUCCESS(rv, rv);
     605               0 :     if (!imgContainer)
     606               0 :       return NS_ERROR_NOT_AVAILABLE;
     607                 : 
     608                 :     // use the size of the image as the size of the drag image
     609               0 :     imgContainer->GetWidth(&aScreenDragRect->width);
     610               0 :     imgContainer->GetHeight(&aScreenDragRect->height);
     611                 :   }
     612                 :   else {
     613               0 :     NS_ASSERTION(aCanvas, "both image and canvas are null");
     614               0 :     nsIntSize sz = aCanvas->GetSizeExternal();
     615               0 :     aScreenDragRect->width = sz.width;
     616               0 :     aScreenDragRect->height = sz.height;
     617                 :   }
     618                 : 
     619               0 :   nsIntSize srcSize = aScreenDragRect->Size();
     620               0 :   nsIntSize destSize = srcSize;
     621                 : 
     622               0 :   if (destSize.width == 0 || destSize.height == 0)
     623               0 :     return NS_ERROR_FAILURE;
     624                 : 
     625                 :   // if the image is larger than half the screen size, scale it down. This
     626                 :   // scaling algorithm is the same as is used in nsPresShell::PaintRangePaintInfo
     627               0 :   nsDeviceContext* deviceContext = aPresContext->DeviceContext();
     628               0 :   nsRect maxSize;
     629               0 :   deviceContext->GetClientRect(maxSize);
     630               0 :   nscoord maxWidth = aPresContext->AppUnitsToDevPixels(maxSize.width >> 1);
     631               0 :   nscoord maxHeight = aPresContext->AppUnitsToDevPixels(maxSize.height >> 1);
     632               0 :   if (destSize.width > maxWidth || destSize.height > maxHeight) {
     633               0 :     float scale = 1.0;
     634               0 :     if (destSize.width > maxWidth)
     635               0 :       scale = NS_MIN(scale, float(maxWidth) / destSize.width);
     636               0 :     if (destSize.height > maxHeight)
     637               0 :       scale = NS_MIN(scale, float(maxHeight) / destSize.height);
     638                 : 
     639               0 :     destSize.width = NSToIntFloor(float(destSize.width) * scale);
     640               0 :     destSize.height = NSToIntFloor(float(destSize.height) * scale);
     641                 : 
     642               0 :     aScreenDragRect->x = NSToIntFloor(aScreenX - float(mImageX) * scale);
     643               0 :     aScreenDragRect->y = NSToIntFloor(aScreenY - float(mImageY) * scale);
     644               0 :     aScreenDragRect->width = destSize.width;
     645               0 :     aScreenDragRect->height = destSize.height;
     646                 :   }
     647                 : 
     648                 :   nsRefPtr<gfxASurface> surface =
     649               0 :     gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(destSize.width, destSize.height),
     650               0 :                                                        gfxASurface::CONTENT_COLOR_ALPHA);
     651               0 :   if (!surface)
     652               0 :     return NS_ERROR_FAILURE;
     653                 : 
     654               0 :   nsRefPtr<gfxContext> ctx = new gfxContext(surface);
     655               0 :   if (!ctx)
     656               0 :     return NS_ERROR_FAILURE;
     657                 : 
     658               0 :   *aSurface = surface;
     659               0 :   NS_ADDREF(*aSurface);
     660                 : 
     661               0 :   if (aImageLoader) {
     662               0 :     gfxRect outRect(0, 0, destSize.width, destSize.height);
     663                 :     gfxMatrix scale =
     664               0 :       gfxMatrix().Scale(srcSize.width/outRect.Width(), srcSize.height/outRect.Height());
     665               0 :     nsIntRect imgSize(0, 0, srcSize.width, srcSize.height);
     666               0 :     imgContainer->Draw(ctx, gfxPattern::FILTER_GOOD, scale, outRect, imgSize,
     667               0 :                        destSize, imgIContainer::FLAG_SYNC_DECODE);
     668               0 :     return NS_OK;
     669                 :   } else {
     670               0 :     return aCanvas->RenderContextsExternal(ctx, gfxPattern::FILTER_GOOD);
     671                 :   }
     672                 : }
     673                 : 
     674                 : void
     675               0 : nsBaseDragService::ConvertToUnscaledDevPixels(nsPresContext* aPresContext,
     676                 :                                               PRInt32* aScreenX, PRInt32* aScreenY)
     677                 : {
     678               0 :   PRInt32 adj = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
     679               0 :   *aScreenX = nsPresContext::CSSPixelsToAppUnits(*aScreenX) / adj;
     680               0 :   *aScreenY = nsPresContext::CSSPixelsToAppUnits(*aScreenY) / adj;
     681               0 : }
     682                 : 
     683                 : NS_IMETHODIMP
     684               0 : nsBaseDragService::Suppress()
     685                 : {
     686               0 :   EndDragSession(false);
     687               0 :   ++mSuppressLevel;
     688               0 :   return NS_OK;
     689                 : }
     690                 : 
     691                 : NS_IMETHODIMP
     692               0 : nsBaseDragService::Unsuppress()
     693                 : {
     694               0 :   --mSuppressLevel;
     695               0 :   return NS_OK;
     696                 : }

Generated by: LCOV version 1.7