LCOV - code coverage report
Current view: top level - dom/base - nsContentAreaDragDrop.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 388 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsReadableUtils.h"
       8             : 
       9             : // Local Includes
      10             : #include "nsContentAreaDragDrop.h"
      11             : 
      12             : // Helper Classes
      13             : #include "nsString.h"
      14             : 
      15             : // Interfaces needed to be included
      16             : #include "nsCopySupport.h"
      17             : #include "nsIDOMUIEvent.h"
      18             : #include "nsISelection.h"
      19             : #include "nsISelectionController.h"
      20             : #include "nsIDOMNode.h"
      21             : #include "nsIDOMNodeList.h"
      22             : #include "nsIDOMEvent.h"
      23             : #include "nsIDOMDragEvent.h"
      24             : #include "nsPIDOMWindow.h"
      25             : #include "nsIDOMRange.h"
      26             : #include "nsIFormControl.h"
      27             : #include "nsIDOMHTMLAreaElement.h"
      28             : #include "nsIDOMHTMLAnchorElement.h"
      29             : #include "nsITransferable.h"
      30             : #include "nsComponentManagerUtils.h"
      31             : #include "nsXPCOM.h"
      32             : #include "nsISupportsPrimitives.h"
      33             : #include "nsServiceManagerUtils.h"
      34             : #include "nsNetUtil.h"
      35             : #include "nsIFile.h"
      36             : #include "nsFrameLoader.h"
      37             : #include "nsIWebNavigation.h"
      38             : #include "nsIDocShell.h"
      39             : #include "nsIContent.h"
      40             : #include "nsIImageLoadingContent.h"
      41             : #include "nsITextControlElement.h"
      42             : #include "nsUnicharUtils.h"
      43             : #include "nsIURL.h"
      44             : #include "nsIDocument.h"
      45             : #include "nsIScriptSecurityManager.h"
      46             : #include "nsIPrincipal.h"
      47             : #include "nsIDocShellTreeItem.h"
      48             : #include "nsIWebBrowserPersist.h"
      49             : #include "nsEscape.h"
      50             : #include "nsContentUtils.h"
      51             : #include "nsIMIMEService.h"
      52             : #include "imgIContainer.h"
      53             : #include "imgIRequest.h"
      54             : #include "mozilla/dom/DataTransfer.h"
      55             : #include "nsIMIMEInfo.h"
      56             : #include "nsRange.h"
      57             : #include "TabParent.h"
      58             : #include "mozilla/dom/Element.h"
      59             : #include "mozilla/dom/HTMLAreaElement.h"
      60             : #include "nsVariant.h"
      61             : 
      62             : using namespace mozilla::dom;
      63             : 
      64           0 : class MOZ_STACK_CLASS DragDataProducer
      65             : {
      66             : public:
      67             :   DragDataProducer(nsPIDOMWindowOuter* aWindow,
      68             :                    nsIContent* aTarget,
      69             :                    nsIContent* aSelectionTargetNode,
      70             :                    bool aIsAltKeyPressed);
      71             :   nsresult Produce(DataTransfer* aDataTransfer,
      72             :                    bool* aCanDrag,
      73             :                    nsISelection** aSelection,
      74             :                    nsIContent** aDragNode);
      75             : 
      76             : private:
      77             :   void AddString(DataTransfer* aDataTransfer,
      78             :                  const nsAString& aFlavor,
      79             :                  const nsAString& aData,
      80             :                  nsIPrincipal* aPrincipal);
      81             :   nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
      82             :                                     DataTransfer* aDataTransfer);
      83             :   static nsresult GetDraggableSelectionData(nsISelection* inSelection,
      84             :                                             nsIContent* inRealTargetNode,
      85             :                                             nsIContent **outImageOrLinkNode,
      86             :                                             bool* outDragSelectedText);
      87             :   static already_AddRefed<nsIContent> FindParentLinkNode(nsIContent* inNode);
      88             :   static MOZ_MUST_USE nsresult
      89             :   GetAnchorURL(nsIContent* inNode, nsAString& outURL);
      90             :   static void GetNodeString(nsIContent* inNode, nsAString & outNodeString);
      91             :   static void CreateLinkText(const nsAString& inURL, const nsAString & inText,
      92             :                               nsAString& outLinkText);
      93             : 
      94             :   nsCOMPtr<nsPIDOMWindowOuter> mWindow;
      95             :   nsCOMPtr<nsIContent> mTarget;
      96             :   nsCOMPtr<nsIContent> mSelectionTargetNode;
      97             :   bool mIsAltKeyPressed;
      98             : 
      99             :   nsString mUrlString;
     100             :   nsString mImageSourceString;
     101             :   nsString mImageDestFileName;
     102             :   nsString mTitleString;
     103             :   // will be filled automatically if you fill urlstring
     104             :   nsString mHtmlString;
     105             :   nsString mContextString;
     106             :   nsString mInfoString;
     107             : 
     108             :   bool mIsAnchor;
     109             :   nsCOMPtr<imgIContainer> mImage;
     110             : };
     111             : 
     112             : 
     113             : nsresult
     114           0 : nsContentAreaDragDrop::GetDragData(nsPIDOMWindowOuter* aWindow,
     115             :                                    nsIContent* aTarget,
     116             :                                    nsIContent* aSelectionTargetNode,
     117             :                                    bool aIsAltKeyPressed,
     118             :                                    DataTransfer* aDataTransfer,
     119             :                                    bool* aCanDrag,
     120             :                                    nsISelection** aSelection,
     121             :                                    nsIContent** aDragNode)
     122             : {
     123           0 :   NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG);
     124             : 
     125           0 :   *aCanDrag = true;
     126             : 
     127             :   DragDataProducer
     128           0 :     provider(aWindow, aTarget, aSelectionTargetNode, aIsAltKeyPressed);
     129           0 :   return provider.Produce(aDataTransfer, aCanDrag, aSelection, aDragNode);
     130             : }
     131             : 
     132             : 
     133           0 : NS_IMPL_ISUPPORTS(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider)
     134             : 
     135             : // SaveURIToFile
     136             : // used on platforms where it's possible to drag items (e.g. images)
     137             : // into the file system
     138             : nsresult
     139           0 : nsContentAreaDragDropDataProvider::SaveURIToFile(nsAString& inSourceURIString,
     140             :                                                  nsIFile* inDestFile,
     141             :                                                  bool isPrivate)
     142             : {
     143           0 :   nsCOMPtr<nsIURI> sourceURI;
     144           0 :   nsresult rv = NS_NewURI(getter_AddRefs(sourceURI), inSourceURIString);
     145           0 :   if (NS_FAILED(rv)) {
     146           0 :     return NS_ERROR_FAILURE;
     147             :   }
     148             : 
     149           0 :   nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(sourceURI);
     150           0 :   if (!sourceURL) {
     151           0 :     return NS_ERROR_NO_INTERFACE;
     152             :   }
     153             : 
     154           0 :   rv = inDestFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
     155           0 :   NS_ENSURE_SUCCESS(rv, rv);
     156             : 
     157             :   // we rely on the fact that the WPB is refcounted by the channel etc,
     158             :   // so we don't keep a ref to it. It will die when finished.
     159             :   nsCOMPtr<nsIWebBrowserPersist> persist =
     160           0 :     do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1",
     161           0 :                       &rv);
     162           0 :   NS_ENSURE_SUCCESS(rv, rv);
     163             : 
     164           0 :   persist->SetPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION);
     165             : 
     166             :   // referrer policy can be anything since the referrer is nullptr
     167           0 :   return persist->SavePrivacyAwareURI(sourceURI, nullptr, nullptr,
     168             :                                       mozilla::net::RP_Unset,
     169             :                                       nullptr, nullptr,
     170           0 :                                       inDestFile, isPrivate);
     171             : }
     172             : 
     173             : // This is our nsIFlavorDataProvider callback. There are several
     174             : // assumptions here that make this work:
     175             : //
     176             : // 1. Someone put a kFilePromiseURLMime flavor into the transferable
     177             : //    with the source URI of the file to save (as a string). We did
     178             : //    that in AddStringsToDataTransfer.
     179             : //
     180             : // 2. Someone put a kFilePromiseDirectoryMime flavor into the
     181             : //    transferable with an nsIFile for the directory we are to
     182             : //    save in. That has to be done by platform-specific code (in
     183             : //    widget), which gets the destination directory from
     184             : //    OS-specific drag information.
     185             : //
     186             : NS_IMETHODIMP
     187           0 : nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable,
     188             :                                                  const char *aFlavor,
     189             :                                                  nsISupports **aData,
     190             :                                                  uint32_t *aDataLen)
     191             : {
     192           0 :   NS_ENSURE_ARG_POINTER(aData && aDataLen);
     193           0 :   *aData = nullptr;
     194           0 :   *aDataLen = 0;
     195             : 
     196           0 :   nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
     197             : 
     198           0 :   if (strcmp(aFlavor, kFilePromiseMime) == 0) {
     199             :     // get the URI from the kFilePromiseURLMime flavor
     200           0 :     NS_ENSURE_ARG(aTransferable);
     201           0 :     nsCOMPtr<nsISupports> tmp;
     202           0 :     uint32_t dataSize = 0;
     203           0 :     aTransferable->GetTransferData(kFilePromiseURLMime,
     204           0 :                                    getter_AddRefs(tmp), &dataSize);
     205             :     nsCOMPtr<nsISupportsString> supportsString =
     206           0 :       do_QueryInterface(tmp);
     207           0 :     if (!supportsString)
     208           0 :       return NS_ERROR_FAILURE;
     209             : 
     210           0 :     nsAutoString sourceURLString;
     211           0 :     supportsString->GetData(sourceURLString);
     212           0 :     if (sourceURLString.IsEmpty())
     213           0 :       return NS_ERROR_FAILURE;
     214             : 
     215           0 :     aTransferable->GetTransferData(kFilePromiseDestFilename,
     216           0 :                                    getter_AddRefs(tmp), &dataSize);
     217           0 :     supportsString = do_QueryInterface(tmp);
     218           0 :     if (!supportsString)
     219           0 :       return NS_ERROR_FAILURE;
     220             : 
     221           0 :     nsAutoString targetFilename;
     222           0 :     supportsString->GetData(targetFilename);
     223           0 :     if (targetFilename.IsEmpty())
     224           0 :       return NS_ERROR_FAILURE;
     225             : 
     226             :     // get the target directory from the kFilePromiseDirectoryMime
     227             :     // flavor
     228           0 :     nsCOMPtr<nsISupports> dirPrimitive;
     229           0 :     dataSize = 0;
     230           0 :     aTransferable->GetTransferData(kFilePromiseDirectoryMime,
     231           0 :                                    getter_AddRefs(dirPrimitive), &dataSize);
     232           0 :     nsCOMPtr<nsIFile> destDirectory = do_QueryInterface(dirPrimitive);
     233           0 :     if (!destDirectory)
     234           0 :       return NS_ERROR_FAILURE;
     235             : 
     236           0 :     nsCOMPtr<nsIFile> file;
     237           0 :     rv = destDirectory->Clone(getter_AddRefs(file));
     238           0 :     NS_ENSURE_SUCCESS(rv, rv);
     239             : 
     240           0 :     file->Append(targetFilename);
     241             : 
     242             :     bool isPrivate;
     243           0 :     aTransferable->GetIsPrivateData(&isPrivate);
     244             : 
     245           0 :     rv = SaveURIToFile(sourceURLString, file, isPrivate);
     246             :     // send back an nsIFile
     247           0 :     if (NS_SUCCEEDED(rv)) {
     248           0 :       CallQueryInterface(file, aData);
     249           0 :       *aDataLen = sizeof(nsIFile*);
     250             :     }
     251             :   }
     252             : 
     253           0 :   return rv;
     254             : }
     255             : 
     256           0 : DragDataProducer::DragDataProducer(nsPIDOMWindowOuter* aWindow,
     257             :                                    nsIContent* aTarget,
     258             :                                    nsIContent* aSelectionTargetNode,
     259           0 :                                    bool aIsAltKeyPressed)
     260             :   : mWindow(aWindow),
     261             :     mTarget(aTarget),
     262             :     mSelectionTargetNode(aSelectionTargetNode),
     263             :     mIsAltKeyPressed(aIsAltKeyPressed),
     264           0 :     mIsAnchor(false)
     265             : {
     266           0 : }
     267             : 
     268             : 
     269             : //
     270             : // FindParentLinkNode
     271             : //
     272             : // Finds the parent with the given link tag starting at |inNode|. If
     273             : // it gets up to the root without finding it, we stop looking and
     274             : // return null.
     275             : //
     276             : already_AddRefed<nsIContent>
     277           0 : DragDataProducer::FindParentLinkNode(nsIContent* inNode)
     278             : {
     279           0 :   nsIContent* content = inNode;
     280           0 :   if (!content) {
     281             :     // That must have been the document node; nothing else to do here;
     282           0 :     return nullptr;
     283             :   }
     284             : 
     285           0 :   for (; content; content = content->GetParent()) {
     286           0 :     if (nsContentUtils::IsDraggableLink(content)) {
     287           0 :       nsCOMPtr<nsIContent> ret = content;
     288           0 :       return ret.forget();
     289             :     }
     290             :   }
     291             : 
     292           0 :   return nullptr;
     293             : }
     294             : 
     295             : 
     296             : //
     297             : // GetAnchorURL
     298             : //
     299             : nsresult
     300           0 : DragDataProducer::GetAnchorURL(nsIContent* inNode, nsAString& outURL)
     301             : {
     302           0 :   nsCOMPtr<nsIURI> linkURI;
     303           0 :   if (!inNode || !inNode->IsLink(getter_AddRefs(linkURI))) {
     304             :     // Not a link
     305           0 :     outURL.Truncate();
     306           0 :     return NS_OK;
     307             :   }
     308             : 
     309           0 :   nsAutoCString spec;
     310           0 :   nsresult rv = linkURI->GetSpec(spec);
     311           0 :   NS_ENSURE_SUCCESS(rv, rv);
     312           0 :   CopyUTF8toUTF16(spec, outURL);
     313           0 :   return NS_OK;
     314             : }
     315             : 
     316             : 
     317             : //
     318             : // CreateLinkText
     319             : //
     320             : // Creates the html for an anchor in the form
     321             : //  <a href="inURL">inText</a>
     322             : //
     323             : void
     324           0 : DragDataProducer::CreateLinkText(const nsAString& inURL,
     325             :                                  const nsAString & inText,
     326             :                                  nsAString& outLinkText)
     327             : {
     328             :   // use a temp var in case |inText| is the same string as
     329             :   // |outLinkText| to avoid overwriting it while building up the
     330             :   // string in pieces.
     331           0 :   nsAutoString linkText(NS_LITERAL_STRING("<a href=\"") +
     332           0 :                         inURL +
     333           0 :                         NS_LITERAL_STRING("\">") +
     334           0 :                         inText +
     335           0 :                         NS_LITERAL_STRING("</a>") );
     336             : 
     337           0 :   outLinkText = linkText;
     338           0 : }
     339             : 
     340             : 
     341             : //
     342             : // GetNodeString
     343             : //
     344             : // Gets the text associated with a node
     345             : //
     346             : void
     347           0 : DragDataProducer::GetNodeString(nsIContent* inNode,
     348             :                                 nsAString & outNodeString)
     349             : {
     350           0 :   nsCOMPtr<nsINode> node = inNode;
     351             : 
     352           0 :   outNodeString.Truncate();
     353             : 
     354             :   // use a range to get the text-equivalent of the node
     355           0 :   nsCOMPtr<nsIDocument> doc = node->OwnerDoc();
     356           0 :   mozilla::IgnoredErrorResult rv;
     357           0 :   RefPtr<nsRange> range = doc->CreateRange(rv);
     358           0 :   if (range) {
     359           0 :     range->SelectNode(*node, rv);
     360           0 :     range->ToString(outNodeString);
     361             :   }
     362           0 : }
     363             : 
     364             : nsresult
     365           0 : DragDataProducer::Produce(DataTransfer* aDataTransfer,
     366             :                           bool* aCanDrag,
     367             :                           nsISelection** aSelection,
     368             :                           nsIContent** aDragNode)
     369             : {
     370           0 :   NS_PRECONDITION(aCanDrag && aSelection && aDataTransfer && aDragNode,
     371             :                   "null pointer passed to Produce");
     372           0 :   NS_ASSERTION(mWindow, "window not set");
     373           0 :   NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set");
     374             : 
     375           0 :   *aDragNode = nullptr;
     376             : 
     377             :   nsresult rv;
     378           0 :   nsIContent* dragNode = nullptr;
     379           0 :   *aSelection = nullptr;
     380             : 
     381             :   // Find the selection to see what we could be dragging and if what we're
     382             :   // dragging is in what is selected. If this is an editable textbox, use
     383             :   // the textbox's selection, otherwise use the window's selection.
     384           0 :   nsCOMPtr<nsISelection> selection;
     385           0 :   nsIContent* editingElement = mSelectionTargetNode->IsEditable() ?
     386           0 :                                mSelectionTargetNode->GetEditingHost() : nullptr;
     387             :   nsCOMPtr<nsITextControlElement> textControl =
     388           0 :     nsITextControlElement::GetTextControlElementFromEditingHost(editingElement);
     389           0 :   if (textControl) {
     390           0 :     nsISelectionController* selcon = textControl->GetSelectionController();
     391           0 :     if (selcon) {
     392           0 :       selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
     393             :     }
     394             : 
     395           0 :     if (!selection)
     396           0 :       return NS_OK;
     397             :   }
     398             :   else {
     399           0 :     selection = mWindow->GetSelection();
     400           0 :     if (!selection)
     401           0 :       return NS_OK;
     402             : 
     403             :     // Check if the node is inside a form control. Don't set aCanDrag to false
     404             :     //however, as we still want to allow the drag.
     405           0 :     nsCOMPtr<nsIContent> findFormNode = mSelectionTargetNode;
     406           0 :     nsIContent* findFormParent = findFormNode->GetParent();
     407           0 :     while (findFormParent) {
     408           0 :       nsCOMPtr<nsIFormControl> form(do_QueryInterface(findFormParent));
     409           0 :       if (form && !form->AllowDraggableChildren()) {
     410           0 :         return NS_OK;
     411             :       }
     412           0 :       findFormParent = findFormParent->GetParent();
     413             :     }
     414             :   }
     415             : 
     416             :   // if set, serialize the content under this node
     417           0 :   nsCOMPtr<nsIContent> nodeToSerialize;
     418             : 
     419           0 :   nsCOMPtr<nsIDocShellTreeItem> dsti = mWindow->GetDocShell();
     420             :   const bool isChromeShell =
     421           0 :     dsti && dsti->ItemType() == nsIDocShellTreeItem::typeChrome;
     422             : 
     423             :   // In chrome shells, only allow dragging inside editable areas.
     424           0 :   if (isChromeShell && !editingElement) {
     425           0 :     nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mTarget);
     426           0 :     if (flo) {
     427           0 :       RefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
     428           0 :       if (fl) {
     429           0 :         TabParent* tp = static_cast<TabParent*>(fl->GetRemoteBrowser());
     430           0 :         if (tp) {
     431             :           // We have a TabParent, so it may have data for dnd in case the child
     432             :           // process started a dnd session.
     433           0 :           tp->AddInitialDnDDataTo(aDataTransfer);
     434             :         }
     435             :       }
     436             :     }
     437           0 :     return NS_OK;
     438             :   }
     439             : 
     440           0 :   if (isChromeShell && textControl) {
     441             :     // Only use the selection if the target node is in the selection.
     442           0 :     bool selectionContainsTarget = false;
     443           0 :     nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(mSelectionTargetNode);
     444           0 :     selection->ContainsNode(targetNode, false, &selectionContainsTarget);
     445           0 :     if (!selectionContainsTarget)
     446           0 :       return NS_OK;
     447             : 
     448           0 :     selection.swap(*aSelection);
     449             :   }
     450             :   else {
     451             :     // In content shells, a number of checks are made below to determine
     452             :     // whether an image or a link is being dragged. If so, add additional
     453             :     // data to the data transfer. This is also done for chrome shells, but
     454             :     // only when in a non-textbox editor.
     455             : 
     456           0 :     bool haveSelectedContent = false;
     457             : 
     458             :     // possible parent link node
     459           0 :     nsCOMPtr<nsIContent> parentLink;
     460           0 :     nsCOMPtr<nsIContent> draggedNode;
     461             : 
     462             :     {
     463             :       // only drag form elements by using the alt key,
     464             :       // otherwise buttons and select widgets are hard to use
     465             : 
     466             :       // Note that while <object> elements implement nsIFormControl, we should
     467             :       // really allow dragging them if they happen to be images.
     468           0 :       nsCOMPtr<nsIFormControl> form(do_QueryInterface(mTarget));
     469           0 :       if (form && !mIsAltKeyPressed && form->ControlType() != NS_FORM_OBJECT) {
     470           0 :         *aCanDrag = false;
     471           0 :         return NS_OK;
     472             :       }
     473             : 
     474           0 :       draggedNode = mTarget;
     475             :     }
     476             : 
     477           0 :     nsCOMPtr<nsIDOMHTMLAreaElement>   area;   // client-side image map
     478           0 :     nsCOMPtr<nsIImageLoadingContent>  image;
     479           0 :     nsCOMPtr<nsIDOMHTMLAnchorElement> link;
     480             : 
     481           0 :     nsCOMPtr<nsIContent> selectedImageOrLinkNode;
     482           0 :     GetDraggableSelectionData(selection, mSelectionTargetNode,
     483           0 :                               getter_AddRefs(selectedImageOrLinkNode),
     484           0 :                               &haveSelectedContent);
     485             : 
     486             :     // either plain text or anchor text is selected
     487           0 :     if (haveSelectedContent) {
     488           0 :       selection.swap(*aSelection);
     489           0 :     } else if (selectedImageOrLinkNode) {
     490             :       // an image is selected
     491           0 :       image = do_QueryInterface(selectedImageOrLinkNode);
     492             :     } else {
     493             :       // nothing is selected -
     494             :       //
     495             :       // look for draggable elements under the mouse
     496             :       //
     497             :       // if the alt key is down, don't start a drag if we're in an
     498             :       // anchor because we want to do selection.
     499           0 :       parentLink = FindParentLinkNode(draggedNode);
     500           0 :       if (parentLink && mIsAltKeyPressed) {
     501           0 :         *aCanDrag = false;
     502           0 :         return NS_OK;
     503             :       }
     504             : 
     505           0 :       area  = do_QueryInterface(draggedNode);
     506           0 :       image = do_QueryInterface(draggedNode);
     507           0 :       link  = do_QueryInterface(draggedNode);
     508             :     }
     509             : 
     510             :     {
     511             :       // set for linked images, and links
     512           0 :       nsCOMPtr<nsIContent> linkNode;
     513             : 
     514           0 :       if (area) {
     515             :         // use the alt text (or, if missing, the href) as the title
     516           0 :         HTMLAreaElement* areaElem = static_cast<HTMLAreaElement*>(area.get());
     517           0 :         areaElem->GetAttribute(NS_LITERAL_STRING("alt"), mTitleString);
     518           0 :         if (mTitleString.IsEmpty()) {
     519             :           // this can be a relative link
     520           0 :           areaElem->GetAttribute(NS_LITERAL_STRING("href"), mTitleString);
     521             :         }
     522             : 
     523             :         // we'll generate HTML like <a href="absurl">alt text</a>
     524           0 :         mIsAnchor = true;
     525             : 
     526             :         // gives an absolute link
     527           0 :         nsresult rv = GetAnchorURL(draggedNode, mUrlString);
     528           0 :         NS_ENSURE_SUCCESS(rv, rv);
     529             : 
     530           0 :         mHtmlString.AssignLiteral("<a href=\"");
     531           0 :         mHtmlString.Append(mUrlString);
     532           0 :         mHtmlString.AppendLiteral("\">");
     533           0 :         mHtmlString.Append(mTitleString);
     534           0 :         mHtmlString.AppendLiteral("</a>");
     535             : 
     536           0 :         dragNode = draggedNode;
     537           0 :       } else if (image) {
     538           0 :         mIsAnchor = true;
     539             :         // grab the href as the url, use alt text as the title of the
     540             :         // area if it's there.  the drag data is the image tag and src
     541             :         // attribute.
     542           0 :         nsCOMPtr<nsIURI> imageURI;
     543           0 :         image->GetCurrentURI(getter_AddRefs(imageURI));
     544           0 :         if (imageURI) {
     545           0 :           nsAutoCString spec;
     546           0 :           rv = imageURI->GetSpec(spec);
     547           0 :           NS_ENSURE_SUCCESS(rv, rv);
     548           0 :           CopyUTF8toUTF16(spec, mUrlString);
     549             :         }
     550             : 
     551           0 :         nsCOMPtr<nsIDOMElement> imageElement(do_QueryInterface(image));
     552             :         // XXXbz Shouldn't we use the "title" attr for title?  Using
     553             :         // "alt" seems very wrong....
     554           0 :         if (imageElement) {
     555           0 :           imageElement->GetAttribute(NS_LITERAL_STRING("alt"), mTitleString);
     556             :         }
     557             : 
     558           0 :         if (mTitleString.IsEmpty()) {
     559           0 :           mTitleString = mUrlString;
     560             :         }
     561             : 
     562           0 :         nsCOMPtr<imgIRequest> imgRequest;
     563             : 
     564             :         // grab the image data, and its request.
     565             :         nsCOMPtr<imgIContainer> img =
     566           0 :           nsContentUtils::GetImageFromContent(image,
     567           0 :                                               getter_AddRefs(imgRequest));
     568             : 
     569             :         nsCOMPtr<nsIMIMEService> mimeService =
     570           0 :           do_GetService("@mozilla.org/mime;1");
     571             : 
     572             :         // Fix the file extension in the URL if necessary
     573           0 :         if (imgRequest && mimeService) {
     574           0 :           nsCOMPtr<nsIURI> imgUri;
     575           0 :           imgRequest->GetURI(getter_AddRefs(imgUri));
     576             : 
     577           0 :           nsCOMPtr<nsIURL> imgUrl(do_QueryInterface(imgUri));
     578             : 
     579           0 :           if (imgUrl) {
     580           0 :             nsAutoCString extension;
     581           0 :             imgUrl->GetFileExtension(extension);
     582             : 
     583           0 :             nsXPIDLCString mimeType;
     584           0 :             imgRequest->GetMimeType(getter_Copies(mimeType));
     585             : 
     586           0 :             nsCOMPtr<nsIMIMEInfo> mimeInfo;
     587           0 :             mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
     588           0 :                                                  getter_AddRefs(mimeInfo));
     589             : 
     590           0 :             if (mimeInfo) {
     591           0 :               nsAutoCString spec;
     592           0 :               rv = imgUrl->GetSpec(spec);
     593           0 :               NS_ENSURE_SUCCESS(rv, rv);
     594             : 
     595             :               // pass out the image source string
     596           0 :               CopyUTF8toUTF16(spec, mImageSourceString);
     597             : 
     598             :               bool validExtension;
     599           0 :               if (extension.IsEmpty() ||
     600           0 :                   NS_FAILED(mimeInfo->ExtensionExists(extension,
     601           0 :                                                       &validExtension)) ||
     602           0 :                   !validExtension) {
     603             :                 // Fix the file extension in the URL
     604           0 :                 nsresult rv = imgUrl->Clone(getter_AddRefs(imgUri));
     605           0 :                 NS_ENSURE_SUCCESS(rv, rv);
     606             : 
     607           0 :                 imgUrl = do_QueryInterface(imgUri);
     608             : 
     609           0 :                 nsAutoCString primaryExtension;
     610           0 :                 mimeInfo->GetPrimaryExtension(primaryExtension);
     611             : 
     612           0 :                 imgUrl->SetFileExtension(primaryExtension);
     613             :               }
     614             : 
     615           0 :               nsAutoCString fileName;
     616           0 :               imgUrl->GetFileName(fileName);
     617             : 
     618           0 :               NS_UnescapeURL(fileName);
     619             : 
     620             :               // make the filename safe for the filesystem
     621             :               fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS,
     622           0 :                                    '-');
     623             : 
     624           0 :               CopyUTF8toUTF16(fileName, mImageDestFileName);
     625             : 
     626             :               // and the image object
     627           0 :               mImage = img;
     628             :             }
     629             :           }
     630             :         }
     631             : 
     632           0 :         if (parentLink) {
     633             :           // If we are dragging around an image in an anchor, then we
     634             :           // are dragging the entire anchor
     635           0 :           linkNode = parentLink;
     636           0 :           nodeToSerialize = linkNode;
     637             :         } else {
     638           0 :           nodeToSerialize = do_QueryInterface(draggedNode);
     639             :         }
     640           0 :         dragNode = nodeToSerialize;
     641           0 :       } else if (link) {
     642             :         // set linkNode. The code below will handle this
     643           0 :         linkNode = do_QueryInterface(link);    // XXX test this
     644           0 :         GetNodeString(draggedNode, mTitleString);
     645           0 :       } else if (parentLink) {
     646             :         // parentLink will always be null if there's selected content
     647           0 :         linkNode = parentLink;
     648           0 :         nodeToSerialize = linkNode;
     649           0 :       } else if (!haveSelectedContent) {
     650             :         // nothing draggable
     651           0 :         return NS_OK;
     652             :       }
     653             : 
     654           0 :       if (linkNode) {
     655           0 :         mIsAnchor = true;
     656           0 :         rv = GetAnchorURL(linkNode, mUrlString);
     657           0 :         NS_ENSURE_SUCCESS(rv, rv);
     658           0 :         dragNode = linkNode;
     659             :       }
     660             :     }
     661             :   }
     662             : 
     663           0 :   if (nodeToSerialize || *aSelection) {
     664           0 :     mHtmlString.Truncate();
     665           0 :     mContextString.Truncate();
     666           0 :     mInfoString.Truncate();
     667           0 :     mTitleString.Truncate();
     668             : 
     669           0 :     nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
     670           0 :     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
     671             : 
     672             :     // if we have selected text, use it in preference to the node
     673           0 :     nsCOMPtr<nsITransferable> transferable;
     674           0 :     if (*aSelection) {
     675           0 :       rv = nsCopySupport::GetTransferableForSelection(*aSelection, doc,
     676           0 :                                                       getter_AddRefs(transferable));
     677             :     }
     678             :     else {
     679           0 :       rv = nsCopySupport::GetTransferableForNode(nodeToSerialize, doc,
     680           0 :                                                  getter_AddRefs(transferable));
     681             :     }
     682           0 :     NS_ENSURE_SUCCESS(rv, rv);
     683             : 
     684           0 :     nsCOMPtr<nsISupports> supports;
     685           0 :     nsCOMPtr<nsISupportsString> data;
     686             :     uint32_t dataSize;
     687           0 :     rv = transferable->GetTransferData(kHTMLMime, getter_AddRefs(supports),
     688           0 :                                        &dataSize);
     689           0 :     data = do_QueryInterface(supports);
     690           0 :     if (NS_SUCCEEDED(rv)) {
     691           0 :       data->GetData(mHtmlString);
     692             :     }
     693           0 :     rv = transferable->GetTransferData(kHTMLContext, getter_AddRefs(supports),
     694           0 :                                        &dataSize);
     695           0 :     data = do_QueryInterface(supports);
     696           0 :     if (NS_SUCCEEDED(rv)) {
     697           0 :       data->GetData(mContextString);
     698             :     }
     699           0 :     rv = transferable->GetTransferData(kHTMLInfo, getter_AddRefs(supports),
     700           0 :                                        &dataSize);
     701           0 :     data = do_QueryInterface(supports);
     702           0 :     if (NS_SUCCEEDED(rv)) {
     703           0 :       data->GetData(mInfoString);
     704             :     }
     705           0 :     rv = transferable->GetTransferData(kUnicodeMime, getter_AddRefs(supports),
     706           0 :                                        &dataSize);
     707           0 :     data = do_QueryInterface(supports);
     708           0 :     NS_ENSURE_SUCCESS(rv, rv); // require plain text at a minimum
     709           0 :     data->GetData(mTitleString);
     710             :   }
     711             : 
     712             :   // default text value is the URL
     713           0 :   if (mTitleString.IsEmpty()) {
     714           0 :     mTitleString = mUrlString;
     715             :   }
     716             : 
     717             :   // if we haven't constructed a html version, make one now
     718           0 :   if (mHtmlString.IsEmpty() && !mUrlString.IsEmpty())
     719           0 :     CreateLinkText(mUrlString, mTitleString, mHtmlString);
     720             : 
     721             :   // if there is no drag node, which will be the case for a selection, just
     722             :   // use the selection target node.
     723           0 :   rv = AddStringsToDataTransfer(
     724           0 :          dragNode ? dragNode : mSelectionTargetNode.get(), aDataTransfer);
     725           0 :   NS_ENSURE_SUCCESS(rv, rv);
     726             : 
     727           0 :   NS_IF_ADDREF(*aDragNode = dragNode);
     728           0 :   return NS_OK;
     729             : }
     730             : 
     731             : void
     732           0 : DragDataProducer::AddString(DataTransfer* aDataTransfer,
     733             :                             const nsAString& aFlavor,
     734             :                             const nsAString& aData,
     735             :                             nsIPrincipal* aPrincipal)
     736             : {
     737           0 :   RefPtr<nsVariantCC> variant = new nsVariantCC();
     738           0 :   variant->SetAsAString(aData);
     739           0 :   aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal);
     740           0 : }
     741             : 
     742             : nsresult
     743           0 : DragDataProducer::AddStringsToDataTransfer(nsIContent* aDragNode,
     744             :                                            DataTransfer* aDataTransfer)
     745             : {
     746           0 :   NS_ASSERTION(aDragNode, "adding strings for null node");
     747             : 
     748             :   // set all of the data to have the principal of the node where the data came from
     749           0 :   nsIPrincipal* principal = aDragNode->NodePrincipal();
     750             : 
     751             :   // add a special flavor if we're an anchor to indicate that we have
     752             :   // a URL in the drag data
     753           0 :   if (!mUrlString.IsEmpty() && mIsAnchor) {
     754           0 :     nsAutoString dragData(mUrlString);
     755           0 :     dragData.Append('\n');
     756             :     // Remove leading and trailing newlines in the title and replace them with
     757             :     // space in remaining positions - they confuse PlacesUtils::unwrapNodes
     758             :     // that expects url\ntitle formatted data for x-moz-url.
     759           0 :     nsAutoString title(mTitleString);
     760           0 :     title.Trim("\r\n");
     761           0 :     title.ReplaceChar("\r\n", ' ');
     762           0 :     dragData += title;
     763             : 
     764           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kURLMime), dragData, principal);
     765           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kURLDataMime), mUrlString, principal);
     766           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kURLDescriptionMime), mTitleString, principal);
     767           0 :     AddString(aDataTransfer, NS_LITERAL_STRING("text/uri-list"), mUrlString, principal);
     768             :   }
     769             : 
     770             :   // add a special flavor for the html context data
     771           0 :   if (!mContextString.IsEmpty())
     772           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), mContextString, principal);
     773             : 
     774             :   // add a special flavor if we have html info data
     775           0 :   if (!mInfoString.IsEmpty())
     776           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), mInfoString, principal);
     777             : 
     778             :   // add the full html
     779           0 :   if (!mHtmlString.IsEmpty())
     780           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLMime), mHtmlString, principal);
     781             : 
     782             :   // add the plain text. we use the url for text/plain data if an anchor is
     783             :   // being dragged, rather than the title text of the link or the alt text for
     784             :   // an anchor image.
     785           0 :   AddString(aDataTransfer, NS_LITERAL_STRING(kTextMime),
     786           0 :             mIsAnchor ? mUrlString : mTitleString, principal);
     787             : 
     788             :   // add image data, if present. For now, all we're going to do with
     789             :   // this is turn it into a native data flavor, so indicate that with
     790             :   // a new flavor so as not to confuse anyone who is really registered
     791             :   // for image/gif or image/jpg.
     792           0 :   if (mImage) {
     793           0 :     RefPtr<nsVariantCC> variant = new nsVariantCC();
     794           0 :     variant->SetAsISupports(mImage);
     795           0 :     aDataTransfer->SetDataWithPrincipal(NS_LITERAL_STRING(kNativeImageMime),
     796           0 :                                         variant, 0, principal);
     797             : 
     798             :     // assume the image comes from a file, and add a file promise. We
     799             :     // register ourselves as a nsIFlavorDataProvider, and will use the
     800             :     // GetFlavorData callback to save the image to disk.
     801             : 
     802             :     nsCOMPtr<nsIFlavorDataProvider> dataProvider =
     803           0 :       new nsContentAreaDragDropDataProvider();
     804           0 :     if (dataProvider) {
     805           0 :       RefPtr<nsVariantCC> variant = new nsVariantCC();
     806           0 :       variant->SetAsISupports(dataProvider);
     807           0 :       aDataTransfer->SetDataWithPrincipal(NS_LITERAL_STRING(kFilePromiseMime),
     808           0 :                                           variant, 0, principal);
     809             :     }
     810             : 
     811           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kFilePromiseURLMime),
     812           0 :               mImageSourceString, principal);
     813           0 :     AddString(aDataTransfer, NS_LITERAL_STRING(kFilePromiseDestFilename),
     814           0 :               mImageDestFileName, principal);
     815             : 
     816             :     // if not an anchor, add the image url
     817           0 :     if (!mIsAnchor) {
     818           0 :       AddString(aDataTransfer, NS_LITERAL_STRING(kURLDataMime), mUrlString, principal);
     819           0 :       AddString(aDataTransfer, NS_LITERAL_STRING("text/uri-list"), mUrlString, principal);
     820             :     }
     821             :   }
     822             : 
     823           0 :   return NS_OK;
     824             : }
     825             : 
     826             : // note that this can return NS_OK, but a null out param (by design)
     827             : // static
     828             : nsresult
     829           0 : DragDataProducer::GetDraggableSelectionData(nsISelection* inSelection,
     830             :                                             nsIContent* inRealTargetNode,
     831             :                                             nsIContent **outImageOrLinkNode,
     832             :                                             bool* outDragSelectedText)
     833             : {
     834           0 :   NS_ENSURE_ARG(inSelection);
     835           0 :   NS_ENSURE_ARG(inRealTargetNode);
     836           0 :   NS_ENSURE_ARG_POINTER(outImageOrLinkNode);
     837             : 
     838           0 :   *outImageOrLinkNode = nullptr;
     839           0 :   *outDragSelectedText = false;
     840             : 
     841           0 :   bool selectionContainsTarget = false;
     842             : 
     843           0 :   bool isCollapsed = false;
     844           0 :   inSelection->GetIsCollapsed(&isCollapsed);
     845           0 :   if (!isCollapsed) {
     846           0 :     nsCOMPtr<nsIDOMNode> realTargetNode = do_QueryInterface(inRealTargetNode);
     847           0 :     inSelection->ContainsNode(realTargetNode, false,
     848           0 :                               &selectionContainsTarget);
     849             : 
     850           0 :     if (selectionContainsTarget) {
     851             :       // track down the anchor node, if any, for the url
     852           0 :       nsCOMPtr<nsIDOMNode> selectionStart;
     853           0 :       inSelection->GetAnchorNode(getter_AddRefs(selectionStart));
     854             : 
     855           0 :       nsCOMPtr<nsIDOMNode> selectionEnd;
     856           0 :       inSelection->GetFocusNode(getter_AddRefs(selectionEnd));
     857             : 
     858             :       // look for a selection around a single node, like an image.
     859             :       // in this case, drag the image, rather than a serialization of the HTML
     860             :       // XXX generalize this to other draggable element types?
     861           0 :       if (selectionStart == selectionEnd) {
     862             :         bool hasChildren;
     863           0 :         selectionStart->HasChildNodes(&hasChildren);
     864           0 :         if (hasChildren) {
     865             :           // see if just one node is selected
     866             :           int32_t anchorOffset, focusOffset;
     867           0 :           inSelection->GetAnchorOffset(&anchorOffset);
     868           0 :           inSelection->GetFocusOffset(&focusOffset);
     869           0 :           if (abs(anchorOffset - focusOffset) == 1) {
     870             :             nsCOMPtr<nsIContent> selStartContent =
     871           0 :               do_QueryInterface(selectionStart);
     872             : 
     873           0 :             if (selStartContent) {
     874             :               int32_t childOffset =
     875           0 :                 (anchorOffset < focusOffset) ? anchorOffset : focusOffset;
     876             :               nsIContent *childContent =
     877           0 :                 selStartContent->GetChildAt(childOffset);
     878             :               // if we find an image, we'll fall into the node-dragging code,
     879             :               // rather the the selection-dragging code
     880           0 :               if (nsContentUtils::IsDraggableImage(childContent)) {
     881           0 :                 NS_ADDREF(*outImageOrLinkNode = childContent);
     882           0 :                 return NS_OK;
     883             :               }
     884             :             }
     885             :           }
     886             :         }
     887             :       }
     888             : 
     889             :       // indicate that a link or text is selected
     890           0 :       *outDragSelectedText = true;
     891             :     }
     892             :   }
     893             : 
     894           0 :   return NS_OK;
     895             : }

Generated by: LCOV version 1.13