Chinaunix首页 | 论坛 | 博客
  • 博客访问: 836615
  • 博文数量: 244
  • 博客积分: 10000
  • 博客等级: 上将
  • 技术积分: 2420
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-29 09:07
文章分类

全部博文(244)

文章存档

2011年(4)

2010年(3)

2009年(72)

2008年(119)

2007年(46)

我的朋友

分类: LINUX

2008-03-05 18:06:55

GTK+(基于DirectFB)的字体绘制是通过pango+freetype+fontconfig三者协作来完成的,其中,fontconfig负责字体的管理和配置,freetype负责单个字符的绘制,pango则完成对文字的排版布局。这几天花了点时间研究GTK+的字体处理,这里记录一些笔记。

 

pango排版文字,首先要创建一个PangoLayout对象。一般来说,不必直接调用pango_layout_new函数创建,而是调用gtk提供的包装函数gtk_widget_create_pango_layout。在该函数又调用gtk_widget_get_pango_context函数获得PangoContext对象。

 

什么是PangoContext呢?顾名思义,PangoContext就是用来保存Pango上下文信息的。其中最重要的是PangoFontMap对象,从字面上讲PangoFontMap是从字体描述到字体之间的映射,它的实际功能就是加载字体。它根据字体的描述,调用fontconfig的函数找到对应的字体文件,然后调用freetype的函数加载该字体。

 

l         字体的初始化。

字体的初始化并不是在gtk_init函数完成中,而是在实际使用字体时才初始化。调用路径为

u       gtkwidget.c: gtk_widget_get_pango_context

u       gtkwidget.c: gtk_widget_create_pango_context

u       gdkpango-directfb.c: gdk_pango_context_get

u       pangoft2-fontmap.c: pango_ft2_get_context

u       pangoft2-fontmap.c: pango_ft2_font_map_for_display

u       pangoft2-fontmap.c: pango_ft2_font_map_new

u       ftinit.c: FT_Init_FreeType

 

初始化并不加载任何字体,字体的加载是根据需要,要任何时候都可以加载。在初始化时,主要是加载freetype的后端。内置的Freetype后端是在ftmodule.h里定义的,可以在此进行裁减,默认内置的后端有:

FT_USE_MODULE(autofit_module_class)

FT_USE_MODULE(tt_driver_class)

FT_USE_MODULE(t1_driver_class)

FT_USE_MODULE(cff_driver_class)

FT_USE_MODULE(t1cid_driver_class)

FT_USE_MODULE(pfr_driver_class)

FT_USE_MODULE(t42_driver_class)

FT_USE_MODULE(winfnt_driver_class)

FT_USE_MODULE(pcf_driver_class)

FT_USE_MODULE(psaux_module_class)

FT_USE_MODULE(psnames_module_class)

FT_USE_MODULE(pshinter_module_class)

FT_USE_MODULE(ft_raster1_renderer_class)

FT_USE_MODULE(sfnt_module_class)

FT_USE_MODULE(ft_smooth_renderer_class)

FT_USE_MODULE(ft_smooth_lcd_renderer_class)

FT_USE_MODULE(ft_smooth_lcdv_renderer_class)

FT_USE_MODULE(otv_module_class)

FT_USE_MODULE(bdf_driver_class)

 

l         字体的加载。

程序第一次显示文字或者后面改变文字的字体,都可能会导致字体加载。在pango排版时,若对应的字体没有加载,它会调用pango_fc_font_map_load_fontset函数去加载该字体。

 

函数pango_fc_font_map_get_patterns会根据字体的描述,调用FcPatternBuild创建一个patternpatternfontconfig的一个术语,fontconfig根据pattern的描述,在配置文件中查找最接近要求的字体,这是一种模糊查询,不必定义精确的查找条件, 它通常始终会返回一种相近的字体。

 

如果pattern对应的字体没有加载,则调用pango_fc_font_map_new_font加载该字体。转了N道弯之后,来到了pango_ft2_font_get_face函数,该函数从pattern中取出一些参数,其中最重要的是字体文件名,然后调用FT_New_Face真正加载字体。

 

l         字体的匹配。

如果没有fontconfig的帮助,要精确的指定字体参数是件痛苦的事情。那些神秘的参数很容易把人搞晕了,即使指定了正确的字体参数,换一个系统如果没有该字体,程序可能就完全不能运行了。而在fontconfig的帮助下,你只要说明对字体的要求,fontconfig总是可以帮你找到最接近要求的字体。

 

Fontconfig的主配置文件在/etc/fonts/目录里,也可以在~/.fonts目录下存放用户自己的配置信息。/etc/fonts/fonts.conf文件是默认的配置,一般不要修改它,但可以修改/etc/fonts/local.conffonts.conf包含了local.conf

 

配置文件里的dir段指明了字体文件存放的路径,在小机上,字体的存放路径一般与PC上不同,所以可能要修改dir段,加入实际字体文件所在的路径。其它配置一般不用修改,使用默认的即可。

 

要注意,字体有三类,SerifSans serifMonospacesans”来源于古法语, 意为“without, 即“非”。 而“serif”来源于荷兰语, 译为衬线, 指字母的拐角或端点位置的修饰线。SerifSans serif是非等宽字体,而Monospace是等宽字体。通过下面的实际效果可以看出它们的差异。

 

Serif : E

Sans serif : E

Monospace: Courier

 

l         字体的显示。

pango_ft2_font_render_glyph函数调用了FT_Load_Glyph去加载字模数据,我想当然的       认为字体是在pangoft2-render.c中绘制的,而且GTK/GDK都不应该知道freetype的细节信息,否则两者之间的耦合就太死了。

 

但是事实是,Pango排版完成后,并没有管字体显示的问题。字体真正显示是在gdk_directfb_draw_glyphs函数里完成的,它调用_glyph_surface_cache_get_surface函数把freetype的字模bitmap拷贝到一个surface里,然后把该surface中的内容blit到窗口的surface上。

 

l         修改widget的字体。

修改widget的字体很简单,调用gtk_widget_modify_font函数即可。如:

PangoFontDescription *desc = pango_font_description_from_string("Serif 12");

gtk_widget_modify_font(widget, desc);

pango_font_description_free(desc);

 

l         GTK+2.6 + DirectFB-0.9.22关于字体问题的BUG

字体无法显示Fontconfig配置正确,对应的字体文件也存在,但是字体就是显示不出来。原因在于,字体显示实际上中调用的函数gdk_draw_glyphs_transformed而不是gdk_draw_glyphs,而函数gdk_draw_glyphs_transformedgdk-directfb中并没有实现,这导致了字体无法显示。解决方法:若不存在旋转字体,可以直接用gdk_draw_glyphs来实现gdk_draw_glyphs_transformed

 

大部文字都带有下划线,界面显得很怪异。原因在于,glyphsurfacecache.c中的函数surface_new创建surface后没有把surface清理一下,里面有些垃圾数据,而字模又并不一定完全占满整个surface,所以这些垃圾数据也被Blit到窗口上了。解决方法:这可以在调用CreateSurface成功后,再调用一下Clear函数。

 

参考资料:

 

~~end~~

 

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