Add support for touch and gesture events for supported mobile webkit platforms.
Extract common implementation and interface out of MouseEvent into HumanInputEvent.

Review at http://gwt-code-reviews.appspot.com/867801

Review by: jgw@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9287 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java b/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java
index c0a0026..2687ede 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java
@@ -110,6 +110,14 @@
         "onmozorientation", "onpaint", "onreset", "onresize", "onscroll",
         "onselect", "onsubmit", "onunload",
         
+        // Safari Web Content Guide
+        // http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/SafariWebContent.pdf
+        // WebKit Window member data, from WebKit DOM Reference
+        // (http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/WebKitDOMRef/DOMWindow_idl/Classes/DOMWindow/index.html)
+        // TODO(fredsa) Many, many more functions and member data to add
+        "ontouchcancel", "ontouchend", "ontouchmove", "ontouchstart",
+        "ongesturestart", "ongesturechange", "ongestureend",
+        
         // extra window methods
         "uneval",
         
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index 9845b9f..0c55278 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -16,6 +16,7 @@
 package com.google.gwt.dom.client;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JsArray;
 
 abstract class DOMImpl {
 
@@ -130,6 +131,14 @@
 
   public abstract EventTarget eventGetRelatedTarget(NativeEvent nativeEvent);
 
+  public native double eventGetRotation(NativeEvent evt) /*-{
+    return evt.rotation;
+  }-*/;
+
+  public native double eventGetScale(NativeEvent evt) /*-{
+    return evt.scale;
+  }-*/;
+
   public native int eventGetScreenX(NativeEvent evt) /*-{
     return evt.screenX || 0;
   }-*/;
@@ -202,6 +211,10 @@
     return 0;
   }-*/;
 
+  public native JsArray<Touch> getChangedTouches(NativeEvent evt) /*-{
+    return evt.changedTouches;
+  }-*/;
+
   public native Element getFirstChildElement(Element elem) /*-{
     var child = elem.firstChild;
     while (child && child.nodeType != 1)
@@ -268,6 +281,14 @@
     return elem.tagName;
   }-*/;
 
+  public native JsArray<Touch> getTargetTouches(NativeEvent evt) /*-{
+    return evt.targetTouches;
+  }-*/;
+
+  public native JsArray<Touch> getTouches(NativeEvent evt) /*-{
+    return evt.touches;
+  }-*/;
+
   public native boolean hasAttribute(Element elem, String name) /*-{
     return elem.hasAttribute(name);
   }-*/;
@@ -365,4 +386,36 @@
   public native String toString(Element elem) /*-{
     return elem.outerHTML;
   }-*/;
