Bug 412486 - widget/event-detection support for multi-touch trackpad gestures, r=smaug,josh, sr=roc
authortdyas@zecador.org
Thu, 23 Oct 2008 23:15:20 +0300
changeset 20793 f39ecb5b05b7234a70560a339b2ab1cebe31eb10
parent 20792 c79936775c2ca4c39447fe47b4ee14e99f84b3e8
child 20794 b7bd85f1dd756ced1cc04a1d80052ffd2d7b1995
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, josh, roc
bugs412486
milestone1.9.1b2pre
Bug 412486 - widget/event-detection support for multi-touch trackpad gestures, r=smaug,josh, sr=roc
content/base/src/nsContentUtils.cpp
content/base/src/nsGkAtomList.h
content/events/public/nsIPrivateDOMEvent.h
content/events/src/Makefile.in
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMSimpleGestureEvent.cpp
content/events/src/nsDOMSimpleGestureEvent.h
content/events/src/nsEventDispatcher.cpp
dom/public/idl/base/nsIDOMWindowUtils.idl
dom/public/idl/events/Makefile.in
dom/public/idl/events/nsIDOMSimpleGestureEvent.idl
dom/public/nsDOMClassInfoID.h
dom/src/base/nsDOMClassInfo.cpp
dom/src/base/nsDOMWindowUtils.cpp
widget/public/nsEvent.h
widget/public/nsGUIEvent.h
widget/src/cocoa/nsChildView.h
widget/src/cocoa/nsChildView.mm
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -474,17 +474,26 @@ nsContentUtils::InitializeEventTable() {
     { &nsGkAtoms::ondataunavailable,             { NS_DATAUNAVAILABLE, EventNameType_HTML }},
     { &nsGkAtoms::oncanshowcurrentframe,         { NS_CANSHOWCURRENTFRAME, EventNameType_HTML }},
     { &nsGkAtoms::oncanplay,                     { NS_CANPLAY, EventNameType_HTML }},
     { &nsGkAtoms::oncanplaythrough,              { NS_CANPLAYTHROUGH, EventNameType_HTML }},
     { &nsGkAtoms::onratechange,                  { NS_RATECHANGE, EventNameType_HTML }},
     { &nsGkAtoms::ondurationchange,              { NS_DURATIONCHANGE, EventNameType_HTML }},
     { &nsGkAtoms::onvolumechange,                { NS_VOLUMECHANGE, EventNameType_HTML }},
 #endif //MOZ_MEDIA
-    { &nsGkAtoms::onMozAfterPaint,               { NS_AFTERPAINT, EventNameType_None }}
+    { &nsGkAtoms::onMozAfterPaint,               { NS_AFTERPAINT, EventNameType_None }},
+
+    // Simple gesture events
+    { &nsGkAtoms::onMozSwipeGesture,             { NS_SIMPLE_GESTURE_SWIPE, EventNameType_None } },
+    { &nsGkAtoms::onMozMagnifyGestureStart,      { NS_SIMPLE_GESTURE_MAGNIFY_START, EventNameType_None } },
+    { &nsGkAtoms::onMozMagnifyGestureUpdate,     { NS_SIMPLE_GESTURE_MAGNIFY_UPDATE, EventNameType_None } },
+    { &nsGkAtoms::onMozMagnifyGesture,           { NS_SIMPLE_GESTURE_MAGNIFY, EventNameType_None } },
+    { &nsGkAtoms::onMozRotateGestureStart,       { NS_SIMPLE_GESTURE_ROTATE_START, EventNameType_None } },
+    { &nsGkAtoms::onMozRotateGestureUpdate,      { NS_SIMPLE_GESTURE_ROTATE_UPDATE, EventNameType_None } },
+    { &nsGkAtoms::onMozRotateGesture,            { NS_SIMPLE_GESTURE_ROTATE, EventNameType_None } }
   };
 
   sEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>;
   if (!sEventTable ||
       !sEventTable->Init(int(NS_ARRAY_LENGTH(eventArray) / 0.75) + 1)) {
     delete sEventTable;
     sEventTable = nsnull;
     return PR_FALSE;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1452,16 +1452,26 @@ GK_ATOM(daysFromDate, "days-from-date")
 GK_ATOM(init, "init")
 GK_ATOM(instance, "instance")
 GK_ATOM(months, "months")
 GK_ATOM(now, "now")
 GK_ATOM(seconds, "seconds")
 GK_ATOM(secondsFromDateTime, "seconds-from-dateTime")
 #endif
 
+// Simple gestures support
+GK_ATOM(onMozSwipeGesture, "onMozSwipeGesture")
+GK_ATOM(onMozMagnifyGestureStart, "onMozMagnifyGestureStart")
+GK_ATOM(onMozMagnifyGestureUpdate, "onMozMagnifyGestureUpdate")
+GK_ATOM(onMozMagnifyGesture, "onMozMagnifyGesture")
+GK_ATOM(onMozRotateGestureStart, "onMozRotateGestureStart")
+GK_ATOM(onMozRotateGestureUpdate, "onMozRotateGestureUpdate")
+GK_ATOM(onMozRotateGesture, "onMozRotateGesture")
+
+
 //---------------------------------------------------------------------------
 // Special atoms
 //---------------------------------------------------------------------------
 
 // Node types
 GK_ATOM(cdataTagName, "#cdata-section")
 GK_ATOM(commentTagName, "#comment")
 GK_ATOM(documentNodeName, "#document")
--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -107,9 +107,11 @@ NS_NewDOMXULCommandEvent(nsIDOMEvent** a
 nsresult
 NS_NewDOMCommandEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsCommandEvent* aEvent);
 nsresult
 NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
 nsresult
 NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
 nsresult
 NS_NewDOMNotifyPaintEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsNotifyPaintEvent* aEvent);
+nsresult
+NS_NewDOMSimpleGestureEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsSimpleGestureEvent* aEvent);
 #endif // nsIPrivateDOMEvent_h__
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -90,16 +90,17 @@ CPPSRCS		= \
 		nsXMLEventsElement.cpp \
 		nsPLDOMEvent.cpp \
 		nsEventDispatcher.cpp \
 		nsIMEStateManager.cpp \
 		nsQueryContentEventHandler.cpp \
 		nsDOMProgressEvent.cpp \
 		nsDOMDataTransfer.cpp \
 		nsDOMNotifyPaintEvent.cpp \
