转载请注明出处:http://www.cnblogs.com/fangkm/p/3943896.html

常见的UI库的绘制逻辑

任何一个成熟的界面框架都有一个相当复杂的结构,消息循环的处理、控件的布局与绘制、焦点的管理以及资源的存取等等,Chromium里的界面框架也不例外,尤其采用的MVC设计方式更是增添了代码结构的复杂度。这里并不打算讨论Chromium的界面框架,本文感兴趣的只是Chromium的UI绘制部分,确切地说应该是引入Aura架构之后控件渲染的硬件加速支持。

在常见的DirectUI实现(Windows平台)中,绘制逻辑一般如下:最外层带HWND句柄的的Window在接收到WM_PAINT消息时,会通过BeginPaint函数获得一个窗口对应的绘制DC,然后根据这个绘制DC创建一个相应的内存DC,之后遍历Window内自绘的控件(呈树型结构),每个控件计算需要更新区域与自己区域的交集,在该内存DC上绘制交集区域对应的控件部位,最后由BitBlt系列的API将内存DC拷贝到绘制DC上,从而完成一整套的渲染逻辑。没有语言功底的人用文字来描述流程逻辑,会显得相当苍白无力,还是附上一张简单的流程图吧。

整体流程结构上很清晰明了,但是实现起来很是繁琐,尤其是处理控件的层级、可视性、绘制区域的计算等逻辑。Chromium中UI框架的软件渲染流程也大致是这个流程,只是引入了硬件渲染后,增加了合成层的概念,为了结构上的一致性,软件渲染流程也经过cc层,路由一大圈,最终绘制在软件渲染提供的OutputSurface上,具体可参见SoftwareOutputDeviceWin实现,Chromium的软件渲染部分在探究CC库的时候会深入研究。

引入Aura框架后的Chromium UI库的绘制逻辑

在普遍的DirectUI库实现中,一般都是采用软件渲染,也就是通过一系列的GDI函数在DC上绘制,软件渲染一旦遇到刷新频率比较高的情况下,比如视频画面、游戏画面等,绘制效率就力不从心了,流畅度体验下降的厉害,所以播放视频或者游戏都用GPU进行硬件渲染,然而Windows下硬件渲染一般都需要提供窗口句柄HWND,比如DirectShow中的渲染组件VMR Filter, 但是在DirectUI框架中加入一个带HWND的子窗口是种很要命的情况,这样就完全破坏了自绘体系,任何完全自绘的控件都无法位于HWND子窗口之上,焦点逻辑、消息路由等体系都会遭受不同程度的破坏。退一步讲,就算一个成熟的DirectUI库对包容子HWND窗口逻辑做的足够好,那试想一下如果一个ui界面中如果有多处需要HWND的情况,那也是很糟糕的事。总之,在我看来,在DirectUI框架中加入带HWND的子窗口完全就是悖论,就是对实际应用场景的一种妥协。还有,DirectUI的一大特色就是完全自绘,这样就容易开发出绚丽多彩的界面,酷炫界面当然少不了动画逻辑,动画的渲染如果能用上GPU也是一大助力。废话了这么多,总之,能够支持硬件渲染对DirectUI库来说是很有必要的。

非常荣幸,Chromium UI库就支持硬件渲染,为此还引入了Aura框架结构来管理UI的渲染底层。Chromium UI框架渲染逻辑涉及到的结构图大致如下:

在介绍渲染流程之前之前,有必要理解一下Aura结构,依据我的理解, Aura中的Window类应该就是Aura框架中的窗口的概念,Window同样采取树型组织结构,从而WindowTreeHost类的作用就不难理解了,就是作为Window树的宿主,WindowTreeHost内部创建一个顶层的Window作为所有的Window树的根节点。WindowTreeHost在不同平台下有着不同的实现,在windows下的实现类是DesktopWindowTreeHostWin, 其维护一个HWNDMessageHandler对象,用来处理windows平台下的窗口的创建、消息处理等逻辑,HWNDMessageHandler从 WindowImpl派生,负责处理庞大的Windows消息处理,并将处理逻辑通过HWNDMessageHandlerDelegate接口传递给DesktopWindowTreeHostWin处理,比如,WM_PAINT消息的处理逻辑就是通过这种方式委托给DesktopWindowTreeHostWin的HandlePaint函数来处理。

