⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 minigui 体系结构之三逻辑字体以及多字体和多字符集实现.htm

📁 是一个标准的体系结构
💻 HTM
📖 第 1 页 / 共 4 页
字号:
      ISO8859 的字符,而“中文”是属于 GB2312 的字符。通过调用这两个字符集操作集中的函数,我们就可以了解该字符串中哪些字符是属于 
      ISO8859 的字符,哪些字符是属于 GB2312 的字符,甚至可以进行更加复杂的分析。比如,MiniGUI 中的 GetFirstWord 
      函数可以从这种字符串中获得第一个单词。比如“ABC DEF 
      中文”字符串中的第一个单词是“ABC”,而第二个单词是“DEF”,第三个单词和第四个单词分别是“中”和“文”。该函数的实现如下:</P>
      <TABLE class=code-sample cellPadding=0 width="100%" border=0>
        <TBODY>
        <TR>
          <TD><PRE>int GUIAPI GetFirstWord (PLOGFONT log_font, const char* mstr, int len,
                    WORDINFO* word_info)
{
    DEVFONT* sbc_devfont = log_font-&gt;sbc_devfont;
    DEVFONT* mbc_devfont = log_font-&gt;mbc_devfont;

    if (mbc_devfont) {
        int mbc_pos;

        mbc_pos = (*mbc_devfont-&gt;charset_ops-&gt;pos_first_char) (mstr, len);
        if (mbc_pos == 0) {
            len = (*mbc_devfont-&gt;charset_ops-&gt;len_first_substr) (mstr, len);

            (*mbc_devfont-&gt;charset_ops-&gt;get_next_word) (mstr, len, word_info);
            return word_info-&gt;len + word_info-&gt;nr_delimiters;
        }
        else if (mbc_pos &gt; 0)
            len = mbc_pos;
    }

    (*sbc_devfont-&gt;charset_ops-&gt;get_next_word) (mstr, len, word_info);
    return word_info-&gt;len + word_info-&gt;nr_delimiters;
}
</PRE></TD></TR></TBODY></TABLE>
      <P>该函数首先判断该逻辑字体是否包含多字节设备字体(mbc_devfont是否为空),如果是,则调用多字节字符集对应的操作函数 
      pos_first_char、len_first_substr、get_next_word 等函数获得第一个单词信息,并填充 word_info 
      结构。如果该逻辑字体只包含单字节设备字体,则直接调用单字节字符集对应的操作函数 get_next_word。一般而言,在 GetFirstWord 
      等函数中,我们首先要进行多字节字符集的某些判断,比如 pos_first_char 
      返回的是字符串中属于该字符集的第一个字符的位置。如果返回值不为零,表明第一个字符是单字节字符;如果为零,才会调用其他函数进行操作。</P>
      <P>有了这样的逻辑字体、设备字体和字符集结构定义,当我们需要新添加一种字符集或者字体支持时,只需按照我们的字体操作集和字符集操作集定义对应的新操作集结构即可,而对上层程序没有任何影响。</P><A 
      id=3 name=3></A>
      <P><STRONG class=subhead>3 MiniGUI 中的字符集支持</STRONG> <STRONG>3.1 
      字符集操作集</STRONG></P>
      <P>在 MiniGUI 
      中,每个特定的字符集由对应的字符集操作集来表示。字符集操作集的定义如下(include/gdi.h。前面的数字表示在该文件中的行数,下同):</P>
      <TABLE class=code-sample cellPadding=0 width="100%" border=0>
        <TBODY>
        <TR>
          <TD><PRE> 250 typedef struct _CHARSETOPS
 251 {
 252     int nr_chars;              // 该字符集中字符的个数
 253     int bytes_per_char;            // 每个字符的平均字节数
 254     int bytes_maxlen_char;     // 字符的最大字节数
 255     const char* name;          // 字符集名称
 256     char def_char [MAX_LEN_MCHAR]; // 默认字符
 257
 258     int (*len_first_char) (const unsigned char* mstr, int mstrlen);
 259     int (*char_offset) (const unsigned char* mchar);
 260
 261     int (*nr_chars_in_str) (const unsigned char* mstr, int mstrlen);
 262
 263     int (*is_this_charset) (const unsigned char* charset);
 264
 265     int (*len_first_substr) (const unsigned char* mstr, int mstrlen);
 266     const unsigned char* (*get_next_word) (const unsigned char* mstr,
 267                 int strlen, WORDINFO* word_info);
 268
 269     int (*pos_first_char) (const unsigned char* mstr, int mstrlen);
 270
 271 #ifndef _LITE_VERSION
 272     unsigned short (*conv_to_uc16) (const unsigned char* mchar, int len);
 273 #endif /* !LITE_VERSION */
 274 } CHARSETOPS;