+		nsDOMSimpleGestureEvent.cpp \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES	= \
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -78,17 +78,24 @@ static const char* const sEventNames[] =
 #endif // MOZ_SVG
 #ifdef MOZ_MEDIA
   "loadstart", "progress", "loadedmetadata", "loadedfirstframe",
   "emptied", "stalled", "play", "pause",
   "waiting", "seeking", "seeked", "timeupdate", "ended", "dataunavailable",
   "canshowcurrentframe", "canplay", "canplaythrough", "ratechange",
   "durationchange", "volumechange",
 #endif // MOZ_MEDIA
-  "MozAfterPaint"
+  "MozAfterPaint",
+  "MozSwipeGesture",
+  "MozMagnifyGestureStart",
+  "MozMagnifyGestureUpdate",
+  "MozMagnifyGesture",
+  "MozRotateGestureStart",
+  "MozRotateGestureUpdate",
+  "MozRotateGesture"
 };
 
 static char *sPopupAllowedEvents;
 
 
 nsDOMEvent::nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent)
 {
   mPresContext = aPresContext;
@@ -645,16 +652,32 @@ nsDOMEvent::SetEventType(const nsAString
     else if (atom == nsGkAtoms::onerror)
       mEvent->message = NS_MEDIA_ERROR;
   }
 #endif // MOZ_MEDIA
   else if (mEvent->eventStructType == NS_NOTIFYPAINT_EVENT) {
     if (atom == nsGkAtoms::onMozAfterPaint)
       mEvent->message = NS_AFTERPAINT;
   }
+  else if (mEvent->eventStructType == NS_SIMPLE_GESTURE_EVENT) {
+    if (atom == nsGkAtoms::onMozSwipeGesture)
+      mEvent->message = NS_SIMPLE_GESTURE_SWIPE;
+    else if (atom == nsGkAtoms::onMozMagnifyGestureStart)
+      mEvent->message = NS_SIMPLE_GESTURE_MAGNIFY_START;
+    else if (atom == nsGkAtoms::onMozMagnifyGestureUpdate)
+      mEvent->message = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE;
+    else if (atom == nsGkAtoms::onMozMagnifyGesture)
+      mEvent->message = NS_SIMPLE_GESTURE_MAGNIFY;
+    else if (atom == nsGkAtoms::onMozRotateGestureStart)
+      mEvent->message = NS_SIMPLE_GESTURE_ROTATE_START;
+    else if (atom == nsGkAtoms::onMozRotateGestureUpdate)
+      mEvent->message = NS_SIMPLE_GESTURE_ROTATE_UPDATE;
+    else if (atom == nsGkAtoms::onMozRotateGesture)
+      mEvent->message = NS_SIMPLE_GESTURE_ROTATE;
+  }
 
   if (mEvent->message == NS_USER_DEFINED_EVENT)
     mEvent->userType = atom;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -967,16 +990,32 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
     case NS_NOTIFYPAINT_EVENT:
     {
       nsNotifyPaintEvent* event = static_cast<nsNotifyPaintEvent*>(mEvent);
       newEvent =
         new nsNotifyPaintEvent(PR_FALSE, msg,
                                event->sameDocRegion, event->crossDocRegion);
       break;
     }
+    case NS_SIMPLE_GESTURE_EVENT:
+    {
+      nsSimpleGestureEvent* oldSimpleGestureEvent = static_cast<nsSimpleGestureEvent*>(mEvent);
+      nsSimpleGestureEvent* simpleGestureEvent = 
+        new nsSimpleGestureEvent(PR_FALSE, msg, nsnull, 0, 0.0);
+      NS_ENSURE_TRUE(simpleGestureEvent, NS_ERROR_OUT_OF_MEMORY);
+      isInputEvent = PR_TRUE;
+      simpleGestureEvent->direction = oldSimpleGestureEvent->direction;
+      simpleGestureEvent->delta = oldSimpleGestureEvent->delta;
+      simpleGestureEvent->isAlt = oldSimpleGestureEvent->isAlt;
+      simpleGestureEvent->isControl = oldSimpleGestureEvent->isControl;
+      simpleGestureEvent->isShift = oldSimpleGestureEvent->isShift;
+      simpleGestureEvent->isMeta = oldSimpleGestureEvent->isMeta;
+      newEvent = simpleGestureEvent;
+      break;
+    }
     default:
     {
       NS_WARNING("Unknown event type!!!");
       return NS_ERROR_FAILURE;
     }
   }
 
   NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
@@ -1466,16 +1505,30 @@ const char* nsDOMEvent::GetEventName(PRU
     return sEventNames[eDOMEvents_ratechange];
   case NS_DURATIONCHANGE:
     return sEventNames[eDOMEvents_durationchange];
   case NS_VOLUMECHANGE:
     return sEventNames[eDOMEvents_volumechange];
 #endif
   case NS_AFTERPAINT:
     return sEventNames[eDOMEvents_afterpaint];
+  case NS_SIMPLE_GESTURE_SWIPE:
+    return sEventNames[eDOMEvents_MozSwipeGesture];
+  case NS_SIMPLE_GESTURE_MAGNIFY_START:
+    return sEventNames[eDOMEvents_MozMagnifyGestureStart];
+  case NS_SIMPLE_GESTURE_MAGNIFY_UPDATE:
+    return sEventNames[eDOMEvents_MozMagnifyGestureUpdate];
+  case NS_SIMPLE_GESTURE_MAGNIFY:
+    return sEventNames[eDOMEvents_MozMagnifyGesture];
+  case NS_SIMPLE_GESTURE_ROTATE_START:
+    return sEventNames[eDOMEvents_MozRotateGestureStart];
+  case NS_SIMPLE_GESTURE_ROTATE_UPDATE:
+    return sEventNames[eDOMEvents_MozRotateGestureUpdate];
+  case NS_SIMPLE_GESTURE_ROTATE:
+    return sEventNames[eDOMEvents_MozRotateGesture];
   default:
     break;
   }
   // XXXldb We can hit this case for nsEvent objects that we didn't
   // create and that are not user defined events since this function and
   // SetEventType are incomplete.  (But fixing that requires fixing the
   // arrays in nsEventListenerManager too, since the events for which
   // this is a problem generally *are* created by nsDOMEvent.)
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -156,17 +156,24 @@ public:
     eDOMEvents_dataunavailable,
     eDOMEvents_canshowcurrentframe,
     eDOMEvents_canplay,
     eDOMEvents_canplaythrough,
     eDOMEvents_ratechange,
     eDOMEvents_durationchange,
     eDOMEvents_volumechange,
 #endif
