LCOV - code coverage report
Current view: directory - content/events/src - nsDOMDataTransfer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 447 2 0.4 %
Date: 2012-06-02 Functions: 44 2 4.5 %

       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 the Mozilla Corporation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2008
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Neil Deakin <enndeakin@gmail.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "mozilla/Util.h"
      39                 : 
      40                 : #include "nsDOMDataTransfer.h"
      41                 : 
      42                 : #include "prlog.h"
      43                 : #include "nsString.h"
      44                 : #include "nsIServiceManager.h"
      45                 : #include "nsIVariant.h"
      46                 : #include "nsISupportsPrimitives.h"
      47                 : #include "nsDOMClassInfoID.h"
      48                 : #include "nsIScriptSecurityManager.h"
      49                 : #include "nsDOMLists.h"
      50                 : #include "nsGUIEvent.h"
      51                 : #include "nsDOMError.h"
      52                 : #include "nsIDragService.h"
      53                 : #include "nsIScriptableRegion.h"
      54                 : #include "nsContentUtils.h"
      55                 : #include "nsIContent.h"
      56                 : #include "nsCRT.h"
      57                 : #include "nsIScriptObjectPrincipal.h"
      58                 : 
      59                 : using namespace mozilla;
      60                 : 
      61            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMDataTransfer)
      62               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMDataTransfer)
      63               0 :   if (tmp->mFiles) {
      64               0 :     tmp->mFiles->Disconnect();
      65               0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFiles)
      66                 :   }
      67               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDragTarget)
      68               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDragImage)
      69               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      70               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMDataTransfer)
      71               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFiles)
      72               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDragTarget)
      73               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDragImage)
      74               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      75                 : 
      76               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMDataTransfer)
      77               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMDataTransfer)
      78                 : 
      79                 : DOMCI_DATA(DataTransfer, nsDOMDataTransfer)
      80                 : 
      81               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMDataTransfer)
      82               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer)
      83               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer)
      84               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DataTransfer)
      85               0 : NS_INTERFACE_MAP_END
      86                 : 
      87                 : // the size of the array
      88                 : const char nsDOMDataTransfer::sEffects[8][9] = {
      89                 :   "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
      90                 : };
      91                 : 
      92               0 : nsDOMDataTransfer::nsDOMDataTransfer()
      93                 :   : mEventType(NS_DRAGDROP_START),
      94                 :     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
      95                 :     mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED),
      96                 :     mCursorState(false),
      97                 :     mReadOnly(false),
      98                 :     mIsExternal(false),
      99                 :     mUserCancelled(false),
     100                 :     mDragImageX(0),
     101               0 :     mDragImageY(0)
     102                 : {
     103               0 : }
     104                 : 
     105               0 : nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType)
     106                 :   : mEventType(aEventType),
     107                 :     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
     108                 :     mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED),
     109                 :     mCursorState(false),
     110                 :     mReadOnly(true),
     111                 :     mIsExternal(true),
     112                 :     mUserCancelled(false),
     113                 :     mDragImageX(0),
     114               0 :     mDragImageY(0)
     115                 : {
     116               0 :   CacheExternalFormats();
     117               0 : }
     118                 : 
     119               0 : nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType,
     120                 :                                      const PRUint32 aEffectAllowed,
     121                 :                                      bool aCursorState,
     122                 :                                      bool aIsExternal,
     123                 :                                      bool aUserCancelled,
     124                 :                                      nsTArray<nsTArray<TransferItem> >& aItems,
     125                 :                                      nsIDOMElement* aDragImage,
     126                 :                                      PRUint32 aDragImageX,
     127                 :                                      PRUint32 aDragImageY)
     128                 :   : mEventType(aEventType),
     129                 :     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
     130                 :     mEffectAllowed(aEffectAllowed),
     131                 :     mCursorState(aCursorState),
     132                 :     mReadOnly(true),
     133                 :     mIsExternal(aIsExternal),
     134                 :     mUserCancelled(aUserCancelled),
     135                 :     mItems(aItems),
     136                 :     mDragImage(aDragImage),
     137                 :     mDragImageX(aDragImageX),
     138               0 :     mDragImageY(aDragImageY)
     139                 : {
     140                 :   // The items are copied from aItems into mItems. There is no need to copy
     141                 :   // the actual data in the items as the data transfer will be read only. The
     142                 :   // draggesture and dragstart events are the only times when items are
     143                 :   // modifiable, but those events should have been using the first constructor
     144                 :   // above.
     145               0 :   NS_ASSERTION(aEventType != NS_DRAGDROP_GESTURE &&
     146                 :                aEventType != NS_DRAGDROP_START,
     147                 :                "invalid event type for nsDOMDataTransfer constructor");
     148               0 : }
     149                 : 
     150                 : NS_IMETHODIMP
     151               0 : nsDOMDataTransfer::GetDropEffect(nsAString& aDropEffect)
     152                 : {
     153               0 :   aDropEffect.AssignASCII(sEffects[mDropEffect]);
     154               0 :   return NS_OK;
     155                 : }
     156                 : 
     157                 : NS_IMETHODIMP
     158               0 : nsDOMDataTransfer::SetDropEffect(const nsAString& aDropEffect)
     159                 : {
     160                 :   // the drop effect can only be 'none', 'copy', 'move' or 'link'.
     161               0 :   for (PRUint32 e = 0; e <= nsIDragService::DRAGDROP_ACTION_LINK; e++) {
     162               0 :     if (aDropEffect.EqualsASCII(sEffects[e])) {
     163                 :       // don't allow copyMove
     164               0 :       if (e != (nsIDragService::DRAGDROP_ACTION_COPY |
     165                 :                 nsIDragService::DRAGDROP_ACTION_MOVE))
     166               0 :         mDropEffect = e;
     167               0 :       break;
     168                 :     }
     169                 :   }
     170                 : 
     171               0 :   return NS_OK;
     172                 : }
     173                 : 
     174                 : NS_IMETHODIMP
     175               0 : nsDOMDataTransfer::GetEffectAllowed(nsAString& aEffectAllowed)
     176                 : {
     177               0 :   if (mEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
     178               0 :     aEffectAllowed.AssignLiteral("uninitialized");
     179                 :   else
     180               0 :     aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]);
     181               0 :   return NS_OK;
     182                 : }
     183                 : 
     184                 : NS_IMETHODIMP
     185               0 : nsDOMDataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed)
     186                 : {
     187               0 :   if (aEffectAllowed.EqualsLiteral("uninitialized")) {
     188               0 :     mEffectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
     189               0 :     return NS_OK;
     190                 :   }
     191                 : 
     192                 :   PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_NONE == 0);
     193                 :   PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_COPY == 1);
     194                 :   PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_MOVE == 2);
     195                 :   PR_STATIC_ASSERT(nsIDragService::DRAGDROP_ACTION_LINK == 4);
     196                 : 
     197               0 :   for (PRUint32 e = 0; e < ArrayLength(sEffects); e++) {
     198               0 :     if (aEffectAllowed.EqualsASCII(sEffects[e])) {
     199               0 :       mEffectAllowed = e;
     200               0 :       break;
     201                 :     }
     202                 :   }
     203                 : 
     204               0 :   return NS_OK;
     205                 : }
     206                 : 
     207                 : NS_IMETHODIMP
     208               0 : nsDOMDataTransfer::GetDropEffectInt(PRUint32* aDropEffect)
     209                 : {
     210               0 :   *aDropEffect = mDropEffect;
     211               0 :   return  NS_OK;
     212                 : }
     213                 : 
     214                 : NS_IMETHODIMP
     215               0 : nsDOMDataTransfer::SetDropEffectInt(PRUint32 aDropEffect)
     216                 : {
     217               0 :   mDropEffect = aDropEffect;
     218               0 :   return  NS_OK;
     219                 : }
     220                 : 
     221                 : NS_IMETHODIMP
     222               0 : nsDOMDataTransfer::GetEffectAllowedInt(PRUint32* aEffectAllowed)
     223                 : {
     224               0 :   *aEffectAllowed = mEffectAllowed;
     225               0 :   return  NS_OK;
     226                 : }
     227                 : 
     228                 : NS_IMETHODIMP
     229               0 : nsDOMDataTransfer::SetEffectAllowedInt(PRUint32 aEffectAllowed)
     230                 : {
     231               0 :   mEffectAllowed = aEffectAllowed;
     232               0 :   return  NS_OK;
     233                 : }
     234                 : 
     235                 : NS_IMETHODIMP
     236               0 : nsDOMDataTransfer::GetMozUserCancelled(bool* aUserCancelled)
     237                 : {
     238               0 :   *aUserCancelled = mUserCancelled;
     239               0 :   return NS_OK;
     240                 : }
     241                 : 
     242                 : NS_IMETHODIMP
     243               0 : nsDOMDataTransfer::GetFiles(nsIDOMFileList** aFileList)
     244                 : {
     245               0 :   *aFileList = nsnull;
     246                 : 
     247               0 :   if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP)
     248               0 :     return NS_OK;
     249                 : 
     250               0 :   if (!mFiles) {
     251               0 :     mFiles = new nsDOMFileList(static_cast<nsIDOMDataTransfer*>(this));
     252               0 :     NS_ENSURE_TRUE(mFiles, NS_ERROR_OUT_OF_MEMORY);
     253                 : 
     254               0 :     PRUint32 count = mItems.Length();
     255                 : 
     256               0 :     for (PRUint32 i = 0; i < count; i++) {
     257               0 :       nsCOMPtr<nsIVariant> variant;
     258               0 :       nsresult rv = MozGetDataAt(NS_ConvertUTF8toUTF16(kFileMime), i, getter_AddRefs(variant));
     259               0 :       NS_ENSURE_SUCCESS(rv, rv);
     260                 : 
     261               0 :       if (!variant)
     262               0 :         continue;
     263                 : 
     264               0 :       nsCOMPtr<nsISupports> supports;
     265               0 :       rv = variant->GetAsISupports(getter_AddRefs(supports));
     266                 : 
     267               0 :       if (NS_FAILED(rv))
     268               0 :         continue;
     269                 : 
     270               0 :       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
     271                 : 
     272               0 :       if (!file)
     273               0 :         continue;
     274                 : 
     275               0 :       nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
     276                 : 
     277               0 :       if (!mFiles->Append(domFile))
     278               0 :         return NS_ERROR_FAILURE;
     279                 :     }
     280                 :   }
     281                 : 
     282               0 :   *aFileList = mFiles;
     283               0 :   NS_ADDREF(*aFileList);
     284               0 :   return NS_OK;
     285                 : }
     286                 : 
     287                 : NS_IMETHODIMP
     288               0 : nsDOMDataTransfer::GetTypes(nsIDOMDOMStringList** aTypes)
     289                 : {
     290               0 :   *aTypes = nsnull;
     291                 : 
     292               0 :   nsRefPtr<nsDOMStringList> types = new nsDOMStringList();
     293               0 :   NS_ENSURE_TRUE(types, NS_ERROR_OUT_OF_MEMORY);
     294                 : 
     295               0 :   if (mItems.Length()) {
     296               0 :     nsTArray<TransferItem>& item = mItems[0];
     297               0 :     for (PRUint32 i = 0; i < item.Length(); i++)
     298               0 :       types->Add(item[i].mFormat);
     299                 : 
     300                 :     bool filePresent, filePromisePresent;
     301               0 :     types->Contains(NS_LITERAL_STRING(kFileMime), &filePresent);
     302               0 :     types->Contains(NS_LITERAL_STRING("application/x-moz-file-promise"), &filePromisePresent);
     303               0 :     if (filePresent || filePromisePresent)
     304               0 :       types->Add(NS_LITERAL_STRING("Files"));
     305                 :   }
     306                 : 
     307               0 :   *aTypes = types;
     308               0 :   NS_ADDREF(*aTypes);
     309                 : 
     310               0 :   return NS_OK;
     311                 : }
     312                 : 
     313                 : NS_IMETHODIMP
     314               0 : nsDOMDataTransfer::GetData(const nsAString& aFormat, nsAString& aData)
     315                 : {
     316                 :   // return an empty string if data for the format was not found
     317               0 :   aData.Truncate();
     318                 : 
     319               0 :   nsCOMPtr<nsIVariant> data;
     320               0 :   nsresult rv = MozGetDataAt(aFormat, 0, getter_AddRefs(data));
     321               0 :   if (rv == NS_ERROR_DOM_INDEX_SIZE_ERR)
     322               0 :     return NS_OK;
     323                 : 
     324               0 :   NS_ENSURE_SUCCESS(rv, rv);
     325                 : 
     326               0 :   if (data) {
     327               0 :     nsAutoString stringdata;
     328               0 :     data->GetAsAString(stringdata);
     329                 : 
     330                 :     // for the URL type, parse out the first URI from the list. The URIs are
     331                 :     // separated by newlines
     332               0 :     nsAutoString lowercaseFormat;
     333               0 :     rv = nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
     334               0 :     if (NS_FAILED(rv)) {
     335               0 :       return rv;
     336                 :     }
     337                 :     
     338               0 :     if (lowercaseFormat.EqualsLiteral("url")) {
     339               0 :       PRInt32 lastidx = 0, idx;
     340               0 :       PRInt32 length = stringdata.Length();
     341               0 :       while (lastidx < length) {
     342               0 :         idx = stringdata.FindChar('\n', lastidx);
     343                 :         // lines beginning with # are comments
     344               0 :         if (stringdata[lastidx] == '#') {
     345               0 :           if (idx == -1)
     346               0 :             break;
     347                 :         }
     348                 :         else {
     349               0 :           if (idx == -1)
     350               0 :             aData.Assign(Substring(stringdata, lastidx));
     351                 :           else
     352               0 :             aData.Assign(Substring(stringdata, lastidx, idx - lastidx));
     353               0 :           aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData, true);
     354               0 :           return NS_OK;
     355                 :         }
     356               0 :         lastidx = idx + 1;
     357                 :       }
     358                 :     }
     359                 :     else {
     360               0 :       aData = stringdata;
     361                 :     }
     362                 :   }
     363                 : 
     364               0 :   return NS_OK;
     365                 : }
     366                 : 
     367                 : NS_IMETHODIMP
     368               0 : nsDOMDataTransfer::SetData(const nsAString& aFormat, const nsAString& aData)
     369                 : {
     370               0 :   nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
     371               0 :   NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
     372                 : 
     373               0 :   variant->SetAsAString(aData);
     374                 : 
     375               0 :   return MozSetDataAt(aFormat, variant, 0);
     376                 : }
     377                 : 
     378                 : NS_IMETHODIMP
     379               0 : nsDOMDataTransfer::ClearData(const nsAString& aFormat)
     380                 : {
     381               0 :   nsresult rv = MozClearDataAt(aFormat, 0);
     382               0 :   return (rv == NS_ERROR_DOM_INDEX_SIZE_ERR) ? NS_OK : rv;
     383                 : }
     384                 : 
     385                 : NS_IMETHODIMP
     386               0 : nsDOMDataTransfer::GetMozItemCount(PRUint32* aCount)
     387                 : {
     388               0 :   *aCount = mItems.Length();
     389               0 :   return NS_OK;
     390                 : }
     391                 : 
     392                 : NS_IMETHODIMP
     393               0 : nsDOMDataTransfer::GetMozCursor(nsAString& aCursorState)
     394                 : {
     395               0 :   if (mCursorState) {
     396               0 :     aCursorState.AssignLiteral("default");
     397                 :   } else {
     398               0 :     aCursorState.AssignLiteral("auto");
     399                 :   }
     400               0 :   return NS_OK;
     401                 : }
     402                 : 
     403                 : NS_IMETHODIMP
     404               0 : nsDOMDataTransfer::SetMozCursor(const nsAString& aCursorState)
     405                 : {
     406                 :   // Lock the cursor to an arrow during the drag.
     407               0 :   mCursorState = aCursorState.EqualsLiteral("default");
     408                 : 
     409               0 :   return NS_OK;
     410                 : }
     411                 : 
     412                 : NS_IMETHODIMP
     413               0 : nsDOMDataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode)
     414                 : {
     415               0 :   *aSourceNode = nsnull;
     416                 : 
     417               0 :   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
     418               0 :   if (!dragSession)
     419               0 :     return NS_OK;
     420                 : 
     421               0 :   nsCOMPtr<nsIDOMNode> sourceNode;
     422               0 :   dragSession->GetSourceNode(getter_AddRefs(sourceNode));
     423               0 :   if (sourceNode && !nsContentUtils::CanCallerAccess(sourceNode))
     424               0 :     return NS_OK;
     425                 : 
     426               0 :   sourceNode.swap(*aSourceNode);
     427               0 :   return NS_OK;
     428                 : }
     429                 : 
     430                 : NS_IMETHODIMP
     431               0 : nsDOMDataTransfer::MozTypesAt(PRUint32 aIndex, nsIDOMDOMStringList** aTypes)
     432                 : {
     433               0 :   *aTypes = nsnull;
     434                 : 
     435               0 :   nsRefPtr<nsDOMStringList> types = new nsDOMStringList();
     436               0 :   NS_ENSURE_TRUE(types, NS_ERROR_OUT_OF_MEMORY);
     437                 : 
     438               0 :   if (aIndex < mItems.Length()) {
     439                 :     // note that you can retrieve the types regardless of their principal
     440               0 :     nsTArray<TransferItem>& item = mItems[aIndex];
     441               0 :     for (PRUint32 i = 0; i < item.Length(); i++)
     442               0 :       types->Add(item[i].mFormat);
     443                 :   }
     444                 : 
     445               0 :   *aTypes = types;
     446               0 :   NS_ADDREF(*aTypes);
     447                 : 
     448               0 :   return NS_OK;
     449                 : }
     450                 : 
     451                 : NS_IMETHODIMP
     452               0 : nsDOMDataTransfer::MozGetDataAt(const nsAString& aFormat,
     453                 :                                 PRUint32 aIndex,
     454                 :                                 nsIVariant** aData)
     455                 : {
     456               0 :   *aData = nsnull;
     457                 : 
     458               0 :   if (aFormat.IsEmpty())
     459               0 :     return NS_OK;
     460                 : 
     461               0 :   if (aIndex >= mItems.Length())
     462               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     463                 : 
     464               0 :   nsAutoString format;
     465               0 :   GetRealFormat(aFormat, format);
     466                 : 
     467               0 :   nsTArray<TransferItem>& item = mItems[aIndex];
     468                 : 
     469                 :   // allow access to any data in the drop and dragdrop events, or if the
     470                 :   // UniversalXPConnect privilege is set, otherwise only allow access to
     471                 :   // data from the same principal.
     472               0 :   nsIPrincipal* principal = nsnull;
     473               0 :   if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
     474               0 :       !nsContentUtils::CallerHasUniversalXPConnect()) {
     475               0 :     nsresult rv = NS_OK;
     476               0 :     principal = GetCurrentPrincipal(&rv);
     477               0 :     NS_ENSURE_SUCCESS(rv, rv);
     478                 :   }
     479                 : 
     480               0 :   PRUint32 count = item.Length();
     481               0 :   for (PRUint32 i = 0; i < count; i++) {
     482               0 :     TransferItem& formatitem = item[i];
     483               0 :     if (formatitem.mFormat.Equals(format)) {
     484                 :       bool subsumes;
     485               0 :       if (formatitem.mPrincipal && principal &&
     486               0 :           (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes))
     487               0 :         return NS_ERROR_DOM_SECURITY_ERR;
     488                 : 
     489               0 :       if (!formatitem.mData) {
     490               0 :         FillInExternalDragData(formatitem, aIndex);
     491                 :       } else {
     492               0 :         nsCOMPtr<nsISupports> data;
     493               0 :         formatitem.mData->GetAsISupports(getter_AddRefs(data));
     494                 :         // Make sure the code that is calling us is same-origin with the data.
     495               0 :         nsCOMPtr<nsIDOMEventTarget> pt = do_QueryInterface(data);
     496               0 :         if (pt) {
     497               0 :           nsresult rv = NS_OK;
     498               0 :           nsIScriptContext* c = pt->GetContextForEventHandlers(&rv);
     499               0 :           NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR);
     500               0 :           nsIScriptObjectPrincipal* sp = c->GetObjectPrincipal();
     501               0 :           NS_ENSURE_TRUE(sp, NS_ERROR_DOM_SECURITY_ERR);
     502               0 :           nsIPrincipal* dataPrincipal = sp->GetPrincipal();
     503               0 :           NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR);
     504               0 :           NS_ENSURE_TRUE(principal || (principal = GetCurrentPrincipal(&rv)),
     505                 :                          NS_ERROR_DOM_SECURITY_ERR);
     506               0 :           NS_ENSURE_SUCCESS(rv, rv);
     507               0 :           bool equals = false;
     508               0 :           NS_ENSURE_TRUE(NS_SUCCEEDED(principal->Equals(dataPrincipal, &equals)) && equals,
     509                 :                          NS_ERROR_DOM_SECURITY_ERR);
     510                 :         }
     511                 :       }
     512               0 :       *aData = formatitem.mData;
     513               0 :       NS_IF_ADDREF(*aData);
     514               0 :       return NS_OK;
     515                 :     }
     516                 :   }
     517                 : 
     518               0 :   return NS_OK;
     519                 : }
     520                 : 
     521                 : NS_IMETHODIMP
     522               0 : nsDOMDataTransfer::MozSetDataAt(const nsAString& aFormat,
     523                 :                                 nsIVariant* aData,
     524                 :                                 PRUint32 aIndex)
     525                 : {
     526               0 :   NS_ENSURE_TRUE(aData, NS_ERROR_NULL_POINTER);
     527                 : 
     528               0 :   if (aFormat.IsEmpty())
     529               0 :     return NS_OK;
     530                 : 
     531               0 :   if (mReadOnly)
     532               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     533                 : 
     534                 :   // Specifying an index less than the current length will replace an existing
     535                 :   // item. Specifying an index equal to the current length will add a new item.
     536               0 :   if (aIndex > mItems.Length())
     537               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     538                 : 
     539                 :   // don't allow non-chrome to add file data
     540                 :   // XXX perhaps this should also limit any non-string type as well
     541               0 :   if ((aFormat.EqualsLiteral("application/x-moz-file-promise") ||
     542               0 :        aFormat.EqualsLiteral("application/x-moz-file")) &&
     543               0 :        !nsContentUtils::CallerHasUniversalXPConnect()) {
     544               0 :     return NS_ERROR_DOM_SECURITY_ERR;
     545                 :   }
     546                 : 
     547               0 :   nsresult rv = NS_OK;
     548               0 :   nsIPrincipal* principal = GetCurrentPrincipal(&rv);
     549               0 :   NS_ENSURE_SUCCESS(rv, rv);
     550               0 :   return SetDataWithPrincipal(aFormat, aData, aIndex, principal);
     551                 : }
     552                 : 
     553                 : NS_IMETHODIMP
     554               0 : nsDOMDataTransfer::MozClearDataAt(const nsAString& aFormat, PRUint32 aIndex)
     555                 : {
     556               0 :   if (mReadOnly)
     557               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     558                 : 
     559               0 :   if (aIndex >= mItems.Length())
     560               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     561                 : 
     562               0 :   nsAutoString format;
     563               0 :   GetRealFormat(aFormat, format);
     564                 : 
     565               0 :   nsresult rv = NS_OK;
     566               0 :   nsIPrincipal* principal = GetCurrentPrincipal(&rv);
     567               0 :   NS_ENSURE_SUCCESS(rv, rv);
     568                 : 
     569                 :   // if the format is empty, clear all formats
     570               0 :   bool clearall = format.IsEmpty();
     571                 : 
     572               0 :   nsTArray<TransferItem>& item = mItems[aIndex];
     573                 :   // count backwards so that the count and index don't have to be adjusted
     574                 :   // after removing an element
     575               0 :   for (PRInt32 i = item.Length() - 1; i >= 0; i--) {
     576               0 :     TransferItem& formatitem = item[i];
     577               0 :     if (clearall || formatitem.mFormat.Equals(format)) {
     578                 :       // don't allow removing data that has a stronger principal
     579                 :       bool subsumes;
     580               0 :       if (formatitem.mPrincipal && principal &&
     581               0 :           (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes))
     582               0 :         return NS_ERROR_DOM_SECURITY_ERR;
     583                 : 
     584               0 :       item.RemoveElementAt(i);
     585                 : 
     586                 :       // if a format was specified, break out. Otherwise, loop around until
     587                 :       // all formats have been removed
     588               0 :       if (!clearall)
     589               0 :         break;
     590                 :     }
     591                 :   }
     592                 : 
     593                 :   // if the last format for an item is removed, remove the entire item
     594               0 :   if (!item.Length())
     595               0 :      mItems.RemoveElementAt(aIndex);
     596                 : 
     597               0 :   return NS_OK;
     598                 : }
     599                 : 
     600                 : NS_IMETHODIMP
     601               0 : nsDOMDataTransfer::SetDragImage(nsIDOMElement* aImage, PRInt32 aX, PRInt32 aY)
     602                 : {
     603               0 :   if (mReadOnly)
     604               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     605                 : 
     606               0 :   if (aImage) {
     607               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aImage);
     608               0 :     NS_ENSURE_TRUE(content, NS_ERROR_INVALID_ARG);
     609                 :   }
     610               0 :   mDragImage = aImage;
     611               0 :   mDragImageX = aX;
     612               0 :   mDragImageY = aY;
     613               0 :   return NS_OK;
     614                 : }
     615                 : 
     616                 : NS_IMETHODIMP
     617               0 : nsDOMDataTransfer::AddElement(nsIDOMElement* aElement)
     618                 : {
     619               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
     620                 : 
     621               0 :   if (mReadOnly)
     622               0 :     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
     623                 : 
     624               0 :   mDragTarget = do_QueryInterface(aElement);
     625                 : 
     626               0 :   return NS_OK;
     627                 : }
     628                 : 
     629                 : nsresult
     630               0 : nsDOMDataTransfer::Clone(PRUint32 aEventType, bool aUserCancelled,
     631                 :                          nsIDOMDataTransfer** aNewDataTransfer)
     632                 : {
     633                 :   nsDOMDataTransfer* newDataTransfer =
     634                 :     new nsDOMDataTransfer(aEventType, mEffectAllowed, mCursorState,
     635                 :                           mIsExternal, aUserCancelled, mItems,
     636               0 :                           mDragImage, mDragImageX, mDragImageY);
     637               0 :   NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_OUT_OF_MEMORY);
     638                 : 
     639               0 :   *aNewDataTransfer = newDataTransfer;
     640               0 :   NS_ADDREF(*aNewDataTransfer);
     641               0 :   return NS_OK;
     642                 : }
     643                 : 
     644                 : void
     645               0 : nsDOMDataTransfer::GetTransferables(nsISupportsArray** aArray)
     646                 : {
     647               0 :   *aArray = nsnull;
     648                 : 
     649                 :   nsCOMPtr<nsISupportsArray> transArray =
     650               0 :     do_CreateInstance("@mozilla.org/supports-array;1");
     651               0 :   if (!transArray)
     652                 :     return;
     653                 : 
     654               0 :   bool added = false;
     655               0 :   PRUint32 count = mItems.Length();
     656               0 :   for (PRUint32 i = 0; i < count; i++) {
     657                 : 
     658               0 :     nsTArray<TransferItem>& item = mItems[i];
     659               0 :     PRUint32 count = item.Length();
     660               0 :     if (!count)
     661               0 :       continue;
     662                 : 
     663                 :     nsCOMPtr<nsITransferable> transferable =
     664               0 :       do_CreateInstance("@mozilla.org/widget/transferable;1");
     665               0 :     if (!transferable)
     666                 :       return;
     667                 : 
     668               0 :     for (PRUint32 f = 0; f < count; f++) {
     669               0 :       TransferItem& formatitem = item[f];
     670               0 :       if (!formatitem.mData) // skip empty items
     671               0 :         continue;
     672                 : 
     673                 :       PRUint32 length;
     674               0 :       nsCOMPtr<nsISupports> convertedData;
     675               0 :       if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length))
     676               0 :         continue;
     677                 : 
     678                 :       // the underlying drag code uses text/unicode, so use that instead of text/plain
     679                 :       const char* format;
     680               0 :       NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
     681               0 :       if (utf8format.EqualsLiteral("text/plain"))
     682               0 :         format = kUnicodeMime;
     683                 :       else
     684               0 :         format = utf8format.get();
     685                 : 
     686                 :       // if a converter is set for a format, set the converter for the
     687                 :       // transferable and don't add the item
     688               0 :       nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData);
     689               0 :       if (converter) {
     690               0 :         transferable->AddDataFlavor(format);
     691               0 :         transferable->SetConverter(converter);
     692               0 :         continue;
     693                 :       }
     694                 : 
     695               0 :       nsresult rv = transferable->SetTransferData(format, convertedData, length);
     696               0 :       if (NS_FAILED(rv))
     697                 :         return;
     698                 : 
     699               0 :       added = true;
     700                 :     }
     701                 : 
     702                 :     // only append the transferable if data was successfully added to it
     703               0 :     if (added)
     704               0 :       transArray->AppendElement(transferable);
     705                 :   }
     706                 : 
     707               0 :   NS_ADDREF(*aArray = transArray);
     708                 : }
     709                 : 
     710                 : bool
     711               0 : nsDOMDataTransfer::ConvertFromVariant(nsIVariant* aVariant,
     712                 :                                       nsISupports** aSupports,
     713                 :                                       PRUint32* aLength)
     714                 : {
     715               0 :   *aSupports = nsnull;
     716               0 :   *aLength = 0;
     717                 : 
     718                 :   PRUint16 type;
     719               0 :   aVariant->GetDataType(&type);
     720               0 :   if (type == nsIDataType::VTYPE_INTERFACE ||
     721                 :       type == nsIDataType::VTYPE_INTERFACE_IS) {
     722               0 :     nsCOMPtr<nsISupports> data;
     723               0 :     if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data))))
     724               0 :        return false;
     725                 :  
     726               0 :     nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data);
     727               0 :     if (fdp) {
     728                 :       // for flavour data providers, use kFlavorHasDataProvider (which has the
     729                 :       // value 0) as the length.
     730               0 :       NS_ADDREF(*aSupports = fdp);
     731               0 :       *aLength = nsITransferable::kFlavorHasDataProvider;
     732                 :     }
     733                 :     else {
     734                 :       // wrap the item in an nsISupportsInterfacePointer
     735                 :       nsCOMPtr<nsISupportsInterfacePointer> ptrSupports =
     736               0 :         do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID);
     737               0 :       if (!ptrSupports)
     738               0 :         return false;
     739                 : 
     740               0 :       ptrSupports->SetData(data);
     741               0 :       NS_ADDREF(*aSupports = ptrSupports);
     742                 : 
     743               0 :       *aLength = sizeof(nsISupportsInterfacePointer *);
     744                 :     }
     745                 : 
     746               0 :     return true;
     747                 :   }
     748                 : 
     749                 :   PRUnichar* chrs;
     750               0 :   PRUint32 len = 0;
     751               0 :   nsresult rv = aVariant->GetAsWStringWithSize(&len, &chrs);
     752               0 :   if (NS_FAILED(rv))
     753               0 :     return false;
     754                 : 
     755               0 :   nsAutoString str;
     756               0 :   str.Adopt(chrs, len);
     757                 : 
     758                 :   nsCOMPtr<nsISupportsString>
     759               0 :     strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     760               0 :   if (!strSupports)
     761               0 :     return false;
     762                 : 
     763               0 :   strSupports->SetData(str);
     764                 : 
     765               0 :   *aSupports = strSupports;
     766               0 :   NS_ADDREF(*aSupports);
     767                 : 
     768                 :   // each character is two bytes
     769               0 :   *aLength = str.Length() << 1;
     770                 : 
     771               0 :   return true;
     772                 : }
     773                 : 
     774                 : void
     775               0 : nsDOMDataTransfer::ClearAll()
     776                 : {
     777               0 :   mItems.Clear();
     778               0 : }
     779                 : 
     780                 : nsresult
     781               0 : nsDOMDataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
     782                 :                                         nsIVariant* aData,
     783                 :                                         PRUint32 aIndex,
     784                 :                                         nsIPrincipal* aPrincipal)
     785                 : {
     786               0 :   nsAutoString format;
     787               0 :   GetRealFormat(aFormat, format);
     788                 : 
     789                 :   // check if the item for the format already exists. In that case,
     790                 :   // just replace it.
     791                 :   TransferItem* formatitem;
     792               0 :   if (aIndex < mItems.Length()) {
     793               0 :     nsTArray<TransferItem>& item = mItems[aIndex];
     794               0 :     PRUint32 count = item.Length();
     795               0 :     for (PRUint32 i = 0; i < count; i++) {
     796               0 :       TransferItem& itemformat = item[i];
     797               0 :       if (itemformat.mFormat.Equals(format)) {
     798                 :         // don't allow replacing data that has a stronger principal
     799                 :         bool subsumes;
     800               0 :         if (itemformat.mPrincipal && aPrincipal &&
     801               0 :             (NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal, &subsumes)) || !subsumes))
     802               0 :           return NS_ERROR_DOM_SECURITY_ERR;
     803                 : 
     804               0 :         itemformat.mPrincipal = aPrincipal;
     805               0 :         itemformat.mData = aData;
     806               0 :         return NS_OK;
     807                 :       }
     808                 :     }
     809                 : 
     810                 :     // add a new format
     811               0 :     formatitem = item.AppendElement();
     812                 :   }
     813                 :   else {
     814               0 :     NS_ASSERTION(aIndex == mItems.Length(), "Index out of range");
     815                 : 
     816                 :     // add a new index
     817               0 :     nsTArray<TransferItem>* item = mItems.AppendElement();
     818               0 :     NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
     819                 : 
     820               0 :     formatitem = item->AppendElement();
     821                 :   }
     822                 : 
     823               0 :   NS_ENSURE_TRUE(formatitem, NS_ERROR_OUT_OF_MEMORY);
     824                 : 
     825               0 :   formatitem->mFormat = format;
     826               0 :   formatitem->mPrincipal = aPrincipal;
     827               0 :   formatitem->mData = aData;
     828                 : 
     829               0 :   return NS_OK;
     830                 : }
     831                 : 
     832                 : nsIPrincipal*
     833               0 : nsDOMDataTransfer::GetCurrentPrincipal(nsresult* rv)
     834                 : {
     835               0 :   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
     836                 : 
     837               0 :   nsCOMPtr<nsIPrincipal> currentPrincipal;
     838               0 :   *rv = ssm->GetSubjectPrincipal(getter_AddRefs(currentPrincipal));
     839               0 :   NS_ENSURE_SUCCESS(*rv, nsnull);
     840                 : 
     841               0 :   if (!currentPrincipal)
     842               0 :     ssm->GetSystemPrincipal(getter_AddRefs(currentPrincipal));
     843                 : 
     844               0 :   return currentPrincipal.get();
     845                 : }
     846                 : 
     847                 : void
     848               0 : nsDOMDataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat)
     849                 : {
     850                 :   // treat text/unicode as equivalent to text/plain
     851               0 :   nsAutoString lowercaseFormat;
     852               0 :   nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat);
     853               0 :   if (lowercaseFormat.EqualsLiteral("text") || lowercaseFormat.EqualsLiteral("text/unicode"))
     854               0 :     aOutFormat.AssignLiteral("text/plain");
     855               0 :   else if (lowercaseFormat.EqualsLiteral("url"))
     856               0 :     aOutFormat.AssignLiteral("text/uri-list");
     857                 :   else
     858               0 :     aOutFormat.Assign(lowercaseFormat);
     859               0 : }
     860                 : 
     861                 : void
     862               0 : nsDOMDataTransfer::CacheExternalFormats()
     863                 : {
     864                 :   // Called during the constructor to cache the formats available from an
     865                 :   // external drag. The data associated with each format will be set to null.
     866                 :   // This data will instead only be retrieved in FillInExternalDragData when
     867                 :   // asked for, as it may be time consuming for the source application to
     868                 :   // generate it.
     869                 : 
     870               0 :   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
     871               0 :   if (!dragSession)
     872                 :     return;
     873                 : 
     874                 :   // make sure that the system principal is used for external drags
     875               0 :   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
     876               0 :   nsCOMPtr<nsIPrincipal> sysPrincipal;
     877               0 :   ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
     878                 : 
     879                 :   // there isn't a way to get a list of the formats that might be available on
     880                 :   // all platforms, so just check for the types that can actually be imported
     881                 :   // XXXndeakin there are some other formats but those are platform specific.
     882               0 :   const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime };
     883                 : 
     884                 :   PRUint32 count;
     885               0 :   dragSession->GetNumDropItems(&count);
     886               0 :   for (PRUint32 c = 0; c < count; c++) {
     887               0 :     for (PRUint32 f = 0; f < ArrayLength(formats); f++) {
     888                 :       // IsDataFlavorSupported doesn't take an index as an argument and just
     889                 :       // checks if any of the items support a particular flavor, even though
     890                 :       // the GetData method does take an index. Here, we just assume that
     891                 :       // every item being dragged has the same set of flavors.
     892                 :       bool supported;
     893               0 :       dragSession->IsDataFlavorSupported(formats[f], &supported);
     894                 :       // if the format is supported, add an item to the array with null as
     895                 :       // the data. When retrieved, GetRealData will read the data.
     896               0 :       if (supported) {
     897               0 :         if (strcmp(formats[f], kUnicodeMime) == 0) {
     898               0 :           SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nsnull, c, sysPrincipal);
     899                 :         }
     900                 :         else {
     901               0 :           if (strcmp(formats[f], kURLDataMime) == 0)
     902               0 :             SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nsnull, c, sysPrincipal);
     903               0 :           SetDataWithPrincipal(NS_ConvertUTF8toUTF16(formats[f]), nsnull, c, sysPrincipal);
     904                 :         }
     905                 :       }
     906                 :     }
     907                 :   }
     908                 : }
     909                 : 
     910                 : void
     911               0 : nsDOMDataTransfer::FillInExternalDragData(TransferItem& aItem, PRUint32 aIndex)
     912                 : {
     913               0 :   NS_PRECONDITION(mIsExternal, "Not an external drag");
     914                 : 
     915               0 :   if (!aItem.mData) {
     916                 :     nsCOMPtr<nsITransferable> trans =
     917               0 :       do_CreateInstance("@mozilla.org/widget/transferable;1");
     918               0 :     if (!trans)
     919                 :       return;
     920                 : 
     921               0 :     NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
     922               0 :     const char* format = utf8format.get();
     923               0 :     if (strcmp(format, "text/plain") == 0)
     924               0 :       format = kUnicodeMime;
     925               0 :     else if (strcmp(format, "text/uri-list") == 0)
     926               0 :       format = kURLDataMime;
     927                 : 
     928               0 :     nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
     929               0 :     if (!dragSession)
     930                 :       return;
     931                 : 
     932               0 :     trans->AddDataFlavor(format);
     933               0 :     dragSession->GetData(trans, aIndex);
     934                 : 
     935               0 :     PRUint32 length = 0;
     936               0 :     nsCOMPtr<nsISupports> data;
     937               0 :     trans->GetTransferData(format, getter_AddRefs(data), &length);
     938               0 :     if (!data)
     939                 :       return;
     940                 : 
     941               0 :     nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
     942               0 :     if (!variant)
     943                 :       return;
     944                 : 
     945               0 :     nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
     946               0 :     if (supportsstr) {
     947               0 :       nsAutoString str;
     948               0 :       supportsstr->GetData(str);
     949               0 :       variant->SetAsAString(str);
     950                 :     }
     951                 :     else {
     952               0 :       variant->SetAsISupports(data);
     953                 :     }
     954               0 :     aItem.mData = variant;
     955                 :   }
     956            4392 : }

Generated by: LCOV version 1.7