minigui字体管理
仅针对内建字体资源,即定义了_INCORE_RES之后的字体管理
minigui配置为使用NEWGAL
minigui-1.6.8
1、 逻辑字体、设备字体及字符集的关系
在minigui中,每个逻辑字体至少由一个单字节的设备字体组成。设备字体是直接与底层字体相关的数据结构。
/** The logical font structure. */
typedef struct _LOGFONT {
/** The type of the logical font. */
char type [LEN_FONT_NAME + 1];
/** The family name of the logical font. */
char family [LEN_FONT_NAME + 1];
/** The charset of the logical font. */
char charset [LEN_FONT_NAME + 1];
/** The styles of the logical font. */
DWORD style;
/** The size of the logical font. */
int size;
/** The rotation angle of the logical font. */
int rotation;
/** The scale factor of sbc device font. */
unsigned short sbc_scale;
/** The scale factor of mbc device font. */
unsigned short mbc_scale;
DEVFONT* sbc_devfont;
DEVFONT* mbc_devfont;
} LOGFONT;
struct _DEVFONT
{
char name [LEN_UNIDEVFONT_NAME + 1];
DWORD style;
FONTOPS* font_ops;
CHARSETOPS* charset_ops;
struct _DEVFONT* sbc_next;
struct _DEVFONT* mbc_next;
void* data;
};
每一个设备字体有一个操作集。通过这个字体操作集,我们可以从相应的字体文件中获得某个字符的点阵(对光栅字体而言,包括等宽光栅字体RBF和变宽光栅字体VBF),或轮廓(对矢量字体而言,包括TrueType、Adobe Type1字体等)。之后,MINIGUI上层函数就可以将这些点阵输出到屏幕上,最终就可以看到显示在屏幕上的文字。
在设备字体中,还有一个字符集操作集,通过这个字符集操作集,可以对多种字符集混合的字符串进行文本分析。
显示文本的过程中,首先要分析文本字符串的组成,然后从设备字体中获取相关的尺寸信息、字型位图等信息,然后再显示在屏幕上。
2、 字体初始化
minigui中,在初始化GDI时,会对字体进行初始化,我们现在关注InitGDI函数中调用的如下几个函数:
1) BOOL InitIncoreRBFonts (void) src/rawbitmap.c line 188-255
BOOL InitIncoreRBFonts (void)
{
int i;
incore_rbf_dev_fonts = calloc (NR_RBFONTS, sizeof (DEVFONT));
incore_rbf_infos = calloc (NR_RBFONTS, sizeof (RBFINFO));
if (!incore_rbf_dev_fonts || !incore_rbf_infos)
return TRUE;
for (i = 0; i < NR_RBFONTS; i++) {
char charset [LEN_FONT_NAME + 1];
if (!fontGetCharsetFromName (incore_rbfonts [i]->name, charset)) {
fprintf (stderr, "GDI: Invalid font name (charset): %s./n",
incore_rbfonts [i]->name);
goto error_load;
}
if ((incore_rbf_infos [i].charset_ops
= GetCharsetOpsEx (charset)) == NULL) {
fprintf (stderr, "GDI: Not supported charset: %s./n", charset);
goto error_load;
}
if ((incore_rbf_infos [i].width = fontGetWidthFromName (incore_rbfonts [i]->name)) == -1) {
fprintf (stderr, "GDI: Invalid font name (width): %s./n",
incore_rbfonts [i]->name);
goto error_load;
}
if ((incore_rbf_infos [i].height = fontGetHeightFromName (incore_rbfonts [i]->name)) == -1) {
fprintf (stderr, "GDI: Invalid font name (height): %s./n",
incore_rbfonts [i]->name);
goto error_load;
}
incore_rbf_infos [i].nr_chars = incore_rbf_infos [i].charset_ops->nr_chars;
incore_rbf_infos [i].font_size = ((incore_rbf_infos [i].width + 7) >> 3) *
incore_rbf_infos [i].height * incore_rbf_infos [i].nr_chars;
incore_rbf_infos [i].font = (unsigned char*) incore_rbfonts [i]->data;
strncpy (incore_rbf_dev_fonts[i].name, incore_rbfonts [i]->name, LEN_DEVFONT_NAME);
incore_rbf_dev_fonts[i].name [LEN_DEVFONT_NAME] = '/0';
incore_rbf_dev_fonts[i].font_ops = &raw_bitmap_font_ops;
incore_rbf_dev_fonts[i].charset_ops = incore_rbf_infos [i].charset_ops;
incore_rbf_dev_fonts[i].data = incore_rbf_infos + i;
#if 0
fprintf (stderr, "GDI: RBFDevFont %i: %s./n", i, incore_rbf_dev_fonts[i].name);
#endif
}
for (i = 0; i < NR_RBFONTS; i++) {
if (incore_rbf_infos [i].charset_ops->bytes_maxlen_char > 1)
AddMBDevFont (incore_rbf_dev_fonts + i);
else
AddSBDevFont (incore_rbf_dev_fonts + i);
}
return TRUE;
error_load:
fprintf (stderr, "GDI: Error in initializing incore raw bitmap fonts!/n");
TermIncoreRBFonts ();
return FALSE;
}
该函数中,首先根据配置时选择的RBF设备字体, 初始化了设备字体数据结构,然后根据这些RBF设备字体是多字节还是单字节,分别将它们添加到多字节设备字体链和单字节设备字体链的链尾。这样所有在配置时选中的RBF设备字体将根据其是单字节的还是多字节的,被保存到了全局的设备字体链中。
2)BOOL InitIncoreVBFonts (void) src/font/varbitmap.c line 356-386
BOOL InitIncoreVBFonts (void)
{
int i;
if (NR_VBFONTS == 0)
return TRUE;
if ((incore_vbf_dev_font = malloc (NR_VBFONTS * sizeof (DEVFONT))) == NULL)
return FALSE;
for (i = 0; i < NR_VBFONTS; i++) {
if ((incore_vbf_dev_font [i].charset_ops
= vbfGetCharsetOps (incore_vbfonts [i])) == NULL) {
fprintf (stderr,
"GDI: Not supported charset for var-bitmap font %s./n",
incore_vbfonts[i]->name);
free (incore_vbf_dev_font);
return FALSE;
}
strncpy (incore_vbf_dev_font [i].name, incore_vbfonts [i]->name, LEN_DEVFONT_NAME);
incore_vbf_dev_font [i].name [LEN_DEVFONT_NAME] = '/0';
incore_vbf_dev_font [i].font_ops = &var_bitmap_font_ops;
incore_vbf_dev_font [i].data = incore_vbfonts [i];
}
for (i = 0; i < NR_VBFONTS; i++)
AddSBDevFont (incore_vbf_dev_font + i);
return TRUE;
}
同样,该函数根据配置时选择的VBF设备字体,初始化了设备字体数据结构。然后把他们添加到单字节设备字体链的尾部。这样,配置时选择的所有VBF设备字体,也被保存到了全局设备字体链中。
3)BOOL InitSysFont (void) src/font/sysfont.c
BOOL InitSysFont (void)
{
int i;
PLOGFONT* sys_fonts;
int nr_fonts;
if (GetMgEtcIntValue ("systemfont", "font_number", &nr_fonts) < 0 )
return FALSE;
if (nr_fonts < 1) return TRUE;
if (nr_fonts > NR_SYSLOGFONTS) nr_fonts = NR_SYSLOGFONTS;
#ifdef HAVE_ALLOCA
if ((sys_fonts = alloca (nr_fonts * sizeof (PLOGFONT))) == NULL)
#else
if ((sys_fonts = malloc (nr_fonts * sizeof (PLOGFONT))) == NULL)
#endif
return FALSE;
memset (sys_fonts, 0, nr_fonts * sizeof (PLOGFONT));
for (i = 0; i < nr_fonts; i++) {
char key [11];
char type[LEN_FONT_NAME + 1];
char family[LEN_FONT_NAME + 1];
char style[LEN_FONT_NAME + 1];
char charset[LEN_FONT_NAME + 1];
int height;
char font_name [LEN_DEVFONT_NAME + 1];
sprintf (key, "font%d", i);
if (GetMgEtcValue ("systemfont", key, font_name, LEN_DEVFONT_NAME) < 0)
goto error_load;
if (!fontGetTypeNameFromName (font_name, type) ||
!fontGetFamilyFromName (font_name, family) ||
!fontCopyStyleFromName (font_name, style) ||
!fontGetCharsetFromName (font_name, charset) ||
((height = fontGetHeightFromName (font_name)) == -1)) {
fprintf (stderr, "GDI: Invalid system logical font name: %s./n",
font_name);
goto error_load;
}
#ifdef _DEBUG
fprintf (stderr, "system font %d: %s-%s-%d-%s/n", i, type, family, height, charset);
#endif
if (i == 0 && GetCharsetOps (charset)->bytes_maxlen_char > 1) {
fprintf (stderr, "GDI: First system font should be a single-byte charset. font_name: %s/n",
font_name);
goto error_load;
}
if ((sys_fonts[i] = CreateLogFont (type, family, charset,
style [0], style [1], style [2],
style [3], style [4], style [5],
height, 0)) == NULL) {
fprintf (stderr, "GDI: Error when creating system logical font./n");
goto error_load;
}
if (i == 0)
g_SysLogFont [0] = sys_fonts [0];
}
for (i = 0; i < NR_SYSLOGFONTS; i++) {
int font_id;
if (GetMgEtcIntValue ("systemfont", sys_font_name [i], &font_id) < 0
|| font_id < 0 || font_id >= nr_fonts) {
fprintf (stderr, "GDI: Error system logical font identifier: %s./n", sys_font_name [i]);
goto error_load;
}
g_SysLogFont [i] = sys_fonts[font_id];
}
#ifndef HAVE_ALLOCA
free (sys_fonts);
#endif
return TRUE;
error_load:
fprintf (stderr, "GDI: Error in creating system logical fonts!/n");
for (i = 0; i < nr_fonts; i++) {
if (sys_fonts [i])
DestroyLogFont (sys_fonts[i]);
}
#ifndef HAVE_ALLOCA
free (sys_fonts);
#endif
return FALSE;
}
这个函数根据src/sysres/mgetc-pc.c文件中对字体的配置,创建出逻辑字体。然后再根据其配置为系统中的各组件设置逻辑字体。组件名定义在:src/font/sysfont.c line 54-62
static char* sys_font_name [] =
{
"default",
"wchar_def",
"fixed",
"caption",
"menu",
"control"
};
设置后逻辑字体保存于全局数组PLOGFONT g_SysLogFont [NR_SYSLOGFONTS]中,这样系统在显示时所用的字体就确定好了。
3、 自定义逻辑字体
当我们创建主窗口或控件时,系统会为其选择不同的逻辑字体以显示文本。当然我们也可以自定义一个逻辑字体来显示文本。可通过如下三个函数创建逻辑字体:
PLOGFONT GUIAPI CreateLogFontIndirect (LOGFONT *logfont);
PLOGFONT GUIAPI CreateLogFont (const char* type, const char* family,
const char* charset, char weight, char slant, char set_width,
char spacing, char underline, char struckout, int size, int rotation);
PLOGFONT GUIAPI CreateLogFontByName (const char* font_name);
创建完逻辑字体后,再通过函数
PLOGFONT GUIAPI SelectFont (HDC hdc, PLOGFONT log_font);
将所创建的逻辑字体设为要显示文本的设备上下文的逻辑字体。这样在对应的设备上下
文中就会以自定义的逻辑字体显示文本。