Chromium网页滑动和捏合手势处理过程分析

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

Chromium网页滑动和捏合手势处理过程分析从前面一文可以知道,Chromium的Browser进程从Touch事件中检测到滑动和捏合手势之后,就会将它们发送给Render进程处理。滑动手势对应于修改网页的Viewport,而捏合手势对应于设置网页的缩放因子。通常我们比较两个浏览器的流畅程度,就是比较它们的滑动和捏合性能。因此,浏览器必须要快速地响应用户的滑动和捏合手势。本文接下来就详细分析Chromium快速响应网页滑动和捏合手势的过程。从前面文章中可以知道,Browser进程是通过一个类型为InputMsg_HandleInputEvent的IPC消息将网页的滑动和捏合手势发送给Render进程处理的。Render进程通过一个InputEventFilter截获这两个手势操作,并且分发给Compositor线程处理,如图1所示:从前面文章中这个系列的文章可以知道,Compositor线程为网页维护了一个CCActiveLayerTree。这个CCActiveLayerTree描述的是网页当前正在显示的内容。由于滑动和捏合手势并没有改变网页的内容,仅仅是改变了它的位置和缩放因子,因此Compositor线程会将滑动和捏合手势直接应用在CCActiveLayerTree。这样就可以快速地响应用户的滑动和捏合操作了。将滑动和捏合手势应用在网页的CCActiveLayerTree之后,就会造成它与网页的CCLayerTree不一致。通常情况下,我们都是将CCLayerTree的变化同步到CCActiveLayerTree中去的。但是在网页被滑动和捏合的情况下,就刚好反过来,我们需要将CCActiveLayerTree的变化同步到CCLayerTree中去,以维持两个Tree的一致性。那么,CCActiveLayerTree的变化什么时候会同步到CCLayerTree去的呢?Compositor线程将滑动和捏合手势应用在CCActiveLayerTree之后,会执行两个操作。第一个操作是请求马上对CCActiveLayerTree进行渲染。第二个操作是请求执行下一次Commit,这将会触发CCLayerTree被重新绘制。CCLayerTree在重新绘制的过程中,就会将之前应用在CCActiveLayerTree上的滑动和捏合操作也应用在CCLayerTree上,从而可以将CCActiveLayerTree的变化同步到CCLayerTree中去。接下来,我们就从Render进程截获Browser进程发送过来的输入事件开始,分析它快速响应网页的滑动和捏合手势的过程。从前面文章中一文可以知道,Render进程在加载网页之后,会通过调用RenderThreadImpl类的成员函数EnsureWebKitInitialized初始化WebKit,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片voidRenderThreadImpl::EnsureWebKitInitialized(){......boolenable=command_line.HasSwitch(switches::kEnableThreadedCompositing);if(enable){......InputHandlerManagerClient*input_handler_manager_client=NULL;......if(!input_handler_manager_client){input_event_filter_=newInputEventFilter(this,compositor_message_loop_proxy_);AddFilter(input_event_filter_.get());input_handler_manager_client=input_event_filter_.get();}input_handler_manager_.reset(newInputHandlerManager(compositor_message_loop_proxy_,input_handler_manager_client));}......}这个函数定义在文件external/chromium_org/content/renderer/render_thread_impl.cc中。在初始化WebKit的过程中,RenderThreadImpl类的成员函数EnsureWebKitInitialized将会创建一个InputEventFilter截获Browser进程发送过来的网页输入事件。这个InputEventFilter保存在RenderThreadImpl类的成员变量input_event_filter_中。接下来,我们就分析这个InputEventFilter的创建过程。InputEventFilter是用来将滑动和捏合手势分发给Render进程的Compositor线程处理的,因此只有Render进程存在Compositor线程的情况下,才会创建InputEventFilter。当Render进程指定了switches::kEnableThreadedCompositing(即enable-threaded-compositing)启动选项时,Render进程就会存在Compositor线程。这时候RenderThreadImpl类的成员函数EnsureWebKitInitialized将会创建一个InputEventFilter。创建出来的InputEventFilter保存在RenderThreadImpl类的成员变量input_event_filter_中,并且在创建的时候,需要指定一个Compositor线程消息循环代理对象。这个消息循环代理对象由RenderThreadImpl类的另外一个成员变量compositor_message_loop_proxy_描述。接下来我们分析InputEventFilter类的构造函数的实现,以便了解InputEventFilter的创建过程,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片InputEventFilter::InputEventFilter(IPC::Listener*main_listener,constscoped_refptrbase::MessageLoopProxy&target_loop):main_loop_(base::MessageLoopProxy::current()),main_listener_(main_listener),......,target_loop_(target_loop),......{......}这个函数定义在文件external/chromium_org/content/renderer/input/input_event_filter.cc中。从前面的调用过程可以知道,参数main_listener指向的是一个RenderThreadImpl对象,它将会保存在InputEventFilter类的成员变量main_listener_中。以后Compositor线程会通过这个RenderThreadImpl对象将截获到的其它输入事件转发给Main线程处理。此外,参数target_loop描述的Compositor线程消息循环代理对象将会保存在InputEventFilter类的另外一个成员变量target_loop_。以后InputEventFilter就会通过这个消息循环代理对象将滑动和捏合手势分发给Compositor线程处理。InputEventFilter类的构造函数还是调用base::MessageLoopProxy类的静态成员函数current获得当前线程(Main线程)的消息循环代理对象,并且将这个消息循环代理对象保存在InputEventFilter类的成员变量main_loop_。以后Compositor线程也会通过这个消息循环代理对象将截获到的其它输入事件转发给Main线程处理。回到RenderThreadImpl类的成员函数EnsureWebKitInitialized中,它创建了一个InputEventFilter之后,接着又要这个InputEventFilter以及Compositor线程的消息循环代理对象创建一个InputHandlerManager对象,并且保存在RenderThreadImpl类的成员变量input_handler_manager_中。接下来我们继续分析InputHandlerManager对象的创建过程,也就是InputHandlerManager类的构造函数的实现,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片InputHandlerManager::InputHandlerManager(constscoped_refptrbase::MessageLoopProxy&message_loop_proxy,InputHandlerManagerClient*client):message_loop_proxy_(message_loop_proxy),client_(client){DCHECK(client_);client_-SetBoundHandler(base::Bind(&InputHandlerManager::HandleInputEvent,base::Unretained(this)));}这个函数定义在文件external/chromium_org/content/renderer/input/input_handler_manager.cc中。InputHandlerManager类的构造函数首先分别将参数message_loop_proxy描述的Compositor线程消息循环代理对象和参数client描述的InputEventFilter保存成员变量message_loop_proxy_和client_中。InputHandlerManager类的构造函数接下来又调用参数client描述的InputEventFilter的成员函数SetBoundHandler,用来给后者设置一个Handler,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片voidInputEventFilter::SetBoundHandler(constHandler&handler){......handler_=handler;}这个函数定义在文件external/chromium_org/content/renderer/input/input_event_filter.cc中。从前面的调用过程可以知道,参数handler描述的Hanlder绑定了InputHandlerManager类的成员函数HandleInputEvent,它被保存在InputEventFilter类的成员变量handler_中。这个Handler以后用来处理网页的滑动和捏合手势。从前面文章中一文可以知道,网页的CCLayerTree是在RenderViewImpl类的成员函数initializeLayerTreeView中创建的。创建之后,RenderViewImpl类的成员函数initializeLayerTreeView将会获得一个InputHandler。这个InputHandler将会注册到前面创建的InputHandlerManager中,用来将网页滑动和捏合手势操作应用在网页的CCActiveLayerTree中。接下来,我们就继续分析上述InputHandler的获取和注册过程,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片voidRenderViewImpl::in

1 / 31
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功