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);

      

将所创建的逻辑字体设为要显示文本的设备上下文的逻辑字体。这样在对应的设备上下

       文中就会以自定义的逻辑字体显示文本。