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
--- 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();