Make it possible to drag a non-selectable node again. b=574596 r=dbaron
authorMats Palmgren <matspal@gmail.com>
Mon, 12 Jul 2010 22:24:25 +0200
changeset 47336 7ca493708001d5181f579a7f9017d581cba84f55
parent 47335 55288e32372b2bef2954bda093fd7c5096096f50
child 47337 7133f717ed2ac649259ed3cc0fce53821d8a924e
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs574596
milestone2.0b2pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Make it possible to drag a non-selectable node again. b=574596 r=dbaron
content/base/public/nsCopySupport.h
content/base/src/nsContentAreaDragDrop.cpp
content/base/src/nsCopySupport.cpp
content/base/test/Makefile.in
content/base/test/test_bug574596.html
--- a/content/base/public/nsCopySupport.h
+++ b/content/base/public/nsCopySupport.h
@@ -34,25 +34,25 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsCopySupport_h__
 #define nsCopySupport_h__
 
 #include "nscore.h"
+#include "nsINode.h"
 
 class nsISelection;
 class nsIDocument;
 class nsIImageLoadingContent;
 class nsIContent;
 class nsITransferable;
 class nsACString;
 class nsAString;
-class nsIDOMNode;
 class nsIPresShell;
 
 class nsCopySupport
 {
   // class of static helper functions for copy support
   public:
     static nsresult HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16 aClipboardID);
     static nsresult DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
@@ -64,20 +64,24 @@ class nsCopySupport
     // doc.
     static nsresult GetContents(const nsACString& aMimeType, PRUint32 aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata);
     
     static nsresult ImageCopy(nsIImageLoadingContent* aImageElement,
                               PRInt32 aCopyFlags);
 
     // Get the selection as a transferable. Similar to HTMLCopy except does
     // not deal with the clipboard.
-    static nsresult GetTransferableForSelection(nsISelection * aSelection,
-                                                nsIDocument * aDocument,
-                                                nsITransferable ** aTransferable);
+    static nsresult GetTransferableForSelection(nsISelection* aSelection,
+                                                nsIDocument* aDocument,
+                                                nsITransferable** aTransferable);
 
+    // Same as GetTransferableForSelection, but doesn't skip invisible content.
+    static nsresult GetTransferableForNode(nsINode* aNode,
+                                           nsIDocument* aDoc,
+                                           nsITransferable** aTransferable);
     /**
      * Retrieve the selection for the given document. If the current focus
      * within the document has its own selection, aSelection will be set to it
      * and this focused content node returned. Otherwise, aSelection will be
      * set to the document's selection and null will be returned.
      */
     static nsIContent* GetSelectionForCopy(nsIDocument* aDocument,
                                            nsISelection** aSelection);
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -74,64 +74,51 @@
 #include "nsIContent.h"
 #include "nsIImageLoadingContent.h"
 #include "nsUnicharUtils.h"
 #include "nsIURL.h"
 #include "nsIDocument.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsIDocShellTreeItem.h"
-#include "nsRange.h"
 #include "nsIWebBrowserPersist.h"
 #include "nsEscape.h"
 #include "nsContentUtils.h"
 #include "nsIMIMEService.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsDOMDataTransfer.h"
 
 // private clipboard data flavors for html copy, used by editor when pasting
 #define kHTMLContext   "text/_moz_htmlcontext"
 #define kHTMLInfo      "text/_moz_htmlinfo"
 
