转载请注明出处: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. HTML前端

    1.<html>内容</html> 解释:HTML文档的文档标记,也成为HTML开始标记 功能:这对标记分别位于网页的最前端和最后端 <html>在最前段表示网页的 ...

  2. Unable to mount the CD/DVD image virtualbox解决方法

    转自: http://askubuntu.com/questions/321589/unable-to-mount-the-cd-dvd-image-on-the-machine-sandbox

  3. Nested List Weight Sum I & II

    Nested List Weight Sum I Given a nested list of integers, return the sum of all integers in the list ...

  4. 【转】JSP中的相对路径和绝对路径

    1.首先明确两个概念: 服务器路径:形如:http://192.168.0.1/的路径 Web应用路径:形如:http://192.168.0.1/yourwebapp的路径 2.关于相对路径与绝对路 ...

  5. cocos2d-x如何解决图片显示模糊问题

    转载http://zhidao.baidu.com/link?url=JTUKP5quGfMQixLZSvtC2XlKMkQDyQbYW72_DRyD6KDRpkLs8_6poQtKkwsyqzU8q ...

  6. php对象引用和析构函数的关系

    在php中构造函数和析构函数都属于魔术方法,比如构造函数在某一个类中,当这个类被实例化的时候就会自动调用,而析构函数是在这个类的对象被销毁的时候自动调用,默认情况下是在程序执行结束时自动调用. 如果我 ...

  7. Java操作Session与Cookie

    1,Java操作Session Java操作Session非常简单,步骤如下 1.1,在servlet中通过request获取session HttpSession session = request ...

  8. hadoop的关键进程

    hadoop集群中主要进程有master:   NameNode, ResourceManager,slaves:   DataNode, NodeManager,  RunJar, MRAppMas ...

  9. 用例视图 Use Case View(rose)

    找开Rose工具,选择用例视图  Use Case View 先看看这个视图下面都有哪些工具,都能做一些什么: 下面详细说一下: 用例视图下面有工具: 一:选择工具 二:文本框Text Box 三:注 ...

  10. struts2的s:iterator 标签 详解

    s:iterator 标签有3个属性:value:被迭代的集合id   :指定集合里面的元素的idstatus 迭代元素的索引1:jsp页面定义元素写法 数组或list <s:iterator ...