content/base/src/nsCopySupport.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsCopySupport.h"
     7 #include "nsIDocumentEncoder.h"
     8 #include "nsISupports.h"
     9 #include "nsIContent.h"
    10 #include "nsIComponentManager.h" 
    11 #include "nsIServiceManager.h"
    12 #include "nsIClipboard.h"
    13 #include "nsISelection.h"
    14 #include "nsWidgetsCID.h"
    15 #include "nsXPCOM.h"
    16 #include "nsISupportsPrimitives.h"
    17 #include "nsIDOMRange.h"
    18 #include "nsRange.h"
    19 #include "imgIContainer.h"
    20 #include "nsIPresShell.h"
    21 #include "nsFocusManager.h"
    22 #include "mozilla/dom/DataTransfer.h"
    24 #include "nsIDocShell.h"
    25 #include "nsIContentViewerEdit.h"
    26 #include "nsIClipboardDragDropHooks.h"
    27 #include "nsIClipboardDragDropHookList.h"
    28 #include "nsIClipboardHelper.h"
    29 #include "nsISelectionController.h"
    31 #include "nsPIDOMWindow.h"
    32 #include "nsIDocument.h"
    33 #include "nsIDOMNode.h"
    34 #include "nsIDOMElement.h"
    35 #include "nsIDOMDocument.h"
    36 #include "nsIHTMLDocument.h"
    37 #include "nsGkAtoms.h"
    38 #include "nsIFrame.h"
    39 #include "nsIURI.h"
    40 #include "nsISimpleEnumerator.h"
    42 // image copy stuff
    43 #include "nsIImageLoadingContent.h"
    44 #include "nsIInterfaceRequestorUtils.h"
    45 #include "nsContentUtils.h"
    46 #include "nsContentCID.h"
    48 #include "mozilla/ContentEvents.h"
    49 #include "mozilla/dom/Element.h"
    50 #include "mozilla/EventDispatcher.h"
    51 #include "mozilla/Preferences.h"
    52 #include "mozilla/dom/Selection.h"
    54 using namespace mozilla;
    55 using namespace mozilla::dom;
    57 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
    59 static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
    60 static NS_DEFINE_CID(kCTransferableCID,        NS_TRANSFERABLE_CID);
    61 static NS_DEFINE_CID(kHTMLConverterCID,        NS_HTMLFORMATCONVERTER_CID);
    63 // copy string data onto the transferable
    64 static nsresult AppendString(nsITransferable *aTransferable,
    65                              const nsAString& aString,
    66                              const char* aFlavor);
    68 // copy HTML node data
    69 static nsresult AppendDOMNode(nsITransferable *aTransferable,
    70                               nsINode* aDOMNode);
    72 // Helper used for HTMLCopy and GetTransferableForSelection since both routines
    73 // share common code.
    74 static nsresult
    75 SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
    76                     bool doPutOnClipboard, int16_t aClipboardID,
    77                     uint32_t aFlags, nsITransferable ** aTransferable)
    78 {
    79   // Clear the output parameter for the transferable, if provided.
    80   if (aTransferable) {
    81     *aTransferable = nullptr;
    82   }
    84   nsresult rv;
    86   nsCOMPtr<nsIDocumentEncoder> docEncoder;
    87   docEncoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID);
    88   NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
    90   // note that we assign text/unicode as mime type, but in fact nsHTMLCopyEncoder
    91   // ignore it and use text/html or text/plain depending where the selection
    92   // is. if it is a selection into input/textarea element or in a html content
    93   // with pre-wrap style : text/plain. Otherwise text/html.
    94   // see nsHTMLCopyEncoder::SetSelection
    95   nsAutoString mimeType;
    96   mimeType.AssignLiteral(kUnicodeMime);
    98   // Do the first and potentially trial encoding as preformatted and raw.
    99   uint32_t flags = aFlags | nsIDocumentEncoder::OutputPreformatted
   100                           | nsIDocumentEncoder::OutputRaw;
   102   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
   103   NS_ASSERTION(domDoc, "Need a document");
   105   rv = docEncoder->Init(domDoc, mimeType, flags);
   106   NS_ENSURE_SUCCESS(rv, rv);
   108   rv = docEncoder->SetSelection(aSel);
   109   NS_ENSURE_SUCCESS(rv, rv);
   111   // SetSelection set the mime type to text/plain if the selection is inside a
   112   // text widget.
   113   rv = docEncoder->GetMimeType(mimeType);
   114   NS_ENSURE_SUCCESS(rv, rv);
   115   bool selForcedTextPlain = mimeType.EqualsLiteral(kTextMime);
   117   nsAutoString buf;
   118   rv = docEncoder->EncodeToString(buf);
   119   NS_ENSURE_SUCCESS(rv, rv);
   121   rv = docEncoder->GetMimeType(mimeType);
   122   NS_ENSURE_SUCCESS(rv, rv);
   124   if (!selForcedTextPlain && mimeType.EqualsLiteral(kTextMime)) {
   125     // SetSelection and EncodeToString use this case to signal that text/plain
   126     // was forced because the document is either not an nsIHTMLDocument or it's
   127     // XHTML.  We want to pretty print XHTML but not non-nsIHTMLDocuments.
   128     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aDoc);
   129     if (!htmlDoc) {
   130       selForcedTextPlain = true;
   131     }
   132   }
   134   // The mime type is ultimately text/html if the encoder successfully encoded
   135   // the selection as text/html.
   136   bool encodedTextHTML = mimeType.EqualsLiteral(kHTMLMime);
   138   // First, prepare the text/plain clipboard flavor.
   139   nsAutoString textPlainBuf;
   140   if (selForcedTextPlain) {
   141     // Nothing to do.  buf contains the final, preformatted, raw text/plain.
   142     textPlainBuf.Assign(buf);
   143   } else {
   144     // Redo the encoding, but this time use pretty printing.
   145     flags =
   146       nsIDocumentEncoder::OutputSelectionOnly |
   147       nsIDocumentEncoder::OutputAbsoluteLinks |
   148       nsIDocumentEncoder::SkipInvisibleContent |
   149       nsIDocumentEncoder::OutputDropInvisibleBreak |
   150       (aFlags & nsIDocumentEncoder::OutputNoScriptContent);
   152     mimeType.AssignLiteral(kTextMime);
   153     rv = docEncoder->Init(domDoc, mimeType, flags);
   154     NS_ENSURE_SUCCESS(rv, rv);
   156     rv = docEncoder->SetSelection(aSel);
   157     NS_ENSURE_SUCCESS(rv, rv);
   159     rv = docEncoder->EncodeToString(textPlainBuf);
   160     NS_ENSURE_SUCCESS(rv, rv);
   161   }
   163   // Second, prepare the text/html flavor.
   164   nsAutoString textHTMLBuf;
   165   nsAutoString htmlParentsBuf;
   166   nsAutoString htmlInfoBuf;
   167   if (encodedTextHTML) {
   168     // Redo the encoding, but this time use the passed-in flags.
   169     mimeType.AssignLiteral(kHTMLMime);
   170     rv = docEncoder->Init(domDoc, mimeType, aFlags);
   171     NS_ENSURE_SUCCESS(rv, rv);
   173     rv = docEncoder->SetSelection(aSel);
   174     NS_ENSURE_SUCCESS(rv, rv);
   176     rv = docEncoder->EncodeToStringWithContext(htmlParentsBuf, htmlInfoBuf,
   177                                                textHTMLBuf);
   178     NS_ENSURE_SUCCESS(rv, rv);
   179   }
   181   // Get the Clipboard
   182   nsCOMPtr<nsIClipboard> clipboard;
   183   if (doPutOnClipboard) {
   184     clipboard = do_GetService(kCClipboardCID, &rv);
   185     if (NS_FAILED(rv))
   186       return rv;
   187   }
   189   if ((doPutOnClipboard && clipboard) || aTransferable != nullptr) {
   190     // Create a transferable for putting data on the Clipboard
   191     nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID);
   192     if (trans) {
   193       trans->Init(aDoc->GetLoadContext());
   194       if (encodedTextHTML) {
   195         // Set up a format converter so that clipboard flavor queries work.
   196         // This converter isn't really used for conversions.
   197         nsCOMPtr<nsIFormatConverter> htmlConverter =
   198           do_CreateInstance(kHTMLConverterCID);
   199         trans->SetConverter(htmlConverter);
   201         if (!textHTMLBuf.IsEmpty()) {
   202           // Add the html DataFlavor to the transferable
   203           rv = AppendString(trans, textHTMLBuf, kHTMLMime);
   204           NS_ENSURE_SUCCESS(rv, rv);
   205         }
   207         // Add the htmlcontext DataFlavor to the transferable
   208         // Even if parents is empty string, this flavor should
   209         // be attached to the transferable
   210         rv = AppendString(trans, htmlParentsBuf, kHTMLContext);
   211         NS_ENSURE_SUCCESS(rv, rv);
   213         if (!htmlInfoBuf.IsEmpty()) {
   214           // Add the htmlinfo DataFlavor to the transferable
   215           rv = AppendString(trans, htmlInfoBuf, kHTMLInfo);
   216           NS_ENSURE_SUCCESS(rv, rv);
   217         }
   219         if (!textPlainBuf.IsEmpty()) {
   220           // unicode text
   221           // Add the unicode DataFlavor to the transferable
   222           // If we didn't have this, then nsDataObj::GetData matches text/unicode against
   223           // the kURLMime flavour which is not desirable (eg. when pasting into Notepad)
   224           rv = AppendString(trans, textPlainBuf, kUnicodeMime);
   225           NS_ENSURE_SUCCESS(rv, rv);
   226         }
   228         // Try and get source URI of the items that are being dragged
   229         nsIURI *uri = aDoc->GetDocumentURI();
   230         if (uri) {
   231           nsAutoCString spec;
   232           uri->GetSpec(spec);
   233           if (!spec.IsEmpty()) {
   234             nsAutoString shortcut;
   235             AppendUTF8toUTF16(spec, shortcut);
   237             // Add the URL DataFlavor to the transferable. Don't use kURLMime, as it will
   238             // cause an unnecessary UniformResourceLocator to be added which confuses
   239             // some apps eg. Outlook 2000 - (See Bug 315370). Don't use
   240             // kURLDataMime, as it will cause a bogus 'url ' flavor to
   241             // show up on the Mac clipboard, confusing other apps, like
   242             // Terminal (see bug 336012).
   243             rv = AppendString(trans, shortcut, kURLPrivateMime);
   244             NS_ENSURE_SUCCESS(rv, rv);
   245           }
   246         }
   247       } else {
   248         if (!textPlainBuf.IsEmpty()) {
   249           // Add the unicode DataFlavor to the transferable
   250           rv = AppendString(trans, textPlainBuf, kUnicodeMime);
   251           NS_ENSURE_SUCCESS(rv, rv);
   252         }
   253       }
   255       if (doPutOnClipboard && clipboard) {
   256         bool actuallyPutOnClipboard = true;
   257         nsCopySupport::DoHooks(aDoc, trans, &actuallyPutOnClipboard);
   259         // put the transferable on the clipboard
   260         if (actuallyPutOnClipboard)
   261           clipboard->SetData(trans, nullptr, aClipboardID);
   262       }
   264       // Return the transferable to the caller if requested.
   265       if (aTransferable != nullptr) {
   266         trans.swap(*aTransferable);
   267       }
   268     }
   269   }
   270   return rv;
   271 }
   273 nsresult
   274 nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc,
   275                         int16_t aClipboardID)
   276 {
   277   return SelectionCopyHelper(aSel, aDoc, true, aClipboardID,
   278                              nsIDocumentEncoder::SkipInvisibleContent,
   279                              nullptr);
   280 }
   282 nsresult
   283 nsCopySupport::GetTransferableForSelection(nsISelection* aSel,
   284                                            nsIDocument* aDoc,
   285                                            nsITransferable** aTransferable)
   286 {
   287   return SelectionCopyHelper(aSel, aDoc, false, 0,
   288                              nsIDocumentEncoder::SkipInvisibleContent,
   289                              aTransferable);
   290 }
   292 nsresult
   293 nsCopySupport::GetTransferableForNode(nsINode* aNode,
   294                                       nsIDocument* aDoc,
   295                                       nsITransferable** aTransferable)
   296 {
   297   nsCOMPtr<nsISelection> selection;
   298   // Make a temporary selection with aNode in a single range.
   299   nsresult rv = NS_NewDomSelection(getter_AddRefs(selection));
   300   NS_ENSURE_SUCCESS(rv, rv);
   301   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
   302   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
   303   nsRefPtr<nsRange> range = new nsRange(aNode);
   304   rv = range->SelectNode(node);
   305   NS_ENSURE_SUCCESS(rv, rv);
   306   rv = selection->AddRange(range);
   307   NS_ENSURE_SUCCESS(rv, rv);
   308   // It's not the primary selection - so don't skip invisible content.
   309   uint32_t flags = 0;
   310   return SelectionCopyHelper(selection, aDoc, false, 0, flags,
   311                              aTransferable);
   312 }
   314 nsresult nsCopySupport::DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
   315                                 bool *aDoPutOnClipboard)
   316 {
   317   NS_ENSURE_ARG(aDoc);
   319   *aDoPutOnClipboard = true;
   321   nsCOMPtr<nsISupports> container = aDoc->GetContainer();
   322   nsCOMPtr<nsIClipboardDragDropHookList> hookObj = do_GetInterface(container);
   323   if (!hookObj) return NS_ERROR_FAILURE;
   325   nsCOMPtr<nsISimpleEnumerator> enumerator;
   326   hookObj->GetHookEnumerator(getter_AddRefs(enumerator));
   327   if (!enumerator) return NS_ERROR_FAILURE;
   329   // the logic here should follow the behavior specified in
   330   // nsIClipboardDragDropHooks.h
   332   nsCOMPtr<nsIClipboardDragDropHooks> override;
   333   nsCOMPtr<nsISupports> isupp;
   334   bool hasMoreHooks = false;
   335   nsresult rv = NS_OK;
   336   while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks))
   337          && hasMoreHooks)
   338   {
   339     rv = enumerator->GetNext(getter_AddRefs(isupp));
   340     if (NS_FAILED(rv)) break;
   341     override = do_QueryInterface(isupp);
   342     if (override)
   343     {
   344 #ifdef DEBUG
   345       nsresult hookResult =
   346 #endif
   347       override->OnCopyOrDrag(nullptr, aTrans, aDoPutOnClipboard);
   348       NS_ASSERTION(NS_SUCCEEDED(hookResult), "OnCopyOrDrag hook failed");
   349       if (!*aDoPutOnClipboard)
   350         break;
   351     }
   352   }
   354   return rv;
   355 }
   357 nsresult
   358 nsCopySupport::GetContents(const nsACString& aMimeType, uint32_t aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata)
   359 {
   360   nsresult rv = NS_OK;
   362   nsCOMPtr<nsIDocumentEncoder> docEncoder;
   364   nsAutoCString encoderContractID(NS_DOC_ENCODER_CONTRACTID_BASE);
   365   encoderContractID.Append(aMimeType);
   367   docEncoder = do_CreateInstance(encoderContractID.get());
   368   NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
   370   uint32_t flags = aFlags | nsIDocumentEncoder::SkipInvisibleContent;
   372   if (aMimeType.Equals("text/plain"))
   373     flags |= nsIDocumentEncoder::OutputPreformatted;
   375   NS_ConvertASCIItoUTF16 unicodeMimeType(aMimeType);
   377   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
   378   NS_ASSERTION(domDoc, "Need a document");
   380   rv = docEncoder->Init(domDoc, unicodeMimeType, flags);
   381   if (NS_FAILED(rv)) return rv;
   383   if (aSel)
   384   {
   385     rv = docEncoder->SetSelection(aSel);
   386     if (NS_FAILED(rv)) return rv;
   387   } 
   389   // encode the selection
   390   return docEncoder->EncodeToString(outdata);
   391 }
   394 nsresult
   395 nsCopySupport::ImageCopy(nsIImageLoadingContent* aImageElement,
   396                          nsILoadContext* aLoadContext,
   397                          int32_t aCopyFlags)
   398 {
   399   nsresult rv;
   401   // create a transferable for putting data on the Clipboard
   402   nsCOMPtr<nsITransferable> trans(do_CreateInstance(kCTransferableCID, &rv));
   403   NS_ENSURE_SUCCESS(rv, rv);
   404   trans->Init(aLoadContext);
   406   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_TEXT) {
   407     // get the location from the element
   408     nsCOMPtr<nsIURI> uri;
   409     rv = aImageElement->GetCurrentURI(getter_AddRefs(uri));
   410     NS_ENSURE_SUCCESS(rv, rv);
   411     NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
   413     nsAutoCString location;
   414     rv = uri->GetSpec(location);
   415     NS_ENSURE_SUCCESS(rv, rv);
   417     // append the string to the transferable
   418     rv = AppendString(trans, NS_ConvertUTF8toUTF16(location), kUnicodeMime);
   419     NS_ENSURE_SUCCESS(rv, rv);
   420   }
   422   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_HTML) {
   423     // append HTML data to the transferable
   424     nsCOMPtr<nsINode> node(do_QueryInterface(aImageElement, &rv));
   425     NS_ENSURE_SUCCESS(rv, rv);
   427     rv = AppendDOMNode(trans, node);
   428     NS_ENSURE_SUCCESS(rv, rv);
   429   }
   431   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_DATA) {
   432     // get the image data from the element
   433     nsCOMPtr<imgIContainer> image =
   434       nsContentUtils::GetImageFromContent(aImageElement);
   435     NS_ENSURE_TRUE(image, NS_ERROR_FAILURE);
   437     nsCOMPtr<nsISupportsInterfacePointer>
   438       imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
   439     NS_ENSURE_SUCCESS(rv, rv);
   441     rv = imgPtr->SetData(image);
   442     NS_ENSURE_SUCCESS(rv, rv);
   444     // copy the image data onto the transferable
   445     rv = trans->SetTransferData(kNativeImageMime, imgPtr,
   446                                 sizeof(nsISupports*));
   447     NS_ENSURE_SUCCESS(rv, rv);
   448   }
   450   // get clipboard
   451   nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
   452   NS_ENSURE_SUCCESS(rv, rv);
   454   // check whether the system supports the selection clipboard or not.
   455   bool selectionSupported;
   456   rv = clipboard->SupportsSelectionClipboard(&selectionSupported);
   457   NS_ENSURE_SUCCESS(rv, rv);
   459   // put the transferable on the clipboard
   460   if (selectionSupported) {
   461     rv = clipboard->SetData(trans, nullptr, nsIClipboard::kSelectionClipboard);
   462     NS_ENSURE_SUCCESS(rv, rv);
   463   }
   465   return clipboard->SetData(trans, nullptr, nsIClipboard::kGlobalClipboard);
   466 }
   468 static nsresult AppendString(nsITransferable *aTransferable,
   469                              const nsAString& aString,
   470                              const char* aFlavor)
   471 {
   472   nsresult rv;
   474   nsCOMPtr<nsISupportsString>
   475     data(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
   476   NS_ENSURE_SUCCESS(rv, rv);
   478   rv = data->SetData(aString);
   479   NS_ENSURE_SUCCESS(rv, rv);
   481   rv = aTransferable->AddDataFlavor(aFlavor);
   482   NS_ENSURE_SUCCESS(rv, rv);
   484   return aTransferable->SetTransferData(aFlavor, data,
   485                                         aString.Length() * sizeof(char16_t));
   486 }
   488 static nsresult AppendDOMNode(nsITransferable *aTransferable,
   489                               nsINode *aDOMNode)
   490 {
   491   nsresult rv;
   493   // selializer
   494   nsCOMPtr<nsIDocumentEncoder>
   495     docEncoder(do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID, &rv));
   496   NS_ENSURE_SUCCESS(rv, rv);
   498   // get document for the encoder
   499   nsCOMPtr<nsIDocument> document = aDOMNode->OwnerDoc();
   501   // Note that XHTML is not counted as HTML here, because we can't copy it
   502   // properly (all the copy code for non-plaintext assumes using HTML
   503   // serializers and parsers is OK, and those mess up XHTML).
   504   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document, &rv);
   505   NS_ENSURE_SUCCESS(rv, NS_OK);
   507   NS_ENSURE_TRUE(document->IsHTML(), NS_OK);
   509   // init encoder with document and node
   510   rv = docEncoder->NativeInit(document, NS_LITERAL_STRING(kHTMLMime),
   511                               nsIDocumentEncoder::OutputAbsoluteLinks |
   512                               nsIDocumentEncoder::OutputEncodeW3CEntities);
   513   NS_ENSURE_SUCCESS(rv, rv);
   515   rv = docEncoder->SetNativeNode(aDOMNode);
   516   NS_ENSURE_SUCCESS(rv, rv);
   518   // serialize to string
   519   nsAutoString html, context, info;
   520   rv = docEncoder->EncodeToStringWithContext(context, info, html);
   521   NS_ENSURE_SUCCESS(rv, rv);
   523   // copy them to the transferable
   524   if (!html.IsEmpty()) {
   525     rv = AppendString(aTransferable, html, kHTMLMime);
   526     NS_ENSURE_SUCCESS(rv, rv);
   527   }
   529   if (!info.IsEmpty()) {
   530     rv = AppendString(aTransferable, info, kHTMLInfo);
   531     NS_ENSURE_SUCCESS(rv, rv);
   532   }
   534   // add a special flavor, even if we don't have html context data
   535   return AppendString(aTransferable, context, kHTMLContext);
   536 }
   538 nsIContent*
   539 nsCopySupport::GetSelectionForCopy(nsIDocument* aDocument, nsISelection** aSelection)
   540 {
   541   *aSelection = nullptr;
   543   nsIPresShell* presShell = aDocument->GetShell();
   544   if (!presShell)
   545     return nullptr;
   547   // check if the focused node in the window has a selection
   548   nsCOMPtr<nsPIDOMWindow> focusedWindow;
   549   nsIContent* content =
   550     nsFocusManager::GetFocusedDescendant(aDocument->GetWindow(), false,
   551                                          getter_AddRefs(focusedWindow));
   552   if (content) {
   553     nsIFrame* frame = content->GetPrimaryFrame();
   554     if (frame) {
   555       nsCOMPtr<nsISelectionController> selCon;
   556       frame->GetSelectionController(presShell->GetPresContext(), getter_AddRefs(selCon));
   557       if (selCon) {
   558         selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection);
   559         return content;
   560       }
   561     }
   562   }
   564   // if no selection was found, use the main selection for the window
   565   NS_IF_ADDREF(*aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL));
   566   return nullptr;
   567 }
   569 bool
   570 nsCopySupport::CanCopy(nsIDocument* aDocument)
   571 {
   572   if (!aDocument)
   573     return false;
   575   nsCOMPtr<nsISelection> sel;
   576   GetSelectionForCopy(aDocument, getter_AddRefs(sel));
   577   NS_ENSURE_TRUE(sel, false);
   579   bool isCollapsed;
   580   sel->GetIsCollapsed(&isCollapsed);
   581   return !isCollapsed;
   582 }
   584 bool
   585 nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, nsISelection* aSelection)
   586 {
   587   NS_ASSERTION(aType == NS_CUT || aType == NS_COPY || aType == NS_PASTE,
   588                "Invalid clipboard event type");
   590   nsCOMPtr<nsIPresShell> presShell = aPresShell;
   591   if (!presShell)
   592     return false;
   594   nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
   595   if (!doc)
   596     return false;
   598   nsCOMPtr<nsPIDOMWindow> piWindow = doc->GetWindow();
   599   if (!piWindow)
   600     return false;
   602   // if a selection was not supplied, try to find it
   603   nsCOMPtr<nsIContent> content;
   604   nsCOMPtr<nsISelection> sel = aSelection;
   605   if (!sel)
   606     content = GetSelectionForCopy(doc, getter_AddRefs(sel));
   608   // retrieve the event target node from the start of the selection
   609   nsresult rv;
   610   if (sel) {
   611     // Only cut or copy when there is an uncollapsed selection
   612     if (aType == NS_CUT || aType == NS_COPY) {
   613       bool isCollapsed;
   614       sel->GetIsCollapsed(&isCollapsed);
   615       if (isCollapsed)
   616         return false;
   617     }
   619     nsCOMPtr<nsIDOMRange> range;
   620     rv = sel->GetRangeAt(0, getter_AddRefs(range));
   621     if (NS_SUCCEEDED(rv) && range) {
   622       nsCOMPtr<nsIDOMNode> startContainer;
   623       range->GetStartContainer(getter_AddRefs(startContainer));
   624       if (startContainer)
   625         content = do_QueryInterface(startContainer);
   626     }
   627   }
   629   // if no content node was set, just get the root
   630   if (!content) {
   631     content = doc->GetRootElement();
   632     if (!content)
   633       return false;
   634   }
   636   // It seems to be unsafe to fire an event handler during reflow (bug 393696)
   637   if (!nsContentUtils::IsSafeToRunScript())
   638     return false;
   640   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(piWindow);
   641   const bool chromeShell =
   642     docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome;
   644   // next, fire the cut, copy or paste event
   645   bool doDefault = true;
   646   nsRefPtr<DataTransfer> clipboardData;
   647   if (chromeShell || Preferences::GetBool("dom.event.clipboardevents.enabled", true)) {
   648     clipboardData =
   649       new DataTransfer(piWindow, aType, aType == NS_PASTE, aClipboardType);
   651     nsEventStatus status = nsEventStatus_eIgnore;
   652     InternalClipboardEvent evt(true, aType);
   653     evt.clipboardData = clipboardData;
   654     EventDispatcher::Dispatch(content, presShell->GetPresContext(), &evt,
   655                               nullptr, &status);
   656     // If the event was cancelled, don't do the clipboard operation
   657     doDefault = (status != nsEventStatus_eConsumeNoDefault);
   658   }
   660   // No need to do anything special during a paste. Either an event listener
   661   // took care of it and cancelled the event, or the caller will handle it.
   662   // Return true to indicate that the event wasn't cancelled.
   663   if (aType == NS_PASTE) {
   664     // Clear and mark the clipboardData as readonly. This prevents someone
   665     // from reading the clipboard contents after the paste event has fired.
   666     if (clipboardData) {
   667       clipboardData->ClearAll();
   668       clipboardData->SetReadOnly();
   669     }
   671     return doDefault;
   672   }
   674   // Update the presentation in case the event handler modified the selection,
   675   // see bug 602231.
   676   presShell->FlushPendingNotifications(Flush_Frames);
   677   if (presShell->IsDestroying())
   678     return false;
   680   // if the event was not cancelled, do the default copy. If the event was cancelled,
   681   // use the data added to the data transfer and copy that instead.
   682   uint32_t count = 0;
   683   if (doDefault) {
   684     // get the data from the selection if any
   685     bool isCollapsed;
   686     sel->GetIsCollapsed(&isCollapsed);
   687     if (isCollapsed) {
   688       return false;
   689     }
   690     // call the copy code
   691     rv = HTMLCopy(sel, doc, aClipboardType);
   692     if (NS_FAILED(rv)) {
   693       return false;
   694     }
   695   } else if (clipboardData) {
   696     // check to see if any data was put on the data transfer.
   697     clipboardData->GetMozItemCount(&count);
   698     if (count) {
   699       nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
   700       NS_ENSURE_TRUE(clipboard, false);
   702       nsCOMPtr<nsITransferable> transferable =
   703         clipboardData->GetTransferable(0, doc->GetLoadContext());
   705       NS_ENSURE_TRUE(transferable, false);
   707       // put the transferable on the clipboard
   708       rv = clipboard->SetData(transferable, nullptr, aClipboardType);
   709       if (NS_FAILED(rv)) {
   710         return false;
   711       }
   712     }
   713   }
   715   // Now that we have copied, update the clipboard commands. This should have
   716   // the effect of updating the enabled state of the paste menu item.
   717   if (doDefault || count) {
   718     piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"));
   719   }
   721   return doDefault;
   722 }

mercurial