summaryrefslogtreecommitdiffstats
path: root/editor
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-06-26 13:55:33 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-06-26 13:55:33 +0200
commit6aa47456c3d5d1952212ff3e970f617e5f6f3617 (patch)
tree2f64682d3e1b84c0fa924c3c4238a4d8421f5b03 /editor
parenta7bc62dcfe5495c8b53532c1b585af07171b4403 (diff)
downloadUXP-6aa47456c3d5d1952212ff3e970f617e5f6f3617.tar
UXP-6aa47456c3d5d1952212ff3e970f617e5f6f3617.tar.gz
UXP-6aa47456c3d5d1952212ff3e970f617e5f6f3617.tar.lz
UXP-6aa47456c3d5d1952212ff3e970f617e5f6f3617.tar.xz
UXP-6aa47456c3d5d1952212ff3e970f617e5f6f3617.zip
Issue #12 Part 3: EditorEventListener should check if it's removed during a call of editor's method.
EditorEventListener doesn't check if mEditorBase is available even after it's removed from the editor. If it becomes nullptr, i.e., it's detached from editor, it shouldn't continue to handle event. This patch changes some methods' nsIDOM*Event argument to WidgetEvent since it's simpler.
Diffstat (limited to 'editor')
-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