Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1465193
  • 博文数量: 267
  • 博客积分: 3010
  • 博客等级: 少校
  • 技术积分: 3089
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 17:09
个人简介

尊天命,尽人事

文章分类

全部博文(267)

文章存档

2017年(6)

2015年(4)

2014年(27)

2013年(52)

2012年(59)

2011年(120)

分类: LINUX

2013-06-13 20:29:42

原文:http://blog.csdn.net/doon/article/details/8964750

虽然MiniGUI的应用范围越来越窄,很多功能和思想都落后于时代的发展,但是,作为一款开源的优秀的GUI库,具有很好的学习和参考价值。基于这个考虑,在我忘掉MiniGUI之前,把我所知道的写下来。

前言

熟悉windows的朋友都了解,GDI对外提供一个HDC的DC句柄。DC为(Device Context)的缩写,表示一个抽象的设备当前绘图情况。

一般情况下,屏幕、打印设备、内存像素都可以抽象出一个HDC句柄。 一个设备可以抽象多个HDC句柄,每个HDC句柄,都有自己独立的上下文信息。

在MiniGUI中,从窗口创建的DC都称为硬件DC,而从位图或者其他DC衍生的DC,称为MemDC。


注:MiniGUI源码目录中有gdi和newgdi两个目录。其中gdi已经被废弃,newgdi是目前使用的。但gdi和newgdi很多文件和函数名都是一样的,容易发生混淆,阅读源码时,要注意区分。


通常,在DC中保存的上下文信息有

当前点,当调用LineTo一类函数时,会绘制一条从当前点到LineTo指定参数的线。可以通过MoveTo来改变;

当前画笔的属性,如:画笔宽度(SetPenWidth), 颜色(SetPenColor),线段连接类型(SetPenJoinStyle), 线段端点的类型(SetPenCapStyle)

当前画刷的属性,如:画刷类型(SetBrushType),颜色(SetBrushColor),等

当前文字的信息:如,选择当前字体(SelectFont),文字颜色(SetTextColor)等

当前剪切域信息:如,SelectClipRect, SelectClipRgn等

逻辑坐标的信息:如,SetWindowOrg,SetWindowExt等。


几乎所有绘图函数,都是通过HDC来操作的。


HDC及tagDC

HDC只是一个简单的句柄,被定义为


[cpp]
  1. typedef unsigned long HDC;  

而它真正对应的结构体就是tagDC。 HDC就是将tagDC的指针转为unsigned long后的值


tagDC的定义如下


[cpp]
  1. /* Device Context */  
  2. struct tagDC  
  3. {  
  4.     short DataType;  /* the data type, always be TYPE_HDC */  
  5.     short DCType;    /* the dc type */  
  6.               
  7.     BOOL inuse; //对于硬件DC,它从一个固定长度的数组缓存中获取一个DC对象。inuse TRUE表示这个DC已经被分配出去了,FALSE表示空闲。这是为了避免频繁调用malloc和free函数。   
  8.     HWND hwnd; //和硬件DC关联的 (DCType == TYPE_GENDC)   
  9.   
  10.     /* surface of this DC */  
  11.     GAL_Surface* surface; //DC所依赖的surface,最重要的数据结构   
  12.   
  13.     /* background color */  
  14.     gal_pixel bkcolor;  
  15.   
  16.     /* pen color */  
  17.     gal_pixel pencolor;  
  18.   
  19.     /* solid brush color */  
  20.     gal_pixel brushcolor;  
  21.   
  22.     /* text color */  
  23.     gal_pixel textcolor;  
  24.   
  25.     int bkmode;  
  26.   
  27.     int tabstop;  
  28.     int cExtra;     /* Character extra */  
  29.     int alExtra;    /* Above line extra */  
  30.     int blExtra;    /* Bellow line extra */  
  31.   
  32.     int mapmode;    /* mappping mode */  
  33.   
  34.     int ta_flags;   /* Text alignment flags */  
  35.   
  36. #ifdef _MGHAVE_ADV_2DAPI   
  37.     /* pen attributes */  
  38.     int pen_type;  
  39.     int pen_cap_style;  
  40.     int pen_join_style;  
  41.     unsigned int pen_width;  
  42.   
  43.     /* brush attributes */  
  44.     int brush_type;  
  45.   
  46.     POINT brush_orig;  
  47.     const BITMAP* brush_tile;  
  48.     const STIPPLE* brush_stipple;  
  49.   
  50.     /* custom dash info */  
  51.     int dash_offset;  
  52.     const unsigned char* dash_list;  
  53.     size_t dash_list_len;  
  54. #endif   
  55.   
  56.     PLOGFONT pLogFont;  
  57.   
  58.     POINT CurPenPos;  
  59.     POINT CurTextPos;  
  60.   
  61.     POINT ViewOrig;  
  62.     POINT ViewExtent;  
  63.     POINT WindowOrig;  
  64.     POINT WindowExtent;  
  65.   
  66.     /* raster operation */  
  67.     int rop;  
  68.   
  69.     /* used by the text rendering for anti-aliasing fonts. */  
  70.     gal_pixel gray_pixels [17];  
  71.     /* used by the text rendering for low-pass filtering. */  
  72.     gal_pixel filter_pixels [17];  
  73.     GAL_PixelFormat* alpha_pixel_format;  
  74.   
  75.     /* pixel and line operation */  
  76.     CB_COMP_SETPIXEL draw_pixel;  
  77.     CB_COMP_SETHLINE draw_pixel_span;  
  78.     CB_COMP_PUTHLINE draw_src_span;  
  79.     DC_MOVE_TO move_to;  
  80.     DC_STEP_X  step_x;  
  81.   
  82.     /* === context information. ============================================= */  
  83.     /* DK[01/22/10]:This segment is binary compatible with _COMP_CTXT struct */  
  84.     int step;  
  85.     gal_uint8* cur_dst;  
  86.     gal_pixel skip_pixel;  
  87.     gal_pixel cur_pixel;  
  88.     void * user_comp_ctxt;  
  89.     /* ====================================================================== */  
  90.   
  91.     CLIPRECT* cur_ban;  
  92.     RECT rc_output;  
  93.   
  94.     /* local clip region information */  
  95.     CLIPRGN  lcrgn;  
  96.   
  97.     /* effective clip region information */  
  98.     CLIPRGN  ecrgn;  
  99.   
  100.     /* device rect */  
  101.     BOOL bIsClient;  
  102.     RECT DevRC;  
  103.   
  104.     PGCRINFO pGCRInfo;  
  105.     unsigned int oldage;  
  106.   
  107.     CB_BITMAP_SCALER_FUNC bitmap_scaler; //图片绘制所使用的数据结构   
  108. };  



