Skip to content

Commit

Permalink
Bug 826657 part.2 Implement NOTIFY_IME_OF_MOUSE_BUTTON_EVENT in XP pa…
Browse files Browse the repository at this point in the history
…rt r=smaug+ehsan
  • Loading branch information
masayuki-nakano committed Aug 29, 2014
1 parent 5d04b0f commit 93cf486
Show file tree
Hide file tree
Showing 10 changed files with 329 additions and 25 deletions.
72 changes: 72 additions & 0 deletions dom/events/IMEContentObserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include "mozilla/AutoRestore.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/TextComposition.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h"
#include "nsAutoPtr.h"
#include "nsContentUtils.h"
Expand Down Expand Up @@ -425,6 +427,76 @@ IMEContentObserver::ReflowInterruptible(DOMHighResTimeStamp aStart,
return NS_OK;
}

bool
IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
WidgetMouseEvent* aMouseEvent)
{
if (!mUpdatePreference.WantMouseButtonEventOnChar()) {
return false;
}
if (!aMouseEvent->mFlags.mIsTrusted ||
aMouseEvent->mFlags.mDefaultPrevented ||
!aMouseEvent->widget) {
return false;
}
// Now, we need to notify only mouse down and mouse up event.
switch (aMouseEvent->message) {
case NS_MOUSE_BUTTON_UP:
case NS_MOUSE_BUTTON_DOWN:
break;
default:
return false;
}
if (NS_WARN_IF(!mWidget)) {
return false;
}

WidgetQueryContentEvent charAtPt(true, NS_QUERY_CHARACTER_AT_POINT,
aMouseEvent->widget);
charAtPt.refPoint = aMouseEvent->refPoint;
ContentEventHandler handler(aPresContext);
handler.OnQueryCharacterAtPoint(&charAtPt);
if (NS_WARN_IF(!charAtPt.mSucceeded) ||
charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
return false;
}

// The result character rect is relative to the top level widget.
// We should notify it with offset in the widget.
nsIWidget* topLevelWidget = mWidget->GetTopLevelWidget();
if (topLevelWidget && topLevelWidget != mWidget) {
charAtPt.mReply.mRect.MoveBy(
topLevelWidget->WidgetToScreenOffset() -
mWidget->WidgetToScreenOffset());
}
// The refPt is relative to its widget.
// We should notify it with offset in the widget.
if (aMouseEvent->widget != mWidget) {
charAtPt.refPoint += LayoutDeviceIntPoint::FromUntyped(
aMouseEvent->widget->WidgetToScreenOffset() -
mWidget->WidgetToScreenOffset());
}

IMENotification notification(NOTIFY_IME_OF_MOUSE_BUTTON_EVENT);
notification.mMouseButtonEventData.mEventMessage = aMouseEvent->message;
notification.mMouseButtonEventData.mOffset = charAtPt.mReply.mOffset;
notification.mMouseButtonEventData.mCursorPos.Set(
LayoutDeviceIntPoint::ToUntyped(charAtPt.refPoint));
notification.mMouseButtonEventData.mCharRect.Set(charAtPt.mReply.mRect);
notification.mMouseButtonEventData.mButton = aMouseEvent->button;
notification.mMouseButtonEventData.mButtons = aMouseEvent->buttons;
notification.mMouseButtonEventData.mModifiers = aMouseEvent->modifiers;

nsresult rv = mWidget->NotifyIME(notification);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}

bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
aMouseEvent->mFlags.mDefaultPrevented = consumed;
return consumed;
}

// Helper class, used for text change notification
class TextChangeEvent : public nsRunnable
{
Expand Down
3 changes: 3 additions & 0 deletions dom/events/IMEContentObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class IMEContentObserver MOZ_FINAL : public nsISelectionListener
// nsIScrollObserver
virtual void ScrollPositionChanged() MOZ_OVERRIDE;

bool OnMouseButtonEvent(nsPresContext* aPresContext,
WidgetMouseEvent* aMouseEvent);

void Init(nsIWidget* aWidget, nsPresContext* aPresContext,
nsIContent* aContent);
void Destroy();
Expand Down
58 changes: 58 additions & 0 deletions dom/events/IMEStateManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "mozilla/Attributes.h"
#include "mozilla/EventStates.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/TextComposition.h"
Expand Down Expand Up @@ -471,6 +472,63 @@ IMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling)
OnChangeFocusInternal(sPresContext, sContent, action);
}

