Bug 888839 - Don't pretty print text/plain when copying and pasting non-(X)HTML documents. r=smaug, a=lsblakk
authorDrew Willcoxon <adw@mozilla.com>
Fri, 09 Aug 2013 17:57:59 -0700
changeset 153711 f8dceda8a125976d4b2d379d67a01346a96dfb3b
parent 153710 87d11537f679b5482fc64337cff5c6a377b35bc1
child 153712 4b9e3bd42389723c557dbc56f8489a6dcbdc53d3
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, lsblakk
bugs888839
milestone25.0a2
Bug 888839 - Don't pretty print text/plain when copying and pasting non-(X)HTML documents. r=smaug, a=lsblakk
content/base/src/nsCopySupport.cpp
content/base/test/Makefile.in
content/base/test/copypaste.js
content/base/test/test_copypaste.html
content/base/test/test_copypaste.xhtml
content/base/test/test_copypaste.xul
testing/mochitest/android.json
testing/mochitest/androidx86.json
testing/mochitest/b2g.json
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -111,20 +111,31 @@ SelectionCopyHelper(nsISelection *aSel, 
   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.
-  rv = docEncoder->GetMimeType(mimeType);
-  NS_ENSURE_SUCCESS(rv, rv);
   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 {
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -321,16 +321,18 @@ MOCHITEST_FILES_B = \
 		file_mozfiledataurl_doc.html \
 		file_mozfiledataurl_text.txt \
 		test_bug475156.html \
 		bug475156.sjs \
 		test_bug544642.html \
 		test_bug564863.xhtml \
 		test_bug588990.html \
 		test_copypaste.html \
+		test_copypaste.xhtml \
+		copypaste.js \
 		test_bug503481.html \
 		file_bug503481.sjs \
 		test_bug503481b.html \
 		file_bug503481b_inner.html \
 		test_viewport_scroll.html \
 		test_CSP.html \
 		file_CSP.sjs \
 		file_CSP.css \
@@ -646,16 +648,17 @@ MOCHITEST_FILES_B += \
 		test_messagemanager_assertpermission.html \
 		test_child_process_shutdown_message.html \
 		$(NULL)
 endif
 endif
 
 MOCHITEST_CHROME_FILES =	\
 		test_bug357450.js \
+		test_copypaste.xul \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 gtk3 windows,$(MOZ_WIDGET_TOOLKIT)))
 MOCHITEST_FILES_C += \
 		test_copyimage.html \
 		$(NULL)
 endif
