Bug 1461708 - part 5: Move EditorEventListener::HandleMiddleClickPaste() to EventStateManager r=smaug

EventStateManager needs to handle middle click paste without editor.
Therefore, the handler should be in EventStateManager.

Differential Revision: https://phabricator.services.mozilla.com/D7852

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-10-10 12:04:17 +00:00
Родитель d472d6f312
Коммит fd4e78f2a1
6 изменённых файлов: 148 добавлений и 58 удалений

Просмотреть файл

@ -35,6 +35,7 @@
#include "nsCOMPtr.h"
#include "nsFocusManager.h"
#include "nsGenericHTMLElement.h"
#include "nsIClipboard.h"
#include "nsIContent.h"
#include "nsIContentInlines.h"
#include "nsIDocument.h"
@ -5120,6 +5121,95 @@ EventStateManager::DispatchClickEvents(nsIPresShell* aPresShell,
return rv;
}
nsresult
EventStateManager::HandleMiddleClickPaste(nsIPresShell* aPresShell,
WidgetMouseEvent* aMouseEvent,
nsEventStatus* aStatus,
TextEditor* aTextEditor)
{
MOZ_ASSERT(aPresShell);
MOZ_ASSERT(aMouseEvent);
MOZ_ASSERT(aMouseEvent->mMessage == eMouseClick &&
aMouseEvent->button == WidgetMouseEventBase::eMiddleButton);
MOZ_ASSERT(aStatus);
MOZ_ASSERT(aTextEditor);
if (*aStatus == nsEventStatus_eConsumeNoDefault) {
// Already consumed. Do nothing.
return NS_OK;
}
RefPtr<Selection> selection = aTextEditor->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
// Move selection to the clicked point.
nsCOMPtr<nsIContent> container;
int32_t offset;
nsLayoutUtils::GetContainerAndOffsetAtEvent(aPresShell, aMouseEvent,
getter_AddRefs(container),
&offset);
if (container) {
// XXX If readonly or disabled <input> or <textarea> in contenteditable
// designMode editor is clicked, the point is in the editor.
// However, outer HTMLEditor and Selection should handle it.
// So, in such case, Selection::Collapse() will fail.
DebugOnly<nsresult> rv = selection->Collapse(container, offset);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to collapse Selection at middle clicked");
}
int32_t clipboardType = nsIClipboard::kGlobalClipboard;
nsresult rv = NS_OK;
nsCOMPtr<nsIClipboard> clipboardService =
do_GetService("@mozilla.org/widget/clipboard;1", &rv);
if (NS_SUCCEEDED(rv)) {
bool selectionSupported;
rv = clipboardService->SupportsSelectionClipboard(&selectionSupported);
if (NS_SUCCEEDED(rv) && selectionSupported) {
clipboardType = nsIClipboard::kSelectionClipboard;
}
}
// Check if the editor is still the good target to paste.
if (aTextEditor->Destroyed() ||
aTextEditor->IsReadonly() ||
aTextEditor->IsDisabled()) {
// XXX Should we consume the event when the editor is readonly and/or
// disabled?
return NS_OK;
}
// The selection may have been modified during reflow. Therefore, we
// should adjust event target to pass IsAcceptableInputEvent().
nsRange* range = selection->GetRangeAt(0);
if (!range) {
return NS_OK;
}
WidgetMouseEvent mouseEvent(*aMouseEvent);
mouseEvent.mOriginalTarget = range->GetStartContainer();
if (NS_WARN_IF(!mouseEvent.mOriginalTarget) ||
!aTextEditor->IsAcceptableInputEvent(&mouseEvent)) {
return NS_OK;
}
// If Control key is pressed, we should paste clipboard content as
// quotation. Otherwise, paste it as is.
if (aMouseEvent->IsControl()) {
DebugOnly<nsresult> rv =
aTextEditor->PasteAsQuotationAsAction(clipboardType);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation");
} else {
DebugOnly<nsresult> rv =
aTextEditor->PasteAsAction(clipboardType);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste");
}
*aStatus = nsEventStatus_eConsumeNoDefault;
return NS_OK;
}
nsIFrame*
EventStateManager::GetEventTarget()
{

Просмотреть файл

@ -363,6 +363,24 @@ public:
MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL = 1000
};
/**
* HandleMiddleClickPaste() handles middle mouse button event as pasting
* clipboard text.
*
* @param aPresShell The PresShell for the ESM. This lifetime
* should be guaranteed by the caller.
* @param aMouseEvent The eMouseClick event which caused the
* paste.
* @param aStatus The event status of aMouseEvent.
* @param aTextEditor TextEditor which may be pasted the
* clipboard text by the middle click.
*/
MOZ_CAN_RUN_SCRIPT
nsresult HandleMiddleClickPaste(nsIPresShell* aPresShell,
WidgetMouseEvent* aMouseEvent,
nsEventStatus* aStatus,
TextEditor* aTextEditor);
protected:
/**
* Prefs class capsules preference management.

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/ContentEvents.h" // for InternalFocusEvent
#include "mozilla/EditorBase.h" // for EditorBase, etc.
#include "mozilla/EventListenerManager.h" // for EventListenerManager
#include "mozilla/EventStateManager.h" // for EventStateManager
#include "mozilla/IMEStateManager.h" // for IMEStateManager
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/TextEditor.h" // for TextEditor
@ -647,18 +648,18 @@ EditorEventListener::MouseClick(MouseEvent* aMouseEvent)
return NS_OK;
}
// nothing to do if editor isn't editable or clicked on out of the editor.
RefPtr<EditorBase> editorBase(mEditorBase);
RefPtr<TextEditor> textEditor = mEditorBase->AsTextEditor();
WidgetMouseEvent* clickEvent =
aMouseEvent->WidgetEventPtr()->AsMouseEvent();
if (editorBase->IsReadonly() || editorBase->IsDisabled() ||
!editorBase->IsAcceptableInputEvent(clickEvent)) {
if (textEditor->IsReadonly() || textEditor->IsDisabled() ||
!textEditor->IsAcceptableInputEvent(clickEvent)) {
return NS_OK;
}
// Notifies clicking on editor to IMEStateManager even when the event was
// consumed.
if (EditorHasFocus()) {
nsPresContext* presContext = GetPresContext();
RefPtr<nsPresContext> presContext = GetPresContext();
if (presContext) {
IMEStateManager::OnClickInEditor(presContext, GetFocusedRootContent(),
clickEvent);
@ -679,64 +680,32 @@ EditorEventListener::MouseClick(MouseEvent* aMouseEvent)
return NS_OK;
}
if (clickEvent->button == 1) {
return HandleMiddleClickPaste(aMouseEvent);
}
return NS_OK;
}
nsresult
EditorEventListener::HandleMiddleClickPaste(MouseEvent* aMouseEvent)
{
MOZ_ASSERT(aMouseEvent);
WidgetMouseEvent* clickEvent =
aMouseEvent->WidgetEventPtr()->AsMouseEvent();
MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(clickEvent));
if (!Preferences::GetBool("middlemouse.paste", false)) {
// Middle click paste isn't enabled.
if (clickEvent->button != WidgetMouseEventBase::eMiddleButton ||
!WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
return NS_OK;
}
// Set the selection to the point under the mouse cursor:
nsCOMPtr<nsINode> parent = aMouseEvent->GetRangeParent();
int32_t offset = aMouseEvent->RangeOffset();
RefPtr<TextEditor> textEditor = mEditorBase->AsTextEditor();
MOZ_ASSERT(textEditor);
RefPtr<Selection> selection = textEditor->GetSelection();
if (selection) {
selection->Collapse(parent, offset);
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (NS_WARN_IF(!presShell)) {
return NS_OK;
}
nsresult rv;
int32_t clipboard = nsIClipboard::kGlobalClipboard;
nsCOMPtr<nsIClipboard> clipboardService =
do_GetService("@mozilla.org/widget/clipboard;1", &rv);
if (NS_SUCCEEDED(rv)) {
bool selectionSupported;
rv = clipboardService->SupportsSelectionClipboard(&selectionSupported);
if (NS_SUCCEEDED(rv) && selectionSupported) {
clipboard = nsIClipboard::kSelectionClipboard;
}
nsPresContext* presContext = GetPresContext();
if (NS_WARN_IF(!presContext)) {
return NS_OK;
}
// If the ctrl key is pressed, we'll do paste as quotation.
// Would've used the alt key, but the kde wmgr treats alt-middle specially.
if (clickEvent->IsControl()) {
textEditor->PasteAsQuotationAsAction(clipboard);
} else {
textEditor->PasteAsAction(clipboard);
MOZ_ASSERT(!clickEvent->DefaultPrevented());
nsEventStatus status = nsEventStatus_eIgnore;
RefPtr<EventStateManager> esm = presContext->EventStateManager();
DebugOnly<nsresult> rv =
esm->HandleMiddleClickPaste(presShell, clickEvent, &status, textEditor);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to paste for the middle button click");
if (status == nsEventStatus_eConsumeNoDefault) {
// Prevent the event from propagating up to be possibly handled
// again by the containing window:
clickEvent->StopImmediatePropagation();
clickEvent->PreventDefault();
}
// Prevent the event from propagating up to be possibly handled
// again by the containing window:
clickEvent->StopPropagation();
clickEvent->PreventDefault();
// We processed the event, whether drop/paste succeeded or not
return NS_OK;
}

Просмотреть файл

@ -91,8 +91,6 @@ protected:
bool EditorHasFocus();
bool IsFileControlTextBox();
bool ShouldHandleNativeKeyBindings(WidgetKeyboardEvent* aKeyboardEvent);
MOZ_CAN_RUN_SCRIPT
nsresult HandleMiddleClickPaste(dom::MouseEvent* aMouseEvent);
/**
* DetachedFromEditor() returns true if editor was detached.

Просмотреть файл

@ -351,6 +351,11 @@ public:
{
return mReason == eReal;
}
/**
* Returns true if middle click paste is enabled.
*/
static bool IsMiddleClickPasteEnabled();
};
/******************************************************************************

Просмотреть файл

@ -650,6 +650,16 @@ WidgetInputEvent::AccelModifier()
return sAccelModifier;
}
/******************************************************************************
* mozilla::WidgetMouseEvent (MouseEvents.h)
******************************************************************************/
/* static */ bool
WidgetMouseEvent::IsMiddleClickPasteEnabled()
{
return Preferences::GetBool("middlemouse.paste", false);
}
/******************************************************************************
* mozilla::WidgetWheelEvent (MouseEvents.h)
******************************************************************************/