// static
bool
IMEStateManager::OnMouseButtonEventInEditor(nsPresContext* aPresContext,
nsIContent* aContent,
nsIDOMMouseEvent* aMouseEvent)
{
PR_LOG(sISMLog, PR_LOG_ALWAYS,
("ISM: IMEStateManager::OnMouseButtonEventInEditor(aPresContext=0x%p, "
"aContent=0x%p, aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
aPresContext, aContent, aMouseEvent, sPresContext, sContent));

if (sPresContext != aPresContext || sContent != aContent) {
PR_LOG(sISMLog, PR_LOG_DEBUG,
("ISM: IMEStateManager::OnMouseButtonEventInEditor(), "
"the mouse event isn't fired on the editor managed by ISM"));
return false;
}

if (!sActiveIMEContentObserver) {
PR_LOG(sISMLog, PR_LOG_DEBUG,
("ISM: IMEStateManager::OnMouseButtonEventInEditor(), "
"there is no active IMEContentObserver"));
return false;
}

if (!sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
PR_LOG(sISMLog, PR_LOG_DEBUG,
("ISM: IMEStateManager::OnMouseButtonEventInEditor(), "
"the active IMEContentObserver isn't managing the editor"));
return false;
}

WidgetMouseEvent* internalEvent =
aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
if (NS_WARN_IF(!internalEvent)) {
PR_LOG(sISMLog, PR_LOG_DEBUG,
("ISM: IMEStateManager::OnMouseButtonEventInEditor(), "
"the internal event of aMouseEvent isn't WidgetMouseEvent"));
return false;
}

bool consumed =
sActiveIMEContentObserver->OnMouseButtonEvent(aPresContext, internalEvent);

#ifdef PR_LOGGING
nsAutoString eventType;
aMouseEvent->GetType(eventType);
PR_LOG(sISMLog, PR_LOG_ALWAYS,
("ISM: IMEStateManager::OnMouseButtonEventInEditor(), "
"mouse event (type=%s, button=%d) is %s",
NS_ConvertUTF16toUTF8(eventType).get(), internalEvent->button,
consumed ? "consumed" : "not consumed"));
#endif

return consumed;
}

// static
void
IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
Expand Down
7 changes: 7 additions & 0 deletions dom/events/IMEStateManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ class IMEStateManager
static void UpdateIMEState(const IMEState &aNewIMEState,
nsIContent* aContent);

// This method is called when user operates mouse button in focused editor
// and before the editor handles it.
// Returns true if IME consumes the event. Otherwise, false.
static bool OnMouseButtonEventInEditor(nsPresContext* aPresContext,
nsIContent* aContent,
nsIDOMMouseEvent* aMouseEvent);

// This method is called when user clicked in an editor.
// aContent must be:
// If the editor is for <input> or <textarea>, the element.
Expand Down
114 changes: 97 additions & 17 deletions editor/libeditor/nsEditorEventListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ nsEditorEventListener::nsEditorEventListener()
: mEditor(nullptr)
, mCommitText(false)
, mInTransaction(false)
, mMouseDownOrUpConsumedByIME(false)
#ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
, mHaveBidiKeyboards(false)
, mShouldSwitchTextDirection(false)
Expand Down Expand Up @@ -299,6 +300,42 @@ nsEditorEventListener::GetPresShell()
return mEditor->GetPresShell();
}

nsPresContext*
nsEditorEventListener::GetPresContext()
{
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
return presShell ? presShell->GetPresContext() : nullptr;
}

nsIContent*
nsEditorEventListener::GetFocusedRootContent()
{
NS_ENSURE_TRUE(mEditor, nullptr);

nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContent();
if (!focusedContent) {
return nullptr;
}

nsIDocument* composedDoc = focusedContent->GetComposedDoc();
NS_ENSURE_TRUE(composedDoc, nullptr);

return composedDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent;
}

bool
nsEditorEventListener::EditorHasFocus()
{
NS_PRECONDITION(mEditor,
"The caller must check whether this is connected to an editor");
nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContent();
if (!focusedContent) {
return false;
}
nsIDocument* composedDoc = focusedContent->GetComposedDoc();
return !!composedDoc;
}

/**
* nsISupports implementation
*/
Expand Down Expand Up @@ -369,16 +406,47 @@ nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
// mousedown
case NS_MOUSE_BUTTON_DOWN: {
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
return MouseDown(mouseEvent);
NS_ENSURE_TRUE(mouseEvent, NS_OK);
// nsEditorEventListener may receive (1) all mousedown, mouseup and click
// events, (2) only mousedown event or (3) only mouseup event.
// mMouseDownOrUpConsumedByIME is used only for ignoring click event if
// preceding mousedown and/or mouseup event is consumed by IME.
// Therefore, even if case #2 or case #3 occurs,
// mMouseDownOrUpConsumedByIME is true here. Therefore, we should always
// overwrite it here.
mMouseDownOrUpConsumedByIME = NotifyIMEOfMouseButtonEvent(mouseEvent);
return mMouseDownOrUpConsumedByIME ? NS_OK : MouseDown(mouseEvent);
}
// mouseup
case NS_MOUSE_BUTTON_UP: {
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
return MouseUp(mouseEvent);
NS_ENSURE_TRUE(mouseEvent, NS_OK);
// See above comment in the NS_MOUSE_BUTTON_DOWN case, first.
// This code assumes that case #1 is occuring. However, if case #3 may
// occurs after case #2 and the mousedown is consumed,
// mMouseDownOrUpConsumedByIME is true even though nsEditorEventListener
// has not received the preceding mousedown event of this mouseup event.
// So, mMouseDownOrUpConsumedByIME may be invalid here. However,
// this is not a matter because mMouseDownOrUpConsumedByIME is referred
// only by NS_MOUSE_CLICK case but click event is fired only in case #1.
// So, before a click event is fired, mMouseDownOrUpConsumedByIME is
// always initialized in the NS_MOUSE_BUTTON_DOWN case if it's referred.
if (NotifyIMEOfMouseButtonEvent(mouseEvent)) {
mMouseDownOrUpConsumedByIME = true;
}
return mMouseDownOrUpConsumedByIME ? NS_OK : MouseUp(mouseEvent);
}
// click
case NS_MOUSE_CLICK: {
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
NS_ENSURE_TRUE(mouseEvent, NS_OK);
// If the preceding mousedown event or mouseup event was consumed,
// editor shouldn't handle this click event.
if (mMouseDownOrUpConsumedByIME) {
mMouseDownOrUpConsumedByIME = false;
mouseEvent->PreventDefault();
return NS_OK;
}
return MouseClick(mouseEvent);
}
// focus
Expand Down Expand Up @@ -592,8 +660,6 @@ nsEditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
nsresult
nsEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
{
NS_ENSURE_TRUE(aMouseEvent, 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)) {
Expand All @@ -602,17 +668,12 @@ nsEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)