-    eDOMEvents_afterpaint
+    eDOMEvents_afterpaint,
+    eDOMEvents_MozSwipeGesture,
+    eDOMEvents_MozMagnifyGestureStart,
+    eDOMEvents_MozMagnifyGestureUpdate,
+    eDOMEvents_MozMagnifyGesture,
+    eDOMEvents_MozRotateGestureStart,
+    eDOMEvents_MozRotateGestureUpdate,
+    eDOMEvents_MozRotateGesture
   };
 
   nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent);
   virtual ~nsDOMEvent();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMEvent, nsIDOMEvent)
 
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMSimpleGestureEvent.cpp
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Thomas K. Dyas <tdyas@zecador.org>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsDOMSimpleGestureEvent.h"
+#include "nsGUIEvent.h"
+#include "nsContentUtils.h"
+
+
+nsDOMSimpleGestureEvent::nsDOMSimpleGestureEvent(nsPresContext* aPresContext, nsSimpleGestureEvent* aEvent)
+  : nsDOMUIEvent(aPresContext, aEvent ? aEvent : new nsSimpleGestureEvent(PR_FALSE, 0, nsnull, 0, 0.0))
+{
+  NS_ASSERTION(mEvent->eventStructType == NS_SIMPLE_GESTURE_EVENT, "event type mismatch");
+
+  if (aEvent) {
+    mEventIsInternal = PR_FALSE;
+  } else {
+    mEventIsInternal = PR_TRUE;
+    mEvent->time = PR_Now();
+  }
+}
+
+nsDOMSimpleGestureEvent::~nsDOMSimpleGestureEvent()
+{
+  if (mEventIsInternal) {
+    delete static_cast<nsSimpleGestureEvent*>(mEvent);
+    mEvent = nsnull;
+  }
+}
+
+NS_IMPL_ADDREF_INHERITED(nsDOMSimpleGestureEvent, nsDOMUIEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMSimpleGestureEvent, nsDOMUIEvent)
+
+NS_INTERFACE_MAP_BEGIN(nsDOMSimpleGestureEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSimpleGestureEvent)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SimpleGestureEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMUIEvent)
+
+/* readonly attribute unsigned long direction; */
+NS_IMETHODIMP
+nsDOMSimpleGestureEvent::GetDirection(PRUint32 *aDirection)
+{
+  NS_ENSURE_ARG_POINTER(aDirection);
+  *aDirection = static_cast<nsSimpleGestureEvent*>(mEvent)->direction;
+  return NS_OK;
+}
+
+/* readonly attribute float delta; */
+NS_IMETHODIMP
+nsDOMSimpleGestureEvent::GetDelta(PRFloat64 *aDelta)
+{
+  NS_ENSURE_ARG_POINTER(aDelta);
+  *aDelta = static_cast<nsSimpleGestureEvent*>(mEvent)->delta;
+  return NS_OK;
+}
+
+/* readonly attribute boolean altKey; */
+NS_IMETHODIMP
+nsDOMSimpleGestureEvent::GetAltKey(PRBool* aIsDown)
+{
+  NS_ENSURE_ARG_POINTER(aIsDown);
+  *aIsDown = static_cast<nsInputEvent*>(mEvent)->isAlt;
+  return NS_OK;
+}
+
+/* readonly attribute boolean ctrlKey; */
+NS_IMETHODIMP
+nsDOMSimpleGestureEvent::GetCtrlKey(PRBool* aIsDown)
+{
+  NS_ENSURE_ARG_POINTER(aIsDown);
+  *aIsDown = static_cast<nsInputEvent*>(mEvent)->isControl;
+  return NS_OK;
+}
+
+/* readonly attribute boolean shiftKey; */
+NS_IMETHODIMP
+nsDOMSimpleGestureEvent::GetShiftKey(PRBool* aIsDown)
+{
+  NS_ENSURE_ARG_POINTER(aIsDown);
+  *aIsDown = static_cast<nsInputEvent*>(mEvent)->isShift;
+  return NS_OK;
+}
+
+/* readonly attribute boolean metaKey; */
+NS_IMETHODIMP
+nsDOMSimpleGestureEvent::GetMetaKey(PRBool* aIsDown)
+{
+  NS_ENSURE_ARG_POINTER(aIsDown);
+  *aIsDown = static_cast<nsInputEvent*>(mEvent)->isMeta;
+  return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsDOMSimpleGestureEvent::InitSimpleGestureEvent(const nsAString & typeArg, PRBool canBubbleArg, PRBool cancelableArg, nsIDOMAbstractView *viewArg, PRInt32 detailArg, PRUint32 directionArg, PRFloat64 deltaArg, PRBool altKeyArg, PRBool ctrlKeyArg, PRBool shiftKeyArg, PRBool metaKeyArg)
+{
+  nsresult rv = nsDOMUIEvent::InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsSimpleGestureEvent* simpleGestureEvent = static_cast<nsSimpleGestureEvent*>(mEvent);
+  simpleGestureEvent->direction = directionArg;
+  simpleGestureEvent->delta = deltaArg;
+  simpleGestureEvent->isAlt = altKeyArg;
+  simpleGestureEvent->isControl = ctrlKeyArg;
+  simpleGestureEvent->isShift = shiftKeyArg;
+  simpleGestureEvent->isMeta = metaKeyArg;
+
+  return NS_OK;
+}
+
+nsresult NS_NewDOMSimpleGestureEvent(nsIDOMEvent** aInstancePtrResult,
+                                     nsPresContext* aPresContext,
+                                     nsSimpleGestureEvent *aEvent)
+{
+  nsDOMSimpleGestureEvent *it = new nsDOMSimpleGestureEvent(aPresContext, aEvent);
+  if (nsnull == it) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  return CallQueryInterface(it, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMSimpleGestureEvent.h
@@ -0,0 +1,60 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Thomas K. Dyas <tdyas@zecador.org>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsDOMSimpleGestureEvent_h__
+#define nsDOMSimpleGestureEvent_h__
+
+#include "nsIDOMSimpleGestureEvent.h"
+#include "nsDOMUIEvent.h"
+
+class nsPresContext;
+
+class nsDOMSimpleGestureEvent : public nsIDOMSimpleGestureEvent,
+  public nsDOMUIEvent
+{
+public:
+  nsDOMSimpleGestureEvent(nsPresContext*, nsSimpleGestureEvent*);
+  virtual ~nsDOMSimpleGestureEvent();
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  NS_DECL_NSIDOMSIMPLEGESTUREEVENT
+
+  // Forward to base class
+  NS_FORWARD_TO_NSDOMUIEVENT
+};
+
+#endif
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -644,16 +644,19 @@ nsEventDispatcher::CreateEvent(nsPresCon
                                                  (aEvent));
     case NS_COMMAND_EVENT:
       return NS_NewDOMCommandEvent(aDOMEvent, aPresContext,
                                    static_cast<nsCommandEvent*>(aEvent));
     case NS_NOTIFYPAINT_EVENT:
       return NS_NewDOMNotifyPaintEvent(aDOMEvent, aPresContext,
                                        static_cast<nsNotifyPaintEvent*>
                                                      (aEvent));
+    case NS_SIMPLE_GESTURE_EVENT:
+      return NS_NewDOMSimpleGestureEvent(aDOMEvent, aPresContext,
+                                         static_cast<nsSimpleGestureEvent*>(aEvent));
     }
 
     // For all other types of events, create a vanilla event object.
     return NS_NewDOMEvent(aDOMEvent, aPresContext, aEvent);
   }
 
   // And if we didn't get an event, check the type argument.
 
@@ -702,11 +705,13 @@ nsEventDispatcher::CreateEvent(nsPresCon
       aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
     return NS_NewDOMDataContainerEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("messageevent"))
     return NS_NewDOMMessageEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("progressevent"))
     return NS_NewDOMProgressEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("notifypaintevent"))
     return NS_NewDOMNotifyPaintEvent(aDOMEvent, aPresContext, nsnull);
