Bug 1261299 - Add a method nsCopySupport::SetSelectionCache instead of relying on the method used to set the os clipboard.
MozReview-Commit-ID: KvmdD2XqKBh
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -291,28 +291,228 @@ SelectionCopyHelper(nsISelection *aSel,
if (aTransferable != nullptr) {
trans.swap(*aTransferable);
}
}
}
return rv;
}
+static nsresult
+SelectionCopyHelper2(nsISelection *aSel, nsIDocument *aDoc,
+ bool doPutOnClipboard, int16_t aClipboardID,
+ uint32_t aFlags, nsITransferable ** aTransferable)
+{
+ // Clear the output parameter for the transferable, if provided.
+ if (aTransferable) {
+ *aTransferable = nullptr;
+ }
+
+ nsresult rv;
+
+ nsCOMPtr<nsIDocumentEncoder> docEncoder;
+ docEncoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID);
+ NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
+
+ // note that we assign text/unicode as mime type, but in fact nsHTMLCopyEncoder
+ // ignore it and use text/html or text/plain depending where the selection
+ // is. if it is a selection into input/textarea element or in a html content
+ // with pre-wrap style : text/plain. Otherwise text/html.
+ // see nsHTMLCopyEncoder::SetSelection
+ nsAutoString mimeType;
+ mimeType.AssignLiteral(kUnicodeMime);
+
+ // Do the first and potentially trial encoding as preformatted and raw.
+ uint32_t flags = aFlags | nsIDocumentEncoder::OutputPreformatted
+ | nsIDocumentEncoder::OutputRaw
+ | nsIDocumentEncoder::OutputForPlainTextClipboardCopy;
+
+ nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
+ NS_ASSERTION(domDoc, "Need a document");
+
+ rv = docEncoder->Init(domDoc, mimeType, flags);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = docEncoder->SetSelection(aSel);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // SetSelection set the mime type to text/plain if the selection is inside a
+ // text widget.
+ rv = docEncoder->GetMimeType(mimeType);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool selForcedTextPlain = mimeType.EqualsLiteral(kTextMime);
+
+ nsAutoString buf;
+ rv = docEncoder->EncodeToString(buf);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = docEncoder->GetMimeType(mimeType);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!selForcedTextPlain && mimeType.EqualsLiteral(kTextMime)) {
+ // SetSelection and EncodeToString use this case to signal that text/plain
+ // was forced because the document is either not an nsIHTMLDocument or it's
+ // XHTML. We want to pretty print XHTML but not non-nsIHTMLDocuments.
+ nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aDoc);
+ if (!htmlDoc) {
+ selForcedTextPlain = true;
+ }
+ }
+
+ // The mime type is ultimately text/html if the encoder successfully encoded
+ // the selection as text/html.
+ bool encodedTextHTML = mimeType.EqualsLiteral(kHTMLMime);
+
+ // First, prepare the text/plain clipboard flavor.
+ nsAutoString textPlainBuf;
+ if (selForcedTextPlain) {
+ // Nothing to do. buf contains the final, preformatted, raw text/plain.
+ textPlainBuf.Assign(buf);
+ } else {
+ // Redo the encoding, but this time use pretty printing.
+ flags =
+ nsIDocumentEncoder::OutputSelectionOnly |
+ nsIDocumentEncoder::OutputAbsoluteLinks |
+ nsIDocumentEncoder::SkipInvisibleContent |
+ nsIDocumentEncoder::OutputDropInvisibleBreak |
+ (aFlags & (nsIDocumentEncoder::OutputNoScriptContent |
+ nsIDocumentEncoder::OutputRubyAnnotation));
+
+ mimeType.AssignLiteral(kTextMime);
+ rv = docEncoder->Init(domDoc, mimeType, flags);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = docEncoder->SetSelection(aSel);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = docEncoder->EncodeToString(textPlainBuf);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // Second, prepare the text/html flavor.
+ nsAutoString textHTMLBuf;
+ nsAutoString htmlParentsBuf;
+ nsAutoString htmlInfoBuf;
+ if (encodedTextHTML) {
+ // Redo the encoding, but this time use the passed-in flags.
+ // Don't allow wrapping of CJK strings.
+ mimeType.AssignLiteral(kHTMLMime);
+ rv = docEncoder->Init(domDoc, mimeType,
+ aFlags |
+ nsIDocumentEncoder::OutputDisallowLineBreaking);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = docEncoder->SetSelection(aSel);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = docEncoder->EncodeToStringWithContext(htmlParentsBuf, htmlInfoBuf,
+ textHTMLBuf);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ if (aTransferable != nullptr) {
+ // Create a transferable for putting data on the Clipboard
+ nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID);
+ if (trans) {
+ trans->Init(aDoc->GetLoadContext());
+ if (encodedTextHTML) {
+ // Set up a format converter so that clipboard flavor queries work.
+ // This converter isn't really used for conversions.
+ nsCOMPtr<nsIFormatConverter> htmlConverter =
+ do_CreateInstance(kHTMLConverterCID);
+ trans->SetConverter(htmlConverter);
+
+ if (!textHTMLBuf.IsEmpty()) {
+ // Add the html DataFlavor to the transferable
+ rv = AppendString(trans, textHTMLBuf, kHTMLMime);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // Add the htmlcontext DataFlavor to the transferable
+ // Even if parents is empty string, this flavor should
+ // be attached to the transferable
+ rv = AppendString(trans, htmlParentsBuf, kHTMLContext);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!htmlInfoBuf.IsEmpty()) {
+ // Add the htmlinfo DataFlavor to the transferable
+ rv = AppendString(trans, htmlInfoBuf, kHTMLInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ if (!textPlainBuf.IsEmpty()) {
+ // unicode text
+ // Add the unicode DataFlavor to the transferable
+ // If we didn't have this, then nsDataObj::GetData matches text/unicode against
+ // the kURLMime flavour which is not desirable (eg. when pasting into Notepad)
+ rv = AppendString(trans, textPlainBuf, kUnicodeMime);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // Try and get source URI of the items that are being dragged
+ nsIURI *uri = aDoc->GetDocumentURI();
+ if (uri) {
+ nsAutoCString spec;
+ uri->GetSpec(spec);
+ if (!spec.IsEmpty()) {
+ nsAutoString shortcut;
+ AppendUTF8toUTF16(spec, shortcut);
+
+ // Add the URL DataFlavor to the transferable. Don't use kURLMime, as it will
+ // cause an unnecessary UniformResourceLocator to be added which confuses
+ // some apps eg. Outlook 2000 - (See Bug 315370). Don't use
+ // kURLDataMime, as it will cause a bogus 'url ' flavor to
+ // show up on the Mac clipboard, confusing other apps, like
+ // Terminal (see bug 336012).
+ rv = AppendString(trans, shortcut, kURLPrivateMime);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+ } else {
+ if (!textPlainBuf.IsEmpty()) {
+ // Add the unicode DataFlavor to the transferable
+ rv = AppendString(trans, textPlainBuf, kUnicodeMime);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ // Return the transferable to the caller if requested.
+ if (aTransferable != nullptr) {
+ trans.swap(*aTransferable);
+ }
+ }
+ }
+ return rv;
+}
+
nsresult
nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc,
int16_t aClipboardID, bool aWithRubyAnnotation)
{
uint32_t flags = nsIDocumentEncoder::SkipInvisibleContent;
if (aWithRubyAnnotation) {
flags |= nsIDocumentEncoder::OutputRubyAnnotation;
}
return SelectionCopyHelper(aSel, aDoc, true, aClipboardID, flags, nullptr);
}
nsresult
+nsCopySupport::SetSelectionCache(nsISelection* aSel, nsIDocument* aDoc)
+{
+ nsresult rv;
+ nsCOMPtr<nsITransferable> transferable;
+ rv = SelectionCopyHelper2(aSel, aDoc, false, 0,
+ nsIDocumentEncoder::SkipInvisibleContent,
+ getter_AddRefs(transferable));
+ nsCOMPtr<nsIClipboard> clipboard = do_GetService(kCClipboardCID, &rv);
+ clipboard->SetData(transferable, nullptr, nsIClipboard::kSelectionCache);
+ return rv;
+}
+
+nsresult
nsCopySupport::ClearSelectionCache()
{
nsresult rv;
nsCOMPtr<nsIClipboard> clipboard = do_GetService(kCClipboardCID, &rv);
clipboard->EmptyClipboard(nsIClipboard::kSelectionCache);
return rv;
}
--- a/dom/base/nsCopySupport.h
+++ b/dom/base/nsCopySupport.h
@@ -21,16 +21,17 @@ class nsAString;
class nsIPresShell;
class nsILoadContext;
class nsCopySupport
{
// class of static helper functions for copy support
public:
static nsresult ClearSelectionCache();
+ static nsresult SetSelectionCache(nsISelection* aSel, nsIDocument* aDoc);
static nsresult HTMLCopy(nsISelection *aSel, nsIDocument *aDoc,
int16_t aClipboardID, bool aWithRubyAnnotation);
static nsresult DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
bool *aDoPutOnClipboard);
// Get the selection, or entire document, in the format specified by the mime type
// (text/html or text/plain). If aSel is non-null, use it, otherwise get the entire
// doc.
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -6517,16 +6517,20 @@ nsAutoCopyListener::NotifySelectionChang
}
/* clear X clipboard? */
return NS_OK;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+ if (mCachedClipboard == nsIClipboard::kSelectionCache) {
+ return nsCopySupport::SetSelectionCache(aSel, doc);
+ }
+
// call the copy code
return nsCopySupport::HTMLCopy(aSel, doc,
mCachedClipboard, false);
}
/**
* See Bug 1288453.
*
@@ -6555,18 +6559,17 @@ nsFrameSelection::UpdateSelectionCacheOn
aDoc = do_QueryInterface(ps->GetDocument());
}
bool collapsed;
if (aDoc && aSel &&
NS_SUCCEEDED(aSel->GetIsCollapsed(&collapsed)) && !collapsed) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
- return nsCopySupport::HTMLCopy(aSel, doc,
- nsIClipboard::kSelectionCache, false);
+ return nsCopySupport::SetSelectionCache(aSel, doc);
}
return NS_OK;
}
// SelectionChangeListener
SelectionChangeListener::RawRangeData::RawRangeData(const nsRange* aRange)