Bug 603008 - Platform support for multitouch events. r=smaug

* * *
Bug 603008 - Platform support for multitouch events.
* * *
ifdefandroid
This commit is contained in:
Wes Johnston 2011-12-16 16:24:11 -08:00
parent a323c9b649
commit 72f42280fd
25 changed files with 1478 additions and 74 deletions

View File

@ -148,6 +148,7 @@ MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@
MOZ_WEBSMS_BACKEND = @MOZ_WEBSMS_BACKEND@
MOZ_JAVA_COMPOSITOR = @MOZ_JAVA_COMPOSITOR@
MOZ_TOUCH = @MOZ_TOUCH@
MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@
MOZ_FEEDS = @MOZ_FEEDS@
MOZ_TOOLKIT_SEARCH = @MOZ_TOOLKIT_SEARCH@

View File

@ -4902,6 +4902,7 @@ cairo-uikit)
cairo-android)
AC_DEFINE(MOZ_WIDGET_ANDROID)
AC_DEFINE(MOZ_TOUCH)
MOZ_WIDGET_TOOLKIT=android
TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
TK_LIBS='$(MOZ_CAIRO_LIBS)'
@ -4909,6 +4910,7 @@ cairo-android)
MOZ_PDF_PRINTING=1
MOZ_INSTRUMENT_EVENT_LOOP=1
MOZ_OLD_LINKER=1
MOZ_TOUCH=1
;;
cairo-gonk)

View File

@ -449,29 +449,29 @@ WINDOW_ONLY_EVENT(deviceorientation,
NS_EVENT)
TOUCH_EVENT(touchstart,
NS_USER_DEFINED_EVENT,
NS_TOUCH_START,
EventNameType_All,
NS_INPUT_EVENT)
NS_TOUCH_EVENT)
TOUCH_EVENT(touchend,
NS_USER_DEFINED_EVENT,
NS_TOUCH_END,
EventNameType_All,
NS_INPUT_EVENT)
NS_TOUCH_EVENT)
TOUCH_EVENT(touchmove,
NS_USER_DEFINED_EVENT,
NS_TOUCH_MOVE,
EventNameType_All,
NS_INPUT_EVENT )
NS_TOUCH_EVENT )
TOUCH_EVENT(touchenter,
NS_USER_DEFINED_EVENT,
NS_TOUCH_ENTER,
EventNameType_All,
NS_INPUT_EVENT )
NS_TOUCH_EVENT )
TOUCH_EVENT(touchleave,
NS_USER_DEFINED_EVENT,
NS_TOUCH_LEAVE,
EventNameType_All,
NS_INPUT_EVENT)
NS_TOUCH_EVENT)
TOUCH_EVENT(touchcancel,
NS_USER_DEFINED_EVENT,
NS_TOUCH_CANCEL,
EventNameType_All,
NS_INPUT_EVENT)
NS_TOUCH_EVENT)
DOCUMENT_ONLY_EVENT(readystatechange,
NS_READYSTATECHANGE,

View File

@ -141,7 +141,7 @@ NS_NewDOMCloseEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContex
nsresult
NS_NewDOMMozTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsMozTouchEvent* aEvent);
nsresult
NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent);
NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsTouchEvent *aEvent);
nsresult
NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult

View File

@ -63,6 +63,8 @@
#include "mozilla/Preferences.h"
#include "nsJSUtils.h"
#include "DictionaryHelpers.h"
#include "nsLayoutUtils.h"
#include "nsIScrollableFrame.h"
using namespace mozilla;
@ -110,6 +112,12 @@ static const char* const sEventNames[] = {
"MozTouchDown",
"MozTouchMove",
"MozTouchUp",
"touchstart",
"touchend",
"touchmove",
"touchcancel",
"touchenter",
"touchleave",
"MozScrolledAreaChanged",
"transitionend",
"animationstart",
@ -902,6 +910,13 @@ NS_METHOD nsDOMEvent::DuplicatePrivateData()
isInputEvent = true;
break;
}
case NS_TOUCH_EVENT:
{
newEvent = new nsTouchEvent(false, msg, nsnull);
NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
isInputEvent = true;
break;
}
default:
{
NS_WARNING("Unknown event type!!!");
@ -1165,6 +1180,92 @@ nsDOMEvent::Shutdown()
}
}
nsIntPoint
nsDOMEvent::GetScreenCoords(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint aPoint)
{
if (!aEvent ||
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_TOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
return nsIntPoint(0, 0);
}
nsGUIEvent* guiEvent = static_cast<nsGUIEvent*>(aEvent);
if (!guiEvent->widget) {
return aPoint;
}
nsIntPoint offset = aPoint + guiEvent->widget->WidgetToScreenOffset();
nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
}
//static
nsIntPoint
nsDOMEvent::GetPageCoords(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint aPoint,
nsIntPoint aDefaultPoint)
{
nsIntPoint pagePoint = nsDOMEvent::GetClientCoords(aPresContext,
aEvent,
aPoint,
aDefaultPoint);
// If there is some scrolling, add scroll info to client point.
if (aPresContext && aPresContext->GetPresShell()) {
nsIPresShell* shell = aPresContext->GetPresShell();
nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
if (scrollframe) {
nsPoint pt = scrollframe->GetScrollPosition();
pagePoint += nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
}
}
return pagePoint;
}
// static
nsIntPoint
nsDOMEvent::GetClientCoords(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint aPoint,
nsIntPoint aDefaultPoint)
{
if (!aEvent ||
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_TOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
!aPresContext ||
!((nsGUIEvent*)aEvent)->widget) {
return aDefaultPoint;
}
nsPoint pt(0, 0);
nsIPresShell* shell = aPresContext->GetPresShell();
if (!shell) {
return nsIntPoint(0, 0);
}
nsIFrame* rootFrame = shell->GetRootFrame();
if (rootFrame)
pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aPoint, rootFrame);
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
}
// To be called ONLY by nsDOMEvent::GetType (which has the additional
// logic for handling user-defined events).
// static
@ -1347,6 +1448,18 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_SVGScroll];
case NS_SVG_ZOOM:
return sEventNames[eDOMEvents_SVGZoom];
case NS_TOUCH_START:
return sEventNames[eDOMEvents_touchstart];
case NS_TOUCH_MOVE:
return sEventNames[eDOMEvents_touchmove];
case NS_TOUCH_END:
return sEventNames[eDOMEvents_touchend];
case NS_TOUCH_ENTER:
return sEventNames[eDOMEvents_touchenter];
case NS_TOUCH_LEAVE:
return sEventNames[eDOMEvents_touchleave];
case NS_TOUCH_CANCEL:
return sEventNames[eDOMEvents_touchcancel];
case NS_SMIL_BEGIN:
return sEventNames[eDOMEvents_beginEvent];
case NS_SMIL_END:

View File

@ -195,6 +195,12 @@ public:
eDOMEvents_MozTouchDown,
eDOMEvents_MozTouchMove,
eDOMEvents_MozTouchUp,
eDOMEvents_touchstart,
eDOMEvents_touchend,
eDOMEvents_touchmove,
eDOMEvents_touchcancel,
eDOMEvents_touchenter,
eDOMEvents_touchleave,
eDOMEvents_MozScrolledAreaChanged,
eDOMEvents_transitionend,
eDOMEvents_animationstart,
@ -242,6 +248,17 @@ public:
static void Shutdown();
static const char* GetEventName(PRUint32 aEventType);
static nsIntPoint GetClientCoords(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint aPoint,
nsIntPoint aDefaultPoint);
static nsIntPoint GetPageCoords(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint aPoint,
nsIntPoint aDefaultPoint);
static nsIntPoint GetScreenCoords(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint aPoint);
protected:
// Internal helper functions

View File