+
+  public native int touchGetClientX(Touch touch)/*-{
+    return touch.clientX;
+  }-*/;
+
+  public native int touchGetClientY(Touch touch)/*-{
+    return touch.clientY;
+  }-*/;
+
+  public native int touchGetIdentifier(Touch touch)/*-{
+    return touch.identifier;
+  }-*/;
+
+  public native int touchGetPageX(Touch touch)/*-{
+    return touch.pageX;
+  }-*/;
+
+  public native int touchGetPageY(Touch touch)/*-{
+    return touch.pageY;
+  }-*/;
+
+  public native int touchGetScreenX(Touch touch)/*-{
+    return touch.ScreenX;
+  }-*/;
+
+  public native int touchGetScreenY(Touch touch)/*-{
+    return touch.ScreenY;
+  }-*/;
+
+  public native EventTarget touchGetTarget(Touch touch)/*-{
+    return touch.target;
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/dom/client/NativeEvent.java b/user/src/com/google/gwt/dom/client/NativeEvent.java
index 7fc6f07..af8bd8b 100644
--- a/user/src/com/google/gwt/dom/client/NativeEvent.java
+++ b/user/src/com/google/gwt/dom/client/NativeEvent.java
@@ -16,6 +16,7 @@
 package com.google.gwt.dom.client;
 
 import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
 
 /**
  * The native dom event.
@@ -64,6 +65,15 @@
   }
 
   /**
+   * Get an array of touches which have changed since the last touch event.
+   * 
+   * @return array of touches which have changed since the last touch event
+   */
+  public final JsArray<Touch> getChangedTouches() {
+    return DOMImpl.impl.getChangedTouches(this);
+  }
+
+  /**
    * Gets the Unicode codepoint of the character generated by this key event.
    * 
    * @return the Unicode codepoint.
@@ -166,6 +176,24 @@
   }
 
   /**
+   * Get the rotation in degrees, with positive values indicating clockwise rotation.
+   * 
+   * @return the rotation in degrees since the gesture started
+   */
+  public final double getRotation() {
+    return DOMImpl.impl.eventGetRotation(this);
+  }
+
+  /**
+   * Get the amount scaled since the gesture started, with 1.0 representing no scaling.
+   * 
+   * @return the amount scaled since the gesture started
+   */
+  public final double getScale() {
+    return DOMImpl.impl.eventGetScale(this);
+  }
+
+  /**
    * Gets the mouse x-position on the user's display.
    * 
    * @return the mouse x-position
@@ -205,6 +233,24 @@
   }
 
   /**
+   * Get an array of touches which have changed since the last touch event.
+   * 
+   * @return array of touches which have changed since the last touch event
+   */
+  public final JsArray<Touch> getTargetTouches() {
+    return DOMImpl.impl.getTargetTouches(this);
+  }
+
+  /**
+   * Get an array of touches which have changed since the last touch event.
+   * 
+   * @return array of touches which have changed since the last touch event
+   */
+  public final JsArray<Touch> getTouches() {
+    return DOMImpl.impl.getTouches(this);
+  }
+
+  /**
    * Gets the enumerated type of this event.
    * 
    * @return the event's enumerated type
diff --git a/user/src/com/google/gwt/dom/client/Touch.java b/user/src/com/google/gwt/dom/client/Touch.java
new file mode 100644
index 0000000..8faa291
--- /dev/null
+++ b/user/src/com/google/gwt/dom/client/Touch.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dom.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+/**
+ * Class representing touches.
+ *
+ * @see http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/TouchClassReference/Touch/Touch.html
+ */
+public class Touch extends JavaScriptObject {
+
+  protected Touch() {
+  }
+
+  /**
+   * Gets the touch x-position within the browser window's client area.
+   *
+   * @return the touch x-position
+   */
+  public final int getClientX() {
+    return DOMImpl.impl.touchGetClientX(this);
+  }
+
+  /**
+   * Gets the touch y-position within the browser window's client area.
+   *
+   * @return the touch y-position
+   */
+  public final int getClientY() {
+    return DOMImpl.impl.touchGetClientY(this);
+  }
+
+  /**
+   * Gets a unique identifier for this touch.
+   *
+   * @return the unique identifier for this touch
+   */
+  public final int getIdentifier() {
+    return DOMImpl.impl.touchGetIdentifier(this);
+  }
+
+  /**
+   * Gets the touch x-position within the browser document.
+   *
+   * @return the touch x-position
+   */
+  public final int getPageX() {
+    return DOMImpl.impl.touchGetPageX(this);
+  }
+
+  /**
+   * Gets the touch y-position within the browser document.
+   *
+   * @return the touch y-position
+   */
+  public final int getPageY() {
+    return DOMImpl.impl.touchGetPageY(this);
+  }
+
+  /**
+   * Gets the touch x-position relative to a given element.
+   *
+   * @param target the element whose coordinate system is to be used
+   * @return the relative x-position
+   */
+  public final int getRelativeX(Element target) {
+    return getClientX() - target.getAbsoluteLeft() + target.getScrollLeft()
+        + target.getOwnerDocument().getScrollLeft();
+  }
+
+  /**
+   * Gets the touch y-position relative to a given element.
+   *
+   * @param target the element whose coordinate system is to be used
+   * @return the relative y-position
+   */
+  public final int getRelativeY(Element target) {
+    return getClientY() - target.getAbsoluteTop() + target.getScrollTop()
+        + target.getOwnerDocument().getScrollTop();
+  }
+
+  /**
+   * Gets the touch x-position on the user's display.
+   *
+   * @return the touch x-position
+   */
+  public final int getScreenX() {
+    return DOMImpl.impl.touchGetScreenX(this);
+  }
+
+  /**
+   * Gets the touch y-position on the user's display.
+   *
+   * @return the touch y-position
+   */
+  public final int getScreenY() {
+    return DOMImpl.impl.touchGetScreenY(this);
+  }
+
+  /**
+   * Gets the target element for the current touch.
+   *
+   * @return the target element
+   */
+  public final EventTarget getTarget() {
+    return DOMImpl.impl.touchGetTarget(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/DomEvent.java b/user/src/com/google/gwt/event/dom/client/DomEvent.java
index 4961054..1500589 100644
--- a/user/src/com/google/gwt/event/dom/client/DomEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DomEvent.java
@@ -71,7 +71,7 @@
     /**
      * Gets the name associated with this event type.
      * 
-     * @return the name of this event typ
+     * @return the name of this event type
      */
     public String getName() {
       return name;
diff --git a/user/src/com/google/gwt/event/dom/client/GestureChangeEvent.java b/user/src/com/google/gwt/event/dom/client/GestureChangeEvent.java
new file mode 100644
index 0000000..5d5e8a8
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/GestureChangeEvent.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+/**
+ * Represents a native gesture change event.
+ */
+public class GestureChangeEvent extends DomEvent<GestureChangeHandler> {
+
+  /**
+   * Event type for gesture change events. Represents the meta-data associated
+   * with this event.
+   */
+  private static final Type<GestureChangeHandler> TYPE = new Type<
+      GestureChangeHandler>("gesturechange", new GestureChangeEvent());
+
+  /**
+   * Gets the event type associated with gesture change events.
+   *
+   * @return the handler type
+   */
+  public static Type<GestureChangeHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use {@link
+   * DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
+   * com.google.gwt.event.shared.HasHandlers)} to fire gesture change events.
+   */
+  protected GestureChangeEvent() {
+  }
+
+  @Override
+  public final Type<GestureChangeHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  public double getRotation() {
+    return getNativeEvent().getRotation();
+  }
+
+  public double getScale() {
+    return getNativeEvent().getScale();
+  }
+
+  @Override
+  protected void dispatch(GestureChangeHandler handler) {
+    handler.onGestureChange(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/GestureChangeHandler.java b/user/src/com/google/gwt/event/dom/client/GestureChangeHandler.java
new file mode 100644
index 0000000..10f0e7f
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/GestureChangeHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler interface for {@link GestureChangeEvent} events.
+ */
+public interface GestureChangeHandler extends EventHandler {
+
+  /**
+   * Called when GestureChangeEvent is fired.
+   *
+   * @param event the {@link GestureChangeEvent} that was fired
+   */
+  void onGestureChange(GestureChangeEvent event);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/GestureEndEvent.java b/user/src/com/google/gwt/event/dom/client/GestureEndEvent.java
new file mode 100644
index 0000000..c1848c0
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/GestureEndEvent.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+/**
+ * Represents a native gesture end event.
+ */
+public class GestureEndEvent extends DomEvent<GestureEndHandler> {
+
+  /**
+   * Event type for gesture end events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<GestureEndHandler> TYPE = new Type<
+      GestureEndHandler>("gestureend", new GestureEndEvent());
+
+  /**
+   * Gets the event type associated with gesture end events.
+   *
+   * @return the handler type
+   */
+  public static Type<GestureEndHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use {@link
+   * DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
+   * com.google.gwt.event.shared.HasHandlers)} to fire gesture end events.
+   */
+  protected GestureEndEvent() {
+  }
+
+  @Override
+  public final Type<GestureEndHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  public double getRotation() {
+    return getNativeEvent().getRotation();
+  }
+
+  public double getScale() {
+    return getNativeEvent().getScale();
+  }
+
+  @Override
+  protected void dispatch(GestureEndHandler handler) {
+    handler.onGestureEnd(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/GestureEndHandler.java b/user/src/com/google/gwt/event/dom/client/GestureEndHandler.java
new file mode 100644
index 0000000..8effcb6
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/GestureEndHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler interface for {@link GestureEndEvent} events.
+ */
+public interface GestureEndHandler extends EventHandler {
+
+  /**
+   * Called when GestureEndEvent is fired.
+   *
+   * @param event the {@link GestureEndEvent} that was fired
+   */
+  void onGestureEnd(GestureEndEvent event);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/GestureStartEvent.java b/user/src/com/google/gwt/event/dom/client/GestureStartEvent.java
new file mode 100644
index 0000000..df9d16f
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/GestureStartEvent.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+/**
+ * Represents a native gesture start event.
+ */
+public class GestureStartEvent extends DomEvent<GestureStartHandler> {
+
+  /**
+   * Event type for gesture start events. Represents the meta-data associated
+   * with this event.
+   */
+  private static final Type<GestureStartHandler> TYPE = new Type<
+      GestureStartHandler>("gesturestart", new GestureStartEvent());
+
+  /**
+   * Gets the event type associated with gesture start events.
+   *
+   * @return the handler type
+   */
+  public static Type<GestureStartHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use {@link
+   * DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
+   * com.google.gwt.event.shared.HasHandlers)} to fire gesture start events.
+   */
+  protected GestureStartEvent() {
+  }
+
+  @Override
+  public final Type<GestureStartHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  public double getRotation() {
+    return getNativeEvent().getRotation();
+  }
+
+  public double getScale() {
+    return getNativeEvent().getScale();
+  }
+
+  @Override
+  protected void dispatch(GestureStartHandler handler) {
+    handler.onGestureStart(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/GestureStartHandler.java b/user/src/com/google/gwt/event/dom/client/GestureStartHandler.java
new file mode 100644
index 0000000..98771db
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/GestureStartHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler interface for {@link GestureStartEvent} events.
+ */
+public interface GestureStartHandler extends EventHandler {
+
+  /**
+   * Called when GestureStartEvent is fired.
+   *
+   * @param event the {@link GestureStartEvent} that was fired
+   */
+  void onGestureStart(GestureStartEvent event);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/HandlesAllTouchEvents.java b/user/src/com/google/gwt/event/dom/client/HandlesAllTouchEvents.java
new file mode 100644
index 0000000..1c8ea00
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HandlesAllTouchEvents.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.event.dom.client;
+
+/**
+ * Receiver used to handle all mouse events at once.
+ *
+ * WARNING, PLEASE READ: As this class is intended for developers who wish to
+ * handle all mouse events in GWT, new mouse handler interfaces will be added to
+ * it. Therefore, updates to GWT could cause breaking API changes.
+ *
+ */
+public abstract class HandlesAllTouchEvents implements TouchStartHandler,
+    TouchMoveHandler, TouchEndHandler, TouchCancelHandler {
+
+  /**
+   * Convenience method used to handle all touch events from an event source.
+   *
+   * @param <H> receiver type, must implement all touch handlers
+   * @param source the event source
+   * @param reciever the receiver implementing all touch handlers
+   */
+  public static <H extends TouchStartHandler & TouchMoveHandler
+      & TouchEndHandler & TouchCancelHandler>
+      void handle(HasAllTouchHandlers source, H reciever) {
+    source.addTouchStartHandler(reciever);
+    source.addTouchMoveHandler(reciever);
+    source.addTouchEndHandler(reciever);
+    source.addTouchCancelHandler(reciever);
+  }
+
+  /**
+   * Constructor.
+   */
+  public HandlesAllTouchEvents() {
+  }
+
+  /**
+   * Convenience method to handle all touch events from an event source.
+   *
+   * @param eventSource the event source
+   */
+  public void handle(HasAllTouchHandlers eventSource) {
+    handle(eventSource, this);
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/HasAllGestureHandlers.java b/user/src/com/google/gwt/event/dom/client/HasAllGestureHandlers.java
new file mode 100644
index 0000000..369052c
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasAllGestureHandlers.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.event.dom.client;
+
+/**
+ * This is a convenience interface that includes all gesture handlers defined by
+ * the core GWT system.
+ * <p>
+ * WARNING, PLEASE READ: As this interface is intended for developers who wish
+ * to handle all gesture events in GWT, new gesture event handlers will be added
+ * to it. Therefore, updates can cause breaking API changes.
+ * </p>
+ */
+public interface HasAllGestureHandlers extends HasGestureStartHandlers,
+    HasGestureChangeHandlers, HasGestureEndHandlers {
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/HasAllTouchHandlers.java b/user/src/com/google/gwt/event/dom/client/HasAllTouchHandlers.java
new file mode 100644
index 0000000..1408954
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasAllTouchHandlers.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.event.dom.client;
+
+/**
+ * This is a convenience interface that includes all touch handlers defined by
+ * the core GWT system.
+ * <p>
+ * WARNING, PLEASE READ: As this interface is intended for developers who wish
+ * to handle all touch events in GWT, new touch event handlers will be added to
+ * it. Therefore, updates can cause breaking API changes.
+ * </p>
+ */
+public interface HasAllTouchHandlers extends HasTouchStartHandlers,
+    HasTouchMoveHandlers, HasTouchEndHandlers, HasTouchCancelHandlers {
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasGestureChangeHandlers.java b/user/src/com/google/gwt/event/dom/client/HasGestureChangeHandlers.java
new file mode 100644
index 0000000..bbc8db8
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasGestureChangeHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface provides registration for
+ * {@link GestureChangeHandler} instances.
+ */
+public interface HasGestureChangeHandlers extends HasHandlers {
+  /**
+   * Adds a {@link GestureChangeEvent} handler.
+   *
+   * @param handler the mouse down handler
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  HandlerRegistration addGestureChangeHandler(GestureChangeHandler handler);
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasGestureEndHandlers.java b/user/src/com/google/gwt/event/dom/client/HasGestureEndHandlers.java
new file mode 100644
index 0000000..a777900
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasGestureEndHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface provides registration for
+ * {@link GestureEndHandler} instances.
+ */
+public interface HasGestureEndHandlers extends HasHandlers {
+  /**
+   * Adds a {@link GestureEndEvent} handler.
+   *
+   * @param handler the mouse down handler
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  HandlerRegistration addGestureEndHandler(GestureEndHandler handler);
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasGestureStartHandlers.java b/user/src/com/google/gwt/event/dom/client/HasGestureStartHandlers.java
new file mode 100644
index 0000000..bc789d3
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasGestureStartHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface provides registration for
+ * {@link GestureStartHandler} instances.
+ */
+public interface HasGestureStartHandlers extends HasHandlers {
+  /**
+   * Adds a {@link GestureStartEvent} handler.
+   *
+   * @param handler the mouse down handler
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  HandlerRegistration addGestureStartHandler(GestureStartHandler handler);
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasTouchCancelHandlers.java b/user/src/com/google/gwt/event/dom/client/HasTouchCancelHandlers.java
new file mode 100644
index 0000000..c51c558
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasTouchCancelHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface provides registration for
+ * {@link TouchCancelHandler} instances.
+ */
+public interface HasTouchCancelHandlers extends HasHandlers {
+  /**
+   * Adds a {@link TouchCancelEvent} handler.
+   *
+   * @param handler the mouse down handler
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler);
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasTouchEndHandlers.java b/user/src/com/google/gwt/event/dom/client/HasTouchEndHandlers.java
new file mode 100644
index 0000000..88ca6e2
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasTouchEndHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface provides registration for
+ * {@link TouchEndHandler} instances.
+ */
+public interface HasTouchEndHandlers extends HasHandlers {
+  /**
+   * Adds a {@link TouchEndEvent} handler.
+   *
+   * @param handler the mouse down handler
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  HandlerRegistration addTouchEndHandler(TouchEndHandler handler);
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasTouchMoveHandlers.java b/user/src/com/google/gwt/event/dom/client/HasTouchMoveHandlers.java
new file mode 100644
index 0000000..a2d8eb9
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasTouchMoveHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface provides registration for
+ * {@link TouchMoveHandler} instances.
+ */
+public interface HasTouchMoveHandlers extends HasHandlers {
+  /**
+   * Adds a {@link TouchMoveEvent} handler.
+   *
+   * @param handler the mouse down handler
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler);
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasTouchStartHandlers.java b/user/src/com/google/gwt/event/dom/client/HasTouchStartHandlers.java
new file mode 100644
index 0000000..2416619
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasTouchStartHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface provides registration for
+ * {@link TouchStartHandler} instances.
+ */
+public interface HasTouchStartHandlers extends HasHandlers {
+  /**
+   * Adds a {@link TouchStartEvent} handler.
+   *
+   * @param handler the mouse down handler
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  HandlerRegistration addTouchStartHandler(TouchStartHandler handler);
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HumanInputEvent.java b/user/src/com/google/gwt/event/dom/client/HumanInputEvent.java
new file mode 100644
index 0000000..6a3a99d
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HumanInputEvent.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Abstract class representing position events such as mouse or touch events.
+ *
+ * @param <H> handler type
+ *
+ */
+public abstract class HumanInputEvent<H extends EventHandler> extends DomEvent<
+    H> {
+
+  /**
+   * Is <code>alt</code> key down.
+   *
+   * @return whether the alt key is down
+   */
+  public boolean isAltKeyDown() {
+    return getNativeEvent().getAltKey();
+  }
+
+  /**
+   * Is <code>control</code> key down.
+   *
+   * @return whether the control key is down
+   */
+  public boolean isControlKeyDown() {
+    return getNativeEvent().getCtrlKey();
+  }
+
+  /**
+   * Is <code>meta</code> key down.
+   *
+   * @return whether the meta key is down
+   */
+  public boolean isMetaKeyDown() {
+    return getNativeEvent().getMetaKey();
+  }
+
+  /**
+   * Is <code>shift</code> key down.
+   *
+   * @return whether the shift key is down
+   */
+  public boolean isShiftKeyDown() {
+    return getNativeEvent().getShiftKey();
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/MouseEvent.java b/user/src/com/google/gwt/event/dom/client/MouseEvent.java
index e9be08c..32b7cf2 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseEvent.java
@@ -25,7 +25,8 @@
  * @param <H> handler type
  * 
  */
-public abstract class MouseEvent<H extends EventHandler> extends DomEvent<H> {
+public abstract class MouseEvent<H extends EventHandler>
+    extends HumanInputEvent<H> {
 
   /**
    * Gets the mouse x-position within the browser window's client area.
@@ -126,40 +127,4 @@
     }
     return getClientY();
   }
-
-  /**
-   * Is <code>alt</code> key down.
-   * 
-   * @return whether the alt key is down
-   */
-  public boolean isAltKeyDown() {
-    return getNativeEvent().getAltKey();
-  }
-
-  /**
-   * Is <code>control</code> key down.
-   * 
-   * @return whether the control key is down
-   */
-  public boolean isControlKeyDown() {
-    return getNativeEvent().getCtrlKey();
-  }
-
-  /**
-   * Is <code>meta</code> key down.
-   * 
-   * @return whether the meta key is down
-   */
-  public boolean isMetaKeyDown() {
-    return getNativeEvent().getMetaKey();
-  }
-
-  /**
-   * Is <code>shift</code> key down.
-   * 
-   * @return whether the shift key is down
-   */
-  public boolean isShiftKeyDown() {
-    return getNativeEvent().getShiftKey();
-  }
 }
diff --git a/user/src/com/google/gwt/event/dom/client/TouchCancelEvent.java b/user/src/com/google/gwt/event/dom/client/TouchCancelEvent.java
new file mode 100644
index 0000000..8522a65
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchCancelEvent.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+/**
+ * Represents a native touch start event.
+ */
+public class TouchCancelEvent extends TouchEvent<TouchCancelHandler> {
+
+  /**
+   * Event type for touch start events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<TouchCancelHandler> TYPE = new Type<
+      TouchCancelHandler>("touchcancel", new TouchCancelEvent());
+
+  /**
+   * Gets the event type associated with touch start events.
+   *
+   * @return the handler type
+   */
+  public static Type<TouchCancelHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use {@link
+   * DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
+   * com.google.gwt.event.shared.HasHandlers)} to fire touch start events.
+   */
+  protected TouchCancelEvent() {
+  }
+
+  @Override
+  public final Type<TouchCancelHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(TouchCancelHandler handler) {
+    handler.onTouchCancel(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/TouchCancelHandler.java b/user/src/com/google/gwt/event/dom/client/TouchCancelHandler.java
new file mode 100644
index 0000000..e829da2
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchCancelHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler interface for {@link TouchCancelEvent} events.
+ */
+public interface TouchCancelHandler extends EventHandler {
+
+  /**
+   * Called when TouchCancelEvent is fired.
+   *
+   * @param event the {@link TouchCancelEvent} that was fired
+   */
+  void onTouchCancel(TouchCancelEvent event);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/TouchEndEvent.java b/user/src/com/google/gwt/event/dom/client/TouchEndEvent.java
new file mode 100644
index 0000000..9b69e37
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchEndEvent.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+/**
+ * Represents a native touch end event.
+ */
+public class TouchEndEvent extends TouchEvent<TouchEndHandler> {
+
+  /**
+   * Event type for touch end events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<TouchEndHandler> TYPE = new Type<TouchEndHandler>(
+      "touchend", new TouchEndEvent());
+
+  /**
+   * Gets the event type associated with touch end events.
+   *
+   * @return the handler type
+   */
+  public static Type<TouchEndHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use {@link
+   * DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
+   * com.google.gwt.event.shared.HasHandlers)} to fire touch end events.
+   */
+  protected TouchEndEvent() {
+  }
+
+  @Override
+  public final Type<TouchEndHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(TouchEndHandler handler) {
+    handler.onTouchEnd(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/TouchEndHandler.java b/user/src/com/google/gwt/event/dom/client/TouchEndHandler.java
new file mode 100644
index 0000000..87cfea5
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchEndHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler interface for {@link TouchEndEvent} events.
+ */
+public interface TouchEndHandler extends EventHandler {
+
+  /**
+   * Called when TouchEndEvent is fired.
+   *
+   * @param event the {@link TouchEndEvent} that was fired
+   */
+  void onTouchEnd(TouchEndEvent event);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/TouchEvent.java b/user/src/com/google/gwt/event/dom/client/TouchEvent.java
new file mode 100644
index 0000000..30cff9b
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchEvent.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.dom.client.Touch;
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Abstract class representing touch events.
+ *
+ * @see http://developer.apple.com/library/safari/documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html
+ *
+ * @param <H> handler type
+ */
+public abstract class TouchEvent<H extends EventHandler>
+    extends HumanInputEvent<H> {
+
+  /**
+   * Get an array of {@link Touch touches} which have changed since the last
+   * touch event fired. Note, that for {@link TouchEndEvent touch end events},
+   * the touch which has just ended will not be present in the array. Moreover,
+   * if the touch which just ended was the last remaining touch, then a zero
+   * length array will be returned.
+   *
+   * @return an array of touches
+   */
+  public JsArray<Touch> getChangedTouches() {
+    return getNativeEvent().getChangedTouches();
+  }
+
+  /**
+   * Get an array of {@link Touch touches} all touch which originated at the
+   * same target as the current touch event. Note, that for {@link TouchEndEvent
+   * touch end events}, the touch which has just ended will not be present in
+   * the array. Moreover, if the touch which just ended was the last remaining
+   * touch, then a zero length array will be returned.
+   *
+   * @return an array of touches
+   */
+  public JsArray<Touch> getTargetTouches() {
+    return getNativeEvent().getTargetTouches();
+  }
+
+  /**
+   * Get an array of all current {@link Touch touches}. Note, that for
+   * {@link TouchEndEvent touch end events}, the touch which has just ended will
+   * not be present in the array. Moreover, if the touch which just ended was
+   * the last remaining touch, then a zero length array will be returned.
+   *
+   * @return an array of touches
+   */
+  public JsArray<Touch> getTouches() {
+    return getNativeEvent().getTouches();
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/TouchMoveEvent.java b/user/src/com/google/gwt/event/dom/client/TouchMoveEvent.java
new file mode 100644
index 0000000..708a9dc
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchMoveEvent.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+/**
+ * Represents a native touch move event.
+ */
+public class TouchMoveEvent extends TouchEvent<TouchMoveHandler> {
+
+  /**
+   * Event type for touch move events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<TouchMoveHandler> TYPE = new Type<TouchMoveHandler>(
+      "touchmove", new TouchMoveEvent());
+
+  /**
+   * Gets the event type associated with touch move events.
+   *
+   * @return the handler type
+   */
+  public static Type<TouchMoveHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use {@link
+   * DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
+   * com.google.gwt.event.shared.HasHandlers)} to fire touch move events.
+   */
+  protected TouchMoveEvent() {
+  }
+
+  @Override
+  public final Type<TouchMoveHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(TouchMoveHandler handler) {
+    handler.onTouchMove(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/TouchMoveHandler.java b/user/src/com/google/gwt/event/dom/client/TouchMoveHandler.java
new file mode 100644
index 0000000..a16d09f
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchMoveHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler interface for {@link TouchMoveEvent} events.
+ */
+public interface TouchMoveHandler extends EventHandler {
+
+  /**
+   * Called when TouchMoveEvent is fired.
+   *
+   * @param event the {@link TouchMoveEvent} that was fired
+   */
+  void onTouchMove(TouchMoveEvent event);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/TouchStartEvent.java b/user/src/com/google/gwt/event/dom/client/TouchStartEvent.java
new file mode 100644
index 0000000..82f0fb4
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchStartEvent.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+/**
+ * Represents a native touch start event.
+ */
+public class TouchStartEvent extends TouchEvent<TouchStartHandler> {
+
+  /**
+   * Event type for touch start events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<TouchStartHandler> TYPE = new Type<
+      TouchStartHandler>("touchstart", new TouchStartEvent());
+
+  /**
+   * Gets the event type associated with touch start events.
+   *
+   * @return the handler type
+   */
+  public static Type<TouchStartHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use {@link
+   * DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
+   * com.google.gwt.event.shared.HasHandlers)} to fire touch start events.
+   */
+  protected TouchStartEvent() {
+  }
+
+  @Override
+  public final Type<TouchStartHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(TouchStartHandler handler) {
+    handler.onTouchStart(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/TouchStartHandler.java b/user/src/com/google/gwt/event/dom/client/TouchStartHandler.java
new file mode 100644
index 0000000..8c1ec20
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/TouchStartHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler interface for {@link TouchStartEvent} events.
+ */
+public interface TouchStartHandler extends EventHandler {
+
+  /**
+   * Called when TouchStartEvent is fired.
+   *
+   * @param event the {@link TouchStartEvent} that was fired
+   */
+  void onTouchStart(TouchStartEvent event);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index 3bacabb..32329cd 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -969,8 +969,9 @@
   }
 
   /**
-   * Releases mouse capture on the given element. Calling this method has no
-   * effect if the element does not currently have mouse capture.
+   * Releases mouse/touch/gesture capture on the given element. Calling this
+   * method has no effect if the element does not currently have
+   * mouse/touch/gesture capture.
    * 
    * @param elem the element to release capture
    * @see #setCapture(Element)
@@ -1063,10 +1064,11 @@
   }
 
   /**
-   * Sets mouse-capture on the given element. This element will directly receive
-   * all mouse events until {@link #releaseCapture(Element)} is called on it.
+   * Sets mouse/touch/gesture capture on the given element. This element will
+   * directly receive all mouse events until {@link #releaseCapture(Element)} is
+   * called on it.
    * 
-   * @param elem the element on which to set mouse capture
+   * @param elem the element on which to set mouse/touch/gesture capture
    */
   public static void setCapture(Element elem) {
     sCaptureElem = elem;
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java
index dedf387..f2465fb 100644
--- a/user/src/com/google/gwt/user/client/Event.java
+++ b/user/src/com/google/gwt/user/client/Event.java
@@ -258,6 +258,21 @@
   public static final int ONFOCUS = 0x00800;
 
   /**
+   * Fired when the user gesture changes.
+   */
+  public static final int ONGESTURECHANGE = 0x2000000;
+
+  /**
+   * Fired when the user gesture ends.
+   */
+  public static final int ONGESTUREEND = 0x4000000;
+
+  /**
+   * Fired when the user gesture starts.
+   */
+  public static final int ONGESTURESTART = 0x1000000;
+
+  /**
    * Fired when the user depresses a key.
    */
   public static final int ONKEYDOWN = 0x00080;
@@ -330,6 +345,25 @@
   public static final int ONSCROLL = 0x04000;
 
   /**
+   * Fired when the user cancels touching an element.
+   */
+  public static final int ONTOUCHCANCEL = 0x800000;
+
+  /**
+   * Fired when the user ends touching an element.
+   */
+  public static final int ONTOUCHEND = 0x400000;
+
+  /**
+   * Fired when the user moves while touching an element.
+   */
+  public static final int ONTOUCHMOVE = 0x200000;
+
+  /**
+   * Fired when the user starts touching an element.
+   */
+  public static final int ONTOUCHSTART = 0x100000;
+  /**
    * Fired when the user requests an element's context menu (usually by
    * right-clicking).
    * 
@@ -355,6 +389,16 @@
       | ONMOUSEOVER | ONMOUSEOUT;
 
   /**
+   * A bit-mask covering all touch events (start, move, end, cancel).
+   */
+  public static final int TOUCHEVENTS = ONTOUCHSTART | ONTOUCHMOVE | ONTOUCHEND | ONTOUCHCANCEL;
+
+  /**
+   * A bit-mask covering all gesture events (start, change, end).
+   */
+  public static final int GESTUREEVENTS = ONGESTURESTART | ONGESTURECHANGE | ONGESTUREEND;
+
+  /**
    * Value returned by accessors when the actual integer value is undefined. In
    * hosted mode, most accessors assert that the requested attribute is reliable
    * across all supported browsers.
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImpl.java b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
index 3f89763..2e682bb 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
@@ -84,6 +84,13 @@
     case "DOMMouseScroll": return 0x20000;
     case "contextmenu": return 0x40000;
     case "paste": return 0x80000;
+    case "touchstart": return 0x100000;
+    case "touchmove": return 0x200000;
+    case "touchend": return 0x400000;
+    case "touchcancel": return 0x800000;
+    case "gesturestart": return 0x1000000;
+    case "gesturechange": return 0x2000000;
+    case "gestureend": return 0x4000000;
     default: return -1;
     }
   }-*/; 
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
index b01707a..f40b951 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -200,6 +200,16 @@
     $wnd.addEventListener('keydown', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
     $wnd.addEventListener('keyup', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
     $wnd.addEventListener('keypress', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
+
+    // Touch and gesture events are not actually mouse events, but we treat
+    // them as such, so that DOM#setCapture() and DOM#releaseCapture() work.
+    $wnd.addEventListener('touchstart', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+    $wnd.addEventListener('touchmove', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+    $wnd.addEventListener('touchend', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+    $wnd.addEventListener('touchcancel', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+    $wnd.addEventListener('gesturestart', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+    $wnd.addEventListener('gesturechange', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+    $wnd.addEventListener('gestureend', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
   }-*/;
 
   protected native void sinkEventsImpl(Element elem, int bits) /*-{
@@ -247,6 +257,20 @@
         @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
     if (chMask & 0x80000) elem.onpaste       = (bits & 0x80000) ? 
         @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
+    if (chMask & 0x100000) elem.ontouchstart = (bits & 0x100000) ? 
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
+    if (chMask & 0x200000) elem.ontouchmove  = (bits & 0x200000) ? 
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
+    if (chMask & 0x400000) elem.ontouchend   = (bits & 0x400000) ? 
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
+    if (chMask & 0x800000) elem.ontouchcancel= (bits & 0x800000) ? 
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
+    if (chMask & 0x1000000) elem.ongesturestart  =(bits & 0x1000000) ? 
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
+    if (chMask & 0x2000000) elem.ongesturechange =(bits & 0x2000000) ? 
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
+    if (chMask & 0x4000000) elem.ongestureend    = (bits & 0x4000000) ? 
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
   }-*/;
 
   private native void releaseCaptureImpl(Element elem) /*-{
diff --git a/user/src/com/google/gwt/user/client/ui/FocusPanel.java b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
index f0a2c84..a793fd6 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
@@ -23,9 +23,17 @@
 import com.google.gwt.event.dom.client.DoubleClickHandler;
 import com.google.gwt.event.dom.client.FocusEvent;
 import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.GestureChangeEvent;
+import com.google.gwt.event.dom.client.GestureChangeHandler;
+import com.google.gwt.event.dom.client.GestureEndEvent;
+import com.google.gwt.event.dom.client.GestureEndHandler;
+import com.google.gwt.event.dom.client.GestureStartEvent;
+import com.google.gwt.event.dom.client.GestureStartHandler;
 import com.google.gwt.event.dom.client.HasAllFocusHandlers;
+import com.google.gwt.event.dom.client.HasAllGestureHandlers;
 import com.google.gwt.event.dom.client.HasAllKeyHandlers;
 import com.google.gwt.event.dom.client.HasAllMouseHandlers;
+import com.google.gwt.event.dom.client.HasAllTouchHandlers;
 import com.google.gwt.event.dom.client.HasClickHandlers;
 import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
 import com.google.gwt.event.dom.client.KeyDownEvent;
@@ -46,6 +54,14 @@
 import com.google.gwt.event.dom.client.MouseUpHandler;
 import com.google.gwt.event.dom.client.MouseWheelEvent;
 import com.google.gwt.event.dom.client.MouseWheelHandler;
+import com.google.gwt.event.dom.client.TouchCancelEvent;
+import com.google.gwt.event.dom.client.TouchCancelHandler;
+import com.google.gwt.event.dom.client.TouchEndEvent;
+import com.google.gwt.event.dom.client.TouchEndHandler;
+import com.google.gwt.event.dom.client.TouchMoveEvent;
+import com.google.gwt.event.dom.client.TouchMoveHandler;
+import com.google.gwt.event.dom.client.TouchStartEvent;
+import com.google.gwt.event.dom.client.TouchStartHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.ui.impl.FocusImpl;
 
@@ -57,7 +73,7 @@
 public class FocusPanel extends SimplePanel implements HasFocus,
     SourcesClickEvents, SourcesMouseEvents, SourcesMouseWheelEvents,
     HasAllMouseHandlers, HasClickHandlers, HasDoubleClickHandlers,
-    HasAllKeyHandlers, HasAllFocusHandlers {
+    HasAllKeyHandlers, HasAllFocusHandlers, HasAllGestureHandlers, HasAllTouchHandlers {
 
   static final FocusImpl impl = FocusImpl.getFocusImplForPanel();
 
@@ -102,6 +118,18 @@
     ListenerWrapper.WrappedFocusListener.add(this, listener);
   }
 
+  public HandlerRegistration addGestureChangeHandler(GestureChangeHandler handler) {
+    return addDomHandler(handler, GestureChangeEvent.getType());
+  }
+
+  public HandlerRegistration addGestureEndHandler(GestureEndHandler handler) {
+    return addDomHandler(handler, GestureEndEvent.getType());
+  }
+
+  public HandlerRegistration addGestureStartHandler(GestureStartHandler handler) {
+    return addDomHandler(handler, GestureStartEvent.getType());
+  }
+
   /**
    * @deprecated Use {@link #addKeyDownHandler}, {@link
    * #addKeyUpHandler} and {@link #addKeyPressHandler} instead
@@ -165,6 +193,22 @@
     ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
   }
 
+  public HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler) {
+    return addDomHandler(handler, TouchCancelEvent.getType());
+  }
+
+  public HandlerRegistration addTouchEndHandler(TouchEndHandler handler) {
+    return addDomHandler(handler, TouchEndEvent.getType());
+  }
+
+  public HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler) {
+    return addDomHandler(handler, TouchMoveEvent.getType());
+  }
+
+  public HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
+    return addDomHandler(handler, TouchStartEvent.getType());
+  }
+
   public int getTabIndex() {
     return impl.getTabIndex(getElement());
   }
diff --git a/user/src/com/google/gwt/user/client/ui/FocusWidget.java b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
index cb39b1e..e3cde65 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusWidget.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
@@ -24,9 +24,17 @@
 import com.google.gwt.event.dom.client.DoubleClickHandler;
 import com.google.gwt.event.dom.client.FocusEvent;
 import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.GestureChangeEvent;
+import com.google.gwt.event.dom.client.GestureChangeHandler;
+import com.google.gwt.event.dom.client.GestureEndEvent;
+import com.google.gwt.event.dom.client.GestureEndHandler;
+import com.google.gwt.event.dom.client.GestureStartEvent;
+import com.google.gwt.event.dom.client.GestureStartHandler;
 import com.google.gwt.event.dom.client.HasAllFocusHandlers;
+import com.google.gwt.event.dom.client.HasAllGestureHandlers;
 import com.google.gwt.event.dom.client.HasAllKeyHandlers;
 import com.google.gwt.event.dom.client.HasAllMouseHandlers;
+import com.google.gwt.event.dom.client.HasAllTouchHandlers;
 import com.google.gwt.event.dom.client.HasClickHandlers;
 import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
 import com.google.gwt.event.dom.client.KeyDownEvent;
@@ -47,6 +55,14 @@
 import com.google.gwt.event.dom.client.MouseUpHandler;
 import com.google.gwt.event.dom.client.MouseWheelEvent;
 import com.google.gwt.event.dom.client.MouseWheelHandler;
+import com.google.gwt.event.dom.client.TouchCancelEvent;
+import com.google.gwt.event.dom.client.TouchCancelHandler;
+import com.google.gwt.event.dom.client.TouchEndEvent;
+import com.google.gwt.event.dom.client.TouchEndHandler;
+import com.google.gwt.event.dom.client.TouchMoveEvent;
+import com.google.gwt.event.dom.client.TouchMoveHandler;
+import com.google.gwt.event.dom.client.TouchStartEvent;
+import com.google.gwt.event.dom.client.TouchStartHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.ui.impl.FocusImpl;
@@ -57,8 +73,8 @@
 @SuppressWarnings("deprecation")
 public abstract class FocusWidget extends Widget implements SourcesClickEvents,
     HasClickHandlers, HasDoubleClickHandlers, HasFocus, HasEnabled,
-    HasAllFocusHandlers, HasAllKeyHandlers, HasAllMouseHandlers,
-    SourcesMouseEvents {
+    HasAllFocusHandlers, HasAllGestureHandlers, HasAllKeyHandlers, HasAllMouseHandlers,
+    HasAllTouchHandlers, SourcesMouseEvents {
 
   private static final FocusImpl impl = FocusImpl.getFocusImplForWidget();
 
@@ -119,6 +135,18 @@
     ListenerWrapper.WrappedFocusListener.add(this, listener);
   }
 
+  public HandlerRegistration addGestureChangeHandler(GestureChangeHandler handler) {
+    return addDomHandler(handler, GestureChangeEvent.getType());
+  }
+
+  public HandlerRegistration addGestureEndHandler(GestureEndHandler handler) {
+    return addDomHandler(handler, GestureEndEvent.getType());
+  }
+
+  public HandlerRegistration addGestureStartHandler(GestureStartHandler handler) {
+    return addDomHandler(handler, GestureStartEvent.getType());
+  }
+
   /**
    * @deprecated Use {@link #addKeyDownHandler}, {@link
    * #addKeyUpHandler} and {@link #addKeyPressHandler} instead
@@ -182,6 +210,22 @@
     ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
   }
 
+  public HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler) {
+    return addDomHandler(handler, TouchCancelEvent.getType());
+  }
+
+  public HandlerRegistration addTouchEndHandler(TouchEndHandler handler) {
+    return addDomHandler(handler, TouchEndEvent.getType());
+  }
+
+  public HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler) {
+    return addDomHandler(handler, TouchMoveEvent.getType());
+  }
+
+  public HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
+    return addDomHandler(handler, TouchStartEvent.getType());
+  }
+
   /**
    * Gets the tab index.
    * 
diff --git a/user/src/com/google/gwt/user/client/ui/Image.java b/user/src/com/google/gwt/user/client/ui/Image.java
index c1eef4d..b057c2c 100644
--- a/user/src/com/google/gwt/user/client/ui/Image.java
+++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -26,7 +26,15 @@
 import com.google.gwt.event.dom.client.DoubleClickHandler;
 import com.google.gwt.event.dom.client.ErrorEvent;
 import com.google.gwt.event.dom.client.ErrorHandler;
+import com.google.gwt.event.dom.client.GestureChangeEvent;
+import com.google.gwt.event.dom.client.GestureChangeHandler;
+import com.google.gwt.event.dom.client.GestureEndEvent;
+import com.google.gwt.event.dom.client.GestureEndHandler;
+import com.google.gwt.event.dom.client.GestureStartEvent;
+import com.google.gwt.event.dom.client.GestureStartHandler;
+import com.google.gwt.event.dom.client.HasAllGestureHandlers;
 import com.google.gwt.event.dom.client.HasAllMouseHandlers;
+import com.google.gwt.event.dom.client.HasAllTouchHandlers;
 import com.google.gwt.event.dom.client.HasClickHandlers;
 import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
 import com.google.gwt.event.dom.client.HasErrorHandlers;
@@ -45,6 +53,14 @@
 import com.google.gwt.event.dom.client.MouseUpHandler;
 import com.google.gwt.event.dom.client.MouseWheelEvent;
 import com.google.gwt.event.dom.client.MouseWheelHandler;
+import com.google.gwt.event.dom.client.TouchCancelEvent;
+import com.google.gwt.event.dom.client.TouchCancelHandler;
+import com.google.gwt.event.dom.client.TouchEndEvent;
+import com.google.gwt.event.dom.client.TouchEndHandler;
+import com.google.gwt.event.dom.client.TouchMoveEvent;
+import com.google.gwt.event.dom.client.TouchMoveHandler;
+import com.google.gwt.event.dom.client.TouchStartEvent;
+import com.google.gwt.event.dom.client.TouchStartHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.user.client.Command;
@@ -94,7 +110,8 @@
 @SuppressWarnings("deprecation")
 public class Image extends Widget implements SourcesLoadEvents, HasLoadHandlers,
     HasErrorHandlers, SourcesClickEvents, HasClickHandlers,
-    HasDoubleClickHandlers, HasAllMouseHandlers, SourcesMouseEvents {
+    HasDoubleClickHandlers, HasAllGestureHandlers, HasAllMouseHandlers, HasAllTouchHandlers,
+    SourcesMouseEvents {
 
   /**
    * The attribute that is set when an image fires a native load or error event
@@ -126,7 +143,7 @@
       // Todo(ecc) This is wrong, we should not be sinking these here on such a
       // common widget.After the branch is stable, this should be fixed.
       image.sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL
-          | Event.ONLOAD);
+          | Event.ONLOAD | Event.TOUCHEVENTS | Event.GESTUREEVENTS);
     }
 
     @Override
@@ -283,7 +300,8 @@
       // This case is relatively unusual, in that we swapped a clipped image
       // out, so does not need to be efficient.
       Event.sinkEvents(element, Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS
-          | Event.ONLOAD | Event.ONERROR | Event.ONMOUSEWHEEL);
+          | Event.ONLOAD | Event.ONERROR | Event.ONMOUSEWHEEL | Event.TOUCHEVENTS
+          | Event.GESTUREEVENTS);
     }
 
     UnclippedState(Image image) {
@@ -295,7 +313,7 @@
 
       // Todo(ecc) this could be more efficient overall.
       image.sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.ONLOAD
-          | Event.ONERROR | Event.ONMOUSEWHEEL);
+          | Event.ONERROR | Event.ONMOUSEWHEEL | Event.TOUCHEVENTS | Event.GESTUREEVENTS);
     }
 
     UnclippedState(Image image, String url) {
@@ -485,6 +503,18 @@
     return addHandler(handler, ErrorEvent.getType());
   }
 
+  public HandlerRegistration addGestureChangeHandler(GestureChangeHandler handler) {
+    return addDomHandler(handler, GestureChangeEvent.getType());
+  }
+
+  public HandlerRegistration addGestureEndHandler(GestureEndHandler handler) {
+    return addDomHandler(handler, GestureEndEvent.getType());
+  }
+
+  public HandlerRegistration addGestureStartHandler(GestureStartHandler handler) {
+    return addDomHandler(handler, GestureStartEvent.getType());
+  }
+
   public HandlerRegistration addLoadHandler(LoadHandler handler) {
     return addHandler(handler, LoadEvent.getType());
   }
@@ -540,6 +570,22 @@
     ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
   }
 
+  public HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler) {
+    return addDomHandler(handler, TouchCancelEvent.getType());
+  }
+
+  public HandlerRegistration addTouchEndHandler(TouchEndHandler handler) {
+    return addDomHandler(handler, TouchEndEvent.getType());
+  }
+
+  public HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler) {
+    return addDomHandler(handler, TouchMoveEvent.getType());
+  }
+
+  public HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
+    return addDomHandler(handler, TouchStartEvent.getType());
+  }
+
   /**
    * Gets the alternate text for the image.
    * 
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java b/user/src/com/google/gwt/user/client/ui/Label.java
index ab4792e..a2ab4bc 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -24,7 +24,15 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
 import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.GestureChangeEvent;
+import com.google.gwt.event.dom.client.GestureChangeHandler;
+import com.google.gwt.event.dom.client.GestureEndEvent;
+import com.google.gwt.event.dom.client.GestureEndHandler;
+import com.google.gwt.event.dom.client.GestureStartEvent;
+import com.google.gwt.event.dom.client.GestureStartHandler;
+import com.google.gwt.event.dom.client.HasAllGestureHandlers;
 import com.google.gwt.event.dom.client.HasAllMouseHandlers;
+import com.google.gwt.event.dom.client.HasAllTouchHandlers;
 import com.google.gwt.event.dom.client.HasClickHandlers;
 import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
 import com.google.gwt.event.dom.client.MouseDownEvent;
@@ -39,6 +47,14 @@
 import com.google.gwt.event.dom.client.MouseUpHandler;
 import com.google.gwt.event.dom.client.MouseWheelEvent;
 import com.google.gwt.event.dom.client.MouseWheelHandler;
+import com.google.gwt.event.dom.client.TouchCancelEvent;
+import com.google.gwt.event.dom.client.TouchCancelHandler;
+import com.google.gwt.event.dom.client.TouchEndEvent;
+import com.google.gwt.event.dom.client.TouchEndHandler;
+import com.google.gwt.event.dom.client.TouchMoveEvent;
+import com.google.gwt.event.dom.client.TouchMoveHandler;
+import com.google.gwt.event.dom.client.TouchStartEvent;
+import com.google.gwt.event.dom.client.TouchStartHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.i18n.client.BidiUtils;
 import com.google.gwt.i18n.client.HasDirection;
@@ -72,8 +88,8 @@
 @SuppressWarnings("deprecation")
 public class Label extends Widget implements HasDirectionalText, HasWordWrap,
     HasDirection, HasClickHandlers, HasDoubleClickHandlers, SourcesClickEvents,
-    SourcesMouseEvents, HasAllMouseHandlers, HasDirectionEstimator,
-    HasAutoHorizontalAlignment, IsEditor<LeafValueEditor<String>> {
+    SourcesMouseEvents, HasAllGestureHandlers, HasAllMouseHandlers, HasAllTouchHandlers,
+    HasDirectionEstimator, HasAutoHorizontalAlignment, IsEditor<LeafValueEditor<String>> {
 
   public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR =
       DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR;
@@ -204,6 +220,18 @@
     return addDomHandler(handler, DoubleClickEvent.getType());
   }
 
+  public HandlerRegistration addGestureChangeHandler(GestureChangeHandler handler) {
+    return addDomHandler(handler, GestureChangeEvent.getType());
+  }
+
+  public HandlerRegistration addGestureEndHandler(GestureEndHandler handler) {
+    return addDomHandler(handler, GestureEndEvent.getType());
+  }
+
+  public HandlerRegistration addGestureStartHandler(GestureStartHandler handler) {
+    return addDomHandler(handler, GestureStartEvent.getType());
+  }
+
   public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
     return addDomHandler(handler, MouseDownEvent.getType());
   }
@@ -246,6 +274,22 @@
     ListenerWrapper.WrappedMouseWheelListener.add(this, listener);
   }
 
+  public HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler) {
+    return addDomHandler(handler, TouchCancelEvent.getType());
+  }
+
+  public HandlerRegistration addTouchEndHandler(TouchEndHandler handler) {
+    return addDomHandler(handler, TouchEndEvent.getType());
+  }
+
+  public HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler) {
+    return addDomHandler(handler, TouchMoveEvent.getType());
+  }
+
+  public HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
+    return addDomHandler(handler, TouchStartEvent.getType());
+  }
+  
   public LeafValueEditor<String> asEditor() {
     return HasTextEditor.of(this);
   }
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 02b6946..7f5a403 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -22,7 +22,9 @@
 import com.google.gwt.user.client.CookieTest;
 import com.google.gwt.user.client.DoubleClickEventSinkTest;
 import com.google.gwt.user.client.EventTest;
+import com.google.gwt.user.client.GestureEventSinkTest;
 import com.google.gwt.user.client.HistoryDisabledTest;
+import com.google.gwt.user.client.TouchEventSinkTest;
 import com.google.gwt.user.client.WindowTest;
 import com.google.gwt.user.client.ui.AbsolutePanelTest;
 import com.google.gwt.user.client.ui.AnchorTest;
@@ -164,6 +166,7 @@
     suite.addTestSuite(FlowPanelTest.class);
     suite.addTestSuite(FocusPanelTest.class);
     suite.addTestSuite(FormPanelTest.class);
+    suite.addTestSuite(GestureEventSinkTest.class);
     suite.addTestSuite(GridTest.class);
     suite.addTestSuite(HiddenTest.class);
     suite.addTestSuite(HistoryTest.class);
@@ -207,6 +210,7 @@
     suite.addTestSuite(TextAreaTest.class);
     suite.addTestSuite(TreeTest.class);
     suite.addTestSuite(TreeItemTest.class);
+    suite.addTestSuite(TouchEventSinkTest.class);
     suite.addTestSuite(UIObjectTest.class);
     suite.addTestSuite(ValueBoxBaseTest.class);
     suite.addTestSuite(ValueListBoxTest.class);
diff --git a/user/test/com/google/gwt/user/client/GestureEventSinkTest.java b/user/test/com/google/gwt/user/client/GestureEventSinkTest.java
new file mode 100644
index 0000000..86c2587
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/GestureEventSinkTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.user.client;
+
+import com.google.gwt.event.dom.client.HasAllGestureHandlers;
+import com.google.gwt.event.dom.client.GestureChangeEvent;
+import com.google.gwt.event.dom.client.GestureChangeHandler;
+import com.google.gwt.event.dom.client.GestureEndEvent;
+import com.google.gwt.event.dom.client.GestureEndHandler;
+import com.google.gwt.event.dom.client.GestureStartEvent;
+import com.google.gwt.event.dom.client.GestureStartHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.ui.Anchor;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.FocusPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.PasswordTextBox;
+import com.google.gwt.user.client.ui.RichTextArea;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.SimpleRadioButton;
+import com.google.gwt.user.client.ui.TextArea;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.ToggleButton;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Test Case for sinking of gesture events.
+ */
+public class GestureEventSinkTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  public void testFocusPanelGestureEventSinkByAddingHandler() {
+    verifyGestureStartEventSinkOnAddHandler(new FocusPanel(), false);
+    verifyGestureEndEventSinkOnAddHandler(new FocusPanel(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new FocusPanel(), false);
+  }
+
+  public void testFocusWidgetGestureEventSinkByAddingHandler() {
+    verifyGestureStartEventSinkOnAddHandler(new Anchor(), false);
+    verifyGestureEndEventSinkOnAddHandler(new Anchor(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new Anchor(), false);
+
+    verifyGestureStartEventSinkOnAddHandler(new Button(), false);
+    verifyGestureEndEventSinkOnAddHandler(new Button(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new Button(), false);
+
+    CheckBox checkBox1 = new CheckBox();
+    // Get the inputElem on which events are sunk
+    Element e1 = (Element) checkBox1.getElement().getFirstChildElement();
+    verifyGestureStartEventSinkOnAddHandler(checkBox1, e1, false);
+
+    CheckBox checkBox2 = new CheckBox();
+    // Get the inputElem on which events are sunk
+    Element e2 = (Element) checkBox2.getElement().getFirstChildElement();
+    verifyGestureChangeEventSinkOnAddHandler(checkBox2, e2, false);
+
+    CheckBox checkBox3 = new CheckBox();
+    // Get the inputElem on which events are sunk
+    Element e3 = (Element) checkBox3.getElement().getFirstChildElement();
+    verifyGestureEndEventSinkOnAddHandler(checkBox3, e3, false);
+
+    verifyGestureStartEventSinkOnAddHandler(new ToggleButton(), false);
+    verifyGestureEndEventSinkOnAddHandler(new ToggleButton(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new ToggleButton(), false);
+
+    verifyGestureStartEventSinkOnAddHandler(new ListBox(), false);
+    verifyGestureEndEventSinkOnAddHandler(new ListBox(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new ListBox(), false);
+
+    verifyGestureStartEventSinkOnAddHandler(new RichTextArea(), false);
+    verifyGestureEndEventSinkOnAddHandler(new RichTextArea(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new RichTextArea(), false);
+
+    verifyGestureStartEventSinkOnAddHandler(new TextArea(), false);
+    verifyGestureEndEventSinkOnAddHandler(new TextArea(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new TextArea(), false);
+
+    verifyGestureStartEventSinkOnAddHandler(new PasswordTextBox(), false);
+    verifyGestureEndEventSinkOnAddHandler(new PasswordTextBox(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new PasswordTextBox(), false);
+
+    verifyGestureStartEventSinkOnAddHandler(new TextBox(), false);
+    verifyGestureEndEventSinkOnAddHandler(new TextBox(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new TextBox(), false);
+
+    verifyGestureStartEventSinkOnAddHandler(
+        new SimpleRadioButton("foo"), false);
+    verifyGestureEndEventSinkOnAddHandler(new SimpleRadioButton("foo"), false);
+    verifyGestureChangeEventSinkOnAddHandler(
+        new SimpleRadioButton("foo"), false);
+  }
+
+  public void testGestureEventBitFieldsNotTriviallyZero() {
+    assertNotSame(0, Event.ONGESTURESTART);
+    assertNotSame(0, Event.ONGESTURECHANGE);
+    assertNotSame(0, Event.ONGESTUREEND);
+  }
+
+  public void testImageGestureEventSinkByAddingHandler() {
+    /*
+     * The Image widget currently sinks events too early, before handlers are
+     * attached. We verify that (broken) behavior in this test. TODO(fredsa)
+     * Once Image has been fixed to lazily sink events, update this test and
+     * remove verifyEventSinkOnAddHandler's second parameter.
+     */
+    verifyGestureStartEventSinkOnAddHandler(new Image(), true);
+    verifyGestureEndEventSinkOnAddHandler(new Image(), true);
+    verifyGestureChangeEventSinkOnAddHandler(new Image(), true);
+  }
+
+  public void testLabelGestureEventSinkByAddingHandler() {
+    verifyGestureStartEventSinkOnAddHandler(new Label(), false);
+    verifyGestureEndEventSinkOnAddHandler(new Label(), false);
+    verifyGestureChangeEventSinkOnAddHandler(new Label(), false);
+  }
+
+  @Override
+  protected void gwtTearDown() throws Exception {
+    // clean up after ourselves
+    RootPanel.get().clear();
+    super.gwtTearDown();
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void assertNotSunkAfterAttach(W w, String eventName, boolean isSunk) {
+    assertFalse(
+        "Event should not be sunk on " + w.getClass().getName() + " until a "
+            + eventName + " handler has been added", isSunk);
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void assertSunkAfterAddHandler(W w, String eventName, boolean isSunk) {
+    assertTrue("Event should have been sunk on " + w.getClass().getName()
+        + " once the widget has been attached and a " + eventName
+        + " handler has been added", isSunk);
+  }
+
+  private <W extends Widget & HasAllGestureHandlers> void assertSunkAfterAttach(
+      W w, String eventName, boolean isSunk) {
+    assertTrue("Event should have been sunk on " + w.getClass().getName()
+        + " once the widget has been attached", isSunk);
+  }
+
+  private boolean isGestureChangeEventSunk(Element e) {
+    return (DOM.getEventsSunk(e) & Event.ONGESTURECHANGE) != 0;
+  }
+
+  private boolean isGestureEndEventSunk(Element e) {
+    return (DOM.getEventsSunk(e) & Event.ONGESTUREEND) != 0;
+  }
+
+  private boolean isGestureStartEventSunk(Element e) {
+    return (DOM.getEventsSunk(e) & Event.ONGESTURESTART) != 0;
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void verifyGestureChangeEventSinkOnAddHandler(
+          W w, boolean allowEarlySink) {
+    verifyGestureChangeEventSinkOnAddHandler(w, w.getElement(), allowEarlySink);
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void verifyGestureChangeEventSinkOnAddHandler(
+          W w, Element e, boolean widgetSinksEventsOnAttach) {
+    RootPanel.get().add(w);
+
+    if (widgetSinksEventsOnAttach) {
+      assertSunkAfterAttach(w, GestureChangeEvent.getType().getName(),
+          isGestureChangeEventSunk(e));
+    } else {
+      assertNotSunkAfterAttach(w, GestureChangeEvent.getType().getName(),
+          isGestureChangeEventSunk(e));
+    }
+
+    w.addGestureChangeHandler(new GestureChangeHandler() {
+      public void onGestureChange(GestureChangeEvent event) {
+      }
+    });
+
+    assertSunkAfterAddHandler(
+        w, GestureChangeEvent.getType().getName(), isGestureChangeEventSunk(e));
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void verifyGestureEndEventSinkOnAddHandler(W w, boolean allowEarlySink) {
+    verifyGestureEndEventSinkOnAddHandler(w, w.getElement(), allowEarlySink);
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void verifyGestureEndEventSinkOnAddHandler(
+          W w, Element e, boolean widgetSinksEventsOnAttach) {
+    RootPanel.get().add(w);
+
+    if (widgetSinksEventsOnAttach) {
+      assertSunkAfterAttach(
+          w, GestureEndEvent.getType().getName(), isGestureEndEventSunk(e));
+    } else {
+      assertNotSunkAfterAttach(
+          w, GestureEndEvent.getType().getName(), isGestureEndEventSunk(e));
+    }
+
+    w.addGestureEndHandler(new GestureEndHandler() {
+      public void onGestureEnd(GestureEndEvent event) {
+      }
+    });
+
+    assertSunkAfterAddHandler(
+        w, GestureEndEvent.getType().getName(), isGestureEndEventSunk(e));
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void verifyGestureStartEventSinkOnAddHandler(
+          W w, boolean allowEarlySink) {
+    verifyGestureStartEventSinkOnAddHandler(w, w.getElement(), allowEarlySink);
+  }
+
+  private <W extends Widget & HasAllGestureHandlers>
+      void verifyGestureStartEventSinkOnAddHandler(
+          W w, Element e, boolean widgetSinksEventsOnAttach) {
+    RootPanel.get().add(w);
+
+    if (widgetSinksEventsOnAttach) {
+      assertSunkAfterAttach(
+          w, GestureStartEvent.getType().getName(), isGestureStartEventSunk(e));
+    } else {
+      assertNotSunkAfterAttach(
+          w, GestureStartEvent.getType().getName(), isGestureStartEventSunk(e));
+    }
+
+    w.addGestureStartHandler(new GestureStartHandler() {
+      public void onGestureStart(GestureStartEvent event) {
+      }
+    });
+
+    assertSunkAfterAddHandler(
+        w, GestureStartEvent.getType().getName(), isGestureStartEventSunk(e));
+  }
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/user/client/TouchEventSinkTest.java b/user/test/com/google/gwt/user/client/TouchEventSinkTest.java
new file mode 100644
index 0000000..022a0f4
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/TouchEventSinkTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.user.client;
+
+import com.google.gwt.event.dom.client.HasAllTouchHandlers;
+import com.google.gwt.event.dom.client.TouchCancelEvent;
+import com.google.gwt.event.dom.client.TouchCancelHandler;
+import com.google.gwt.event.dom.client.TouchEndEvent;
+import com.google.gwt.event.dom.client.TouchEndHandler;
+import com.google.gwt.event.dom.client.TouchMoveEvent;
+import com.google.gwt.event.dom.client.TouchMoveHandler;
+import com.google.gwt.event.dom.client.TouchStartEvent;
+import com.google.gwt.event.dom.client.TouchStartHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.ui.Anchor;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.FocusPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.PasswordTextBox;
+import com.google.gwt.user.client.ui.RichTextArea;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.SimpleRadioButton;
+import com.google.gwt.user.client.ui.TextArea;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.ToggleButton;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Test Case for sinking of touch events.
+ */
+public class TouchEventSinkTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  public void testFocusPanelTouchEventSinkByAddingHandler() {
+    verifyTouchStartEventSinkOnAddHandler(new FocusPanel(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new FocusPanel(), false);
+    verifyTouchEndEventSinkOnAddHandler(new FocusPanel(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new FocusPanel(), false);
+  }
+
+  public void testFocusWidgetTouchEventSinkByAddingHandler() {
+    verifyTouchStartEventSinkOnAddHandler(new Anchor(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new Anchor(), false);
+    verifyTouchEndEventSinkOnAddHandler(new Anchor(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new Anchor(), false);
+
+    verifyTouchStartEventSinkOnAddHandler(new Button(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new Button(), false);
+    verifyTouchEndEventSinkOnAddHandler(new Button(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new Button(), false);
+
+    CheckBox checkBox1 = new CheckBox();
+    // Get the inputElem on which events are sunk
+    Element e1 = (Element) checkBox1.getElement().getFirstChildElement();
+    verifyTouchStartEventSinkOnAddHandler(checkBox1, e1, false);
+
+    CheckBox checkBox2 = new CheckBox();
+    // Get the inputElem on which events are sunk
+    Element e2 = (Element) checkBox2.getElement().getFirstChildElement();
+    verifyTouchMoveEventSinkOnAddHandler(checkBox2, e2, false);
+
+    CheckBox checkBox3 = new CheckBox();
+    // Get the inputElem on which events are sunk
+    Element e3 = (Element) checkBox3.getElement().getFirstChildElement();
+    verifyTouchEndEventSinkOnAddHandler(checkBox3, e3, false);
+
+    CheckBox checkBox4 = new CheckBox();
+    // Get the inputElem on which events are sunk
+    Element e4 = (Element) checkBox4.getElement().getFirstChildElement();
+    verifyTouchCancelEventSinkOnAddHandler(checkBox4, e4, false);
+
+    verifyTouchStartEventSinkOnAddHandler(new ToggleButton(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new ToggleButton(), false);
+    verifyTouchEndEventSinkOnAddHandler(new ToggleButton(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new ToggleButton(), false);
+
+    verifyTouchStartEventSinkOnAddHandler(new ListBox(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new ListBox(), false);
+    verifyTouchEndEventSinkOnAddHandler(new ListBox(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new ListBox(), false);
+
+    verifyTouchStartEventSinkOnAddHandler(new RichTextArea(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new RichTextArea(), false);
+    verifyTouchEndEventSinkOnAddHandler(new RichTextArea(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new RichTextArea(), false);
+
+    verifyTouchStartEventSinkOnAddHandler(new TextArea(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new TextArea(), false);
+    verifyTouchEndEventSinkOnAddHandler(new TextArea(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new TextArea(), false);
+
+    verifyTouchStartEventSinkOnAddHandler(new PasswordTextBox(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new PasswordTextBox(), false);
+    verifyTouchEndEventSinkOnAddHandler(new PasswordTextBox(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new PasswordTextBox(), false);
+
+    verifyTouchStartEventSinkOnAddHandler(new TextBox(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new TextBox(), false);
+    verifyTouchEndEventSinkOnAddHandler(new TextBox(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new TextBox(), false);
+
+    verifyTouchStartEventSinkOnAddHandler(new SimpleRadioButton("foo"), false);
+    verifyTouchMoveEventSinkOnAddHandler(new SimpleRadioButton("foo"), false);
+    verifyTouchEndEventSinkOnAddHandler(new SimpleRadioButton("foo"), false);
+    verifyTouchCancelEventSinkOnAddHandler(new SimpleRadioButton("foo"), false);
+  }
+
+  public void testImageTouchEventSinkByAddingHandler() {
+    /*
+     * The Image widget currently sinks events too early, before handlers are
+     * attached. We verify that (broken) behavior in this test. TODO(fredsa)
+     * Once Image has been fixed to lazily sink events, update this test and
+     * remove verifyEventSinkOnAddHandler's second parameter.
+     */
+    verifyTouchStartEventSinkOnAddHandler(new Image(), true);
+    verifyTouchMoveEventSinkOnAddHandler(new Image(), true);
+    verifyTouchEndEventSinkOnAddHandler(new Image(), true);
+    verifyTouchCancelEventSinkOnAddHandler(new Image(), true);
+  }
+
+  public void testLabelTouchEventSinkByAddingHandler() {
+    verifyTouchStartEventSinkOnAddHandler(new Label(), false);
+    verifyTouchMoveEventSinkOnAddHandler(new Label(), false);
+    verifyTouchEndEventSinkOnAddHandler(new Label(), false);
+    verifyTouchCancelEventSinkOnAddHandler(new Label(), false);
+  }
+
+  public void testTouchEventBitFieldsNotTriviallyZero() {
+    assertNotSame(0, Event.ONTOUCHSTART);
+    assertNotSame(0, Event.ONTOUCHMOVE);
+    assertNotSame(0, Event.ONTOUCHEND);
+    assertNotSame(0, Event.ONTOUCHCANCEL);
+  }
+
+  @Override
+  protected void gwtTearDown() throws Exception {
+    // clean up after ourselves
+    RootPanel.get().clear();
+    super.gwtTearDown();
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void assertNotSunkAfterAttach(W w, String eventName, boolean isSunk) {
+    assertFalse(
+        "Event should not be sunk on " + w.getClass().getName() + " until a "
+            + eventName + " handler has been added", isSunk);
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void assertSunkAfterAddHandler(W w, String eventName, boolean isSunk) {
+    assertTrue("Event should have been sunk on " + w.getClass().getName()
+        + " once the widget has been attached and a " + eventName
+        + " handler has been added", isSunk);
+  }
+
+  private <W extends Widget & HasAllTouchHandlers> void assertSunkAfterAttach(
+      W w, String eventName, boolean isSunk) {
+    assertTrue("Event should have been sunk on " + w.getClass().getName()
+        + " once the widget has been attached", isSunk);
+  }
+
+  private boolean isTouchCancelEventSunk(Element e) {
+    return (DOM.getEventsSunk(e) & Event.ONTOUCHCANCEL) != 0;
+  }
+
+  private boolean isTouchEndEventSunk(Element e) {
+    return (DOM.getEventsSunk(e) & Event.ONTOUCHEND) != 0;
+  }
+
+  private boolean isTouchMoveEventSunk(Element e) {
+    return (DOM.getEventsSunk(e) & Event.ONTOUCHMOVE) != 0;
+  }
+
+  private boolean isTouchStartEventSunk(Element e) {
+    return (DOM.getEventsSunk(e) & Event.ONTOUCHSTART) != 0;
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchCancelEventSinkOnAddHandler(W w, boolean allowEarlySink) {
+    verifyTouchCancelEventSinkOnAddHandler(w, w.getElement(), allowEarlySink);
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchCancelEventSinkOnAddHandler(
+          W w, Element e, boolean widgetSinksEventsOnAttach) {
+    RootPanel.get().add(w);
+
+    if (widgetSinksEventsOnAttach) {
+      assertSunkAfterAttach(
+          w, TouchCancelEvent.getType().getName(), isTouchCancelEventSunk(e));
+    } else {
+      assertNotSunkAfterAttach(
+          w, TouchCancelEvent.getType().getName(), isTouchCancelEventSunk(e));
+    }
+
+    w.addTouchCancelHandler(new TouchCancelHandler() {
+      public void onTouchCancel(TouchCancelEvent event) {
+      }
+    });
+
+    assertSunkAfterAddHandler(
+        w, TouchCancelEvent.getType().getName(), isTouchCancelEventSunk(e));
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchEndEventSinkOnAddHandler(W w, boolean allowEarlySink) {
+    verifyTouchEndEventSinkOnAddHandler(w, w.getElement(), allowEarlySink);
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchEndEventSinkOnAddHandler(
+          W w, Element e, boolean widgetSinksEventsOnAttach) {
+    RootPanel.get().add(w);
+
+    if (widgetSinksEventsOnAttach) {
+      assertSunkAfterAttach(
+          w, TouchEndEvent.getType().getName(), isTouchEndEventSunk(e));
+    } else {
+      assertNotSunkAfterAttach(
+          w, TouchEndEvent.getType().getName(), isTouchEndEventSunk(e));
+    }
+
+    w.addTouchEndHandler(new TouchEndHandler() {
+      public void onTouchEnd(TouchEndEvent event) {
+      }
+    });
+
+    assertSunkAfterAddHandler(
+        w, TouchEndEvent.getType().getName(), isTouchEndEventSunk(e));
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchMoveEventSinkOnAddHandler(W w, boolean allowEarlySink) {
+    verifyTouchMoveEventSinkOnAddHandler(w, w.getElement(), allowEarlySink);
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchMoveEventSinkOnAddHandler(
+          W w, Element e, boolean widgetSinksEventsOnAttach) {
+    RootPanel.get().add(w);
+
+    if (widgetSinksEventsOnAttach) {
+      assertSunkAfterAttach(
+          w, TouchMoveEvent.getType().getName(), isTouchMoveEventSunk(e));
+    } else {
+      assertNotSunkAfterAttach(
+          w, TouchMoveEvent.getType().getName(), isTouchMoveEventSunk(e));
+    }
+
+    w.addTouchMoveHandler(new TouchMoveHandler() {
+
+      public void onTouchMove(TouchMoveEvent event) {
+      }
+    });
+
+    assertSunkAfterAddHandler(
+        w, TouchMoveEvent.getType().getName(), isTouchMoveEventSunk(e));
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchStartEventSinkOnAddHandler(W w, boolean allowEarlySink) {
+    verifyTouchStartEventSinkOnAddHandler(w, w.getElement(), allowEarlySink);
+  }
+
+  private <W extends Widget & HasAllTouchHandlers>
+      void verifyTouchStartEventSinkOnAddHandler(
+          W w, Element e, boolean widgetSinksEventsOnAttach) {
+    RootPanel.get().add(w);
+
+    if (widgetSinksEventsOnAttach) {
+      assertSunkAfterAttach(
+          w, TouchStartEvent.getType().getName(), isTouchStartEventSunk(e));
+    } else {
+      assertNotSunkAfterAttach(
+          w, TouchStartEvent.getType().getName(), isTouchStartEventSunk(e));
+    }
+
+    w.addTouchStartHandler(new TouchStartHandler() {
+      public void onTouchStart(TouchStartEvent event) {
+      }
+    });
+
+    assertSunkAfterAddHandler(
+        w, TouchStartEvent.getType().getName(), isTouchStartEventSunk(e));
+  }
+}