Bug 1146349 - Wire up native event synthesization in child processes. r=smaug

This commit is contained in:
Kartikaya Gupta 2015-04-14 11:36:36 -04:00
parent a7f747bfcb
commit 595f53686c
10 changed files with 438 additions and 45 deletions

View File

@ -59,6 +59,7 @@ using mozilla::Modifiers from "mozilla/EventForwards.h";
using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
using mozilla::WritingMode from "mozilla/WritingModes.h";
using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
using nsIWidget::TouchPointerState from "nsIWidget.h";
namespace mozilla {
namespace dom {
@ -334,14 +335,6 @@ parent:
sync IsParentWindowMainWidgetVisible() returns (bool visible);
/**
* Content process forward from PuppetWidget for synth mouse move
* events.
*
* aPoint a synth point relative to the window
*/
sync SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint);
/**
* Returns the offset of this tab from the top level window
* origin in device pixels.
@ -491,6 +484,41 @@ parent:
sync RequestNativeKeyBindings(WidgetKeyboardEvent event)
returns (MaybeNativeKeyBinding bindings);
SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
int32_t aNativeKeyCode,
uint32_t aModifierFlags,
nsString aCharacters,
nsString aUnmodifiedCharacters,
uint64_t aObserverId);
SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
uint32_t aModifierFlags,
uint64_t aObserverId);
SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
uint64_t aObserverId);
SynthesizeNativeMouseScrollEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
double aDeltaX,
double aDeltaY,
double aDeltaZ,
uint32_t aModifierFlags,
uint32_t aAdditionalFlags,
uint64_t aObserverId);
SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
nsIntPoint aPointerScreenPoint,
double aPointerPressure,
uint32_t aPointerOrientation,
uint64_t aObserverId);
SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint,
bool aLongTap,
uint64_t aObserverId);
ClearNativeTouchSequence(uint64_t aObserverId);
child:
NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
parent:
/**
* Child informs the parent that the graphics objects are ready for
* compositing. This is sent when all pending changes have been

View File

@ -2469,6 +2469,14 @@ TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache,
}
}
bool
TabChild::RecvNativeSynthesisResponse(const uint64_t& aObserverId,
const nsCString& aResponse)
{
mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId, aResponse.get());
return true;
}
bool
TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
const MaybeNativeKeyBinding& aBindings)

View File

@ -371,6 +371,8 @@ public:
const bool& aPreventDefault) override;
virtual bool RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId,
const nsString& aEvent) override;
virtual bool RecvNativeSynthesisResponse(const uint64_t& aObserverId,
const nsCString& aResponse) override;
virtual bool RecvCompositionEvent(const mozilla::WidgetCompositionEvent& event) override;
virtual bool RecvSelectionEvent(const mozilla::WidgetSelectionEvent& event) override;
virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture) override;

View File

@ -1346,6 +1346,177 @@ TabParent::RecvRequestNativeKeyBindings(const WidgetKeyboardEvent& aEvent,
return true;
}
class SynthesizedEventObserver : public nsIObserver
{
NS_DECL_ISUPPORTS
public:
SynthesizedEventObserver(TabParent* aTabParent, const uint64_t& aObserverId)
: mTabParent(aTabParent)
, mObserverId(aObserverId)
{
MOZ_ASSERT(mTabParent);
}
NS_IMETHODIMP Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!mTabParent) {
// We already sent the notification
return NS_OK;
}
if (!mTabParent->SendNativeSynthesisResponse(mObserverId, nsCString(aTopic))) {
NS_WARNING("Unable to send native event synthesization response!");
}
// Null out tabparent to indicate we already sent the response
mTabParent = nullptr;
return NS_OK;
}
private:
virtual ~SynthesizedEventObserver() { }
nsRefPtr<TabParent> mTabParent;
uint64_t mObserverId;
};
NS_IMPL_ISUPPORTS(SynthesizedEventObserver, nsIObserver)
class MOZ_STACK_CLASS AutoSynthesizedEventResponder
{
public:
AutoSynthesizedEventResponder(TabParent* aTabParent,
const uint64_t& aObserverId,
const char* aTopic)
: mObserver(new SynthesizedEventObserver(aTabParent, aObserverId))
, mTopic(aTopic)
{ }
~AutoSynthesizedEventResponder()
{
// This may be a no-op if the observer already sent a response.
mObserver->Observe(nullptr, mTopic, nullptr);
}
nsIObserver* GetObserver()
{
return mObserver;
}
private:
nsCOMPtr<nsIObserver> mObserver;
const char* mTopic;
};
bool
TabParent::RecvSynthesizeNativeKeyEvent(const int32_t& aNativeKeyboardLayout,
const int32_t& aNativeKeyCode,
const uint32_t& aModifierFlags,
const nsString& aCharacters,
const nsString& aUnmodifiedCharacters,
const uint64_t& aObserverId)
{
AutoSynthesizedEventResponder responder(this, aObserverId, "keyevent");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeKeyEvent(aNativeKeyboardLayout, aNativeKeyCode,
aModifierFlags, aCharacters, aUnmodifiedCharacters,
responder.GetObserver());
}
return true;
}
bool
TabParent::RecvSynthesizeNativeMouseEvent(const LayoutDeviceIntPoint& aPoint,
const uint32_t& aNativeMessage,
const uint32_t& aModifierFlags,
const uint64_t& aObserverId)
{
AutoSynthesizedEventResponder responder(this, aObserverId, "mouseevent");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeMouseEvent(aPoint, aNativeMessage, aModifierFlags,
responder.GetObserver());
}
return true;
}
bool
TabParent::RecvSynthesizeNativeMouseMove(const LayoutDeviceIntPoint& aPoint,
const uint64_t& aObserverId)
{
AutoSynthesizedEventResponder responder(this, aObserverId, "mousemove");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeMouseMove(aPoint, responder.GetObserver());
}
return true;
}
bool
TabParent::RecvSynthesizeNativeMouseScrollEvent(const LayoutDeviceIntPoint& aPoint,
const uint32_t& aNativeMessage,
const double& aDeltaX,
const double& aDeltaY,
const double& aDeltaZ,
const uint32_t& aModifierFlags,
const uint32_t& aAdditionalFlags,
const uint64_t& aObserverId)
{
AutoSynthesizedEventResponder responder(this, aObserverId, "mousescrollevent");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeMouseScrollEvent(aPoint, aNativeMessage,
aDeltaX, aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags,
responder.GetObserver());
}
return true;
}
bool
TabParent::RecvSynthesizeNativeTouchPoint(const uint32_t& aPointerId,
const TouchPointerState& aPointerState,
const nsIntPoint& aPointerScreenPoint,
const double& aPointerPressure,
const uint32_t& aPointerOrientation,
const uint64_t& aObserverId)
{
AutoSynthesizedEventResponder responder(this, aObserverId, "touchpoint");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeTouchPoint(aPointerId, aPointerState, aPointerScreenPoint,
aPointerPressure, aPointerOrientation, responder.GetObserver());
}
return true;
}
bool
TabParent::RecvSynthesizeNativeTouchTap(const nsIntPoint& aPointerScreenPoint,
const bool& aLongTap,
const uint64_t& aObserverId)
{
AutoSynthesizedEventResponder responder(this, aObserverId, "touchtap");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeTouchTap(aPointerScreenPoint, aLongTap,
responder.GetObserver());
}
return true;
}
bool
TabParent::RecvClearNativeTouchSequence(const uint64_t& aObserverId)
{
AutoSynthesizedEventResponder responder(this, aObserverId, "cleartouch");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->ClearNativeTouchSequence(responder.GetObserver());
}
return true;
}
bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event)
{
if (mIsDestroyed) {
@ -2248,17 +2419,6 @@ TabParent::RecvIsParentWindowMainWidgetVisible(bool* aIsVisible)
return NS_SUCCEEDED(rv);
}
bool
TabParent::RecvSynthesizeNativeMouseMove(const mozilla::LayoutDeviceIntPoint& aPoint)
{
// The widget associated with the browser window
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeMouseMove(aPoint, nullptr);
}
return true;
}
bool
TabParent::RecvGetDPI(float* aValue)
{

View File

@ -206,7 +206,6 @@ public:
virtual bool RecvSetBackgroundColor(const nscolor& aValue) override;
virtual bool RecvSetStatus(const uint32_t& aType, const nsString& aStatus) override;
virtual bool RecvIsParentWindowMainWidgetVisible(bool* aIsVisible) override;
virtual bool RecvSynthesizeNativeMouseMove(const mozilla::LayoutDeviceIntPoint& aPoint) override;
virtual bool RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip) override;
virtual bool RecvHideTooltip() override;
virtual bool RecvGetTabOffset(LayoutDeviceIntPoint* aPoint) override;
@ -271,6 +270,37 @@ public:
virtual bool RecvRequestNativeKeyBindings(const mozilla::WidgetKeyboardEvent& aEvent,
MaybeNativeKeyBinding* aBindings) override;
virtual bool RecvSynthesizeNativeKeyEvent(const int32_t& aNativeKeyboardLayout,
const int32_t& aNativeKeyCode,
const uint32_t& aModifierFlags,
const nsString& aCharacters,
const nsString& aUnmodifiedCharacters,
const uint64_t& aObserverId) override;
virtual bool RecvSynthesizeNativeMouseEvent(const LayoutDeviceIntPoint& aPoint,
const uint32_t& aNativeMessage,
const uint32_t& aModifierFlags,
const uint64_t& aObserverId) override;
virtual bool RecvSynthesizeNativeMouseMove(const LayoutDeviceIntPoint& aPoint,
const uint64_t& aObserverId) override;
virtual bool RecvSynthesizeNativeMouseScrollEvent(const LayoutDeviceIntPoint& aPoint,
const uint32_t& aNativeMessage,
const double& aDeltaX,
const double& aDeltaY,
const double& aDeltaZ,
const uint32_t& aModifierFlags,
const uint32_t& aAdditionalFlags,
const uint64_t& aObserverId) override;
virtual bool RecvSynthesizeNativeTouchPoint(const uint32_t& aPointerId,
const TouchPointerState& aPointerState,
const nsIntPoint& aPointerScreenPoint,
const double& aPointerPressure,
const uint32_t& aPointerOrientation,
const uint64_t& aObserverId) override;
virtual bool RecvSynthesizeNativeTouchTap(const nsIntPoint& aPointerScreenPoint,
const bool& aLongTap,
const uint64_t& aObserverId) override;
virtual bool RecvClearNativeTouchSequence(const uint64_t& aObserverId) override;
void SendMouseEvent(const nsAString& aType, float aX, float aY,
int32_t aButton, int32_t aClickCount,
int32_t aModifiers, bool aIgnoreRootScrollFrame);

View File

@ -22,6 +22,7 @@
#include <stdint.h>
#include "nsID.h"
#include "nsIWidget.h"
#include "nsMemory.h"
#include "nsString.h"
#include "nsTArray.h"
@ -743,6 +744,13 @@ struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
}
};
template <>
struct ParamTraits<nsIWidget::TouchPointerState>
: public BitFlagsEnumSerializer<nsIWidget::TouchPointerState,
nsIWidget::TouchPointerState::ALL_BITS>
{
};
} /* namespace IPC */
#endif /* __IPC_GLUE_IPCMESSAGEUTILS_H__ */

View File

@ -376,6 +376,114 @@ PuppetWidget::DispatchAPZAwareEvent(WidgetInputEvent* aEvent)
return nsEventStatus_eIgnore;
}
nsresult
PuppetWidget::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
int32_t aNativeKeyCode,
uint32_t aModifierFlags,
const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters,
nsIObserver* aObserver)
{
AutoObserverNotifier notifier(aObserver, "keyevent");
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendSynthesizeNativeKeyEvent(aNativeKeyboardLayout, aNativeKeyCode,
aModifierFlags, nsString(aCharacters), nsString(aUnmodifiedCharacters),
notifier.SaveObserver());
return NS_OK;
}
nsresult
PuppetWidget::SynthesizeNativeMouseEvent(mozilla::LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
uint32_t aModifierFlags,
nsIObserver* aObserver)
{
AutoObserverNotifier notifier(aObserver, "mouseevent");
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendSynthesizeNativeMouseEvent(aPoint, aNativeMessage,
aModifierFlags, notifier.SaveObserver());
return NS_OK;
}
nsresult
PuppetWidget::SynthesizeNativeMouseMove(mozilla::LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver)
{
AutoObserverNotifier notifier(aObserver, "mousemove");
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendSynthesizeNativeMouseMove(aPoint, notifier.SaveObserver());
return NS_OK;
}
nsresult
PuppetWidget::SynthesizeNativeMouseScrollEvent(mozilla::LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
double aDeltaX,
double aDeltaY,
double aDeltaZ,
uint32_t aModifierFlags,
uint32_t aAdditionalFlags,
nsIObserver* aObserver)
{
AutoObserverNotifier notifier(aObserver, "mousescrollevent");
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendSynthesizeNativeMouseScrollEvent(aPoint, aNativeMessage,
aDeltaX, aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags,
notifier.SaveObserver());
return NS_OK;
}
nsresult
PuppetWidget::SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
nsIntPoint aPointerScreenPoint,
double aPointerPressure,
uint32_t aPointerOrientation,
nsIObserver* aObserver)
{
AutoObserverNotifier notifier(aObserver, "touchpoint");
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendSynthesizeNativeTouchPoint(aPointerId, aPointerState,
aPointerScreenPoint, aPointerPressure, aPointerOrientation,
notifier.SaveObserver());
return NS_OK;
}
nsresult
PuppetWidget::SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint,
bool aLongTap,
nsIObserver* aObserver)
{
AutoObserverNotifier notifier(aObserver, "touchtap");
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendSynthesizeNativeTouchTap(aPointerScreenPoint, aLongTap,
notifier.SaveObserver());
return NS_OK;
}
nsresult
PuppetWidget::ClearNativeTouchSequence(nsIObserver* aObserver)
{
AutoObserverNotifier notifier(aObserver, "cleartouch");
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendClearNativeTouchSequence(notifier.SaveObserver());
return NS_OK;
}
NS_IMETHODIMP_(bool)
PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
const mozilla::WidgetKeyboardEvent& aEvent,
@ -854,18 +962,6 @@ PuppetWidget::SetCursor(nsCursor aCursor)
return NS_OK;
}
nsresult
PuppetWidget::SynthesizeNativeMouseMove(mozilla::LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver)
{
//XXX Do something wtih aObserver (will happen in a later patch)
if (mTabChild &&
!mTabChild->SendSynthesizeNativeMouseMove(aPoint)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
PuppetWidget::Paint()
{

View File

@ -130,12 +130,6 @@ public:
virtual mozilla::LayoutDeviceIntPoint WidgetToScreenOffset() override
{ return LayoutDeviceIntPoint::FromUntyped(GetWindowPosition() + GetChromeDimensions()); }
// Synthesized mouse events we need to forwarded to chrome. Event
// state manager uses this api to position the mouse in the center
// of the window for pointer lock.
virtual nsresult SynthesizeNativeMouseMove(mozilla::LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override;
void InitEvent(WidgetGUIEvent& aEvent, nsIntPoint* aPoint = nullptr);
NS_IMETHOD DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) override;
@ -217,6 +211,37 @@ public:
NS_IMETHOD SetPluginFocused(bool& aFocused) override;
virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
int32_t aNativeKeyCode,
uint32_t aModifierFlags,
const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseEvent(mozilla::LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
uint32_t aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseMove(mozilla::LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseScrollEvent(mozilla::LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
double aDeltaX,
double aDeltaY,
double aDeltaZ,
uint32_t aModifierFlags,
uint32_t aAdditionalFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
nsIntPoint aPointerScreenPoint,
double aPointerPressure,
uint32_t aPointerOrientation,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint,
bool aLongTap,
nsIObserver* aObserver) override;
virtual nsresult ClearNativeTouchSequence(nsIObserver* aObserver) override;
protected:
bool mEnabled;
bool mVisible;

View File

@ -94,6 +94,10 @@ bool gDisableNativeTheme = false;
#define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
int32_t nsIWidget::sPointerIdCounter = 0;
// Some statics from nsIWidget.h
/*static*/ uint64_t AutoObserverNotifier::sObserverId = 0;
/*static*/ nsDataHashtable<nsUint64HashKey, nsCOMPtr<nsIObserver>> AutoObserverNotifier::sSavedObservers;
nsAutoRollup::nsAutoRollup()
{
// remember if mLastRollup was null, and only clear it upon destruction

View File

@ -23,6 +23,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/gfx/Point.h"
#include "nsDataHashtable.h"
#include "nsIObserver.h"
#include "Units.h"
@ -727,6 +728,17 @@ struct AutoObserverNotifier {
mObserver = nullptr;
}
uint64_t SaveObserver()
{
if (!mObserver) {
return 0;
}
uint64_t observerId = ++sObserverId;
sSavedObservers.Put(observerId, mObserver);
SkipNotification();
return observerId;
}
~AutoObserverNotifier()
{
if (mObserver) {
@ -734,9 +746,26 @@ struct AutoObserverNotifier {
}
}
static void NotifySavedObserver(const uint64_t& aObserverId,
const char* aTopic)
{
nsCOMPtr<nsIObserver> observer = sSavedObservers.Get(aObserverId);
if (!observer) {
MOZ_ASSERT(aObserverId == 0, "We should always find a saved observer for nonzero IDs");
return;
}
sSavedObservers.Remove(aObserverId);
observer->Observe(nullptr, aTopic, nullptr);
}
private:
nsCOMPtr<nsIObserver> mObserver;
const char* mTopic;
private:
static uint64_t sObserverId;
static nsDataHashtable<nsUint64HashKey, nsCOMPtr<nsIObserver>> sSavedObservers;
};
} // namespace widget
@ -1958,16 +1987,19 @@ class nsIWidget : public nsISupports {
*/
enum TouchPointerState {
// The pointer is in a hover state above the digitizer
TOUCH_HOVER = 0x01,
TOUCH_HOVER = (1 << 0),
// The pointer is in contact with the digitizer
TOUCH_CONTACT = 0x02,
TOUCH_CONTACT = (1 << 1),
// The pointer has been removed from the digitizer detection area
TOUCH_REMOVE = 0x04,
TOUCH_REMOVE = (1 << 2),
// The pointer has been canceled. Will cancel any pending os level
// gestures that would triggered as a result of completion of the
// input sequence. This may not cancel moz platform related events
// that might get tirggered by input already delivered.
TOUCH_CANCEL = 0x08
TOUCH_CANCEL = (1 << 3),
// ALL_BITS used for validity checking during IPC serialization
ALL_BITS = (1 << 4) - 1
};
/*
@ -2000,9 +2032,9 @@ class nsIWidget : public nsISupports {
* @param aObserver The observer that will get notified once the events
* have been dispatched.
*/
nsresult SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint,
bool aLongTap,
nsIObserver* aObserver);
virtual nsresult SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint,
bool aLongTap,
nsIObserver* aObserver);
/*
* Cancels all active simulated touch input points and pending long taps.