@ -236,7 +236,13 @@ nsDOMMouseEvent::GetRelatedTarget(nsIDOMEventTarget** aRelatedTarget)
NS_METHOD nsDOMMouseEvent::GetScreenX(PRInt32* aScreenX)
{
NS_ENSURE_ARG_POINTER(aScreenX);
#ifdef MOZ_TOUCH
*aScreenX = nsDOMEvent::GetScreenCoords(mPresContext,
mEvent,
mEvent->refPoint).x;
#else
*aScreenX = GetScreenPoint().x;
#endif
return NS_OK;
}
@ -244,7 +250,13 @@ NS_IMETHODIMP
nsDOMMouseEvent::GetScreenY(PRInt32* aScreenY)
{
NS_ENSURE_ARG_POINTER(aScreenY);
#ifdef MOZ_TOUCH
*aScreenY = nsDOMEvent::GetScreenCoords(mPresContext,
mEvent,
mEvent->refPoint).y;
#else
*aScreenY = GetScreenPoint().y;
#endif
return NS_OK;
}
@ -252,7 +264,14 @@ nsDOMMouseEvent::GetScreenY(PRInt32* aScreenY)
NS_METHOD nsDOMMouseEvent::GetClientX(PRInt32* aClientX)
{
NS_ENSURE_ARG_POINTER(aClientX);
#ifdef MOZ_TOUCH
*aClientX = nsDOMEvent::GetClientCoords(mPresContext,
mEvent,
mEvent->refPoint,
mClientPoint).x;
#else
*aClientX = GetClientPoint().x;
#endif
return NS_OK;
}
@ -260,7 +279,14 @@ NS_IMETHODIMP
nsDOMMouseEvent::GetClientY(PRInt32* aClientY)
{
NS_ENSURE_ARG_POINTER(aClientY);
#ifdef MOZ_TOUCH
*aClientY = nsDOMEvent::GetClientCoords(mPresContext,
mEvent,
mEvent->refPoint,
mClientPoint).y;
#else
*aClientY = GetClientPoint().y;
#endif
return NS_OK;
}

View File

