Bug 970964 - Implement generic mouse/touch -> Pointer events converter. r=smaug,jimm

--HG--
extra : rebase_source : 165dc4e5c598f9e9f9de928efe16824037b95ff3
This commit is contained in:
Oleg Romashin 2014-02-26 13:37:01 -08:00
parent 443d4364bc
commit 6cea53ee81
7 changed files with 174 additions and 11 deletions

View File

@ -8,6 +8,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/MouseEvents.h"
#include "nsWrapperCache.h"
#include "nsAutoPtr.h"
#include "Units.h"
@ -21,6 +22,7 @@ class EventTarget;
class Touch MOZ_FINAL : public nsISupports
, public nsWrapperCache
, public WidgetPointerHelper
{
public:
static bool PrefEnabled(JSContext* aCx, JSObject* aGlobal);

View File

@ -688,6 +688,7 @@ nsIPresShell::FrameSelection()
static bool sSynthMouseMove = true;
static uint32_t sNextPresShellId;
static bool sPointerEventEnabled = true;
PresShell::PresShell()
: mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
@ -736,6 +737,12 @@ PresShell::PresShell()
"layout.reflow.synthMouseMove", true);
addedSynthMouseMove = true;
}
static bool addedPointerEventEnabled = false;
if (addedPointerEventEnabled) {
Preferences::AddBoolVarCache(&sPointerEventEnabled,
"dom.w3c_pointer_events.enabled", true);
addedPointerEventEnabled = true;
}
mPaintingIsFrozen = false;
}
@ -6299,12 +6306,102 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
return true;
}
static nsresult
DispatchPointerFromMouseOrTouch(PresShell* aShell,
nsIFrame* aFrame,
WidgetGUIEvent* aEvent,
bool aDontRetargetEvents,
nsEventStatus* aStatus)
{
uint32_t pointerMessage = 0;
if (aEvent->eventStructType == NS_MOUSE_EVENT) {
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
// if it is not mouse then it is likely will come as touch event
if (!mouseEvent->convertToPointer) {
return NS_OK;
}
int16_t button = mouseEvent->button;
switch (mouseEvent->message) {
case NS_MOUSE_MOVE:
if (mouseEvent->buttons == 0) {
button = -1;
}
pointerMessage = NS_POINTER_MOVE;
break;
case NS_MOUSE_BUTTON_UP:
pointerMessage = NS_POINTER_UP;
break;
case NS_MOUSE_BUTTON_DOWN:
pointerMessage = NS_POINTER_DOWN;
break;
default:
return NS_OK;
}
WidgetPointerEvent event(*mouseEvent);
event.message = pointerMessage;
event.button = button;
event.convertToPointer = mouseEvent->convertToPointer = false;
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
} else if (aEvent->eventStructType == NS_TOUCH_EVENT) {
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
// loop over all touches and dispatch pointer events on each touch
// copy the event
switch (touchEvent->message) {
case NS_TOUCH_MOVE:
pointerMessage = NS_POINTER_MOVE;
break;
case NS_TOUCH_END:
pointerMessage = NS_POINTER_UP;
break;
case NS_TOUCH_START:
pointerMessage = NS_POINTER_DOWN;
break;
case NS_TOUCH_CANCEL:
pointerMessage = NS_POINTER_CANCEL;
break;
default:
return NS_OK;
}
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
mozilla::dom::Touch* touch = touchEvent->touches[i];
if (!touch || !touch->convertToPointer) {
continue;
}
WidgetPointerEvent event(touchEvent->mFlags.mIsTrusted, pointerMessage, touchEvent->widget);
event.isPrimary = i == 0;
event.pointerId = touch->Identifier();
event.refPoint.x = touch->mRefPoint.x;
event.refPoint.y = touch->mRefPoint.y;
event.modifiers = touchEvent->modifiers;
event.width = touch->RadiusX();
event.height = touch->RadiusY();
event.tiltX = touch->tiltX;
event.tiltY = touch->tiltY;
event.time = touchEvent->time;
event.mFlags = touchEvent->mFlags;
event.button = WidgetMouseEvent::eLeftButton;
event.buttons = WidgetMouseEvent::eLeftButtonFlag;
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
event.convertToPointer = touch->convertToPointer = false;
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
}
}
return NS_OK;
}
nsresult
PresShell::HandleEvent(nsIFrame* aFrame,
WidgetGUIEvent* aEvent,
bool aDontRetargetEvents,
nsEventStatus* aEventStatus)
{
if (sPointerEventEnabled) {
DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents, aEventStatus);
}
NS_ASSERTION(aFrame, "null frame");
if (mIsDestroying ||

View File

@ -36,6 +36,27 @@ namespace dom {
class PBrowserChild;
} // namespace dom
/******************************************************************************
* mozilla::WidgetPointerHelper
******************************************************************************/
class WidgetPointerHelper
{
public:
bool convertToPointer;
uint32_t tiltX;
uint32_t tiltY;
WidgetPointerHelper() : convertToPointer(true), tiltX(0), tiltY(0) {}
void AssignPointerHelperData(const WidgetPointerHelper& aEvent)
{
convertToPointer = aEvent.convertToPointer;
tiltX = aEvent.tiltX;
tiltY = aEvent.tiltY;
}
};
/******************************************************************************
* mozilla::WidgetMouseEventBase
******************************************************************************/
@ -128,7 +149,7 @@ public:
* mozilla::WidgetMouseEvent
******************************************************************************/
class WidgetMouseEvent : public WidgetMouseEventBase
class WidgetMouseEvent : public WidgetMouseEventBase, public WidgetPointerHelper
{
private:
friend class mozilla::dom::PBrowserParent;
@ -242,6 +263,7 @@ public:
void AssignMouseEventData(const WidgetMouseEvent& aEvent, bool aCopyTargets)
{
AssignMouseEventBaseData(aEvent, aCopyTargets);
AssignPointerHelperData(aEvent);
acceptActivation = aEvent.acceptActivation;
ignoreRootScrollFrame = aEvent.ignoreRootScrollFrame;
@ -532,8 +554,6 @@ public:
, pointerId(0)
, width(0)
, height(0)
, tiltX(0)
, tiltY(0)
, isPrimary(true)
{
UpdateFlags();
@ -544,8 +564,6 @@ public:
, pointerId(0)
, width(0)
, height(0)
, tiltX(0)
, tiltY(0)
, isPrimary(true)
{
eventStructType = NS_POINTER_EVENT;
@ -579,8 +597,6 @@ public:
uint32_t pointerId;
uint32_t width;
uint32_t height;
uint32_t tiltX;
uint32_t tiltY;
bool isPrimary;
// XXX Not tested by test_assign_event_data.html
@ -592,8 +608,6 @@ public:
pointerId = aEvent.pointerId;
width = aEvent.width;
height = aEvent.height;
tiltX = aEvent.tiltX;
tiltY = aEvent.tiltY;
isPrimary = aEvent.isPrimary;
}
};

View File

@ -558,6 +558,16 @@ WinUtils::GetMouseInputSource()
return static_cast<uint16_t>(inputSource);
}
bool
WinUtils::GetIsMouseFromTouch(uint32_t aEventType)
{
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
return (aEventType == NS_MOUSE_BUTTON_DOWN ||
aEventType == NS_MOUSE_BUTTON_UP ||
aEventType == NS_MOUSE_MOVE) &&
(GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH);
}
/* static */
MSG
WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd)

View File

@ -237,6 +237,8 @@ public:
*/
static uint16_t GetMouseInputSource();
static bool GetIsMouseFromTouch(uint32_t aEventType);
/**
* SHCreateItemFromParsingName() calls native SHCreateItemFromParsingName()
* API which is available on Vista and up.

View File

@ -283,6 +283,9 @@ static const int32_t kGlassMarginAdjustment = 2;
// content.
static const int32_t kResizableBorderMinSize = 3;
// Cached pointer events enabler value, True if pointer events are enabled.
static bool gIsPointerEventsEnabled = false;
// We should never really try to accelerate windows bigger than this. In some
// cases this might lead to no D3D9 acceleration where we could have had it
// but D3D9 does not reliably report when it supports bigger windows. 8192
@ -382,6 +385,10 @@ nsWindow::nsWindow() : nsWindowBase()
// Init theme data
nsUXThemeData::UpdateNativeThemeInfo();
RedirectedKeyDownMessageManager::Forget();
Preferences::AddBoolVarCache(&gIsPointerEventsEnabled,
"dom.w3c_pointer_events.enabled",
gIsPointerEventsEnabled);
} // !sInstanceCount
mIdleService = nullptr;
@ -1271,7 +1278,8 @@ void nsWindow::SetThemeRegion()
**************************************************************/
NS_METHOD nsWindow::RegisterTouchWindow() {
if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0)) {
if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) ||
gIsPointerEventsEnabled) {
mTouchWindow = true;
mGesture.RegisterTouchWindow(mWnd);
::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
@ -3792,6 +3800,10 @@ bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam,
modifierKeyState.InitInputEvent(event);
event.button = aButton;
event.inputSource = aInputSource;
// Convert Mouse events generated by pen device or if mouse not generated from touch
event.convertToPointer =
aInputSource == nsIDOMMouseEvent::MOZ_SOURCE_PEN ||
!(WinUtils::GetIsMouseFromTouch(aEventType) && mTouchWindow);
nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
@ -5231,6 +5243,11 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
// A GestureNotify event is dispatched to decide which single-finger panning
// direction should be active (including none) and if pan feedback should
// be displayed. Java and plugin windows can make their own calls.
if (gIsPointerEventsEnabled) {
result = false;
break;
}
GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
nsPointWin touchPoint;
touchPoint = gestureinfo->ptsLocation;
@ -6093,6 +6110,10 @@ static int32_t RoundDown(double aDouble)
// Gesture event processing. Handles WM_GESTURE events.
bool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
{
if (gIsPointerEventsEnabled) {
return false;
}
// Treatment for pan events which translate into scroll events:
if (mGesture.IsPanEvent(lParam)) {
if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )

View File

@ -76,18 +76,23 @@ namespace {
uint32_t pointerId;
Foundation::Rect contactRect;
float pressure;
float tiltX;
float tiltY;
aPoint->get_Properties(props.GetAddressOf());
aPoint->get_Position(&position);
aPoint->get_PointerId(&pointerId);
props->get_ContactRect(&contactRect);
props->get_Pressure(&pressure);
props->get_XTilt(&tiltX);
props->get_YTilt(&tiltY);
nsIntPoint touchPoint = MetroUtils::LogToPhys(position);
nsIntPoint touchRadius;
touchRadius.x = WinUtils::LogToPhys(contactRect.Width) / 2;
touchRadius.y = WinUtils::LogToPhys(contactRect.Height) / 2;
return new Touch(pointerId,
Touch* touch =
new Touch(pointerId,
touchPoint,
// Rotation radius and angle.
// W3C touch events v1 do not use these.
@ -109,6 +114,9 @@ namespace {
// draft says that the value should be 0.0 if no value
// known.
pressure);
touch->tiltX = tiltX;
touch->tiltY = tiltY;
return touch;
}
/**
@ -224,6 +232,8 @@ namespace {
aData->mRadius,
aData->mRotationAngle,
aData->mForce);
copy->tiltX = aData->tiltX;
copy->tiltY = aData->tiltY;
touches->AppendElement(copy);
aData->mChanged = false;
return PL_DHASH_NEXT;
@ -789,6 +799,8 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
uint64_t timestamp;
float pressure;
boolean canBeDoubleTap;
float tiltX;
float tiltY;
aPointerPoint->get_Position(&position);
aPointerPoint->get_Timestamp(&timestamp);
@ -796,6 +808,9 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
device->get_PointerDeviceType(&deviceType);
aPointerPoint->get_Properties(props.GetAddressOf());
props->get_Pressure(&pressure);
props->get_XTilt(&tiltX);
props->get_YTilt(&tiltY);
mGestureRecognizer->CanBeDoubleTap(aPointerPoint, &canBeDoubleTap);
TransformRefPoint(position, aEvent->refPoint);
@ -806,6 +821,8 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
aEvent->clickCount = 2;
}
aEvent->pressure = pressure;
aEvent->tiltX = tiltX;
aEvent->tiltY = tiltY;
aEvent->buttons = ButtonsForPointerPoint(aPointerPoint);
MozInputSourceFromDeviceType(deviceType, aEvent->inputSource);