new file mode 100644
--- /dev/null
+++ b/content/base/test/copypaste.js
@@ -0,0 +1,269 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function modifySelection(s) {
+  var g = window.getSelection();
+  var l = g.getRangeAt(0);
+  var d = document.createElement("p");
+  d.innerHTML = s;
+  d.appendChild(l.cloneContents());
+
+  var e = document.createElement("div");
+  document.body.appendChild(e);
+  e.appendChild(d);
+  var a = document.createRange();
+  a.selectNode(d);
+  g.removeAllRanges();
+  g.addRange(a);
+  window.setTimeout(function () {
+      e.parentNode.removeChild(e);
+      g.removeAllRanges();
+      g.addRange(l);
+  }, 0)
+}
+
+function getLoadContext() {
+  var Ci = SpecialPowers.wrap(Components).interfaces;
+  return SpecialPowers.wrap(window).QueryInterface(Ci.nsIInterfaceRequestor)
+                                   .getInterface(Ci.nsIWebNavigation)
+                                   .QueryInterface(Ci.nsILoadContext);
+}
+
+function testCopyPaste (isXHTML) {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  var suppressUnicodeCheckIfHidden = !!isXHTML;
+  var suppressHTMLCheck = !!isXHTML;
+
+  var webnav = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                     .getInterface(Components.interfaces.nsIWebNavigation)
+
+  var docShell = webnav.QueryInterface(Components.interfaces.nsIDocShell);
+
+  var documentViewer = docShell.contentViewer
+                               .QueryInterface(Components.interfaces.nsIContentViewerEdit);
+
+  var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
+                            .getService(Components.interfaces.nsIClipboard);
+
+  var textarea = SpecialPowers.wrap(document.getElementById('input'));
+
+  function copySelectionToClipboard(suppressUnicodeCheck) {
+    documentViewer.copySelection();
+    if (!suppressUnicodeCheck)
+      ok(clipboard.hasDataMatchingFlavors(["text/unicode"], 1,1), "check text/unicode");
+    if (!suppressHTMLCheck)
+      ok(clipboard.hasDataMatchingFlavors(["text/html"], 1,1), "check text/html");
+  }
+  function copyToClipboard(node, suppressUnicodeCheck) {
+    textarea.blur();
+    clipboard.emptyClipboard(1);
+    var sel = window.getSelection();
+    sel.removeAllRanges();
+    var r = document.createRange();
+    r.selectNode(node);
+    window.getSelection().addRange(r);
+    copySelectionToClipboard(suppressUnicodeCheck);
+  }
+  function copyRangeToClipboard(startNode,startIndex,endNode,endIndex,suppressUnicodeCheck) {
+    textarea.blur();
+    clipboard.emptyClipboard(1);
+    var sel = window.getSelection();
+    sel.removeAllRanges();
+    var r = document.createRange();
+    r.setStart(startNode,startIndex)
+    r.setEnd(endNode,endIndex)
+    window.getSelection().addRange(r);
+    copySelectionToClipboard(suppressUnicodeCheck);
+  }
+  function copyChildrenToClipboard(id) {
+    textarea.blur();
+    clipboard.emptyClipboard(1);
+    window.getSelection().selectAllChildren(document.getElementById(id));
+    copySelectionToClipboard();
+  }
+  function getClipboardData(mime) {
+    var transferable = Components.classes['@mozilla.org/widget/transferable;1']
+                                 .createInstance(Components.interfaces.nsITransferable);
+    transferable.init(getLoadContext());
+    transferable.addDataFlavor(mime);
+    clipboard.getData(transferable, 1);
+    var data = {};
+    transferable.getTransferData(mime, data, {}) ;
+    return data;
+  }
+  function testClipboardValue(mime, expected) {
+    if (suppressHTMLCheck && mime == "text/html")
+      return null;
+    var data = getClipboardData(mime);
+    is (data.value == null ? data.value :
+        data.value.QueryInterface(Components.interfaces.nsISupportsString).data,
+      expected,
+      mime + " value in the clipboard");
+    return data.value;
+  }
+  function testPasteText(expected) {
+    textarea.value="";
+    textarea.focus();
+    textarea.editor.paste(1);
+    is(textarea.value, expected, "value of the textarea after the paste");
+  }
+  function testSelectionToString(expected) {
+    is(window.getSelection().toString().replace(/\r\n/g,"\n"), expected, "Selection.toString");
+  }
+  function testInnerHTML(id, expected) {
+    var value = document.getElementById(id).innerHTML;
+    is(value, expected, id + ".innerHTML");
+  }
+  function testEmptyChildren(id) {
+    copyChildrenToClipboard(id);
+    testSelectionToString("");
+    testClipboardValue("text/unicode", null);
+    testClipboardValue("text/html", null);
+    testPasteText("");
+  }
+
+  copyChildrenToClipboard("draggable");
+  testSelectionToString("This is a draggable bit of text.");
+  testClipboardValue("text/unicode",
+                     "This is a draggable bit of text.");
+  testClipboardValue("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>");
+  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>");
+  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>");
+  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>");
+    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>");
+    testInnerHTML("div4", "\n  T<textarea>t t t</textarea>\n");
+  }
+  testPasteText(" Tt t t ");
+
+  copyChildrenToClipboard("div5");
+  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>");
+    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>");
+    testInnerHTML("div5", "\n  T<textarea>     </textarea>\n");
+  }
+  testPasteText(" T ");
+
+  copyRangeToClipboard($("div6").childNodes[0],0, $("div6").childNodes[1],1,suppressUnicodeCheckIfHidden);
+  testSelectionToString("");
+// START Disabled due to bug 564688
+if (false) {
+  testClipboardValue("text/unicode", "");
+  testClipboardValue("text/html", "");
+}
+// END Disabled due to bug 564688
+  testInnerHTML("div6", "div6");
+
+  copyRangeToClipboard($("div7").childNodes[0],0, $("div7").childNodes[0],4,suppressUnicodeCheckIfHidden);
+  testSelectionToString("");
+// START Disabled due to bug 564688
+if (false) {
+  testClipboardValue("text/unicode", "");
+  testClipboardValue("text/html", "");
+}
+// END Disabled due to bug 564688
+  testInnerHTML("div7", "div7");
+
+  copyRangeToClipboard($("div8").childNodes[0],0, $("div8").childNodes[0],4,suppressUnicodeCheckIfHidden);
+  testSelectionToString("");
+// START Disabled due to bug 564688
+if (false) {
+  testClipboardValue("text/unicode", "");
+  testClipboardValue("text/html", "");
+}
+// END Disabled due to bug 564688
+  testInnerHTML("div8", "div8");
+
+  copyRangeToClipboard($("div9").childNodes[0],0, $("div9").childNodes[0],4,suppressUnicodeCheckIfHidden);
+  testSelectionToString("div9");
+  testClipboardValue("text/unicode", "div9");
+  testClipboardValue("text/html", "div9");
+  testInnerHTML("div9", "div9");
+
+  copyToClipboard($("div10"), suppressUnicodeCheckIfHidden);
+  testSelectionToString("");
+  testInnerHTML("div10", "div10");
+
+  copyToClipboard($("div10").firstChild, suppressUnicodeCheckIfHidden);
+  testSelectionToString("");
+
+  copyRangeToClipboard($("div10").childNodes[0],0, $("div10").childNodes[0],1,suppressUnicodeCheckIfHidden);
+  testSelectionToString("");
+
+  copyRangeToClipboard($("div10").childNodes[1],0, $("div10").childNodes[1],1,suppressUnicodeCheckIfHidden);
+  testSelectionToString("");
+
+  // ============ copy/paste test from/to a textarea
+
+  var val = "1\n 2\n  3";
+  textarea.value=val;
+  textarea.select();
+  textarea.editor.copy();
+  
+  textarea.value="";
+  textarea.editor.paste(1);
+  is(textarea.value, val);
+  textarea.value="";
+
+  // ============ NOSCRIPT should not be copied
+
+  copyChildrenToClipboard("div13");
+  testSelectionToString("__");
+  testClipboardValue("text/unicode", "__");
+  testClipboardValue("text/html", "<div id=\"div13\">__</div>");
+  testPasteText("__");
+
+  // ============ converting cell boundaries to tabs in tables
+
+  copyToClipboard($("tr1"));
+  testClipboardValue("text/unicode", "foo\tbar");
+
+  // ============ 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>");
+  setTimeout(function(){testSelectionToString("div11")},0);
+
+  setTimeout(function(){
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    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>");
+    setTimeout(function(){ 
+      testSelectionToString("div12"); 
+      setTimeout(SimpleTest.finish,0);
+    },0);
+  },0);
+}
--- a/content/base/test/test_copypaste.html
+++ b/content/base/test/test_copypaste.html
@@ -1,276 +1,28 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 -->
 <head>
   <title>Test for copy/paste</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="copypaste.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=524975">Mozilla Bug </a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-function modifySelection(s) {
-  var g = window.getSelection();
-  var l = g.getRangeAt(0);
-  var d = document.createElement("p");
-  d.innerHTML = s;
-  d.appendChild(l.cloneContents());
-
-  var e = document.createElement("div");
-  document.body.appendChild(e);
-  e.appendChild(d);
-  var a = document.createRange();
-  a.selectNode(d);
-  g.removeAllRanges();
-  g.addRange(a);
-  window.setTimeout(function () {
-      e.parentNode.removeChild(e);
-      g.removeAllRanges();
-      g.addRange(l);
-  }, 0)
-}
-
-function getLoadContext() {
-  var Ci = SpecialPowers.wrap(Components).interfaces;
-  return SpecialPowers.wrap(window).QueryInterface(Ci.nsIInterfaceRequestor)
-                                   .getInterface(Ci.nsIWebNavigation)
-                                   .QueryInterface(Ci.nsILoadContext);
-}
-
-function testCopyPaste () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
-  var webnav = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                     .getInterface(Components.interfaces.nsIWebNavigation)
-
-  var docShell = webnav.QueryInterface(Components.interfaces.nsIDocShell);
-
-  var documentViewer = docShell.contentViewer
-                               .QueryInterface(Components.interfaces.nsIContentViewerEdit);
-
-  var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
-                            .getService(Components.interfaces.nsIClipboard);
-
-  var textarea = SpecialPowers.wrap(document.getElementById('input'));
-
-  function copySelectionToClipboard() {
-    documentViewer.copySelection();
-    ok(clipboard.hasDataMatchingFlavors(["text/unicode"], 1,1), "check text/unicode");
-    ok(clipboard.hasDataMatchingFlavors(["text/html"], 1,1), "check text/html");
-  }
-  function copyToClipboard(node) {
-    textarea.blur();
-    clipboard.emptyClipboard(1);
-    var sel = window.getSelection();
-    sel.removeAllRanges();
-    var r = document.createRange();
-    r.selectNode(node);
-    window.getSelection().addRange(r);
-    copySelectionToClipboard();
-  }
-  function copyRangeToClipboard(startNode,startIndex,endNode,endIndex) {
-    textarea.blur();
-    clipboard.emptyClipboard(1);
-    var sel = window.getSelection();
-    sel.removeAllRanges();
-    var r = document.createRange();
-    r.setStart(startNode,startIndex)
-    r.setEnd(endNode,endIndex)
-    window.getSelection().addRange(r);
-    copySelectionToClipboard();
-  }
-  function copyChildrenToClipboard(id) {
-    textarea.blur();
-    clipboard.emptyClipboard(1);
-    window.getSelection().selectAllChildren(document.getElementById(id));
-    copySelectionToClipboard();
-  }
-  function getClipboardData(mime) {
-    var transferable = Components.classes['@mozilla.org/widget/transferable;1']
-                                 .createInstance(Components.interfaces.nsITransferable);
-    transferable.init(getLoadContext());
-    transferable.addDataFlavor(mime);
-    clipboard.getData(transferable, 1);
-    var data = {};
-    transferable.getTransferData(mime, data, {}) ;
-    return data;
-  }
-  function testClipboardValue(mime, expected) {
-    var data = getClipboardData(mime);
-    is (data.value == null ? data.value :
-        data.value.QueryInterface(Components.interfaces.nsISupportsString).data,
-      expected,
-      mime + " value in the clipboard");
-    return data.value;
-  }
-  function testPasteText(expected) {
-    textarea.value="";
-    textarea.focus();
-    textarea.editor.paste(1);
-    is(textarea.value, expected, "value of the textarea after the paste");
-  }
-  function testSelectionToString(expected) {
-    is(window.getSelection().toString().replace(/\r\n/g,"\n"), expected, "Selection.toString");
-  }
-  function testInnerHTML(id, expected) {
-    var value = document.getElementById(id).innerHTML;
-    is(value, expected, id + ".innerHTML");
-  }
-  function testEmptyChildren(id) {
-    copyChildrenToClipboard(id);
-    testSelectionToString("");
-    testClipboardValue("text/unicode", null);
-    testClipboardValue("text/html", null);
-    testPasteText("");
-  }
-
-  copyChildrenToClipboard("draggable");
-  testSelectionToString("This is a draggable bit of text.");
-  testClipboardValue("text/unicode",
-                     "This is a draggable bit of text.");
-  testClipboardValue("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>");
-  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>");
-  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>");
-  testPasteText(" mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
-
-  copyChildrenToClipboard("div4");
-  testSelectionToString(" Tt t t ");
-  testClipboardValue("text/unicode", " Tt t t ");
-  testClipboardValue("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 ");
-
-  copyChildrenToClipboard("div5");
-  testSelectionToString(" T ");
-  testClipboardValue("text/unicode", " T ");
-  testClipboardValue("text/html", "<div id=\"div5\">\n  T<textarea>     </textarea>\n</div>");
-  testInnerHTML("div5", "\n  T<textarea>     </textarea>\n");
-  testPasteText(" T ");
-
-  copyRangeToClipboard($("div6").childNodes[0],0, $("div6").childNodes[1],1);
-  testSelectionToString("");
-// START Disabled due to bug 564688
-if (false) {
-  testClipboardValue("text/unicode", "");
-  testClipboardValue("text/html", "");
-}
-// END Disabled due to bug 564688
-  testInnerHTML("div6", "div6");
-
-  copyRangeToClipboard($("div7").childNodes[0],0, $("div7").childNodes[0],4);
-  testSelectionToString("");
-// START Disabled due to bug 564688
-if (false) {
-  testClipboardValue("text/unicode", "");
-  testClipboardValue("text/html", "");
-}
-// END Disabled due to bug 564688
-  testInnerHTML("div7", "div7");
-
-  copyRangeToClipboard($("div8").childNodes[0],0, $("div8").childNodes[0],4);
-  testSelectionToString("");
-// START Disabled due to bug 564688
-if (false) {
-  testClipboardValue("text/unicode", "");
-  testClipboardValue("text/html", "");
-}
-// END Disabled due to bug 564688
-  testInnerHTML("div8", "div8");
-
-  copyRangeToClipboard($("div9").childNodes[0],0, $("div9").childNodes[0],4);
-  testSelectionToString("div9");
-  testClipboardValue("text/unicode", "div9");
-  testClipboardValue("text/html", "div9");
-  testInnerHTML("div9", "div9");
-
-  copyToClipboard($("div10"));
-  testSelectionToString("");
-  testInnerHTML("div10", "div10");
-
-  copyToClipboard($("div10").firstChild);
-  testSelectionToString("");
-
-  copyRangeToClipboard($("div10").childNodes[0],0, $("div10").childNodes[0],1);
-  testSelectionToString("");
-
-  copyRangeToClipboard($("div10").childNodes[1],0, $("div10").childNodes[1],1);
-  testSelectionToString("");
-
-  // ============ copy/paste test from/to a textarea
-
-  var val = "1\n 2\n  3";
-  textarea.value=val;
-  textarea.select();
-  textarea.editor.copy();
-  
-  textarea.value="";
-  textarea.editor.paste(1);
-  is(textarea.value, val);
-  textarea.value="";
-
-  // ============ NOSCRIPT should not be copied
-
-  copyChildrenToClipboard("div13");
-  testSelectionToString("__");
-  testClipboardValue("text/unicode", "__");
-  testClipboardValue("text/html", "<div id=\"div13\">__</div>");
-  testPasteText("__");
-
-  // ============ converting cell boundaries to tabs in tables
-
-  copyToClipboard($("tr1"));
-  testClipboardValue("text/unicode", "foo\tbar");
-
-  // ============ 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>");
-  setTimeout(function(){testSelectionToString("div11")},0);
-
-  setTimeout(function(){
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    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>");
-    setTimeout(function(){ 
-      testSelectionToString("div12"); 
-      setTimeout(SimpleTest.finish,0);
-    },0);
-  },0);
-}
-
 
 SimpleTest.waitForExplicitFinish();