@ -42,6 +42,7 @@
#include "nsIXPCScriptable.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
#include "nsPresContext.h"
using namespace mozilla;
@ -75,56 +76,56 @@ nsDOMTouch::GetTarget(nsIDOMEventTarget** aTarget)
NS_IMETHODIMP
nsDOMTouch::GetScreenX(PRInt32* aScreenX)
{
*aScreenX = mScreenX;
*aScreenX = mScreenPoint.x;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouch::GetScreenY(PRInt32* aScreenY)
{
*aScreenY = mScreenY;
*aScreenY = mScreenPoint.y;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouch::GetClientX(PRInt32* aClientX)
{
*aClientX = mClientX;
*aClientX = mClientPoint.x;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouch::GetClientY(PRInt32* aClientY)
{
*aClientY = mClientY;
*aClientY = mClientPoint.y;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouch::GetPageX(PRInt32* aPageX)
{
*aPageX = mPageX;
*aPageX = mPagePoint.x;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouch::GetPageY(PRInt32* aPageY)
{
*aPageY = mPageY;
*aPageY = mPagePoint.y;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouch::GetRadiusX(PRInt32* aRadiusX)
{
*aRadiusX = mRadiusX;
*aRadiusX = mRadius.x;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouch::GetRadiusY(PRInt32* aRadiusY)
{
*aRadiusY = mRadiusY;
*aRadiusY = mRadius.y;
return NS_OK;
}
@ -142,7 +143,27 @@ nsDOMTouch::GetForce(float* aForce)
return NS_OK;
}
bool
nsDOMTouch::Equals(nsIDOMTouch* aTouch)
{
float force;
float orientation;
PRInt32 radiusX, radiusY;
aTouch->GetForce(&force);
aTouch->GetRotationAngle(&orientation);
aTouch->GetRadiusX(&radiusX);
aTouch->GetRadiusY(&radiusY);
return mRefPoint != aTouch->mRefPoint ||
(mForce != force) ||
(mRotationAngle != orientation) ||
(mRadius.x != radiusX) || (mRadius.y != radiusY);
}
// TouchList
nsDOMTouchList::nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches)
{
mPoints.AppendElements(aTouches);
}
DOMCI_DATA(TouchList, nsDOMTouchList)
@ -155,11 +176,11 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMTouchList)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMTouchList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPoints)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mPoints)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMTouchList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPoints)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mPoints)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTouchList)
@ -168,14 +189,14 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTouchList)
NS_IMETHODIMP
nsDOMTouchList::GetLength(PRUint32* aLength)
{
*aLength = mPoints.Count();
*aLength = mPoints.Length();
return NS_OK;
}
NS_IMETHODIMP
nsDOMTouchList::Item(PRUint32 aIndex, nsIDOMTouch** aRetVal)
{
NS_IF_ADDREF(*aRetVal = mPoints.SafeObjectAt(aIndex));
NS_IF_ADDREF(*aRetVal = mPoints.SafeElementAt(aIndex, nsnull));
return NS_OK;
}
@ -183,7 +204,7 @@ NS_IMETHODIMP
nsDOMTouchList::IdentifiedTouch(PRInt32 aIdentifier, nsIDOMTouch** aRetVal)
{
*aRetVal = nsnull;
for (PRInt32 i = 0; i < mPoints.Count(); ++i) {
for (PRUint32 i = 0; i < mPoints.Length(); ++i) {
nsCOMPtr<nsIDOMTouch> point = mPoints[i];
PRInt32 identifier;
if (point && NS_SUCCEEDED(point->GetIdentifier(&identifier)) &&
@ -198,12 +219,18 @@ nsDOMTouchList::IdentifiedTouch(PRInt32 aIdentifier, nsIDOMTouch** aRetVal)
// TouchEvent
nsDOMTouchEvent::nsDOMTouchEvent(nsPresContext* aPresContext,
nsInputEvent* aEvent)
nsTouchEvent* aEvent)
: nsDOMUIEvent(aPresContext, aEvent ? aEvent :
new nsInputEvent(false, 0, nsnull))
new nsTouchEvent(false, 0, nsnull))
{
if (aEvent) {
mEventIsInternal = false;
for (PRUint32 i = 0; i < aEvent->touches.Length(); ++i) {
nsIDOMTouch *touch = aEvent->touches[i];
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
domtouch->InitializePoints(mPresContext, aEvent);
}
} else {
mEventIsInternal = true;
mEvent->time = PR_Now();
@ -213,7 +240,7 @@ nsDOMTouchEvent::nsDOMTouchEvent(nsPresContext* aPresContext,
nsDOMTouchEvent::~nsDOMTouchEvent()
{
if (mEventIsInternal && mEvent) {
delete static_cast<nsInputEvent*>(mEvent);
delete static_cast<nsTouchEvent*>(mEvent);
mEvent = nsnull;
}
}
@ -257,7 +284,11 @@ nsDOMTouchEvent::InitTouchEvent(const nsAString& aType,
nsIDOMTouchList* aTargetTouches,
nsIDOMTouchList* aChangedTouches)
{
nsresult rv = nsDOMUIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
nsresult rv = nsDOMUIEvent::InitUIEvent(aType,
aCanBubble,
aCancelable,
aView,
aDetail);
NS_ENSURE_SUCCESS(rv, rv);
static_cast<nsInputEvent*>(mEvent)->isControl = aCtrlKey;
@ -273,22 +304,80 @@ nsDOMTouchEvent::InitTouchEvent(const nsAString& aType,
NS_IMETHODIMP
nsDOMTouchEvent::GetTouches(nsIDOMTouchList** aTouches)
{
NS_IF_ADDREF(*aTouches = mTouches);
return NS_OK;
NS_ENSURE_ARG_POINTER(aTouches);
NS_ENSURE_STATE(mEvent);
nsRefPtr<nsDOMTouchList> t;
if (mTouches) {
return CallQueryInterface(mTouches, aTouches);
}
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent);
if (mEvent->message == NS_TOUCH_END || mEvent->message == NS_TOUCH_CANCEL) {
// for touchend events, remove any changed touches from the touches array
nsTArray<nsCOMPtr<nsIDOMTouch> > unchangedTouches;
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
for (PRUint32 i = 0; i < touches.Length(); ++i) {
if (!touches[i]->mChanged) {
unchangedTouches.AppendElement(touches[i]);
}
}
t = new nsDOMTouchList(unchangedTouches);
} else {
t = new nsDOMTouchList(touchEvent->touches);
}
mTouches = t;
return CallQueryInterface(mTouches, aTouches);
}
NS_IMETHODIMP
nsDOMTouchEvent::GetTargetTouches(nsIDOMTouchList** aTargetTouches)
{
NS_IF_ADDREF(*aTargetTouches = mTargetTouches);
return NS_OK;
NS_ENSURE_ARG_POINTER(aTargetTouches);
NS_ENSURE_STATE(mEvent);
if (mTargetTouches) {
return CallQueryInterface(mTargetTouches, aTargetTouches);
}
nsTArray<nsCOMPtr<nsIDOMTouch> > targetTouches;
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent);
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
for (PRUint32 i = 0; i < touches.Length(); ++i) {
// for touchend/cancel events, don't append to the target list if this is a
// touch that is ending
if ((mEvent->message != NS_TOUCH_END &&
mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) {
nsIDOMEventTarget* targetPtr = touches[i]->GetTarget();
if (targetPtr == mEvent->target) {
targetTouches.AppendElement(touches[i]);
}
}
}
mTargetTouches = new nsDOMTouchList(targetTouches);
return CallQueryInterface(mTargetTouches, aTargetTouches);
}
NS_IMETHODIMP
nsDOMTouchEvent::GetChangedTouches(nsIDOMTouchList** aChangedTouches)
{
NS_IF_ADDREF(*aChangedTouches = mChangedTouches);
return NS_OK;
NS_ENSURE_ARG_POINTER(aChangedTouches);
NS_ENSURE_STATE(mEvent);
if (mChangedTouches) {
return CallQueryInterface(mChangedTouches, aChangedTouches);
}
nsTArray<nsCOMPtr<nsIDOMTouch> > changedTouches;
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent);
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
for (PRUint32 i = 0; i < touches.Length(); ++i) {
if (touches[i]->mChanged) {
changedTouches.AppendElement(touches[i]);
}
}
mChangedTouches = new nsDOMTouchList(changedTouches);
return CallQueryInterface(mChangedTouches, aChangedTouches);
}
NS_IMETHODIMP
@ -337,7 +426,7 @@ nsDOMTouchEvent::PrefEnabled()
nsresult
NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsInputEvent *aEvent)
nsTouchEvent *aEvent)
{
nsDOMTouchEvent* it = new nsDOMTouchEvent(aPresContext, aEvent);

View File

@ -40,7 +40,7 @@
#include "nsDOMUIEvent.h"
#include "nsIDOMTouchEvent.h"
#include "nsString.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
class nsDOMTouch : public nsIDOMTouch
{
@ -57,33 +57,72 @@ public:
PRInt32 aRadiusY,
float aRotationAngle,
float aForce)
: mTarget(aTarget),
mIdentifier(aIdentifier),
mPageX(aPageX),
mPageY(aPageY),
mScreenX(aScreenX),
mScreenY(aScreenY),
mClientX(aClientX),
mClientY(aClientY),
mRadiusX(aRadiusX),
mRadiusY(aRadiusY),
mRotationAngle(aRotationAngle),
mForce(aForce)
{}
{
mTarget = aTarget;
mIdentifier = aIdentifier;
mPagePoint = nsIntPoint(aPageX, aPageY);
mScreenPoint = nsIntPoint(aScreenX, aScreenY);
mClientPoint = nsIntPoint(aClientX, aClientY);
mRefPoint = nsIntPoint(0, 0);
mPointsInitialized = true;
mRadius.x = aRadiusX;
mRadius.y = aRadiusY;
mRotationAngle = aRotationAngle;
mForce = aForce;
mChanged = false;
mMessage = 0;
}
nsDOMTouch(PRInt32 aIdentifier,
nsIntPoint aPoint,
nsIntPoint aRadius,
float aRotationAngle,
float aForce)
{
mIdentifier = aIdentifier;
mPagePoint = nsIntPoint(0, 0);
mScreenPoint = nsIntPoint(0, 0);
mClientPoint = nsIntPoint(0, 0);
mRefPoint = aPoint;
mPointsInitialized = false;
mRadius = aRadius;
mRotationAngle = aRotationAngle;
mForce = aForce;
mChanged = false;
mMessage = 0;
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouch)
NS_DECL_NSIDOMTOUCH
void InitializePoints(nsPresContext* aPresContext, nsEvent* aEvent)
{
if (mPointsInitialized) {
return;
}
mClientPoint = nsDOMEvent::GetClientCoords(aPresContext,
aEvent,
mRefPoint,
mClientPoint);
mPagePoint = nsDOMEvent::GetPageCoords(aPresContext,
aEvent,
mRefPoint,
mClientPoint);
mScreenPoint = nsDOMEvent::GetScreenCoords(aPresContext, aEvent, mRefPoint);
mPointsInitialized = true;
}
void SetTarget(nsIDOMEventTarget *aTarget)
{
mTarget = aTarget;
}
bool Equals(nsIDOMTouch* aTouch);
protected:
nsCOMPtr<nsIDOMEventTarget> mTarget;
bool mPointsInitialized;
PRInt32 mIdentifier;
PRInt32 mPageX;
PRInt32 mPageY;
PRInt32 mScreenX;
PRInt32 mScreenY;
PRInt32 mClientX;
PRInt32 mClientY;
PRInt32 mRadiusX;
PRInt32 mRadiusY;
nsIntPoint mPagePoint;
nsIntPoint mClientPoint;
nsIntPoint mScreenPoint;
nsIntPoint mRadius;
float mRotationAngle;
float mForce;
};
@ -94,25 +133,28 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
NS_DECL_NSIDOMTOUCHLIST
nsDOMTouchList() { }
nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches);
void Append(nsIDOMTouch* aPoint)
{
mPoints.AppendObject(aPoint);
mPoints.AppendElement(aPoint);
}
nsIDOMTouch* GetItemAt(PRUint32 aIndex)
{
return mPoints.SafeObjectAt(aIndex);
return mPoints.SafeElementAt(aIndex, nsnull);
}
protected:
nsCOMArray<nsIDOMTouch> mPoints;
nsTArray<nsCOMPtr<nsIDOMTouch> > mPoints;
};
class nsDOMTouchEvent : public nsDOMUIEvent,
public nsIDOMTouchEvent
{
public:
nsDOMTouchEvent(nsPresContext* aPresContext, nsInputEvent* aEvent);
nsDOMTouchEvent(nsPresContext* aPresContext, nsTouchEvent* aEvent);
virtual ~nsDOMTouchEvent();
NS_DECL_ISUPPORTS_INHERITED

View File

@ -244,7 +244,18 @@ NS_IMETHODIMP
nsDOMUIEvent::GetPageX(PRInt32* aPageX)
{
NS_ENSURE_ARG_POINTER(aPageX);
#ifdef MOZ_TOUCH
if (mPrivateDataDuplicated) {
*aPageX = mPagePoint.x;
} else {
*aPageX = nsDOMEvent::GetPageCoords(mPresContext,
mEvent,
mEvent->refPoint,
mClientPoint).x;
}
#else
*aPageX = GetPagePoint().x;
#endif
return NS_OK;
}
@ -252,7 +263,18 @@ NS_IMETHODIMP
nsDOMUIEvent::GetPageY(PRInt32* aPageY)
{
NS_ENSURE_ARG_POINTER(aPageY);
#ifdef MOZ_TOUCH
if (mPrivateDataDuplicated) {
*aPageY = mPagePoint.y;
} else {
*aPageY = nsDOMEvent::GetPageCoords(mPresContext,
mEvent,
mEvent->refPoint,
mClientPoint).y;
}
#else
*aPageY = GetPagePoint().y;
#endif
return NS_OK;
}
@ -338,6 +360,7 @@ nsDOMUIEvent::GetLayerPoint()
mEvent->eventStructType != NS_POPUP_EVENT &&
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
mEvent->eventStructType != NS_TOUCH_EVENT &&
mEvent->eventStructType != NS_DRAG_EVENT &&
mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
!mPresContext ||
@ -390,11 +413,27 @@ nsDOMUIEvent::GetIsChar(bool* aIsChar)
NS_METHOD
nsDOMUIEvent::DuplicatePrivateData()
{
#ifdef MOZ_TOUCH
mClientPoint = nsDOMEvent::GetClientCoords(mPresContext,
mEvent,
mEvent->refPoint,
mClientPoint);
mLayerPoint = GetLayerPoint();
mPagePoint = nsDOMEvent::GetPageCoords(mPresContext,
mEvent,
mEvent->refPoint,
mClientPoint);
// GetScreenPoint converts mEvent->refPoint to right coordinates.
nsIntPoint screenPoint = nsDOMEvent::GetScreenCoords(mPresContext,
mEvent,
mEvent->refPoint);
#else
mClientPoint = GetClientPoint();
mLayerPoint = GetLayerPoint();
mPagePoint = GetPagePoint();
// GetScreenPoint converts mEvent->refPoint to right coordinates.
nsIntPoint screenPoint = GetScreenPoint();
#endif
nsresult rv = nsDOMEvent::DuplicatePrivateData();
if (NS_SUCCEEDED(rv)) {
mEvent->refPoint = screenPoint;

View File

@ -68,8 +68,8 @@ public:
JSContext* aCx, jsval* aVal);
protected:
// Internal helper functions
nsIntPoint GetClientPoint();
nsIntPoint GetScreenPoint();
nsIntPoint GetClientPoint();
nsIntPoint GetLayerPoint();
nsIntPoint GetPagePoint();

View File

@ -808,6 +808,9 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
case NS_MOZTOUCH_EVENT:
return NS_NewDOMMozTouchEvent(aDOMEvent, aPresContext,
static_cast<nsMozTouchEvent*>(aEvent));
case NS_TOUCH_EVENT:
return NS_NewDOMTouchEvent(aDOMEvent, aPresContext,
static_cast<nsTouchEvent*>(aEvent));
case NS_TRANSITION_EVENT:
return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext,
static_cast<nsTransitionEvent*>(aEvent));

View File

@ -130,6 +130,12 @@ _TEST_FILES += \
$(NULL)
endif
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
_TEST_FILES += \
test_bug603008.html \
$(NULL)
endif
_CHROME_FILES = \
test_bug336682_2.xul \
test_bug336682.js \

View File

@ -0,0 +1,524 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=508906
-->
<head>
<title>Test for Bug 603008</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=508906">Mozilla Bug 603008</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">
/** Test for Bug 306008 - Touch* Events **/
let tests = [], testTarget, parent;
let touch = {
id: 0,
point: {x: 0, y: 0},
radius: {x: 0, y: 0},
rotation: 0,
force: 0.5,
target: null
}
function nextTest() {
if (tests.length)
SimpleTest.executeSoon(tests.shift());
}
function random() {
return Math.floor(Math.random() * 100);
}
function checkEvent(aFakeEvent) {
return function(aEvent) {
is(aFakeEvent.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
is(aFakeEvent.altKey, aEvent.altKey, "Correct altKey");
is(aFakeEvent.shiftKey, aEvent.shiftKey, "Correct shiftKey");
is(aFakeEvent.metaKey, aEvent.metaKey, "Correct metaKey");
checkTouches(aFakeEvent.touches, aEvent.touches);
checkTouches(aFakeEvent.targetTouches, aEvent.targetTouches);
checkTouches(aFakeEvent.changedTouches, aEvent.changedTouches);
}
}
function checkTouches(aTouches1, aTouches2) {
is(aTouches1.length, aTouches2.length, "Correct touches length");
for (var i = 0; i < aTouches1.length; i++) {
checkTouch(aTouches1[i], aTouches2[i]);
}
}
function checkTouch(aFakeTouch, aTouch) {
is(aFakeTouch.identifier, aTouch.identifier, "Touch has correct identifier");
is(aFakeTouch.target, aTouch.target, "Touch has correct target");
is(aFakeTouch.page.x, aTouch.pageX, "Touch has correct pageX");
is(aFakeTouch.page.y, aTouch.pageY, "Touch has correct pageY");
is(aFakeTouch.page.x + Math.round(window.mozInnerScreenX), aTouch.screenX, "Touch has correct screenX");
is(aFakeTouch.page.y + Math.round(window.mozInnerScreenY), aTouch.screenY, "Touch has correct screenY");
is(aFakeTouch.page.x, aTouch.clientX, "Touch has correct clientX");
is(aFakeTouch.page.y, aTouch.clientY, "Touch has correct clientY");
is(aFakeTouch.radius.x, aTouch.radiusX, "Touch has correct radiusX");
is(aFakeTouch.radius.y, aTouch.radiusY, "Touch has correct radiusY");
is(aFakeTouch.rotationAngle, aTouch.rotationAngle, "Touch has correct rotationAngle");
is(aFakeTouch.force, aTouch.force, "Touch has correct force");
}
function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
var ids = [], xs=[], ys=[], rxs = [], rys = [],
rotations = [], forces = [];
for each (var touchType in ["touches", "changedTouches", "targetTouches"]) {
for (var i = 0; i < aEvent[touchType].length; i++) {
if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
ids.push(aEvent[touchType][i].identifier);
xs.push(aEvent[touchType][i].page.x);
ys.push(aEvent[touchType][i].page.y);
rxs.push(aEvent[touchType][i].radius.x);
rys.push(aEvent[touchType][i].radius.y);
rotations.push(aEvent[touchType][i].rotationAngle);
forces.push(aEvent[touchType][i].force);
}
}
}
return windowUtils.sendTouchEvent(aType,
ids, xs, ys, rxs, rys,
rotations, forces,
ids.length, aModifiers, 0);
}
function touchEvent(aOptions) {
if (!aOptions) {
aOptions = {};
}
this.ctrlKey = aOptions.ctrlKey || false;
this.altKey = aOptions.altKey || false;
this.shiftKey = aOptions.shiftKey || false;
this.metaKey = aOptions.metaKey || false;
this.touches = aOptions.touches || [];
this.targetTouches = aOptions.targetTouches || [];
this.changedTouches = aOptions.changedTouches || [];
}
function testtouch(aOptions) {
if (!aOptions)
aOptions = {};
this.identifier = aOptions.identifier || 0;
this.target = aOptions.target || 0;
this.page = aOptions.page || {x: 0, y: 0};
this.radius = aOptions.radius || {x: 0, y: 0};
this.rotationAngle = aOptions.rotationAngle || 0;
this.force = aOptions.force || 1;
}
function testSingleTouch(name) {
let cwu = SpecialPowers.getDOMWindowUtils(window);
let target = document.getElementById("testTarget");
let target2 = document.getElementById("testTarget2");
let bcr = target.getBoundingClientRect();
let bcr2 = target2.getBoundingClientRect();
let touch1 = new testtouch({
page: {x: Math.round(bcr.left + bcr.width/2),
y: Math.round(bcr.top + bcr.height/2)},
target: target
});
let event = new touchEvent({
touches: [touch1],
targetTouches: [touch1],
changedTouches: [touch1]
});
// test touchstart event fires correctly
var checkFunction = checkEvent(event);
window.addEventListener("touchstart", checkFunction, false);
sendTouchEvent(cwu, "touchstart", event, 0);
window.removeEventListener("touchstart", checkFunction, false);
// test touchmove event fires correctly
event.touches[0].page.x -= 1;
event.targetTouches[0].page.x -= 1;
event.changedTouches[0].page.x -= 1;
checkFunction = checkEvent(event);
window.addEventListener("touchmove", checkFunction, false);
sendTouchEvent(cwu, "touchmove", event, 0);
window.removeEventListener("touchmove", checkFunction, false);
// test touchend event fires correctly
event.touches = [];
event.targetTouches = [];
checkFunction = checkEvent(event);
window.addEventListener("touchend", checkFunction, false);
sendTouchEvent(cwu, "touchend", event, 0);
window.removeEventListener("touchend", checkFunction, false);
nextTest();
}
function testSingleTouch2(name) {
// firing a touchstart that includes only one touch will evict any touches in the queue with touchend messages
let cwu = SpecialPowers.getDOMWindowUtils(window);
let target = document.getElementById("testTarget");
let target2 = document.getElementById("testTarget2");
let bcr = target.getBoundingClientRect();
let bcr2 = target2.getBoundingClientRect();
let touch1 = new testtouch({
identifier: 0,
page: {x: Math.round(bcr.left + bcr.width/2),
y: Math.round(bcr.top + bcr.height/2)},
target: target
});
let event1 = new touchEvent({
touches: [touch1],
targetTouches: [touch1],
changedTouches: [touch1]
});
let touch2 = new testtouch({
identifier: 1,
page: {x: Math.round(bcr2.left + bcr2.width/2),
y: Math.round(bcr2.top + bcr2.height/2)},
target: target2
});
let event2 = new touchEvent({
touches: [touch2],
targetTouches: [touch2],
changedTouches: [touch2]
});
// test touchstart event fires correctly
var checkFunction1 = checkEvent(event1);
window.addEventListener("touchstart", checkFunction1, false);
sendTouchEvent(cwu, "touchstart", event1, 0);
window.removeEventListener("touchstart", checkFunction1, false);
event1.touches = [];
event1.targetTouches = [];
checkFunction1 = checkEvent(event1);
var checkFunction2 = checkEvent(event2);
window.addEventListener("touchend", checkFunction1, false);
window.addEventListener("touchstart", checkFunction2, false);
sendTouchEvent(cwu, "touchstart", event2, 0);
window.removeEventListener("touchend", checkFunction1, false);
window.removeEventListener("touchstart", checkFunction2, false);
sendTouchEvent(cwu, "touchstart", event1, 0);
nextTest();
}
function testMultiTouch(name) {
let cwu = SpecialPowers.getDOMWindowUtils(window);
let target1 = document.getElementById("testTarget");
let target2 = document.getElementById("testTarget2");
let bcr = target1.getBoundingClientRect();
let bcr2 = target2.getBoundingClientRect();
let touch1 = new testtouch({
identifier: 0,
page: {x: Math.round(bcr.left + bcr.width/2),
y: Math.round(bcr.top + bcr.height/2)},
target: target1
});
let touch2 = new testtouch({
identifier: 1,
page: {x: Math.round(bcr2.left + bcr2.width/2),
y: Math.round(bcr2.top + bcr2.height/2)},
target: target2
});
let event = new touchEvent({
touches: [touch1],
targetTouches: [touch1],
changedTouches: [touch1]
});
// test touchstart event fires correctly
var checkFunction = checkEvent(event);
window.addEventListener("touchstart", checkFunction, false);
sendTouchEvent(cwu, "touchstart", event, 0);
window.removeEventListener("touchstart", checkFunction, false);
event.touches.push(touch2);
event.targetTouches = [touch2];
event.changedTouches = [touch2];
window.addEventListener("touchstart", checkFunction, false);
sendTouchEvent(cwu, "touchstart", event, 0);
window.removeEventListener("touchstart", checkFunction, false);
// test moving one touch point
event.touches[0].page.x -= 1;
event.targetTouches = [event.touches[0]];
event.changedTouches = [event.touches[0]];
window.addEventListener("touchmove", checkFunction, false);
sendTouchEvent(cwu, "touchmove", event, 0);
window.removeEventListener("touchmove", checkFunction, false);
// test moving both touch points -- two touchmove events should fire, one on each target
event.touches[0].page.x -= 1;
event.touches[1].page.x -= 1;
event.targetTouches = event.touches;
event.changedTouches = event.touches;
var touchMoveEvents = 0;
var checkFunction2 = function(aEvent) {
is(event.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
is(event.altKey, aEvent.altKey, "Correct altKey");
is(event.shiftKey, aEvent.shiftKey, "Correct shiftKey");
is(event.metaKey, aEvent.metaKey, "Correct metaKey");
checkTouches(event.touches, aEvent.touches);
checkTouches(event.changedTouches, aEvent.changedTouches);
if (aEvent.targetTouches[0].target == target1) {
checkTouches([event.touches[0]], aEvent.targetTouches);
} else if (aEvent.targetTouches[0].target == target2) {
checkTouches([event.touches[1]], aEvent.targetTouches);
} else
ok(false, "Event target is incorrect: " + event.targetTouches[0].target.nodeName + "#" + event.targetTouches[0].target.id);
touchMoveEvents++;
};
window.addEventListener("touchmove", checkFunction2, false);
sendTouchEvent(cwu, "touchmove", event, 0);
ok(touchMoveEvents, 2, "Correct number of touchmove events fired");
window.removeEventListener("touchmove", checkFunction2, false);
// test removing just one finger
var expected = new touchEvent({
touches: [touch2],
targetTouches: [],
changedTouches: [touch1]
});
checkFunction = checkEvent(expected);
event.touches = [];
event.targetTouches = [];
event.changedTouches = [touch1];
// test removing the other finger
window.addEventListener("touchend", checkFunction, false);
sendTouchEvent(cwu, "touchend", event, 0);
window.removeEventListener("touchend", checkFunction, false);
event.touches = [];
event.targetTouches = [];
event.changedTouches = [touch2];
checkFunction = checkEvent(event);
window.addEventListener("touchend", checkFunction, false);
sendTouchEvent(cwu, "touchend", event, 0);
window.removeEventListener("touchend", checkFunction, false);
nextTest();
}
function testTouchChanged() {
let cwu = SpecialPowers.getDOMWindowUtils(window);
let target1 = document.getElementById("testTarget");
let bcr = target1.getBoundingClientRect();
let touch1 = new testtouch({
identifier: 0,
page: {x: Math.round(bcr.left + bcr.width/2),
y: Math.round(bcr.top + bcr.height/2)},
target: target1
});
let event = new touchEvent({
touches: [touch1],
targetTouches: [touch1],
changedTouches: [touch1]
});
var checkFunction = checkEvent(event);
sendTouchEvent(cwu, "touchstart", event, 0);
var moveEvents = 0;
function onMove(aEvent) {
moveEvents++;
}
window.addEventListener("touchmove", onMove, false);
// changing nothing should not fire a touchmove event
sendTouchEvent(cwu, "touchmove", event, 0);
// test moving x
event.touches[0].page.x -= 1;
sendTouchEvent(cwu, "touchmove", event, 0);
// test moving y
event.touches[0].page.y -= 1;
sendTouchEvent(cwu, "touchmove", event, 0);
// test changing y radius
event.touches[0].radius.y += 1;
sendTouchEvent(cwu, "touchmove", event, 0);
// test changing x radius
event.touches[0].radius.x += 1;
sendTouchEvent(cwu, "touchmove", event, 0);
// test changing rotationAngle
event.touches[0].rotationAngle += 1;
sendTouchEvent(cwu, "touchmove", event, 0);
// test changing force
event.touches[0].force += 1;
sendTouchEvent(cwu, "touchmove", event, 0);
// changing nothing again
sendTouchEvent(cwu, "touchmove", event, 0);
is(moveEvents, 6, "Six move events fired");
window.removeEventListener("touchmove", onMove, false);
sendTouchEvent(cwu, "touchend", event, 0);
nextTest();
}
function testPreventDefault() {
let cwu = SpecialPowers.getDOMWindowUtils(window);
let target = document.getElementById("testTarget");
let target2 = document.getElementById("testTarget2");
let bcr = target.getBoundingClientRect();
let bcr2 = target2.getBoundingClientRect();
let touch1 = new testtouch({
page: {x: bcr.left + bcr.width/2,
y: bcr.top + bcr.height/2},
target: target
});
let event = new touchEvent({
touches: [touch1],
targetTouches: [touch1],
changedTouches: [touch1]
});
let preventFunction = function(aEvent) {
aEvent.preventDefault();
}
let tests = [
[{ name: "touchstart", prevent: false },
{ name: "touchmove", prevent: false },
{ name: "touchmove", prevent: false },
{ name: "touchend", prevent: false }],
[{ name: "touchstart", prevent: true, doPrevent: true },
{ name: "touchmove", prevent: true },
{ name: "touchmove", prevent: true },
{ name: "touchend", prevent: true }],
[{ name: "touchstart", prevent: false },
{ name: "touchmove", prevent: true, doPrevent: true },
{ name: "touchmove", prevent: true },
{ name: "touchend", prevent: true }],
[{ name: "touchstart", prevent: false },
{ name: "touchmove", prevent: false },
{ name: "touchmove", prevent: false, doPrevent: true },
{ name: "touchend", prevent: false }],
[{ name: "touchstart", prevent: false },
{ name: "touchmove", prevent: false },
{ name: "touchmove", prevent: false },
{ name: "touchend", prevent: false, doPrevent: true }]
];
var dotest = function(aTest) {
if (aTest.doPrevent) {
target.addEventListener(aTest.name, preventFunction, false);
}
if (aTest.name == "touchmove") {
touch1.page.x++;
event.touches[0] = touch1;
}
is(sendTouchEvent(cwu, aTest.name, event, 0), aTest.prevent, "Got correct status");
if (aTest.doPrevent)
target.removeEventListener(aTest.name, preventFunction, false);
}
for (var i = 0; i < tests.length; i++) {
for (var j = 0; j < tests[i].length; j++) {
dotest(tests[i][j]);
}
}
nextTest();
}
function testRemovingElement() {
let cwu = SpecialPowers.getDOMWindowUtils(window);
let target = document.getElementById("testTarget");
let bcr = document.getElementById("testTarget").getBoundingClientRect();
let touch1 = new testtouch({
page: {x: bcr.left + bcr.width/2,
y: bcr.top + bcr.height/2},
});
let e = new touchEvent({
touches: [touch1],
targetTouches: [touch1],
changedTouches: [touch1]
});
var touchEvents = 0;
var removeTarget = function(aEvent) {
aEvent.target.parentNode.removeChild(aEvent.target);
};
var checkTarget = function(aEvent) {
is(aEvent.target, target, "Event has correct target");
touchEvents++;
};
target.addEventListener("touchstart", removeTarget, false);
target.addEventListener("touchmove", checkTarget, false);
target.addEventListener("touchend", checkTarget, false);
sendTouchEvent(cwu, "touchstart", e, 0);
e.touches[0].page.x++;
sendTouchEvent(cwu, "touchmove", e, 0);
sendTouchEvent(cwu, "touchend", e, 0);
target.removeEventListener("touchstart", removeTarget, false);
target.removeEventListener("touchmove", checkTarget, false);
target.removeEventListener("touchend", checkTarget, false);
is(touchEvents, 2, "Check target was called twice");
nextTest();
}
function doTest() {
tests.push(testSingleTouch);
tests.push(testSingleTouch2);
tests.push(testMultiTouch);
tests.push(testPreventDefault);
tests.push(testTouchChanged);
tests.push(testRemovingElement);
tests.push(function() {
SimpleTest.finish();
});
nextTest();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</pre>
<div id="parent">
<span id="testTarget" style="padding: 5px; border: 1px solid black;">testTarget</span>
<span id="testTarget2" style="padding: 5px; border: 1px solid blue;">testTarget</span>
</div>
</body>
</html>

View File

@ -49,6 +49,8 @@
#include "nsEventStateManager.h"
#include "nsFrameManager.h"
#include "nsRefreshDriver.h"
#include "nsDOMTouchEvent.h"
#include "nsIDOMTouchEvent.h"
#include "nsIScrollableFrame.h"
@ -550,6 +552,79 @@ nsDOMWindowUtils::SendMouseScrollEvent(const nsAString& aType,
return widget->DispatchEvent(&event, status);
}
NS_IMETHODIMP
nsDOMWindowUtils::SendTouchEvent(const nsAString& aType,
PRUint32 *aIdentifiers,
PRInt32 *aXs,
PRInt32 *aYs,
PRUint32 *aRxs,
PRUint32 *aRys,
float *aRotationAngles,
float *aForces,
PRUint32 aCount,
PRInt32 aModifiers,
bool aIgnoreRootScrollFrame,
bool *aPreventDefault)
{
if (!IsUniversalXPConnectCapable()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
// get the widget to send the event to
nsPoint offset;
nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
if (!widget) {
return NS_ERROR_NULL_POINTER;
}
PRInt32 msg;
if (aType.EqualsLiteral("touchstart")) {
msg = NS_TOUCH_START;
} else if (aType.EqualsLiteral("touchmove")) {
msg = NS_TOUCH_MOVE;
} else if (aType.EqualsLiteral("touchend")) {
msg = NS_TOUCH_END;
} else if (aType.EqualsLiteral("touchcancel")) {
msg = NS_TOUCH_CANCEL;
} else {
return NS_ERROR_UNEXPECTED;
}
nsTouchEvent event(true, msg, widget);
event.isShift = (aModifiers & nsIDOMNSEvent::SHIFT_MASK) ? true : false;
event.isControl = (aModifiers & nsIDOMNSEvent::CONTROL_MASK) ? true : false;
event.isAlt = (aModifiers & nsIDOMNSEvent::ALT_MASK) ? true : false;
event.isMeta = (aModifiers & nsIDOMNSEvent::META_MASK) ? true : false;
event.widget = widget;
event.time = PR_Now();
nsPresContext* presContext = GetPresContext();
if (!presContext) {
return NS_ERROR_FAILURE;
}
event.touches.SetCapacity(aCount);
PRInt32 appPerDev = presContext->AppUnitsPerDevPixel();
for (int i = 0; i < aCount; ++i) {
nsIntPoint pt(0, 0);
pt.x =
NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aXs[i]) + offset.x,
appPerDev);
pt.y =
NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aYs[i]) + offset.y,
appPerDev);
nsCOMPtr<nsIDOMTouch> t(new nsDOMTouch(aIdentifiers[i],
pt,
nsIntPoint(aRxs[i], aRys[i]),
aRotationAngles[i],
aForces[i]));
event.touches.AppendElement(t);
}
nsEventStatus status;
nsresult rv = widget->DispatchEvent(&event, status);
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
return rv;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
PRInt32 aKeyCode,

View File

@ -68,8 +68,9 @@ interface nsIDOMWindow;
interface nsIDOMBlob;
interface nsIDOMFile;
interface nsIFile;
interface nsIDOMTouch;
[scriptable, uuid(b9c1f815-c2f2-4607-a060-6a8566581927)]
[scriptable, uuid(e01171b0-712a-47ce-8552-b7b2ef0a2507)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -227,6 +228,45 @@ interface nsIDOMWindowUtils : nsISupports {
in long aModifiers,
[optional] in boolean aIgnoreRootScrollFrame);
/** Synthesize a touch event. The event types supported are:
* touchstart, touchend, touchmove, and touchcancel
*
* Events are sent in coordinates offset by aX and aY from the window.
*
* Cannot be accessed from unprivileged context (not content-accessible)
* Will throw a DOM security error if called without UniversalXPConnect
* privileges.
*
* The event is dispatched via the toplevel window, so it could go to any
* window under the toplevel window, in some cases it could never reach this
* window at all.
*
* @param aType event type
* @param xs array of offsets in CSS pixels for each touch to be sent
* @param ys array of offsets in CSS pixels for each touch to be sent
* @param rxs array of radii in CSS pixels for each touch to be sent
* @param rys array of radii in CSS pixels for each touch to be sent
* @param rotationAngles array of angles in degrees for each touch to be sent
* @param forces array of forces (floats from 0 to 1) for each touch to be sent
* @param count number of touches in this set
* @param aModifiers modifiers pressed, using constants defined in nsIDOMNSEvent
* @param aIgnoreRootScrollFrame whether the event should ignore viewport bounds
* during dispatch
*
* returns true if the page called prevent default on this touch event
*/
boolean sendTouchEvent(in AString aType,
[array, size_is(count)] in PRUint32 aIdentifiers,
[array, size_is(count)] in PRInt32 aXs,
[array, size_is(count)] in PRInt32 aYs,
[array, size_is(count)] in PRUint32 aRxs,
[array, size_is(count)] in PRUint32 aRys,
[array, size_is(count)] in float aRotationAngles,
[array, size_is(count)] in float aForces,
in PRUint32 count,
in long aModifiers,
[optional] in boolean aIgnoreRootScrollFrame);
/** The same as sendMouseEvent but ensures that the event is dispatched to
* this DOM window or one of its children.
*/

View File

@ -36,13 +36,17 @@
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMUIEvent.idl"
%{C++
#include "nsWeakPtr.h"
#include "nsPoint.h"
%}
interface nsIVariant;
/**
* @see http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
*/
[scriptable, uuid(98bc0f7d-5bff-4387-9c42-58af54b48dd5)]
[scriptable, builtinclass, uuid(98bc0f7d-5bff-4387-9c42-58af54b48dd5)]
interface nsIDOMTouch : nsISupports {
readonly attribute long identifier;
readonly attribute nsIDOMEventTarget target;
@ -56,6 +60,14 @@ interface nsIDOMTouch : nsISupports {
readonly attribute long radiusY;
readonly attribute float rotationAngle;
readonly attribute float force;
%{C++
nsCOMPtr<nsIDOMEventTarget> mTarget;
nsIDOMEventTarget *GetTarget() { return mTarget; }
void SetTarget(nsIDOMEventTarget *target) { mTarget = target; }
nsIntPoint mRefPoint;
bool mChanged;
PRUint32 mMessage;
%}
};
[scriptable, uuid(60706eb7-d50d-4379-b01c-e78e6af84213)]

View File

@ -69,6 +69,8 @@
#include "nsWeakReference.h"
#include <stdio.h> // for FILE definition
#include "nsChangeHint.h"
#include "nsGUIEvent.h"
#include "nsInterfaceHashtable.h"
class nsIContent;
class nsIDocument;
@ -1047,6 +1049,9 @@ public:
static CapturingContentInfo gCaptureInfo;
static nsInterfaceHashtable<nsUint32HashKey, nsIDOMTouch> gCaptureTouchList;
static bool gPreventMouseEvents;
/**
* When capturing content is set, it traps all mouse events and retargets
* them at this content node. If capturing is not allowed

View File

@ -956,13 +956,20 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT &&
aEvent->eventStructType != NS_GESTURENOTIFY_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
#ifdef MOZ_TOUCH
aEvent->eventStructType != NS_TOUCH_EVENT &&
#endif
aEvent->eventStructType != NS_QUERY_CONTENT_EVENT))
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
const nsGUIEvent* GUIEvent = static_cast<const nsGUIEvent*>(aEvent);
#ifdef MOZ_TOUCH
return GetEventCoordinatesRelativeTo(aEvent,
GUIEvent->refPoint,
aFrame);
#else
if (!GUIEvent->widget)
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
/* If we walk up the frame tree and discover that any of the frames are
* transformed, we need to do extra work to convert from the global
* space to the local space.
@ -973,7 +980,6 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
if (f->IsTransformed())
transformFound = true;
rootFrame = f;
}
@ -1004,6 +1010,68 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
* so we can just subtract out the different.
*/
return widgetToView - aFrame->GetOffsetToCrossDoc(rootFrame);
#endif
}
nsPoint
nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent,
const nsIntPoint aPoint,
nsIFrame* aFrame)
{
if (!aFrame) {
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
const nsGUIEvent* GUIEvent = static_cast<const nsGUIEvent*>(aEvent);
nsIWidget* widget = GUIEvent->widget;
if (!widget) {
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
/* If we walk up the frame tree and discover that any of the frames are
* transformed, we need to do extra work to convert from the global
* space to the local space.
*/
nsIFrame* rootFrame = aFrame;
bool transformFound = false;
for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
if (f->IsTransformed()) {
transformFound = true;
}
rootFrame = f;
}
nsIView* rootView = rootFrame->GetView();
if (!rootView) {
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
nsPoint widgetToView = TranslateWidgetToView(rootFrame->PresContext(),
widget, aPoint, rootView);
if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
// Convert from root document app units to app units of the document aFrame
// is in.
PRInt32 rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
PRInt32 localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
widgetToView = widgetToView.ConvertAppUnits(rootAPD, localAPD);
/* If we encountered a transform, we can't do simple arithmetic to figure
* out how to convert back to aFrame's coordinates and must use the CTM.
*/
if (transformFound) {
return TransformRootPointToFrame(aFrame, widgetToView);
}
/* Otherwise, all coordinate systems are translations of one another,
* so we can just subtract out the different.
*/
nsPoint offset = aFrame->GetOffsetToCrossDoc(rootFrame);
return widgetToView - offset;
}
nsIFrame*

View File

@ -425,6 +425,20 @@ public:
static nsPoint GetEventCoordinatesRelativeTo(const nsEvent* aEvent,
nsIFrame* aFrame);
/**
* Get the coordinates of a given point relative to an event and a
* given frame.
* @param aEvent the event
* @param aPoint the point to get the coordinates relative to
* @param aFrame the frame to make coordinates relative to
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
* for some reason the coordinates for the mouse are not known (e.g.,
* the event is not a GUI event).
*/
static nsPoint GetEventCoordinatesRelativeTo(const nsEvent* aEvent,
const nsIntPoint aPoint,
nsIFrame* aFrame);
/**
* Get the popup frame of a given native mouse event.
* @param aPresContext only check popups within aPresContext or a descendant

View File

@ -119,6 +119,7 @@
#include "nsILineIterator.h" // for ScrollContentIntoView
#include "nsWeakPtr.h"
#include "pldhash.h"
#include "nsDOMTouchEvent.h"
#include "nsIObserverService.h"
#include "nsIDocShell.h" // for reflow observation
#include "nsIBaseWindow.h"
@ -235,6 +236,8 @@ CapturingContentInfo nsIPresShell::gCaptureInfo =
{ false /* mAllowed */, false /* mRetargetToElement */,
false /* mPreventDrag */, nsnull /* mContent */ };
nsIContent* nsIPresShell::gKeyDownTarget;
nsInterfaceHashtable<nsUint32HashKey, nsIDOMTouch> nsIPresShell::gCaptureTouchList;
bool nsIPresShell::gPreventMouseEvents = false;
static PRUint32
ChangeFlag(PRUint32 aFlags, bool aOnOff, PRUint32 aFlag)
@ -5709,6 +5712,54 @@ PresShell::RecordMouseLocation(nsGUIEvent* aEvent)
}
}
static void
EvictTouchPoint(nsCOMPtr<nsIDOMTouch>& aTouch)
{
nsIWidget *widget = nsnull;
// is there an easier/better way to dig out the widget?
nsCOMPtr<nsINode> node(do_QueryInterface(aTouch->GetTarget()));
if (!node) {
return;
}
nsIDocument* doc = node->GetCurrentDoc();
if (!doc) {
return;
}
nsIPresShell *presShell = doc->GetShell();
if (!presShell) {
return;
}
nsIFrame* frame = presShell->GetRootFrame();
if (!frame) {
return;
}
nsPoint *pt = new nsPoint(aTouch->mRefPoint.x, aTouch->mRefPoint.y);
widget = frame->GetView()->GetNearestWidget(pt);
if (!widget) {
return;
}
nsTouchEvent event(true, NS_TOUCH_END, widget);
event.isShift = false;
event.isControl = false;
event.isAlt = false;
event.isMeta = false;
event.widget = widget;
event.time = PR_IntervalNow();
event.touches.AppendElement(aTouch);
nsEventStatus status;
widget->DispatchEvent(&event, status);
}
static PLDHashOperator
AppendToTouchList(const PRUint32& aKey, nsCOMPtr<nsIDOMTouch>& aData, void *aTouchList)
{
nsTArray<nsCOMPtr<nsIDOMTouch> > *touches = static_cast<nsTArray<nsCOMPtr<nsIDOMTouch> > *>(aTouchList);
aData->mChanged = false;
touches->AppendElement(aData);
return PL_DHASH_NEXT;
}
nsresult
PresShell::HandleEvent(nsIFrame *aFrame,
nsGUIEvent* aEvent,
@ -5921,8 +5972,59 @@ PresShell::HandleEvent(nsIFrame *aFrame,
// with a window-level mouse exit event since we want to start sending
// mouse out events at the root EventStateManager.
if (!captureRetarget && !isWindowLevelMouseExit) {
#ifdef MOZ_TOUCH
nsPoint eventPoint;
if (aEvent->message == NS_TOUCH_START) {
// Add any new touches to the queue
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
// if there is only one touch in this touchstart event, assume that it is
// the start of a new touch session and evict any old touches in the
// queue
if (touchEvent->touches.Length() == 1) {
nsTArray<nsCOMPtr<nsIDOMTouch> > touches;
gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
for (PRUint32 i = 0; i < touches.Length(); ++i) {
EvictTouchPoint(touches[i]);
}
}
for (PRUint32 i = 0; i < touchEvent->touches.Length(); ++i) {
nsIDOMTouch *touch = touchEvent->touches[i];
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
touch->mMessage = aEvent->message;
PRInt32 id = 0;
touch->GetIdentifier(&id);
if (!gCaptureTouchList.Get(id, nsnull)) {
// This event is a new touch. Mark it as a changedTouch and
// add it to the queue.
touch->mChanged = true;
gCaptureTouchList.Put(id, touch);
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touch->mRefPoint, frame);
} else {
// This touch is an old touch, we need to ensure that is not
// marked as changed and set its target correctly
touch->mChanged = false;
PRInt32 id;
touch->GetIdentifier(&id);
nsCOMPtr<nsIDOMTouch> oldTouch;
gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
if (oldTouch) {
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
oldTouch->GetTarget(getter_AddRefs(targetPtr));
domtouch->SetTarget(targetPtr);
gCaptureTouchList.Put(id, touch);
}
}
}
} else {
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
}
#else
nsPoint eventPoint
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
#endif
{
bool ignoreRootScrollFrame = false;
if (aEvent->eventStructType == NS_MOUSE_EVENT) {
@ -6322,6 +6424,9 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
nsresult rv = NS_OK;
if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
#ifdef MOZ_TOUCH
bool touchIsNew = false;
#endif
bool isHandlingUserInput = false;
// XXX How about IME events and input events for plugins?
@ -6364,6 +6469,84 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
case NS_MOUSE_BUTTON_UP:
isHandlingUserInput = true;
break;
#ifdef MOZ_TOUCH
case NS_TOUCH_CANCEL:
case NS_TOUCH_END: {
// Remove the changed touches
// need to make sure we only remove touches that are ending here
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
nsTArray<nsCOMPtr<nsIDOMTouch> > &touches = touchEvent->touches;
for (PRUint32 i = 0; i < touches.Length(); ++i) {
nsIDOMTouch *touch = touches[i];
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
if (!touch) {
continue;
}
touch->mMessage = aEvent->message;
touch->mChanged = true;
nsCOMPtr<nsIDOMTouch> oldTouch;
PRInt32 id;
touch->GetIdentifier(&id);
gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
if (!oldTouch) {
continue;
}
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
oldTouch->GetTarget(getter_AddRefs(targetPtr));
mCurrentEventContent = do_QueryInterface(targetPtr);
domtouch->SetTarget(targetPtr);
gCaptureTouchList.Remove(id);
}
// add any touches left in the touch list, but ensure changed=false
gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
break;
}
case NS_TOUCH_MOVE: {
// Check for touches that changed. Mark them add to queue
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
bool haveChanged = false;
for (PRUint32 i = 0; i < touches.Length(); ++i) {
nsIDOMTouch *touch = touches[i];
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
if (!touch) {
continue;
}
PRInt32 id;
touch->GetIdentifier(&id);
touch->mMessage = aEvent->message;
nsCOMPtr<nsIDOMTouch> oldTouch;
gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
if (!oldTouch) {
continue;
}
if(domtouch->Equals(oldTouch)) {
touch->mChanged = true;
haveChanged = true;
}
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
oldTouch->GetTarget(getter_AddRefs(targetPtr));
domtouch->SetTarget(targetPtr);
gCaptureTouchList.Put(id, touch);
// if we're moving from touchstart to touchmove for this touch
// we allow preventDefault to prevent mouse events
if (oldTouch->mMessage != touch->mMessage) {
touchIsNew = true;
}
}
// is nothing has changed, we should just return
if (!haveChanged) {
return NS_OK;
}
break;
}
#endif
case NS_DRAGDROP_DROP:
nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
if (session) {
@ -6389,7 +6572,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
if (me->isShift)
aEvent->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH |
NS_EVENT_RETARGET_TO_NON_NATIVE_ANONYMOUS;
}
}
nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
aEvent, mDocument);
@ -6422,7 +6605,14 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
// because they do not have a reliable refPoint.
if (!IsSynthesizedMouseEvent(aEvent)) {
nsPresShellEventCB eventCB(this);
#ifdef MOZ_TOUCH
if (aEvent->eventStructType == NS_TOUCH_EVENT) {
DispatchTouchEvent(aEvent, aStatus, &eventCB, touchIsNew);
}
else if (mCurrentEventContent) {
#else
if (mCurrentEventContent) {
#endif
nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
aEvent, nsnull, aStatus, &eventCB);
}
@ -6460,6 +6650,98 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
return rv;
}
void
PresShell::DispatchTouchEvent(nsEvent *aEvent,
nsEventStatus* aStatus,
nsPresShellEventCB* aEventCB,
bool aTouchIsNew)
{
nsresult rv = NS_OK;
// calling preventDefault on touchstart or the first touchmove for a
// point prevents mouse events
bool canPrevent = aEvent->message == NS_TOUCH_START ||
(aEvent->message == NS_TOUCH_MOVE && aTouchIsNew);
bool preventDefault = false;
nsEventStatus tmpStatus = nsEventStatus_eIgnore;
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
// touch events should fire on all targets
if (aEvent->message != NS_TOUCH_START) {
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
for (PRUint32 i = 0; i < touches.Length(); ++i) {
nsIDOMTouch *touch = touches[i];
if (!touch || !touch->mChanged) {
continue;
}
// copy the event
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
touch->GetTarget(getter_AddRefs(targetPtr));
if (!targetPtr) {
continue;
}
nsTouchEvent newEvent(touchEvent);
newEvent.target = targetPtr;
nsCOMPtr<nsIContent> content(do_QueryInterface(targetPtr));
nsPresContext *context = nsContentUtils::GetContextForContent(content);
if (!context) {
context = mPresContext;
}
tmpStatus = nsEventStatus_eIgnore;
nsEventDispatcher::Dispatch(targetPtr, context,
&newEvent, nsnull, &tmpStatus, aEventCB);
if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
preventDefault = true;
}
}
} else {
// touchevents need to have the target attribute set on each touch
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
for (PRUint32 i = 0; i < touches.Length(); ++i) {
nsIDOMTouch *touch = touches[i];
if (touch->mChanged) {
touch->SetTarget(mCurrentEventContent);
}
}
if (mCurrentEventContent) {
nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
aEvent, nsnull, &tmpStatus, aEventCB);
} else {
nsCOMPtr<nsIContent> targetContent;
rv = mCurrentEventFrame->GetContentForEvent(aEvent,
getter_AddRefs(targetContent));
if (NS_SUCCEEDED(rv) && targetContent) {
nsEventDispatcher::Dispatch(targetContent, mPresContext, aEvent,
nsnull, &tmpStatus, aEventCB);
} else if (mDocument) {
nsEventDispatcher::Dispatch(mDocument, mPresContext, aEvent,
nsnull, &tmpStatus, nsnull);
}
}
if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
preventDefault = true;
}
if (touchEvent->touches.Length() == 1) {
gPreventMouseEvents = false;
}
}
// if preventDefault was called on any of the events dispatched
// and this is touchstart, or the first touchmove, widget should consume
// other events that would be associated with this touch session
if (preventDefault && canPrevent) {
gPreventMouseEvents = true;
}
if (gPreventMouseEvents) {
*aStatus = nsEventStatus_eConsumeNoDefault;
} else {
*aStatus = nsEventStatus_eIgnore;
}
}
// Dispatch event to content only (NOT full processing)
// See also HandleEventWithTarget which does full event processing.
nsresult
@ -8723,6 +9005,7 @@ void nsIPresShell::InitializeStatics()
NS_ASSERTION(sLiveShells == nsnull, "InitializeStatics called multiple times!");
sLiveShells = new nsTHashtable<PresShellPtrKey>();
sLiveShells->Init();
gCaptureTouchList.Init();
}
void nsIPresShell::ReleaseStatics()

