Bug 1344149 EditorEventListener shouldn't handle odd focus/blur events which may be created in chrome script r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 08 Mar 2017 15:24:55 +0900
changeset 495058 52688e66b162c7d362a3430b743779bf6edac61b
parent 495057 ec83771acae40101fefceef3026caeffb1077122
child 495064 837d117a3b248dc12da73f52acd5d72b62aa73ca
child 495220 e32e38382c0c905cd7729e7fae4587c41650ebc2
push id48212
push usermasayuki@d-toybox.com
push dateWed, 08 Mar 2017 06:28:56 +0000
reviewerssmaug
bugs1344149
milestone55.0a1
Bug 1344149 EditorEventListener shouldn't handle odd focus/blur events which may be created in chrome script r?smaug EditorEventListener listens any trusted focus/blur events which may be synthesized by JS without proper event class. Then, editor will setup selection limitation. This may cause odd behavior. Therefore, EditorEventListener should stop handling focus/blur events which do not come from nsFocusManager. MozReview-Commit-ID: 7SlfIRgArkr
dom/tests/mochitest/chrome/window_focus.xul
editor/libeditor/EditorEventListener.cpp
editor/libeditor/EditorEventListener.h
--- a/dom/tests/mochitest/chrome/window_focus.xul
+++ b/dom/tests/mochitest/chrome/window_focus.xul
@@ -1339,19 +1339,18 @@ function switchWindowTest(otherWindow, f
   fm.activeWindow = topWindow;
   fm.activeWindow = otherWindow;
   is(otherTextbox.selectionStart, 2, "selectionStart after textbox focus and window raise");
   is(otherTextbox.selectionEnd, 3, "selectionEnd after textbox focus and window raise");
   is(fm.getLastFocusMethod(null), fm.FLAG_BYMOVEFOCUS, "last focus method after textbox focus and window raise");
 
   fm.clearFocus(otherWindow);
 
-  // test to ensure that a synthetic event works
-  var synevent = document.createEvent("Event");
-  synevent.initEvent("focus", false, false);
+  // test to ensure that a synthetic event won't move focus
+  var synevent = new FocusEvent("focus", {});
   otherTextbox.inputField.dispatchEvent(synevent);
   is(synevent.type, "focus", "event.type after synthetic focus event");
   is(synevent.target, otherTextbox, "event.target after synthetic focus event");
   is(fm.focusedElement, null, "focusedElement after synthetic focus event");
   is(otherWindow.document.activeElement, otherWindow.document.documentElement,
      "document.activeElement after synthetic focus event");
 
   // check accessing a focus event after the event has finishing firing
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=4 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EditorEventListener.h"
 
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc.
+#include "mozilla/ContentEvents.h"      // for InternalFocusEvent
 #include "mozilla/EditorBase.h"         // for EditorBase, etc.
 #include "mozilla/EventListenerManager.h" // for EventListenerManager
 #include "mozilla/IMEStateManager.h"    // for IMEStateManager
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/TextEvents.h"         // for WidgetCompositionEvent
 #include "mozilla/dom/Element.h"        // for Element
 #include "mozilla/dom/Event.h"          // for Event
 #include "mozilla/dom/EventTarget.h"    // for EventTarget
@@ -183,18 +184,21 @@ EditorEventListener::InstallToEditor()
                                NS_LITERAL_STRING("mousedown"),
                                TrustedEventsAtCapture());
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("mouseup"),
                                TrustedEventsAtCapture());
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("click"),
                                TrustedEventsAtCapture());
-// Focus event doesn't bubble so adding the listener to capturing phase.
-// Make sure this works after bug 235441 gets fixed.
+  // Focus event doesn't bubble so adding the listener to capturing phase.
+  // XXX Should we listen focus/blur events of system group too? Or should
+  //     editor notified focus/blur of the element from nsFocusManager
+  //     directly?  Because if the event propagation is stopped by JS,
+  //     editor cannot initialize selection as expected.
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("blur"),
                                TrustedEventsAtCapture());
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("focus"),
                                TrustedEventsAtCapture());
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("text"),
@@ -461,45 +465,37 @@ EditorEventListener::HandleEvent(nsIDOME
         mMouseDownOrUpConsumedByIME = false;
         mouseEvent->AsEvent()->PreventDefault();
         return NS_OK;
       }
       return MouseClick(mouseEvent);
     }
     // focus
     case eFocus:
-      return Focus(internalEvent);
+      return Focus(internalEvent->AsFocusEvent());
     // blur
     case eBlur:
-      return Blur(internalEvent);
+      return Blur(internalEvent->AsFocusEvent());
     // text
     case eCompositionChange:
       return HandleChangeComposition(internalEvent->AsCompositionEvent());
     // compositionstart
     case eCompositionStart:
       return HandleStartComposition(internalEvent->AsCompositionEvent());
     // compositionend
     case eCompositionEnd:
       HandleEndComposition(internalEvent->AsCompositionEvent());
       return NS_OK;
     default:
       break;
   }
 