+  if (aEventType.LowerCaseEqualsLiteral("simplegestureevent"))
+    return NS_NewDOMSimpleGestureEvent(aDOMEvent, aPresContext, nsnull);
 
   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 }
--- a/dom/public/idl/base/nsIDOMWindowUtils.idl
+++ b/dom/public/idl/base/nsIDOMWindowUtils.idl
@@ -42,17 +42,17 @@
  * to the current nsIDOMWindow.  Some of the methods may require
  * elevated privileges; the method implementations should contain the
  * necessary security checks.  Access this interface by calling
  * getInterface on a DOMWindow.
  */
 
 interface nsIDOMElement;
 
-[scriptable, uuid(9a1ff4e0-5e31-46af-b393-2cbab8093442)]
+[scriptable, uuid(3fe733aa-823b-443a-9945-b02f973ab439)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -235,9 +235,29 @@ interface nsIDOMWindowUtils : nsISupport
    */
   void garbageCollect();
 
   /**
    * Force processing of any queued paints
    */
 
   void processUpdates();
+
+  /** Synthesize a simple gesture event for a window. The event types
+   *  supported are: MozSwipeGesture, MozMagnifyGestureStart,
+   *  MozMagnifyGestureUpdate, MozMagnifyGesture,
+   *  MozRotateGestureStart, MozRotateGestureUpdate, and
+   *  MozRotateGesture.
+   *
+   * Cannot be accessed from unprivileged context (not
+   * content-accessible) Will throw a DOM security error if called
+   * without UniversalXPConnect privileges.
+   *
+   * @param aType event type
+   * @param aDirection direction, using constants defined in nsIDOMSimpleGestureEvent
+   * @param aDelta  amount of magnification or rotation for magnify and rotation events
+   * @param aModifiers modifiers pressed, using constants defined in nsIDOMNSEvent
+   */
+  void sendSimpleGestureEvent(in AString aType,
+                              in unsigned long aDirection,
+                              in double aDelta,
+                              in long aModifiers);
 };
--- a/dom/public/idl/events/Makefile.in
+++ b/dom/public/idl/events/Makefile.in
@@ -71,11 +71,12 @@ XPIDLSRCS =					\
 	nsIDOMPopupBlockedEvent.idl		\
 	nsIDOMBeforeUnloadEvent.idl		\
 	nsIDOMNSEventTarget.idl			\
 	nsIDOMSmartCardEvent.idl                \
 	nsIDOMPageTransitionEvent.idl		\
 	nsIDOMCommandEvent.idl			\
 	nsIDOMMessageEvent.idl			\
 	nsIDOMNotifyPaintEvent.idl              \