View File

@ -459,6 +459,12 @@ protected:
nsresult DidCauseReflow();
friend class nsAutoCauseReflowNotifier;
bool TouchesAreEqual(nsIDOMTouch *aTouch1, nsIDOMTouch *aTouch2);
void DispatchTouchEvent(nsEvent *aEvent,
nsEventStatus* aStatus,
nsPresShellEventCB* aEventCB,
bool aTouchIsNew);
void WillDoReflow();
void DidDoReflow(bool aInterruptible);
// ProcessReflowCommands returns whether we processed all our dirty roots

View File

@ -147,8 +147,7 @@ static ViewWrapper* GetWrapperFor(nsIWidget* aWidget)
static nsEventStatus HandleEvent(nsGUIEvent *aEvent)
{
#if 0
printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->widgetSupports,
aEvent->message, aEvent->point.x, aEvent->point.y);
printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->message);
#endif
nsEventStatus result = nsEventStatus_eIgnore;
nsView *view = nsView::GetViewFor(aEvent->widget);
@ -327,11 +326,13 @@ nsIView* nsIView::GetViewFor(nsIWidget* aWidget)
ViewWrapper* wrapper = GetWrapperFor(aWidget);
if (!wrapper)
if (!wrapper) {
wrapper = GetAttachedWrapperFor(aWidget);
}
if (wrapper)
if (wrapper) {
return wrapper->GetView();
}
return nsnull;
}