和窗口相关的DC

和窗口相关的DC,有几个重要函数:

BeginPaint/EndPaint, GetDC, GetClientDC/ReleaseDC。还有一种PrivateDC,是一个历史遗留的DC,现在几乎不使用,不必考虑它。


BeginPaint/EndPaint是必须用在窗口回调的MSG_PAINT消息中的。之所以这样做,是因为BeginPaint会清除窗口的无效区域(详细了解 MiniGUI源码分析--Helloworld(3):消息概览)。

GetDC针对整个窗口,而GetClientDC则针对客户区。 这两个函数在MSG_CREATE消息中和所有的key, mouse消息等都可以使用。但是对于 MSG_NCCREATE, MSG_SIZECHANGING的极个别消息不能使用。

这些DC创建方法大同小异,我以GetClientDC为例来说明

[cpp]
  1. HDC GUIAPI GetClientDC(HWND hWnd)  
  2. {  
  3.     int i;  
  4.   
  5. #ifndef _LITE_VERSION   
  6.     pthread_mutex_lock (&dcslot);  
  7. #endif   
  8.     for (i = 0; i < DCSLOTNUMBER; i++) { //从固定缓冲区分配   
  9.         if (!DCSlot[i].inuse) {  
  10.             DCSlot[i].inuse = TRUE;  
  11.             DCSlot[i].DataType = TYPE_HDC;  
  12.             DCSlot[i].DCType   = TYPE_GENDC;  
  13.             break;   
  14.         }  
  15.     }  
  16. #ifndef _LITE_VERSION   
  17.     pthread_mutex_unlock (&dcslot);  
  18. #endif   
  19.   
  20.     if (i >= DCSLOTNUMBER)  
  21.         return HDC_SCREEN;  
  22.   
  23.     dc_InitDC (DCSlot + i, hWnd, TRUE); //这是关键函数   
  24.     return (HDC) (DCSlot + i);  
  25. }  
GetClientDC和GetDC都是通过dc_InitDC来初始化的,这是DC创建的关键点 (请仔细看注释)


