Overview and background
Windows provides very primitive tools for building user interfaces. The system provides a few basic controls and native window containers, but building a custom user interface is difficult. Since we desired a differentiated aesthetic for Chromium, we have had to build a framework on Windows to accelerate our development of custom UI. This system is called views.
views is a rendering system not unlike that used in WebKit or Gecko to render web pages. The user interface is constructed of a tree of components called Views. These Views are responsible for rendering, layout, and event handling. Each View in the tree represents a different component of the UI. An analog is the hierarchical structure of an HTML document.
At the root of a View hierarchy is a Widget, which is a native window. The native window receives messages from Windows, converts them into something the View hierarchy can understand, and then passes them to the RootView. The RootView then begins propagation of the event into the View hierarchy.
Painting and layout are done in a similar way. A View in the View tree has its own bounds (often imbued upon it by its containing View's Layout method), and so when it is asked to Paint, it paints into a canvas clipped to its bounds, with the origin of rendering translated to the View's top left. Rendering for the entire View tree is done into a single canvas set up and owned by the Widget when it receives a Paint message. Rendering itself is done using a combination of Skia and GDI calls — GDI for text and Skia for everything else.
Several UI controls in Chromium's UI are not rendered using Views, however. Rather, they are native Windows controls hosted within a special kind of View that knows how to display and size a native widget. These are used for buttons, tables, radio buttons, checkboxes, text fields, and other such controls. Since they use native controls, these Views are also not especially portable, except perhaps in API.
Barring platform-specific rendering code, code that sizes things based on system metrics, and so on, the rest of the View system is not especially unportable, since most rendering is done using the cross-platform Skia library. For historical reasons, many of View's functions take Windows or ATL types, but we have since augmented ui/gfx/ with many platform independent types that we can eventually replace these with.
总览与背景
Windows提供的构建用户界面的工具是非常落后的。虽然系统提供了一些基础控件以及原生的窗口容器,但是想要定制一个用户界面仍然非常困难。为了使得Chromium能够呈现出一个不同的外观,我们需要在windows上开发一套框架来提高我们开发定制的UI的速度。这套UI框架叫做views。
views是一个渲染系统,但是这个系统是渲染网页的引擎webkit以及Gecko有所不同。许多Views组成的一棵views树就构成了一个用户界面。其中,这些View组件负责了整个用户界面的渲染,布局甚至事件处理的任务。views树中的每一个view都是一个不同的UI组件。这套UI系统的逻辑结构与HTML document的框架非常相似。
在这些View的层次结构中,他们的根就是Widget,这是一个本地窗口。该窗口从Windows接受消息,将这些消息转换成View系统能处理的事件,并将事件传递给RootView。然后RootView开始按照View的层级一层层传递消息事件。
绘制和布局也是按照上述的过程进行的。在View树中的每一个View有其特定的区域(通常是调用它所包含的view的layout方法来填充),当接收到绘制的请求时,便向定位在它区域上的画布进行绘制。绘制的过程是从View的左上角开始。每个Widget都拥有一个唯一的画布,当Widget收到一个绘制消息,便将整个View树的内容绘制到这个画布中。渲染的过程是由Skia和GDI调用共同完成——GDI负责文本绘制,Skia负责其他部分的绘制。
然而,Chromium用户界面中有相当一部分UI控件是Windows系统组件,而不是用Views系统来绘制的。这些控件由一种特别的View(我觉得应该是windows窗口系统)控制他们的显示和大小。它们是buttons,tables,radio buttons,checkboxes,text fields 以及其他的控件。因为他们使用了系统控件,所以除了API,这些Views的其他部分不太好移植。
除了平台相关的渲染代码以外,还有一些代码与系统相关,譬如衡量视图尺寸的代码需要依赖平台相关的系统度量。View系统的其余部分的代码有相当一部分是可以一直的,因为大部分的渲染工作都是由跨平台的Skia库完成。由于历史的原因,许多View的函数使用了Windows编码形式或者ATL类型,但是自从我们在ui/gfx中增加了大量系统无关的类型后,我们最终会将这些系统相关的类型全部替换掉。Code Location and Info 代码路径与信息
The base set of classes and interfaces provided by views can be found in the src/ui/views/ directory. All base views classes are in the "views" namespace.
Common Widgets
- WidgetWin: The base class for all Widgets in views. Provides a basic child window control implementation. Subclass this directly if you are not making a top-level window or dialog.
- Window: A top-level window. A subclass of WidgetWin.
- BrowserFrame: A subclass of Window that provides additional message processing for the Browser window in Chrome. See Browser Window.
- ConstrainedWindowImpl: A subclass of Window that provides the frame for constrained dialogs such as the HTTP basic auth prompt.
通用Widget
- WidgetWin: view中所有Widget的基类。提供一个基本的孩子窗口控件的实现。如果创建的不是一个顶层窗口或者对话框的话,直接继承这个类即可。
- Window: 顶层窗口,一个WidgetWin的子类
- BrowserFrame: 一个Window的子类,提供Chrome中浏览器窗口附加的消息处理。参考Browser Window
- ConstrainedWindowImpl:Window的子类,提供了诸如授权提示这样的受约束对话框的框架(constrained window是限制在WebContentsView边界内的窗口)
Other approaches
At the start of the project, we began building the Chromium browser using native windows and the owner-draw approach used in many Windows applications. This proved to be unsatisfactory, since native windows don't support transparency natively, and handling events requires tedious window subclassing. Some early UI elements gravitated towards custom painting and event handling (e.g. Autocomplete), but this was very ad-hoc based on the circumstance.
Existing UI toolkits for Windows are similarly unsatisfying, with limited widget sets, unnatural aesthetics, or awkward programming models.
其他方法
Limitations/issues
By and large, views makes it relatively easy to build complex custom UIs. However it has a few rough edges that can be improved over time:
- The Event types currently are occasionally problematic - they crack the native windows message parameters and then discard them. Sometimes this information is useful.
- Some ad-hoc message processing.
- Mix of native controls that don't work properly until inserted into a View hierarchy attached to a Widget with a valid HWND. Many of our native controls have API methods that require them to exist within a window hierarchy. This means that they cannot be fully initialized until they are inserted. The View API will eventually be improved to make this clearer (bug 5191).
- The base Widget interface itself is somewhat frozen in time. Some improvement and consolidation would be worthwhile.
限制和问题
目前的事件类型偶尔会出现问题——破坏了本地窗口接收到消息的参数,使得这些参数被忽略了。某些这些参数信息是有用的。
- 一些特定的消息处理。
- 我们需要将混合使用的本地控件插入到一个绑定在有效HWND的Widget的View的层次结构中,这样这些控件才能工作。许多本地控件的API方法使用的前提是他们要在系统的窗口层次结构中。这意味着当这些控件在插入到View层级中之前是不能完全初始化的。我们会通过View API来改善这一问题。
- Widget基类自身的一部分接口总有一天会被冻结。一些改进和调整将会很有价值。