View File

@ -104,6 +104,7 @@ class nsFocusEvent;
class nsSelectionEvent;
class nsContentCommandEvent;
class nsMozTouchEvent;
class nsTouchEvent;
class nsFormEvent;
class nsCommandEvent;
class nsUIEvent;

View File

@ -42,6 +42,7 @@
#ifndef nsGUIEvent_h__
#define nsGUIEvent_h__
#include "nsCOMArray.h"
#include "nsPoint.h"
#include "nsRect.h"
#include "nsRegion.h"
@ -53,6 +54,7 @@
#include "nsIDOMMouseEvent.h"
#include "nsIDOMDataTransfer.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMTouchEvent.h"
#include "nsWeakPtr.h"
#include "nsIWidget.h"
#include "nsTArray.h"
@ -60,6 +62,7 @@
#include "nsITransferable.h"
#include "nsIVariant.h"
#include "nsStyleConsts.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace dom {
@ -124,6 +127,7 @@ class nsHashKey;
#define NS_UISTATECHANGE_EVENT 41
#define NS_MOZTOUCH_EVENT 42
#define NS_PLUGIN_EVENT 43
#define NS_TOUCH_EVENT 44
// These flags are sort of a mess. They're sort of shared between event
// listener flags and event flags, but only some of them. You've been
@ -546,6 +550,14 @@ class nsHashKey;
#define NS_FULLSCREENCHANGE (NS_FULL_SCREEN_START)
#define NS_FULLSCREENERROR (NS_FULL_SCREEN_START + 1)
#define NS_TOUCH_EVENT_START 5200
#define NS_TOUCH_START (NS_TOUCH_EVENT_START)
#define NS_TOUCH_MOVE (NS_TOUCH_EVENT_START+1)
#define NS_TOUCH_END (NS_TOUCH_EVENT_START+2)
#define NS_TOUCH_ENTER (NS_TOUCH_EVENT_START+3)
#define NS_TOUCH_LEAVE (NS_TOUCH_EVENT_START+4)
#define NS_TOUCH_CANCEL (NS_TOUCH_EVENT_START+5)
/**
* Return status for event processors, nsEventStatus, is defined in
* nsEvent.h.
@ -1528,6 +1540,31 @@ public:
PRUint32 streamId;
};
class nsTouchEvent : public nsInputEvent
{
public:
nsTouchEvent(nsTouchEvent *aEvent)
:nsInputEvent(aEvent->flags & NS_EVENT_FLAG_TRUSTED ? true : false,
aEvent->message,
aEvent->widget,
NS_TOUCH_EVENT)
{
touches.AppendElements(aEvent->touches);
MOZ_COUNT_CTOR(nsTouchEvent);
}
nsTouchEvent(bool isTrusted, PRUint32 msg, nsIWidget* w)
: nsInputEvent(isTrusted, msg, w, NS_TOUCH_EVENT)
{
MOZ_COUNT_CTOR(nsTouchEvent);
}
~nsTouchEvent()
{
MOZ_COUNT_DTOR(nsTouchEvent);
}
nsTArray<nsCOMPtr<nsIDOMTouch> > touches;
};
/**
* Form event
*