-
-addLoadEvent(testCopyPaste);
+addLoadEvent(function () testCopyPaste(false));
 
 </script>
 </pre>
 <div>
 
   <div id="draggable" title="title to have a long HTML line">This is a <em>draggable</em> bit of text.</div>
   <textarea id="input" cols="40" rows="10"></textarea>
 
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_copypaste.xhtml
@@ -0,0 +1,108 @@
+<?xml version="1.0"?>
+<!--
+This test is copied from test_copypaste.html, but it's XHTML instead of HTML.
+XHTML is encoded differently from HTML when copied; see bugs 888839 and 723163.
+This test is different from test_copypaste.html in two ways:
+
+  1. The text/html clipboard flavor isn't tested, since nsCopySupport doesn't
+     produce it for XHTML.
+  2. The text/unicode flavor isn't tested when the selection is in hidden
+     elements, since nsCopySupport doesn't produce text/plain for hidden
+     elements, and unlike HTML, neither does it produce text/_moz_htmlcontext
+     and text/_moz_htmlinfo, which the clipboard converts to text/unicode.
+-->
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test for copy/paste with XHTML</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="copypaste.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=888839">Mozilla Bug 888839</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+function modifySelectionDiv12() {
+  modifySelection("X<b style='display:none'>Y</b>");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function () testCopyPaste(true));
+
+]]>
+</script>
+</pre>
+<div>
+
+  <div id="draggable" title="title to have a long HTML line">This is a <em>draggable</em> bit of text.</div>
+  <textarea id="input" cols="40" rows="10"></textarea>
+
+  <div id="alist">
+    bla
+    <ul>
+      <li>foo</li>
+      <li style="display: none;">baz</li>
+      <li>bar</li>
+    </ul>
+  </div>
+
+  <div id="blist">
+    mozilla
+    <ol>
+      <li>foo</li>
+      <li style="display: none;">baz</li>
+      <li>bar</li>
+    </ol>
+  </div>
+
+  <div id="clist">
+    mzla
+    <ul>
+      <li>foo<ul>
+        <li>bazzinga!</li>
+      </ul></li>
+      <li style="display: none;">baz</li>
+      <li>bar</li>
+    </ul>
+  </div>
+
+<div id="div4">
+  T<textarea>t t t</textarea>
+</div>
+
+<div id="div5">
+  T<textarea>     </textarea>
+</div>
+
+<div id="div6" style="display:none"></div>
+<script>
+var x = $("div6")
+x.appendChild(document.createTextNode('di'))
+x.appendChild(document.createTextNode('v6'))
+</script>
+
+<div id="div7" style="display:none">div7</div>
+<div id="div8" style="visibility:hidden">div8</div>
+<div style="visibility:hidden"><div id="div9" style="visibility:visible">div9</div></div>
+<div style="visibility:hidden"><div><div><div id="div10"></div></div></div></div>
+<script>
+var x = $("div10")
+x.appendChild(document.createTextNode('div'))
+x.appendChild(document.createTextNode('10'))
+</script>
+
+<div id="div11" oncopy="modifySelection('X')"><span>div</span>11</div>
+<div id="div12" oncopy="modifySelectionDiv12()"><span>div</span>12</div>
+
+<div id="div13">_<noscript>FAIL</noscript>_</div>
+
+<table><tr id="tr1"><td>foo</td><td>bar</td></tr></table>
+
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_copypaste.xul
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=888839
+-->
+<window title="Mozilla Bug 888839"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <script type="application/javascript"><![CDATA[
+
+let { classes: Cc, interfaces: Ci } = Components;
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+function runTest() {
+  let desc = document.querySelector("description");
+  window.getSelection().selectAllChildren(desc);
+
+  let webnav = window.
+               QueryInterface(Ci.nsIInterfaceRequestor).
+               getInterface(Ci.nsIWebNavigation);
+
+  webnav.
+    QueryInterface(Ci.nsIDocShell).
+    contentViewer.
+    QueryInterface(Ci.nsIContentViewerEdit).
+    copySelection();
+
+  let mime = "text/unicode";
+  let whichClipboard = Ci.nsIClipboard.kGlobalClipboard;
+  let clipboard = Cc["@mozilla.org/widget/clipboard;1"].
+                  getService(Ci.nsIClipboard);
+  ok(clipboard.hasDataMatchingFlavors([mime], 1, whichClipboard),
+     "Clipboard should have text/unicode");
+
+  let transferable = Cc["@mozilla.org/widget/transferable;1"].
+                     createInstance(Ci.nsITransferable);
+  transferable.init(webnav.QueryInterface(Ci.nsILoadContext));
+  transferable.addDataFlavor(mime);
+  clipboard.getData(transferable, whichClipboard);
+  var data = {};
+  transferable.getTransferData(mime, data, {});
+  is(data.value.QueryInterface(Ci.nsISupportsString).data,
+     "\n    hello\n    world\n  ",
+     "Paste is not HTML, so it should not be pretty printed");
+
+  SimpleTest.finish();
+}
+
+  ]]></script>
+
+  <description style="-moz-user-focus: normal; -moz-user-select: text;"><![CDATA[
+    hello
+    world
+  ]]></description>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=888839"
+     target="_blank">Mozilla Bug 888839</a>
+  </body>
+</window>
--- a/testing/mochitest/android.json
+++ b/testing/mochitest/android.json
@@ -6,16 +6,18 @@
  "content/base/test/test_bug466080.html": "",
  "content/base/test/test_bug475156.html": "bug 855762",
  "content/base/test/test_bug482935.html": "bug 855762",
  "content/base/test/test_bug503481.html": "TIMED_OUT",
  "content/base/test/test_bug503481b.html": "TIMED_OUT",
  "content/base/test/test_bug505783.html": "TIMED_OUT",
  "content/base/test/test_bug590812.html": "bug 687032",
  "content/base/test/test_copypaste.html": "",
