Bug 583976. Part 3 - Automatically forward mouse and key input events to out-of-process content, and add cursor support in PuppetWidget. r=smaug,stechz

This commit is contained in:
Felipe Gomes 2011-06-21 17:32:43 -07:00
parent 00693c144c
commit 9628013f99
15 changed files with 305 additions and 0 deletions

View File

@ -240,6 +240,24 @@ interface nsIFrameLoader : nsISupports
const unsigned long RENDER_MODE_ASYNC_SCROLL = 0x00000001;
attribute unsigned long renderMode;
/**
* The default event mode automatically forwards the events
* handled in nsEventStateManager::HandleCrossProcessEvent to
* the child content process when these events are targeted to
* the remote browser element.
*
* Used primarly for input events (mouse, keyboard)
*/
const unsigned long EVENT_MODE_NORMAL_DISPATCH = 0x00000000;
/**
* With this event mode, it's the application's responsability to
* convert and forward events to the content process
*/
const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001;
attribute unsigned long eventMode;
};
native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);

View File

@ -327,6 +327,7 @@ nsFrameLoader::nsFrameLoader(nsIContent *aOwner, PRBool aNetworkCreated)
, mCurrentRemoteFrame(nsnull)
, mRemoteBrowser(nsnull)
, mRenderMode(RENDER_MODE_DEFAULT)
, mEventMode(EVENT_MODE_NORMAL_DISPATCH)
{
}
@ -1660,6 +1661,20 @@ nsFrameLoader::SetRenderMode(PRUint32 aRenderMode)
return NS_OK;
}
NS_IMETHODIMP
nsFrameLoader::GetEventMode(PRUint32* aEventMode)
{
*aEventMode = mEventMode;
return NS_OK;
}
NS_IMETHODIMP
nsFrameLoader::SetEventMode(PRUint32 aEventMode)
{
mEventMode = aEventMode;
return NS_OK;
}
nsIntSize
nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
{

View File

@ -342,6 +342,10 @@ private:
// RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in
// favor of what content tells.
PRUint32 mRenderMode;
// See nsIFrameLoader.idl. EVENT_MODE_NORMAL_DISPATCH automatically
// forwards some input events to out-of-process content.
PRUint32 mEventMode;
};
#endif

View File

@ -1657,6 +1657,93 @@ nsEventStateManager::HandleAccessKey(nsPresContext* aPresContext,
}// if end. bubble up process
}// end of HandleAccessKey
void
nsEventStateManager::DispatchCrossProcessEvent(nsEvent* aEvent, nsIFrameLoader* frameLoader) {
nsFrameLoader* fml = static_cast<nsFrameLoader*>(frameLoader);
PBrowserParent* remoteBrowser = fml->GetRemoteBrowser();
TabParent* remote = static_cast<TabParent*>(remoteBrowser);
if (!remote) {
return;
}
if (aEvent->eventStructType == NS_MOUSE_EVENT) {
nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
remote->SendRealMouseEvent(*mouseEvent);
}
if (aEvent->eventStructType == NS_KEY_EVENT) {
nsKeyEvent* keyEvent = static_cast<nsKeyEvent*>(aEvent);
remote->SendRealKeyEvent(*keyEvent);
}
if (aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
nsMouseScrollEvent* scrollEvent = static_cast<nsMouseScrollEvent*>(aEvent);
remote->SendMouseScrollEvent(*scrollEvent);
}
}
PRBool
nsEventStateManager::IsRemoteTarget(nsIContent* target) {
return target &&
target->Tag() == nsGkAtoms::browser &&
target->IsXUL() &&
target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
nsGkAtoms::_true, eIgnoreCase);
}
PRBool
nsEventStateManager::HandleCrossProcessEvent(nsEvent *aEvent,
nsIFrame* aTargetFrame,
nsEventStatus *aStatus) {
switch (aEvent->eventStructType) {
case NS_KEY_EVENT:
case NS_MOUSE_SCROLL_EVENT:
break;
case NS_MOUSE_EVENT:
if (aEvent->message == NS_MOUSE_BUTTON_DOWN ||
aEvent->message == NS_MOUSE_BUTTON_UP ||
aEvent->message == NS_MOUSE_MOVE) {
break;
}
default:
return PR_FALSE;
}
nsIContent* target = mCurrentTargetContent;
if (!target && aTargetFrame) {
target = aTargetFrame->GetContent();
}
if (*aStatus == nsEventStatus_eConsumeNoDefault ||
!target ||
!IsRemoteTarget(target)) {
return PR_FALSE;
}
nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(target);
if (!loaderOwner) {
return PR_FALSE;
}
nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
if (!frameLoader) {
return PR_FALSE;
}
PRUint32 eventMode;
frameLoader->GetEventMode(&eventMode);
if (eventMode == nsIFrameLoader::EVENT_MODE_DONT_FORWARD_TO_CHILD) {
return PR_FALSE;
}
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aTargetFrame);
aEvent->refPoint = pt.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
DispatchCrossProcessEvent(aEvent, frameLoader);
return PR_TRUE;
}
//
// CreateClickHoldTimer
@ -2905,6 +2992,8 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
NS_ENSURE_ARG(aPresContext);
NS_ENSURE_ARG_POINTER(aStatus);
HandleCrossProcessEvent(aEvent, aTargetFrame, aStatus);
mCurrentTarget = aTargetFrame;
mCurrentTargetContent = nsnull;
@ -3420,6 +3509,10 @@ nsEventStateManager::UpdateCursor(nsPresContext* aPresContext,
nsEvent* aEvent, nsIFrame* aTargetFrame,
nsEventStatus* aStatus)
{
if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
return;
}
PRInt32 cursor = NS_STYLE_CURSOR_DEFAULT;
imgIContainer* container = nsnull;
PRBool haveHotspot = PR_FALSE;

