http://blog.csdn.net/qq295445028/article/details/9356729
chromium手势事件的处理,简而言之就是browser进程调用系统接口捕获并判断事件,传给render进程处理事件的过程。
捕获事件的接口:ContentViewGestureHandler::onTouchEvent。在这个函数中有一些判断这里不再赘述,只提一个重要的函数ContentViewGestureHandler::offerTouchEventToJavaScript。这个函数的意义在于,如果网页中的js代码也需要事件处理的话,则会进入该函数的逻辑,否则不会。
先看第一种情况,即没有js事件处理的过程,onTouchEvent之后进入processTouchEvent来处理事件,其中调用GestureDetector::onTouchEvent系统接口对事件进行判断,来确定其手势。并触发监听器的回调(当然监听器只有接口,具体回调要自己实现),此时事件已经成为手势。在这里注意一下事件和手势的区别,最初的touchevent只是一个事件,它并不知道是什么动作,只有通过上述系统接口判断后,才知道是单击,双击还是滚动等手势。然后调用ContentViewCore::sendGesture对手势进行一些处理并发往render进程。
render进程通过WebViewImpl::handleInputEvent来对所有事件和手势进行处理,如果是手势,则进入webkit的手势处理WebViewImpl::handleGestureEvent(或者有些手势处理会进入CC部分)。至于webkit对手势的处理暂时不考虑。
第二种情况,当网页中有js需要事件处理时,进入该网页时就会有对browser的回调ContentViewGestureHandler::hasTouchEventHandlers,来设置需要js处理。此时onTouchEvent之后就会进入offerTouchEventToJavaScript函数,该函数会将事件存起来,并发给render进程(注意发的是事件而不是手势,此时没有经过手势判断)。调用ContentViewCore::sendTouchEvent接口发送,WebViewImpl::handleInputEvent接收后发现是事件而不是手势,webkit会询问js是否需要执行该事件。之后回调给browser进程ContentViewGestureHandler::confirmTouchEvent函数。
如果js需要监听某些事件,它会向特定的DOM节点增加监听器,相关js代码最终会调用到EventListenerMap::add函数来增加监听器。而如果事件恰好与该监听器匹配,大致是如下处理流程:
#0 WebCore::V8AbstractEventListener::invokeEventHandler (this=0x4bed6e60, context=0x4ada04ac, event=0x4cdd4c20, jsEvent=...) at third_party/WebKit/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp:118
#1 0x5c4d3136 in WebCore::V8AbstractEventListener::handleEvent (this=0x4bed6e60, context=0x4ada04ac, event=0x4cdd4c20) at third_party/WebKit/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp:108
#2 WebCore::V8AbstractEventListener::handleEvent (this=0x4bed6e60, context=0x4ada04ac, event=0x4cdd4c20) at third_party/WebKit/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp:83
#3 0x5c2b7f06 in WebCore::EventTarget::fireEventListeners (this=0x4b8746a0, event=0x4cdd4c20, d=0x4b19cac0, entry=...) at third_party/WebKit/Source/WebCore/dom/EventTarget.cpp:217
#4 0x5c2b7f7a in WebCore::EventTarget::fireEventListeners (this=0x4b8746a0, event=0x4cdd4c20) at third_party/WebKit/Source/WebCore/dom/EventTarget.cpp:182
#5 0x5c2b4a7c in WebCore::EventContext::handleLocalEvents (this=0x4cdd4cf8, event=0x4cdd4c20) at third_party/WebKit/Source/WebCore/dom/EventContext.cpp:54
#6 0x5c2b4d9a in WebCore::EventDispatcher::dispatchEventAtBubbling (this=0x60870790, event=..., windowContext=...) at third_party/WebKit/Source/WebCore/dom/EventDispatcher.cpp:328
#7 0x5c2b5472 in WebCore::EventDispatcher::dispatchEvent (this=0x60870790, prpEvent=<value optimized out>) at third_party/WebKit/Source/WebCore/dom/EventDispatcher.cpp:265
#8 0x5c2b4b0e in WebCore::EventDispatchMediator::dispatchEvent (this=<value optimized out>, dispatcher=<value optimized out>) at third_party/WebKit/Source/WebCore/dom/EventDispatchMediator.cpp:52
#9 0x5c2b509e in WebCore::EventDispatcher::dispatchEvent (node=<value optimized out>, mediator=...) at third_party/WebKit/Source/WebCore/dom/EventDispatcher.cpp:133
#10 0x5c2bf9b8 in WebCore::Node::dispatchEvent (this=0x4b9e3c90, event=...) at third_party/WebKit/Source/WebCore/dom/Node.cpp:2581
#11 0x5c2b7be0 in WebCore::EventTarget::dispatchEvent (this=0x4b9e3c90, event=..., ec=<value optimized out>) at third_party/WebKit/Source/WebCore/dom/EventTarget.cpp:152
#12 0x5c5edc32 in WebCore::EventHandler::handleTouchEvent (this=<value optimized out>, event=...) at third_party/WebKit/Source/WebCore/page/EventHandler.cpp:3826
#13 0x5c15fd92 in WebKit::PageWidgetEventHandler::handleTouchEvent (this=<value optimized out>, mainFrame=..., event=<value optimized out>)
at third_party/WebKit/Source/WebKit/chromium/src/PageWidgetDelegate.cpp:223
#14 0x5c160032 in WebKit::PageWidgetDelegate::handleInputEvent (page=<value optimized out>, handler=<value optimized out>, event=<value optimized out>)
at third_party/WebKit/Source/WebKit/chromium/src/PageWidgetDelegate.cpp:171
#15 0x5c1825f8 in WebKit::WebViewImpl::handleInputEvent (this=0x60e7bc10, inputEvent=...) at third_party/WebKit/Source/WebKit/chromium/src/WebViewImpl.cpp:2248
#16 WebKit::WebViewImpl::handleInputEvent (this=0x60e7bc10, inputEvent=...) at third_party/WebKit/Source/WebKit/chromium/src/WebViewImpl.cpp:2195
再下步就进入了V8来处理JS事件。
如果webkit没有把事件丢给js执行,那么在confirmTouchEvent函数中会调用processTouchEventNoLongPress,类似第一种情况,重新对事件进行手势判断并丢给render进程取执行。如果该事件已经被js执行,那么就不会被再次执行。
可见第二种情况下,事件可能经历了 browser--->render--->browser--->render 三次传递才最终被执行。也就是说在有js需要处理事件的网页中,事件传递的效率是很低的。最新的代码中进行了改进,就是offerTouchEventToJavaScript的准入标准,不仅要网页中有js处理事件,而且需要事件发送在特定区域才会进入该函数。这样点击网页中的其他位置就不会进行三次传递。
这就是chromium对手势事件的处理流程,宏观上来看条理还算比较清晰的,要想做到完美处理事件,其中的细节还要不断推敲。