Bug 788943: Allow TabParents to capture event series for faster dispatch to subprocesses. Implements capturing of touch-event series. r=smaug sr=roc

This commit is contained in:
Chris Jones 2012-09-11 13:05:52 -07:00
Родитель b3325f556e
Коммит ec4f0b7652
7 изменённых файлов: 157 добавлений и 36 удалений

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

@ -1576,6 +1576,42 @@ nsEventStateManager::IsRemoteTarget(nsIContent* target) {
return false;
}
/*static*/ void
nsEventStateManager::MapEventCoordinatesForChildProcess(nsFrameLoader* aFrameLoader,
nsEvent* aEvent)
{
// The "toplevel widget" in child processes is always at position
// 0,0. Map the event coordinates to match that.
nsIFrame* targetFrame = aFrameLoader->GetPrimaryFrameOfOwningContent();
if (!targetFrame) {
return;
}
nsPresContext* presContext = targetFrame->PresContext();
if (aEvent->eventStructType != NS_TOUCH_EVENT) {
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
targetFrame);
aEvent->refPoint = pt.ToNearestPixels(presContext->AppUnitsPerDevPixel());
} else {
aEvent->refPoint = nsIntPoint();
// Find out how far we're offset from the nearest widget.
nsPoint offset =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, targetFrame);
nsIntPoint intOffset =
offset.ToNearestPixels(presContext->AppUnitsPerDevPixel());
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
// Then offset all the touch points by that distance, to put them
// in the space where top-left is 0,0.
const nsTArray<nsCOMPtr<nsIDOMTouch> >& touches = touchEvent->touches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
nsIDOMTouch* touch = touches[i];
if (touch) {
touch->mRefPoint += intOffset;
}
}
}
}
bool
CrossProcessSafeEvent(const nsEvent& aEvent)
{
@ -1689,32 +1725,7 @@ nsEventStateManager::HandleCrossProcessEvent(nsEvent *aEvent,
continue;
}
// The "toplevel widget" in content processes is always at position
// 0,0. Map the event coordinates to match that.
if (aEvent->eventStructType != NS_TOUCH_EVENT) {
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
aTargetFrame);
aEvent->refPoint =
pt.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
} else {
nsIFrame* targetFrame = frameLoader->GetPrimaryFrameOfOwningContent();
aEvent->refPoint = nsIntPoint();
// Find out how far we're offset from the nearest widget.
nsPoint offset =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, targetFrame);
nsIntPoint intOffset =
offset.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
// Then offset all the touch points by that distance, to put them
// in the space where top-left is 0,0.
const nsTArray<nsCOMPtr<nsIDOMTouch> >& touches = touchEvent->touches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
nsIDOMTouch* touch = touches[i];
if (touch) {
touch->mRefPoint += intOffset;
}
}
}
MapEventCoordinatesForChildProcess(frameLoader, aEvent);
dispatched |= DispatchCrossProcessEvent(aEvent, frameLoader, aStatus);
}

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

@ -204,6 +204,9 @@ public:
static bool IsRemoteTarget(nsIContent* aTarget);
static void MapEventCoordinatesForChildProcess(nsFrameLoader* aFrameLoader,
nsEvent* aEvent);
// Holds the point in screen coords that a mouse event was dispatched to,
// before we went into pointer lock mode. This is constantly updated while
// the pointer is not locked, but we don't update it while the pointer is

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