// Notifies clicking on editor to IMEStateManager even when the event was
// consumed.
nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContent();
if (focusedContent) {
nsIDocument* currentDoc = focusedContent->GetCurrentDoc();
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
nsPresContext* presContext =
presShell ? presShell->GetPresContext() : nullptr;
if (presContext && currentDoc) {
IMEStateManager::OnClickInEditor(presContext,
currentDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent,
aMouseEvent);
}
if (EditorHasFocus()) {
nsPresContext* presContext = GetPresContext();
if (presContext) {
IMEStateManager::OnClickInEditor(presContext, GetFocusedRootContent(),
aMouseEvent);
}
}

bool preventDefault;
Expand Down Expand Up @@ -694,11 +755,30 @@ nsEditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
return NS_OK;
}

bool
nsEditorEventListener::NotifyIMEOfMouseButtonEvent(
nsIDOMMouseEvent* aMouseEvent)
{
if (!EditorHasFocus()) {
return false;
}

bool defaultPrevented;
nsresult rv = aMouseEvent->GetDefaultPrevented(&defaultPrevented);
NS_ENSURE_SUCCESS(rv, false);
if (defaultPrevented) {
return false;
}
nsPresContext* presContext = GetPresContext();
NS_ENSURE_TRUE(presContext, false);
return IMEStateManager::OnMouseButtonEventInEditor(presContext,
GetFocusedRootContent(),
aMouseEvent);
}

nsresult
nsEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
NS_ENSURE_TRUE(aMouseEvent, NS_OK);

mEditor->ForceCompositionEnd();
return NS_OK;
}
Expand Down
6 changes: 6 additions & 0 deletions editor/libeditor/nsEditorEventListener.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ class nsEditorEventListener : public nsIDOMEventListener
bool CanDrop(nsIDOMDragEvent* aEvent);
void CleanupDragDropCaret();
already_AddRefed<nsIPresShell> GetPresShell();
nsPresContext* GetPresContext();
nsIContent* GetFocusedRootContent();
// Returns true if IME consumes the mouse event.
bool NotifyIMEOfMouseButtonEvent(nsIDOMMouseEvent* aMouseEvent);
bool EditorHasFocus();
bool IsFileControlTextBox();
bool ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent);
nsresult HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent);
Expand All @@ -81,6 +86,7 @@ class nsEditorEventListener : public nsIDOMEventListener
nsRefPtr<nsCaret> mCaret;
bool mCommitText;
bool mInTransaction;
bool mMouseDownOrUpConsumedByIME;
#ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
bool mHaveBidiKeyboards;
bool mShouldSwitchTextDirection;
Expand Down
6 changes: 0 additions & 6 deletions editor/libeditor/nsHTMLEditorEventListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ nsHTMLEditorEventListener::GetHTMLEditor()
nsresult
nsHTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
{
NS_ENSURE_TRUE(aMouseEvent, NS_OK);

nsHTMLEditor* htmlEditor = GetHTMLEditor();

nsCOMPtr<nsIDOMEventTarget> target;
Expand All @@ -73,8 +71,6 @@ nsHTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
nsresult
nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
NS_ENSURE_TRUE(aMouseEvent, NS_OK);

nsHTMLEditor* htmlEditor = GetHTMLEditor();

// Detect only "context menu" click
Expand Down Expand Up @@ -204,8 +200,6 @@ nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
nsresult
nsHTMLEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
{
NS_ENSURE_TRUE(aMouseEvent, NS_OK);

nsCOMPtr<nsIDOMEventTarget> target;
nsresult rv = aMouseEvent->GetTarget(getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
Expand Down
Loading

0 comments on commit 93cf486

Please sign in to comment.