Bug 920036 - Send touch inputs through the APZ before sending them to the gecko thread. r=mwu,dvander,smaug

This commit is contained in:
Kartikaya Gupta 2015-01-15 10:37:54 -05:00
parent 277a11f599
commit 846e3755ae
4 changed files with 83 additions and 41 deletions

View File

@ -2208,7 +2208,11 @@ TabParent::MaybeForwardEventToRenderFrame(WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId)
{
if (aEvent.mClass == eWheelEventClass) {
if (aEvent.mClass == eWheelEventClass
#ifdef MOZ_WIDGET_GONK
|| aEvent.mClass == eTouchEventClass
#endif
) {
// Wheel events must be sent to APZ directly from the widget. New APZ-
// aware events should follow suit and move there as well. However, we
// do need to inform the child process of the correct target and block

View File

@ -24,7 +24,6 @@
#include "gfxPrefs.h"
#include "libui/Input.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Mutex.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TouchEvents.h"
@ -333,21 +332,6 @@ GeckoTouchDispatcher::ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp a
aOutTouch.mTimeStamp = sampleTime;
}
// Some touch events get sent as mouse events. If APZ doesn't capture the event
// and if a touch only has 1 touch input, we can send a mouse event.
void
GeckoTouchDispatcher::DispatchMouseEvent(MultiTouchInput& aMultiTouch,
bool aForwardToChildren)
{
WidgetMouseEvent mouseEvent = aMultiTouch.ToWidgetMouseEvent(nullptr);
if (mouseEvent.message == NS_EVENT_NULL) {
return;
}
mouseEvent.mFlags.mNoCrossProcessBoundaryForwarding = !aForwardToChildren;
nsWindow::DispatchInputEvent(mouseEvent);
}
static bool
IsExpired(const MultiTouchInput& aTouch)
{
@ -372,9 +356,7 @@ GeckoTouchDispatcher::DispatchTouchEvent(MultiTouchInput& aMultiTouch)
return;
}
bool captured = false;
WidgetTouchEvent event = aMultiTouch.ToWidgetTouchEvent(nullptr);
nsEventStatus status = nsWindow::DispatchInputEvent(event, &captured);
nsWindow::DispatchTouchInput(aMultiTouch);
if (mEnabledUniformityInfo && profiler_is_active()) {
const char* touchAction = "Invalid";
@ -395,11 +377,6 @@ GeckoTouchDispatcher::DispatchTouchEvent(MultiTouchInput& aMultiTouch)
TouchDataPayload* payload = new TouchDataPayload(touchPoint);
PROFILER_MARKER_PAYLOAD(touchAction, payload);
}
if (!captured && (aMultiTouch.mTouches.Length() == 1)) {
bool forwardToChildren = status != nsEventStatus_eConsumeNoDefault;
DispatchMouseEvent(aMultiTouch, forwardToChildren);
}
}
} // namespace mozilla

View File

@ -47,6 +47,9 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/InputAPZContext.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/TouchEvents.h"
#include "nsThreadUtils.h"
#include "HwcComposer2D.h"
@ -227,33 +230,89 @@ nsWindow::NotifyVsync(TimeStamp aVsyncTimestamp)
}
}
nsEventStatus
nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent, bool* aWasCaptured)
/*static*/ nsEventStatus
nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent)
{
if (aWasCaptured) {
*aWasCaptured = false;
}
if (!gFocusedWindow) {
return nsEventStatus_eIgnore;
}
gFocusedWindow->UserActivity();
nsEventStatus status;
aEvent.widget = gFocusedWindow;
gFocusedWindow->DispatchEvent(&aEvent, status);
return status;
}
/*static*/ void
nsWindow::DispatchTouchInput(MultiTouchInput& aInput)
{
if (!gFocusedWindow) {
return;
}
gFocusedWindow->UserActivity();
gFocusedWindow->DispatchTouchInputViaAPZ(aInput);
}
void
nsWindow::DispatchTouchInputViaAPZ(MultiTouchInput& aInput)
{
if (!mAPZC) {
// In general mAPZC should not be null, but during initial setup
// it might be, so we handle that case by ignoring touch input there.
return;
}
// First send it through the APZ code
mozilla::layers::ScrollableLayerGuid guid;
uint64_t inputBlockId;
nsEventStatus rv = mAPZC->ReceiveInputEvent(aInput, &guid, &inputBlockId);
// If the APZ says to drop it, then we drop it
if (rv == nsEventStatus_eConsumeNoDefault) {
return;
}
// Convert it to an event we can send to Gecko
WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this);
// If there is an event capturing child process, send it directly there.
// This happens if we already sent a touchstart event through the root
// process hit test and it ended up going to a child process. The event
// capturing process should get all subsequent touch events in the same
// event block. In this case the TryCapture call below will return true,
// and the child process will take care of responding to the event as needed
// so we don't need to do anything else here.
if (TabParent* capturer = TabParent::GetEventCapturer()) {
bool captured = capturer->TryCapture(aEvent);
if (aWasCaptured) {
*aWasCaptured = captured;
}
if (captured) {
return nsEventStatus_eConsumeNoDefault;
InputAPZContext context(guid, inputBlockId);
if (capturer->TryCapture(event)) {
return;
}
}
nsEventStatus status;
gFocusedWindow->DispatchEvent(&aEvent, status);
return status;
// If it didn't get captured, dispatch the event into the gecko root process
// for "normal" flow. The event might get sent to the child process still,
// but if it doesn't we need to notify the APZ of various things. All of
// that happens in DispatchEventForAPZ
rv = DispatchEventForAPZ(&event, guid, inputBlockId);
// Finally, if the touch event had only one touch point, generate a mouse
// event for it and send it through the gecko root process.
// Technically we should not need to do this if the touch event was routed
// to the child process, but that seems to expose a bug in B2G where the
// keyboard doesn't go away in some cases.
// Also for now we're dispatching mouse events from all touch events because
// we need this for click events to work in the chrome process. Once we have
// APZ and ChromeProcessController::HandleSingleTap working for the chrome
// process we shouldn't need to do this at all.
if (event.touches.Length() == 1) {
WidgetMouseEvent mouseEvent = aInput.ToWidgetMouseEvent(this);
if (mouseEvent.message != NS_EVENT_NULL) {
mouseEvent.mFlags.mNoCrossProcessBoundaryForwarding = (rv == nsEventStatus_eConsumeNoDefault);
DispatchEvent(&mouseEvent, rv);
}
}
}
NS_IMETHODIMP

View File

@ -16,6 +16,7 @@
#ifndef nsWindow_h
#define nsWindow_h
#include "InputData.h"
#include "nsBaseWidget.h"
#include "nsRegion.h"
#include "nsIIdleServiceInternal.h"
@ -51,8 +52,8 @@ public:
static void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp);
static void DoDraw(void);
static nsEventStatus DispatchInputEvent(mozilla::WidgetGUIEvent& aEvent,
bool* aWasCaptured = nullptr);
static nsEventStatus DispatchInputEvent(mozilla::WidgetGUIEvent& aEvent);
static void DispatchTouchInput(mozilla::MultiTouchInput& aInput);
NS_IMETHOD Create(nsIWidget *aParent,
void *aNativeParent,
@ -87,6 +88,7 @@ public:
return NS_OK;
}
virtual nsIntPoint WidgetToScreenOffset();
void DispatchTouchInputViaAPZ(mozilla::MultiTouchInput& aInput);
NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
nsEventStatus& aStatus);
NS_IMETHOD CaptureRollupEvents(nsIRollupListener *aListener,