@ -25,6 +25,7 @@
#include "nsContentUtils.h"
#include "nsDebug.h"
#include "nsEventDispatcher.h"
#include "nsEventStateManager.h"
#include "nsFocusManager.h"
#include "nsFrameLoader.h"
#include "nsIContent.h"
@ -66,6 +67,8 @@ using namespace mozilla::dom::indexedDB;
namespace mozilla {
namespace dom {
TabParent* sEventCapturer;
TabParent *TabParent::mIMETabParent = nullptr;
NS_IMPL_ISUPPORTS3(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI)
@ -79,6 +82,7 @@ TabParent::TabParent(mozIApplication* aApp, bool aIsBrowserElement)
, mIMECompositionEnding(false)
, mIMECompositionStart(0)
, mIMESeqno(0)
, mEventCaptureDepth(0)
, mDPI(0)
, mActive(false)
, mIsBrowserElement(aIsBrowserElement)
@ -121,8 +125,12 @@ TabParent::Recv__delete__()
void
TabParent::ActorDestroy(ActorDestroyReason why)
{
if (mIMETabParent == this)
if (sEventCapturer == this) {
sEventCapturer = nullptr;
}
if (mIMETabParent == this) {
mIMETabParent = nullptr;
}
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (frameLoader) {
frameLoader->DestroyChild();
@ -361,21 +369,72 @@ bool TabParent::SendRealKeyEvent(nsKeyEvent& event)
bool TabParent::SendRealTouchEvent(nsTouchEvent& event)
{
if (event.message == NS_TOUCH_START) {
MOZ_ASSERT((!sEventCapturer && mEventCaptureDepth == 0) ||
(sEventCapturer == this && mEventCaptureDepth > 0));
// We want to capture all remaining touch events in this series
// for fast-path dispatch.
sEventCapturer = this;
++mEventCaptureDepth;
}
nsTouchEvent e(event);
// PresShell::HandleEventInternal adds touches on touch end/cancel.
// PresShell::HandleEventInternal adds touches on touch end/cancel,
// when we're not capturing raw events from the widget backend.
// This hack filters those out. Bug 785554
if (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL) {
if (sEventCapturer != this &&
(event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL)) {
for (int i = e.touches.Length() - 1; i >= 0; i--) {
if (!e.touches[i]->mChanged)
e.touches.RemoveElementAt(i);
}
}
MaybeForwardEventToRenderFrame(event, &e);
return (e.message == NS_TOUCH_MOVE) ?
PBrowserParent::SendRealTouchMoveEvent(e) :
PBrowserParent::SendRealTouchEvent(e);
}
/*static*/ TabParent*
TabParent::GetEventCapturer()
{
return sEventCapturer;
}
bool
TabParent::TryCapture(const nsGUIEvent& aEvent)
{
MOZ_ASSERT(sEventCapturer == this && mEventCaptureDepth > 0);
if (aEvent.eventStructType != NS_TOUCH_EVENT) {
// Only capture of touch events is implemented, for now.
return false;
}
nsTouchEvent event(static_cast<const nsTouchEvent&>(aEvent));
bool isTouchPointUp = (event.message == NS_TOUCH_END ||
event.message == NS_TOUCH_CANCEL);
if (event.message == NS_TOUCH_START || isTouchPointUp) {
// Let the DOM see touch start/end events so that its touch-point
// state stays consistent.
if (isTouchPointUp && 0 == --mEventCaptureDepth) {
// All event series are un-captured, don't try to catch any
// more.
sEventCapturer = nullptr;
}
return false;
}
// Adjust the widget coordinates to be relative to our frame.
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
nsEventStateManager::MapEventCoordinatesForChildProcess(frameLoader, &event);
SendRealTouchEvent(event);
return true;
}
bool
TabParent::RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,

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

@ -66,6 +66,30 @@ public:
mozIApplication* GetApp() { return mApp; }
bool IsBrowserElement() { return mIsBrowserElement; }
/**
* Return the TabParent that has decided it wants to capture an
* event series for fast-path dispatch to its subprocess, if one
* has.
*
* DOM event dispatch and widget are free to ignore capture
* requests from TabParents; the end result wrt remote content is
* (must be) always the same, albeit usually slower without
* subprocess capturing. This allows frontends/widget backends to
* "opt in" to faster cross-process dispatch.
*/
static TabParent* GetEventCapturer();
/**
* If this is the current event capturer, give this a chance to
* capture the event. If it was captured, return true, false
* otherwise. Un-captured events should follow normal DOM
* dispatch; captured events should result in no further
* processing from the caller of TryCapture().
*
* It's an error to call TryCapture() if this isn't the event
* capturer.
*/
bool TryCapture(const nsGUIEvent& aEvent);
void Destroy();
virtual bool RecvMoveFocus(const bool& aForward);
@ -246,6 +270,9 @@ protected:
uint32_t mIMECompositionStart;
uint32_t mIMESeqno;
// The number of event series we're currently capturing.
int32_t mEventCaptureDepth;
float mDPI;
bool mActive;
bool mIsBrowserElement;

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

@ -154,7 +154,7 @@ addDOMTouch(UserInputData& data, nsTouchEvent& event, int i)
}
static nsEventStatus
sendTouchEvent(UserInputData& data)
sendTouchEvent(UserInputData& data, bool* captured)
{
uint32_t msg;
int32_t action = data.action & AMOTION_EVENT_ACTION_MASK;
@ -190,7 +190,7 @@ sendTouchEvent(UserInputData& data)
addDOMTouch(data, event, i);
}
return nsWindow::DispatchInputEvent(event);
return nsWindow::DispatchInputEvent(event, captured);
}
static nsEventStatus
@ -435,7 +435,11 @@ GeckoInputDispatcher::dispatchOnce()
nsEventStatus status = nsEventStatus_eIgnore;
if ((data.action & AMOTION_EVENT_ACTION_MASK) !=
AMOTION_EVENT_ACTION_HOVER_MOVE) {
status = sendTouchEvent(data);
bool captured;
status = sendTouchEvent(data, &captured);
if (captured) {
return;
}
}
uint32_t msg;

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

@ -20,6 +20,7 @@
#include "android/log.h"
#include "ui/FramebufferNativeWindow.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/Hal.h"
#include "mozilla/Preferences.h"
#include "mozilla/FileUtils.h"
@ -283,15 +284,30 @@ nsWindow::DoDraw(void)
}
nsEventStatus
nsWindow::DispatchInputEvent(nsGUIEvent &aEvent)
nsWindow::DispatchInputEvent(nsGUIEvent &aEvent, bool* aWasCaptured)
{
if (!gFocusedWindow)
if (aWasCaptured) {
*aWasCaptured = false;
}
if (!gFocusedWindow) {
return nsEventStatus_eIgnore;
}
gFocusedWindow->UserActivity();
nsEventStatus status;
aEvent.widget = gFocusedWindow;
if (TabParent* capturer = TabParent::GetEventCapturer()) {
bool captured = capturer->TryCapture(aEvent);
if (aWasCaptured) {
*aWasCaptured = captured;
}
if (captured) {
return nsEventStatus_eConsumeNoDefault;
}
}
nsEventStatus status;
gFocusedWindow->DispatchEvent(&aEvent, status);
return status;
}

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

@ -46,7 +46,8 @@ public:
virtual ~nsWindow();
static void DoDraw(void);
static nsEventStatus DispatchInputEvent(nsGUIEvent &aEvent);
static nsEventStatus DispatchInputEvent(nsGUIEvent &aEvent,
bool* aWasCaptured = nullptr);
NS_IMETHOD Create(nsIWidget *aParent,
void *aNativeParent,