summaryrefslogtreecommitdiffstats
path: root/WebCore/page
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page')
-rw-r--r--WebCore/page/ChromeClient.h4
-rw-r--r--WebCore/page/DOMWindow.h5
-rw-r--r--WebCore/page/DOMWindow.idl19
-rw-r--r--WebCore/page/EventHandler.cpp333
-rw-r--r--WebCore/page/EventHandler.h33
5 files changed, 247 insertions, 147 deletions
diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h
index 117953c..b28473b 100644
--- a/WebCore/page/ChromeClient.h
+++ b/WebCore/page/ChromeClient.h
@@ -225,6 +225,10 @@ namespace WebCore {
virtual void willPopUpMenu(NSMenu *) { }
#endif
+#if ENABLE(TOUCH_EVENTS)
+ virtual void needTouchEvents(bool, bool force = false) = 0;
+#endif
+
protected:
virtual ~ChromeClient() { }
};
diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h
index 5e2d990..0aee619 100644
--- a/WebCore/page/DOMWindow.h
+++ b/WebCore/page/DOMWindow.h
@@ -322,13 +322,12 @@ namespace WebCore {
DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationend, webkitAnimationEnd);
DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkittransitionend, webkitTransitionEnd);
-#if ENABLE(TOUCH_EVENTS) // Android
+#if ENABLE(TOUCH_EVENTS)
DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend);
DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend);
DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel);
#endif
-
void captureEvents();
void releaseEvents();
diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl
index c4b08c6..cfc9401 100644
--- a/WebCore/page/DOMWindow.idl
+++ b/WebCore/page/DOMWindow.idl
@@ -206,12 +206,6 @@ module window {
raises(DOMException);
// Events
-#if ENABLE_TOUCH_EVENTS
- attribute EventListener ontouchstart;
- attribute EventListener ontouchend;
- attribute EventListener ontouchmove;
- attribute EventListener ontouchcancel;
-#endif
attribute EventListener onabort;
attribute EventListener onbeforeunload;
@@ -296,6 +290,12 @@ module window {
#if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS
attribute EventListener onorientationchange;
#endif
+#if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS
+ attribute [DontEnum] EventListener ontouchstart;
+ attribute [DontEnum] EventListener ontouchmove;
+ attribute [DontEnum] EventListener ontouchend;
+ attribute [DontEnum] EventListener ontouchcancel;
+#endif
// EventTarget interface
[Custom] void addEventListener(in DOMString type,
@@ -466,9 +466,6 @@ module window {
attribute WheelEventConstructor WheelEvent;
attribute MessageEventConstructor MessageEvent;
attribute EventExceptionConstructor EventException;
-#if ENABLE_TOUCH_EVENTS
- attribute TouchEventConstructor TouchEvent;
-#endif
attribute WebKitCSSKeyframeRuleConstructor WebKitCSSKeyframeRule;
attribute WebKitCSSKeyframesRuleConstructor WebKitCSSKeyframesRule;
@@ -576,6 +573,10 @@ module window {
#endif
#endif
+#if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS
+ attribute TouchEventConstructor TouchEvent;
+#endif
+
#endif // defined(LANGUAGE_JAVASCRIPT)
#if defined(V8_BINDING) && V8_BINDING
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
index 8b6b602..a7dc13a 100644
--- a/WebCore/page/EventHandler.cpp
+++ b/WebCore/page/EventHandler.cpp
@@ -56,6 +56,7 @@
#include "Page.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformWheelEvent.h"
+#include "PluginView.h"
#include "RenderFrameSet.h"
#include "RenderTextControlSingleLine.h"
#include "RenderView.h"
@@ -74,9 +75,9 @@
#include "SVGUseElement.h"
#endif
-#if ENABLE(TOUCH_EVENTS) // Android
-#include "TouchEvent.h"
+#if ENABLE(TOUCH_EVENTS)
#include "PlatformTouchEvent.h"
+#include "TouchEvent.h"
#endif
#if defined(ANDROID_PLUGINS)
@@ -207,8 +208,16 @@ void EventHandler::clear()
m_lastScrollbarUnderMouse = 0;
m_clickCount = 0;
m_clickNode = 0;
-#if ENABLE(TOUCH_EVENTS) // Android
- m_touch = 0;
+#if ENABLE(TOUCH_EVENTS)
+ m_touchEventTarget = 0;
+ if (Document* doc = m_frame->document()) {
+ if (Page* page = doc->page()) {
+ // We are clearing event handlers, which includes any touch
+ // event handlers so force webkit to tell the chrome client to
+ // stop forwarding the events.
+ page->chrome()->client()->needTouchEvents(false, true);
+ }
+ }
#endif
m_frameSetBeingResized = 0;
#if ENABLE(DRAG_SUPPORT)
@@ -2546,141 +2555,221 @@ bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults&
return scrollbar->mouseDown(mev.event());
}
-#if ENABLE(TOUCH_EVENTS) // Android
-int EventHandler::handleTouchEvent(const PlatformTouchEvent& e)
+// If scrollbar (under mouse) is different from last, send a mouse exited. Set
+// last to scrollbar if setLast is true; else set last to 0.
+void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
{
- // only handle the touch event in the top frame handler
- if (m_frame->tree()->parent(true))
- return m_frame->tree()->parent()->eventHandler()->handleTouchEvent(e);
-
- Document* doc = m_frame->document();
- if (!doc)
- return 0;
-
- RenderObject* docRenderer = doc->renderer();
- if (!docRenderer)
- return 0;
-
- if (doc->touchEventListeners().size() == 0)
- return 0;
+ if (m_lastScrollbarUnderMouse != scrollbar) {
+ // Send mouse exited to the old scrollbar.
+ if (m_lastScrollbarUnderMouse)
+ m_lastScrollbarUnderMouse->mouseExited();
+ m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
+ }
+}
- TouchEventType type = e.eventType();
- if (type == TouchEventStart || type == TouchEventLongPress || type == TouchEventDoubleTap) {
- Frame* frame = m_frame;
- IntPoint vPoint = frame->view()->windowToContents(e.pos());
- HitTestRequest request(HitTestRequest::ReadOnly);
- HitTestResult result(vPoint);
- frame->contentRenderer()->layer()->hitTest(request, result);
- Node* node = result.innerNode();
- if (node) {
- RenderObject* target = node->renderer();
- while (target && target->isWidget()) {
- Widget* widget = static_cast<RenderWidget*>(target)->widget();
- if (widget->isFrameView()) {
- frame = static_cast<FrameView*>(widget)->frame();
- vPoint = frame->view()->windowToContents(e.pos());
- HitTestResult ret(vPoint);
- frame->contentRenderer()->layer()->hitTest(request, ret);
- node = ret.innerNode();
- if (!node)
- break;
- else
- target = node->renderer();
- } else
- // plugin view??
- break;
- }
+#if ENABLE(TOUCH_EVENTS)
+#if PLATFORM(ANDROID)
+// TODO(benm): On Android we return an int back to Java to signify whether the default actions
+// for longpress/doubletap in the Browser should be prevented. I think that before upstreaming
+// to webkit.org we can refactor the Java side to not require this.
+int EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
+#else
+bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
+#endif
+{
+ RefPtr<TouchList> touches = TouchList::create();
+ RefPtr<TouchList> pressedTouches = TouchList::create();
+ RefPtr<TouchList> releasedTouches = TouchList::create();
+ RefPtr<TouchList> movedTouches = TouchList::create();
+ RefPtr<TouchList> targetTouches = TouchList::create();
+ RefPtr<TouchList> cancelTouches = TouchList::create();
+
+ const Vector<PlatformTouchPoint>& points = event.touchPoints();
+ AtomicString* eventName = 0;
+
+ for (int i = 0; i < points.size(); ++i) {
+ const PlatformTouchPoint& point = points[i];
+ IntPoint framePoint = documentPointForWindowPoint(m_frame, point.pos());
+ HitTestResult result = hitTestResultAtPoint(framePoint, /*allowShadowContent*/ false);
+ Node* target = result.innerNode();
+
+ // Touch events should not go to text nodes
+ if (target && target->isTextNode())
+ target = target->parentNode();
+
+ Document* doc = target->document();
+ if (!doc)
+ continue;
+ if (!doc->hasListenerType(Document::TOUCH_LISTENER))
+ continue;
+
+ int adjustedPageX = lroundf(framePoint.x() / m_frame->pageZoomFactor());
+ int adjustedPageY = lroundf(framePoint.y() / m_frame->pageZoomFactor());
+
+ if ( (event.type() == TouchStart
+#if PLATFORM(ANDROID)
+ || event.type() == TouchDoubleTap
+ || event.type() == TouchLongPress
+#endif
+ ) && !i) {
+ m_touchEventTarget = target;
+ m_firstTouchScreenPos = point.screenPos();
+ m_firstTouchPagePos = framePoint;
}
- if (!node) {
- // reset to the top document node
- node = doc;
- frame = m_frame;
- vPoint = frame->view()->windowToContents(e.pos());
- }
+ RefPtr<Touch> touch = Touch::create(m_frame, m_touchEventTarget.get(), point.id(),
+ point.screenPos().x(), point.screenPos().y(),
+ adjustedPageX, adjustedPageY);
- m_touch = Touch::create(frame, node, 0,
- e.x(), e.y(), vPoint.x(), vPoint.y());
- } else if (m_touch) {
- if ((type == TouchEventMove) && (e.x() == m_touch->screenX()) &&
- (e.y() == m_touch->screenY())) {
- // don't trigger the event if it hasn't really moved
- return 0;
+ if (point.state() == PlatformTouchPoint::TouchReleased)
+ releasedTouches->append(touch);
+ else if (point.state() == PlatformTouchPoint::TouchCancelled)
+ cancelTouches->append(touch);
+ else {
+ if (point.state() == PlatformTouchPoint::TouchPressed)
+ pressedTouches->append(touch);
+ else {
+ touches->append(touch);
+ if (m_touchEventTarget == target)
+ targetTouches->append(touch);
+ if (point.state() == PlatformTouchPoint::TouchMoved)
+ movedTouches->append(touch);
+ }
}
+ }
- IntPoint vPoint = m_touch->frame()->view()->windowToContents(e.pos());
- m_touch->updateLocation(e.x(), e.y(), vPoint.x(), vPoint.y());
- } else {
+ if (!m_touchEventTarget)
+#if PLATFORM(ANDROID)
return 0;
- }
+#else
+ return false;
+#endif
- RefPtr<TouchList> touchList = TouchList::create();
- touchList->append(m_touch);
- // For TouchEventEnd, touches and targetTouches are empty list
- RefPtr<TouchList> emptyList = TouchList::create();
- RefPtr<TouchEvent> te;
- switch(type) {
- case TouchEventStart:
- te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
- eventNames().touchstartEvent, m_touch->frame()->document()->defaultView(),
- m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
- break;
+ bool defaultPrevented = false;
+#if PLATFORM(ANDROID)
+ // TODO (benm): We should be able to remove this prior to upstreaming once Java side refactorings to make
+ // preventDeault work better are complete.
+ bool longPressPrevented = false;
+ bool doubleTapPrevented = false;
+#endif
- case TouchEventEnd:
- te = TouchEvent::create(emptyList.get(), emptyList.get(), touchList.get(),
- eventNames().touchendEvent, m_touch->frame()->document()->defaultView(),
- m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
- break;
+ if (event.type() == TouchCancel) {
+ eventName = &eventNames().touchcancelEvent;
+ RefPtr<TouchEvent> cancelEv =
+ TouchEvent::create(TouchList::create().get(), TouchList::create().get(), cancelTouches.get(),
+ *eventName, m_touchEventTarget->document()->defaultView(),
+ m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(),
+ m_firstTouchPagePos.x(), m_firstTouchPagePos.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+
+ ExceptionCode ec = 0;
+ m_touchEventTarget->dispatchEvent(cancelEv.get(), ec);
+ defaultPrevented |= cancelEv->defaultPrevented();
+ }
+
+ if (releasedTouches->length() > 0) {
+ eventName = &eventNames().touchendEvent;
+
+ RefPtr<TouchEvent> endEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), releasedTouches.get(),
+ *eventName, m_touchEventTarget->document()->defaultView(),
+ m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(),
+ m_firstTouchPagePos.x(), m_firstTouchPagePos.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+
+ ExceptionCode ec = 0;
+ m_touchEventTarget->dispatchEvent(endEv.get(), ec);
+ defaultPrevented |= endEv->defaultPrevented();
+ }
+
+ if (pressedTouches->length() > 0) {
+ // Add pressed touchpoints to touches and targetTouches.
+ for (int i = 0; i < pressedTouches->length(); ++i) {
+ touches->append(pressedTouches->item(i));
+ if (m_touchEventTarget == pressedTouches->item(i)->target())
+ targetTouches->append(pressedTouches->item(i));
+ }
- case TouchEventMove:
- te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
- eventNames().touchmoveEvent, m_touch->frame()->document()->defaultView(),
- m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
- break;
+#if PLATFORM(ANDROID)
+ if (event.type() == TouchLongPress) {
+ eventName = &eventNames().touchlongpressEvent;
+ RefPtr<TouchEvent> longpressEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(),
+ *eventName, m_touchEventTarget->document()->defaultView(),
+ m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(),
+ m_firstTouchPagePos.x(), m_firstTouchPagePos.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+
+ ExceptionCode ec = 0;
+ m_touchEventTarget->dispatchEvent(longpressEv.get(), ec);
+ defaultPrevented |= longpressEv->defaultPrevented();
+ } else if (event.type() == TouchDoubleTap) {
+ eventName = &eventNames().touchdoubletapEvent;
+ RefPtr<TouchEvent> doubleTapEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(),
+ *eventName, m_touchEventTarget->document()->defaultView(),
+ m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(),
+ m_firstTouchPagePos.x(), m_firstTouchPagePos.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+
+ ExceptionCode ec = 0;
+ m_touchEventTarget->dispatchEvent(doubleTapEv.get(), ec);
+ defaultPrevented |= doubleTapEv->defaultPrevented();
+ } else {
+#endif
+ eventName = &eventNames().touchstartEvent;
+ RefPtr<TouchEvent> startEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(),
+ *eventName, m_touchEventTarget->document()->defaultView(),
+ m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(),
+ m_firstTouchPagePos.x(), m_firstTouchPagePos.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ m_touchEventTarget->dispatchEvent(startEv.get(), ec);
+ defaultPrevented |= startEv->defaultPrevented();
+#if PLATFORM(ANDROID)
+ longPressPrevented |= startEv->longPressPrevented();
+ doubleTapPrevented |= startEv->doubleTapPrevented();
+ }
+#endif
+ }
- case TouchEventCancel:
- te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
- eventNames().touchcancelEvent, m_touch->frame()->document()->defaultView(),
- m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
- break;
+ if (movedTouches->length() > 0) {
+ eventName = &eventNames().touchmoveEvent;
+ RefPtr<TouchEvent> moveEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), movedTouches.get(),
+ *eventName, m_touchEventTarget->document()->defaultView(),
+ m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(),
+ m_firstTouchPagePos.x(), m_firstTouchPagePos.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ m_touchEventTarget->dispatchEvent(moveEv.get(), ec);
+ defaultPrevented |= moveEv->defaultPrevented();
+ }
- case TouchEventLongPress:
- te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
- eventNames().touchlongpressEvent, m_touch->frame()->document()->defaultView(),
- m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
- break;
- case TouchEventDoubleTap:
- te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
- eventNames().touchdoubletapEvent, m_touch->frame()->document()->defaultView(),
- m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
- break;
+ if (event.type() == TouchEnd || event.type() == TouchCancel)
+ m_touchEventTarget = 0;
- default:
- return false;
- }
- ExceptionCode ec = 0;
- m_touch->target()->dispatchEvent(te.get(), ec);
- if (type == TouchEventEnd || type == TouchEventCancel)
- m_touch = 0;
- if (type == TouchEventLongPress || type == TouchEventDoubleTap)
+#if PLATFORM(ANDROID)
+ // TODO (benm): We should be able to remove this prior to upstreaming once Java side refactorings to make
+ // preventDefault work better are complete.
+ if (event.type() == TouchLongPress || event.type() == TouchDoubleTap)
return 0;
- return (te->defaultPrevented() ? preventTouch : 0)
- | (te->longPressPrevented() ? preventLongPress : 0)
- | (te->doubleTapPrevented() ? preventDoubleTap : 0);
-}
-#endif
-// If scrollbar (under mouse) is different from last, send a mouse exited. Set
-// last to scrollbar if setLast is true; else set last to 0.
-void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
-{
- if (m_lastScrollbarUnderMouse != scrollbar) {
- // Send mouse exited to the old scrollbar.
- if (m_lastScrollbarUnderMouse)
- m_lastScrollbarUnderMouse->mouseExited();
- m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
- }
+ return (defaultPrevented ? preventTouch : 0)
+ | (longPressPrevented ? preventLongPress : 0)
+ | (doubleTapPrevented ? preventDoubleTap : 0);
+#else
+ return defaultPrevented;
+#endif
}
+#endif
}
diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h
index 0da44f2..8ccd761 100644
--- a/WebCore/page/EventHandler.h
+++ b/WebCore/page/EventHandler.h
@@ -52,6 +52,7 @@ class KeyboardEvent;
class MouseEventWithHitTestResults;
class Node;
class PlatformKeyboardEvent;
+class PlatformTouchEvent;
class PlatformWheelEvent;
class RenderLayer;
class RenderObject;
@@ -60,11 +61,8 @@ class Scrollbar;
class String;
class SVGElementInstance;
class TextEvent;
+class TouchEvent;
class Widget;
-#if ENABLE(TOUCH_EVENTS) // Android
-class PlatformTouchEvent;
-class Touch;
-#endif
#if ENABLE(DRAG_SUPPORT)
extern const int LinkDragHysteresis;
@@ -75,13 +73,16 @@ extern const int GeneralDragHysteresis;
enum HitTestScrollbars { ShouldHitTestScrollbars, DontHitTestScrollbars };
-#if ENABLE(TOUCH_EVENTS) // Android
+#if PLATFORM(ANDROID)
+// TODO (benm): I think with some Java refactoring we can remove this before upstreaming to webkit.org.
+#if ENABLE(TOUCH_EVENTS)
enum TouchResultMask {
preventTouch = 1 << 0,
preventLongPress = 1 << 1,
preventDoubleTap = 1 << 2,
};
#endif
+#endif
class EventHandler : public Noncopyable {
public:
@@ -151,11 +152,6 @@ public:
bool handleMouseReleaseEvent(const PlatformMouseEvent&);
bool handleWheelEvent(PlatformWheelEvent&);
-#if ENABLE(TOUCH_EVENTS) // Android
- // See TouchResultMask for the return value options
- int handleTouchEvent(const PlatformTouchEvent&);
-#endif
-
#if ENABLE(CONTEXT_MENUS)
bool sendContextMenuEvent(const PlatformMouseEvent&);
#endif
@@ -208,6 +204,14 @@ public:
static NSEvent *currentNSEvent();
#endif
+#if ENABLE(TOUCH_EVENTS)
+#if PLATFORM(ANDROID)
+ int handleTouchEvent(const PlatformTouchEvent&);
+#else
+ bool handleTouchEvent(const PlatformTouchEvent&);
+#endif
+#endif
+
private:
#if ENABLE(DRAG_SUPPORT)
enum DragAndDropHandleType {
@@ -389,9 +393,6 @@ private:
int m_clickCount;
RefPtr<Node> m_clickNode;
-#if ENABLE(TOUCH_EVENTS) // Android
- RefPtr<Touch> m_touch;
-#endif
#if ENABLE(DRAG_SUPPORT)
RefPtr<Node> m_dragTarget;
@@ -418,6 +419,12 @@ private:
bool m_sendingEventToSubview;
int m_activationEventNumber;
#endif
+#if ENABLE(TOUCH_EVENTS)
+ RefPtr<Node> m_touchEventTarget;
+ IntPoint m_firstTouchScreenPos;
+ IntPoint m_firstTouchPagePos;
+#endif
+
};
} // namespace WebCore