Chromium on Android: 理解Chromium WebView的绘制模型

感觉这篇写的很好,赞一个,本文转载,原文地址:http://blog.csdn.net/hongbomin/article/details/18499295


摘要

从应用程序层次来看,WebView只是一个视图(View)部件而已,与普通的TextView一样,它可以被嵌入在应用程序的任何一个位置,所以,尽管WebView是一个较为复杂的视图部件,但仍然工作在Android视图系统的绘制模型下。

绘制模型 vs. 渲染模型

事实上,绘制模型和渲染模型两个术语可以混用。但本文还是对两者做了细微的区分。当谈及与Android视图系统整合,使用“绘制模型”术语说明Android View系统的绘制模型是如何作用到WebView部件上,而谈及WebView内页面内容的合成方式时,使用“渲染模型”术语描述以何种方式将页面内容渲染到由绘制模型中给定的Canvas对象上。两者的联系是,渲染模型会根据绘制模型中的Canvas对象决定采取何种渲染方式。

WebView的绘制模型

Android SDK中,android.webkit.WebView实际上是一个ViewGroup,并将后端的具体实现抽象为WebViewProvider,而WebViewChromium正是一个提供基于Chromium的具体实现类,对核心类AwContents做了一层简单的封装,加强了对线程安全方面的考量。大致结构如下图所示:

简单的来说,当一个视图(View)部件的内容发生更新时,会调用invalidate()方法通知Android视图系统表明这个View的内容已经失效,视图系统会根据view层次结构计算有哪些View需要重绘,并调用View.draw方法将更新的内容绘制到传入Canvas上,对于用户自定义的View,绘制的逻辑代码实现在重载地View.onDraw方法中,决定在在Canvas上绘制什么内容。关于Android视图系统的绘制模型,详细信息可参考这里

再回到WebView的情况。当WebView部件发生内容更新时,例如页面加载完毕,CSS动画,或者是滚动、缩放操作导致页面内容更新,同样会在WebView触发invalidate方法,随后在视图系统的统筹安排下,WebView.onDraw方法会被调用,最后实际上调用了AwContents.onDraw方法,它会请求对应的native端对象执行OnDraw方法,将页面的内容更新绘制到WebView对应的Canvas上去,至此,就像按下了WebView渲染器的启动开关,一个完整的渲染流水线开始工作了。

  1. WebViewChromium::onDraw(Canvas canvas) (WebViewChromium.java in AOSP)  
  2. --> AwContents::onDraw(Canvas canvas) (AwContents.java in chromium)  
  3.     --> android_webview::AwContents::OnDraw(...) (aw_contents.cc)  
  4.         -->  android_webview::InProcessViewRenderer::OnDraw(...) (in_process_view_renderer.cc)  

绘制方法OnDraw

Native端InProcessViewRenderer对象负责响应从Java层发出的OnDraw调用请求,首先会根据判断硬件加速是否开启,决定渲染的执行路径。

  1. bool InProcessViewRenderer::OnDraw(jobject java_canvas,  
  2.                                    bool is_hardware_canvas,  
  3.                                    const gfx::Vector2d& scroll,  
  4.                                    const gfx::Rect& clip) {  
  5.   scroll_at_start_of_frame_  = scroll;  
  6.   if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) {  
  7.     // We should be performing a hardware draw here. If we don't have the  
  8.     // comositor yet or if RequestDrawGL fails, it means we failed this draw and  
  9.     // thus return false here to clear to background color for this draw.  
  10.     return compositor_ && client_->RequestDrawGL(java_canvas);  
  11.   }  
  12.   // Perform a software draw  
  13.   return DrawSWInternal(java_canvas, clip);  
  14. }  

上面的代码片段中,OnDraw方法接受四个参数,

  1. java_canvas:Java层Canvas对象在JNI层的native表示,对这个Canvas的绘制实际上是在更新WebView部件的内容;
  2. is_hardware_canvas:布尔值,标识java_canvas对象是否启用了硬件加速的Canvas对象,在Java层通过调用Canvas.isHardwareAccelerated()来获取;
  3. scroll:因屏幕滚动而发生的偏移;
  4. clip:WebView部件内容发生更新的矩形区域;

显然,OnDraw有两条不同的执行路径:

  • 硬件渲染路径:当同时满足 1)WebView的Canvas开启了硬件加速;2)当WebView与一个Window关联后;3)没有通过命令行选项--disable-webview-gl-mode禁用WebView的GL模式等这三者条件时,会请求Client对象调用RequestDrawGL以硬件方式绘制Canvas。RequestDrawGL方法最终还是会调用InProcessViewRenderer::DrawGL,但其中涉及到Java层和JNI的互操作性问题,调用过程看起来不是那么直接了当,后续文章将会详细介绍。

  • 软件渲染路径:当上述三者条件不满足时,调用DrawSWInternal方法以软件方式绘制Canvas。而DrawSWInternal还会考虑两种情况,1)从AOSP编译的WebView;2)从Chromium编译的WebView。两者不同之处在于,是否提供了直接访问Java层Canvas对象中Pixels的函数表,对于从AOSP编译的WebView,可以直接将Java层Canvas对象转换为SkCanvas,合成器(compositor)直接将合成的内容渲染到这个Canvas上。而从Chromium编译出来的WebView,编译期是不能直接访问AOSP代码,也就是说不能直接将Canvas对象转换为SkCanvas,需要先调用NDK方法创建一个Bitmap,合成器只能先将页面内容渲染到这个Bitmap上,然后再通过JNI调用Java层的drawBitmap将这个Bitmap绘制到Canvas对象上。

小结:

WebView只是一个普通的View部件而已,当页面内容更新时,会触发invalidate,Android视图系统收到失效消息后会要求WebView部件回调onDraw方法重绘自己。WebView重绘过程较为复杂,方法InProcessViewRenderer::OnDraw是理解和分析WebView渲染模型的入口点,Canvas对象的硬件加速属性决定了渲染路径的不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值