</PRE></TD></TR></TBODY></TABLE>
      <P>其中,前几个字段(nr_chars、bytes_per_char、bytes_maxlen_char、name、def_char 
      等)表示了该字符集的一些基本信息,具体含义参见注释。这里需要对 bytes_maxlen_char 和 def_chat 作进一步解释:</P>
      <UL>
        <LI>bytes_maxlen_char 
        用来表示该字符集中字符的最长字节数。通常情况下,一个字符集中的每个字符的长度一般是定长的,但是也有许多例外,比如在 
        GB18303、UNICODE 等字符集中,字符的最长字节数可能超过 4 字节。 
        <LI>def_char 
        用来表示该字符集中的默认字符。该字段主要和字体配合使用。当某个针对该字符集的字体中缺少一些字符的定义时,就需要用默认字体替代这些缺少的字符。 
        </LI></UL>
      <P>在上述字符集的操作集定义中,后几个字段定义为函数指针,它们均由逻辑字体接口用来进行文本分析:</P>
      <UL>
        <LI>len_first_char 返回多字节字符串中第一个属于该字符集的字符的长度。若不属于该字符集,则返回 0。 
        <LI>char_offset 返回某个字符在该字符集中的位置。该信息可以由设备字体使用,用来从一个字体文件中获取该字符对应的宽度或点阵。 
        <LI>nr_chars_in_str 计算字符串中属于该字符集的字符个数并返回。注意,传入的字符串必须均为该字符集字符。 
        <LI>is_this_charset 判断给定的用来表示字符集的名称是否指该字符集。因为对某种特定的字符集,其名称不一定和 name 
        字段所定义的名称匹配。比如,对 GB2312 字符集,就可能有 gb2312-1980.0、GB2312_80 
        等各种不同的名称。该函数可以帮助正确判断一个名称是否指该字符集。 
        <LI>len_first_substr 返回某个多字节字符串中属于该字符集的子字符串长度。如果第一个字符不属于该字符集,则返回为 0。 
        <LI>get_next_word 
        返回多字节字符串中属于该字符集的字符串中下一个单词的信息。对欧美语言来说,单词之间由空格、标点符号、制表符等相隔;对亚洲语言来说,单词通常定义为字符。 

        <LI>pos_first_char 该函数返回多字节字符串中属于该字符集的第一个字符的位置。 
        <LI>conv_to_uc16 该函数将某个属于该字符集的字符,转换为 UNICODE 的 16 位内码。该函数主要用来从 TrueType 
        字体中获得字符的轮廓信息。因为 TrueType 字体使用 UNICODE 定位字符,所以需要这个函数完成特定字符集内码到 UNICODE 
        内码的转换。由于 MiniGUI-Lite 版本尚不支持 TrueType 字体,所以该函数在 MiniGUI-Lite 版本中无需定义。 
        </LI></UL>
      <P>在 src/font/charset.c 中,定义了系统支持的所有字符集操作集,并由函数 GetCharsetOps 
      返回某个字符集名称对应的字符集操作集(src/font/charset.c):</P>
      <TABLE class=code-sample cellPadding=0 width="100%" border=0>
        <TBODY>
        <TR>
          <TD><PRE> 716 static CHARSETOPS* Charsets [] =
 717 {
 718     &amp;CharsetOps_iso8859_1,
 719     &amp;CharsetOps_iso8859_5,
 720 #ifdef _GB_SUPPORT
 721     &amp;CharsetOps_gb2312,
 722 #endif
 723 #ifdef _BIG5_SUPPORT
 724     &amp;CharsetOps_big5,
 725 #endif
 726 #ifdef _EUCKR_SUPPORT
 727     &amp;CharsetOps_euckr,
 728 #endif
 729 #ifdef _UJIS_SUPPORT
 730     &amp;CharsetOps_ujis
 731 #endif
 732 };
 733
 734 #define NR_CHARSETS     (sizeof(Charsets)/sizeof(CHARSETOPS*))
 735
 736 CHARSETOPS* GetCharsetOps (const char* charset_name)
 737 {
 738     int i;
 739
 740     for (i = 0; i &amp;lt; NR_CHARSETS; i++) {
 741         if ((*Charsets [i]-&amp;gt;is_this_charset) (charset_name) == 0)
 742             return Charsets [i];
 743     }
 744
 745     return NULL;
 746 }
 747