+ "content/base/test/test_copypaste.xhtml": "",
+ "content/base/test/test_copypaste.xul": "",
  "content/base/test/test_CrossSiteXHR.html": "",
  "content/base/test/test_CrossSiteXHR_cache.html": "",
  "content/base/test/test_CrossSiteXHR_origin.html": "",
  "content/base/test/test_CSP.html": "TIMED_OUT",
  "content/base/test/test_CSP_frameancestors.html": "",
  "content/base/test/test_CSP_inlinescript.html": "",
  "content/base/test/test_csp_redirects.html": "TIMED_OUT",
  "content/base/test/test_fileapi_slice.html": "bug 775227",
--- a/testing/mochitest/androidx86.json
+++ b/testing/mochitest/androidx86.json
@@ -10,16 +10,18 @@
  "content/base/test/test_CrossSiteXHR_origin.html": "",
  "content/base/test/test_bug166235.html": "",
  "content/base/test/test_bug338583.html": "",
  "content/base/test/test_bug466080.html": "",
  "content/base/test/test_bug503481.html": "TIMED_OUT",
  "content/base/test/test_bug503481b.html": "TIMED_OUT",
  "content/base/test/test_bug505783.html": "TIMED_OUT",
  "content/base/test/test_copypaste.html": "",
+ "content/base/test/test_copypaste.xhtml": "",
+ "content/base/test/test_copypaste.xul": "",
  "content/base/test/test_csp_redirects.html": "TIMED_OUT",
  "content/base/test/test_fileapi_slice.html": "bug 775227",
  "content/base/test/test_mozfiledataurl.html": "TIMED_OUT",
  "content/base/test/test_mixed_content_blocker.html": "TIMED_OUT, SSL_REQUIRED",
  "content/base/test/test_mixed_content_blocker_bug803225.html": "TIMED_OUT, SSL_REQUIRED",
  "content/base/test/test_mixed_content_blocker_frameNavigation.html": "TIMED_OUT, SSL_REQUIRED",
  "content/base/test/test_mutationobservers.html": "",
  "content/base/test/test_plugin_freezing.html": "CLICK_TO_PLAY",
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -151,16 +151,18 @@
     "content/base/test/test_bug498433.html":"",
     "content/base/test/test_bug650386_redirect_301.html":"",
     "content/base/test/test_bug650386_redirect_302.html":"",
     "content/base/test/test_bug650386_redirect_303.html":"",
     "content/base/test/test_bug650386_redirect_307.html":"",
     "content/base/test/test_bug717511.html":"",
     "content/base/test/test_child_process_shutdown_message.html":"",
     "content/base/test/test_copypaste.html":"",
+    "content/base/test/test_copypaste.xhtml":"",
+    "content/base/test/test_copypaste.xul":"",
     "content/base/test/test_csp_redirects.html":"",
     "content/base/test/test_fileapi_slice.html":"",
     "content/base/test/test_messagemanager_assertpermission.html":"",
     "content/base/test/test_mixed_content_blocker.html":"",
     "content/base/test/test_mixed_content_blocker_bug803225.html":"",
     "content/base/test/test_mixed_content_blocker_frameNavigation.html":"",
     "content/base/test/test_mozfiledataurl.html":"",
     "content/base/test/test_websocket.html":"",