+	nsIDOMSimpleGestureEvent.idl		\
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/events/nsIDOMSimpleGestureEvent.idl
@@ -0,0 +1,141 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Thomas K. Dyas <tdyas@zecador.org>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#include "nsIDOMUIEvent.idl"
+
+/**
+ * The nsIDOMSimpleGestureEvent interface is the datatype for all
+ * Mozila-specific simple gesture events in the Document Object Model.
+ *
+ * The following events are generated:
+ *
+ * MozSwipeGesture - Generated when the user swipes their fingers
+ * across the input device.
+ *
+ * MozMagnifyGestureStart - Generated when the user begins the magnify
+ * ("pinch") gesture.  The "delta" value represents the initial
+ * movement.
+ *
+ * MozMagnifyGestureUpdate - Generated periodically while the user is
+ * continuing the magnify ("pinch") gesture.  The "delta" value
+ * represents the movement since the last MozMagnifyGestureStart or
+ * MozMagnifyGestureUpdate event.
+ *
+ * MozMagnifyGesture - Generated when the user has completed the
+ * magnify ("pinch") gesture.  If you only want to receive a single
+ * event when the magnify gesture is complete, you only need to hook
+ * this event and can safely ignore the MozMagnifyGestureStart and the
+ * MozMagnifyGestureUpdate events. The "delta" value is the cumulative
+ * amount represented by the user's gesture.
+ *
+ * MozRotateGestureStart - Generated when the user begins the rotation
+ * gesture.  The "delta" value represents the initial rotation.
+ *
+ * MozRotateGestureUpdate - Generated periodically while the user is
+ * continuing the rotation gesture.  The "delta" value represents the
+ * rotation since the last MozRotateGestureStart or
+ * MozRotateGestureUpdate event.
+ *
+ * MozRotateGesture - Generated when the user has completed the
+ * rotation gesture.  If you only want to receive a single event when
+ * the rotation gesture is complete, you only need to hook this event
+ * and can safely ignore the MozRotateGestureStart and the
+ * MozRotateGestureUpdate events.  The "delta" value is the cumulative
+ * amount of rotation represented by the user's gesture.
+ */
+
+[scriptable, uuid(20AB8E74-BF9B-4D1D-8A18-B5EE0F3C0A36)]
+interface nsIDOMSimpleGestureEvent : nsIDOMUIEvent
+{
+  /* Direction constants */
+  const unsigned long DIRECTION_UP = 1;
+  const unsigned long DIRECTION_DOWN = 2;
+  const unsigned long DIRECTION_LEFT = 4;
+  const unsigned long DIRECTION_RIGHT = 8;
+  
+  /* Direction of a gesture. Diagonals are indicated by OR'ing the
+   * applicable constants together.
+   *
+   * Swipes gestures may occur in any direction.
+   *
+   * Magnify gestures do not have a direction.
+   *
+   * Rotation gestures will be either DIRECTION_LEFT or
+   * DIRECTION_RIGHT (i.e., counter-clockwise and clockwise).
+   */
+  readonly attribute unsigned long direction;
+
+  /* Delta value for magnify and rotate gestures.
+   * 
+   * For rotation, the value is in degrees and is positive for
+   * clockwise rotation and negative for counterclockwise
+   * rotation. The "direction" attribute also denotes the direction of
+   * the rotation: clockwise is DIRECTION_RIGHT and counterclockwise
+   * is DIRECTION_LEFT.
+   *
+   * For magnification, the value will be positive for a "zoom in"
+   * (i.e, increased magnification) and negative for a "zoom out"
+   * (i.e., decreased magnification).  The particular units
+   * represented by the "delta" are currently implementation specific.
+   *
+   * XXX - The units for measuring magnification are currently
+   * unspecified because the units used by Mac OS X are currently
+   * undocumented.  The values are typically in the range of 0.0 to
+   * 100.0, but it is only safe currently to rely on the delta being
+   * positive or negative.
+   */
+  readonly attribute double delta;
+
+  /* Modifier keys that may have been pressed during the gesture. */
+  readonly attribute boolean altKey;
+  readonly attribute boolean ctrlKey;
+  readonly attribute boolean shiftKey;
+  readonly attribute boolean metaKey;
+
+  void initSimpleGestureEvent(in DOMString typeArg,
+                              in boolean canBubbleArg,
+                              in boolean cancelableArg,
+                              in nsIDOMAbstractView viewArg,
+                              in long detailArg,
+                              in unsigned long directionArg,
+                              in double deltaArg,
+                              in boolean altKeyArg,
+                              in boolean ctrlKeyArg,
+                              in boolean shiftKeyArg,
+                              in boolean metaKeyArg);
+};
--- a/dom/public/nsDOMClassInfoID.h
+++ b/dom/public/nsDOMClassInfoID.h
@@ -447,16 +447,18 @@ enum nsDOMClassInfoID {
 
   // DOM Traversal NodeIterator class
   eDOMClassInfo_NodeIterator_id,
 
   eDOMClassInfo_DataTransfer_id,
 
   eDOMClassInfo_NotifyPaintEvent_id,
 
+  eDOMClassInfo_SimpleGestureEvent_id,
+
   // This one better be the last one in this list
   eDOMClassInfoIDCount
 };
 
 /**
  * nsIClassInfo helper macros
  */
 
--- a/dom/src/base/nsDOMClassInfo.cpp
+++ b/dom/src/base/nsDOMClassInfo.cpp
@@ -460,16 +460,19 @@
 // Geolocation
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMGeoPosition.h"
 #include "nsIDOMGeoPositionError.h"
 
 #include "nsDOMFile.h"
 #include "nsIDOMFileException.h"
 
+// Simple gestures include
+#include "nsIDOMSimpleGestureEvent.h"
+
 static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
 
 // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
 //       are defined in nsIDOMClassInfo.h.