</PRE></TD></TR></TBODY></TABLE><STRONG>3.2 新字符集的实现举例</STRONG> 
      <P>如果我们需要定义一种新的字符集支持时,只需在该文件中添加相应的操作集函数以及对应的操作集结构定义即可,比如,对 EUCKR 
      字符集的支持定义如下(src/font/charset.c):</P>
      <TABLE class=code-sample cellPadding=0 width="100%" border=0>
        <TBODY>
        <TR>
          <TD><PRE> 468 #ifdef _EUCKR_SUPPORT
 469 /************************* EUCKR Specific Operations ************************/
 470 static int euckr_len_first_char (const unsigned char* mstr, int len)
 471 {
 472     unsigned char ch1;
 473     unsigned char ch2;
 474
 475     if (len &lt; 2) return 0;
 476
 477     ch1 = mstr [0];
 478     if (ch1 == '\0')
 479         return 0;
 480
 481     ch2 = mstr [1];
 482     if (ch1 &gt;= 0xA1 &amp;&amp; ch1 &lt;= 0xFE &amp;&amp; ch2 &gt;= 0xA1 &amp;&amp; ch2 &lt;= 0xFE)
 483         return 2;
 484
 485     return 0;
 486 }
 487
 488 static int euckr_char_offset (const unsigned char* mchar)
 489 {
 490     if(mchar [0] &gt; 0xAD)
 491         return ((mchar [0] - 0xA4) * 94 + mchar [1] - 0xA1 - 0x8E);
 492     else
 493         return ((mchar [0] - 0xA1) * 94 + mchar [1] - 0xA1 - 0x8E);
 494 }
 495
 496 static int euckr_is_this_charset (const unsigned char* charset)
 497 {
 498     int i;
 499     char name [LEN_FONT_NAME + 1];
 500
 501     for (i = 0; i &lt; LEN_FONT_NAME + 1; i++) {
 502         if (charset [i] == '\0')
 503             break;
 504         name [i] = toupper (charset [i]);
 505     }
 506     name [i] = '\0';
 507
 508     if (strstr (name, "EUCKR") )
 509         return 0;
 510
 511     return 1;
 512 }
 513
 514 static int euckr_len_first_substr (const unsigned char* mstr, int mstrlen)
 515 {
 516     unsigned char ch1;
 517     unsigned char ch2;
 518     int i, left;
 519     int sub_len = 0;
 520
 521     left = mstrlen;
 522     for (i = 0; i &lt; mstrlen; i += 2) {
 523         if (left &lt; 2) return sub_len;
 524
 525         ch1 = mstr [i];
 526         if (ch1 == '\0') return sub_len;
 527
 528         ch2 = mstr [i + 1];
 529         if (ch1 &gt;= 0xA1 &amp;&amp; ch1 &lt;= 0xFE &amp;&amp; ch2 &gt;= 0xA1 &amp;&amp; ch2 &lt;= 0xFE)
 530             sub_len += 2;
 531         else
 532             return sub_len;
 533
 534         left -= 2;
 535     }
 536
 537     return sub_len;
 538 }
 539
 540 static int euckr_pos_first_char (const unsigned char* mstr, int mstrlen)
 541 {
 542     unsigned char ch1;
 543     unsigned char ch2;
 544     int i, left;
 545
 546     i = 0;
 547     left = mstrlen;
 548     while (left) {
 549         if (left &lt; 2) return -1;
 550
 551         ch1 = mstr [i];
 552         if (ch1 == '\0') return -1;
 553
 554         ch2 = mstr [i + 1];
 555         if (ch1 &gt;= 0xA1 &amp;&amp; ch1 &lt;= 0xFE &amp;&amp; ch2 &gt;= 0xA1 &amp;&amp; ch2 &lt;= 0xFE)
 556             return i;
 557
 558         i += 1;
 559         left -= 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -