概述和背景
Windows 提供的用户界面构建工具非常原始。系统提供了一些基本的控件和原生窗口容器,但构建自定义用户界面相当困难。由于我们希望为 Chromium 提供与众不同的美学效果,因此我们必须在 Windows 上构建一个框架,以加速自定义 UI 的开发。这个系统称为 Views。
Views 是一个渲染系统,类似于 WebKit 或 Gecko 用于渲染网页的系统。用户界面由一棵称为 Views 的组件树构成。这些 Views 负责渲染、布局和事件处理。树中的每个 View 代表 UI 的不同组件,可以类比为 HTML 文档的层次结构。
在 View 层次结构的根部是一个 Widget,它是一个原生窗口。原生窗口从 Windows 接收消息,将其转换为 View 层次结构能够理解的内容,然后将其传递给 RootView。RootView 然后开始将事件传播到 View 层次结构中。
绘制和布局的过程类似。View 树中的一个 View 有其自己的边界(通常由其包含的 View 的布局方法赋予),因此当它被要求绘制时,它会在限制在其边界内的画布上绘制,并将渲染原点转换到 View 的左上角。整个 View 树的渲染在 Widget 接收到 Paint 消息时被设置和拥有的单个画布上完成。渲染本身使用 Skia 和 GDI 调用的组合完成——GDI 用于文本,Skia 用于其他所有内容。
然而,Chromium UI 中的几个 UI 控件并不使用 Views 渲染。相反,它们是托管在一种特殊的 View 中的原生 Windows 控件,这种 View 知道如何显示和调整原生控件的大小。这些控件用于按钮、表格、单选按钮、复选框、文本字段等。由于它们使用原生控件,因此这些 Views 在移植性方面并不强,除了 API 之外。
除平台特定的渲染代码、基于系统指标调整大小的代码等外,View 系统的其他部分具有较好的可移植性,因为大多数渲染是使用跨平台的 Skia 库完成的。出于历史原因,许多 View 的函数接受 Windows 或 ATL 类型,但我们已经在 ui/gfx/ 中增加了许多平台独立的类型,最终可以替换这些类型。
代码位置和信息
Views 提供的一组基本类和接口可以在 src/ui/views/
目录中找到。所有基本 Views 类都在 “views” 命名空间中。
常见的 Widgets
在 Views 框架中:
- WidgetWin: 所有 Views 中 Widget 的基类。提供了一个基本的子窗口控件实现。如果你不是创建顶级窗口或对话框,直接继承这个类。
- Window: 一个顶级窗口。WidgetWin 的子类。
有关使用 Window、CustomFrameWindow 等构建对话框和其他窗口化 UI 的更多信息,请参阅 Views 窗口化内容。
在 Chromium 浏览器前端:
- BrowserFrame: Window 的子类,为 Chrome 中的浏览器窗口提供额外的消息处理。参见浏览器窗口。
- ConstrainedWindowImpl: Window 的子类,为受限对话框(如 HTTP 基本身份验证提示)提供框架。
其他方法
在项目开始时,我们开始使用原生窗口和许多 Windows 应用程序中使用的自绘制方法来构建 Chromium 浏览器。这证明是令人不满意的,因为原生窗口不支持透明性,并且处理事件需要繁琐的窗口子类化。某些早期的 UI 元素倾向于自定义绘制和事件处理(例如自动完成),但这通常是基于具体情况的临时做法。
现有的 Windows UI 工具包同样不令人满意,控件集有限,美学效果不自然,或编程模型不便。
限制/问题
总体来说,Views 使构建复杂的自定义 UI 相对容易。然而,它还有一些需要随着时间改善的粗糙边缘:
- 事件类型目前有时存在问题——它们破解了原生 Windows 消息参数,然后丢弃了它们。有时这些信息是有用的。
- 一些临时的消息处理。
- 与原生控件的混合在插入到具有有效 HWND 的附加到 Widget 的 View 层次结构之前无法正常工作。我们的许多原生控件有需要它们存在于窗口层次结构中的 API 方法。这意味着在插入之前它们无法完全初始化。View API 最终将得到改进,以使这一点更清晰(bug 5191)。
- 基础的 Widget 接口本身有点停滞不前。一些改进和整合将是值得的。