summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--editor/libeditor/EditorEventListener.cpp232
-rw-r--r--editor/libeditor/EditorEventListener.h24
-rw-r--r--editor/libeditor/HTMLEditorEventListener.cpp16
3 files changed, 173 insertions, 99 deletions
diff --git a/editor/libeditor/EditorEventListener.cpp b/editor/libeditor/EditorEventListener.cpp
index 5694fc1f2..ce7960a05 100644
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -214,7 +214,7 @@ EditorEventListener::InstallToEditor()
void
EditorEventListener::Disconnect()
{
- if (!mEditorBase) {
+ if (DetachedFromEditor()) {
return;
}
UninstallFromEditor();
@@ -301,8 +301,7 @@ EditorEventListener::UninstallFromEditor()
already_AddRefed<nsIPresShell>
EditorEventListener::GetPresShell()
{
- NS_PRECONDITION(mEditorBase,
- "The caller must check whether this is connected to an editor");
+ MOZ_ASSERT(!DetachedFromEditor());
return mEditorBase->GetPresShell();
}
@@ -316,8 +315,7 @@ EditorEventListener::GetPresContext()
nsIContent*
EditorEventListener::GetFocusedRootContent()
{
- NS_ENSURE_TRUE(mEditorBase, nullptr);
-
+ MOZ_ASSERT(!DetachedFromEditor());
nsCOMPtr<nsIContent> focusedContent = mEditorBase->GetFocusedContent();
if (!focusedContent) {
return nullptr;
@@ -336,8 +334,7 @@ EditorEventListener::GetFocusedRootContent()
bool
EditorEventListener::EditorHasFocus()
{
- NS_PRECONDITION(mEditorBase,
- "The caller must check whether this is connected to an editor");
+ MOZ_ASSERT(!DetachedFromEditor());
nsCOMPtr<nsIContent> focusedContent = mEditorBase->GetFocusedContent();
if (!focusedContent) {
return false;
@@ -348,16 +345,26 @@ EditorEventListener::EditorHasFocus()
NS_IMPL_ISUPPORTS(EditorEventListener, nsIDOMEventListener)
+bool
+EditorEventListener::DetachedFromEditor() const
+{
+ return !mEditorBase;
+}
+
+bool
+EditorEventListener::DetachedFromEditorOrDefaultPrevented(
+ WidgetEvent* aWidgetEvent) const
+{
+ return NS_WARN_IF(!aWidgetEvent) || DetachedFromEditor() ||
+ aWidgetEvent->DefaultPrevented();
+}
+
NS_IMETHODIMP
EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
{
- NS_ENSURE_TRUE(mEditorBase, NS_ERROR_FAILURE);
-
nsCOMPtr<nsIEditor> kungFuDeathGrip = mEditorBase;
Unused << kungFuDeathGrip; // mEditorBase is not referred to in this function
- WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
-
// Let's handle each event with the message of the internal event of the
// coming event. If the DOM event was created with improper interface,
// e.g., keydown event is created with |new MouseEvent("keydown", {});|,
@@ -368,6 +375,7 @@ EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
// calling it, this queries the specific interface. If it would fail,
// each event handler would just ignore the event. So, in this method,
// you don't need to check if the QI succeeded before each call.
+ WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
switch (internalEvent->mMessage) {
// dragenter
case eDragEnter: {
@@ -454,19 +462,19 @@ EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
}
// focus
case eFocus:
- return Focus(aEvent);
+ return Focus(internalEvent);
// blur
case eBlur:
- return Blur(aEvent);
+ return Blur(internalEvent);
// text
case eCompositionChange:
- return HandleText(aEvent);
+ return HandleChangeComposition(internalEvent->AsCompositionEvent());
// compositionstart
case eCompositionStart:
- return HandleStartComposition(aEvent);
+ return HandleStartComposition(internalEvent->AsCompositionEvent());
// compositionend
case eCompositionEnd:
- HandleEndComposition(aEvent);
+ HandleEndComposition(internalEvent->AsCompositionEvent());
return NS_OK;
default:
break;
@@ -477,10 +485,10 @@ EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
// 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(aEvent);
+ return Focus(internalEvent);
}
if (eventType.EqualsLiteral("blur")) {
- return Blur(aEvent);
+ return Blur(internalEvent);
}
#ifdef DEBUG
nsPrintfCString assertMessage("Editor doesn't handle \"%s\" event "
@@ -541,12 +549,15 @@ bool IsCtrlShiftPressed(nsIDOMKeyEvent* aEvent, bool& isRTL)
nsresult
EditorEventListener::KeyUp(nsIDOMKeyEvent* aKeyEvent)
{
- NS_ENSURE_TRUE(aKeyEvent, NS_OK);
+ if (NS_WARN_IF(!aKeyEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
if (!mHaveBidiKeyboards) {
return NS_OK;
}
+ // XXX Why doesn't this method check if it's consumed?
uint32_t keyCode = 0;
aKeyEvent->GetKeyCode(&keyCode);
if ((keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT ||
@@ -563,12 +574,15 @@ EditorEventListener::KeyUp(nsIDOMKeyEvent* aKeyEvent)
nsresult
EditorEventListener::KeyDown(nsIDOMKeyEvent* aKeyEvent)
{
- NS_ENSURE_TRUE(aKeyEvent, NS_OK);
+ if (NS_WARN_IF(!aKeyEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
if (!mHaveBidiKeyboards) {
return NS_OK;
}
+ // XXX Why isn't this method check if it's consumed?
uint32_t keyCode = 0;
aKeyEvent->GetKeyCode(&keyCode);
if (keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT) {
@@ -588,33 +602,22 @@ EditorEventListener::KeyDown(nsIDOMKeyEvent* aKeyEvent)
nsresult
EditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
{
- NS_ENSURE_TRUE(aKeyEvent, NS_OK);
+ if (NS_WARN_IF(!aKeyEvent)) {
+ return NS_OK;
+ }
WidgetKeyboardEvent* keypressEvent =
aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
MOZ_ASSERT(keypressEvent,
"DOM key event's internal event must be WidgetKeyboardEvent");
- if (!mEditorBase->IsAcceptableInputEvent(keypressEvent)) {
- return NS_OK;
- }
-
- // DOM event handling happens in two passes, the client pass and the system
- // pass. We do all of our processing in the system pass, to allow client
- // handlers the opportunity to cancel events and prevent typing in the editor.
- // If the client pass cancelled the event, defaultPrevented will be true
- // below.
-
- bool defaultPrevented;
- aKeyEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ if (!mEditorBase->IsAcceptableInputEvent(keypressEvent) ||
+ DetachedFromEditorOrDefaultPrevented(keypressEvent)) {
return NS_OK;
}
nsresult rv = mEditorBase->HandleKeyPressEvent(aKeyEvent);
NS_ENSURE_SUCCESS(rv, rv);
-
- aKeyEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ if (DetachedFromEditorOrDefaultPrevented(keypressEvent)) {
return NS_OK;
}
@@ -645,6 +648,9 @@ EditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
nsresult
EditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
{
+ if (NS_WARN_IF(!aMouseEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
// nothing to do if editor isn't editable or clicked on out of the editor.
WidgetMouseEvent* clickEvent =
aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
@@ -660,26 +666,23 @@ EditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
if (presContext) {
IMEStateManager::OnClickInEditor(presContext, GetFocusedRootContent(),
aMouseEvent);
- }
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
+ }
}
- bool preventDefault;
- nsresult rv = aMouseEvent->AsEvent()->GetDefaultPrevented(&preventDefault);
- if (NS_FAILED(rv) || preventDefault) {
+ if (DetachedFromEditorOrDefaultPrevented(clickEvent)) {
// We're done if 'preventdefault' is true (see for example bug 70698).
- return rv;
- }
-
- // IMEStateManager::OnClickInEditor() may cause anything because it may
- // set input context. For example, it may cause opening VKB, changing focus
- // or reflow. So, mEditorBase here might have been gone.
- if (!mEditorBase) {
return NS_OK;
}
// If we got a mouse down inside the editing area, we should force the
// IME to commit before we change the cursor position
mEditorBase->ForceCompositionEnd();
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
int16_t button = -1;
aMouseEvent->GetButton(&button);
@@ -692,6 +695,10 @@ EditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
nsresult
EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
{
+ MOZ_ASSERT(aMouseEvent);
+ MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(
+ aMouseEvent->AsEvent()->WidgetEventPtr()));
+
if (!Preferences::GetBool("middlemouse.paste", false)) {
// Middle click paste isn't enabled.
return NS_OK;
@@ -753,16 +760,12 @@ bool
EditorEventListener::NotifyIMEOfMouseButtonEvent(
nsIDOMMouseEvent* aMouseEvent)
{
+ MOZ_ASSERT(aMouseEvent);
+
if (!EditorHasFocus()) {
return false;
}
- bool defaultPrevented;
- nsresult rv = aMouseEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- NS_ENSURE_SUCCESS(rv, false);
- if (defaultPrevented) {
- return false;
- }
nsPresContext* presContext = GetPresContext();
NS_ENSURE_TRUE(presContext, false);
return IMEStateManager::OnMouseButtonEventInEditor(presContext,
@@ -773,20 +776,25 @@ EditorEventListener::NotifyIMEOfMouseButtonEvent(
nsresult
EditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
+ // FYI: We don't need to check if it's already consumed here because
+ // we need to commit composition at mouse button operation.
// FYI: This may be called by HTMLEditorEventListener::MouseDown() even
// when the event is not acceptable for committing composition.
- if (mEditorBase) {
- mEditorBase->ForceCompositionEnd();
+ if (DetachedFromEditor()) {
+ return NS_OK;
}
+ mEditorBase->ForceCompositionEnd();
return NS_OK;
}
nsresult
-EditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
+EditorEventListener::HandleChangeComposition(
+ WidgetCompositionEvent* aCompositionChangeEvent)
{
- WidgetCompositionEvent* compositionChangeEvent =
- aTextEvent->WidgetEventPtr()->AsCompositionEvent();
- if (!mEditorBase->IsAcceptableInputEvent(compositionChangeEvent)) {
+ MOZ_ASSERT(!aCompositionChangeEvent->DefaultPrevented(),
+ "eCompositionChange event shouldn't be cancelable");
+ if (DetachedFromEditor() ||
+ !mEditorBase->IsAcceptableInputEvent(aCompositionChangeEvent)) {
return NS_OK;
}
@@ -795,9 +803,7 @@ EditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
return NS_OK;
}
- // AsCompositionEvent() should always return non-nullptr. Anyway, it'll be
- // checked in TextEditor::UpdateIMEComposition().
- return mEditorBase->UpdateIMEComposition(compositionChangeEvent);
+ return mEditorBase->UpdateIMEComposition(aCompositionChangeEvent);
}
/**
@@ -807,7 +813,9 @@ EditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
nsresult
EditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
+ if (NS_WARN_IF(!aDragEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
NS_ENSURE_TRUE(presShell, NS_OK);
@@ -830,15 +838,13 @@ EditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
nsresult
EditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
-
- nsCOMPtr<nsIDOMNode> parent;
- bool defaultPrevented;
- aDragEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ if (NS_WARN_IF(!aDragEvent) ||
+ DetachedFromEditorOrDefaultPrevented(
+ aDragEvent->AsEvent()->WidgetEventPtr())) {
return NS_OK;
}
+ nsCOMPtr<nsIDOMNode> parent;
aDragEvent->GetRangeParent(getter_AddRefs(parent));
nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
NS_ENSURE_TRUE(dropParent, NS_ERROR_FAILURE);
@@ -893,7 +899,15 @@ EditorEventListener::CleanupDragDropCaret()
nsresult
EditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
+ // XXX If aDragEvent 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(
+ !aDragEvent->AsEvent()->WidgetEventPtr()->DefaultPrevented(),
+ "eDragExit shouldn't be cancelable");
+ if (NS_WARN_IF(!aDragEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
CleanupDragDropCaret();
@@ -903,13 +917,11 @@ EditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
nsresult
EditorEventListener::Drop(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
-
CleanupDragDropCaret();
- bool defaultPrevented;
- aDragEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ if (NS_WARN_IF(!aDragEvent) ||
+ DetachedFromEditorOrDefaultPrevented(
+ aDragEvent->AsEvent()->WidgetEventPtr())) {
return NS_OK;
}
@@ -939,6 +951,9 @@ EditorEventListener::Drop(nsIDOMDragEvent* aDragEvent)
bool
EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
{
+ MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(
+ aEvent->AsEvent()->WidgetEventPtr()));
+
// if the target doc is read-only, we can't drop
if (mEditorBase->IsReadonly() || mEditorBase->IsDisabled()) {
return false;
@@ -1036,32 +1051,45 @@ EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
}
nsresult
-EditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
+EditorEventListener::HandleStartComposition(
+ WidgetCompositionEvent* aCompositionStartEvent)
{
- WidgetCompositionEvent* compositionStart =
- aCompositionEvent->WidgetEventPtr()->AsCompositionEvent();
- if (!mEditorBase->IsAcceptableInputEvent(compositionStart)) {
+ if (DetachedFromEditor() ||
+ !mEditorBase->IsAcceptableInputEvent(aCompositionStartEvent)) {
return NS_OK;
}
- return mEditorBase->BeginIMEComposition(compositionStart);
+ // Although, "compositionstart" should be cancelable, but currently,
+ // eCompositionStart event coming from widget is not cancelable.
+ MOZ_ASSERT(!aCompositionStartEvent->DefaultPrevented(),
+ "eCompositionStart shouldn't be cancelable");
+ return mEditorBase->BeginIMEComposition(aCompositionStartEvent);
}
void
-EditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
+EditorEventListener::HandleEndComposition(
+ WidgetCompositionEvent* aCompositionEndEvent)
{
- WidgetCompositionEvent* compositionEnd =
- aCompositionEvent->WidgetEventPtr()->AsCompositionEvent();
- if (!mEditorBase->IsAcceptableInputEvent(compositionEnd)) {
+ if (DetachedFromEditor() ||
+ !mEditorBase->IsAcceptableInputEvent(aCompositionEndEvent)) {
return;
}
-
+ MOZ_ASSERT(!aCompositionEndEvent->DefaultPrevented(),
+ "eCompositionEnd shouldn't be cancelable");
mEditorBase->EndIMEComposition();
}
nsresult
-EditorEventListener::Focus(nsIDOMEvent* aEvent)
+EditorEventListener::Focus(WidgetEvent* aFocusEvent)
{
- NS_ENSURE_TRUE(aEvent, NS_OK);
+ 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.
if (mEditorBase->IsDisabled()) {
@@ -1076,8 +1104,7 @@ EditorEventListener::Focus(nsIDOMEvent* aEvent)
return NS_OK;
}
- nsCOMPtr<nsIDOMEventTarget> target;
- aEvent->GetTarget(getter_AddRefs(target));
+ nsCOMPtr<nsIDOMEventTarget> target = aFocusEvent->GetDOMEventTarget();
nsCOMPtr<nsINode> node = do_QueryInterface(target);
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
@@ -1109,8 +1136,8 @@ EditorEventListener::Focus(nsIDOMEvent* aEvent)
return NS_OK;
}
- nsCOMPtr<nsIDOMEventTarget> originalTarget;
- aEvent->GetOriginalTarget(getter_AddRefs(originalTarget));
+ nsCOMPtr<nsIDOMEventTarget> originalTarget =
+ aFocusEvent->GetOriginalDOMEventTarget();
nsCOMPtr<nsIContent> originalTargetAsContent =
do_QueryInterface(originalTarget);
@@ -1126,6 +1153,9 @@ EditorEventListener::Focus(nsIDOMEvent* aEvent)
}
mEditorBase->OnFocus(target);
+ if (DetachedFromEditorOrDefaultPrevented(aFocusEvent)) {
+ return NS_OK;
+ }
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_OK);
@@ -1137,9 +1167,17 @@ EditorEventListener::Focus(nsIDOMEvent* aEvent)
}
nsresult
-EditorEventListener::Blur(nsIDOMEvent* aEvent)
+EditorEventListener::Blur(WidgetEvent* aBlurEvent)
{
- NS_ENSURE_TRUE(aEvent, NS_OK);
+ 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.
@@ -1157,6 +1195,8 @@ EditorEventListener::Blur(nsIDOMEvent* aEvent)
void
EditorEventListener::SpellCheckIfNeeded()
{
+ MOZ_ASSERT(!DetachedFromEditor());
+
// If the spell check skip flag is still enabled from creation time,
// disable it because focused editors are allowed to spell check.
uint32_t currentFlags = 0;
@@ -1170,6 +1210,8 @@ EditorEventListener::SpellCheckIfNeeded()
bool
EditorEventListener::IsFileControlTextBox()
{
+ MOZ_ASSERT(!DetachedFromEditor());
+
Element* root = mEditorBase->GetRoot();
if (!root || !root->ChromeOnlyAccess()) {
return false;
@@ -1185,6 +1227,8 @@ EditorEventListener::IsFileControlTextBox()
bool
EditorEventListener::ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent)
{
+ MOZ_ASSERT(!DetachedFromEditor());
+
// Only return true if the target of the event is a desendant of the active
// editing host in order to match the similar decision made in
// nsXBLWindowKeyHandler.
diff --git a/editor/libeditor/EditorEventListener.h b/editor/libeditor/EditorEventListener.h
index 505b711c7..7244ebea4 100644
--- a/editor/libeditor/EditorEventListener.h
+++ b/editor/libeditor/EditorEventListener.h
@@ -6,6 +6,7 @@
#ifndef EditorEventListener_h
#define EditorEventListener_h
+#include "mozilla/EventForwards.h"
#include "nsCOMPtr.h"
#include "nsError.h"
#include "nsIDOMEventListener.h"
@@ -60,14 +61,14 @@ protected:
nsresult KeyUp(nsIDOMKeyEvent* aKeyEvent);
#endif
nsresult KeyPress(nsIDOMKeyEvent* aKeyEvent);
- nsresult HandleText(nsIDOMEvent* aTextEvent);
- nsresult HandleStartComposition(nsIDOMEvent* aCompositionEvent);
- void HandleEndComposition(nsIDOMEvent* aCompositionEvent);
+ 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(nsIDOMEvent* aEvent);
- nsresult Blur(nsIDOMEvent* aEvent);
+ nsresult Focus(WidgetEvent* aFocusEvent);
+ nsresult Blur(WidgetEvent* aBlurEvent);
nsresult DragEnter(nsIDOMDragEvent* aDragEvent);
nsresult DragOver(nsIDOMDragEvent* aDragEvent);
nsresult DragExit(nsIDOMDragEvent* aDragEvent);
@@ -85,6 +86,19 @@ protected:
bool ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent);
nsresult HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent);
+ /**
+ * DetachedFromEditor() returns true if editor was detached.
+ * Otherwise, false.
+ */
+ bool DetachedFromEditor() const;
+
+ /**
+ * DetachedFromEditorOrDefaultPrevented() returns true if editor was detached
+ * and/or the event was consumed. Otherwise, i.e., attached editor can
+ * handle the event, returns true.
+ */
+ bool DetachedFromEditorOrDefaultPrevented(WidgetEvent* aEvent) const;
+
EditorBase* mEditorBase; // weak
RefPtr<nsCaret> mCaret;
bool mCommitText;
diff --git a/editor/libeditor/HTMLEditorEventListener.cpp b/editor/libeditor/HTMLEditorEventListener.cpp
index c4d857908..a22188483 100644
--- a/editor/libeditor/HTMLEditorEventListener.cpp
+++ b/editor/libeditor/HTMLEditorEventListener.cpp
@@ -53,6 +53,12 @@ HTMLEditorEventListener::GetHTMLEditor()
nsresult
HTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
{
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
+
+ // FYI: We need to notify HTML editor of mouseup even if it's consumed
+ // because HTML editor always needs to release grabbing resizer.
HTMLEditor* htmlEditor = GetHTMLEditor();
nsCOMPtr<nsIDOMEventTarget> target;
@@ -72,6 +78,10 @@ HTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
nsresult
HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
+ if (NS_WARN_IF(!aMouseEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
+
WidgetMouseEvent* mousedownEvent =
aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
@@ -86,6 +96,9 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
return EditorEventListener::MouseDown(aMouseEvent);
}
+ // XXX This method may change selection. So, we need to commit composition
+ // here, first.
+
// Detect only "context menu" click
// XXX This should be easier to do!
// But eDOMEvents_contextmenu and eContextMenu is not exposed in any event
@@ -179,6 +192,9 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
} else {
htmlEditor->SelectElement(element);
}
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
}
}
// HACK !!! Context click places the caret but the context menu consumes