1. 程式人生 > >chromium手勢事件處理流程

chromium手勢事件處理流程

 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對手勢事件的處理流程,巨集觀上來看條理還算比較清晰的,要想做到完美處理事件,其中的細節還要不斷推敲。