Bug 586587 - support kHTMLMime in the Windows clipboard as CF_HTML. r=jimm

This commit is contained in:
Andrew Herron 2015-07-22 16:56:57 +10:00
parent 42f828e354
commit 130eb91e43
14 changed files with 213 additions and 63 deletions

View File

@ -20,6 +20,10 @@ const base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" +
const { base64jpeg } = require("./fixtures");
const { platform } = require("sdk/system");
// For Windows, Mac and Linux, platform returns the following: winnt, darwin and linux.
var isWindows = platform.toLowerCase().indexOf("win") == 0;
const canvasHTML = "data:text/html," + encodeURIComponent(
"<html>\
<body>\
@ -99,6 +103,13 @@ exports["test With No Flavor"] = function(assert) {
exports["test With Flavor"] = function(assert) {
var contents = "<b>hello there</b>";
var contentsText = "hello there";
// On windows, HTML clipboard includes extra data.
// The values are from widget/windows/nsDataObj.cpp.
var contentsWindowsHtml = "<html><body>\n<!--StartFragment-->" +
contents +
"<!--EndFragment-->\n</body>\n</html>";
var flavor = "html";
var fullFlavor = "text/html";
var unicodeFlavor = "text";
@ -110,8 +121,8 @@ exports["test With Flavor"] = function(assert) {
assert.equal(clip.currentFlavors[0], unicodeFlavor);
assert.equal(clip.currentFlavors[1], flavor);
assert.equal(clip.get(), contentsText);
assert.equal(clip.get(flavor), contents);
assert.equal(clip.get(fullFlavor), contents);
assert.equal(clip.get(flavor), isWindows ? contentsWindowsHtml : contents);
assert.equal(clip.get(fullFlavor), isWindows ? contentsWindowsHtml : contents);
assert.equal(clip.get(unicodeFlavor), contentsText);
assert.equal(clip.get(unicodeFullFlavor), contentsText);
};

View File

@ -14,11 +14,16 @@ add_task(function*() {
yield promiseTabLoadEvent(tab, "data:text/html," + escape(testPage));
yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
const modifier = (content.navigator.platform.indexOf("Mac") >= 0) ?
const modifier = (navigator.platform.indexOf("Mac") >= 0) ?
Components.interfaces.nsIDOMWindowUtils.MODIFIER_META :
Components.interfaces.nsIDOMWindowUtils.MODIFIER_CONTROL;
let results = yield ContentTask.spawn(browser, { modifier: modifier },
// On windows, HTML clipboard includes extra data.
// The values are from widget/windows/nsDataObj.cpp.
const htmlPrefix = (navigator.platform.indexOf("Win") >= 0) ? "<html><body>\n<!--StartFragment-->" : "";
const htmlPostfix = (navigator.platform.indexOf("Win") >= 0) ? "<!--EndFragment-->\n</body>\n</html>" : "";
let results = yield ContentTask.spawn(browser, { modifier: modifier, htmlPrefix: htmlPrefix, htmlPostfix: htmlPostfix },
function* (arg) {
var doc = content.document;
var main = doc.getElementById("main");
@ -71,7 +76,7 @@ add_task(function*() {
is(clipboardData.types.length, 2, "Two types on clipboard");
is(clipboardData.types[0], "text/html", "text/html on clipboard");
is(clipboardData.types[1], "text/plain", "text/plain on clipboard");
is(clipboardData.getData("text/html"), "t <b>Bold</b>", "text/html value");
is(clipboardData.getData("text/html"), arg.htmlPrefix + "t <b>Bold</b>" + arg.htmlPostfix, "text/html value");
is(clipboardData.getData("text/plain"), "t Bold", "text/plain value");
resolve();
}, true)
@ -106,7 +111,7 @@ add_task(function*() {
is(clipboardData.types.length, 2, "Two types on clipboard 2");
is(clipboardData.types[0], "text/html", "text/html on clipboard 2");
is(clipboardData.types[1], "text/plain", "text/plain on clipboard 2");
is(clipboardData.getData("text/html"), "<i>Italic</i> ", "text/html value 2");
is(clipboardData.getData("text/html"), arg.htmlPrefix + "<i>Italic</i> " + arg.htmlPostfix, "text/html value 2");
is(clipboardData.getData("text/plain"), "Some text", "text/plain value 2");
resolve();
}, true)
@ -140,7 +145,7 @@ add_task(function*() {
// Focus the content again
yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
let expectedContent = yield ContentTask.spawn(browser, { modifier: modifier },
let expectedContent = yield ContentTask.spawn(browser, { modifier: modifier, htmlPrefix: htmlPrefix, htmlPostfix: htmlPostfix },
function* (arg) {
var doc = content.document;
var main = doc.getElementById("main");
@ -153,9 +158,10 @@ add_task(function*() {
// DataTransfer doesn't support the image types yet, so only text/html
// will be present.
if (clipboardData.getData("text/html") !=
'<img id="img" tabindex="1" src="http://example.org/browser/browser/base/content/test/general/moz.png">') {
reject();
if (clipboardData.getData("text/html") !== arg.htmlPrefix +
'<img id="img" tabindex="1" src="http://example.org/browser/browser/base/content/test/general/moz.png">' +
arg.htmlPostfix) {
reject('Clipboard Data did not contain an image, was ' + clipboardData.getData("text/html"));
}
resolve();
}, true)

View File

@ -92,6 +92,17 @@ function testCopyPaste (isXHTML) {
transferable.getTransferData(mime, data, {}) ;
return data;
}
function testHtmlClipboardValue(mime, expected) {
// For Windows, navigator.platform returns "Win32".
var expectedValue = expected;
if (navigator.platform.indexOf("Win") >= 0) {
// Windows has extra content.
var expectedValue = "<html><body>\n<!--StartFragment-->" +
expected.replace(/\n/g, '\n') +
"<!--EndFragment-->\n</body>\n</html>";
}
testClipboardValue(mime, expectedValue);
}
function testClipboardValue(mime, expected) {
if (suppressHTMLCheck && mime == "text/html")
return null;
@ -133,37 +144,37 @@ function testCopyPaste (isXHTML) {
testSelectionToString("This is a draggable bit of text.");
testClipboardValue("text/unicode",
"This is a draggable bit of text.");
testClipboardValue("text/html",
testHtmlClipboardValue("text/html",
"<div id=\"draggable\" title=\"title to have a long HTML line\">This is a <em>draggable</em> bit of text.</div>");
testPasteText("This is a draggable bit of text.");
copyChildrenToClipboard("alist");
testSelectionToString(" bla\n\n foo\n bar\n\n");
testClipboardValue("text/unicode", " bla\n\n foo\n bar\n\n");
testClipboardValue("text/html", "<div id=\"alist\">\n bla\n <ul>\n <li>foo</li>\n \n <li>bar</li>\n </ul>\n </div>");
testHtmlClipboardValue("text/html", "<div id=\"alist\">\n bla\n <ul>\n <li>foo</li>\n \n <li>bar</li>\n </ul>\n </div>");
testPasteText(" bla\n\n foo\n bar\n\n");
copyChildrenToClipboard("blist");
testSelectionToString(" mozilla\n\n foo\n bar\n\n");
testClipboardValue("text/unicode", " mozilla\n\n foo\n bar\n\n");
testClipboardValue("text/html", "<div id=\"blist\">\n mozilla\n <ol>\n <li>foo</li>\n \n <li>bar</li>\n </ol>\n </div>");
testHtmlClipboardValue("text/html", "<div id=\"blist\">\n mozilla\n <ol>\n <li>foo</li>\n \n <li>bar</li>\n </ol>\n </div>");
testPasteText(" mozilla\n\n foo\n bar\n\n");
copyChildrenToClipboard("clist");
testSelectionToString(" mzla\n\n foo\n bazzinga!\n bar\n\n");
testClipboardValue("text/unicode", " mzla\n\n foo\n bazzinga!\n bar\n\n");
testClipboardValue("text/html", "<div id=\"clist\">\n mzla\n <ul>\n <li>foo<ul>\n <li>bazzinga!</li>\n </ul></li>\n \n <li>bar</li>\n </ul>\n </div>");
testHtmlClipboardValue("text/html", "<div id=\"clist\">\n mzla\n <ul>\n <li>foo<ul>\n <li>bazzinga!</li>\n </ul></li>\n \n <li>bar</li>\n </ul>\n </div>");
testPasteText(" mzla\n\n foo\n bazzinga!\n bar\n\n");
copyChildrenToClipboard("div4");
testSelectionToString(" Tt t t ");
testClipboardValue("text/unicode", " Tt t t ");
if (isXHTML) {
testClipboardValue("text/html", "<div id=\"div4\">\n T<textarea xmlns=\"http://www.w3.org/1999/xhtml\">t t t</textarea>\n</div>");
testHtmlClipboardValue("text/html", "<div id=\"div4\">\n T<textarea xmlns=\"http://www.w3.org/1999/xhtml\">t t t</textarea>\n</div>");
testInnerHTML("div4", "\n T<textarea xmlns=\"http://www.w3.org/1999/xhtml\">t t t</textarea>\n");
}
else {
testClipboardValue("text/html", "<div id=\"div4\">\n T<textarea>t t t</textarea>\n</div>");
testHtmlClipboardValue("text/html", "<div id=\"div4\">\n T<textarea>t t t</textarea>\n</div>");
testInnerHTML("div4", "\n T<textarea>t t t</textarea>\n");
}
testPasteText(" Tt t t ");
@ -172,11 +183,11 @@ function testCopyPaste (isXHTML) {
testSelectionToString(" T ");
testClipboardValue("text/unicode", " T ");
if (isXHTML) {
testClipboardValue("text/html", "<div id=\"div5\">\n T<textarea xmlns=\"http://www.w3.org/1999/xhtml\"> </textarea>\n</div>");
testHtmlClipboardValue("text/html", "<div id=\"div5\">\n T<textarea xmlns=\"http://www.w3.org/1999/xhtml\"> </textarea>\n</div>");
testInnerHTML("div5", "\n T<textarea xmlns=\"http://www.w3.org/1999/xhtml\"> </textarea>\n");
}
else {
testClipboardValue("text/html", "<div id=\"div5\">\n T<textarea> </textarea>\n</div>");
testHtmlClipboardValue("text/html", "<div id=\"div5\">\n T<textarea> </textarea>\n</div>");
testInnerHTML("div5", "\n T<textarea> </textarea>\n");
}
testPasteText(" T ");
@ -214,7 +225,7 @@ if (false) {
copyRangeToClipboard($("div9").childNodes[0],0, $("div9").childNodes[0],4,suppressUnicodeCheckIfHidden);
testSelectionToString("div9");
testClipboardValue("text/unicode", "div9");
testClipboardValue("text/html", "div9");
testHtmlClipboardValue("text/html", "div9");
testInnerHTML("div9", "div9");
copyToClipboard($("div10"), suppressUnicodeCheckIfHidden);
@ -357,7 +368,7 @@ if (false) {
copyChildrenToClipboard("div13");
testSelectionToString("__");
testClipboardValue("text/unicode", "__");
testClipboardValue("text/html", "<div id=\"div13\">__</div>");
testHtmlClipboardValue("text/html", "<div id=\"div13\">__</div>");
testPasteText("__");
// ============ converting cell boundaries to tabs in tables
@ -370,7 +381,7 @@ if (false) {
copyRangeToClipboard($("tr2"),0,$("tr3"),0);
testClipboardValue("text/unicode", "1\t2\n3\t4\n");
testClipboardValue("text/html", '<table><tbody><tr id="tr2"><tr id="tr2"><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr><tr id="tr3"></tr></tr></tbody></table>');
testHtmlClipboardValue("text/html", '<table><tbody><tr id="tr2"><tr id="tr2"><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr><tr id="tr3"></tr></tr></tbody></table>');
// ============ spanning multiple rows in multi-range selection
@ -379,20 +390,20 @@ if (false) {
addRange($("tr3"),0,$("tr3"),2);
copySelectionToClipboard();
testClipboardValue("text/unicode", "1\t2\n5\t6");
testClipboardValue("text/html", '<table><tbody><tr id="tr2"><td>1</td><td>2</td></tr><tr id="tr3"><td>5</td><td>6</td></tr></tbody></table>');
testHtmlClipboardValue("text/html", '<table><tbody><tr id="tr2"><td>1</td><td>2</td></tr><tr id="tr3"><td>5</td><td>6</td></tr></tbody></table>');
}
// ============ manipulating Selection in oncopy
copyRangeToClipboard($("div11").childNodes[0],0, $("div11").childNodes[1],2);
testClipboardValue("text/unicode", "Xdiv11");
testClipboardValue("text/html", "<div><p>X<span>div</span>11</p></div>");
testHtmlClipboardValue("text/html", "<div><p>X<span>div</span>11</p></div>");
setTimeout(function(){testSelectionToString("div11")},0);
setTimeout(function(){
copyRangeToClipboard($("div12").childNodes[0],0, $("div12").childNodes[1],2);
testClipboardValue("text/unicode", "Xdiv12");
testClipboardValue("text/html", "<div><p>X<span>div</span>12</p></div>");
testHtmlClipboardValue("text/html", "<div><p>X<span>div</span>12</p></div>");
setTimeout(function(){
testSelectionToString("div12");
setTimeout(SimpleTest.finish,0);

View File

@ -67,6 +67,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=816298
transferable.getTransferData(mime, data, {}) ;
return SpecialPowers.wrap(data);
}
function testHtmlClipboardValue(mime, expected, test) {
var expectedValue = expected;
// For Windows, navigator.platform returns "Win32".
if (navigator.platform.indexOf("Win") >= 0) {
expectedValue = "<html><body>\n<!--StartFragment-->" + expected + "<!--EndFragment-->\n</body>\n</html>";
}
testClipboardValue(mime, expectedValue, test);
}
function testClipboardValue(mime, expected, test) {
var data = getClipboardData(mime);
is (data.value == null ? data.value :
@ -140,7 +148,7 @@ for (var i = 0; i < originalStrings.length; i++) {
var id = 'test' + i;
copyChildrenToClipboard(id);
is(window.getSelection().toString(), originalStrings[i], id + ' Selection.toString()');
testClipboardValue("text/html", clipboardHTML[i], id);
testHtmlClipboardValue("text/html", clipboardHTML[i], id);
testClipboardValue("text/unicode", clipboardUnicode[i], id);
testInnerHTML(id, innerHTMLStrings[i]);
testPasteText(textareaStrings[i], id + '.innerHTML');

View File

@ -71,7 +71,11 @@ function testCopyImage () {
// Is the text/uncodie data correct ?
testClipboardValue('text/unicode', 'about:logo');
// Is the text/html data correct ?
testClipboardValue('text/html', '<img id="logo" src="about:logo">');
var expected = '<img id="logo" src="about:logo">';
if (navigator.platform.indexOf("Win") >= 0) {
expected = "<html><body>\n<!--StartFragment-->" + expected + "<!--EndFragment-->\n</body>\n</html>";
}
testClipboardValue('text/html', expected);
SimpleTest.finish();
}

View File

@ -1361,7 +1361,14 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
variant->SetAsAString(str);
}
else {
variant->SetAsISupports(data);
nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data);
if (supportscstr) {
nsAutoCString str;
supportscstr->GetData(str);
variant->SetAsACString(str);
} else {
variant->SetAsISupports(data);
}
}
aItem.mData = variant;

View File

@ -812,8 +812,7 @@ NS_IMETHODIMP nsHTMLEditor::PrepareTransferable(nsITransferable **transferable)
}
nsresult
nsHTMLEditor::PrepareHTMLTransferable(nsITransferable **aTransferable,
bool aHavePrivFlavor)
nsHTMLEditor::PrepareHTMLTransferable(nsITransferable **aTransferable)
{
// Create generic Transferable for getting the data
nsresult rv = CallCreateInstance("@mozilla.org/widget/transferable;1", aTransferable);
@ -831,10 +830,7 @@ nsHTMLEditor::PrepareHTMLTransferable(nsITransferable **aTransferable,
// This should only happen in html editors, not plaintext
if (!IsPlaintextEditor())
{
if (!aHavePrivFlavor)
{
(*aTransferable)->AddDataFlavor(kNativeHTMLMime);
}
(*aTransferable)->AddDataFlavor(kNativeHTMLMime);
(*aTransferable)->AddDataFlavor(kHTMLMime);
(*aTransferable)->AddDataFlavor(kFileMime);
@ -1095,6 +1091,7 @@ nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable,
nsIDOMDocument *aSourceDoc,
const nsAString & aContextStr,
const nsAString & aInfoStr,
bool havePrivateHTMLFlavor,
nsIDOMNode *aDestinationNode,
int32_t aDestOffset,
bool aDoDeleteSelection)
@ -1134,12 +1131,24 @@ nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable,
if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
{
nsAutoEditBatch beginBatching(this);
rv = DoInsertHTMLWithContext(cffragment,
cfcontext, cfselection, flavor,
aSourceDoc,
aDestinationNode, aDestOffset,
aDoDeleteSelection,
isSafe);
// If we have our private HTML flavor, we will only use the fragment
// from the CF_HTML. The rest comes from the clipboard.
if (havePrivateHTMLFlavor) {
rv = DoInsertHTMLWithContext(cffragment,
aContextStr, aInfoStr, flavor,
aSourceDoc,
aDestinationNode, aDestOffset,
aDoDeleteSelection,
isSafe);
} else {
rv = DoInsertHTMLWithContext(cffragment,
cfcontext, cfselection, flavor,
aSourceDoc,
aDestinationNode, aDestOffset,
aDoDeleteSelection,
isSafe);
}
} else {
// In some platforms (like Linux), the clipboard might return data
// requested for unknown flavors (for example:
@ -1241,9 +1250,10 @@ nsresult nsHTMLEditor::InsertFromDataTransfer(DataTransfer *aDataTransfer,
aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
}
}
else if (!hasPrivateHTMLFlavor && type.EqualsLiteral(kNativeHTMLMime)) {
else if (type.EqualsLiteral(kNativeHTMLMime)) {
// Windows only clipboard parsing.
nsAutoString text;
GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kNativeHTMLMime), aIndex, text);
GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
NS_ConvertUTF16toUTF8 cfhtml(text);
nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
@ -1252,12 +1262,28 @@ nsresult nsHTMLEditor::InsertFromDataTransfer(DataTransfer *aDataTransfer,
if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
{
nsAutoEditBatch beginBatching(this);
return DoInsertHTMLWithContext(cffragment,
cfcontext, cfselection, type,
aSourceDoc,
aDestinationNode, aDestOffset,
aDoDeleteSelection,
isSafe);
if (hasPrivateHTMLFlavor) {
// If we have our private HTML flavor, we will only use the fragment
// from the CF_HTML. The rest comes from the clipboard.
nsAutoString contextString, infoString;
GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), aIndex, contextString);
GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), aIndex, infoString);
return DoInsertHTMLWithContext(cffragment,
contextString, infoString, type,
aSourceDoc,
aDestinationNode, aDestOffset,
aDoDeleteSelection,
isSafe);
}
else {
return DoInsertHTMLWithContext(cffragment,
cfcontext, cfselection, type,
aSourceDoc,
aDestinationNode, aDestOffset,
aDoDeleteSelection,
isSafe);
}
}
}
else if (type.EqualsLiteral(kHTMLMime)) {
@ -1321,13 +1347,9 @@ NS_IMETHODIMP nsHTMLEditor::Paste(int32_t aSelectionType)
nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
// find out if we have our internal html flavor on the clipboard. We don't want to mess
// around with cfhtml if we do.
bool bHavePrivateHTMLFlavor = HavePrivateHTMLFlavor(clipboard);
// Get the nsITransferable interface for getting the data from the clipboard
nsCOMPtr<nsITransferable> trans;
rv = PrepareHTMLTransferable(getter_AddRefs(trans), bHavePrivateHTMLFlavor);
rv = PrepareHTMLTransferable(getter_AddRefs(trans));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(trans, NS_ERROR_FAILURE);
// Get the Data from the clipboard
@ -1340,7 +1362,9 @@ NS_IMETHODIMP nsHTMLEditor::Paste(int32_t aSelectionType)
// also get additional html copy hints, if present
nsAutoString contextStr, infoStr;
// also get additional html copy hints, if present
// If we have our internal html flavor on the clipboard, there is special
// context to use instead of cfhtml context.
bool bHavePrivateHTMLFlavor = HavePrivateHTMLFlavor(clipboard);
if (bHavePrivateHTMLFlavor)
{
nsCOMPtr<nsISupports> contextDataObj, infoDataObj;
@ -1388,7 +1412,7 @@ NS_IMETHODIMP nsHTMLEditor::Paste(int32_t aSelectionType)
if (!nsEditorHookUtils::DoInsertionHook(domdoc, nullptr, trans))
return NS_OK;
return InsertFromTransferable(trans, nullptr, contextStr, infoStr,
return InsertFromTransferable(trans, nullptr, contextStr, infoStr, bHavePrivateHTMLFlavor,
nullptr, 0, true);
}
@ -1406,7 +1430,7 @@ NS_IMETHODIMP nsHTMLEditor::PasteTransferable(nsITransferable *aTransferable)
return NS_OK;
nsAutoString contextStr, infoStr;
return InsertFromTransferable(aTransferable, nullptr, contextStr, infoStr,
return InsertFromTransferable(aTransferable, nullptr, contextStr, infoStr, false,
nullptr, 0, true);
}
@ -1436,7 +1460,7 @@ NS_IMETHODIMP nsHTMLEditor::PasteNoFormatting(int32_t aSelectionType)
if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
{
const nsAFlatString& empty = EmptyString();
rv = InsertFromTransferable(trans, nullptr, empty, empty, nullptr, 0,
rv = InsertFromTransferable(trans, nullptr, empty, empty, false, nullptr, 0,
true);
}
}

View File

@ -552,11 +552,12 @@ protected:
// factored methods for handling insertion of data from transferables (drag&drop or clipboard)
NS_IMETHOD PrepareTransferable(nsITransferable **transferable) override;
nsresult PrepareHTMLTransferable(nsITransferable **transferable, bool havePrivFlavor);
nsresult PrepareHTMLTransferable(nsITransferable **transferable);
nsresult InsertFromTransferable(nsITransferable *transferable,
nsIDOMDocument *aSourceDoc,
const nsAString & aContextStr,
const nsAString & aInfoStr,
bool havePrivateHTMLFlavor,
nsIDOMNode *aDestinationNode,
int32_t aDestinationOffset,
bool aDoDeleteSelection);

View File

@ -26,7 +26,13 @@ function runTest() {
function verifyContent(s) {
var e = document.getElementById('i1');
var doc = e.contentDocument;
is(doc.body.innerHTML, s, "");
if (navigator.platform.indexOf("Win") >= 0) {
// On Windows ignore \n which got left over from the removal of the fragment tags
// <html><body>\n<!--StartFragment--> and <!--EndFragment-->\n</body>\n</html>.
is(doc.body.innerHTML.replace(/\n/g, ""), s, "");
} else {
is(doc.body.innerHTML, s, "");
}
}
function pasteInto(trans, html, target_id) {

View File

@ -79,6 +79,40 @@ nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void*
} // CreatePrimitiveForData
//
// CreatePrimitiveForCFHTML
//
// Platform specific CreatePrimitive, windows CF_HTML.
//
void
nsPrimitiveHelpers :: CreatePrimitiveForCFHTML ( const void* aDataBuff,
uint32_t* aDataLen, nsISupports** aPrimitive )
{
if (!aPrimitive)
return;
nsCOMPtr<nsISupportsString> primitive =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
if (!primitive)
return;
// We need to duplicate the input buffer, since the removal of linebreaks
// might reallocte it.
void* utf8 = moz_xmalloc(*aDataLen);
if (!utf8)
return;
memcpy(utf8, aDataBuff, *aDataLen);
int32_t signedLen = static_cast<int32_t>(*aDataLen);
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(kTextMime, &utf8, &signedLen);
*aDataLen = signedLen;
nsAutoString str(NS_ConvertUTF8toUTF16(reinterpret_cast<const char*>(utf8), *aDataLen));
free(utf8);
*aDataLen = str.Length() * sizeof(char16_t);
primitive->SetData(str);
NS_ADDREF(*aPrimitive = primitive);
}
//
// CreateDataFromPrimitive

View File

@ -23,6 +23,10 @@ public:
static void CreatePrimitiveForData ( const char* aFlavor, const void* aDataBuff,
uint32_t aDataLen, nsISupports** aPrimitive ) ;
// A specific case of CreatePrimitive for windows CF_HTML handling in DataTransfer
static void CreatePrimitiveForCFHTML ( const void* aDataBuff,
uint32_t* aDataLen, nsISupports** aPrimitive ) ;
// Given a nsISupports* primitive and the flavor it represents, creates a new data
// buffer with the data in it. This data will be null terminated, but the length
// parameter does not reflect that.

View File

@ -102,7 +102,8 @@ UINT nsClipboard::GetFormat(const char* aMimeStr)
else if (strcmp(aMimeStr, kFileMime) == 0 ||
strcmp(aMimeStr, kFilePromiseMime) == 0)
format = CF_HDROP;
else if (strcmp(aMimeStr, kNativeHTMLMime) == 0)
else if (strcmp(aMimeStr, kNativeHTMLMime) == 0 ||
strcmp(aMimeStr, kHTMLMime) == 0)
format = CF_HTML;
else
format = ::RegisterClipboardFormatW(NS_ConvertASCIItoUTF16(aMimeStr).get());
@ -624,11 +625,12 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
genericDataWrapper = do_QueryInterface(file);
free(data);
}
else if ( strcmp(flavorStr, kNativeHTMLMime) == 0) {
else if ( strcmp(flavorStr, kNativeHTMLMime) == 0 ) {
uint32_t dummy;
// the editor folks want CF_HTML exactly as it's on the clipboard, no conversions,
// no fancy stuff. Pull it off the clipboard, stuff it into a wrapper and hand
// it back to them.
if ( FindPlatformHTML(aDataObject, anIndex, &data, &dataLen) )
if ( FindPlatformHTML(aDataObject, anIndex, &data, &dummy, &dataLen) )
nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
else
{
@ -637,6 +639,23 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
}
free(data);
}
else if ( strcmp(flavorStr, kHTMLMime) == 0 ) {
uint32_t startOfData = 0;
// The JS folks want CF_HTML exactly as it is on the clipboard, but
// minus the CF_HTML header index information.
// It also needs to be converted to UTF16 and have linebreaks changed.
if ( FindPlatformHTML(aDataObject, anIndex, &data, &startOfData, &dataLen) ) {
dataLen -= startOfData;
nsPrimitiveHelpers::CreatePrimitiveForCFHTML ( static_cast<char*>(data) + startOfData,
&dataLen, getter_AddRefs(genericDataWrapper) );
}
else
{
free(data);
continue; // something wrong with this flavor, keep looking for other data
}
free(data);
}
else if ( strcmp(flavorStr, kJPEGImageMime) == 0 ||
strcmp(flavorStr, kJPGImageMime) == 0 ||
strcmp(flavorStr, kPNGImageMime) == 0) {
@ -678,7 +697,9 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
// Someone asked for the OS CF_HTML flavor. We give it back to them exactly as-is.
//
bool
nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen )
nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex,
void** outData, uint32_t* outStartOfData,
uint32_t* outDataLen )
{
// Reference: MSDN doc entitled "HTML Clipboard Format"
// http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx#unknown_854
@ -721,6 +742,10 @@ nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void*
// We want to return the buffer not offset by startOfData because it will be
// parsed out later (probably by nsHTMLEditor::ParseCFHTML) when it is still
// in CF_HTML format.
// We return the byte offset from the start of the data buffer to where the
// HTML data starts. The caller might want to extract the HTML only.
*outStartOfData = startOfData;
*outDataLen = endOfData;
return true;
}

View File

@ -63,7 +63,8 @@ protected:
static bool FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
static bool FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
static bool FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
static bool FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen );
static bool FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData,
uint32_t* outStartOfData, uint32_t* outDataLen );
static void ResolveShortcut ( nsIFile* inFileName, nsACString& outURL ) ;
nsIWidget * mWindow;

View File

@ -539,6 +539,14 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
if (mDataObject->QueryGetData(&fe) == S_OK)
*_retval = true; // found it!
}
else if (strcmp(aDataFlavor, kHTMLMime) == 0) {
// If the client wants html, maybe it's in "HTML Format".
format = nsClipboard::GetFormat(kHTMLMime);
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL);
if (mDataObject->QueryGetData(&fe) == S_OK)
*_retval = true; // found it!
}
} // else try again
}