chrome UI排版绘制消息分发机制剖析.docx
- 文档编号:10598521
- 上传时间:2023-02-21
- 格式:DOCX
- 页数:166
- 大小:1.12MB
chrome UI排版绘制消息分发机制剖析.docx
《chrome UI排版绘制消息分发机制剖析.docx》由会员分享,可在线阅读,更多相关《chrome UI排版绘制消息分发机制剖析.docx(166页珍藏版)》请在冰豆网上搜索。
chromeUI排版绘制消息分发机制剖析
ChromeUI框架分析
一、总体结构
1、概述
代码结构
UI部分的通用代码放在src/chrome/views目录下。
其中:
control目录中为各种控件,如Label、Textfield等,这个目录最为庞大。
widget目录中为系统相关的UI底层细节,特别是UI消息机制。
window目录中为UIFrame相关的细节,例如窗口的标题栏、系统按钮以及、Frame、Dialog等的代理接口。
focus目录下为焦点管理、快捷键相关代码。
animation中为与动画相关的代码。
主要特点
1、采用DUI技术,大部分窗口和控件都是DUI的。
2、虚窗口的基类是View,每个View可以包含子View,他们组织成一棵树结构。
3、真窗口的基类是Widget,它处理与操作系统相关的最原始的消息,在windows上,它处理所有窗口消息。
Window是顶层窗口的基类,包括气泡、漂浮窗口、对话框、主窗口等。
4、View树的根节点是RootView,这个View的主要用途就是从Widget中接收UI消息,进行分发,包括排版与绘制,它是整个窗口树的根。
5、NonClientView表示整个实际的窗口树的根,是RootView唯一的子节点。
RootView向上和OS层打交道,而NonClientView则专注于下层的控件View。
NonClientView表示整个非客户区的View,包括标题栏、窗口图标、关闭按钮、最大化与最小化按钮、边框等,它负责非客户区的排版与绘制,这类可以被派生,以实现各种不同的客户区。
ClientView是客户区的根,负责客户区的排版与绘制。
6、排版由专门的LayoutManager负责。
7、界面绘制上,绘制引擎(Canvas)与窗框系统分开。
可以根据实际情况使用不同的图形引擎(Skia与D2D)。
一般情况下,绘图采用Skia,字体用windows的GDI,Skia保证可以跨平台。
绘制引擎提供了裁剪、平移变换等机制,使得View可以只重绘一部分,而且支持紧急与非紧急绘制。
8、控件消息的响应采用Listener模式。
9、绘制通过任务机制实现,从Task派生出一个PaintTask,其Run函数中实现绘制,该任务被放到MessagePumpForUI的任务队列中,每次消息循环的时候取出来执行。
10、广泛采用设计模式,顶层窗口的实现大类运用了代理模式,复杂的界面元素采用MVC模式实现界面(排版、绘制、界面消息响应)与逻辑的分离。
UI核心类与模块的关系如下图所示:
UI的基础代码可以分为消息循环(MessagePumpForUI与MessageLoopForUI)、真窗口(Widget以及派生类)、虚窗口(View以及派生类)、窗口树的根(RootView以及派生类,它实际上是View的派生类)、消息分发与响应、排版(LayoutManager)、绘制(Canvas、CanvasPaint等)、焦点与快捷键管理(FocusManager)组成。
这些是UI最底层、最核心的模块,控件建立在这些模块的基础之上。
类的继承关系图
View是所有控件、子窗口(虚窗口)的基类。
View类的派生关系图:
这其中有一个庞大的分支为各种控件,具体有:
按钮Button
菜单Menu
滚动条ScrollBar
表格TableView
树控件TreeView
组合框ComboBox
列表框ListBox
编辑框TextField
静态控件Label
超链接控件Link
其中,树控件、编辑框采用windows自己的原生控件,其他控件均为DUI的。
但是有些控件,如按钮等,chrome还包装了windows的原生控件。
Widget是所有真窗口的基类,它负责窗口的消息映射、子窗口的管理,每个Widget有一个RootView,作为窗口树的根,管理其子窗口。
Widget类的派生关系图:
WidgetWin有两类派生类,分别是气泡与漂浮窗口(地址栏自动提示窗口、标签拖出去形成的新窗口、信息气泡、菜单);有标题栏与边框的窗口(对话框、主窗口)。
WindowWin是所有有标题栏与边框的窗口的基类(对话框、主窗口)。
WindowWin中有客户区(client_view_)与非客户区(frame_view_),WindowWin通过配置不同的客户区,可以形成不同的窗口。
WindowImpl是对窗口创建、风格与扩展风格、窗口过程管理的封装。
窗口的结构
窗口中最大的子窗口是RootView,它是窗口树的根,它有唯一的一个孩子NonClientView。
NonClientView是逻辑上的根,它有两个孩子NonClientFrameView和ClientView,前者是窗口的非客户区,负责非客户区的绘制、消息响应;后者是窗口的客户区,负责客户区的绘制、消息响应。
这种结构如下图所示:
各个类之间的关系如下图所示(虚线为包含,实线为继承):
WidgetWin中有成员变量root_view_(RootView),为其窗口树的根,而窗口在初始化时RootView通过SetContentsView设置其孩子节点NonClientView。
NonClientView有两个节点frame_view_(NonClientFrameView)与client_view_(ClientView),分别是窗口的客户区与非客户区,各自处理客户区与非客户区的消息、绘制、排版等。
WindowWin继承自WidgetWin,是有边框的窗口,其中有成员变量non_client_view_。
而WidgetWin并没有该成员,这是因为对于气泡等漂浮窗口,没必要划分客户区与非客户区。
非客户区与客户区View的派生关系如下图所示(虚线为包含,实线为继承):
ClientView有两个派生类,分别是DialogClientView与BrowserView,前者是对话框的客户区,后者是浏览器主窗口的客户区。
NonClientFrameView有4个派生类,其中GlassBrowserFrameView为毛玻璃效果的窗口,OpaqueBrowserFrameView为非透明的窗口。
窗口的风格
窗口的风格、扩展风格的计算由WindowWin类的的两个函数CalculateWindowStyle、CalculateWindowExStyle统一完成,最基本的风格是WS_CLIPCHILDREN(裁剪孩子)、WS_CLIPSIBLINGS(裁剪兄弟)。
主窗口是WS_OVERLAPPED/WS_OVERLAPPEDWINDOW;对话框是WS_POPUP、DS_MODALFRAME;可缩放的窗口是WS_OVERLAPPED、WS_THICKFRAME;控件等原生窗口为WS_CHILD。
2、View
View是View层次结构中的一个矩形区域,是所有View的基类。
View是其他View的容器。
View有一些基本属性,用于缩放、排版、绘制、事件分发等。
View采用简单的盒式排版管理器,类似于XUL的SprocketLayout系统。
基类只提供了抽象的接口,很由子类负责实现绘制、与子类相关的属性、函数。
View的的继承关系
classView:
publicAcceleratorTarget
AcceleratorTarget是一个虚基类,它有唯一一个成员函数AcceleratorPressed,用于处理快捷键消息。
因此,所有View都可以处理快捷键
View的主要数据成员
是否Eanable:
boolenabled_;
是否能够获得焦点:
boolfocusable_;
View所占的区域:
gfx:
:
Rectbounds_;注意,该区域是相对于其父窗口的坐标系。
是否需要排版:
boolneeds_layout_;
父节点:
View*parent_;
子节点数组:
ViewListchild_views_;
排版管理器,永于对子窗口的排版:
scoped_ptr
是否可见:
boolis_visible_;
背景:
scoped_ptr
边框:
scoped_ptr
是否被父亲拥有:
boolis_parent_owned_;
当可视区域改变时需要通知的后代View的列表:
scoped_ptr
该View的名字:
std:
:
wstringaccessible_name_;
按Tab键时下一个获得焦点的View:
View*next_focusable_view_;
按Shift-Tab键时下一个获得焦点的View:
View*previous_focusable_view_;
焦点管理器:
FocusManager*accelerator_focus_manager_;
快捷键列表:
scoped_ptr : vector size_tregistered_accelerator_count_; 右键菜单管理器: ContextMenuController*context_menu_controller_; 拖拽管理器,负责为View写拖拽数据,同时提供拖拽支持: DragController*drag_controller_; 窗口树的组织(黄色为父节点指针,蓝色为子节点指针): ContextMenuController右键菜单管理器为一个抽象接口,View中有这个成员,这使得所有View及其子类都具有显示、响应右键菜单的能力: classContextMenuController{ public: virtualvoidShowContextMenu(View*source, constgfx: : Point&p, boolis_mouse_gesture)=0; protected: virtual~ContextMenuController(){} }; 其中唯一一个成员函数是ShowContextMenu,用于为View显示右键菜单,其中source是要显示菜单的View的指针,p是菜单显示的位置,为屏幕坐标系。 DragController也是一个抽象的接口,负责为View的拖拽写数据,View中有这个成员,这使得所有View都支持拖拽。 classDragController{ public: //Writesthedataforthedrag. virtualvoidWriteDragData(View*sender, constgfx: : Point&press_pt, OSExchangeData*data)=0; //Returnsthesupporteddragoperations(seeDragDropTypesforpossible //values).Adragisonlystartedifthisreturnsanon-zerovalue. virtualintGetDragOperations(View*sender,constgfx: : Point&p)=0; //Returnstrueifadragoperationcanbestarted. //|press_pt|representsthecoordinateswherethemousewasinitially //presseddown.|p|isthecurrentmousecoordinates. virtualboolCanStartDrag(View*sender, constgfx: : Point&press_pt, constgfx: : Point&p)=0; protected: virtual~DragController(){} }; AcceleratorTarget为快捷键接收者,所有View都从其中派生,这使得所有View及其子类都具有处理快捷键的能力。 AcceleratorTarget的唯一一个成员函数为AcceleratorPressed,用于处理具体的快捷键,各个View可以重写此函数,用于处理自己的快捷键。 charView: : kViewClassName[]="views/View"; constintView: : kShowFolderDropMenuDelay=400; View的主要成员函数 基本属性相关: constgfx: : Rect&bounds()const{returnbounds_;} constgfx: : Size&size()const{returnbounds_.size();} voidSetBounds(constgfx: : Rect&bounds); voidSetBounds(intx,inty,intwidth,intheight) virtualgfx: : SizeGetPreferredSize(); virtualvoidSetVisible(boolflag); virtualboolIsVisible()const{returnis_visible_;} virtualvoidSetEnabled(boolflag); virtualboolIsEnabled()const; virtualboolIsPushed()const{returnfalse;} 排版相关: virtualvoidLayout(); 对本View进行排版,默认实现是调用排版管理器进行排版,这是一个虚函数,重载它可以实现各种不同的排版。 voidInvalidateLayout(); 为本View和所有父节点设置需要重拍版标记,这可以确保下次调用Layout()时可以传播到本View,即使父View的大小不变。 LayoutManager*GetLayoutManager()const; 获取本View的焦点管理器。 voidSetLayoutManager(LayoutManager*layout); 为本View设置焦点管理器。 绘制相关的函数: virtualvoidSchedulePaint(constgfx: : Rect&r,boolurgent); 将指定的区域标记为脏区域(需要重绘),如果urgent标志为true,则在当前事件处理完成后该区域马上被重绘,否则,会尽可能早的重绘。 virtualvoidSchedulePaint(); 将整个View标记为脏,将尽可能早的重绘。 virtualvoidProcessPaint(gfx: : Canvas*canvas); 这是绘制本View及其孩子的主入口函数。 该函数被绘制系统调用,只有需要绘制子树时才调用此函数。 virtualvoidPaint(gfx: : Canvas*canvas); 绘制本View virtualvoidPaintBackground(gfx: : Canvas*canvas); 绘制View的背景 virtualvoidPaintBorder(gfx: : Canvas*canvas); 绘制View的边框 virtualvoidPaintFocusBorder(gfx: : Canvas*canvas); 绘制焦点边框,如果本View有焦点。 默认的实现是在View周围绘制一个灰色的边框,重载该函数可以实现不同的效果。 virtualvoidPaintNow(); 立刻绘制本View。 子节点、父节点操作相关的函数: voidAddChildView(View*v); voidAddChildView(intindex,View*v); View*GetChildViewAt(intindex)const; voidRemoveChildView(View*v); voidRemoveAllChildViews(booldelete_views); intGetChildViewCount()const; boolHasChildView(View*a_view); virtualView*GetViewForPoint(constgfx: : Point&point); virtualWidget*GetWidget()const; virtualWindow*GetWindow()const; virtualboolContainsNativeView(gfx: : NativeViewnative_view)const; virtualRootView*GetRootView(); View*GetParent()const{returnparent_;} intGetChildIndex(constView*v)const; boolIsParentOf(View*v)const; virtualView*GetViewByID(intid)const; voidSetID(intid); intGetID()const; voidSetGroup(intgid); intGetGroup()const; virtualboolIsGroupFocusTraversable()const{returntrue;} voidGetViewsWithGroup(intgroup_id,std: : vector virtualView*GetSelectedViewForGroup(intgroup_id); 每个View的Layout函数用于定位它所有的子View。 当因为某些原因整个窗口需要重构时,根View调用Layout函数,然后递归调用每一个子View的Layout函数。 关于Chrome的Layout,Chrome还提供了一个GridLayout和FillLayout。 添加子节点的流程: voidView: : AddChildView(intindex,View*v) 如果v有父节点,则先从其父节点中删除 设置v的前一个、后一个焦点view 将v插入本节点的子节点数组中,并将v的父节点设置为本节点 从本节点一直循环上溯到根节点,调用ViewHierarchyChangedImpl PropagateAddNotifications 更新tooltips 为RootView调用RegisterChildrenForVisibleBoundsNotification 排版管理器调用ViewAdded 焦点、快捷键管理相关: View*GetNextFocusableView(); View*GetPreviousFocusableView(); voidSetNextFocusableView(View*view); virtualvoidSetFocusable(boolfocusable); boolIsFocusableInRootView()const; boolIsAccessibilityFocusableInRootView()const; virtualvoidset_accessibility_focusable(boolaccessibility_focusable) virtualFocusManager*GetFocusManager(); virtualvoidAddAccelerator(constAccelerator&accelerator); virtualvoidRemoveAccelerator(constAccelerator&accelerator); virtualvoidResetAccelerators(); virtualboolAcceleratorPressed(constAccelerator&accelerator) virtualboolHasFocus(); 工具函数: staticvoidConvertPointToView(constView*src, constView*dst, gfx: : Point*point); staticvoidConvertPointToWidget(constView*src,gfx: : Point*point); staticvoidConvertPointFromWidget(constView*dest,gfx: : Point*p); staticvoidConvertPointToScreen(constView*src,gfx: : Point*point); 事件处理函数: virtualboolOnMousePressed(constMouseEvent&event); virtualboolOnMouseDragged(constMouseEvent&event); virtualvoidOnMouseReleased(constMouseEvent&event,boolcanceled); virtualvoidOnMouseMoved(constMouseEvent&e); virtualvoidOnMouseEntered(constMouseEvent&event); virtualvoidOnMouseExited(constMouseEvent&event); virtualvoidSetMouseHandler(View*new_mouse_handler); virtualvoidRequestFocus(); virtualvoidWillGainFocus(); virtualvoidDidGainFocus(); virtualvoidWillLoseFocus(); virtualvoidAboutToRequestFocusFromTabTraversal(boolreverse) virtualboolSkipDefaultKeyEventProcessing(constKeyEvent&e) virtualboolOnKeyPressed(constKeyEvent&e); virtualboolOnKeyReleased(constKeyEvent&e); virtualboolOnMouseWheel(constMouseWheelEvent&e); 拖拽相关: voidSetDragControl
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- chrome UI排版绘制消息分发机制剖析 UI 排版 绘制 消息 分发 机制 剖析