DirectFB 源码解读之字体-1

来源:互联网 发布:长春 跑腿软件 编辑:程序博客网 时间:2024/05/18 01:08
转载时请表明原文出处(http://blog.sina.com.cn/wyw1976)及作者邮箱(wyw1976@gmail.com)
 
    我们在DirectFB初始化中了解到gfx driver, input driver等都是在DirectFBCreate()时完成初始化,也就是说在用户真正使用之前,这些driver已经准备就绪。
    而字体(font)与此不同,只有用户明确使用字体时,才会进行初始化及资源分配,类似还有Image和Video,在DirectFB中它们通称为Interface。源码对应的目录就是DirectFB-1.4.0/Interfaces。
    在DirectFB运行环境中,interface的存在形式也是动态链接库。对应的目录是:lib/directfb-1.4.0/interfaces/IDirectFBFont等。
 
    当前的directfb支持三种字体文件:
   (1)FreeType2。有关freetype2的资料,可以参考官方网站:http://freetype.sourceforge.net/。
    (2) DGIFF字体。 DGIFF是DirectFB Glyph Image File Format的简称,从名字就可以看出,这是DirectFB所特有的一种字体格式。 DFB在tools目录中有一个mkdgiff可以将TrueType的字体文件转化为一个DGIFF字体文件。(命令为:./mkdgiff -f A8 -s 10,20,30 one.ttf > one.dgiff, 将字体文件one.ttf转化为DGIFF格式,结果保存在one.dgiff中,指定字体的格式是A8, 大小支持10,20,30),DGIFF与FreeType2的一个重要区别是FreeType2可以支持无限大小的字体,而DGIFF只支持一定个数的字体大小,例如对于上面的one.dgiff它只支持10,20或30,三种大小的字体。
    (3) 缺省字体。如果系统不支持FreeType2, 也不想是使用DGIFF,则可以使用DFB中提供了一种缺省字体,这种字体固定大小的,也就是说指定是non-scalable的字体。
 
    DFB使用字体的一个例子:
   
    DirectFBInit( argc, argv );
    DirectFBCreate( &dfb );
//创建字体对象
    font_dsc.flags = DFDESC_HEIGHT;
    font_dsc.height = 10;
    dfb->CreateFont (dfb, "my.ttf", &font_dsc, &font_1);
 
    dfb->CreateSurface(dfb, &sdsc, &f_surface);
    f_surface->Clear(f_surface, 0x0, 0, 00, 0);    
//将字体对象与surface关联
    f_surface->SetFont(f_surface, font_1);
    f_surface->SetColor(f_surface, 0xff, 0, 0, 0);
//画字体
    f_surface->DrawString(f_surface, "1234567890", -1, 0, 50, DSTF_LEFT);
    f_surface->Flip(f_surface, NULL, DSFLIP_WAITFORSYNC );
 

    如果在调用CreateFont() 时,字体文件设为NULL,则DFB会自动调用Default font即缺省字体,而这时的font_dsc.height 是不起作用的。


我们以DFB中的FT2为例,研究一下DFB与字体库之间的分工。
先看一个使用FT2的例子:
  FT_Init_FreeType( &library );
  FT_New_Face( library, "example.ttf", 0, &face );
  FT_Set_Char_Size( face, 20*64, 0,72, 0 );
  FT_Load_Char( face, 'M', FT_LOAD_RENDER );
 //to show the Char
  FT_Done_Face    ( face );
  FT_Done_FreeType( library );
 
总结下来,FT2画一个字符,需要经过的步骤:
(1)初始化FT库。
(2)根据指定的字体文件创建一个FACE。如果字体文件不是FT2支持的,则创建失败。
 (3) 设定字体的大小。字体的高度或宽度单位是1/64像素,而resolution的单位是dpi
(4)加载指定的字符。其结果存放在face->glyph->bitmap中,这时就可以对一个字符进行一些处理如显示等
 (5)释放资源。
 
从上面FT2的处理过程我们看出,有一些事情FT2并没有处理:
(1)字符的显示。这是涉及到字符显示的颜色,字符显示的格式转换,字符显示的位置等
(2)字符的缓存。在上面的例子中FT_Load_Char()是相对比较耗时的操作,而在使用字体是,往往很多字符是重复的,如果对于重复的字符,将bitmap的结果保存下来,就不需要每次都调用FT_Load_Char
(3)字符串的分解。FT2处理的是单个字符,而用户往往使用的是字符串,FT不支持字符串分解为字符的操作。
 上面这三种工作是所有的字体库都不支持但却是必须的, 他们会由DFB完成。另外,作为一个框架,DFB还支持多种字体库。


前面我们了解了DFB字体的用法以及DFB与字体库的关系,现在我们进入代码,看看DFB是如何具体管理
字体的。
  
    实际上,DFB所有与字体有关的逻辑,几乎可以被下面这几句调用所覆盖:
   (1)  dfb->CreateFont(dfb, "myfont.ttf", desc, &myfont);
   (2)  mysurface_1->SetFont(mysurface_1, myfont);
   (3)  mysurface_1->DrawString(mysurface_1, "aAbB", -1, 50, 100, DSTF_LEFT);
   (4)  mysurface_2->SetFont(mysurface_2, myfont);
   (5)  mysurface_2->DrawString(mysurface_2, "aAbB", -1, 50, 150, DSTF_LEFT);
  
 第一句,创建字体对象,需要指定一个字体文件,以及在desc中指定字体大小
 第二句, 将字体与surface_1关联,以后该surface上调用DrawString()或DrawGlyph()都会用这个字体
 第三句,在surface_1的指定位置(50,100)输出字符串
 第四句,将字体与surface_2关联
 第五句,在surface_2的指定位置(50, 150)输出同样的字符串,虽然第三句和第五局的调用几乎完全相
         同 ,但在DFB中的流程却完全不一样,第五句与字体库没有任何关系,直接是从DFB缓存中提取字
         体图像的。
 
 
创建字体对象
    我们知道, DFB支持三种字体:DGIFF, FT2和default font。在创建字体对象之前,首先调用
DirectGetInterface(),找到合适的字体interface。其过程与gfxdriver及input driver类似,就是依次
打开lib\Direct-1.4.0\Interface\IDirectFBFont目录中的每一个动态链接库(每个动态链接库实现了一种
字体interface,对应一种字体库), 然后调用动态库中的Probe函数来判断当前的动态库是否与
CreateFont中指定的字体文件匹配。
    对于Default Font, 如果字体文件为NULL, 则匹配
    对于DGIFF, 如果字体文件头中包含字符串"DGIFF", 则匹配
    对于FT2, 如果FT_NEW_FACE()调用成功,则匹配。(FT_NEW_FACE()是FT2中的一个标准函数,其作用是
根据字体文件创建一个FACE),因此对于FT2,DFB直接将问题直接踢给了FT2。


    在找到合适的字体interface后,就会调用该interface的Construct()函数。我们以FT2为例看看
Construct的实现。
   
     FT2的Construct()首先会调用FT_Init_FreeType()初始化FT2字体库,接着调用FT_New_Face()创建一个FACE,然后调用FT_Set_Char_Size()设置字体大小,这些调用都是与FT2字体库有关的。
     接着Constrct()调用dfb_font_create()创建一个CoreFont,初始化这个数据结构。为了以后的代码
解读,我们有必要看看这个数据结构的一些重要字段:
 
 
struct _CoreFont {
.............
     DFBSurfaceBlittingFlags       blittingflags;
     CardState                     state;        
     DFBSurfacePixelFormat         pixel_format;
     DFBSurfaceCapabilities        surface_caps;
//CoreFontCacheRow是DFB字体中的一个重要结构,是实际存放字体图像的地方。每个CoreFontCacheRow包
含一个surface(实际上就是一块buffer),每个字符在FT2中对应一张bitmap图像,在将这个图像绘制到最终的surface之前,需要先将其拷贝到这个字体对象内部的surface上,以后用户如果再画同样的字符,就直接从这个surface中取,这就是DFB所谓的对字体有缓存
     CoreFontCacheRow            **rows;         
 
     int                           row_width;
//每个row对应的surface的缓存大小是一定的,即存放的字符是一定的,如果字体库中的字体数量很多,一
个row的surface可能不够,需要创建新的row,max_row 记录了DFB支持的最大row的数量(当前值是5)
     int                           max_rows;
//num_rows记录了当前rows的数量,num_rows<=max_rows
     int                           num_rows;
//active_row, 记录了当前活动的row,
     int                           active_row;
//row_stamp用于记录每个row的使用频率,每次绘制的字符如果属于每个row,则该row的row_stamp会加1,这个变量的作用在于row的删除替换。 当row的数量达到max_rows时,而又有新的字符需要绘制,这时显然不能分配新的row了,需要现存的某个row进行删除,而其依据就是row_stamp。
     unsigned int                  row_stamp;
//rows是存放字体图像的地方,就像是一个仓库,如何从仓库中快速拿到所需的货物, 也是DFB需要考虑的
问题。为此,DFB提供了两种途径,一是数组,二是哈希表,他们中的每一项都存放了rows中的一个字符图
像的索引,两者的区别是数组的大小固定,为128,存放的是前128个字符(实际上,大部分字符都在这个范
围内), 而哈希表的大小是可变的,存放的是除去数组之外的其他字符。
     DirectHash                   *glyph_hash;   
     CoreGlyphData                *glyph_data[128];
//下面这两个函数负责将字符图像拷贝到指定的surface中,与各个实现有关
     DFBResult                  (* GetGlyphData) ( CoreFont      *thiz,
                                                   unsigned int   index,
                                                   CoreGlyphData *data );
     DFBResult                  (* RenderGlyph)  ( CoreFont      *thiz,
                                                   unsigned int   index,
                                                   CoreGlyphData *data );
........
};
 
   
    综上所述,在用户调用CreateFont()时, DFB会调用Probe和Construct(这也是每个字体interface 需
要实现的接口)完成字体库的初始化及字体对象的创建。

原创粉丝点击