在引入Aura之前,Widget类直接HWNDMessageHandler进行对接,引入Aura之后,Widget与HWND脱离开来,不过逻辑上仍然作为对外开发接口中的顶层窗口。

views框架为Widget配备一个DesktopNativeWidgetAura对象作为与Aura层的适配,如图所示,DesktopNativeWidgetAura逻辑上只维护了一个Window对象,即content_window_成员,该Window对应整个的Widget窗口层级,也就是说整个Widget包括其内部的View树都属于Aura中的一个窗口层。

在Aura体系中,Window和Layer为一一对应的关系,从而很好地表示出每个窗口就是一个渲染层的概念。当渲染引擎渲染之前,需要收集每个Layer的绘制逻辑时,Layer对象通过LayerDelegate接口的OnPaintLayer方法来将逻辑委托给与其对应的Window类。同样,DesktopNativeWidgetAura为Widget维护了一个Window对象,它就有义务从Window对象中将绘制逻辑通过WindowDelegate接口承接过来,然后通过NativeWidgetDelegate接口将该逻辑抛给Widget对象,Widget对象响应OnNativeWidgetPaint函数,遍历自身的View树,往画布上添砖加瓦。

在这里需要补充一下,Widget的View也可以持有Layer对象,刚才的结构图中实在不便标出,View同样实现了LayerDelegate接口,控件可以根据需要创建属于自己的Layer层,并将其添加到DesktopNativeWidgetAura成员content_window_对应的Layer层的子节点中(再次嵌套补充一下,这里说的Layer是ui层的Layer,添加到其子节点,为的是添加到与ui层Layer对应的cc层的Layer的树层级中,cc层的Layer树才是真正的渲染树,ui层的Layer只是为了方便Aura访问做的一层适配。有点绕了,以后讨论cc库的时候再细说吧)。通过调用View的SetPaintToLayer方法,View就会创建自己的Layer层。此时View直接实现OnPaintLayer方法来处理绘制即可,而且绘制的层级在不创建Layer的View控件之上。如果要创建一个显示视频的控件,可以考虑创建一个属于自己的Layer层,从而在独立的层上绘制视频数据。啰嗦了这么多,还是配上一张序列图啊,一图抵千言:

cc库的逻辑以后再开始重点研究,这里姑且就当黑盒处理。这个流程中,绘制的驱动由windows消息WM_PAINT的响应来驱动,这是典型的软件渲染流程,另外可以调用View控件的SchedulePaint方法来重绘该控件,重绘的流程是找到与View绑定的Layer对象,如果没有绑定则一直向上找,最顶层的Widget可以通过GetLayer方法访问到DesktopNativeWidgetAura成员content_window_对应的Layer。找到Layer后调用Layer的SchedulePaint函数,从而驱动Compositor出发绘制流程。

本文就先介绍到这里,其实这里面还有很多逻辑可扒,比如绘制流程一旦触发,怎么确定单个Layer或View是否需要重新绘制等。时间有限,精力有限,还是留点激情稍后去研究CC模块为好。