+#ifdef DEBUG
   nsAutoString eventType;
   aEvent->GetType(eventType);
-  // We should accept "focus" and "blur" event even if it's synthesized with
-  // wrong interface for compatibility with older Gecko.
-  if (eventType.EqualsLiteral("focus")) {
-    return Focus(internalEvent);
-  }
-  if (eventType.EqualsLiteral("blur")) {
-    return Blur(internalEvent);
-  }
-#ifdef DEBUG
   nsPrintfCString assertMessage("Editor doesn't handle \"%s\" event "
     "because its internal event doesn't have proper message",
     NS_ConvertUTF16toUTF8(eventType).get());
   NS_ASSERTION(false, assertMessage.get());
 #endif
 
   return NS_OK;
 }
@@ -1073,28 +1069,22 @@ EditorEventListener::HandleEndCompositio
     return;
   }
   MOZ_ASSERT(!aCompositionEndEvent->DefaultPrevented(),
              "eCompositionEnd shouldn't be cancelable");
   editorBase->EndIMEComposition();
 }
 
 nsresult
-EditorEventListener::Focus(WidgetEvent* aFocusEvent)
+EditorEventListener::Focus(InternalFocusEvent* aFocusEvent)
 {
   if (NS_WARN_IF(!aFocusEvent) || DetachedFromEditor()) {
     return NS_OK;
   }
 
-  // XXX If aFocusEvent was created by chrome script, its defaultPrevented
-  //     may be true, though.  We shouldn't handle such event but we don't
-  //     have a way to distinguish if coming event is created by chrome script.
-  NS_WARNING_ASSERTION(!aFocusEvent->DefaultPrevented(),
-                       "eFocus event shouldn't be cancelable");
-
   // Don't turn on selection and caret when the editor is disabled.
   RefPtr<EditorBase> editorBase(mEditorBase);
   if (editorBase->IsDisabled()) {
     return NS_OK;
   }
 
   // Spell check a textarea the first time that it is focused.
   SpellCheckIfNeeded();
@@ -1162,28 +1152,22 @@ EditorEventListener::Focus(WidgetEvent* 
   nsCOMPtr<nsIContent> focusedContent = editorBase->GetFocusedContentForIME();
   IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent,
                                    editorBase);
 
   return NS_OK;
 }
 
 nsresult
-EditorEventListener::Blur(WidgetEvent* aBlurEvent)
+EditorEventListener::Blur(InternalFocusEvent* aBlurEvent)
 {
   if (NS_WARN_IF(!aBlurEvent) || DetachedFromEditor()) {
     return NS_OK;
   }
 
-  // XXX If aBlurEvent was created by chrome script, its defaultPrevented
-  //     may be true, though.  We shouldn't handle such event but we don't
-  //     have a way to distinguish if coming event is created by chrome script.
-  NS_WARNING_ASSERTION(!aBlurEvent->DefaultPrevented(),
-                       "eBlur event shouldn't be cancelable");
-
   // check if something else is focused. If another element is focused, then
   // we should not change the selection.
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_OK);
 
   nsCOMPtr<nsIDOMElement> element;
   fm->GetFocusedElement(getter_AddRefs(element));
   if (!element) {
--- a/editor/libeditor/EditorEventListener.h
+++ b/editor/libeditor/EditorEventListener.h
@@ -63,18 +63,18 @@ protected:
 #endif
   nsresult KeyPress(WidgetKeyboardEvent* aKeyboardEvent);
   nsresult HandleChangeComposition(WidgetCompositionEvent* aCompositionEvent);
   nsresult HandleStartComposition(WidgetCompositionEvent* aCompositionEvent);
   void HandleEndComposition(WidgetCompositionEvent* aCompositionEvent);
   virtual nsresult MouseDown(nsIDOMMouseEvent* aMouseEvent);
   virtual nsresult MouseUp(nsIDOMMouseEvent* aMouseEvent) { return NS_OK; }
   virtual nsresult MouseClick(nsIDOMMouseEvent* aMouseEvent);
-  nsresult Focus(WidgetEvent* aFocusEvent);
-  nsresult Blur(WidgetEvent* aBlurEvent);
+  nsresult Focus(InternalFocusEvent* aFocusEvent);
+  nsresult Blur(InternalFocusEvent* aBlurEvent);
   nsresult DragEnter(nsIDOMDragEvent* aDragEvent);
   nsresult DragOver(nsIDOMDragEvent* aDragEvent);
   nsresult DragExit(nsIDOMDragEvent* aDragEvent);
   nsresult Drop(nsIDOMDragEvent* aDragEvent);
 
   bool CanDrop(nsIDOMDragEvent* aEvent);
   void CleanupDragDropCaret();
   already_AddRefed<nsIPresShell> GetPresShell();