Bug 796275 - Context menu fires on wrong target out of process. r=cjones

This commit is contained in:
Andrea Marchesini 2012-11-08 14:35:02 -05:00
parent ea76afa081
commit d2e9fb6a55
10 changed files with 119 additions and 5 deletions

View File

@ -307,6 +307,13 @@ child:
*/
HandleSingleTap(nsIntPoint point);
/**
* Requests handling of a long tap. |point| is in CSS pixels, relative to
* the scroll offset. This message is expected to send a "contextmenu"
* events at this point.
*/
HandleLongTap(nsIntPoint point);
/**
* Sending an activate message moves focus to the child.
*/

View File

@ -1250,6 +1250,22 @@ TabChild::RecvHandleSingleTap(const nsIntPoint& aPoint)
return true;
}
bool
TabChild::RecvHandleLongTap(const nsIntPoint& aPoint)
{
if (!mCx || !mTabChildGlobal) {
return true;
}
RecvMouseEvent(NS_LITERAL_STRING("contextmenu"), aPoint.x, aPoint.y,
2 /* Right button */,
1 /* Click count */,
0 /* Modifiers */,
false /* Ignore root scroll frame */);
return true;
}
bool
TabChild::RecvActivate()
{

View File

@ -200,6 +200,7 @@ public:
virtual bool RecvUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
virtual bool RecvHandleDoubleTap(const nsIntPoint& aPoint);
virtual bool RecvHandleSingleTap(const nsIntPoint& aPoint);
virtual bool RecvHandleLongTap(const nsIntPoint& aPoint);
virtual bool RecvActivate();
virtual bool RecvDeactivate();
virtual bool RecvMouseEvent(const nsString& aType,

View File

@ -266,6 +266,11 @@ void TabParent::HandleSingleTap(const nsIntPoint& aPoint)
unused << SendHandleSingleTap(aPoint);
}
void TabParent::HandleLongTap(const nsIntPoint& aPoint)
{
unused << SendHandleLongTap(aPoint);
}
void
TabParent::Activate()
{

View File

@ -162,6 +162,7 @@ public:
void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
void HandleDoubleTap(const nsIntPoint& aPoint);
void HandleSingleTap(const nsIntPoint& aPoint);
void HandleLongTap(const nsIntPoint& aPoint);
void Activate();
void Deactivate();

View File

@ -537,7 +537,17 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
}
nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) {
// XXX: Implement this.
if (mGeckoContentController) {
MonitorAutoLock monitor(mMonitor);
gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
resolution);
mGeckoContentController->HandleLongTap(nsIntPoint(NS_lround(point.x),
NS_lround(point.y)));
return nsEventStatus_eConsumeNoDefault;
}
return nsEventStatus_eIgnore;
}

View File

@ -38,6 +38,12 @@ public:
*/
virtual void HandleSingleTap(const nsIntPoint& aPoint) = 0;
/**
* Requests handling a long tap. |aPoint| is in CSS pixels, relative to the
* current scroll offset.
*/
virtual void HandleLongTap(const nsIntPoint& aPoint) = 0;
GeckoContentController() {}
virtual ~GeckoContentController() {}
};

View File