@@ -1288,16 +1291,19 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // data transfer for drag and drop
   NS_DEFINE_CLASSINFO_DATA(DataTransfer, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(NotifyPaintEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+  NS_DEFINE_CLASSINFO_DATA(SimpleGestureEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 };
 
 // Objects that shuld be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
   const char *mContractID;
 };
@@ -3526,16 +3532,21 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSDataTransfer)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(NotifyPaintEvent, nsIDOMNotifyPaintEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNotifyPaintEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(SimpleGestureEvent, nsIDOMSimpleGestureEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSimpleGestureEvent)
+    DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
 #ifdef NS_DEBUG
   {
     PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData);
 
     if (i != eDOMClassInfoIDCount) {
       NS_ERROR("The number of items in sClassInfoData doesn't match the "
                "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
 
--- a/dom/src/base/nsDOMWindowUtils.cpp
+++ b/dom/src/base/nsDOMWindowUtils.cpp
@@ -488,8 +488,53 @@ nsDOMWindowUtils::ProcessUpdates()
   if (!viewManager)
     return NS_ERROR_UNEXPECTED;
   
   nsIViewManager::UpdateViewBatch batch;
   batch.BeginUpdateViewBatch(viewManager);
   batch.EndUpdateViewBatch(NS_VMREFRESH_IMMEDIATE);
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType,
+                                         PRUint32 aDirection,
+                                         PRFloat64 aDelta,
+                                         PRInt32 aModifiers)
+{
+  PRBool hasCap = PR_FALSE;
+  if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap))
+      || !hasCap)
+    return NS_ERROR_DOM_SECURITY_ERR;
+
+  // get the widget to send the event to
+  nsCOMPtr<nsIWidget> widget = GetWidget();
+  if (!widget)
+    return NS_ERROR_FAILURE;
+
+  PRInt32 msg;
+  if (aType.EqualsLiteral("MozSwipeGesture"))
+    msg = NS_SIMPLE_GESTURE_SWIPE;
+  else if (aType.EqualsLiteral("MozMagnifyGestureStart"))
+    msg = NS_SIMPLE_GESTURE_MAGNIFY_START;
+  else if (aType.EqualsLiteral("MozMagnifyGestureUpdate"))
+    msg = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE;
+  else if (aType.EqualsLiteral("MozMagnifyGesture"))
+    msg = NS_SIMPLE_GESTURE_MAGNIFY;
+  else if (aType.EqualsLiteral("MozRotateGestureStart"))
+    msg = NS_SIMPLE_GESTURE_ROTATE_START;
+  else if (aType.EqualsLiteral("MozRotateGestureUpdate"))
+    msg = NS_SIMPLE_GESTURE_ROTATE_UPDATE;
+  else if (aType.EqualsLiteral("MozRotateGesture"))
+    msg = NS_SIMPLE_GESTURE_ROTATE;
+  else
+    return NS_ERROR_FAILURE;
+ 
+  nsSimpleGestureEvent event(PR_TRUE, msg, widget, aDirection, aDelta);
+  event.isShift = (aModifiers & nsIDOMNSEvent::SHIFT_MASK) ? PR_TRUE : PR_FALSE;
+  event.isControl = (aModifiers & nsIDOMNSEvent::CONTROL_MASK) ? PR_TRUE : PR_FALSE;
+  event.isAlt = (aModifiers & nsIDOMNSEvent::ALT_MASK) ? PR_TRUE : PR_FALSE;
+  event.isMeta = (aModifiers & nsIDOMNSEvent::META_MASK) ? PR_TRUE : PR_FALSE;
+  event.time = PR_IntervalNow();
+
+  nsEventStatus status;
+  return widget->DispatchEvent(&event, status);
+}
--- a/widget/public/nsEvent.h
+++ b/widget/public/nsEvent.h
@@ -71,12 +71,13 @@ class nsMouseEvent;
 class nsAccessibleEvent;
 class nsKeyEvent;
 class nsTextEvent;
 class nsCompositionEvent;
 class nsMouseScrollEvent;
 class nsReconversionEvent;
 class nsTooltipEvent;
 class nsMenuEvent;
+class nsSimpleGestureEvent;
 
 struct nsTextEventReply;
 
 #endif // nsEvent_h__
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Makoto Kato  <m_kato@ga2.so-net.ne.jp>
  *   Dean Tessman <dean_tessman@hotmail.com>
+ *   Thomas K. Dyas <tdyas@zecador.org> (simple gestures support)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -98,16 +99,17 @@ class nsHashKey;
 #endif // MOZ_SVG
 #define NS_XUL_COMMAND_EVENT              32
 #define NS_QUERY_CONTENT_EVENT            33
 #ifdef MOZ_MEDIA
 #define NS_MEDIA_EVENT                    34
 #endif // MOZ_MEDIA
 #define NS_DRAG_EVENT                     35
 #define NS_NOTIFYPAINT_EVENT              36
+#define NS_SIMPLE_GESTURE_EVENT           37
 
 // 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
 // warned!
 #define NS_EVENT_FLAG_NONE                0x0000
 #define NS_EVENT_FLAG_TRUSTED             0x0001
 #define NS_EVENT_FLAG_BUBBLE              0x0002
 #define NS_EVENT_FLAG_CAPTURE             0x0004
@@ -377,16 +379,26 @@ class nsHashKey;
 #define NS_MEDIA_ABORT         (NS_MEDIA_EVENT_START+20)
 #define NS_MEDIA_ERROR         (NS_MEDIA_EVENT_START+21)
 #endif // MOZ_MEDIA
 
 // paint notification events
 #define NS_NOTIFYPAINT_START    3400
 #define NS_AFTERPAINT           (NS_NOTIFYPAINT_START)
 
+// Simple gesture events
+#define NS_SIMPLE_GESTURE_EVENT_START    3500
+#define NS_SIMPLE_GESTURE_SWIPE          (NS_SIMPLE_GESTURE_EVENT_START)
+#define NS_SIMPLE_GESTURE_MAGNIFY_START  (NS_SIMPLE_GESTURE_EVENT_START+1)
+#define NS_SIMPLE_GESTURE_MAGNIFY_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+2)
+#define NS_SIMPLE_GESTURE_MAGNIFY        (NS_SIMPLE_GESTURE_EVENT_START+3)
+#define NS_SIMPLE_GESTURE_ROTATE_START   (NS_SIMPLE_GESTURE_EVENT_START+4)
+#define NS_SIMPLE_GESTURE_ROTATE_UPDATE  (NS_SIMPLE_GESTURE_EVENT_START+5)
+#define NS_SIMPLE_GESTURE_ROTATE         (NS_SIMPLE_GESTURE_EVENT_START+6)
+
 /**
  * Return status for event processors, nsEventStatus, is defined in
  * nsEvent.h.
  */
 
 /**
  * sizemode is an adjunct to widget size
  */