Chromium的UI绘制初探的更多相关文章

  1. Android UI 绘制过程浅析(五)自定义View

    前言 这已经是Android UI 绘制过程浅析系列文章的第五篇了,不出意外的话也是最后一篇.再次声明一下,这一系列文章,是我在拜读了csdn大牛郭霖的博客文章<带你一步步深入了解View> ...

  2. Win10 UWP开发中的重复性静态UI绘制小技巧 2

    小技巧1 地址:http://www.cnblogs.com/ms-uap/p/4641419.html 介绍 我们在上一篇博文中展示了通过Shape.Stroke族属性实现静态重复性UI绘制,使得U ...

  3. Win10 UWP开发中的重复性静态UI绘制小技巧 1

    介绍 在Windows 10 UWP界面实现的过程中,有时会遇到一些重复性的.静态的界面设计.比如:画许多等距的线条,画一圈时钟型的刻度线,同特别的策略排布元素,等等. 读者可能觉得这些需求十分简单, ...

  4. Unity4.6新UI系统初探(uGUI)

    一.引言 Unity终于在即将到来的4.6版本内集成了所见即所得的UI解决方案(视频).事实上从近几个版本开始,Unity就在为这套系统做技术扩展,以保证最终能实现较理想的UI系统.本文试图通过初步的 ...

  5. 传感器仿真平台——UI绘制模块(二)

    这一章讲的是UI绘制模块 该模块的作用是将实验对象绘制出来,它可能是目标.传感器等等,由于事先并不知道会有哪些物体,也无法事先定义好某个对象该怎么画,以我懒人的性格,得了,就抛给用的人吧~喝前摇一摇, ...

  6. 一篇文章教你读懂UI绘制流程

    最近有好多人问我Android没信心去深造了,找不到好的工作,其实我以一个他们进行回复,发现他们主要是内心比较浮躁,要知道技术行业永远缺少的是高手.建议先阅读浅谈Android发展趋势分析,在工作中, ...

  7. 基于Docker的UI自动化初探

    本文来自网易云社区 前言 一直以来,项目迭代的时间都是比较紧张的,开发加班加点coding,测试加班加点提bug.都说"时间像海绵里的水,挤挤总会有的"(当然这里的"挤挤 ...

  8. 乘风破浪,遇见Android Jetpack之Compose声明式UI开发工具包,逐渐大一统的原生UI绘制体系

    什么是Android Jetpack https://developer.android.com/jetpack Android Jetpack是一个由多个库组成的套件,可帮助开发者遵循最佳做法.减少 ...

  9. Android UI 绘制过程浅析(四)draw过程

    前言 draw是绘制View三个步骤中的最后一步.同measure.layout一样,通常不对draw本身进行重写,draw内部会调用onDraw方法,子类View需要重写onDraw(Canvas) ...

随机推荐

  1. 《C#高级编程》学习笔记------C#中的事件和委托

    本文转载自张子阳 目录 委托的作用 将方法绑定到委托 事件的来由 Observer设计模式 .Net Framework中的委托与事件   引言 委托 和 事件在 .Net Framework中的应用 ...

  2. canva实践小实例 —— 马赛克效果

    前面给大家带来了操作像素的API,此时此刻,我觉得应该配以小实例来进行进一步的说明和演示,以便给大家带来更宽广的视野和灵感,你们看了我的那么多的文章,应该是懂我的风格,废话不多说,进入正题: 这次给大 ...

  3. PrincipalView的使用参数

    4 G:\PrincipalView\model\m426.off 注意,路径是绝对路径,所以如果程序移位的话,要注意修改: 路径中不能包含空格

  4. Tomcat 解决The code of method _jspService(HttpServletRequest, HttpServletResponse) is exceeding the 65535 bytes limit

    解法: 修改tomcat下的web.xml,     搜索:JspServlet, 增加: <init-param> <param-name>mappedfile</pa ...

  5. 越狱后想禁用Spotlight

    如果你的是ios7越狱后不想用Spotlight搜索功能,大老板源的NoSpot ios7可轻松帮你实现.亲测可用……………………

  6. 设计模式学习起点 UML类图笔记

    UML类图笔记 大学开设的软件设计课程一般都会学习UML类图,大部分关于设计模式的描述都是使用的UML类图,可以说类图的表示是学习设计模式的起点.UML定义类之间的关系主要有六种:泛化关系.实现关系. ...

  7. watchdog机制

    转自:http://blog.sina.com.cn/s/blog_4dff871201012yzh.html 什么是Watchdog? Watchdog,又称watchdog timer,是计算机可 ...

  8. javascript二叉树基本功能实现

    都是常用的功能. 删除是最复杂的.. <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  9. sublime Emmet的用法及相关语法

    本节来讲一下Emmet插件的用法及相关语法. Emmet插件极大的提高了编程员的编程速度,下面我们来讲讲它的具体语法: 一.生成 HTML 文档初始结构 HTML 文档的初始结构,就是包括 docty ...

  10. wp7 BaseDictionary<TKey, TValue>

    /// <summary>/// Represents a dictionary mapping keys to values./// </summary>/// /// &l ...