LCOV - code coverage report
Current view: top level - dom/base - nsCopySupport.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 18 369 4.9 %
Date: 2017-07-14 16:53:18 Functions: 2 15 13.3 %
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 "nsCopySupport.h"
       8             : #include "nsIDocumentEncoder.h"
       9             : #include "nsISupports.h"
      10             : #include "nsIContent.h"
      11             : #include "nsIComponentManager.h"
      12             : #include "nsIServiceManager.h"
      13             : #include "nsIClipboard.h"
      14             : #include "nsIFormControl.h"
      15             : #include "nsISelection.h"
      16             : #include "nsWidgetsCID.h"
      17             : #include "nsXPCOM.h"
      18             : #include "nsISupportsPrimitives.h"
      19             : #include "nsIDOMRange.h"
      20             : #include "nsRange.h"
      21             : #include "imgIContainer.h"
      22             : #include "imgIRequest.h"
      23             : #include "nsIPresShell.h"
      24             : #include "nsFocusManager.h"
      25             : #include "mozilla/dom/DataTransfer.h"
      26             : 
      27             : #include "nsIDocShell.h"
      28             : #include "nsIContentViewerEdit.h"
      29             : #include "nsIClipboardDragDropHooks.h"
      30             : #include "nsIClipboardDragDropHookList.h"
      31             : #include "nsIClipboardHelper.h"
      32             : #include "nsISelectionController.h"
      33             : 
      34             : #include "nsPIDOMWindow.h"
      35             : #include "nsIDocument.h"
      36             : #include "nsIDOMNode.h"
      37             : #include "nsIDOMElement.h"
      38             : #include "nsIDOMDocument.h"
      39             : #include "nsIHTMLDocument.h"
      40             : #include "nsGkAtoms.h"
      41             : #include "nsIFrame.h"
      42             : #include "nsIURI.h"
      43             : #include "nsISimpleEnumerator.h"
      44             : 
      45             : // image copy stuff
      46             : #include "nsIImageLoadingContent.h"
      47             : #include "nsIInterfaceRequestorUtils.h"
      48             : #include "nsContentUtils.h"
      49             : #include "nsContentCID.h"
      50             : 
      51             : #ifdef XP_WIN
      52             : #include "nsCExternalHandlerService.h"
      53             : #include "nsEscape.h"
      54             : #include "nsIMIMEInfo.h"
      55             : #include "nsIMIMEService.h"
      56             : #include "nsIURL.h"
      57             : #include "nsReadableUtils.h"
      58             : #include "nsXULAppAPI.h"
      59             : #endif
      60             : 
      61             : #include "mozilla/ContentEvents.h"
      62             : #include "mozilla/dom/Element.h"
      63             : #include "mozilla/EventDispatcher.h"
      64             : #include "mozilla/Preferences.h"
      65             : #include "mozilla/dom/Selection.h"
      66             : #include "mozilla/IntegerRange.h"
      67             : 
      68             : using namespace mozilla;
      69             : using namespace mozilla::dom;
      70             : 
      71             : nsresult NS_NewDomSelection(nsISelection **aDomSelection);
      72             : 
      73             : static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
      74             : static NS_DEFINE_CID(kCTransferableCID,        NS_TRANSFERABLE_CID);
      75             : static NS_DEFINE_CID(kHTMLConverterCID,        NS_HTMLFORMATCONVERTER_CID);
      76             : 
      77             : // copy string data onto the transferable
      78             : static nsresult AppendString(nsITransferable *aTransferable,
      79             :                              const nsAString& aString,
      80             :                              const char* aFlavor);
      81             : 
      82             : // copy HTML node data
      83             : static nsresult AppendDOMNode(nsITransferable *aTransferable,
      84             :                               nsINode* aDOMNode);
      85             : 
      86             : #ifdef XP_WIN
      87             : // copy image as file promise onto the transferable
      88             : static nsresult AppendImagePromise(nsITransferable* aTransferable,
      89             :                                    imgIRequest* aImgRequest,
      90             :                                    nsIImageLoadingContent* aImageElement);
      91             : #endif
      92             : 
      93             : // Helper used for HTMLCopy and GetTransferableForSelection since both routines
      94             : // share common code.
      95             : static nsresult
      96           0 : SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
      97             :                     bool doPutOnClipboard, int16_t aClipboardID,
      98             :                     uint32_t aFlags, nsITransferable ** aTransferable)
      99             : {
     100             :   // Clear the output parameter for the transferable, if provided.
     101           0 :   if (aTransferable) {
     102           0 :     *aTransferable = nullptr;
     103             :   }
     104             : 
     105             :   nsresult rv;
     106             : 
     107           0 :   nsCOMPtr<nsIDocumentEncoder> docEncoder;
     108           0 :   docEncoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID);
     109           0 :   NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
     110             : 
     111             :   // note that we assign text/unicode as mime type, but in fact nsHTMLCopyEncoder
     112             :   // ignore it and use text/html or text/plain depending where the selection
     113             :   // is. if it is a selection into input/textarea element or in a html content
     114             :   // with pre-wrap style : text/plain. Otherwise text/html.
     115             :   // see nsHTMLCopyEncoder::SetSelection
     116           0 :   nsAutoString mimeType;
     117           0 :   mimeType.AssignLiteral(kUnicodeMime);
     118             : 
     119             :   // Do the first and potentially trial encoding as preformatted and raw.
     120             :   uint32_t flags = aFlags | nsIDocumentEncoder::OutputPreformatted
     121             :                           | nsIDocumentEncoder::OutputRaw
     122           0 :                           | nsIDocumentEncoder::OutputForPlainTextClipboardCopy;
     123             : 
     124           0 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
     125           0 :   NS_ASSERTION(domDoc, "Need a document");
     126             : 
     127           0 :   rv = docEncoder->Init(domDoc, mimeType, flags);
     128           0 :   NS_ENSURE_SUCCESS(rv, rv);
     129             : 
     130           0 :   rv = docEncoder->SetSelection(aSel);
     131           0 :   NS_ENSURE_SUCCESS(rv, rv);
     132             : 
     133             :   // SetSelection set the mime type to text/plain if the selection is inside a
     134             :   // text widget.
     135           0 :   rv = docEncoder->GetMimeType(mimeType);
     136           0 :   NS_ENSURE_SUCCESS(rv, rv);
     137           0 :   bool selForcedTextPlain = mimeType.EqualsLiteral(kTextMime);
     138             : 
     139           0 :   nsAutoString buf;
     140           0 :   rv = docEncoder->EncodeToString(buf);
     141           0 :   NS_ENSURE_SUCCESS(rv, rv);
     142             : 
     143           0 :   rv = docEncoder->GetMimeType(mimeType);
     144           0 :   NS_ENSURE_SUCCESS(rv, rv);
     145             : 
     146           0 :   if (!selForcedTextPlain && mimeType.EqualsLiteral(kTextMime)) {
     147             :     // SetSelection and EncodeToString use this case to signal that text/plain
     148             :     // was forced because the document is either not an nsIHTMLDocument or it's
     149             :     // XHTML.  We want to pretty print XHTML but not non-nsIHTMLDocuments.
     150           0 :     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aDoc);
     151           0 :     if (!htmlDoc) {
     152           0 :       selForcedTextPlain = true;
     153             :     }
     154             :   }
     155             : 
     156             :   // The mime type is ultimately text/html if the encoder successfully encoded
     157             :   // the selection as text/html.
     158           0 :   bool encodedTextHTML = mimeType.EqualsLiteral(kHTMLMime);
     159             : 
     160             :   // First, prepare the text/plain clipboard flavor.
     161           0 :   nsAutoString textPlainBuf;
     162           0 :   if (selForcedTextPlain) {
     163             :     // Nothing to do.  buf contains the final, preformatted, raw text/plain.
     164           0 :     textPlainBuf.Assign(buf);
     165             :   } else {
     166             :     // Redo the encoding, but this time use pretty printing.
     167           0 :     flags =
     168             :       nsIDocumentEncoder::OutputSelectionOnly |
     169             :       nsIDocumentEncoder::OutputAbsoluteLinks |
     170             :       nsIDocumentEncoder::SkipInvisibleContent |
     171             :       nsIDocumentEncoder::OutputDropInvisibleBreak |
     172           0 :       (aFlags & (nsIDocumentEncoder::OutputNoScriptContent |
     173             :                  nsIDocumentEncoder::OutputRubyAnnotation));
     174             : 
     175           0 :     mimeType.AssignLiteral(kTextMime);
     176           0 :     rv = docEncoder->Init(domDoc, mimeType, flags);
     177           0 :     NS_ENSURE_SUCCESS(rv, rv);
     178             : 
     179           0 :     rv = docEncoder->SetSelection(aSel);
     180           0 :     NS_ENSURE_SUCCESS(rv, rv);
     181             : 
     182           0 :     rv = docEncoder->EncodeToString(textPlainBuf);
     183           0 :     NS_ENSURE_SUCCESS(rv, rv);
     184             :   }
     185             : 
     186             :   // Second, prepare the text/html flavor.
     187           0 :   nsAutoString textHTMLBuf;
     188           0 :   nsAutoString htmlParentsBuf;
     189           0 :   nsAutoString htmlInfoBuf;
     190           0 :   if (encodedTextHTML) {
     191             :     // Redo the encoding, but this time use the passed-in flags.
     192             :     // Don't allow wrapping of CJK strings.
     193           0 :     mimeType.AssignLiteral(kHTMLMime);
     194           0 :     rv = docEncoder->Init(domDoc, mimeType,
     195             :                           aFlags |
     196           0 :                           nsIDocumentEncoder::OutputDisallowLineBreaking);
     197           0 :     NS_ENSURE_SUCCESS(rv, rv);
     198             : 
     199           0 :     rv = docEncoder->SetSelection(aSel);
     200           0 :     NS_ENSURE_SUCCESS(rv, rv);
     201             : 
     202           0 :     rv = docEncoder->EncodeToStringWithContext(htmlParentsBuf, htmlInfoBuf,
     203           0 :                                                textHTMLBuf);
     204           0 :     NS_ENSURE_SUCCESS(rv, rv);
     205             :   }
     206             : 
     207             :   // Get the Clipboard
     208           0 :   nsCOMPtr<nsIClipboard> clipboard;
     209           0 :   if (doPutOnClipboard) {
     210           0 :     clipboard = do_GetService(kCClipboardCID, &rv);
     211           0 :     if (NS_FAILED(rv))
     212           0 :       return rv;
     213             :   }
     214             : 
     215           0 :   if ((doPutOnClipboard && clipboard) || aTransferable != nullptr) {
     216             :     // Create a transferable for putting data on the Clipboard
     217           0 :     nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID);
     218           0 :     if (trans) {
     219           0 :       trans->Init(aDoc->GetLoadContext());
     220           0 :       if (encodedTextHTML) {
     221             :         // Set up a format converter so that clipboard flavor queries work.
     222             :         // This converter isn't really used for conversions.
     223             :         nsCOMPtr<nsIFormatConverter> htmlConverter =
     224           0 :           do_CreateInstance(kHTMLConverterCID);
     225           0 :         trans->SetConverter(htmlConverter);
     226             : 
     227           0 :         if (!textHTMLBuf.IsEmpty()) {
     228             :           // Add the html DataFlavor to the transferable
     229           0 :           rv = AppendString(trans, textHTMLBuf, kHTMLMime);
     230           0 :           NS_ENSURE_SUCCESS(rv, rv);
     231             :         }
     232             : 
     233             :         // Add the htmlcontext DataFlavor to the transferable
     234             :         // Even if parents is empty string, this flavor should
     235             :         // be attached to the transferable
     236           0 :         rv = AppendString(trans, htmlParentsBuf, kHTMLContext);
     237           0 :         NS_ENSURE_SUCCESS(rv, rv);
     238             : 
     239           0 :         if (!htmlInfoBuf.IsEmpty()) {
     240             :           // Add the htmlinfo DataFlavor to the transferable
     241           0 :           rv = AppendString(trans, htmlInfoBuf, kHTMLInfo);
     242           0 :           NS_ENSURE_SUCCESS(rv, rv);
     243             :         }
     244             : 
     245           0 :         if (!textPlainBuf.IsEmpty()) {
     246             :           // unicode text
     247             :           // Add the unicode DataFlavor to the transferable
     248             :           // If we didn't have this, then nsDataObj::GetData matches text/unicode against
     249             :           // the kURLMime flavour which is not desirable (eg. when pasting into Notepad)
     250           0 :           rv = AppendString(trans, textPlainBuf, kUnicodeMime);
     251           0 :           NS_ENSURE_SUCCESS(rv, rv);
     252             :         }
     253             : 
     254             :         // Try and get source URI of the items that are being dragged
     255           0 :         nsIURI *uri = aDoc->GetDocumentURI();
     256           0 :         if (uri) {
     257           0 :           nsAutoCString spec;
     258           0 :           nsresult rv = uri->GetSpec(spec);
     259           0 :           NS_ENSURE_SUCCESS(rv, rv);
     260           0 :           if (!spec.IsEmpty()) {
     261           0 :             nsAutoString shortcut;
     262           0 :             AppendUTF8toUTF16(spec, shortcut);
     263             : 
     264             :             // Add the URL DataFlavor to the transferable. Don't use kURLMime, as it will
     265             :             // cause an unnecessary UniformResourceLocator to be added which confuses
     266             :             // some apps eg. Outlook 2000 - (See Bug 315370). Don't use
     267             :             // kURLDataMime, as it will cause a bogus 'url ' flavor to
     268             :             // show up on the Mac clipboard, confusing other apps, like
     269             :             // Terminal (see bug 336012).
     270           0 :             rv = AppendString(trans, shortcut, kURLPrivateMime);
     271           0 :             NS_ENSURE_SUCCESS(rv, rv);
     272             :           }
     273             :         }
     274             :       } else {
     275           0 :         if (!textPlainBuf.IsEmpty()) {
     276             :           // Add the unicode DataFlavor to the transferable
     277           0 :           rv = AppendString(trans, textPlainBuf, kUnicodeMime);
     278           0 :           NS_ENSURE_SUCCESS(rv, rv);
     279             :         }
     280             :       }
     281             : 
     282           0 :       if (doPutOnClipboard && clipboard) {
     283           0 :         bool actuallyPutOnClipboard = true;
     284           0 :         nsCopySupport::DoHooks(aDoc, trans, &actuallyPutOnClipboard);
     285             : 
     286             :         // put the transferable on the clipboard
     287           0 :         if (actuallyPutOnClipboard)
     288           0 :           clipboard->SetData(trans, nullptr, aClipboardID);
     289             :       }
     290             : 
     291             :       // Return the transferable to the caller if requested.
     292           0 :       if (aTransferable != nullptr) {
     293           0 :         trans.swap(*aTransferable);
     294             :       }
     295             :     }
     296             :   }
     297           0 :   return rv;
     298             : }
     299             : 
     300             : nsresult
     301           0 : nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc,
     302             :                         int16_t aClipboardID, bool aWithRubyAnnotation)
     303             : {
     304           0 :   uint32_t flags = nsIDocumentEncoder::SkipInvisibleContent;
     305           0 :   if (aWithRubyAnnotation) {
     306           0 :     flags |= nsIDocumentEncoder::OutputRubyAnnotation;
     307             :   }
     308           0 :   return SelectionCopyHelper(aSel, aDoc, true, aClipboardID, flags, nullptr);
     309             : }
     310             : 
     311             : nsresult
     312           0 : nsCopySupport::ClearSelectionCache()
     313             : {
     314             :   nsresult rv;
     315           0 :   nsCOMPtr<nsIClipboard> clipboard = do_GetService(kCClipboardCID, &rv);
     316           0 :   clipboard->EmptyClipboard(nsIClipboard::kSelectionCache);
     317           0 :   return rv;
     318             : }
     319             : 
     320             : nsresult
     321           0 : nsCopySupport::GetTransferableForSelection(nsISelection* aSel,
     322             :                                            nsIDocument* aDoc,
     323             :                                            nsITransferable** aTransferable)
     324             : {
     325             :   return SelectionCopyHelper(aSel, aDoc, false, 0,
     326             :                              nsIDocumentEncoder::SkipInvisibleContent,
     327           0 :                              aTransferable);
     328             : }
     329             : 
     330             : nsresult
     331           0 : nsCopySupport::GetTransferableForNode(nsINode* aNode,
     332             :                                       nsIDocument* aDoc,
     333             :                                       nsITransferable** aTransferable)
     334             : {
     335           0 :   nsCOMPtr<nsISelection> selection;
     336             :   // Make a temporary selection with aNode in a single range.
     337             :   // XXX We should try to get rid of the Selection object here.
     338             :   // XXX bug 1245883
     339           0 :   nsresult rv = NS_NewDomSelection(getter_AddRefs(selection));
     340           0 :   NS_ENSURE_SUCCESS(rv, rv);
     341           0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
     342           0 :   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
     343           0 :   RefPtr<nsRange> range = new nsRange(aNode);
     344           0 :   rv = range->SelectNode(node);
     345           0 :   NS_ENSURE_SUCCESS(rv, rv);
     346           0 :   ErrorResult result;
     347           0 :   selection->AsSelection()->AddRangeInternal(*range, aDoc, result);
     348           0 :   rv = result.StealNSResult();
     349           0 :   NS_ENSURE_SUCCESS(rv, rv);
     350             :   // It's not the primary selection - so don't skip invisible content.
     351           0 :   uint32_t flags = 0;
     352           0 :   return SelectionCopyHelper(selection, aDoc, false, 0, flags,
     353           0 :                              aTransferable);
     354             : }
     355             : 
     356           0 : nsresult nsCopySupport::DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
     357             :                                 bool *aDoPutOnClipboard)
     358             : {
     359           0 :   NS_ENSURE_ARG(aDoc);
     360             : 
     361           0 :   *aDoPutOnClipboard = true;
     362             : 
     363           0 :   nsCOMPtr<nsISupports> container = aDoc->GetContainer();
     364           0 :   nsCOMPtr<nsIClipboardDragDropHookList> hookObj = do_GetInterface(container);
     365           0 :   if (!hookObj) return NS_ERROR_FAILURE;
     366             : 
     367           0 :   nsCOMPtr<nsISimpleEnumerator> enumerator;
     368           0 :   hookObj->GetHookEnumerator(getter_AddRefs(enumerator));
     369           0 :   if (!enumerator) return NS_ERROR_FAILURE;
     370             : 
     371             :   // the logic here should follow the behavior specified in
     372             :   // nsIClipboardDragDropHooks.h
     373             : 
     374           0 :   nsCOMPtr<nsIClipboardDragDropHooks> override;
     375           0 :   nsCOMPtr<nsISupports> isupp;
     376           0 :   bool hasMoreHooks = false;
     377           0 :   nsresult rv = NS_OK;
     378           0 :   while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks))
     379           0 :          && hasMoreHooks)
     380             :   {
     381           0 :     rv = enumerator->GetNext(getter_AddRefs(isupp));
     382           0 :     if (NS_FAILED(rv)) break;
     383           0 :     override = do_QueryInterface(isupp);
     384           0 :     if (override)
     385             :     {
     386             : #ifdef DEBUG
     387             :       nsresult hookResult =
     388             : #endif
     389           0 :       override->OnCopyOrDrag(nullptr, aTrans, aDoPutOnClipboard);
     390           0 :       NS_ASSERTION(NS_SUCCEEDED(hookResult), "OnCopyOrDrag hook failed");
     391           0 :       if (!*aDoPutOnClipboard)
     392           0 :         break;
     393             :     }
     394             :   }
     395             : 
     396           0 :   return rv;
     397             : }
     398             : 
     399             : nsresult
     400           0 : nsCopySupport::GetContents(const nsACString& aMimeType, uint32_t aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata)
     401             : {
     402           0 :   nsresult rv = NS_OK;
     403             : 
     404           0 :   nsCOMPtr<nsIDocumentEncoder> docEncoder;
     405             : 
     406           0 :   nsAutoCString encoderContractID(NS_DOC_ENCODER_CONTRACTID_BASE);
     407           0 :   encoderContractID.Append(aMimeType);
     408             : 
     409           0 :   docEncoder = do_CreateInstance(encoderContractID.get());
     410           0 :   NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
     411             : 
     412           0 :   uint32_t flags = aFlags | nsIDocumentEncoder::SkipInvisibleContent;
     413             : 
     414           0 :   if (aMimeType.EqualsLiteral("text/plain"))
     415           0 :     flags |= nsIDocumentEncoder::OutputPreformatted;
     416             : 
     417           0 :   NS_ConvertASCIItoUTF16 unicodeMimeType(aMimeType);
     418             : 
     419           0 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
     420           0 :   NS_ASSERTION(domDoc, "Need a document");
     421             : 
     422           0 :   rv = docEncoder->Init(domDoc, unicodeMimeType, flags);
     423           0 :   if (NS_FAILED(rv)) return rv;
     424             : 
     425           0 :   if (aSel)
     426             :   {
     427           0 :     rv = docEncoder->SetSelection(aSel);
     428           0 :     if (NS_FAILED(rv)) return rv;
     429             :   }
     430             : 
     431             :   // encode the selection
     432           0 :   return docEncoder->EncodeToString(outdata);
     433             : }
     434             : 
     435             : 
     436             : nsresult
     437           0 : nsCopySupport::ImageCopy(nsIImageLoadingContent* aImageElement,
     438             :                          nsILoadContext* aLoadContext,
     439             :                          int32_t aCopyFlags)
     440             : {
     441             :   nsresult rv;
     442             : 
     443             :   // create a transferable for putting data on the Clipboard
     444           0 :   nsCOMPtr<nsITransferable> trans(do_CreateInstance(kCTransferableCID, &rv));
     445           0 :   NS_ENSURE_SUCCESS(rv, rv);
     446           0 :   trans->Init(aLoadContext);
     447             : 
     448           0 :   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_TEXT) {
     449             :     // get the location from the element
     450           0 :     nsCOMPtr<nsIURI> uri;
     451           0 :     rv = aImageElement->GetCurrentURI(getter_AddRefs(uri));
     452           0 :     NS_ENSURE_SUCCESS(rv, rv);
     453           0 :     NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
     454             : 
     455           0 :     nsAutoCString location;
     456           0 :     rv = uri->GetSpec(location);
     457           0 :     NS_ENSURE_SUCCESS(rv, rv);
     458             : 
     459             :     // append the string to the transferable
     460           0 :     rv = AppendString(trans, NS_ConvertUTF8toUTF16(location), kUnicodeMime);
     461           0 :     NS_ENSURE_SUCCESS(rv, rv);
     462             :   }
     463             : 
     464           0 :   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_HTML) {
     465             :     // append HTML data to the transferable
     466           0 :     nsCOMPtr<nsINode> node(do_QueryInterface(aImageElement, &rv));
     467           0 :     NS_ENSURE_SUCCESS(rv, rv);
     468             : 
     469           0 :     rv = AppendDOMNode(trans, node);
     470           0 :     NS_ENSURE_SUCCESS(rv, rv);
     471             :   }
     472             : 
     473           0 :   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_DATA) {
     474             :     // get the image data and its request from the element
     475           0 :     nsCOMPtr<imgIRequest> imgRequest;
     476             :     nsCOMPtr<imgIContainer> image =
     477           0 :       nsContentUtils::GetImageFromContent(aImageElement,
     478           0 :                                           getter_AddRefs(imgRequest));
     479           0 :     NS_ENSURE_TRUE(image, NS_ERROR_FAILURE);
     480             : 
     481             : #ifdef XP_WIN
     482             :     rv = AppendImagePromise(trans, imgRequest, aImageElement);
     483             :     NS_ENSURE_SUCCESS(rv, rv);
     484             : #endif
     485             : 
     486             :     nsCOMPtr<nsISupportsInterfacePointer>
     487           0 :       imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
     488           0 :     NS_ENSURE_SUCCESS(rv, rv);
     489             : 
     490           0 :     rv = imgPtr->SetData(image);
     491           0 :     NS_ENSURE_SUCCESS(rv, rv);
     492             : 
     493             :     // copy the image data onto the transferable
     494           0 :     rv = trans->SetTransferData(kNativeImageMime, imgPtr,
     495           0 :                                 sizeof(nsISupports*));
     496           0 :     NS_ENSURE_SUCCESS(rv, rv);
     497             :   }
     498             : 
     499             :   // get clipboard
     500           0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
     501           0 :   NS_ENSURE_SUCCESS(rv, rv);
     502             : 
     503             :   // check whether the system supports the selection clipboard or not.
     504             :   bool selectionSupported;
     505           0 :   rv = clipboard->SupportsSelectionClipboard(&selectionSupported);
     506           0 :   NS_ENSURE_SUCCESS(rv, rv);
     507             : 
     508             :   // put the transferable on the clipboard
     509           0 :   if (selectionSupported) {
     510           0 :     rv = clipboard->SetData(trans, nullptr, nsIClipboard::kSelectionClipboard);
     511           0 :     NS_ENSURE_SUCCESS(rv, rv);
     512             :   }
     513             : 
     514           0 :   return clipboard->SetData(trans, nullptr, nsIClipboard::kGlobalClipboard);
     515             : }
     516             : 
     517           0 : static nsresult AppendString(nsITransferable *aTransferable,
     518             :                              const nsAString& aString,
     519             :                              const char* aFlavor)
     520             : {
     521             :   nsresult rv;
     522             : 
     523             :   nsCOMPtr<nsISupportsString>
     524           0 :     data(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
     525           0 :   NS_ENSURE_SUCCESS(rv, rv);
     526             : 
     527           0 :   rv = data->SetData(aString);
     528           0 :   NS_ENSURE_SUCCESS(rv, rv);
     529             : 
     530           0 :   rv = aTransferable->AddDataFlavor(aFlavor);
     531           0 :   NS_ENSURE_SUCCESS(rv, rv);
     532             : 
     533           0 :   return aTransferable->SetTransferData(aFlavor, data,
     534           0 :                                         aString.Length() * sizeof(char16_t));
     535             : }
     536             : 
     537           0 : static nsresult AppendDOMNode(nsITransferable *aTransferable,
     538             :                               nsINode *aDOMNode)
     539             : {
     540             :   nsresult rv;
     541             : 
     542             :   // selializer
     543             :   nsCOMPtr<nsIDocumentEncoder>
     544           0 :     docEncoder(do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID, &rv));
     545           0 :   NS_ENSURE_SUCCESS(rv, rv);
     546             : 
     547             :   // get document for the encoder
     548           0 :   nsCOMPtr<nsIDocument> document = aDOMNode->OwnerDoc();
     549             : 
     550             :   // Note that XHTML is not counted as HTML here, because we can't copy it
     551             :   // properly (all the copy code for non-plaintext assumes using HTML
     552             :   // serializers and parsers is OK, and those mess up XHTML).
     553             :   DebugOnly<nsCOMPtr<nsIHTMLDocument>> htmlDoc =
     554           0 :     nsCOMPtr<nsIHTMLDocument>(do_QueryInterface(document, &rv));
     555           0 :   NS_ENSURE_SUCCESS(rv, NS_OK);
     556             : 
     557           0 :   NS_ENSURE_TRUE(document->IsHTMLDocument(), NS_OK);
     558             : 
     559             :   // init encoder with document and node
     560           0 :   rv = docEncoder->NativeInit(document, NS_LITERAL_STRING(kHTMLMime),
     561             :                               nsIDocumentEncoder::OutputAbsoluteLinks |
     562           0 :                               nsIDocumentEncoder::OutputEncodeW3CEntities);
     563           0 :   NS_ENSURE_SUCCESS(rv, rv);
     564             : 
     565           0 :   rv = docEncoder->SetNativeNode(aDOMNode);
     566           0 :   NS_ENSURE_SUCCESS(rv, rv);
     567             : 
     568             :   // serialize to string
     569           0 :   nsAutoString html, context, info;
     570           0 :   rv = docEncoder->EncodeToStringWithContext(context, info, html);
     571           0 :   NS_ENSURE_SUCCESS(rv, rv);
     572             : 
     573             :   // copy them to the transferable
     574           0 :   if (!html.IsEmpty()) {
     575           0 :     rv = AppendString(aTransferable, html, kHTMLMime);
     576           0 :     NS_ENSURE_SUCCESS(rv, rv);
     577             :   }
     578             : 
     579           0 :   if (!info.IsEmpty()) {
     580           0 :     rv = AppendString(aTransferable, info, kHTMLInfo);
     581           0 :     NS_ENSURE_SUCCESS(rv, rv);
     582             :   }
     583             : 
     584             :   // add a special flavor, even if we don't have html context data
     585           0 :   return AppendString(aTransferable, context, kHTMLContext);
     586             : }
     587             : 
     588             : #ifdef XP_WIN
     589             : static nsresult AppendImagePromise(nsITransferable* aTransferable,
     590             :                                    imgIRequest* aImgRequest,
     591             :                                    nsIImageLoadingContent* aImageElement)
     592             : {
     593             :   nsresult rv;
     594             : 
     595             :   NS_ENSURE_TRUE(aImgRequest, NS_OK);
     596             : 
     597             :   uint32_t imageStatus;
     598             :   rv = aImgRequest->GetImageStatus(&imageStatus);
     599             :   NS_ENSURE_SUCCESS(rv, rv);
     600             :   if (!(imageStatus & imgIRequest::STATUS_FRAME_COMPLETE) ||
     601             :       (imageStatus & imgIRequest::STATUS_ERROR)) {
     602             :     return NS_OK;
     603             :   }
     604             : 
     605             :   bool isMultipart;
     606             :   rv = aImgRequest->GetMultipart(&isMultipart);
     607             :   NS_ENSURE_SUCCESS(rv, rv);
     608             :   if (isMultipart) {
     609             :     return NS_OK;
     610             :   }
     611             : 
     612             :   nsCOMPtr<nsINode> node = do_QueryInterface(aImageElement, &rv);
     613             :   NS_ENSURE_SUCCESS(rv, rv);
     614             : 
     615             :   // Fix the file extension in the URL if necessary
     616             :   nsCOMPtr<nsIMIMEService> mimeService =
     617             :     do_GetService(NS_MIMESERVICE_CONTRACTID);
     618             :   NS_ENSURE_TRUE(mimeService, NS_OK);
     619             : 
     620             :   nsCOMPtr<nsIURI> imgUri;
     621             :   rv = aImgRequest->GetCurrentURI(getter_AddRefs(imgUri));
     622             :   NS_ENSURE_SUCCESS(rv, rv);
     623             : 
     624             :   nsCOMPtr<nsIURL> imgUrl = do_QueryInterface(imgUri);
     625             :   NS_ENSURE_TRUE(imgUrl, NS_OK);
     626             : 
     627             :   nsAutoCString extension;
     628             :   rv = imgUrl->GetFileExtension(extension);
     629             :   NS_ENSURE_SUCCESS(rv, rv);
     630             : 
     631             :   nsXPIDLCString mimeType;
     632             :   rv = aImgRequest->GetMimeType(getter_Copies(mimeType));
     633             :   NS_ENSURE_SUCCESS(rv, rv);
     634             : 
     635             :   nsCOMPtr<nsIMIMEInfo> mimeInfo;
     636             :   mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
     637             :                                        getter_AddRefs(mimeInfo));
     638             :   NS_ENSURE_TRUE(mimeInfo, NS_OK);
     639             : 
     640             :   nsAutoCString spec;
     641             :   rv = imgUrl->GetSpec(spec);
     642             :   NS_ENSURE_SUCCESS(rv, rv);
     643             : 
     644             :   // pass out the image source string
     645             :   nsString imageSourceString;
     646             :   CopyUTF8toUTF16(spec, imageSourceString);
     647             : 
     648             :   bool validExtension;
     649             :   if (extension.IsEmpty() ||
     650             :       NS_FAILED(mimeInfo->ExtensionExists(extension,
     651             :                                           &validExtension)) ||
     652             :       !validExtension) {
     653             :     // Fix the file extension in the URL
     654             :     rv = imgUrl->Clone(getter_AddRefs(imgUri));
     655             :     NS_ENSURE_SUCCESS(rv, rv);
     656             : 
     657             :     imgUrl = do_QueryInterface(imgUri);
     658             : 
     659             :     nsAutoCString primaryExtension;
     660             :     mimeInfo->GetPrimaryExtension(primaryExtension);
     661             : 
     662             :     imgUrl->SetFileExtension(primaryExtension);
     663             :   }
     664             : 
     665             :   nsAutoCString fileName;
     666             :   imgUrl->GetFileName(fileName);
     667             : 
     668             :   NS_UnescapeURL(fileName);
     669             : 
     670             :   // make the filename safe for the filesystem
     671             :   fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
     672             : 
     673             :   nsString imageDestFileName;
     674             :   CopyUTF8toUTF16(fileName, imageDestFileName);
     675             : 
     676             :   rv = AppendString(aTransferable, imageSourceString, kFilePromiseURLMime);
     677             :   NS_ENSURE_SUCCESS(rv, rv);
     678             : 
     679             :   rv = AppendString(aTransferable, imageDestFileName, kFilePromiseDestFilename);
     680             :   NS_ENSURE_SUCCESS(rv, rv);
     681             : 
     682             :   aTransferable->SetRequestingPrincipal(node->NodePrincipal());
     683             : 
     684             :   // add the dataless file promise flavor
     685             :   return aTransferable->AddDataFlavor(kFilePromiseMime);
     686             : }
     687             : #endif // XP_WIN
     688             : 
     689             : nsIContent*
     690           3 : nsCopySupport::GetSelectionForCopy(nsIDocument* aDocument, nsISelection** aSelection)
     691             : {
     692           3 :   *aSelection = nullptr;
     693             : 
     694           3 :   nsIPresShell* presShell = aDocument->GetShell();
     695           3 :   if (!presShell)
     696           0 :     return nullptr;
     697             : 
     698           6 :   nsCOMPtr<nsIContent> focusedContent;
     699             :   nsCOMPtr<nsISelectionController> selectionController =
     700           6 :     presShell->GetSelectionControllerForFocusedContent(
     701          12 :       getter_AddRefs(focusedContent));
     702           3 :   if (!selectionController) {
     703           0 :     return nullptr;
     704             :   }
     705             : 
     706           3 :   selectionController->GetSelection(nsISelectionController::SELECTION_NORMAL,
     707           3 :                                     aSelection);
     708           3 :   return focusedContent;
     709             : }
     710             : 
     711             : bool
     712           3 : nsCopySupport::CanCopy(nsIDocument* aDocument)
     713             : {
     714           3 :   if (!aDocument)
     715           0 :     return false;
     716             : 
     717           6 :   nsCOMPtr<nsISelection> sel;
     718           3 :   GetSelectionForCopy(aDocument, getter_AddRefs(sel));
     719           3 :   NS_ENSURE_TRUE(sel, false);
     720             : 
     721             :   bool isCollapsed;
     722           3 :   sel->GetIsCollapsed(&isCollapsed);
     723           3 :   return !isCollapsed;
     724             : }
     725             : 
     726             : static bool
     727           0 : IsInsideRuby(nsINode* aNode)
     728             : {
     729           0 :   for (; aNode; aNode = aNode->GetParent()) {
     730           0 :     if (aNode->IsHTMLElement(nsGkAtoms::ruby)) {
     731           0 :       return true;
     732             :     }
     733             :   }
     734           0 :   return false;
     735             : }
     736             : 
     737             : static bool
     738           0 : IsSelectionInsideRuby(nsISelection* aSelection)
     739             : {
     740             :   int32_t rangeCount;
     741           0 :   nsresult rv = aSelection->GetRangeCount(&rangeCount);
     742           0 :   if (NS_FAILED(rv)) {
     743           0 :     return false;
     744             :   }
     745           0 :   for (auto i : IntegerRange(rangeCount)) {
     746           0 :     nsCOMPtr<nsIDOMRange> range;
     747           0 :     aSelection->GetRangeAt(i, getter_AddRefs(range));
     748           0 :     nsCOMPtr<nsIDOMNode> node;
     749           0 :     range->GetCommonAncestorContainer(getter_AddRefs(node));
     750           0 :     nsCOMPtr<nsINode> n = do_QueryInterface(node);
     751           0 :     if (!IsInsideRuby(n)) {
     752           0 :       return false;
     753             :     }
     754             :   }
     755           0 :   return true;
     756             : }
     757             : 
     758             : bool
     759           0 : nsCopySupport::FireClipboardEvent(EventMessage aEventMessage,
     760             :                                   int32_t aClipboardType,
     761             :                                   nsIPresShell* aPresShell,
     762             :                                   nsISelection* aSelection,
     763             :                                   bool* aActionTaken)
     764             : {
     765           0 :   if (aActionTaken) {
     766           0 :     *aActionTaken = false;
     767             :   }
     768             : 
     769           0 :   EventMessage originalEventMessage = aEventMessage;
     770           0 :   if (originalEventMessage == ePasteNoFormatting) {
     771           0 :     originalEventMessage = ePaste;
     772             :   }
     773             : 
     774           0 :   NS_ASSERTION(originalEventMessage == eCut || originalEventMessage == eCopy ||
     775             :                originalEventMessage == ePaste,
     776             :                "Invalid clipboard event type");
     777             : 
     778           0 :   nsCOMPtr<nsIPresShell> presShell = aPresShell;
     779           0 :   if (!presShell)
     780           0 :     return false;
     781             : 
     782           0 :   nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
     783           0 :   if (!doc)
     784           0 :     return false;
     785             : 
     786           0 :   nsCOMPtr<nsPIDOMWindowOuter> piWindow = doc->GetWindow();
     787           0 :   if (!piWindow)
     788           0 :     return false;
     789             : 
     790             :   // if a selection was not supplied, try to find it
     791           0 :   nsCOMPtr<nsIContent> content;
     792           0 :   nsCOMPtr<nsISelection> sel = aSelection;
     793           0 :   if (!sel)
     794           0 :     content = GetSelectionForCopy(doc, getter_AddRefs(sel));
     795             : 
     796             :   // retrieve the event target node from the start of the selection
     797             :   nsresult rv;
     798           0 :   if (sel) {
     799           0 :     nsCOMPtr<nsIDOMRange> range;
     800           0 :     rv = sel->GetRangeAt(0, getter_AddRefs(range));
     801           0 :     if (NS_SUCCEEDED(rv) && range) {
     802           0 :       nsCOMPtr<nsIDOMNode> startContainer;
     803           0 :       range->GetStartContainer(getter_AddRefs(startContainer));
     804           0 :       if (startContainer)
     805           0 :         content = do_QueryInterface(startContainer);
     806             :     }
     807             :   }
     808             : 
     809             :   // if no content node was set, just get the root
     810           0 :   if (!content) {
     811           0 :     content = doc->GetRootElement();
     812           0 :     if (!content)
     813           0 :       return false;
     814             :   }
     815             : 
     816             :   // It seems to be unsafe to fire an event handler during reflow (bug 393696)
     817           0 :   if (!nsContentUtils::IsSafeToRunScript()) {
     818           0 :     nsContentUtils::WarnScriptWasIgnored(doc);
     819           0 :     return false;
     820             :   }
     821             : 
     822           0 :   nsCOMPtr<nsIDocShell> docShell = piWindow->GetDocShell();
     823             :   const bool chromeShell =
     824           0 :     docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome;
     825             : 
     826             :   // next, fire the cut, copy or paste event
     827           0 :   bool doDefault = true;
     828           0 :   RefPtr<DataTransfer> clipboardData;
     829           0 :   if (chromeShell || Preferences::GetBool("dom.event.clipboardevents.enabled", true)) {
     830             :     clipboardData =
     831           0 :       new DataTransfer(doc->GetScopeObject(), aEventMessage,
     832           0 :                        originalEventMessage == ePaste, aClipboardType);
     833             : 
     834           0 :     nsEventStatus status = nsEventStatus_eIgnore;
     835           0 :     InternalClipboardEvent evt(true, originalEventMessage);
     836           0 :     evt.mClipboardData = clipboardData;
     837           0 :     EventDispatcher::Dispatch(content, presShell->GetPresContext(), &evt,
     838           0 :                               nullptr, &status);
     839             :     // If the event was cancelled, don't do the clipboard operation
     840           0 :     doDefault = (status != nsEventStatus_eConsumeNoDefault);
     841             :   }
     842             : 
     843             :   // No need to do anything special during a paste. Either an event listener
     844             :   // took care of it and cancelled the event, or the caller will handle it.
     845             :   // Return true to indicate that the event wasn't cancelled.
     846           0 :   if (originalEventMessage == ePaste) {
     847             :     // Clear and mark the clipboardData as readonly. This prevents someone
     848             :     // from reading the clipboard contents after the paste event has fired.
     849           0 :     if (clipboardData) {
     850           0 :       clipboardData->ClearAll();
     851           0 :       clipboardData->SetReadOnly();
     852             :     }
     853             : 
     854           0 :     if (aActionTaken) {
     855           0 :       *aActionTaken = true;
     856             :     }
     857           0 :     return doDefault;
     858             :   }
     859             : 
     860             :   // Update the presentation in case the event handler modified the selection,
     861             :   // see bug 602231.
     862           0 :   presShell->FlushPendingNotifications(FlushType::Frames);
     863           0 :   if (presShell->IsDestroying())
     864           0 :     return false;
     865             : 
     866             :   // if the event was not cancelled, do the default copy. If the event was cancelled,
     867             :   // use the data added to the data transfer and copy that instead.
     868           0 :   uint32_t count = 0;
     869           0 :   if (doDefault) {
     870             :     // find the focused node
     871           0 :     nsCOMPtr<nsIContent> srcNode = content;
     872           0 :     if (content->IsInNativeAnonymousSubtree()) {
     873           0 :       srcNode = content->FindFirstNonChromeOnlyAccessContent();
     874             :     }
     875             : 
     876             :     // check if we are looking at a password input
     877           0 :     nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(srcNode);
     878           0 :     if (formControl) {
     879           0 :       if (formControl->ControlType() == NS_FORM_INPUT_PASSWORD) {
     880           0 :         return false;
     881             :       }
     882             :     }
     883             : 
     884             :     // when cutting non-editable content, do nothing
     885             :     // XXX this is probably the wrong editable flag to check
     886           0 :     if (originalEventMessage != eCut || content->IsEditable()) {
     887             :       // get the data from the selection if any
     888             :       bool isCollapsed;
     889           0 :       sel->GetIsCollapsed(&isCollapsed);
     890           0 :       if (isCollapsed) {
     891           0 :         if (aActionTaken) {
     892           0 :           *aActionTaken = true;
     893             :         }
     894           0 :         return false;
     895             :       }
     896             :       // XXX Code which decides whether we should copy text with ruby
     897             :       // annotation is currenct depending on whether each range of the
     898             :       // selection is inside a same ruby container. But we really should
     899             :       // expose the full functionality in browser. See bug 1130891.
     900           0 :       bool withRubyAnnotation = IsSelectionInsideRuby(sel);
     901             :       // call the copy code
     902           0 :       rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation);
     903           0 :       if (NS_FAILED(rv)) {
     904           0 :         return false;
     905             :       }
     906             :     } else {
     907           0 :       return false;
     908             :     }
     909           0 :   } else if (clipboardData) {
     910             :     // check to see if any data was put on the data transfer.
     911           0 :     clipboardData->GetMozItemCount(&count);
     912           0 :     if (count) {
     913           0 :       nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
     914           0 :       NS_ENSURE_TRUE(clipboard, false);
     915             : 
     916             :       nsCOMPtr<nsITransferable> transferable =
     917           0 :         clipboardData->GetTransferable(0, doc->GetLoadContext());
     918             : 
     919           0 :       NS_ENSURE_TRUE(transferable, false);
     920             : 
     921             :       // put the transferable on the clipboard
     922           0 :       rv = clipboard->SetData(transferable, nullptr, aClipboardType);
     923           0 :       if (NS_FAILED(rv)) {
     924           0 :         return false;
     925             :       }
     926             :     }
     927             :   }
     928             : 
     929             :   // Now that we have copied, update the clipboard commands. This should have
     930             :   // the effect of updating the enabled state of the paste menu item.
     931           0 :   if (doDefault || count) {
     932           0 :     piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"), nullptr, 0);
     933             :   }
     934             : 
     935           0 :   if (aActionTaken) {
     936           0 :     *aActionTaken = true;
     937             :   }
     938           0 :   return doDefault;
     939             : }

Generated by: LCOV version 1.13