@@ -1116,16 +1128,33 @@ public:
     : nsInputEvent(isTrusted, msg, w, NS_XUL_COMMAND_EVENT)
   {
   }
 
   nsCOMPtr<nsIDOMEvent> sourceEvent;
 };
 
 /**
+ * Simple gesture event
+ */
+class nsSimpleGestureEvent : public nsInputEvent
+{
+public:
+  nsSimpleGestureEvent(PRBool isTrusted, PRUint32 msg, nsIWidget* w,
+                         PRUint32 directionArg, PRFloat64 deltaArg)
+    : nsInputEvent(isTrusted, msg, w, NS_SIMPLE_GESTURE_EVENT),
+      direction(directionArg), delta(deltaArg)
+  {
+  }
+
+  PRUint32 direction;   // See nsIDOMSimpleGestureEvent for values
+  PRFloat64 delta;      // Delta for magnify and rotate events
+};
+
+/**
  * Event status for D&D Event
  */
 enum nsDragDropEventStatus {  
   /// The event is a enter
   nsDragDropEventStatus_eDragEntered,            
   /// The event is exit
   nsDragDropEventStatus_eDragExited, 
   /// The event is drop
--- a/widget/src/cocoa/nsChildView.h
+++ b/widget/src/cocoa/nsChildView.h
@@ -15,16 +15,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Thomas K. Dyas <tdyas@zecador.org> (simple gestures support)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -177,30 +178,69 @@ enum {
   nsIDragService* mDragService;
   
   PRUint32 mLastModifierState;
 
   // For use with plugins, so that we can support IME in them.  We can't use
   // Cocoa TSM documents (those created and managed by the NSTSMInputContext
   // class) -- for some reason TSMProcessRawKeyEvent() doesn't work with them.
   TSMDocumentID mPluginTSMDoc;
+
+  // Simple gestures support
+  //
+  // mGestureState is used to detect when Cocoa has called both
+  // magnifyWithEvent and rotateWithEvent within the same
+  // beginGestureWithEvent and endGestureWithEvent sequence. We
+  // discard the spurious gesture event so as not to confuse Gecko.
+  //
+  // mCumulativeMagnification keeps track of the total amount of
+  // magnification peformed during a magnify gesture so that we can
+  // send that value with the final MozMagnifyGesture event.
+  //
+  // mCumulativeRotation keeps track of the total amount of rotation
+  // performed during a rotate gesture so we can send that value with
+  // the final MozRotateGesture event.
+  enum {
+    eGestureState_None,
+    eGestureState_StartGesture,
+    eGestureState_MagnifyGesture,
+    eGestureState_RotateGesture
+  } mGestureState;
+  float mCumulativeMagnification;
+  float mCumulativeRotation;
 }
 
 // these are sent to the first responder when the window key status changes
 - (void)viewsWindowDidBecomeKey;
 - (void)viewsWindowDidResignKey;
 
 // Stop NSView hierarchy being changed during [ChildView drawRect:]
 - (void)delayedTearDown;
 
 - (void)setTransparent:(BOOL)transparent;
 
 - (void)sendFocusEvent:(PRUint32)eventType;
 
 - (void) processPluginKeyEvent:(EventRef)aKeyEvent;
+
+// Simple gestures support
+//
+// XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
+// rotateWithEvent, and endGestureWithEvent methods are part of a
+// PRIVATE interface exported by nsResponder and reverse-engineering
+// was necessary to obtain the methods' prototypes. Thus, Apple may
+// change the interface in the future without notice.
+//
+// The prototypes were obtained from the following link:
+// http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
+- (void)swipeWithEvent:(NSEvent *)anEvent;
+- (void)beginGestureWithEvent:(NSEvent *)anEvent;
+- (void)magnifyWithEvent:(NSEvent *)anEvent;
+- (void)rotateWithEvent:(NSEvent *)anEvent;
+- (void)endGestureWithEvent:(NSEvent *)anEvent;
 @end
 
 
 
 //-------------------------------------------------------------------------
 //
 // nsTSMManager
 //
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -20,16 +20,17 @@
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Josh Aas <josh@mozilla.com>
  *   Mark Mentovai <mark@moxienet.com>
  *   HÃ¥kan Waara <hwaara@gmail.com>
  *   Stuart Morgan <stuart.morgan@alumni.case.edu>
  *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Thomas K. Dyas <tdyas@zecador.org> (simple gestures support)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or 
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -67,16 +68,18 @@
 #include "nsIMenuRollup.h"
 
 #include "nsDragService.h"
 #include "nsCursorManager.h"
 #include "nsWindowMap.h"
 #include "nsCocoaUtils.h"
 #include "nsMenuBarX.h"
 
+#include "nsIDOMSimpleGestureEvent.h"
+
 #include "gfxContext.h"
 #include "gfxQuartzSurface.h"
 
 #include <dlfcn.h>
 
 #undef DEBUG_IME
 #undef DEBUG_UPDATE
 #undef INVALIDATE_DEBUGGING  // flash areas as they are invalidated
@@ -2353,16 +2356,20 @@ NSEvent* gLastDragEvent = nil;
     // initialization for NSTextInput
     mMarkedRange.location = NSNotFound;
     mMarkedRange.length = 0;
 
     mLastMouseDownEvent = nil;
     mDragService = nsnull;
 
     mPluginTSMDoc = nil;
+
+    mGestureState = eGestureState_None;
+    mCumulativeMagnification = 0.0;
+    mCumulativeRotation = 0.0;
   }
   
   // register for things we'll take from other applications
   PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView initWithFrame: registering drag types\n"));
   [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
                                                           NSStringPboardType,
                                                           NSURLPboardType,
                                                           NSFilesPromisePboardType,
@@ -3230,16 +3237,224 @@ static const PRInt32 sShadowInvalidation
   }
 
   return retVal;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
 
