diff options
author | Ben Murdoch <benm@google.com> | 2010-01-07 16:20:05 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-01-20 10:33:01 +0000 |
commit | f5306da72ab6bb63f7ae07371e687f72a75c2fb2 (patch) | |
tree | 34c3ada7bea43cd10fd036aad91a9bf2e7dbdc2d | |
parent | efd3d8ad1e5b1af7b31f8a9569df0b8568cdb52b (diff) | |
download | external_webkit-f5306da72ab6bb63f7ae07371e687f72a75c2fb2.zip external_webkit-f5306da72ab6bb63f7ae07371e687f72a75c2fb2.tar.gz external_webkit-f5306da72ab6bb63f7ae07371e687f72a75c2fb2.tar.bz2 |
Refactor our touch event code to use the version submitted to webkit.org by the Qt team.
Change-Id: I2953472cee68aadf18f9dd740e9b3f69ad729cf0
37 files changed, 778 insertions, 457 deletions
diff --git a/WebCore/Android.mk b/WebCore/Android.mk index 19e3fd2..7c3781a 100644 --- a/WebCore/Android.mk +++ b/WebCore/Android.mk @@ -402,6 +402,8 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/android/GeolocationServiceBridge.cpp \ platform/android/KeyEventAndroid.cpp \ platform/android/LocalizedStringsAndroid.cpp \ + platform/android/PlatformTouchEventAndroid.cpp \ + platform/android/PlatformTouchPointAndroid.cpp \ platform/android/PopupMenuAndroid.cpp \ platform/android/RenderThemeAndroid.cpp \ platform/android/ScreenAndroid.cpp \ diff --git a/WebCore/bindings/js/JSEventCustom.cpp b/WebCore/bindings/js/JSEventCustom.cpp index 7b951bd..04ceec5 100644 --- a/WebCore/bindings/js/JSEventCustom.cpp +++ b/WebCore/bindings/js/JSEventCustom.cpp @@ -78,7 +78,7 @@ #include "SVGZoomEvent.h" #endif -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) #include "JSTouchEvent.h" #include "TouchEvent.h" #endif @@ -118,7 +118,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Event* event) #endif else if (event->isCompositionEvent()) wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, CompositionEvent, event); -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) else if (event->isTouchEvent()) wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, TouchEvent, event); #endif diff --git a/WebCore/bindings/js/ScriptController.cpp b/WebCore/bindings/js/ScriptController.cpp index 89f2345..8d34f88 100644 --- a/WebCore/bindings/js/ScriptController.cpp +++ b/WebCore/bindings/js/ScriptController.cpp @@ -247,7 +247,7 @@ bool ScriptController::processingUserGestureEvent() const // keyboard events || type == eventNames().keydownEvent || type == eventNames().keypressEvent || type == eventNames().keyupEvent -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) // touch events || type == eventNames().touchstartEvent || type == eventNames().touchmoveEvent || type == eventNames().touchendEvent || type == eventNames().touchcancelEvent diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp index 69b326a..d031853 100644 --- a/WebCore/dom/Document.cpp +++ b/WebCore/dom/Document.cpp @@ -171,12 +171,10 @@ #include "SVGStyleElement.h" #endif -#if ENABLE(TOUCH_EVENTS) // Android -#include "TouchEvent.h" #if PLATFORM(ANDROID) +// FIXME: We shouldn't be including this from WebCore! #include "WebViewCore.h" #endif -#endif #ifdef ANDROID_META_SUPPORT #include "Settings.h" @@ -191,6 +189,11 @@ #include "TimeCounter.h" #endif +#if ENABLE(TOUCH_EVENTS) +#include "ChromeClient.h" +#include "TouchEvent.h" +#endif + #if ENABLE(WML) #include "WMLDocument.h" #include "WMLElement.h" @@ -1484,17 +1487,6 @@ void Document::detach() FrameView* view = m_frame->view(); if (view) view->detachCustomScrollbars(); - -#if ENABLE(TOUCH_EVENTS) // Android - // clean up for the top document - if (!m_frame->ownerElement()) { - m_touchEventListeners.clear(); -#if PLATFORM(ANDROID) - if (view) - android::WebViewCore::getWebViewCore(view)->needTouchEvents(false); -#endif - } -#endif } // indicate destruction mode, i.e. attached() but renderer == 0 @@ -3062,7 +3054,7 @@ PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& else if (eventType == "SVGZoomEvents") event = SVGZoomEvent::create(); #endif -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) else if (eventType == "TouchEvent") event = TouchEvent::create(); #endif @@ -3102,6 +3094,14 @@ void Document::addListenerTypeIfNeeded(const AtomicString& eventType) addListenerType(TRANSITIONEND_LISTENER); else if (eventType == eventNames().beforeloadEvent) addListenerType(BEFORELOAD_LISTENER); + else if (eventType == eventNames().touchstartEvent + || eventType == eventNames().touchmoveEvent + || eventType == eventNames().touchendEvent + || eventType == eventNames().touchcancelEvent) { + addListenerType(TOUCH_LISTENER); + if (Page* page = this->page()) + page->chrome()->client()->needTouchEvents(true); + } } CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&) @@ -4673,38 +4673,6 @@ void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl) m_haveExplicitlyDisabledDNSPrefetch = true; } -#if ENABLE(TOUCH_EVENTS) // Android -void Document::addTouchEventListener(Node* node) -{ - // Note: we only keep track of touch listener in the top frame - if (m_frame && m_frame->tree()->parent()) { - m_frame->page()->mainFrame()->document()->addTouchEventListener(node); - } else { -#if PLATFORM(ANDROID) - if (m_frame && m_frame->view() && m_touchEventListeners.isEmpty()) - android::WebViewCore::getWebViewCore(m_frame->view())->needTouchEvents(true); -#endif - m_touchEventListeners.add(node, 0); - } -} - -void Document::removeTouchEventListener(Node* node) -{ - // Note: we only keep track of touch listener in the top frame - if (m_frame && m_frame->tree()->parent()) { - m_frame->page()->mainFrame()->document()->removeTouchEventListener(node); - } else { -#if PLATFORM(ANDROID) - if (m_frame && m_frame->view() && m_touchEventListeners.size() == 1 && - m_touchEventListeners.contains(node)) - android::WebViewCore::getWebViewCore(m_frame->view())->needTouchEvents(false); -#endif - m_touchEventListeners.remove(node); - } -} - -#endif - void Document::reportException(const String& errorMessage, int lineNumber, const String& sourceURL) { if (DOMWindow* window = domWindow()) diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h index f2125b1..b24063a 100644 --- a/WebCore/dom/Document.h +++ b/WebCore/dom/Document.h @@ -252,6 +252,12 @@ public: DEFINE_ATTRIBUTE_EVENT_LISTENER(reset); DEFINE_ATTRIBUTE_EVENT_LISTENER(search); DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart); +#if ENABLE(TOUCH_EVENTS) + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel); +#endif DocumentType* doctype() const { return m_docType.get(); } @@ -624,7 +630,8 @@ public: ANIMATIONSTART_LISTENER = 0x200, ANIMATIONITERATION_LISTENER = 0x400, TRANSITIONEND_LISTENER = 0x800, - BEFORELOAD_LISTENER = 0x1000 + BEFORELOAD_LISTENER = 0x1000, + TOUCH_LISTENER = 0x2000 }; bool hasListenerType(ListenerType listenerType) const { return (m_listenerTypes & listenerType); } @@ -937,17 +944,6 @@ protected: void clearXMLVersion() { m_xmlVersion = String(); } -#if ENABLE(TOUCH_EVENTS) // Android -public: - typedef HashMap<Node*, unsigned > TouchListenerMap; - - void addTouchEventListener(Node*); - void removeTouchEventListener(Node*); - const TouchListenerMap& touchEventListeners() const { return m_touchEventListeners; } - -private: - TouchListenerMap m_touchEventListeners; -#endif // ENABLE(TOUCH_EVENTS) private: virtual bool isDocument() const { return true; } @@ -1120,7 +1116,7 @@ private: #if ENABLE(XBL) OwnPtr<XBLBindingManager> m_bindingManager; // The access point through which documents and elements communicate with XBL. #endif - + typedef HashMap<AtomicStringImpl*, HTMLMapElement*> ImageMapsByName; ImageMapsByName m_imageMapsByName; diff --git a/WebCore/dom/Document.idl b/WebCore/dom/Document.idl index e54add0..69417c8 100644 --- a/WebCore/dom/Document.idl +++ b/WebCore/dom/Document.idl @@ -284,12 +284,6 @@ module core { attribute [DontEnum] EventListener onscroll; attribute [DontEnum] EventListener onselect; attribute [DontEnum] EventListener onsubmit; -#if ENABLE_TOUCH_EVENTS - attribute [DontEnum] EventListener ontouchstart; - attribute [DontEnum] EventListener ontouchend; - attribute [DontEnum] EventListener ontouchmove; - attribute [DontEnum] EventListener ontouchcancel; -#endif // attribute [DontEnum] EventListener oncanplay; // attribute [DontEnum] EventListener oncanplaythrough; @@ -326,6 +320,12 @@ module core { attribute [DontEnum] EventListener onreset; attribute [DontEnum] EventListener onsearch; attribute [DontEnum] EventListener onselectstart; +#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 #endif #endif }; diff --git a/WebCore/dom/Element.h b/WebCore/dom/Element.h index 97d3eb4..ce25d70 100644 --- a/WebCore/dom/Element.h +++ b/WebCore/dom/Element.h @@ -88,7 +88,12 @@ public: DEFINE_ATTRIBUTE_EVENT_LISTENER(reset); DEFINE_ATTRIBUTE_EVENT_LISTENER(search); DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart); - +#if ENABLE(TOUCH_EVENTS) + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel); +#endif const AtomicString& getIDAttribute() const; bool hasAttribute(const QualifiedName&) const; const AtomicString& getAttribute(const QualifiedName&) const; diff --git a/WebCore/dom/Element.idl b/WebCore/dom/Element.idl index c24ef65..4a223bb 100644 --- a/WebCore/dom/Element.idl +++ b/WebCore/dom/Element.idl @@ -167,12 +167,6 @@ module core { attribute [DontEnum] EventListener onscroll; attribute [DontEnum] EventListener onselect; attribute [DontEnum] EventListener onsubmit; -#if ENABLE_TOUCH_EVENTS - attribute [DontEnum] EventListener ontouchstart; - attribute [DontEnum] EventListener ontouchend; - attribute [DontEnum] EventListener ontouchmove; - attribute [DontEnum] EventListener ontouchcancel; -#endif // attribute [DontEnum] EventListener oncanplay; // attribute [DontEnum] EventListener oncanplaythrough; @@ -209,6 +203,12 @@ module core { attribute [DontEnum] EventListener onreset; attribute [DontEnum] EventListener onsearch; attribute [DontEnum] EventListener onselectstart; +#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 #endif #endif }; diff --git a/WebCore/dom/Event.cpp b/WebCore/dom/Event.cpp index eda44b0..be2b37b 100644 --- a/WebCore/dom/Event.cpp +++ b/WebCore/dom/Event.cpp @@ -180,20 +180,20 @@ bool Event::isStorageEvent() const } #endif -#if ENABLE(TOUCH_EVENTS) // Android -bool Event::isTouchEvent() const +#if ENABLE(WORKERS) +bool Event::isErrorEvent() const { return false; } #endif -#if ENABLE(WORKERS) -bool Event::isErrorEvent() const +#if ENABLE(TOUCH_EVENTS) +bool Event::isTouchEvent() const { return false; } #endif - + bool Event::storesResultAsString() const { return false; diff --git a/WebCore/dom/Event.h b/WebCore/dom/Event.h index 7ec85a7..4624663 100644 --- a/WebCore/dom/Event.h +++ b/WebCore/dom/Event.h @@ -123,12 +123,12 @@ namespace WebCore { #if ENABLE(DOM_STORAGE) virtual bool isStorageEvent() const; #endif -#if ENABLE(TOUCH_EVENTS) // Android - virtual bool isTouchEvent() const; -#endif #if ENABLE(WORKERS) virtual bool isErrorEvent() const; #endif +#if ENABLE(TOUCH_EVENTS) + virtual bool isTouchEvent() const; +#endif bool propagationStopped() const { return m_propagationStopped; } diff --git a/WebCore/dom/EventNames.h b/WebCore/dom/EventNames.h index 63460a5..c8c3291 100644 --- a/WebCore/dom/EventNames.h +++ b/WebCore/dom/EventNames.h @@ -95,14 +95,6 @@ namespace WebCore { macro(storage) \ macro(submit) \ macro(textInput) \ -/* #if ENABLE(TOUCH_EVENTS) // Android */ \ - macro(touchstart) \ - macro(touchmove) \ - macro(touchend) \ - macro(touchcancel) \ - macro(touchlongpress) \ - macro(touchdoubletap) \ -/* #endif */ \ macro(unload) \ macro(updateready) \ macro(zoom) \ @@ -154,6 +146,15 @@ namespace WebCore { \ macro(orientationchange) \ \ + macro(touchstart) \ + macro(touchmove) \ + macro(touchend) \ + macro(touchcancel) \ +/* #if PLATFORM(ANDROID) */ \ + macro(touchlongpress) \ + macro(touchdoubletap) \ +/* #endif */ \ + \ // end of DOM_EVENT_NAMES_FOR_EACH class EventNames : public Noncopyable { diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp index 4ae83de..c2d5281 100644 --- a/WebCore/dom/Node.cpp +++ b/WebCore/dom/Node.cpp @@ -101,6 +101,10 @@ #include "HTMLNoScriptElement.h" #endif +#if ENABLE(TOUCH_EVENTS) +#include "ChromeClient.h" +#endif + #define DUMP_NODE_STATISTICS 0 using namespace std; @@ -2422,16 +2426,8 @@ bool Node::addEventListener(const AtomicString& eventType, PassRefPtr<EventListe if (Document* document = this->document()) document->addListenerTypeIfNeeded(eventType); - updateSVGElementInstancesAfterEventListenerChange(this); -#if ENABLE(TOUCH_EVENTS) // Android - if (this->document() && - (eventType == eventNames().touchstartEvent || - eventType == eventNames().touchendEvent || - eventType == eventNames().touchmoveEvent || - eventType == eventNames().touchcancelEvent)) - this->document()->addTouchEventListener(this); -#endif + updateSVGElementInstancesAfterEventListenerChange(this); return true; } @@ -2442,13 +2438,17 @@ bool Node::removeEventListener(const AtomicString& eventType, EventListener* lis updateSVGElementInstancesAfterEventListenerChange(this); -#if ENABLE(TOUCH_EVENTS) // Android - if (this->document() && - (eventType == eventNames().touchstartEvent || - eventType == eventNames().touchendEvent || - eventType == eventNames().touchmoveEvent || - eventType == eventNames().touchcancelEvent)) - this->document()->removeTouchEventListener(this); +#if ENABLE(TOUCH_EVENTS) + if (Document* document = this->document()) { + if (document->page() + && (eventType == eventNames().touchstartEvent + || eventType == eventNames().touchmoveEvent + || eventType == eventNames().touchendEvent + || eventType == eventNames().touchcancelEvent)) + // Note the corresponding needTouchEvents(true) is called in Document::addListenerTypeIfNeeded(). + document->page()->chrome()->client()->needTouchEvents(false); + + } #endif return true; } diff --git a/WebCore/dom/Node.h b/WebCore/dom/Node.h index 7da8634..ebf275a 100644 --- a/WebCore/dom/Node.h +++ b/WebCore/dom/Node.h @@ -565,13 +565,6 @@ public: */ virtual bool disabled() const; -#if ENABLE(TOUCH_EVENTS) // Android - DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart); - DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend); - DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove); - DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel); -#endif - using TreeShared<Node>::ref; using TreeShared<Node>::deref; diff --git a/WebCore/dom/Touch.cpp b/WebCore/dom/Touch.cpp index 561a786..41d5c19 100644 --- a/WebCore/dom/Touch.cpp +++ b/WebCore/dom/Touch.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) #include "Touch.h" @@ -40,7 +40,7 @@ static int contentsX(Frame* frame) FrameView* frameView = frame->view(); if (!frameView) return 0; - return frameView->scrollX(); + return frameView->scrollX() / frame->pageZoomFactor(); } static int contentsY(Frame* frame) @@ -50,7 +50,7 @@ static int contentsY(Frame* frame) FrameView* frameView = frame->view(); if (!frameView) return 0; - return frameView->scrollY(); + return frameView->scrollY() / frame->pageZoomFactor(); } Touch::Touch(Frame* frame, EventTarget* target, unsigned identifier, diff --git a/WebCore/dom/Touch.h b/WebCore/dom/Touch.h index 62822fb..cf39faf 100644 --- a/WebCore/dom/Touch.h +++ b/WebCore/dom/Touch.h @@ -26,7 +26,7 @@ #ifndef TOUCH_H_ #define TOUCH_H_ -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) #include "EventTarget.h" #include "Frame.h" @@ -36,41 +36,41 @@ namespace WebCore { - class Touch : public RefCounted<Touch> { - public: - static PassRefPtr<Touch> create(Frame* frame, EventTarget* target, - unsigned identifier, int screenX, int screenY, int pageX, int pageY) - { - return adoptRef(new Touch(frame, target, identifier, screenX, - screenY, pageX, pageY)); - } +class Touch : public RefCounted<Touch> { +public: + static PassRefPtr<Touch> create(Frame* frame, EventTarget* target, + unsigned identifier, int screenX, int screenY, int pageX, int pageY) + { + return adoptRef(new Touch(frame, target, identifier, screenX, + screenY, pageX, pageY)); + } - void updateLocation(int screenX, int screenY, int pageX, int pageY); + void updateLocation(int screenX, int screenY, int pageX, int pageY); - Frame* frame() const { return m_frame.get(); } - EventTarget* target() const { return m_target.get(); } - unsigned identifier() const { return m_identifier; } - int clientX() const { return m_clientX; } - int clientY() const { return m_clientY; } - int screenX() const { return m_screenX; } - int screenY() const { return m_screenY; } - int pageX() const { return m_pageX; } - int pageY() const { return m_pageY; } + Frame* frame() const { return m_frame.get(); } + EventTarget* target() const { return m_target.get(); } + unsigned identifier() const { return m_identifier; } + int clientX() const { return m_clientX; } + int clientY() const { return m_clientY; } + int screenX() const { return m_screenX; } + int screenY() const { return m_screenY; } + int pageX() const { return m_pageX; } + int pageY() const { return m_pageY; } - private: - Touch(Frame* frame, EventTarget* target, unsigned identifier, - int screenX, int screenY, int pageX, int pageY); +private: + Touch(Frame* frame, EventTarget* target, unsigned identifier, + int screenX, int screenY, int pageX, int pageY); - RefPtr<Frame> m_frame; - RefPtr<EventTarget> m_target; - unsigned m_identifier; - int m_clientX; - int m_clientY; - int m_screenX; - int m_screenY; - int m_pageX; - int m_pageY; - }; + RefPtr<Frame> m_frame; + RefPtr<EventTarget> m_target; + unsigned m_identifier; + int m_clientX; + int m_clientY; + int m_screenX; + int m_screenY; + int m_pageX; + int m_pageY; +}; } // namespace WebCore diff --git a/WebCore/dom/TouchEvent.cpp b/WebCore/dom/TouchEvent.cpp index 7ce856f..1fbba6c 100644 --- a/WebCore/dom/TouchEvent.cpp +++ b/WebCore/dom/TouchEvent.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) #include "TouchEvent.h" @@ -33,20 +33,24 @@ namespace WebCore { TouchEvent::TouchEvent(TouchList* touches, TouchList* targetTouches, TouchList* changedTouches, const AtomicString& type, - PassRefPtr<AbstractView> view, int screenX, int screenY, int pageX, int pageY) + PassRefPtr<AbstractView> view, int screenX, int screenY, int pageX, int pageY, + bool ctrlKey, bool altKey, bool shiftKey, bool metaKey) : MouseRelatedEvent(type, true, true, view, 0, screenX, screenY, pageX, pageY, - false, false, false, false) + ctrlKey, altKey, shiftKey, metaKey) , m_touches(touches) , m_targetTouches(targetTouches) , m_changedTouches(changedTouches) +#if PLATFORM(ANDROID) , m_longPressPrevented(false) , m_doubleTapPrevented(false) +#endif { } void TouchEvent::initTouchEvent(TouchList* touches, TouchList* targetTouches, TouchList* changedTouches, const AtomicString& type, - PassRefPtr<AbstractView> view, int screenX, int screenY, int clientX, int clientY) + PassRefPtr<AbstractView> view, int screenX, int screenY, int clientX, int clientY, + bool ctrlKey, bool altKey, bool shiftKey, bool metaKey) { if (dispatched()) return; @@ -55,6 +59,10 @@ void TouchEvent::initTouchEvent(TouchList* touches, TouchList* targetTouches, m_screenX = screenX; m_screenY = screenY; + m_ctrlKey = ctrlKey; + m_altKey = altKey; + m_shiftKey = shiftKey; + m_metaKey = metaKey; initCoordinates(clientX, clientY); } diff --git a/WebCore/dom/TouchEvent.h b/WebCore/dom/TouchEvent.h index 6b7d384..abc1ee2 100644 --- a/WebCore/dom/TouchEvent.h +++ b/WebCore/dom/TouchEvent.h @@ -26,61 +26,69 @@ #ifndef TouchEvent_h #define TouchEvent_h -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) #include "MouseRelatedEvent.h" #include "TouchList.h" namespace WebCore { - class TouchEvent : public MouseRelatedEvent { - public: - static PassRefPtr<TouchEvent> create() - { - return adoptRef(new TouchEvent); - } - static PassRefPtr<TouchEvent> create(TouchList* touches, - TouchList* targetTouches, TouchList* changedTouches, - const AtomicString& type, PassRefPtr<AbstractView> view, - int screenX, int screenY, int pageX, int pageY) - { - return adoptRef(new TouchEvent(touches, targetTouches, changedTouches, - type, view, screenX, screenY, pageX, pageY)); - } - - void initTouchEvent(TouchList* touches, TouchList* targetTouches, - TouchList* changedTouches, const AtomicString& type, - PassRefPtr<AbstractView> view, int screenX, int screenY, - int clientX, int clientY); - - TouchList* touches() const {return m_touches.get();} - TouchList* targetTouches() const {return m_targetTouches.get();} - TouchList* changedTouches() const {return m_changedTouches.get();} - - bool longPressPrevented() const { return m_longPressPrevented; } - void preventLongPress() { m_longPressPrevented = true; } - void setLongPressPrevented(bool prevented) { m_longPressPrevented = prevented; } - - bool doubleTapPrevented() const { return m_doubleTapPrevented; } - void preventDoubleTap() { m_doubleTapPrevented = true; } - void setDoubleTapPrevented(bool prevented) { m_doubleTapPrevented = prevented; } - - private: - TouchEvent() {} - TouchEvent(TouchList* touches, TouchList* targetTouches, - TouchList* changedTouches, const AtomicString& type, - PassRefPtr<AbstractView>, int screenX, int screenY, int pageX, - int pageY); - - virtual bool isTouchEvent() const {return true;} - - RefPtr<TouchList> m_touches; - RefPtr<TouchList> m_targetTouches; - RefPtr<TouchList> m_changedTouches; - - bool m_longPressPrevented; - bool m_doubleTapPrevented; - }; +class TouchEvent : public MouseRelatedEvent { +public: + static PassRefPtr<TouchEvent> create() + { + return adoptRef(new TouchEvent); + } + static PassRefPtr<TouchEvent> create(TouchList* touches, + TouchList* targetTouches, TouchList* changedTouches, + const AtomicString& type, PassRefPtr<AbstractView> view, + int screenX, int screenY, int pageX, int pageY, + bool ctrlKey, bool altKey, bool shiftKey, bool metaKey) + { + return adoptRef(new TouchEvent(touches, targetTouches, changedTouches, + type, view, screenX, screenY, pageX, pageY, + ctrlKey, altKey, shiftKey, metaKey)); + } + + void initTouchEvent(TouchList* touches, TouchList* targetTouches, + TouchList* changedTouches, const AtomicString& type, + PassRefPtr<AbstractView> view, int screenX, int screenY, + int clientX, int clientY, + bool ctrlKey, bool altKey, bool shiftKey, bool metaKey); + + TouchList* touches() const { return m_touches.get(); } + TouchList* targetTouches() const { return m_targetTouches.get(); } + TouchList* changedTouches() const { return m_changedTouches.get(); } + +#if PLATFORM(ANDROID) + bool longPressPrevented() const { return m_longPressPrevented; } + void preventLongPress() { m_longPressPrevented = true; } + void setLongPressPrevented(bool prevented) { m_longPressPrevented = prevented; } + + bool doubleTapPrevented() const { return m_doubleTapPrevented; } + void preventDoubleTap() { m_doubleTapPrevented = true; } + void setDoubleTapPrevented(bool prevented) { m_doubleTapPrevented = prevented; } +#endif + +private: + TouchEvent() {} + TouchEvent(TouchList* touches, TouchList* targetTouches, + TouchList* changedTouches, const AtomicString& type, + PassRefPtr<AbstractView>, int screenX, int screenY, int pageX, + int pageY, + bool ctrlKey, bool altKey, bool shiftKey, bool metaKey); + + virtual bool isTouchEvent() const { return true; } + + RefPtr<TouchList> m_touches; + RefPtr<TouchList> m_targetTouches; + RefPtr<TouchList> m_changedTouches; + +#if PLATFORM(ANDROID) + bool m_longPressPrevented; + bool m_doubleTapPrevented; +#endif +}; } // namespace WebCore diff --git a/WebCore/dom/TouchEvent.idl b/WebCore/dom/TouchEvent.idl index b7148b0..010c36f 100644 --- a/WebCore/dom/TouchEvent.idl +++ b/WebCore/dom/TouchEvent.idl @@ -32,6 +32,10 @@ module events { readonly attribute TouchList touches; readonly attribute TouchList targetTouches; readonly attribute TouchList changedTouches; + readonly attribute boolean ctrlKey; + readonly attribute boolean shiftKey; + readonly attribute boolean altKey; + readonly attribute boolean metaKey; void initTouchEvent(in TouchList touches, in TouchList targetTouches, @@ -41,6 +45,10 @@ module events { in long screenX, in long screenY, in long clientX, - in long clientY); + in long clientY, + in boolean ctrlKey, + in boolean altKey, + in boolean shiftKey, + in boolean metaKey); }; } diff --git a/WebCore/dom/TouchList.cpp b/WebCore/dom/TouchList.cpp index 78b588e..4167e42 100644 --- a/WebCore/dom/TouchList.cpp +++ b/WebCore/dom/TouchList.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) #include "TouchList.h" diff --git a/WebCore/dom/TouchList.h b/WebCore/dom/TouchList.h index fa5fc80..f5033c9 100644 --- a/WebCore/dom/TouchList.h +++ b/WebCore/dom/TouchList.h @@ -26,7 +26,7 @@ #ifndef TOUCHLIST_H_ #define TOUCHLIST_H_ -#if ENABLE(TOUCH_EVENTS) // Android +#if ENABLE(TOUCH_EVENTS) #include <wtf/RefCounted.h> #include <wtf/Vector.h> @@ -34,24 +34,24 @@ namespace WebCore { - class TouchList : public RefCounted<TouchList> { - public: - static PassRefPtr<TouchList> create() - { - return adoptRef(new TouchList); - } +class TouchList : public RefCounted<TouchList> { +public: + static PassRefPtr<TouchList> create() + { + return adoptRef(new TouchList); + } - unsigned length() const { return m_values.size(); } + unsigned length() const { return m_values.size(); } - Touch* item (unsigned); + Touch* item(unsigned); - void append(const PassRefPtr<Touch> touch) { m_values.append(touch); } + void append(const PassRefPtr<Touch> touch) { m_values.append(touch); } - private: - TouchList() {} +private: + TouchList() {} - Vector<RefPtr<Touch> > m_values; - }; + Vector<RefPtr<Touch> > m_values; +}; } // namespace WebCore diff --git a/WebCore/html/HTMLAttributeNames.in b/WebCore/html/HTMLAttributeNames.in index c989dbd..967b695 100644 --- a/WebCore/html/HTMLAttributeNames.in +++ b/WebCore/html/HTMLAttributeNames.in @@ -199,12 +199,10 @@ onstorage onsuspend onsubmit ontimeupdate -/* #if ENABLE(TOUCH_EVENTS) // Android */ ontouchstart ontouchmove ontouchend ontouchcancel -/* #endif */ onunload onvolumechange onwaiting diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp index af15f6e..a4fc52a 100644 --- a/WebCore/html/HTMLElement.cpp +++ b/WebCore/html/HTMLElement.cpp @@ -218,20 +218,18 @@ void HTMLElement::parseMappedAttribute(MappedAttribute *attr) setAttributeEventListener(eventNames().webkitAnimationEndEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onwebkittransitionendAttr) { setAttributeEventListener(eventNames().webkitTransitionEndEvent, createAttributeEventListener(this, attr)); -#if ENABLE(TOUCH_EVENTS) // Android + } else if (attr->name() == oninputAttr) { + setAttributeEventListener(eventNames().inputEvent, createAttributeEventListener(this, attr)); + } else if (attr->name() == oninvalidAttr) { + setAttributeEventListener(eventNames().invalidEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ontouchstartAttr) { setAttributeEventListener(eventNames().touchstartEvent, createAttributeEventListener(this, attr)); - } else if (attr->name() == ontouchendAttr) { - setAttributeEventListener(eventNames().touchendEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ontouchmoveAttr) { setAttributeEventListener(eventNames().touchmoveEvent, createAttributeEventListener(this, attr)); + } else if (attr->name() == ontouchendAttr) { + setAttributeEventListener(eventNames().touchendEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ontouchcancelAttr) { setAttributeEventListener(eventNames().touchcancelEvent, createAttributeEventListener(this, attr)); -#endif - } else if (attr->name() == oninputAttr) { - setAttributeEventListener(eventNames().inputEvent, createAttributeEventListener(this, attr)); - } else if (attr->name() == oninvalidAttr) { - setAttributeEventListener(eventNames().invalidEvent, createAttributeEventListener(this, attr)); } } 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 diff --git a/WebCore/platform/PlatformTouchEvent.h b/WebCore/platform/PlatformTouchEvent.h index 6c8629c..78de894 100644 --- a/WebCore/platform/PlatformTouchEvent.h +++ b/WebCore/platform/PlatformTouchEvent.h @@ -1,67 +1,86 @@ /* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ #ifndef PlatformTouchEvent_h #define PlatformTouchEvent_h -#if ENABLE(TOUCH_EVENTS) // Android +#include "PlatformTouchPoint.h" +#include <wtf/Vector.h> + +#if ENABLE(TOUCH_EVENTS) + +#if PLATFORM(QT) +QT_BEGIN_NAMESPACE +class QTouchEvent; +QT_END_NAMESPACE +#endif +#if PLATFORM(ANDROID) #include "IntPoint.h" +#endif namespace WebCore { - enum TouchEventType {TouchEventStart, TouchEventMove, TouchEventEnd, TouchEventCancel, TouchEventLongPress, TouchEventDoubleTap}; - - class PlatformTouchEvent { - public: - PlatformTouchEvent() - : m_eventType(TouchEventCancel) - { - } - - PlatformTouchEvent(const IntPoint& pos, const IntPoint& globalPos, TouchEventType eventType) - : m_position(pos) - , m_globalPosition(globalPos) - , m_eventType(eventType) - { - } - - const IntPoint& pos() const { return m_position; } - int x() const { return m_position.x(); } - int y() const { return m_position.y(); } - int globalX() const { return m_globalPosition.x(); } - int globalY() const { return m_globalPosition.y(); } - TouchEventType eventType() const { return m_eventType; } - - private: - IntPoint m_position; - IntPoint m_globalPosition; - TouchEventType m_eventType; - }; - -} // namespace WebCore +enum TouchEventType { + TouchStart + , TouchMove + , TouchEnd + , TouchCancel +#if PLATFORM(ANDROID) + , TouchLongPress + , TouchDoubleTap +#endif +}; + +class PlatformTouchEvent { +public: + PlatformTouchEvent() + : m_type(TouchStart) + , m_ctrlKey(false) + , m_altKey(false) + , m_shiftKey(false) + , m_metaKey(false) + {} +#if PLATFORM(QT) + PlatformTouchEvent(QTouchEvent*); +#elif PLATFORM(ANDROID) + PlatformTouchEvent(const IntPoint&, const IntPoint&, TouchEventType, PlatformTouchPoint::State); +#endif + + TouchEventType type() const { return m_type; } + const Vector<PlatformTouchPoint>& touchPoints() const { return m_touchPoints; } + + bool ctrlKey() const { return m_ctrlKey; } + bool altKey() const { return m_altKey; } + bool shiftKey() const { return m_shiftKey; } + bool metaKey() const { return m_metaKey; } + +private: + TouchEventType m_type; + Vector<PlatformTouchPoint> m_touchPoints; + bool m_ctrlKey; + bool m_altKey; + bool m_shiftKey; + bool m_metaKey; +}; + +} #endif // ENABLE(TOUCH_EVENTS) diff --git a/WebCore/platform/PlatformTouchPoint.h b/WebCore/platform/PlatformTouchPoint.h new file mode 100644 index 0000000..339fe73 --- /dev/null +++ b/WebCore/platform/PlatformTouchPoint.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef PlatformTouchPoint_h +#define PlatformTouchPoint_h + +#include "IntPoint.h" +#include <wtf/Platform.h> +#include <wtf/Vector.h> + +#if ENABLE(TOUCH_EVENTS) + +#if PLATFORM(QT) +#include <QTouchEvent> +#endif + +namespace WebCore { + +class PlatformTouchEvent; + +class PlatformTouchPoint { +public: + enum State { + TouchReleased, + TouchPressed, + TouchMoved, + TouchStationary, + TouchCancelled + }; + +#if PLATFORM(QT) + PlatformTouchPoint(const QTouchEvent::TouchPoint&); +#elif PLATFORM(ANDROID) + PlatformTouchPoint(const IntPoint&, const IntPoint&, State); +#endif + + int id() const { return m_id; } + State state() const { return m_state; } + IntPoint screenPos() const { return m_screenPos; } + IntPoint pos() const { return m_pos; } + +private: + int m_id; + State m_state; + IntPoint m_screenPos; + IntPoint m_pos; +}; + +} + +#endif // ENABLE(TOUCH_EVENTS) + +#endif // PlatformTouchPoint_h diff --git a/WebCore/platform/android/PlatformTouchEventAndroid.cpp b/WebCore/platform/android/PlatformTouchEventAndroid.cpp new file mode 100644 index 0000000..46d5c6f --- /dev/null +++ b/WebCore/platform/android/PlatformTouchEventAndroid.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformTouchEvent.h" + +#if ENABLE(TOUCH_EVENTS) + +namespace WebCore { + +PlatformTouchEvent::PlatformTouchEvent(const IntPoint& pos, const IntPoint& globalPos, TouchEventType type, PlatformTouchPoint::State state) : m_type(type) { + m_touchPoints.append(PlatformTouchPoint(pos, globalPos, state)); +} + +} + +#endif diff --git a/WebCore/platform/android/PlatformTouchPointAndroid.cpp b/WebCore/platform/android/PlatformTouchPointAndroid.cpp new file mode 100644 index 0000000..cb22f5f --- /dev/null +++ b/WebCore/platform/android/PlatformTouchPointAndroid.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformTouchPoint.h" + +#if ENABLE(TOUCH_EVENTS) + +namespace WebCore { + +PlatformTouchPoint::PlatformTouchPoint(const IntPoint& pos, const IntPoint& globalPos, State state) :m_id(0), m_state(state), m_screenPos(pos), m_pos(globalPos) {} + +} + +#endif diff --git a/WebCore/plugins/android/PluginViewAndroid.cpp b/WebCore/plugins/android/PluginViewAndroid.cpp index e10641d..0d02941 100644 --- a/WebCore/plugins/android/PluginViewAndroid.cpp +++ b/WebCore/plugins/android/PluginViewAndroid.cpp @@ -52,7 +52,9 @@ #include "PlatformKeyboardEvent.h" #include "PluginMainThreadScheduler.h" #include "PluginPackage.h" +#include "Touch.h" #include "TouchEvent.h" +#include "TouchList.h" #include "android_graphics.h" #include "SkCanvas.h" #include "npruntime_impl.h" @@ -206,11 +208,16 @@ void PluginView::handleTouchEvent(TouchEvent* event) evt.data.touch.modifiers = 0; // todo - // convert to coordinates that are relative to the plugin. The pageX / pageY - // values are the only values in the event that are consistently in frame - // coordinates despite their misleading name. - evt.data.touch.x = event->pageX() - m_npWindow.x; - evt.data.touch.y = event->pageY() - m_npWindow.y; + // In the event of a touchend (up) event, we must ask the changedTouch for the + // co-ordinates as there is no touch in touches anymore. + TouchList* touches = (evt.data.touch.action == kUp_ANPTouchAction) ? + event->changedTouches() : event->touches(); + + // Convert to coordinates that are relative to the plugin. + // We only support single touch points at the moment, so we want to look at index 0 only. + IntPoint localPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(IntPoint(touches->item(0)->pageX(), touches->item(0)->pageY()))); + evt.data.touch.x = localPos.x(); + evt.data.touch.y = localPos.y(); int16 ret = m_plugin->pluginFuncs()->event(m_instance, &evt); if (ignoreRet) @@ -243,11 +250,11 @@ void PluginView::handleMouseEvent(MouseEvent* event) SkANP::InitEvent(&evt, kMouse_ANPEventType); evt.data.mouse.action = isUp ? kUp_ANPMouseAction : kDown_ANPMouseAction; - // convert to coordinates that are relative to the plugin. The pageX / pageY - // values are the only values in the event that are consistently in frame - // coordinates despite their misleading name. - evt.data.mouse.x = event->pageX() - m_npWindow.x; - evt.data.mouse.y = event->pageY() - m_npWindow.y; + // Convert to coordinates that are relative to the plugin. + IntPoint localPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation())); + evt.data.mouse.x = localPos.x(); + evt.data.mouse.y = localPos.y(); + if (isDown) { // The plugin needs focus to receive keyboard events if (Page* page = m_parentFrame->page()) diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index f14c2c1..ffa96f8 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -465,4 +465,14 @@ void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long newQuota) { m_quotaThreadCondition.signal(); } +#if ENABLE(TOUCH_EVENTS) +void ChromeClientAndroid::needTouchEvents(bool needTouchEvents, bool force) +{ + FrameView* frameView = m_webFrame->page()->mainFrame()->view(); + android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); + if (core) + core->needTouchEvents(needTouchEvents, force); +} +#endif + } diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h index 45dd078..b61f9fd 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h @@ -136,6 +136,10 @@ namespace android { virtual void populateVisitedLinks(); +#if ENABLE(TOUCH_EVENTS) + virtual void needTouchEvents(bool, bool); +#endif + // Methods used to request and provide Geolocation permissions. virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*); // Android-specific diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 8414068..15cef2b 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -266,6 +266,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_screenWidth = 320; m_scale = 1; m_screenWidthScale = 1; + m_touchEventListenerCount = 0; LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); @@ -348,6 +349,9 @@ WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) { + if (!view) + return 0; + WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget()); if (!webFrameView) return 0; @@ -991,15 +995,28 @@ void WebViewCore::restoreScreenWidthScale(int scale) checkException(env); } -void WebViewCore::needTouchEvents(bool need) +void WebViewCore::needTouchEvents(bool need, bool force) { DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); #if ENABLE(TOUCH_EVENTS) // Android - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need); - checkException(env); + bool needToUpdateJava = false; + if (need) { + if (++m_touchEventListenerCount == 1) + needToUpdateJava = true; + } else { + if (force) + m_touchEventListenerCount = 0; + else if (--m_touchEventListenerCount == 0) + needToUpdateJava = true; + } + + if (needToUpdateJava || force) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need); + checkException(env); + } #endif } @@ -1910,29 +1927,47 @@ int WebViewCore::handleTouchEvent(int action, int x, int y) #endif #if ENABLE(TOUCH_EVENTS) // Android - WebCore::TouchEventType type = WebCore::TouchEventCancel; + WebCore::TouchEventType type = WebCore::TouchStart; + WebCore::PlatformTouchPoint::State touchState = WebCore::PlatformTouchPoint::TouchPressed; switch (action) { case 0: // MotionEvent.ACTION_DOWN - type = WebCore::TouchEventStart; + type = WebCore::TouchStart; break; case 1: // MotionEvent.ACTION_UP - type = WebCore::TouchEventEnd; + type = WebCore::TouchEnd; + touchState = WebCore::PlatformTouchPoint::TouchReleased; break; case 2: // MotionEvent.ACTION_MOVE - type = WebCore::TouchEventMove; + type = WebCore::TouchMove; + touchState = WebCore::PlatformTouchPoint::TouchMoved; break; case 3: // MotionEvent.ACTION_CANCEL - type = WebCore::TouchEventCancel; + type = WebCore::TouchCancel; + touchState = WebCore::PlatformTouchPoint::TouchCancelled; break; case 0x100: // WebViewCore.ACTION_LONGPRESS - type = WebCore::TouchEventLongPress; + type = WebCore::TouchLongPress; + touchState = WebCore::PlatformTouchPoint::TouchPressed; break; case 0x200: // WebViewCore.ACTION_DOUBLETAP - type = WebCore::TouchEventDoubleTap; + type = WebCore::TouchDoubleTap; + touchState = WebCore::PlatformTouchPoint::TouchPressed; + break; + default: + type = WebCore::TouchCancel; + touchState = WebCore::PlatformTouchPoint::TouchCancelled; break; } + + // Track previous touch and if stationary set the state. WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY); - WebCore::PlatformTouchEvent te(pt, pt, type); + + if (type == WebCore::TouchMove && pt == m_lastTouchPoint) + touchState = WebCore::PlatformTouchPoint::TouchStationary; + + m_lastTouchPoint = pt; + + WebCore::PlatformTouchEvent te(pt, pt, type, touchState); preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); #endif diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 0569b4d..c662441 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -375,7 +375,7 @@ namespace android { Node* cursorNodeIsPlugin(); // Notify the Java side whether it needs to pass down the touch events - void needTouchEvents(bool); + void needTouchEvents(bool, bool); // Notify the Java side that webkit is requesting a keyboard void requestKeyboard(bool showKeyboard, bool isTextView); @@ -526,6 +526,11 @@ namespace android { bool handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr); WebCore::HTMLAnchorElement* retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node); +#if ENABLE(TOUCH_EVENTS) + int m_touchEventListenerCount; + IntPoint m_lastTouchPoint; +#endif + #if DEBUG_NAV_UI uint32_t m_now; #endif diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp index 0fcdc3b..17443b7 100644 --- a/WebKit/android/plugins/PluginWidgetAndroid.cpp +++ b/WebKit/android/plugins/PluginWidgetAndroid.cpp @@ -28,6 +28,7 @@ #include "Document.h" #include "Element.h" #include "Frame.h" +#include "Page.h" #include "PluginPackage.h" #include "PluginView.h" #include "PluginWidgetAndroid.h" @@ -38,6 +39,10 @@ #include "WebViewCore.h" #include "jni_utility.h" +#if ENABLE(TOUCH_EVENTS) +#include "ChromeClient.h" +#endif + #define DEBUG_VISIBLE_RECTS 1 // temporary debug printfs and fixes PluginWidgetAndroid::PluginWidgetAndroid(WebCore::PluginView* view) @@ -259,12 +264,18 @@ void PluginWidgetAndroid::updateEventFlags(ANPEventFlags flags) { } Document* doc = m_pluginView->getParentFrame()->document(); +#if ENABLE(TOUCH_EVENTS) if((m_eventFlags ^ flags) & kTouch_ANPEventFlag) { - if(flags & kTouch_ANPEventFlag) - doc->addTouchEventListener(m_pluginView->getElement()); - else - doc->removeTouchEventListener(m_pluginView->getElement()); + if (flags & kTouch_ANPEventFlag) { + if (Page* page = doc->page()) + page->chrome()->client()->needTouchEvents(true, false); + doc->addListenerTypeIfNeeded(eventNames().touchstartEvent); + } else { + if (Page* page = doc->page()) + page->chrome()->client()->needTouchEvents(false, false); + } } +#endif m_eventFlags = flags; } |