美文网首页
minigui 4.0 源代码分析(四)

minigui 4.0 源代码分析(四)

作者: RonZheng2010 | 来源:发表于2020-11-23 09:44 被阅读0次

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()初始化有效区域。

相关文章

网友评论

      本文标题:minigui 4.0 源代码分析(四)

      本文链接:https://www.haomeiwen.com/subject/asxpiktx.html