1. 设备描述表
1.1 DC
DC (Device Context,设备描述表)向使用者提供绘制接口,除一组函数集,还包括与绘图方式有关的对象,比如画笔、笔刷、调色板、剪裁区域等。
- 成员DCType是DC类型。可取值包括TYPE_SCRDC、TYPE_GENDC和TYPE_MEMDC。
- 成员surface是用于绘制的设备表面,也就是GAL_Surface。
- 成员pLogFont是字体对象,这是一个LOGFONT实例。
- 成员rop与光栅操作(raster operation)有关。用rop从函数数组draw_pixel_ops[]、draw_pixel_span_ops[]等数组中,选择对应的光栅操作函数,来初始化成员函数cb_comp_set_pixel()、cb_comp_set_h_line()等。
- 成员lcrgn、ecrgn是剪裁区域。
minigui预定义两个全局的DC实例,一个是__mg_screen_dc,一个是__mg_screen_sys_dc。
用户创建的DC则保存在全局数组DCSlot[]中。
DC DCSlot [16];
DC __mg_screen_dc;
DC __mg_screen_sys_dc;
1.2 HDC
HDC是DC的句柄。它有三类取值。
dc_HDC2PDC()可以从DC句柄得到DC实例。
#define HDC_SCREEN ((HDC)0)
#define HDC_SCREEN_SYS ((HDC)1)
PDC dc_HDC2PDC (HDC hdc)
{
if (hdc == HDC_SCREEN_SYS)
return &__mg_screen_sys_dc;
else if (hdc == HDC_SCREEN)
return &__mg_screen_dc;
return (PDC) hdc;
}
1.3 get_valid_dc()
get_valid_dc()得到窗口DC的句柄。如果需要,调用GetDC()等函数创建DC实例。
1.4 GetDC()
-
遍历DCSlot[],找到空闲的DC实例。 将DC的成员surface设置为全局变量__gal_screen。
GAL_Surface* __gal_screen;
在mg_InitGAL()函数中,将__gal_screen设置为GAL_VideoDevice的成员surface。
// newgal.c
int mg_InitGAL (char* engine, char* mode)
{
if (!(__gal_screen = GAL_SetVideoMode (w, h, depth, GAL_HWPALETTE))) {
}
...
}
- 调用dc_InitDC()初始化它。其中,
- 调用GAL_MapRGB()初始化DC的颜色对象。
- 调用GetWindowFont()检查字体,如果没有设置,则调用GetSystemFont()得到系统字体。
- 根据DC的成员rop的值,从函数数组中选择相应的函数,设置cb_comp_set_pixel()、cb_comp_set_h_line()、dc_move_to()等。
- 调用kernel_GetGCRgnInfo()得到窗口剪裁区域,并调用ClipRgnCopy()设置DC的有效剪裁区域。
1.5 GetClientDC()
GetClientDC()的实现与GetDC()一样。
1.6 GetSecondarySubDC()
GetSecondarySubDC()基于指定的secondary DC,得到子窗口的DC实例。
-
调用dc_HDC2PDC(),从指定的secondary DC句柄得到DC实例。
-
遍历数组DCSlot[],得到空闲的DC实例,作为子窗口的DC。
-
调用gui_WndRect()分别得到父窗口和子窗口的区域,计算子窗口相对于父窗口的偏移,从而设置子窗口的DC区域。
-
设置子窗口DC的成员surface,指向父窗口的surface。
-
调用dc_InitMemDCFrom(),基于窗口的DC,初始化子窗口的DC。
- dc_InitMemDCFRom()从源DC中复制颜色,位置等属性,还设置DC的成员函数cb_comp_set_pixel()、cb_comp_set_h_line()等。
-
调用EmptyClipRgn()和InitClipRgn(),初始化子窗口DC的剪裁区域。调用CopyRegion(),复制窗口的剪裁区域到子窗口。
1.7 mg_InitScreenDC()
mg_InitScreenDC()初始化预定义的DC实例__mg_screen_sys_dc和__mg_screen_dc。
- 调用InitFreeClipRectList()初始化全局的BLOCKHEAP堆__mg_FreeClipRectList,其中的数据块为CLIPRECT。
- 调用dc_InitClipRgn(),初始化DCSlot[]中的DC的剪裁区域,包括本地区域、有效区域。
- 调用dc_InitScreenDC(),其中,
- 根据Surface的位置和大小,调用SetClipRgn()设置DC的有效区域。
- 设置DC的成员函数cb_comp_set_pixel()、cb_comp_set_h_line()等。
2. 剪裁区域
可以指定一块区域,让DC绘制时不超出这个区域。这个区域就是剪裁区域CLIPRGN。
-
CLIPRGN由一系列剪裁矩形CLIPRECT的链表组成。成员head和tail是这个链表的头和尾。
-
新分配CLIPRECT结构时,从成员heap指定的BlOCKHEAP实例中得到它。 成员heap指向全局堆__mg_FreeCIipRectList。
BLOCKHEAP __mg_FreeClipRectList;
-
成员rcBound是覆盖所有CLIPRECT的最小矩形区域。
2.1 InitClipRgn()
InitClipRgn()初始化CLIPRGN实例。
- 调用SetRectEmtpy()将成员rcBound置空。
- 指定成员heap,也就是从哪里分配CLIPRECT。
2.2 SetClipRgn()
SetClipRgn()设置CIPRGN的区域。
- 调用EmptyClipRgn(),将成员head指向的链表中的CLIPRECT实例全部释放。
- 调用ClipRectAlloc()从成员heap中分配CLIPRECT实例,并赋值为指定的RECT。
- 将CLIPRECT实例链入head链表。
dc_InitClipRgn()初始化全局数组DCSlot[]中DC的剪裁区域。
它遍历DCSLot[],对其中的DC,
- 调用InitClipRgn()初始化本地区域,将成员heap设置为__mg_FreeClipRectList。
- 调用MAKE_REGION_INFINITE()设置本地区域为无限大。
- 调用InitClipRgn()初始化有效区域。
网友评论