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

来源:互联网 发布:python 生成日志文件 编辑:程序博客网 时间:2024/05/17 02:52

摘要

从应用程序层次来看,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渲染器的启动开关,一个完整的渲染流水线开始工作了。

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

绘制方法OnDraw

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

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

上面的代码片段中,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对象的硬件加速属性决定了渲染路径的不同。

0 0
原创粉丝点击