Bug 1461708 - part 4: Move implementation of UIEvent::GetRangeParent() and UIEvent::RangeOffset() to nsLayoutUtils r=smaug

We need to move EditorEventListener::HandleMiddleClickPaste() into
EventStateManager to handle middle click paste after all click events are
dispatched.  This is preparation of the change.

HandleMiddleClickPaste() uses UIEvent::GetRangeParent() and
UIEvent::RangeOffset() to collapse Selection at clicked point.  However,
EventStateManager cannot access them since EventStateManager can handle it
with WidgetMouseEvent.  Fortunately, only WidgetMouseEvent is necessary for
implementing them.  Therefore, we can move the implementation into
nsLayoutUtils and merge them.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-10-10 12:03:34 +00:00
parent 4bc3e93065
commit d472d6f312
10 changed files with 122 additions and 51 deletions

View File

@ -184,54 +184,34 @@ UIEvent::PageY() const
already_AddRefed<nsINode>
UIEvent::GetRangeParent()
{
nsIFrame* targetFrame = nullptr;
if (mPresContext) {
nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
if (shell) {
shell->FlushPendingNotifications(FlushType::Layout);
targetFrame = mPresContext->EventStateManager()->GetEventTarget();
}
if (NS_WARN_IF(!mPresContext)) {
return nullptr;
}
if (targetFrame) {
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
targetFrame);
nsCOMPtr<nsIContent> parent = targetFrame->GetContentOffsetsFromPoint(pt).content;
if (parent) {
if (parent->ChromeOnlyAccess() &&
!nsContentUtils::CanAccessNativeAnon()) {
return nullptr;
}
return parent.forget();
}
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (NS_WARN_IF(!presShell)) {
return nullptr;
}
return nullptr;
nsCOMPtr<nsIContent> container;
nsLayoutUtils::GetContainerAndOffsetAtEvent(presShell, mEvent,
getter_AddRefs(container),
nullptr);
return container.forget();
}
int32_t
UIEvent::RangeOffset() const
{
if (!mPresContext) {
if (NS_WARN_IF(!mPresContext)) {
return 0;
}
nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
if (!shell) {
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (NS_WARN_IF(!presShell)) {
return 0;
}
shell->FlushPendingNotifications(FlushType::Layout);
nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
if (!targetFrame) {
return 0;
}
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
targetFrame);
return targetFrame->GetContentOffsetsFromPoint(pt).offset;
int32_t offset = 0;
nsLayoutUtils::GetContainerAndOffsetAtEvent(presShell, mEvent,
nullptr, &offset);
return offset;
}
nsIntPoint

View File

@ -88,8 +88,10 @@ public:
return 0;
}
MOZ_CAN_RUN_SCRIPT
already_AddRefed<nsINode> GetRangeParent();
MOZ_CAN_RUN_SCRIPT
int32_t RangeOffset() const;
protected:

View File

@ -380,19 +380,26 @@ EditorEventListener::HandleEvent(Event* aEvent)
switch (internalEvent->mMessage) {
// dragenter
case eDragEnter: {
return DragEnter(aEvent->AsDragEvent());
// aEvent should be grabbed by the caller since this is
// nsIDOMEventListener method. However, our clang plugin cannot check it
// if we use Event::As*Event(). So, we need to grab it by ourselves.
RefPtr<DragEvent> dragEvent = aEvent->AsDragEvent();
return DragEnter(dragEvent);
}
// dragover
case eDragOver: {
return DragOver(aEvent->AsDragEvent());
RefPtr<DragEvent> dragEvent = aEvent->AsDragEvent();
return DragOver(dragEvent);
}
// dragexit
case eDragExit: {
return DragExit(aEvent->AsDragEvent());
RefPtr<DragEvent> dragEvent = aEvent->AsDragEvent();
return DragExit(dragEvent);
}
// drop
case eDrop: {
return Drop(aEvent->AsDragEvent());
RefPtr<DragEvent> dragEvent = aEvent->AsDragEvent();
return Drop(dragEvent);
}
#ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
// keydown
@ -420,7 +427,7 @@ EditorEventListener::HandleEvent(Event* aEvent)
if (mMouseDownOrUpConsumedByIME) {
return NS_OK;
}
MouseEvent* mouseEvent = aEvent->AsMouseEvent();
RefPtr<MouseEvent> mouseEvent = aEvent->AsMouseEvent();
return NS_WARN_IF(!mouseEvent) ? NS_OK : MouseDown(mouseEvent);
}
// mouseup
@ -441,13 +448,15 @@ EditorEventListener::HandleEvent(Event* aEvent)
if (mMouseDownOrUpConsumedByIME) {
return NS_OK;
}
MouseEvent* mouseEvent = aEvent->AsMouseEvent();
RefPtr<MouseEvent> mouseEvent = aEvent->AsMouseEvent();
return NS_WARN_IF(!mouseEvent) ? NS_OK : MouseUp(mouseEvent);
}
// click
case eMouseClick: {
MouseEvent* mouseEvent = aEvent->AsMouseEvent();
NS_ENSURE_TRUE(mouseEvent, NS_OK);
RefPtr<MouseEvent> mouseEvent = aEvent->AsMouseEvent();
if (NS_WARN_IF(!mouseEvent)) {
return NS_OK;
}
// If the preceding mousedown event or mouseup event was consumed,
// editor shouldn't handle this click event.
if (mMouseDownOrUpConsumedByIME) {

View File

@ -48,7 +48,10 @@ public:
void Disconnect();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
// nsIDOMEventListener
MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHOD HandleEvent(dom::Event *aEvent) override;
void SpellCheckIfNeeded();
@ -66,17 +69,19 @@ protected:
nsresult HandleChangeComposition(WidgetCompositionEvent* aCompositionEvent);
nsresult HandleStartComposition(WidgetCompositionEvent* aCompositionEvent);
void HandleEndComposition(WidgetCompositionEvent* aCompositionEvent);
MOZ_CAN_RUN_SCRIPT
virtual nsresult MouseDown(dom::MouseEvent* aMouseEvent);
virtual nsresult MouseUp(dom::MouseEvent* aMouseEvent) { return NS_OK; }
MOZ_CAN_RUN_SCRIPT
virtual nsresult MouseClick(dom::MouseEvent* aMouseEvent);
nsresult Focus(InternalFocusEvent* aFocusEvent);
nsresult Blur(InternalFocusEvent* aBlurEvent);
nsresult DragEnter(dom::DragEvent* aDragEvent);
nsresult DragOver(dom::DragEvent* aDragEvent);
MOZ_CAN_RUN_SCRIPT nsresult DragEnter(dom::DragEvent* aDragEvent);
MOZ_CAN_RUN_SCRIPT nsresult DragOver(dom::DragEvent* aDragEvent);
nsresult DragExit(dom::DragEvent* aDragEvent);
nsresult Drop(dom::DragEvent* aDragEvent);
MOZ_CAN_RUN_SCRIPT nsresult Drop(dom::DragEvent* aDragEvent);
bool CanDrop(dom::DragEvent* aEvent);
MOZ_CAN_RUN_SCRIPT bool CanDrop(dom::DragEvent* aEvent);
void CleanupDragDropCaret();
nsIPresShell* GetPresShell() const;
nsPresContext* GetPresContext() const;
@ -86,6 +91,7 @@ protected:
bool EditorHasFocus();
bool IsFileControlTextBox();
bool ShouldHandleNativeKeyBindings(WidgetKeyboardEvent* aKeyboardEvent);
MOZ_CAN_RUN_SCRIPT
nsresult HandleMiddleClickPaste(dom::MouseEvent* aMouseEvent);
/**

View File

@ -30,8 +30,10 @@ public:
virtual nsresult Connect(EditorBase* aEditorBase) override;
protected:
MOZ_CAN_RUN_SCRIPT
virtual nsresult MouseDown(dom::MouseEvent* aMouseEvent) override;
virtual nsresult MouseUp(dom::MouseEvent* aMouseEvent) override;
MOZ_CAN_RUN_SCRIPT
virtual nsresult MouseClick(dom::MouseEvent* aMouseEvent) override;
};

View File

@ -213,6 +213,7 @@ public:
* OnDrop() is called from EditorEventListener::Drop that is handler of drop
* event.
*/
MOZ_CAN_RUN_SCRIPT
nsresult OnDrop(dom::DragEvent* aDropEvent);
/**

View File

@ -12,6 +12,7 @@
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/PathHelpers.h"
@ -2230,6 +2231,59 @@ nsLayoutUtils::GetPopupFrameForEventCoordinates(nsPresContext* aPresContext,
return nullptr;
}
void
nsLayoutUtils::GetContainerAndOffsetAtEvent(nsIPresShell* aPresShell,
const WidgetEvent* aEvent,
nsIContent** aContainer,
int32_t* aOffset)
{
MOZ_ASSERT(aContainer || aOffset);
if (aContainer) {
*aContainer = nullptr;
}
if (aOffset) {
*aOffset = 0;
}
if (!aPresShell) {
return;
}
aPresShell->FlushPendingNotifications(FlushType::Layout);
RefPtr<nsPresContext> presContext = aPresShell->GetPresContext();
if (!presContext) {
return;
}
nsIFrame* targetFrame = presContext->EventStateManager()->GetEventTarget();
if (!targetFrame) {
return;
}
nsPoint point =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, targetFrame);
if (aContainer) {
// TODO: This result may be useful to change to Selection. However, this
// may return improper node (e.g., native anonymous node) for the
// Selection. Perhaps, this should take Selection optionally and
// if it's specified, needs to check if it's proper for the
// Selection.
nsCOMPtr<nsIContent> container =
targetFrame->GetContentOffsetsFromPoint(point).content;
if (container &&
(!container->ChromeOnlyAccess() ||
nsContentUtils::CanAccessNativeAnon())) {
container.forget(aContainer);
}
}
if (aOffset) {
*aOffset = targetFrame->GetContentOffsetsFromPoint(point).offset;
}
}
static void ConstrainToCoordValues(float& aStart, float& aSize)
{
MOZ_ASSERT(aSize >= 0);

View File

@ -776,6 +776,22 @@ public:
nsPresContext* aPresContext,
const mozilla::WidgetEvent* aEvent);
/**
* Get container and offset if aEvent collapses Selection.
* @param aPresShell The PresShell handling aEvent.
* @param aEvent The event having coordinates where you want to
* collapse Selection.
* @param aContainer Returns the container node at the point.
* Set nullptr if you don't need this.
* @param aOffset Returns offset in the container node at the point.
* Set nullptr if you don't need this.
*/
MOZ_CAN_RUN_SCRIPT
static void GetContainerAndOffsetAtEvent(nsIPresShell* aPresShell,
const mozilla::WidgetEvent* aEvent,
nsIContent** aContainer,
int32_t* aOffset);
/**
* Translate from widget coordinates to the view's coordinates
* @param aPresContext the PresContext for the view

View File

@ -632,7 +632,7 @@ nsXULPopupManager::InitTriggerEvent(Event* aEvent, nsIContent* aPopup,
mCachedModifiers = 0;
UIEvent* uiEvent = aEvent ? aEvent->AsUIEvent() : nullptr;
RefPtr<UIEvent> uiEvent = aEvent ? aEvent->AsUIEvent() : nullptr;
if (uiEvent) {
mRangeParent = uiEvent->GetRangeParent();
mRangeOffset = uiEvent->RangeOffset();

View File

@ -714,6 +714,7 @@ protected:
// set the event that was used to trigger the popup, or null to clear the
// event details. aTriggerContent will be set to the target of the event.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
void InitTriggerEvent(mozilla::dom::Event* aEvent, nsIContent* aPopup, nsIContent** aTriggerContent);
// callbacks for ShowPopup and HidePopup as events may be done asynchronously