View File

@ -49,6 +49,7 @@
#include "nsCOMPtr.h"
#include "nsIDocument.h"
#include "nsCOMArray.h"
#include "nsIFrameLoader.h"
#include "nsIFrame.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIMarkupDocumentViewer.h"
@ -427,6 +428,12 @@ protected:
mozilla::dom::TabParent *GetCrossProcessTarget();
PRBool IsTargetCrossProcess(nsGUIEvent *aEvent);
void DispatchCrossProcessEvent(nsEvent* aEvent, nsIFrameLoader* remote);
PRBool IsRemoteTarget(nsIContent* target);
PRBool HandleCrossProcessEvent(nsEvent *aEvent,
nsIFrame* aTargetFrame,
nsEventStatus *aStatus);
private:
static inline void DoStateChange(mozilla::dom::Element* aElement,
nsEventStates aState, PRBool aAddState);

View File

@ -58,6 +58,9 @@ using nsQueryContentEvent;
using nsRect;
using nsSelectionEvent;
using nsTextEvent;
using nsMouseEvent;
using nsMouseScrollEvent;
using nsKeyEvent;
using RemoteDOMEvent;
namespace mozilla {
@ -180,6 +183,8 @@ parent:
*/
sync GetDPI() returns (float value);
SetCursor(PRUint32 value);
PContentPermissionRequest(nsCString aType, URI uri);
PContentDialog(PRUint32 aType, nsCString aName, nsCString aFeatures,
@ -254,6 +259,10 @@ child:
PRInt32 aModifiers,
bool aIgnoreRootScrollFrame);
RealMouseEvent(nsMouseEvent event);
RealKeyEvent(nsKeyEvent event);
MouseScrollEvent(nsMouseScrollEvent event);
/**
* @see nsIDOMWindowUtils sendKeyEvent.
*/

View File

@ -580,6 +580,31 @@ TabChild::RecvMouseEvent(const nsString& aType,
return true;
}
bool
TabChild::RecvRealMouseEvent(const nsMouseEvent& event)
{
nsMouseEvent localEvent(event);
DispatchWidgetEvent(localEvent);
return true;
}
bool
TabChild::RecvMouseScrollEvent(const nsMouseScrollEvent& event)
{
nsMouseScrollEvent localEvent(event);
DispatchWidgetEvent(localEvent);
return true;
}
bool
TabChild::RecvRealKeyEvent(const nsKeyEvent& event)
{
nsKeyEvent localEvent(event);
DispatchWidgetEvent(localEvent);
return true;
}
bool
TabChild::RecvKeyEvent(const nsString& aType,
const PRInt32& aKeyCode,

View File

@ -188,6 +188,9 @@ public:
const PRInt32& aClickCount,
const PRInt32& aModifiers,
const bool& aIgnoreRootScrollFrame);
virtual bool RecvRealMouseEvent(const nsMouseEvent& event);
virtual bool RecvRealKeyEvent(const nsKeyEvent& event);
virtual bool RecvMouseScrollEvent(const nsMouseScrollEvent& event);
virtual bool RecvKeyEvent(const nsString& aType,
const PRInt32& aKeyCode,
const PRInt32& aCharCode,

View File

@ -67,6 +67,7 @@
#include "nsSerializationHelper.h"
#include "nsIPromptFactory.h"
#include "nsIContent.h"
#include "nsIWidget.h"
#include "mozilla/unused.h"
#include "nsDebug.h"
@ -299,6 +300,21 @@ TabParent::SendKeyEvent(const nsAString& aType,
aModifiers, aPreventDefault);
}
bool TabParent::SendRealMouseEvent(nsMouseEvent& event)
{
return PBrowserParent::SendRealMouseEvent(event);
}
bool TabParent::SendMouseScrollEvent(nsMouseScrollEvent& event)
{
return PBrowserParent::SendMouseScrollEvent(event);
}
bool TabParent::SendRealKeyEvent(nsKeyEvent& event)
{
return PBrowserParent::SendRealKeyEvent(event);
}
bool
TabParent::RecvSyncMessage(const nsString& aMessage,
const nsString& aJSON,
@ -314,6 +330,16 @@ TabParent::RecvAsyncMessage(const nsString& aMessage,
return ReceiveMessage(aMessage, PR_FALSE, aJSON, nsnull);
}
bool
TabParent::RecvSetCursor(const PRUint32& aCursor)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SetCursor((nsCursor) aCursor);
}
return true;
}
bool
TabParent::RecvNotifyIMEFocus(const PRBool& aFocus,
nsIMEUpdatePreference* aPreference,

View File

@ -107,6 +107,7 @@ public:
virtual bool RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const nsString& aAction, const PRUint32& aReason);
virtual bool RecvGetIMEOpenState(PRBool* aValue);
virtual bool RecvSetIMEOpenState(const PRBool& aValue);
virtual bool RecvSetCursor(const PRUint32& aValue);
virtual bool RecvGetDPI(float* aValue);
virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
const nsCString& aName,
@ -134,6 +135,9 @@ public:
void SendKeyEvent(const nsAString& aType, PRInt32 aKeyCode,
PRInt32 aCharCode, PRInt32 aModifiers,
PRBool aPreventDefault);
bool SendRealMouseEvent(nsMouseEvent& event);
bool SendMouseScrollEvent(nsMouseScrollEvent& event);
bool SendRealKeyEvent(nsKeyEvent& event);
virtual PDocumentRendererParent*
AllocPDocumentRenderer(const nsRect& documentRect, const gfxMatrix& transform,

View File

@ -2845,6 +2845,7 @@ Tab.prototype = {
let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
fl.renderMode = Ci.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL;
fl.eventMode = Ci.nsIFrameLoader.EVENT_MODE_DONT_FORWARD_TO_CHILD;
return browser;
},

View File

@ -821,7 +821,16 @@ public:
class nsMouseEvent_base : public nsInputEvent
{
private:
friend class mozilla::dom::PBrowserParent;
friend class mozilla::dom::PBrowserChild;
public:
nsMouseEvent_base()
{
}
nsMouseEvent_base(PRBool isTrusted, PRUint32 msg, nsIWidget *w, PRUint8 type)
: nsInputEvent(isTrusted, msg, w, type), button(0), pressure(0),
inputSource(nsIDOMNSMouseEvent::MOZ_SOURCE_MOUSE) {}
@ -841,12 +850,20 @@ public:
class nsMouseEvent : public nsMouseEvent_base
{
private:
friend class mozilla::dom::PBrowserParent;
friend class mozilla::dom::PBrowserChild;
public:
enum buttonType { eLeftButton = 0, eMiddleButton = 1, eRightButton = 2 };
enum reasonType { eReal, eSynthesized };
enum contextType { eNormal, eContextMenuKey };
enum exitType { eChild, eTopLevel };
nsMouseEvent()
{
}
protected:
nsMouseEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w,
PRUint8 structType, reasonType aReason)
@ -953,7 +970,15 @@ struct nsAlternativeCharCode {
class nsKeyEvent : public nsInputEvent
{
private:
friend class mozilla::dom::PBrowserParent;
friend class mozilla::dom::PBrowserChild;
public:
nsKeyEvent()
{
}
nsKeyEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
: nsInputEvent(isTrusted, msg, w, NS_KEY_EVENT),
keyCode(0), charCode(0), isChar(0)
@ -1180,6 +1205,14 @@ public:
class nsMouseScrollEvent : public nsMouseEvent_base
{
private:
friend class mozilla::dom::PBrowserParent;
friend class mozilla::dom::PBrowserChild;
nsMouseScrollEvent()
{
}
public:
enum nsMouseScrollFlags {
kIsFullPage = 1 << 0,

View File

@ -153,6 +153,61 @@ struct ParamTraits<nsMouseScrollEvent>
}
};
template<>
struct ParamTraits<nsMouseEvent>
{
typedef nsMouseEvent paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, static_cast<nsMouseEvent_base>(aParam));
WriteParam(aMsg, aParam.ignoreRootScrollFrame);
WriteParam(aMsg, (PRUint8) aParam.reason);
WriteParam(aMsg, (PRUint8) aParam.context);
WriteParam(aMsg, (PRUint8) aParam.exit);
WriteParam(aMsg, aParam.clickCount);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
bool rv;
PRUint8 reason, context, exit;
rv = ReadParam(aMsg, aIter, static_cast<nsMouseEvent_base*>(aResult)) &&
ReadParam(aMsg, aIter, &aResult->ignoreRootScrollFrame) &&
ReadParam(aMsg, aIter, &reason) &&
ReadParam(aMsg, aIter, &context) &&
ReadParam(aMsg, aIter, &exit) &&
ReadParam(aMsg, aIter, &aResult->clickCount);
aResult->reason = static_cast<nsMouseEvent::reasonType>(reason);
aResult->context = static_cast<nsMouseEvent::contextType>(context);
aResult->exit = static_cast<nsMouseEvent::exitType>(exit);
return rv;
}
};
template<>
struct ParamTraits<nsKeyEvent>
{
typedef nsKeyEvent paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, static_cast<nsInputEvent>(aParam));
WriteParam(aMsg, aParam.keyCode);
WriteParam(aMsg, aParam.charCode);
WriteParam(aMsg, aParam.isChar);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, static_cast<nsInputEvent*>(aResult)) &&
ReadParam(aMsg, aIter, &aResult->keyCode) &&
ReadParam(aMsg, aIter, &aResult->charCode) &&
ReadParam(aMsg, aIter, &aResult->isChar);
}
};
template<>
struct ParamTraits<nsTextRangeStyle>
{

View File

@ -505,6 +505,16 @@ PuppetWidget::OnIMESelectionChange(void)
return NS_OK;
}
NS_IMETHODIMP
PuppetWidget::SetCursor(nsCursor aCursor)
{
if (!mTabChild ||
!mTabChild->SendSetCursor(aCursor)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
PuppetWidget::DispatchPaintEvent()
{

View File

@ -180,6 +180,8 @@ public:
PRUint32 aNewEnd);
NS_IMETHOD OnIMESelectionChange(void);
NS_IMETHOD SetCursor(nsCursor aCursor);
// Gets the DPI of the screen corresponding to this widget.
// Contacts the parent process which gets the DPI from the
// proper widget there. TODO: Handle DPI changes that happen