[cpp]
  1. /* This function initializes a DC: set the default parameters. */  
  2. static void dc_InitDC (PDC pdc, HWND hWnd, BOOL bIsClient)  
  3. {  
  4.     PCONTROL pCtrl;  
  5.     CLIPRGN ergn;  
  6.   
  7.     pdc->hwnd = hWnd; //关联窗口   
  8.   
  9.     //初始化上下文代码的内容,基本可以跳过不看   
  10.     memset (pdc->gray_pixels, 0, sizeof (pdc->gray_pixels));  
  11.     memset (pdc->filter_pixels, 0, sizeof (pdc->filter_pixels));  
  12.   
  13.     pdc->bkcolor = GAL_MapRGB (pdc->surface->format, 0xFF, 0xFF, 0xFF);  
  14.     pdc->bkmode = 0;  
  15.   
  16.     pdc->pencolor = GAL_MapRGB (pdc->surface->format, 0x00, 0x00, 0x00);  
  17.     pdc->brushcolor = GAL_MapRGB (pdc->surface->format, 0xFF, 0xFF, 0xFF);  
  18.   
  19.     pdc->textcolor = GAL_MapRGB (pdc->surface->format, 0x00, 0x00, 0x00);  
  20.     if (!(pdc->pLogFont = GetWindowFont (hWnd)))  
  21.         pdc->pLogFont = GetSystemFont (SYSLOGFONT_WCHAR_DEF);  
  22.     pdc->tabstop = 8;  
  23.     pdc->CurTextPos.x = pdc->CurTextPos.y = 0;  
  24.     pdc->cExtra = pdc->alExtra = pdc->blExtra = 0;  
  25.   
  26.     pdc->mapmode = MM_TEXT;  
  27.     pdc->ta_flags = TA_LEFT | TA_TOP | TA_NOUPDATECP;  
  28.   
  29.     pdc->ViewOrig.x = pdc->ViewOrig.y = 0;  
  30.     pdc->ViewExtent.x = pdc->ViewExtent.y = 1;  
  31.     pdc->WindowOrig.x = pdc->WindowOrig.y = 0;  
  32.     pdc->WindowExtent.x = pdc->WindowExtent.y = 1;  
  33.   
  34. #ifdef _MGHAVE_ADV_2DAPI   
  35.     pdc->pen_type = PT_SOLID;  
  36.     pdc->pen_cap_style = PT_CAP_BUTT;  
  37.     pdc->pen_join_style = PT_JOIN_MITER;  
  38.     pdc->pen_width = 0;  
  39.     pdc->dash_offset = 0;  
  40.     pdc->dash_list = NULL;  
  41.     pdc->dash_list_len = 0;  
  42.   
  43.     pdc->brush_type = BT_SOLID;  
  44.     pdc->brush_orig.x = pdc->brush_orig.y = 0;  
  45.     pdc->brush_tile = NULL;  
  46.     pdc->brush_stipple = NULL;  
  47. #endif   
  48.   
  49.     /* Assume that the local clip region is empty. */  
  50.     /* Get global clip region info and generate effective clip region. */  
  51.     if (dc_IsGeneralDC (pdc)) {  
  52.         RECT minimal;  
  53.   
  54.         pdc->pGCRInfo = kernel_GetGCRgnInfo (hWnd);  
  55.         LOCK_GCRINFO (pdc);  
  56.   
  57.         pdc->oldage = pdc->pGCRInfo->age;  
  58.         ClipRgnCopy (&pdc->ecrgn, &pdc->pGCRInfo->crgn);   
  59.   
  60.         pdc->bIsClient = bIsClient;  
  61.         if (bIsClient)  // 限制DC的剪切域为客户区/整个窗口   
  62.             WndClientRect (pdc->hwnd, &pdc->DevRC);  
  63.         else  
  64.             WndRect (pdc->hwnd, &pdc->DevRC);  
  65.   
  66.         minimal = pdc->DevRC;  
  67.   
  68.         pCtrl = gui_Control (pdc->hwnd);  
  69.   
  70.         if (pCtrl && !(pCtrl->dwExStyle & WS_EX_CTRLASMAINWIN))  
  71.         {  
  72.             InitClipRgn (&ergn, &__mg_FreeClipRectList);  
  73.   
  74.             if (RestrictControlECRGNEx (&minimal, pCtrl, &ergn)) {  
  75.                 ClipRgnIntersect (&pdc->ecrgn, &pdc->ecrgn, &ergn);  
  76.                 EmptyClipRgn (&ergn);  
  77.             }  
  78.             else {  
  79.                 EmptyClipRgn (&pdc->ecrgn);  
  80.             }  
  81.         }  
  82.         else {  
  83.             IntersectClipRect (&pdc->ecrgn, &minimal);  
  84.         }  
  85.   
  86.         UNLOCK_GCRINFO (pdc);  
  87.     }  
  88.   
  89.     /* context info and raster operations. */  
  90.     pdc->CurPenPos.x = pdc->CurTextPos.x = 0;  
  91.     pdc->CurPenPos.y = pdc->CurTextPos.y = 0;  
  92.   
  93.     //设置图像和背景的混合方法,同windows中的 NOT画笔、异或笔等类型的功能   
  94.     pdc->rop = ROP_SET;  
  95.     pdc->step = 1;  
  96.     //每种混合方式都有对应的函数,这是为了提高绘制速度   
  97.     pdc->draw_pixel = draw_pixel_ops [pdc->rop]    
  98.         [pdc->surface->format->BytesPerPixel - 1];  
  99.     pdc->draw_pixel_span = draw_pixel_span_ops [pdc->rop]  
  100.         [pdc->surface->format->BytesPerPixel - 1];  
  101.     pdc->draw_src_span = draw_src_span_ops [pdc->rop]  
  102.         [pdc->surface->format->BytesPerPixel - 1];  
  103.     //设置dc的像素起点值   
  104.     pdc->cur_dst = (BYTE*)pdc->surface->pixels   
  105.             + pdc->surface->pitch * pdc->DevRC.top  
  106.             + pdc->surface->format->BytesPerPixel * pdc->DevRC.left;  
  107.   
  108.     pdc->move_to = move_to_ops [pdc->surface->format->BytesPerPixel - 1];  
  109.     pdc->step_x = step_x_ops [pdc->surface->format->BytesPerPixel - 1];  
  110.   
  111.     pdc->alpha_pixel_format = NULL;  
  112.     SetBitmapScalerType((HDC)pdc, BITMAP_SCALER_DDA); //设置默认的位图缩放算法:DDA 这是一种速度快但是效果差的缩放算法   
  113. }  

