1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsCopySupport.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,722 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsCopySupport.h" 1.10 +#include "nsIDocumentEncoder.h" 1.11 +#include "nsISupports.h" 1.12 +#include "nsIContent.h" 1.13 +#include "nsIComponentManager.h" 1.14 +#include "nsIServiceManager.h" 1.15 +#include "nsIClipboard.h" 1.16 +#include "nsISelection.h" 1.17 +#include "nsWidgetsCID.h" 1.18 +#include "nsXPCOM.h" 1.19 +#include "nsISupportsPrimitives.h" 1.20 +#include "nsIDOMRange.h" 1.21 +#include "nsRange.h" 1.22 +#include "imgIContainer.h" 1.23 +#include "nsIPresShell.h" 1.24 +#include "nsFocusManager.h" 1.25 +#include "mozilla/dom/DataTransfer.h" 1.26 + 1.27 +#include "nsIDocShell.h" 1.28 +#include "nsIContentViewerEdit.h" 1.29 +#include "nsIClipboardDragDropHooks.h" 1.30 +#include "nsIClipboardDragDropHookList.h" 1.31 +#include "nsIClipboardHelper.h" 1.32 +#include "nsISelectionController.h" 1.33 + 1.34 +#include "nsPIDOMWindow.h" 1.35 +#include "nsIDocument.h" 1.36 +#include "nsIDOMNode.h" 1.37 +#include "nsIDOMElement.h" 1.38 +#include "nsIDOMDocument.h" 1.39 +#include "nsIHTMLDocument.h" 1.40 +#include "nsGkAtoms.h" 1.41 +#include "nsIFrame.h" 1.42 +#include "nsIURI.h" 1.43 +#include "nsISimpleEnumerator.h" 1.44 + 1.45 +// image copy stuff 1.46 +#include "nsIImageLoadingContent.h" 1.47 +#include "nsIInterfaceRequestorUtils.h" 1.48 +#include "nsContentUtils.h" 1.49 +#include "nsContentCID.h" 1.50 + 1.51 +#include "mozilla/ContentEvents.h" 1.52 +#include "mozilla/dom/Element.h" 1.53 +#include "mozilla/EventDispatcher.h" 1.54 +#include "mozilla/Preferences.h" 1.55 +#include "mozilla/dom/Selection.h" 1.56 + 1.57 +using namespace mozilla; 1.58 +using namespace mozilla::dom; 1.59 + 1.60 +nsresult NS_NewDomSelection(nsISelection **aDomSelection); 1.61 + 1.62 +static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); 1.63 +static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); 1.64 +static NS_DEFINE_CID(kHTMLConverterCID, NS_HTMLFORMATCONVERTER_CID); 1.65 + 1.66 +// copy string data onto the transferable 1.67 +static nsresult AppendString(nsITransferable *aTransferable, 1.68 + const nsAString& aString, 1.69 + const char* aFlavor); 1.70 + 1.71 +// copy HTML node data 1.72 +static nsresult AppendDOMNode(nsITransferable *aTransferable, 1.73 + nsINode* aDOMNode); 1.74 + 1.75 +// Helper used for HTMLCopy and GetTransferableForSelection since both routines 1.76 +// share common code. 1.77 +static nsresult 1.78 +SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc, 1.79 + bool doPutOnClipboard, int16_t aClipboardID, 1.80 + uint32_t aFlags, nsITransferable ** aTransferable) 1.81 +{ 1.82 + // Clear the output parameter for the transferable, if provided. 1.83 + if (aTransferable) { 1.84 + *aTransferable = nullptr; 1.85 + } 1.86 + 1.87 + nsresult rv; 1.88 + 1.89 + nsCOMPtr<nsIDocumentEncoder> docEncoder; 1.90 + docEncoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID); 1.91 + NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE); 1.92 + 1.93 + // note that we assign text/unicode as mime type, but in fact nsHTMLCopyEncoder 1.94 + // ignore it and use text/html or text/plain depending where the selection 1.95 + // is. if it is a selection into input/textarea element or in a html content 1.96 + // with pre-wrap style : text/plain. Otherwise text/html. 1.97 + // see nsHTMLCopyEncoder::SetSelection 1.98 + nsAutoString mimeType; 1.99 + mimeType.AssignLiteral(kUnicodeMime); 1.100 + 1.101 + // Do the first and potentially trial encoding as preformatted and raw. 1.102 + uint32_t flags = aFlags | nsIDocumentEncoder::OutputPreformatted 1.103 + | nsIDocumentEncoder::OutputRaw; 1.104 + 1.105 + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc); 1.106 + NS_ASSERTION(domDoc, "Need a document"); 1.107 + 1.108 + rv = docEncoder->Init(domDoc, mimeType, flags); 1.109 + NS_ENSURE_SUCCESS(rv, rv); 1.110 + 1.111 + rv = docEncoder->SetSelection(aSel); 1.112 + NS_ENSURE_SUCCESS(rv, rv); 1.113 + 1.114 + // SetSelection set the mime type to text/plain if the selection is inside a 1.115 + // text widget. 1.116 + rv = docEncoder->GetMimeType(mimeType); 1.117 + NS_ENSURE_SUCCESS(rv, rv); 1.118 + bool selForcedTextPlain = mimeType.EqualsLiteral(kTextMime); 1.119 + 1.120 + nsAutoString buf; 1.121 + rv = docEncoder->EncodeToString(buf); 1.122 + NS_ENSURE_SUCCESS(rv, rv); 1.123 + 1.124 + rv = docEncoder->GetMimeType(mimeType); 1.125 + NS_ENSURE_SUCCESS(rv, rv); 1.126 + 1.127 + if (!selForcedTextPlain && mimeType.EqualsLiteral(kTextMime)) { 1.128 + // SetSelection and EncodeToString use this case to signal that text/plain 1.129 + // was forced because the document is either not an nsIHTMLDocument or it's 1.130 + // XHTML. We want to pretty print XHTML but not non-nsIHTMLDocuments. 1.131 + nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aDoc); 1.132 + if (!htmlDoc) { 1.133 + selForcedTextPlain = true; 1.134 + } 1.135 + } 1.136 + 1.137 + // The mime type is ultimately text/html if the encoder successfully encoded 1.138 + // the selection as text/html. 1.139 + bool encodedTextHTML = mimeType.EqualsLiteral(kHTMLMime); 1.140 + 1.141 + // First, prepare the text/plain clipboard flavor. 1.142 + nsAutoString textPlainBuf; 1.143 + if (selForcedTextPlain) { 1.144 + // Nothing to do. buf contains the final, preformatted, raw text/plain. 1.145 + textPlainBuf.Assign(buf); 1.146 + } else { 1.147 + // Redo the encoding, but this time use pretty printing. 1.148 + flags = 1.149 + nsIDocumentEncoder::OutputSelectionOnly | 1.150 + nsIDocumentEncoder::OutputAbsoluteLinks | 1.151 + nsIDocumentEncoder::SkipInvisibleContent | 1.152 + nsIDocumentEncoder::OutputDropInvisibleBreak | 1.153 + (aFlags & nsIDocumentEncoder::OutputNoScriptContent); 1.154 + 1.155 + mimeType.AssignLiteral(kTextMime); 1.156 + rv = docEncoder->Init(domDoc, mimeType, flags); 1.157 + NS_ENSURE_SUCCESS(rv, rv); 1.158 + 1.159 + rv = docEncoder->SetSelection(aSel); 1.160 + NS_ENSURE_SUCCESS(rv, rv); 1.161 + 1.162 + rv = docEncoder->EncodeToString(textPlainBuf); 1.163 + NS_ENSURE_SUCCESS(rv, rv); 1.164 + } 1.165 + 1.166 + // Second, prepare the text/html flavor. 1.167 + nsAutoString textHTMLBuf; 1.168 + nsAutoString htmlParentsBuf; 1.169 + nsAutoString htmlInfoBuf; 1.170 + if (encodedTextHTML) { 1.171 + // Redo the encoding, but this time use the passed-in flags. 1.172 + mimeType.AssignLiteral(kHTMLMime); 1.173 + rv = docEncoder->Init(domDoc, mimeType, aFlags); 1.174 + NS_ENSURE_SUCCESS(rv, rv); 1.175 + 1.176 + rv = docEncoder->SetSelection(aSel); 1.177 + NS_ENSURE_SUCCESS(rv, rv); 1.178 + 1.179 + rv = docEncoder->EncodeToStringWithContext(htmlParentsBuf, htmlInfoBuf, 1.180 + textHTMLBuf); 1.181 + NS_ENSURE_SUCCESS(rv, rv); 1.182 + } 1.183 + 1.184 + // Get the Clipboard 1.185 + nsCOMPtr<nsIClipboard> clipboard; 1.186 + if (doPutOnClipboard) { 1.187 + clipboard = do_GetService(kCClipboardCID, &rv); 1.188 + if (NS_FAILED(rv)) 1.189 + return rv; 1.190 + } 1.191 + 1.192 + if ((doPutOnClipboard && clipboard) || aTransferable != nullptr) { 1.193 + // Create a transferable for putting data on the Clipboard 1.194 + nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID); 1.195 + if (trans) { 1.196 + trans->Init(aDoc->GetLoadContext()); 1.197 + if (encodedTextHTML) { 1.198 + // Set up a format converter so that clipboard flavor queries work. 1.199 + // This converter isn't really used for conversions. 1.200 + nsCOMPtr<nsIFormatConverter> htmlConverter = 1.201 + do_CreateInstance(kHTMLConverterCID); 1.202 + trans->SetConverter(htmlConverter); 1.203 + 1.204 + if (!textHTMLBuf.IsEmpty()) { 1.205 + // Add the html DataFlavor to the transferable 1.206 + rv = AppendString(trans, textHTMLBuf, kHTMLMime); 1.207 + NS_ENSURE_SUCCESS(rv, rv); 1.208 + } 1.209 + 1.210 + // Add the htmlcontext DataFlavor to the transferable 1.211 + // Even if parents is empty string, this flavor should 1.212 + // be attached to the transferable 1.213 + rv = AppendString(trans, htmlParentsBuf, kHTMLContext); 1.214 + NS_ENSURE_SUCCESS(rv, rv); 1.215 + 1.216 + if (!htmlInfoBuf.IsEmpty()) { 1.217 + // Add the htmlinfo DataFlavor to the transferable 1.218 + rv = AppendString(trans, htmlInfoBuf, kHTMLInfo); 1.219 + NS_ENSURE_SUCCESS(rv, rv); 1.220 + } 1.221 + 1.222 + if (!textPlainBuf.IsEmpty()) { 1.223 + // unicode text 1.224 + // Add the unicode DataFlavor to the transferable 1.225 + // If we didn't have this, then nsDataObj::GetData matches text/unicode against 1.226 + // the kURLMime flavour which is not desirable (eg. when pasting into Notepad) 1.227 + rv = AppendString(trans, textPlainBuf, kUnicodeMime); 1.228 + NS_ENSURE_SUCCESS(rv, rv); 1.229 + } 1.230 + 1.231 + // Try and get source URI of the items that are being dragged 1.232 + nsIURI *uri = aDoc->GetDocumentURI(); 1.233 + if (uri) { 1.234 + nsAutoCString spec; 1.235 + uri->GetSpec(spec); 1.236 + if (!spec.IsEmpty()) { 1.237 + nsAutoString shortcut; 1.238 + AppendUTF8toUTF16(spec, shortcut); 1.239 + 1.240 + // Add the URL DataFlavor to the transferable. Don't use kURLMime, as it will 1.241 + // cause an unnecessary UniformResourceLocator to be added which confuses 1.242 + // some apps eg. Outlook 2000 - (See Bug 315370). Don't use 1.243 + // kURLDataMime, as it will cause a bogus 'url ' flavor to 1.244 + // show up on the Mac clipboard, confusing other apps, like 1.245 + // Terminal (see bug 336012). 1.246 + rv = AppendString(trans, shortcut, kURLPrivateMime); 1.247 + NS_ENSURE_SUCCESS(rv, rv); 1.248 + } 1.249 + } 1.250 + } else { 1.251 + if (!textPlainBuf.IsEmpty()) { 1.252 + // Add the unicode DataFlavor to the transferable 1.253 + rv = AppendString(trans, textPlainBuf, kUnicodeMime); 1.254 + NS_ENSURE_SUCCESS(rv, rv); 1.255 + } 1.256 + } 1.257 + 1.258 + if (doPutOnClipboard && clipboard) { 1.259 + bool actuallyPutOnClipboard = true; 1.260 + nsCopySupport::DoHooks(aDoc, trans, &actuallyPutOnClipboard); 1.261 + 1.262 + // put the transferable on the clipboard 1.263 + if (actuallyPutOnClipboard) 1.264 + clipboard->SetData(trans, nullptr, aClipboardID); 1.265 + } 1.266 + 1.267 + // Return the transferable to the caller if requested. 1.268 + if (aTransferable != nullptr) { 1.269 + trans.swap(*aTransferable); 1.270 + } 1.271 + } 1.272 + } 1.273 + return rv; 1.274 +} 1.275 + 1.276 +nsresult 1.277 +nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc, 1.278 + int16_t aClipboardID) 1.279 +{ 1.280 + return SelectionCopyHelper(aSel, aDoc, true, aClipboardID, 1.281 + nsIDocumentEncoder::SkipInvisibleContent, 1.282 + nullptr); 1.283 +} 1.284 + 1.285 +nsresult 1.286 +nsCopySupport::GetTransferableForSelection(nsISelection* aSel, 1.287 + nsIDocument* aDoc, 1.288 + nsITransferable** aTransferable) 1.289 +{ 1.290 + return SelectionCopyHelper(aSel, aDoc, false, 0, 1.291 + nsIDocumentEncoder::SkipInvisibleContent, 1.292 + aTransferable); 1.293 +} 1.294 + 1.295 +nsresult 1.296 +nsCopySupport::GetTransferableForNode(nsINode* aNode, 1.297 + nsIDocument* aDoc, 1.298 + nsITransferable** aTransferable) 1.299 +{ 1.300 + nsCOMPtr<nsISelection> selection; 1.301 + // Make a temporary selection with aNode in a single range. 1.302 + nsresult rv = NS_NewDomSelection(getter_AddRefs(selection)); 1.303 + NS_ENSURE_SUCCESS(rv, rv); 1.304 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode); 1.305 + NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); 1.306 + nsRefPtr<nsRange> range = new nsRange(aNode); 1.307 + rv = range->SelectNode(node); 1.308 + NS_ENSURE_SUCCESS(rv, rv); 1.309 + rv = selection->AddRange(range); 1.310 + NS_ENSURE_SUCCESS(rv, rv); 1.311 + // It's not the primary selection - so don't skip invisible content. 1.312 + uint32_t flags = 0; 1.313 + return SelectionCopyHelper(selection, aDoc, false, 0, flags, 1.314 + aTransferable); 1.315 +} 1.316 + 1.317 +nsresult nsCopySupport::DoHooks(nsIDocument *aDoc, nsITransferable *aTrans, 1.318 + bool *aDoPutOnClipboard) 1.319 +{ 1.320 + NS_ENSURE_ARG(aDoc); 1.321 + 1.322 + *aDoPutOnClipboard = true; 1.323 + 1.324 + nsCOMPtr<nsISupports> container = aDoc->GetContainer(); 1.325 + nsCOMPtr<nsIClipboardDragDropHookList> hookObj = do_GetInterface(container); 1.326 + if (!hookObj) return NS_ERROR_FAILURE; 1.327 + 1.328 + nsCOMPtr<nsISimpleEnumerator> enumerator; 1.329 + hookObj->GetHookEnumerator(getter_AddRefs(enumerator)); 1.330 + if (!enumerator) return NS_ERROR_FAILURE; 1.331 + 1.332 + // the logic here should follow the behavior specified in 1.333 + // nsIClipboardDragDropHooks.h 1.334 + 1.335 + nsCOMPtr<nsIClipboardDragDropHooks> override; 1.336 + nsCOMPtr<nsISupports> isupp; 1.337 + bool hasMoreHooks = false; 1.338 + nsresult rv = NS_OK; 1.339 + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) 1.340 + && hasMoreHooks) 1.341 + { 1.342 + rv = enumerator->GetNext(getter_AddRefs(isupp)); 1.343 + if (NS_FAILED(rv)) break; 1.344 + override = do_QueryInterface(isupp); 1.345 + if (override) 1.346 + { 1.347 +#ifdef DEBUG 1.348 + nsresult hookResult = 1.349 +#endif 1.350 + override->OnCopyOrDrag(nullptr, aTrans, aDoPutOnClipboard); 1.351 + NS_ASSERTION(NS_SUCCEEDED(hookResult), "OnCopyOrDrag hook failed"); 1.352 + if (!*aDoPutOnClipboard) 1.353 + break; 1.354 + } 1.355 + } 1.356 + 1.357 + return rv; 1.358 +} 1.359 + 1.360 +nsresult 1.361 +nsCopySupport::GetContents(const nsACString& aMimeType, uint32_t aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata) 1.362 +{ 1.363 + nsresult rv = NS_OK; 1.364 + 1.365 + nsCOMPtr<nsIDocumentEncoder> docEncoder; 1.366 + 1.367 + nsAutoCString encoderContractID(NS_DOC_ENCODER_CONTRACTID_BASE); 1.368 + encoderContractID.Append(aMimeType); 1.369 + 1.370 + docEncoder = do_CreateInstance(encoderContractID.get()); 1.371 + NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE); 1.372 + 1.373 + uint32_t flags = aFlags | nsIDocumentEncoder::SkipInvisibleContent; 1.374 + 1.375 + if (aMimeType.Equals("text/plain")) 1.376 + flags |= nsIDocumentEncoder::OutputPreformatted; 1.377 + 1.378 + NS_ConvertASCIItoUTF16 unicodeMimeType(aMimeType); 1.379 + 1.380 + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc); 1.381 + NS_ASSERTION(domDoc, "Need a document"); 1.382 + 1.383 + rv = docEncoder->Init(domDoc, unicodeMimeType, flags); 1.384 + if (NS_FAILED(rv)) return rv; 1.385 + 1.386 + if (aSel) 1.387 + { 1.388 + rv = docEncoder->SetSelection(aSel); 1.389 + if (NS_FAILED(rv)) return rv; 1.390 + } 1.391 + 1.392 + // encode the selection 1.393 + return docEncoder->EncodeToString(outdata); 1.394 +} 1.395 + 1.396 + 1.397 +nsresult 1.398 +nsCopySupport::ImageCopy(nsIImageLoadingContent* aImageElement, 1.399 + nsILoadContext* aLoadContext, 1.400 + int32_t aCopyFlags) 1.401 +{ 1.402 + nsresult rv; 1.403 + 1.404 + // create a transferable for putting data on the Clipboard 1.405 + nsCOMPtr<nsITransferable> trans(do_CreateInstance(kCTransferableCID, &rv)); 1.406 + NS_ENSURE_SUCCESS(rv, rv); 1.407 + trans->Init(aLoadContext); 1.408 + 1.409 + if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_TEXT) { 1.410 + // get the location from the element 1.411 + nsCOMPtr<nsIURI> uri; 1.412 + rv = aImageElement->GetCurrentURI(getter_AddRefs(uri)); 1.413 + NS_ENSURE_SUCCESS(rv, rv); 1.414 + NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); 1.415 + 1.416 + nsAutoCString location; 1.417 + rv = uri->GetSpec(location); 1.418 + NS_ENSURE_SUCCESS(rv, rv); 1.419 + 1.420 + // append the string to the transferable 1.421 + rv = AppendString(trans, NS_ConvertUTF8toUTF16(location), kUnicodeMime); 1.422 + NS_ENSURE_SUCCESS(rv, rv); 1.423 + } 1.424 + 1.425 + if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_HTML) { 1.426 + // append HTML data to the transferable 1.427 + nsCOMPtr<nsINode> node(do_QueryInterface(aImageElement, &rv)); 1.428 + NS_ENSURE_SUCCESS(rv, rv); 1.429 + 1.430 + rv = AppendDOMNode(trans, node); 1.431 + NS_ENSURE_SUCCESS(rv, rv); 1.432 + } 1.433 + 1.434 + if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_DATA) { 1.435 + // get the image data from the element 1.436 + nsCOMPtr<imgIContainer> image = 1.437 + nsContentUtils::GetImageFromContent(aImageElement); 1.438 + NS_ENSURE_TRUE(image, NS_ERROR_FAILURE); 1.439 + 1.440 + nsCOMPtr<nsISupportsInterfacePointer> 1.441 + imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv)); 1.442 + NS_ENSURE_SUCCESS(rv, rv); 1.443 + 1.444 + rv = imgPtr->SetData(image); 1.445 + NS_ENSURE_SUCCESS(rv, rv); 1.446 + 1.447 + // copy the image data onto the transferable 1.448 + rv = trans->SetTransferData(kNativeImageMime, imgPtr, 1.449 + sizeof(nsISupports*)); 1.450 + NS_ENSURE_SUCCESS(rv, rv); 1.451 + } 1.452 + 1.453 + // get clipboard 1.454 + nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); 1.455 + NS_ENSURE_SUCCESS(rv, rv); 1.456 + 1.457 + // check whether the system supports the selection clipboard or not. 1.458 + bool selectionSupported; 1.459 + rv = clipboard->SupportsSelectionClipboard(&selectionSupported); 1.460 + NS_ENSURE_SUCCESS(rv, rv); 1.461 + 1.462 + // put the transferable on the clipboard 1.463 + if (selectionSupported) { 1.464 + rv = clipboard->SetData(trans, nullptr, nsIClipboard::kSelectionClipboard); 1.465 + NS_ENSURE_SUCCESS(rv, rv); 1.466 + } 1.467 + 1.468 + return clipboard->SetData(trans, nullptr, nsIClipboard::kGlobalClipboard); 1.469 +} 1.470 + 1.471 +static nsresult AppendString(nsITransferable *aTransferable, 1.472 + const nsAString& aString, 1.473 + const char* aFlavor) 1.474 +{ 1.475 + nsresult rv; 1.476 + 1.477 + nsCOMPtr<nsISupportsString> 1.478 + data(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv)); 1.479 + NS_ENSURE_SUCCESS(rv, rv); 1.480 + 1.481 + rv = data->SetData(aString); 1.482 + NS_ENSURE_SUCCESS(rv, rv); 1.483 + 1.484 + rv = aTransferable->AddDataFlavor(aFlavor); 1.485 + NS_ENSURE_SUCCESS(rv, rv); 1.486 + 1.487 + return aTransferable->SetTransferData(aFlavor, data, 1.488 + aString.Length() * sizeof(char16_t)); 1.489 +} 1.490 + 1.491 +static nsresult AppendDOMNode(nsITransferable *aTransferable, 1.492 + nsINode *aDOMNode) 1.493 +{ 1.494 + nsresult rv; 1.495 + 1.496 + // selializer 1.497 + nsCOMPtr<nsIDocumentEncoder> 1.498 + docEncoder(do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID, &rv)); 1.499 + NS_ENSURE_SUCCESS(rv, rv); 1.500 + 1.501 + // get document for the encoder 1.502 + nsCOMPtr<nsIDocument> document = aDOMNode->OwnerDoc(); 1.503 + 1.504 + // Note that XHTML is not counted as HTML here, because we can't copy it 1.505 + // properly (all the copy code for non-plaintext assumes using HTML 1.506 + // serializers and parsers is OK, and those mess up XHTML). 1.507 + nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document, &rv); 1.508 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.509 + 1.510 + NS_ENSURE_TRUE(document->IsHTML(), NS_OK); 1.511 + 1.512 + // init encoder with document and node 1.513 + rv = docEncoder->NativeInit(document, NS_LITERAL_STRING(kHTMLMime), 1.514 + nsIDocumentEncoder::OutputAbsoluteLinks | 1.515 + nsIDocumentEncoder::OutputEncodeW3CEntities); 1.516 + NS_ENSURE_SUCCESS(rv, rv); 1.517 + 1.518 + rv = docEncoder->SetNativeNode(aDOMNode); 1.519 + NS_ENSURE_SUCCESS(rv, rv); 1.520 + 1.521 + // serialize to string 1.522 + nsAutoString html, context, info; 1.523 + rv = docEncoder->EncodeToStringWithContext(context, info, html); 1.524 + NS_ENSURE_SUCCESS(rv, rv); 1.525 + 1.526 + // copy them to the transferable 1.527 + if (!html.IsEmpty()) { 1.528 + rv = AppendString(aTransferable, html, kHTMLMime); 1.529 + NS_ENSURE_SUCCESS(rv, rv); 1.530 + } 1.531 + 1.532 + if (!info.IsEmpty()) { 1.533 + rv = AppendString(aTransferable, info, kHTMLInfo); 1.534 + NS_ENSURE_SUCCESS(rv, rv); 1.535 + } 1.536 + 1.537 + // add a special flavor, even if we don't have html context data 1.538 + return AppendString(aTransferable, context, kHTMLContext); 1.539 +} 1.540 + 1.541 +nsIContent* 1.542 +nsCopySupport::GetSelectionForCopy(nsIDocument* aDocument, nsISelection** aSelection) 1.543 +{ 1.544 + *aSelection = nullptr; 1.545 + 1.546 + nsIPresShell* presShell = aDocument->GetShell(); 1.547 + if (!presShell) 1.548 + return nullptr; 1.549 + 1.550 + // check if the focused node in the window has a selection 1.551 + nsCOMPtr<nsPIDOMWindow> focusedWindow; 1.552 + nsIContent* content = 1.553 + nsFocusManager::GetFocusedDescendant(aDocument->GetWindow(), false, 1.554 + getter_AddRefs(focusedWindow)); 1.555 + if (content) { 1.556 + nsIFrame* frame = content->GetPrimaryFrame(); 1.557 + if (frame) { 1.558 + nsCOMPtr<nsISelectionController> selCon; 1.559 + frame->GetSelectionController(presShell->GetPresContext(), getter_AddRefs(selCon)); 1.560 + if (selCon) { 1.561 + selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection); 1.562 + return content; 1.563 + } 1.564 + } 1.565 + } 1.566 + 1.567 + // if no selection was found, use the main selection for the window 1.568 + NS_IF_ADDREF(*aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL)); 1.569 + return nullptr; 1.570 +} 1.571 + 1.572 +bool 1.573 +nsCopySupport::CanCopy(nsIDocument* aDocument) 1.574 +{ 1.575 + if (!aDocument) 1.576 + return false; 1.577 + 1.578 + nsCOMPtr<nsISelection> sel; 1.579 + GetSelectionForCopy(aDocument, getter_AddRefs(sel)); 1.580 + NS_ENSURE_TRUE(sel, false); 1.581 + 1.582 + bool isCollapsed; 1.583 + sel->GetIsCollapsed(&isCollapsed); 1.584 + return !isCollapsed; 1.585 +} 1.586 + 1.587 +bool 1.588 +nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, nsISelection* aSelection) 1.589 +{ 1.590 + NS_ASSERTION(aType == NS_CUT || aType == NS_COPY || aType == NS_PASTE, 1.591 + "Invalid clipboard event type"); 1.592 + 1.593 + nsCOMPtr<nsIPresShell> presShell = aPresShell; 1.594 + if (!presShell) 1.595 + return false; 1.596 + 1.597 + nsCOMPtr<nsIDocument> doc = presShell->GetDocument(); 1.598 + if (!doc) 1.599 + return false; 1.600 + 1.601 + nsCOMPtr<nsPIDOMWindow> piWindow = doc->GetWindow(); 1.602 + if (!piWindow) 1.603 + return false; 1.604 + 1.605 + // if a selection was not supplied, try to find it 1.606 + nsCOMPtr<nsIContent> content; 1.607 + nsCOMPtr<nsISelection> sel = aSelection; 1.608 + if (!sel) 1.609 + content = GetSelectionForCopy(doc, getter_AddRefs(sel)); 1.610 + 1.611 + // retrieve the event target node from the start of the selection 1.612 + nsresult rv; 1.613 + if (sel) { 1.614 + // Only cut or copy when there is an uncollapsed selection 1.615 + if (aType == NS_CUT || aType == NS_COPY) { 1.616 + bool isCollapsed; 1.617 + sel->GetIsCollapsed(&isCollapsed); 1.618 + if (isCollapsed) 1.619 + return false; 1.620 + } 1.621 + 1.622 + nsCOMPtr<nsIDOMRange> range; 1.623 + rv = sel->GetRangeAt(0, getter_AddRefs(range)); 1.624 + if (NS_SUCCEEDED(rv) && range) { 1.625 + nsCOMPtr<nsIDOMNode> startContainer; 1.626 + range->GetStartContainer(getter_AddRefs(startContainer)); 1.627 + if (startContainer) 1.628 + content = do_QueryInterface(startContainer); 1.629 + } 1.630 + } 1.631 + 1.632 + // if no content node was set, just get the root 1.633 + if (!content) { 1.634 + content = doc->GetRootElement(); 1.635 + if (!content) 1.636 + return false; 1.637 + } 1.638 + 1.639 + // It seems to be unsafe to fire an event handler during reflow (bug 393696) 1.640 + if (!nsContentUtils::IsSafeToRunScript()) 1.641 + return false; 1.642 + 1.643 + nsCOMPtr<nsIDocShell> docShell = do_GetInterface(piWindow); 1.644 + const bool chromeShell = 1.645 + docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome; 1.646 + 1.647 + // next, fire the cut, copy or paste event 1.648 + bool doDefault = true; 1.649 + nsRefPtr<DataTransfer> clipboardData; 1.650 + if (chromeShell || Preferences::GetBool("dom.event.clipboardevents.enabled", true)) { 1.651 + clipboardData = 1.652 + new DataTransfer(piWindow, aType, aType == NS_PASTE, aClipboardType); 1.653 + 1.654 + nsEventStatus status = nsEventStatus_eIgnore; 1.655 + InternalClipboardEvent evt(true, aType); 1.656 + evt.clipboardData = clipboardData; 1.657 + EventDispatcher::Dispatch(content, presShell->GetPresContext(), &evt, 1.658 + nullptr, &status); 1.659 + // If the event was cancelled, don't do the clipboard operation 1.660 + doDefault = (status != nsEventStatus_eConsumeNoDefault); 1.661 + } 1.662 + 1.663 + // No need to do anything special during a paste. Either an event listener 1.664 + // took care of it and cancelled the event, or the caller will handle it. 1.665 + // Return true to indicate that the event wasn't cancelled. 1.666 + if (aType == NS_PASTE) { 1.667 + // Clear and mark the clipboardData as readonly. This prevents someone 1.668 + // from reading the clipboard contents after the paste event has fired. 1.669 + if (clipboardData) { 1.670 + clipboardData->ClearAll(); 1.671 + clipboardData->SetReadOnly(); 1.672 + } 1.673 + 1.674 + return doDefault; 1.675 + } 1.676 + 1.677 + // Update the presentation in case the event handler modified the selection, 1.678 + // see bug 602231. 1.679 + presShell->FlushPendingNotifications(Flush_Frames); 1.680 + if (presShell->IsDestroying()) 1.681 + return false; 1.682 + 1.683 + // if the event was not cancelled, do the default copy. If the event was cancelled, 1.684 + // use the data added to the data transfer and copy that instead. 1.685 + uint32_t count = 0; 1.686 + if (doDefault) { 1.687 + // get the data from the selection if any 1.688 + bool isCollapsed; 1.689 + sel->GetIsCollapsed(&isCollapsed); 1.690 + if (isCollapsed) { 1.691 + return false; 1.692 + } 1.693 + // call the copy code 1.694 + rv = HTMLCopy(sel, doc, aClipboardType); 1.695 + if (NS_FAILED(rv)) { 1.696 + return false; 1.697 + } 1.698 + } else if (clipboardData) { 1.699 + // check to see if any data was put on the data transfer. 1.700 + clipboardData->GetMozItemCount(&count); 1.701 + if (count) { 1.702 + nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1")); 1.703 + NS_ENSURE_TRUE(clipboard, false); 1.704 + 1.705 + nsCOMPtr<nsITransferable> transferable = 1.706 + clipboardData->GetTransferable(0, doc->GetLoadContext()); 1.707 + 1.708 + NS_ENSURE_TRUE(transferable, false); 1.709 + 1.710 + // put the transferable on the clipboard 1.711 + rv = clipboard->SetData(transferable, nullptr, aClipboardType); 1.712 + if (NS_FAILED(rv)) { 1.713 + return false; 1.714 + } 1.715 + } 1.716 + } 1.717 + 1.718 + // Now that we have copied, update the clipboard commands. This should have 1.719 + // the effect of updating the enabled state of the paste menu item. 1.720 + if (doDefault || count) { 1.721 + piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard")); 1.722 + } 1.723 + 1.724 + return doDefault; 1.725 +}