-nsresult NS_NewDomSelection(nsISelection **aDomSelection);
-
-// if inNode is null, use the selection from the window
+// if aNode is null, use the selection from the window
 static nsresult
 GetTransferableForNodeOrSelection(nsIDOMWindow*     aWindow,
                                   nsIContent*       aNode,
                                   nsITransferable** aTransferable)
 {
   NS_ENSURE_ARG_POINTER(aWindow);
 
   nsCOMPtr<nsIDOMDocument> domDoc;
   aWindow->GetDocument(getter_AddRefs(domDoc));
   NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
 
   nsresult rv;
-  nsCOMPtr<nsISelection> selection;
-  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
-  if (node) {
-    // Make a temporary selection with this node in a single range.
-    rv = NS_NewDomSelection(getter_AddRefs(selection));
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsCOMPtr<nsIDOMRange> range;
-    rv = NS_NewRange(getter_AddRefs(range));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = range->SelectNode(node);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = selection->AddRange(range);
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (aNode) {
+    rv = nsCopySupport::GetTransferableForNode(aNode, doc, aTransferable);
   } else {
+    nsCOMPtr<nsISelection> selection;
     aWindow->GetSelection(getter_AddRefs(selection));
+    rv = nsCopySupport::GetTransferableForSelection(selection, doc,
+                                                    aTransferable);
   }
 
-  rv = nsCopySupport::GetTransferableForSelection(selection, doc,
-                                                  aTransferable);
   NS_ENSURE_SUCCESS(rv, rv);
   return rv;
 }
 
 class NS_STACK_CLASS DragDataProducer
 {
 public:
   DragDataProducer(nsIDOMWindow* aWindow,
@@ -419,17 +406,16 @@ DragDataProducer::GetNodeString(nsIConte
     docRange->CreateRange(getter_AddRefs(range));
     if (range) {
       range->SelectNode(node);
       range->ToString(outNodeString);
     }
   }
 }
 
-
 nsresult
 DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
                           PRBool* aCanDrag,
                           PRBool* aDragSelection,
                           nsIContent** aDragNode)
 {
   NS_PRECONDITION(aCanDrag && aDragSelection && aDataTransfer && aDragNode,
                   "null pointer passed to Produce");
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -45,16 +45,17 @@
 #include "nsIComponentManager.h" 
 #include "nsIServiceManager.h"
 #include "nsIClipboard.h"
 #include "nsISelection.h"
 #include "nsWidgetsCID.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMRange.h"
+#include "nsRange.h"
 #include "imgIContainer.h"
 #include "nsIPresShell.h"
 #include "nsFocusManager.h"
 #include "nsEventDispatcher.h"
 
 #include "nsIDocShell.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIClipboardDragDropHooks.h"
@@ -73,16 +74,18 @@
 #include "nsIFrame.h"
 
 // image copy stuff
 #include "nsIImageLoadingContent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsContentUtils.h"
 #include "nsContentCID.h"
 
+nsresult NS_NewDomSelection(nsISelection **aDomSelection);
+
 static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
 static NS_DEFINE_CID(kCTransferableCID,        NS_TRANSFERABLE_CID);
 static NS_DEFINE_CID(kHTMLConverterCID,        NS_HTMLFORMATCONVERTER_CID);
 
 // private clipboard data flavors for html copy, used by editor when pasting
 #define kHTMLContext   "text/_moz_htmlcontext"
 #define kHTMLInfo      "text/_moz_htmlinfo"
 
@@ -95,17 +98,17 @@ static nsresult AppendString(nsITransfer
 static nsresult AppendDOMNode(nsITransferable *aTransferable,
                               nsIDOMNode *aDOMNode);
 
 // Helper used for HTMLCopy and GetTransferableForSelection since both routines
 // share common code.
 static nsresult
 SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
                     PRBool doPutOnClipboard, PRInt16 aClipboardID,
-                    nsITransferable ** aTransferable)
+                    PRUint32 aFlags, nsITransferable ** aTransferable)
 {
   // Clear the output parameter for the transferable, if provided.
   if (aTransferable) {
     *aTransferable = nsnull;
   }
 
   nsresult rv = NS_OK;
   
@@ -130,19 +133,18 @@ SelectionCopyHelper(nsISelection *aSel, 
   // 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
   mimeType.AssignLiteral(kUnicodeMime);
   
   // we want preformatted for the case where the selection is inside input/textarea
   // and we don't want pretty printing for others cases, to not have additionnal
   // line breaks which are then converted into spaces by the htmlConverter (see bug #524975)
-  PRUint32 flags = nsIDocumentEncoder::OutputPreformatted
-                   | nsIDocumentEncoder::OutputRaw
-                   | nsIDocumentEncoder::SkipInvisibleContent;
+  PRUint32 flags = aFlags | nsIDocumentEncoder::OutputPreformatted
+                          | nsIDocumentEncoder::OutputRaw;
 
   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
   NS_ASSERTION(domDoc, "Need a document");
 
   rv = docEncoder->Init(domDoc, mimeType, flags);
   if (NS_FAILED(rv)) 
     return rv;
 
@@ -173,17 +175,17 @@ SelectionCopyHelper(nsISelection *aSel, 
     PRUint32 ConvertedLen;
     rv = htmlConverter->Convert(kHTMLMime, plainHTML, textBuffer.Length() * 2, kUnicodeMime, getter_AddRefs(ConvertedData), &ConvertedLen);
     NS_ENSURE_SUCCESS(rv, rv);
 
     ConvertedData->GetData(plaintextBuffer);
 
     mimeType.AssignLiteral(kHTMLMime);
 
-    flags = nsIDocumentEncoder::SkipInvisibleContent;
+    flags = aFlags;
 
     rv = docEncoder->Init(domDoc, mimeType, flags);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = docEncoder->SetSelection(aSel);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // encode the selection as html with contextual info
@@ -274,27 +276,57 @@ SelectionCopyHelper(nsISelection *aSel, 
       if (aTransferable != nsnull) {
         trans.swap(*aTransferable);
       }
     }
   }
   return rv;
 }
 
-nsresult nsCopySupport::HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16 aClipboardID)
+nsresult
+nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc,
+                        PRInt16 aClipboardID)
 {
-  return SelectionCopyHelper(aSel, aDoc, PR_TRUE, aClipboardID, nsnull);
+  return SelectionCopyHelper(aSel, aDoc, PR_TRUE, aClipboardID,
+                             nsIDocumentEncoder::SkipInvisibleContent,
+                             nsnull);
+}
+
+nsresult
+nsCopySupport::GetTransferableForSelection(nsISelection* aSel,
+                                           nsIDocument* aDoc,
+                                           nsITransferable** aTransferable)
+{
+  return SelectionCopyHelper(aSel, aDoc, PR_FALSE, 0,
+                             nsIDocumentEncoder::SkipInvisibleContent,
+                             aTransferable);
 }
 
 nsresult