+/*
+ * XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
+ * rotateWithEvent, and endGestureWithEvent methods are part of a
+ * PRIVATE interface exported by nsResponder and reverse-engineering
+ * was necessary to obtain the methods' prototypes. Thus, Apple may
+ * change the interface in the future without notice.
+ *
+ * The prototypes were obtained from the following link:
+ * http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
+ */
+
+- (void)swipeWithEvent:(NSEvent *)anEvent
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  if (!anEvent || !mGeckoChild)
+    return;
+
+  nsAutoRetainCocoaObject kungFuDeathGrip(self);
+
+  float deltaX = [anEvent deltaX];  // left=1.0, right=-1.0
+  float deltaY = [anEvent deltaY];  // up=1.0, down=-1.0
+
+  // Setup the "swipe" event.
+  nsSimpleGestureEvent geckoEvent(PR_TRUE, NS_SIMPLE_GESTURE_SWIPE, mGeckoChild, 0, 0.0);
+  [self convertGenericCocoaEvent:anEvent toGeckoEvent:&geckoEvent];
+
+  // Record the left/right direction.
+  if (deltaX > 0.0)
+    geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
+  else if (deltaX < 0.0)
+    geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
+
+  // Record the up/down direction.
+  if (deltaY > 0.0)
+    geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_UP;
+  else if (deltaY < 0.0)
+    geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
+
+  // Send the event.
+  mGeckoChild->DispatchWindowEvent(geckoEvent);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+
+- (void)beginGestureWithEvent:(NSEvent *)anEvent
+{
+  NS_ASSERTION(mGestureState == eGestureState_None, "mGestureState should be eGestureState_None");
+
+  if (!anEvent)
+    return;
+
+  mGestureState = eGestureState_StartGesture;
+  mCumulativeMagnification = 0;
+  mCumulativeRotation = 0.0;
+}
+
+
+- (void)magnifyWithEvent:(NSEvent *)anEvent
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  if (!anEvent || !mGeckoChild)
+    return;
+
+  nsAutoRetainCocoaObject kungFuDeathGrip(self);
+
+  float deltaZ = [anEvent deltaZ];
+
+  PRUint32 msg;
+  switch (mGestureState) {
+  case eGestureState_StartGesture:
+    msg = NS_SIMPLE_GESTURE_MAGNIFY_START;
+    mGestureState = eGestureState_MagnifyGesture;
+    break;
+
+  case eGestureState_MagnifyGesture:
+    msg = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE;
+    break;
+
+  case eGestureState_None:
+  case eGestureState_RotateGesture:
+  default:
+    return;
+  }
+
+  // Setup the event.
+  nsSimpleGestureEvent geckoEvent(PR_TRUE, msg, mGeckoChild, 0, deltaZ);
+  [self convertGenericCocoaEvent:anEvent toGeckoEvent:&geckoEvent];
+
+  // Send the event.
+  mGeckoChild->DispatchWindowEvent(geckoEvent);
+
+  // Keep track of the cumulative magnification for the final "magnify" event.
+  mCumulativeMagnification += deltaZ;
+  
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+
+- (void)rotateWithEvent:(NSEvent *)anEvent
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  if (!anEvent || !mGeckoChild)
+    return;
+
+  nsAutoRetainCocoaObject kungFuDeathGrip(self);
+
+  float rotation = [anEvent rotation];
+
+  PRUint32 msg;
+  switch (mGestureState) {
+  case eGestureState_StartGesture:
+    msg = NS_SIMPLE_GESTURE_ROTATE_START;
+    mGestureState = eGestureState_RotateGesture;
+    break;
+
+  case eGestureState_RotateGesture:
+    msg = NS_SIMPLE_GESTURE_ROTATE_UPDATE;
+    break;
+
+  case eGestureState_None:
+  case eGestureState_MagnifyGesture:
+  default:
+    return;
+  }
+
+  // Setup the event.
+  nsSimpleGestureEvent geckoEvent(PR_TRUE, msg, mGeckoChild, 0, 0.0);
+  [self convertGenericCocoaEvent:anEvent toGeckoEvent:&geckoEvent];
+  geckoEvent.delta = -rotation;
+  if (rotation > 0.0) {
+    geckoEvent.direction = nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
+  } else {
+    geckoEvent.direction = nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
+  }
+
+  // Send the event.
+  mGeckoChild->DispatchWindowEvent(geckoEvent);
+
+  // Keep track of the cumulative rotation for the final "rotate" event.
+  mCumulativeRotation += rotation;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+
+- (void)endGestureWithEvent:(NSEvent *)anEvent
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  if (!anEvent || !mGeckoChild) {
+    // Clear the gestures state if we cannot send an event.
+    mGestureState = eGestureState_None;
+    mCumulativeMagnification = 0.0;
+    mCumulativeRotation = 0.0;
+    return;
+  }
+
+  nsAutoRetainCocoaObject kungFuDeathGrip(self);
+
+  switch (mGestureState) {
+  case eGestureState_MagnifyGesture:
+    {
+      // Setup the "magnify" event.
+      nsSimpleGestureEvent geckoEvent(PR_TRUE, NS_SIMPLE_GESTURE_MAGNIFY,
+                                      mGeckoChild, 0, mCumulativeMagnification);
+      [self convertGenericCocoaEvent:anEvent toGeckoEvent:&geckoEvent];
+
+      // Send the event.
+      mGeckoChild->DispatchWindowEvent(geckoEvent);
+    }
+    break;
+
+  case eGestureState_RotateGesture:
+    {
+      // Setup the "rotate" event.
+      nsSimpleGestureEvent geckoEvent(PR_TRUE, NS_SIMPLE_GESTURE_ROTATE, mGeckoChild, 0, 0.0);
+      [self convertGenericCocoaEvent:anEvent toGeckoEvent:&geckoEvent];
+      geckoEvent.delta = -mCumulativeRotation;
+      if (mCumulativeRotation > 0.0) {
+        geckoEvent.direction = nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
+      } else {
+        geckoEvent.direction = nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
+      }
+
+      // Send the event.
+      mGeckoChild->DispatchWindowEvent(geckoEvent);
+    }
+    break;
+
+  case eGestureState_None:
+  case eGestureState_StartGesture:
+  default:
+    break;
+  }
+
+  // Clear the gestures state.
+  mGestureState = eGestureState_None;
+  mCumulativeMagnification = 0.0;
+  mCumulativeRotation = 0.0;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+
 - (void)mouseDown:(NSEvent*)theEvent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   // If we've already seen this event due to direct dispatch from menuForEvent:
   // just bail; if not, remember it.
   if (mLastMouseDownEvent == theEvent) {
     [mLastMouseDownEvent release];