diff options
Diffstat (limited to 'WebCore/page')
-rw-r--r-- | WebCore/page/ChromeClient.h | 4 | ||||
-rw-r--r-- | WebCore/page/DOMWindow.h | 5 | ||||
-rw-r--r-- | WebCore/page/DOMWindow.idl | 19 | ||||
-rw-r--r-- | WebCore/page/EventHandler.cpp | 333 | ||||
-rw-r--r-- | WebCore/page/EventHandler.h | 33 |
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 |