这里,值得一提的是关于HDC如何确定像素的内存地址的。这需要一个重要的概念:pitch。pitch表示一行像素的字节宽度(单位为字节)。


像素在显存(内存)中,是一段连续的内存。如 800x600-16bpp的一个屏幕,它的像素占用的内存是 800*2*600 = 960000 byte。 每一行占用的字节数为800x2 = 1600。那么,它的pitch=1600。

pitch和3个因素相关:像素矩阵的宽度、单个像素占用的字节数和对齐。在32位设备上,每一行像素必须是4的倍数。宽度为799的像素矩阵,其pitch = 1600,因为最后两个字节因为对其的原因,必须是补充进来。


上图中,外层为屏幕的surface的像素矩阵;内层位DC的大小和位置。DecRC表示的DC在surface中的大小和位置。


cur_dst的像素指针为

[cpp]
  1. pdc->cur_dst = (BYTE*)pdc->surface->pixels   
  2.          + pdc->surface->pitch * pdc->DevRC.top  
  3.          + pdc->surface->format->BytesPerPixel * pdc->DevRC.left;  
如果要计算DC中某个点(a,b)的像素位置,只要进行如下运算:



[cpp]
  1. pixel = cur_dst + a + b * pitch;  


兼容的MemDC

兼容的概念指,创建的内存DC的像素格式和屏幕的像素格式一样。

创建兼容DC,使用CreateCompatibleDCEx。这个函数,接受一个HDC参数(可以是任意一个有效的HDC)。

它们的实际实现是,根据传递的DC类型,创建一个和DC的像素格式一样的内存DC。 

但是CreateComnpatibleDCEx将直接分配内存来供新的DC来使用。


自定义的MemDC

另外,我们还可以创建的DC包括CreateMemDCEx和CreateMemDCFromBitmap。CreateMemDC(CreateMemDCEx)这个函数会为dc生成专门的surface,而CreateMemDCFromBitmap则利用位图的像素矩阵作为surface。 这样做就可以在一个位图上绘制信息了。


Sub DC

SubDC的含义为子DC。即在原DC的基础上,创建一个区域小于或者等于原DC的新DC。这个DC将继承原DC的所有属性值。SubDC和原DC都基于同一个surface,这样,SubDC和原DC都可以在同一位置绘制了。

SubDC的概念来自于java的AWT。主要用于窗口的绘制(从父窗口向子窗口绘制时,创建一个SubDC,可以避免子窗口的绘制上下文污染父窗口)

涉及的函数包括 GetSubDC(针对BeginPaint, GetDC和GetClientDC得到的dc)和CreateSubMemDC。


Secondary DC

SecondaryDC是在MiniGUI 3.0引入的。它是和窗口关联的一个后备缓冲区。起到的作用是防止闪烁(实际有限)和在窗口不可见的情况下获取窗口的内容(目的是为了实现窗口特效)。

SecondaryDC只有主窗口才有,子窗口是没有SecondaryDC的。通过给窗口的扩展风格,增加WS_EX_AUTOSECONDARYDC(必须在窗口创建时),可以自动创建一个SecondaryDC。 通过GetSecondaryDC能够获取到该DC。


个人认为SecondaryDC的设置不是很成功,读者不需要给予过多关注。

阅读(4245) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~