-nsCopySupport::GetTransferableForSelection(nsISelection * aSel,
-                                           nsIDocument * aDoc,
-                                           nsITransferable ** aTransferable)
+nsCopySupport::GetTransferableForNode(nsINode* aNode,
+                                      nsIDocument* aDoc,
+                                      nsITransferable** aTransferable)
 {
-  return SelectionCopyHelper(aSel, aDoc, PR_FALSE, 0, aTransferable);
+  nsCOMPtr<nsISelection> selection;
+  // Make a temporary selection with aNode in a single range.
+  nsresult rv = NS_NewDomSelection(getter_AddRefs(selection));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIDOMRange> range;
+  rv = NS_NewRange(getter_AddRefs(range));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
+  NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
+  rv = range->SelectNode(node);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = selection->AddRange(range);
+  NS_ENSURE_SUCCESS(rv, rv);
+  // It's not the primary selection - so don't skip invisible content.
+  PRUint32 flags = 0;
+  return SelectionCopyHelper(selection, aDoc, PR_FALSE, 0, flags,
+                             aTransferable);
 }
 
 nsresult nsCopySupport::DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
                                 PRBool *aDoPutOnClipboard)
 {
   NS_ENSURE_ARG(aDoc);
 
   *aDoPutOnClipboard = PR_TRUE;
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -397,16 +397,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug300992.html \
 		test_websocket_hello.html \
 		file_websocket_hello_wsh.py \
 		test_ws_basic_tests.html \
 		file_ws_basic_tests_wsh.py \
 		test_websocket.html \
 		file_websocket_wsh.py \
 		file_websocket_http_resource.txt \
+		test_bug574596.html \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
 _TEST_FILES2 += 	test_copyimage.html \
 		$(NULL)
 endif
 
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug574596.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=574596
+-->
+<head>
+  <title>Test for Bug 574596</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"  src="/tests/SimpleTest/EventUtils.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=574596">Mozilla Bug 574596</a>
+<style type="text/css">
+#link1 a { -moz-user-select:none; }
+</style>
+<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
+<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 574596 **/
+
+function ignoreFunc(actualData, expectedData) {
+  return true;
+}
+
+var dragLinkText = [[
+  { type:"text/x-moz-url",          data:"", eqTest:ignoreFunc },
+  { type:"text/x-moz-url-data",     data:"http://www.mozilla.org/" },
+  { type:"text/x-moz-url-desc",     data:"link1" },
+  { type:"text/uri-list",           data:"http://www.mozilla.org/" },
+  { type:"text/_moz_htmlcontext",   data:"", eqTest:ignoreFunc },
+  { type:"text/_moz_htmlinfo",      data:"", eqTest:ignoreFunc },
+  { type:"text/html",               data:'<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>' },
+  { type:"text/plain",              data:"http://www.mozilla.org/" }
+]];
+
+
+function dumpTransfer(dataTransfer,expect) {
+  dtData = dataTransfer.mozItemCount + "items:\n";
+  for (var i = 0; i < dataTransfer.mozItemCount; i++) {
+    var dtTypes = dataTransfer.mozTypesAt(i);
+    for (var j = 0; j < dtTypes.length; j++) {
+      var actualData = dataTransfer.mozGetDataAt(dtTypes[j],i)
+      if (expect && expect[i] && expect[i][j]) {
+        if (expect[i][j].eqTest)
+          dtData += expect[i][j].eqTest(actualData,expect[i][j].data) ? "ok" : "fail";
+        else
+          dtData += (actualData == expect[i][j].data) ? "ok" : "fail";
+      }
+      dtData += "["+i+"]" + "["+j+"]: " + '"' + dtTypes[j] + '"  "' + actualData + '"\n';
+    }
+  }
+  alert(dtData);
+}
+
+function runTest() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  var result = synthesizeDragStart($('link1'), dragLinkText, window);
+  is(result, null, "Drag -moz-user-select:none link (#link1)");
+  // if (result) dumpTransfer(result,dragLinkText);
+
+  dragLinkText[0][2].data = "link2";
+  dragLinkText[0][6].data = '<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>'
+  var result = synthesizeDragStart($('link2'), dragLinkText, window);
+  is(result, null, "Drag link (#link2)");
+  // if (result) dumpTransfer(result,dragLinkText);
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTest);
+
+
+</script>
+</pre>
+</body>
+</html>