Bug 674770 part.1 Shouldn't accept click event if the event target isn't in focused editor r=ehsan
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 26 Nov 2011 13:51:48 +0900
changeset 82441 dad793c1b1437c83315fda28289228767a0a7a92
parent 82440 5c6903c68234a2a290861eaa9cf921989281d2bf
child 82442 1a9cc49f9cf1276defa2726c8849d1d83c1780d5
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs674770
milestone11.0a1
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
Bug 674770 part.1 Shouldn't accept click event if the event target isn't in focused editor r=ehsan
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditorEventListener.cpp
editor/libeditor/html/nsHTMLEditor.cpp
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -5382,22 +5382,39 @@ nsEditor::IsActiveInDOMWindow()
 
 bool
 nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
 {
   // If the event is trusted, the event should always cause input.
   nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aEvent);
   NS_ENSURE_TRUE(NSEvent, false);
 
+  // If this is mouse event but this editor doesn't have focus, we shouldn't
+  // handle it.
+  nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
+  if (mouseEvent) {
+    nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
+    if (!focusedContent) {
+      return false;
+    }
+  }
+
   bool isTrusted;
   nsresult rv = NSEvent->GetIsTrusted(&isTrusted);
   NS_ENSURE_SUCCESS(rv, false);
   if (isTrusted) {
     return true;
   }
+
+  // Ignore untrusted mouse event.
+  // XXX Why are we handling other untrusted input events?
+  if (mouseEvent) {
+    return false;
+  }
+
   // Otherwise, we shouldn't handle any input events when we're not an active
   // element of the DOM window.
   return IsActiveInDOMWindow();
 }
 
 NS_IMETHODIMP
 nsEditor::GetLastKeypressEventTrusted(bool *aWasTrusted)
 {
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -174,16 +174,21 @@ nsEditorEventListener::InstallToEditor()
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("dragexit"),
                                NS_EVENT_FLAG_BUBBLE |
                                NS_EVENT_FLAG_SYSTEM_EVENT);
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("drop"),
                                NS_EVENT_FLAG_BUBBLE |
                                NS_EVENT_FLAG_SYSTEM_EVENT);
+  // XXX We should add the mouse event listeners as system event group.
+  //     E.g., web applications cannot prevent middle mouse paste by
+  //     preventDefault() of click event at bubble phase.
+  //     However, if we do so, all click handlers in any frames and frontend
+  //     code need to check if it's editable.  It makes easier create new bugs.
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("mousedown"),
                                NS_EVENT_FLAG_CAPTURE);
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("mouseup"),
                                NS_EVENT_FLAG_CAPTURE);
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("click"),
@@ -509,24 +514,26 @@ nsEditorEventListener::KeyPress(nsIDOMEv
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
 
   nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
-  nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aMouseEvent);
-  bool isTrusted = false;
-  if (!mouseEvent || !nsevent ||
-      NS_FAILED(nsevent->GetIsTrusted(&isTrusted)) || !isTrusted) {
-    // Non-ui or non-trusted event passed in. Bad things.
+  NS_ENSURE_TRUE(mouseEvent, NS_OK);
+
+  // nothing to do if editor isn't editable or clicked on out of the editor.
+  if (mEditor->IsReadonly() || mEditor->IsDisabled() ||
+      !mEditor->IsAcceptableInputEvent(aMouseEvent)) {
     return NS_OK;
   }
 
+  nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aMouseEvent);
+  NS_ASSERTION(nsevent, "nsevent must not be NULL here");
   bool preventDefault;
   nsresult rv = nsevent->GetPreventDefault(&preventDefault);
   if (NS_FAILED(rv) || preventDefault) {
     // We're done if 'preventdefault' is true (see for example bug 70698).
     return rv;
   }
 
   // If we got a mouse down inside the editing area, we should force the 
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -5985,20 +5985,55 @@ nsHTMLEditor::IsAcceptableInputEvent(nsI
       return targetDocument == document;
     }
     // Otherwise, check whether the event target is in this document or not.
     nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
     NS_ENSURE_TRUE(targetContent, false);
     return document == targetContent->GetCurrentDoc();
   }
 
-  // If this is for contenteditable, we should check whether the target is
-  // editable or not.
+  // This HTML editor is for contenteditable.  We need to check the validity of
+  // the target.
   nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
   NS_ENSURE_TRUE(targetContent, false);
+
+  // If the event is a mouse event, we need to check if the target content is
+  // the focused editing host or its descendant.
+  nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
+  if (mouseEvent) {
+    nsIContent* editingHost = GetActiveEditingHost();
+    // If there is no active editing host, we cannot handle the mouse event
+    // correctly.
+    if (!editingHost) {
+      return false;
+    }
+    // If clicked on non-editable root element but the body element is the
+    // active editing host, we should assume that the click event is targetted.
+    if (targetContent == document->GetRootElement() &&
+        !targetContent->HasFlag(NODE_IS_EDITABLE) &&
+        editingHost == document->GetBodyElement()) {
+      targetContent = editingHost;
+    }
+    // If the target element is neither the active editing host nor a descendant
+    // of it, we may not be able to handle the event.
+    if (!nsContentUtils::ContentIsDescendantOf(targetContent, editingHost)) {
+      return false;
+    }
+    // If the clicked element has an independent selection, we shouldn't
+    // handle this click event.
+    if (targetContent->HasIndependentSelection()) {
+      return false;
+    }
+    // If the target content is editable, we should handle this event.
+    return targetContent->HasFlag(NODE_IS_EDITABLE);
+  }
+
+  // If the target of the other events which target focused element isn't
+  // editable or has an independent selection, this editor shouldn't handle the
+  // event.
   if (!targetContent->HasFlag(NODE_IS_EDITABLE) ||
       targetContent->HasIndependentSelection()) {
     return false;
   }
 
   // Finally, check whether we're actually focused or not.  When we're not
   // focused, we should ignore the dispatched event by script (or something)
   // because content editable element needs selection in itself for editing.