@ -10,6 +10,8 @@
#include "GestureEventListener.h"
#include "AsyncPanZoomController.h"
#include "mozilla/Preferences.h"
namespace mozilla {
namespace layers {
@ -47,6 +49,11 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
}
const MultiTouchInput& event = static_cast<const MultiTouchInput&>(aEvent);
// Cache the current event since it may become the single or long tap that we
// send.
mLastTouchInput = event;
switch (event.mType)
{
case MultiTouchInput::MULTITOUCH_START:
@ -75,6 +82,14 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
mTouchStartPosition = event.mTouches[0].mScreenPoint;
if (mState == GESTURE_NONE) {
mState = GESTURE_WAITING_SINGLE_TAP;
mLongTapTimeoutTask =
NewRunnableMethod(this, &GestureEventListener::TimeoutLongTap);
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
mLongTapTimeoutTask,
Preferences::GetInt("ui.click_hold_context_menus.delay", 500));
}
} else if (length == 2) {
// Another finger has been added; it can't be a tap anymore.
@ -129,6 +144,8 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
HandleDoubleTap(event);
mState = GESTURE_NONE;
} else if (mState == GESTURE_WAITING_SINGLE_TAP) {
mLongTapTimeoutTask->Cancel();
HandleSingleTapUpEvent(event);
// We were not waiting for anything but a single tap has happened that
@ -136,10 +153,6 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
// a double tap, send a single tap instead.
mState = GESTURE_WAITING_DOUBLE_TAP;
// Cache the current event since it may become the single tap that we
// send.
mLastTouchInput = event;
mDoubleTapTimeoutTask =
NewRunnableMethod(this, &GestureEventListener::TimeoutDoubleTap);
@ -260,6 +273,12 @@ nsEventStatus GestureEventListener::HandleSingleTapConfirmedEvent(const MultiTou
return mAsyncPanZoomController->ReceiveInputEvent(tapEvent);
}
nsEventStatus GestureEventListener::HandleLongTapEvent(const MultiTouchInput& aEvent)
{
TapGestureInput tapEvent(TapGestureInput::TAPGESTURE_LONG, aEvent.mTime, aEvent.mTouches[0].mScreenPoint);
return mAsyncPanZoomController->ReceiveInputEvent(tapEvent);
}
nsEventStatus GestureEventListener::HandleTapCancel(const MultiTouchInput& aEvent)
{
mTapStartTime = 0;
@ -267,6 +286,10 @@ nsEventStatus GestureEventListener::HandleTapCancel(const MultiTouchInput& aEven
switch (mState)
{
case GESTURE_WAITING_SINGLE_TAP:
mLongTapTimeoutTask->Cancel();
mState = GESTURE_NONE;
break;
case GESTURE_WAITING_DOUBLE_TAP:
mState = GESTURE_NONE;
break;
@ -294,6 +317,16 @@ void GestureEventListener::TimeoutDoubleTap()
}
}
void GestureEventListener::TimeoutLongTap()
{
// If the tap has not been released, this is a long press.
if (mState == GESTURE_WAITING_SINGLE_TAP) {
mState = GESTURE_NONE;
HandleLongTapEvent(mLastTouchInput);
}
}
AsyncPanZoomController* GestureEventListener::GetAsyncPanZoomController() {
return mAsyncPanZoomController;
}

View File

@ -104,6 +104,12 @@ protected:
*/
nsEventStatus HandleSingleTapConfirmedEvent(const MultiTouchInput& aEvent);
/**
* Attempts to handle a long tap confirmation. This is what will use
* for context menu.
*/
nsEventStatus HandleLongTapEvent(const MultiTouchInput& aEvent);
/**
* Attempts to handle a tap event cancellation. This happens when we think
* something was a tap but it actually wasn't. In general, this will not
@ -130,6 +136,11 @@ protected:
* has time to tap again (to make a double tap).
*/
void TimeoutDoubleTap();
/**
* Times out a long tap. This should be called a 'long' time after a single
* tap is detected.
*/
void TimeoutLongTap();
nsRefPtr<AsyncPanZoomController> mAsyncPanZoomController;
@ -183,6 +194,13 @@ protected:
*/
CancelableTask *mDoubleTapTimeoutTask;
/**
* Task used to timeout a long tap. This gets posted to the UI thread such
* that it runs a time when a single tap happens. We cache it so that
* we can cancel it if any other touch event happens.
*/
CancelableTask *mLongTapTimeoutTask;
/**
* Position of the last touch starting. This is only valid during an attempt
* to determine if a touch is a tap. This means that it is used in both the

View File

@ -538,6 +538,23 @@ public:
}
}
virtual void HandleLongTap(const nsIntPoint& aPoint) MOZ_OVERRIDE
{
if (MessageLoop::current() != mUILoop) {
// We have to send this message from the "UI thread" (main
// thread).
mUILoop->PostTask(
FROM_HERE,
NewRunnableMethod(this, &RemoteContentController::HandleLongTap,
aPoint));
return;
}
if (mRenderFrame) {
TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
browser->HandleLongTap(aPoint);
}
}
void ClearRenderFrame() { mRenderFrame = nullptr; }
private: