gdkfont-win32.c

Go to the documentation of this file.
00001 /* GDK - The GIMP Drawing Kit
00002  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 /*
00021  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
00022  * file for a list of people on the GTK+ Team.  See the ChangeLog
00023  * files for a list of changes.  These files are distributed with
00024  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
00025  */
00026 
00027 #include "config.h"
00028 
00029 #include <stdio.h>
00030 #include <ctype.h>
00031 
00032 #include "gdkfont.h"
00033 #include "gdkwin32.h"
00034 
00035 static GHashTable *font_name_hash = NULL;
00036 static GHashTable *fontset_name_hash = NULL;
00037 
00038 static float gfont_angle = 0.0;
00039 
00040 static void
00041 gdk_font_hash_insert(GdkFontType type,
00042                      GdkFont * font, const gchar * font_name)
00043 {
00044    GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
00045    GHashTable **hashp = (type == GDK_FONT_FONT) ?
00046        &font_name_hash : &fontset_name_hash;
00047 
00048    if (!*hashp)
00049       *hashp = g_hash_table_new(g_str_hash, g_str_equal);
00050 
00051    private->names = g_slist_prepend(private->names, g_strdup(font_name));
00052    g_hash_table_insert(*hashp, private->names->data, font);
00053 }
00054 
00055 static void gdk_font_hash_remove(GdkFontType type, GdkFont * font)
00056 {
00057    GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
00058    GSList *tmp_list;
00059    GHashTable *hash = (type == GDK_FONT_FONT) ?
00060        font_name_hash : fontset_name_hash;
00061 
00062    tmp_list = private->names;
00063    while (tmp_list) {
00064       g_hash_table_remove(hash, tmp_list->data);
00065       g_free(tmp_list->data);
00066 
00067       tmp_list = tmp_list->next;
00068    }
00069 
00070    g_slist_free(private->names);
00071    private->names = NULL;
00072 }
00073 
00074 static GdkFont *gdk_font_hash_lookup(GdkFontType type,
00075                                      const gchar * font_name)
00076 {
00077    GdkFont *result;
00078    GHashTable *hash = (type == GDK_FONT_FONT) ?
00079        font_name_hash : fontset_name_hash;
00080 
00081    if (!hash)
00082       return NULL;
00083    else {
00084       result = g_hash_table_lookup(hash, font_name);
00085       if (result)
00086          gdk_font_ref(result);
00087 
00088       return result;
00089    }
00090 }
00091 
00092 static const char *charset_name(DWORD charset)
00093 {
00094    switch (charset) {
00095    case ANSI_CHARSET:
00096       return "ansi";
00097    case DEFAULT_CHARSET:
00098       return "default";
00099    case SYMBOL_CHARSET:
00100       return "symbol";
00101    case SHIFTJIS_CHARSET:
00102       return "shiftjis";
00103    case HANGEUL_CHARSET:
00104       return "hangeul";
00105    case GB2312_CHARSET:
00106       return "gb2312";
00107    case CHINESEBIG5_CHARSET:
00108       return "big5";
00109    case JOHAB_CHARSET:
00110       return "johab";
00111    case HEBREW_CHARSET:
00112       return "hebrew";
00113    case ARABIC_CHARSET:
00114       return "arabic";
00115    case GREEK_CHARSET:
00116       return "greek";
00117    case TURKISH_CHARSET:
00118       return "turkish";
00119    case VIETNAMESE_CHARSET:
00120       return "vietnamese";
00121    case THAI_CHARSET:
00122       return "thai";
00123    case EASTEUROPE_CHARSET:
00124       return "easteurope";
00125    case RUSSIAN_CHARSET:
00126       return "russian";
00127    case MAC_CHARSET:
00128       return "mac";
00129    case BALTIC_CHARSET:
00130       return "baltic";
00131    }
00132    return "unknown";
00133 }
00134 
00135 static gint num_fonts;
00136 static gint font_names_size;
00137 static gchar **xfontnames;
00138 
00139 static gchar *logfont_to_xlfd(const LOGFONT * lfp,
00140                               int size, int res, int avg_width)
00141 {
00142    const gchar *weight;
00143    const gchar *registry, *encoding;
00144    int point_size;
00145    static int logpixelsy = 0;
00146    gchar facename[LF_FACESIZE * 5];
00147    gchar *utf8_facename;
00148    gchar *p;
00149    const gchar *q;
00150 
00151    if (logpixelsy == 0) {
00152       logpixelsy = GetDeviceCaps(gdk_DC, LOGPIXELSY);
00153    }
00154 
00155    if (lfp->lfWeight >= FW_HEAVY)
00156       weight = "heavy";
00157    else if (lfp->lfWeight >= FW_EXTRABOLD)
00158       weight = "extrabold";
00159    else if (lfp->lfWeight >= FW_BOLD)
00160       weight = "bold";
00161 #ifdef FW_DEMIBOLD
00162    else if (lfp->lfWeight >= FW_DEMIBOLD)
00163       weight = "demibold";
00164 #endif
00165    else if (lfp->lfWeight >= FW_MEDIUM)
00166       weight = "medium";
00167    else if (lfp->lfWeight >= FW_NORMAL)
00168       weight = "normal";
00169    else if (lfp->lfWeight >= FW_LIGHT)
00170       weight = "light";
00171    else if (lfp->lfWeight >= FW_EXTRALIGHT)
00172       weight = "extralight";
00173    else if (lfp->lfWeight >= FW_THIN)
00174       weight = "thin";
00175    else
00176       weight = "regular";
00177 
00178    switch (lfp->lfCharSet) {
00179    case ANSI_CHARSET:
00180       registry = "iso8859";
00181       encoding = "1";
00182       break;
00183    case SHIFTJIS_CHARSET:
00184       registry = "jisx0208.1983";
00185       encoding = "0";
00186       break;
00187    case HANGEUL_CHARSET:
00188       registry = "ksc5601.1987";
00189       encoding = "0";
00190       break;
00191    case GB2312_CHARSET:
00192       registry = "gb2312.1980";
00193       encoding = "0";
00194       break;
00195    case CHINESEBIG5_CHARSET:
00196       registry = "big5";
00197       encoding = "0";
00198       break;
00199    case GREEK_CHARSET:
00200       registry = "iso8859";
00201       encoding = "7";
00202       break;
00203    case TURKISH_CHARSET:
00204       registry = "iso8859";
00205       encoding = "9";
00206       break;
00207 #if 0                           /* Not a good idea, I think, to use ISO8859-8 and -6 for the Windows
00208                                  * hebrew and arabic codepages, they differ too much.
00209                                  */
00210    case HEBREW_CHARSET:
00211       registry = "iso8859";
00212       encoding = "8";
00213       break;
00214    case ARABIC_CHARSET:
00215       registry = "iso8859";
00216       encoding = "6";
00217       break;
00218 #endif
00219    default:
00220       registry = "microsoft";
00221       encoding = charset_name(lfp->lfCharSet);
00222    }
00223 
00224    point_size = (int) (((double) size / logpixelsy) * 720.);
00225 
00226    if (res == -1)
00227       res = logpixelsy;
00228 
00229    /* Convert the facename Windows fives us from the locale-dependent
00230     * codepage to UTF-8.
00231     */
00232    utf8_facename = g_filename_to_utf8(lfp->lfFaceName, NULL);
00233 
00234    /* Replace characters illegal in an XLFD with hex escapes. */
00235    p = facename;
00236    q = utf8_facename;
00237    while (*q) {
00238       if (*q == '-' || *q == '*' || *q == '?' || *q == '%')
00239          p += sprintf(p, "%%%.02x", *q);
00240       else
00241          *p++ = *q;
00242       q++;
00243    }
00244    *p = '\0';
00245    g_free(utf8_facename);
00246 
00247    return g_strdup_printf
00248        ("-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s",
00249         "unknown",
00250         facename,
00251         weight,
00252         (lfp->lfItalic ?
00253          ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN
00254           || (lfp->lfPitchAndFamily & 0xF0) == FF_SCRIPT ?
00255           "i" : "o") : "r"),
00256         "normal",
00257         "",
00258         size,
00259         point_size,
00260         res,
00261         res,
00262         ((lfp->lfPitchAndFamily & 0x03) == FIXED_PITCH ? "m" : "p"),
00263         avg_width, registry, encoding);
00264 }
00265 
00266 gchar *gdk_font_full_name_get(GdkFont * font)
00267 {
00268    GdkFontPrivateWin32 *private;
00269    GdkWin32SingleFont *singlefont;
00270    GSList *list;
00271    GString *string;
00272    gchar *result;
00273    gchar *xlfd;
00274    LOGFONT logfont;
00275 
00276    g_return_val_if_fail(font != NULL, NULL);
00277 
00278    private = (GdkFontPrivateWin32 *) font;
00279 
00280    list = private->fonts;
00281    string = g_string_new("");
00282 
00283    while (list) {
00284       singlefont = (GdkWin32SingleFont *) list->data;
00285 
00286       if (GetObject(singlefont->xfont, sizeof(LOGFONT), &logfont) == 0) {
00287          WIN32_GDI_FAILED("GetObject");
00288          return NULL;
00289       }
00290 
00291       xlfd = logfont_to_xlfd(&logfont, logfont.lfHeight, -1, 0);
00292       string = g_string_append(string, xlfd);
00293       g_free(xlfd);
00294       list = list->next;
00295       if (list)
00296          string = g_string_append_c(string, ',');
00297    }
00298    result = string->str;
00299    g_string_free(string, FALSE);
00300    return result;
00301 }
00302 
00303 void gdk_font_full_name_free(gchar * name)
00304 {
00305    g_free(name);
00306 }
00307 
00308 static gboolean pattern_match(const gchar * pattern, const gchar * string)
00309 {
00310    const gchar *p = pattern, *n = string;
00311    gchar c, c1;
00312 
00313    /* Common case first */
00314    if ((pattern[0] == '*' && pattern[1] == '\0')
00315        || (pattern[0] == '-' && pattern[1] == '*' && pattern[2] == '\0'))
00316       return TRUE;
00317 
00318    while ((c = *p++) != '\0') {
00319       c = tolower(c);
00320 
00321       switch (c) {
00322       case '?':
00323          if (*n == '\0')
00324             return FALSE;
00325          break;
00326 
00327       case '*':
00328          for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
00329             if (c == '?' && *n == '\0')
00330                return FALSE;
00331 
00332          if (c == '\0')
00333             return TRUE;
00334 
00335          c1 = tolower(c);
00336          for (--p; *n != '\0'; ++n)
00337             if (tolower(*n) == c1 && pattern_match(p, n))
00338                return TRUE;
00339          return FALSE;
00340 
00341       default:
00342          if (c != tolower(*n))
00343             return FALSE;
00344       }
00345 
00346       ++n;
00347    }
00348 
00349    if (*n == '\0')
00350       return TRUE;
00351 
00352    return FALSE;
00353 }
00354 
00355 static int CALLBACK
00356 InnerEnumFontFamExProc(const LOGFONT * lfp,
00357                        const TEXTMETRIC * metrics,
00358                        DWORD fontType, LPARAM lParam)
00359 {
00360    int size;
00361    gchar *xlfd;
00362 
00363    if (fontType == TRUETYPE_FONTTYPE) {
00364       size = 0;
00365    } else {
00366       size = lfp->lfHeight;
00367    }
00368 
00369    xlfd = logfont_to_xlfd(lfp, size, 0, 0);
00370 
00371    if (!pattern_match((gchar *) lParam, xlfd)) {
00372       g_free(xlfd);
00373       return 1;
00374    }
00375 
00376    num_fonts++;
00377    if (num_fonts == font_names_size) {
00378       font_names_size *= 2;
00379       xfontnames =
00380           g_realloc(xfontnames, font_names_size * sizeof(gchar *));
00381    }
00382    xfontnames[num_fonts - 1] = xlfd;
00383 
00384    return 1;
00385 }
00386 
00387 static int CALLBACK
00388 EnumFontFamExProc(const LOGFONT * lfp,
00389                   const TEXTMETRIC * metrics,
00390                   DWORD fontType, LPARAM lParam)
00391 {
00392    if (fontType == TRUETYPE_FONTTYPE) {
00393       LOGFONT lf;
00394 
00395       lf = *lfp;
00396 
00397       EnumFontFamiliesEx(gdk_DC, &lf, InnerEnumFontFamExProc, lParam, 0);
00398    } else
00399       InnerEnumFontFamExProc(lfp, metrics, fontType, lParam);
00400 
00401    return 1;
00402 }
00403 
00404 gchar **gdk_font_list_new(const gchar * font_pattern, gint * n_returned)
00405 {
00406    LOGFONT logfont;
00407    gchar **result;
00408 
00409    num_fonts = 0;
00410    font_names_size = 100;
00411    xfontnames = g_new(gchar *, font_names_size);
00412    memset(&logfont, 0, sizeof(logfont));
00413    logfont.lfCharSet = DEFAULT_CHARSET;
00414    EnumFontFamiliesEx(gdk_DC, &logfont, EnumFontFamExProc,
00415                       (LPARAM) font_pattern, 0);
00416 
00417    result = g_new(gchar *, num_fonts + 1);
00418    memmove(result, xfontnames, num_fonts * sizeof(gchar *));
00419    result[num_fonts] = NULL;
00420    g_free(xfontnames);
00421 
00422    *n_returned = num_fonts;
00423    return result;
00424 }
00425 
00426 void gdk_font_list_free(gchar ** font_list)
00427 {
00428    g_strfreev(font_list);
00429 }
00430 
00431 /* This table classifies Unicode characters according to the Microsoft
00432  * Unicode subset numbering. This is based on the table in "Developing
00433  * International Software for Windows 95 and Windows NT". This is almost,
00434  * but not quite, the same as the official Unicode block table in
00435  * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield
00436  * number as in the FONTSIGNATURE struct's fsUsb field.
00437  * There are some grave bugs in the table in the books. For instance
00438  * it claims there are Hangul at U+3400..U+4DFF while this range in
00439  * fact contains CJK Unified Ideographs Extension A. Also, the whole
00440  * block of Hangul Syllables U+AC00..U+D7A3 is missing from the book.
00441  */
00442 
00443 typedef enum {
00444    U_BASIC_LATIN = 0,
00445    U_LATIN_1_SUPPLEMENT = 1,
00446    U_LATIN_EXTENDED_A = 2,
00447    U_LATIN_EXTENDED_B = 3,
00448    U_IPA_EXTENSIONS = 4,
00449    U_SPACING_MODIFIER_LETTERS = 5,
00450    U_COMBINING_DIACRITICAL_MARKS = 6,
00451    U_BASIC_GREEK = 7,
00452    U_GREEK_SYMBOLS_AND_COPTIC = 8,
00453    U_CYRILLIC = 9,
00454    U_ARMENIAN = 10,
00455    U_HEBREW_EXTENDED = 12,
00456    U_BASIC_HEBREW = 11,
00457    U_BASIC_ARABIC = 13,
00458    U_ARABIC_EXTENDED = 14,
00459    U_DEVANAGARI = 15,
00460    U_BENGALI = 16,
00461    U_GURMUKHI = 17,
00462    U_GUJARATI = 18,
00463    U_ORIYA = 19,
00464    U_TAMIL = 20,
00465    U_TELUGU = 21,
00466    U_KANNADA = 22,
00467    U_MALAYALAM = 23,
00468    U_THAI = 24,
00469    U_LAO = 25,
00470    U_GEORGIAN_EXTENDED = 27,
00471    U_BASIC_GEORGIAN = 26,
00472    U_HANGUL_JAMO = 28,
00473    U_LATIN_EXTENDED_ADDITIONAL = 29,
00474    U_GREEK_EXTENDED = 30,
00475    U_GENERAL_PUNCTUATION = 31,
00476    U_SUPERSCRIPTS_AND_SUBSCRIPTS = 32,
00477    U_CURRENCY_SYMBOLS = 33,
00478    U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS = 34,
00479    U_LETTERLIKE_SYMBOLS = 35,
00480    U_NUMBER_FORMS = 36,
00481    U_ARROWS = 37,
00482    U_MATHEMATICAL_OPERATORS = 38,
00483    U_MISCELLANEOUS_TECHNICAL = 39,
00484    U_CONTROL_PICTURES = 40,
00485    U_OPTICAL_CHARACTER_RECOGNITION = 41,
00486    U_ENCLOSED_ALPHANUMERICS = 42,
00487    U_BOX_DRAWING = 43,
00488    U_BLOCK_ELEMENTS = 44,
00489    U_GEOMETRIC_SHAPES = 45,
00490    U_MISCELLANEOUS_SYMBOLS = 46,
00491    U_DINGBATS = 47,
00492    U_CJK_SYMBOLS_AND_PUNCTUATION = 48,
00493    U_HIRAGANA = 49,
00494    U_KATAKANA = 50,
00495    U_BOPOMOFO = 51,
00496    U_HANGUL_COMPATIBILITY_JAMO = 52,
00497    U_CJK_MISCELLANEOUS = 53,
00498    U_ENCLOSED_CJK = 54,
00499    U_CJK_COMPATIBILITY = 55,
00500    U_HANGUL = 56,
00501    U_HANGUL_SUPPLEMENTARY_A = 57,
00502    U_HANGUL_SUPPLEMENTARY_B = 58,
00503    U_CJK_UNIFIED_IDEOGRAPHS = 59,
00504    U_PRIVATE_USE_AREA = 60,
00505    U_CJK_COMPATIBILITY_IDEOGRAPHS = 61,
00506    U_ALPHABETIC_PRESENTATION_FORMS = 62,
00507    U_ARABIC_PRESENTATION_FORMS_A = 63,
00508    U_COMBINING_HALF_MARKS = 64,
00509    U_CJK_COMPATIBILITY_FORMS = 65,
00510    U_SMALL_FORM_VARIANTS = 66,
00511    U_ARABIC_PRESENTATION_FORMS_B = 67,
00512    U_SPECIALS = 69,
00513    U_HALFWIDTH_AND_FULLWIDTH_FORMS = 68,
00514    U_LAST_PLUS_ONE
00515 } unicode_subset;
00516 
00517 static struct {
00518    wchar_t low, high;
00519    unicode_subset bit;
00520    gchar *name;
00521 } utab[] = {
00522    {
00523    0x0000, 0x007E, U_BASIC_LATIN, "Basic Latin"}, {
00524    0x00A0, 0x00FF, U_LATIN_1_SUPPLEMENT, "Latin-1 Supplement"}, {
00525    0x0100, 0x017F, U_LATIN_EXTENDED_A, "Latin Extended-A"}, {
00526    0x0180, 0x024F, U_LATIN_EXTENDED_B, "Latin Extended-B"}, {
00527    0x0250, 0x02AF, U_IPA_EXTENSIONS, "IPA Extensions"}, {
00528    0x02B0, 0x02FF,
00529           U_SPACING_MODIFIER_LETTERS, "Spacing Modifier Letters"}, {
00530    0x0300, 0x036F,
00531           U_COMBINING_DIACRITICAL_MARKS, "Combining Diacritical Marks"}, {
00532    0x0370, 0x03CF, U_BASIC_GREEK, "Basic Greek"}, {
00533    0x03D0, 0x03FF,
00534           U_GREEK_SYMBOLS_AND_COPTIC, "Greek Symbols and Coptic"}, {
00535    0x0400, 0x04FF, U_CYRILLIC, "Cyrillic"}, {
00536    0x0530, 0x058F, U_ARMENIAN, "Armenian"}, {
00537    0x0590, 0x05CF, U_HEBREW_EXTENDED, "Hebrew Extended"}, {
00538    0x05D0, 0x05FF, U_BASIC_HEBREW, "Basic Hebrew"}, {
00539    0x0600, 0x0652, U_BASIC_ARABIC, "Basic Arabic"}, {
00540    0x0653, 0x06FF, U_ARABIC_EXTENDED, "Arabic Extended"}, {
00541    0x0900, 0x097F, U_DEVANAGARI, "Devanagari"}, {
00542    0x0980, 0x09FF, U_BENGALI, "Bengali"}, {
00543    0x0A00, 0x0A7F, U_GURMUKHI, "Gurmukhi"}, {
00544    0x0A80, 0x0AFF, U_GUJARATI, "Gujarati"}, {
00545    0x0B00, 0x0B7F, U_ORIYA, "Oriya"}, {
00546    0x0B80, 0x0BFF, U_TAMIL, "Tamil"}, {
00547    0x0C00, 0x0C7F, U_TELUGU, "Telugu"}, {
00548    0x0C80, 0x0CFF, U_KANNADA, "Kannada"}, {
00549    0x0D00, 0x0D7F, U_MALAYALAM, "Malayalam"}, {
00550    0x0E00, 0x0E7F, U_THAI, "Thai"}, {
00551    0x0E80, 0x0EFF, U_LAO, "Lao"}, {
00552    0x10A0, 0x10CF, U_GEORGIAN_EXTENDED, "Georgian Extended"}, {
00553    0x10D0, 0x10FF, U_BASIC_GEORGIAN, "Basic Georgian"}, {
00554    0x1100, 0x11FF, U_HANGUL_JAMO, "Hangul Jamo"}, {
00555    0x1E00, 0x1EFF,
00556           U_LATIN_EXTENDED_ADDITIONAL, "Latin Extended Additional"}, {
00557    0x1F00, 0x1FFF, U_GREEK_EXTENDED, "Greek Extended"}, {
00558    0x2000, 0x206F, U_GENERAL_PUNCTUATION, "General Punctuation"}, {
00559    0x2070, 0x209F,
00560           U_SUPERSCRIPTS_AND_SUBSCRIPTS, "Superscripts and Subscripts"}, {
00561    0x20A0, 0x20CF, U_CURRENCY_SYMBOLS, "Currency Symbols"}, {
00562    0x20D0, 0x20FF,
00563           U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS,
00564           "Combining Diacritical Marks for Symbols"}, {
00565    0x2100, 0x214F, U_LETTERLIKE_SYMBOLS, "Letterlike Symbols"}, {
00566    0x2150, 0x218F, U_NUMBER_FORMS, "Number Forms"}, {
00567    0x2190, 0x21FF, U_ARROWS, "Arrows"}, {
00568    0x2200, 0x22FF, U_MATHEMATICAL_OPERATORS, "Mathematical Operators"}, {
00569    0x2300, 0x23FF, U_MISCELLANEOUS_TECHNICAL, "Miscellaneous Technical"}, {
00570    0x2400, 0x243F, U_CONTROL_PICTURES, "Control Pictures"}, {
00571    0x2440, 0x245F,
00572           U_OPTICAL_CHARACTER_RECOGNITION,
00573           "Optical Character Recognition"}, {
00574    0x2460, 0x24FF, U_ENCLOSED_ALPHANUMERICS, "Enclosed Alphanumerics"}, {
00575    0x2500, 0x257F, U_BOX_DRAWING, "Box Drawing"}, {
00576    0x2580, 0x259F, U_BLOCK_ELEMENTS, "Block Elements"}, {
00577    0x25A0, 0x25FF, U_GEOMETRIC_SHAPES, "Geometric Shapes"}, {
00578    0x2600, 0x26FF, U_MISCELLANEOUS_SYMBOLS, "Miscellaneous Symbols"}, {
00579    0x2700, 0x27BF, U_DINGBATS, "Dingbats"}, {
00580    0x3000, 0x303F,
00581           U_CJK_SYMBOLS_AND_PUNCTUATION, "CJK Symbols and Punctuation"}, {
00582    0x3040, 0x309F, U_HIRAGANA, "Hiragana"}, {
00583    0x30A0, 0x30FF, U_KATAKANA, "Katakana"}, {
00584    0x3100, 0x312F, U_BOPOMOFO, "Bopomofo"}, {
00585    0x3130, 0x318F,
00586           U_HANGUL_COMPATIBILITY_JAMO, "Hangul Compatibility Jamo"}, {
00587    0x3190, 0x319F, U_CJK_MISCELLANEOUS, "CJK Miscellaneous"}, {
00588    0x3200, 0x32FF, U_ENCLOSED_CJK, "Enclosed CJK"}, {
00589    0x3300, 0x33FF, U_CJK_COMPATIBILITY, "CJK Compatibility"},
00590        /* The book claims:
00591         * U+3400..U+3D2D Hangul
00592         * U+3D2E..U+44B7 Hangul Supplementary A
00593         * U+44B8..U+4DFF Hangul Supplementary B
00594         * but actually in Unicode
00595         * U+3400..U+4DB5 is CJK Unified Ideographs Extension A
00596         */
00597    {
00598    0x3400, 0x4DB5,
00599           U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs Extension A"},
00600    {
00601    0x4E00, 0x9FFF, U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs"},
00602        /* This was missing completely from the book's table. */
00603    {
00604    0xAC00, 0xD7A3, U_HANGUL, "Hangul Syllables"}, {
00605    0xE000, 0xF8FF, U_PRIVATE_USE_AREA, "Private Use Area"}, {
00606    0xF900, 0xFAFF,
00607           U_CJK_COMPATIBILITY_IDEOGRAPHS, "CJK Compatibility Ideographs"},
00608    {
00609    0xFB00, 0xFB4F,
00610           U_ALPHABETIC_PRESENTATION_FORMS,
00611           "Alphabetic Presentation Forms"}, {
00612    0xFB50, 0xFDFF, U_ARABIC_PRESENTATION_FORMS_A,
00613           "Arabic Presentation Forms-A"}, {
00614    0xFE20, 0xFE2F, U_COMBINING_HALF_MARKS, "Combining Half Marks"}, {
00615    0xFE30, 0xFE4F, U_CJK_COMPATIBILITY_FORMS, "CJK Compatibility Forms"}, {
00616    0xFE50, 0xFE6F, U_SMALL_FORM_VARIANTS, "Small Form Variants"}, {
00617    0xFE70, 0xFEFE,
00618           U_ARABIC_PRESENTATION_FORMS_B, "Arabic Presentation Forms-B"}, {
00619    0xFEFF, 0xFEFF, U_SPECIALS, "Specials"}, {
00620    0xFF00, 0xFFEF,
00621           U_HALFWIDTH_AND_FULLWIDTH_FORMS,
00622           "Halfwidth and Fullwidth Forms"}, {
00623    0xFFF0, 0xFFFD, U_SPECIALS, "Specials"}
00624 };
00625 
00626 static void print_unicode_subranges(FONTSIGNATURE * fsp)
00627 {
00628    int i;
00629    gboolean checked[sizeof(utab) / sizeof(utab[0])];
00630    gboolean need_comma = FALSE;
00631 
00632    memset(checked, 0, sizeof(checked));
00633 
00634    for (i = 0; i < sizeof(utab) / sizeof(utab[0]); i++)
00635       if (!checked[i]
00636           && (fsp->fsUsb[utab[i].bit / 32] & (1 << (utab[i].bit % 32)))) {
00637          g_print("%s %s", (need_comma ? "," : ""), utab[i].name);
00638          need_comma = TRUE;
00639          checked[i] = TRUE;
00640       }
00641    if (!need_comma)
00642       g_print(" none!");
00643    g_print("\n");
00644 }
00645 
00646 static gboolean check_unicode_subranges(UINT charset, FONTSIGNATURE * fsp)
00647 {
00648    gint i;
00649    gboolean retval = FALSE;
00650 
00651    /* If the fsUsb bit array has at least one of the bits set, trust it */
00652    for (i = 0; i < U_LAST_PLUS_ONE; i++)
00653       if (i != U_PRIVATE_USE_AREA
00654           && (fsp->fsUsb[i / 32] & (1 << (i % 32))))
00655          return FALSE;
00656 
00657    /* Otherwise, guess what subranges there should be in the font */
00658    fsp->fsUsb[0] = fsp->fsUsb[1] = fsp->fsUsb[2] = fsp->fsUsb[3] = 0;
00659 
00660 #define set_bit(bitno) (fsp->fsUsb[(bitno)/32] |= (1 << ((bitno) % 32)))
00661 
00662    /* Set Unicode subrange bits based on code pages supported.
00663     * This is mostly just guesswork.
00664     */
00665 
00666 #define check_cp(bit) (fsp->fsCsb[0] & (bit))
00667 
00668    if (check_cp(FS_LATIN1)) {
00669       set_bit(U_BASIC_LATIN);
00670       set_bit(U_LATIN_1_SUPPLEMENT);
00671       set_bit(U_CURRENCY_SYMBOLS);
00672       retval = TRUE;
00673    }
00674    if (check_cp(FS_LATIN2)) {
00675       set_bit(U_BASIC_LATIN);
00676       set_bit(U_LATIN_1_SUPPLEMENT);
00677       set_bit(U_LATIN_EXTENDED_A);
00678       set_bit(U_CURRENCY_SYMBOLS);
00679       retval = TRUE;
00680    }
00681    if (check_cp(FS_CYRILLIC)) {
00682       set_bit(U_BASIC_LATIN);
00683       set_bit(U_CYRILLIC);
00684       retval = TRUE;
00685    }
00686    if (check_cp(FS_GREEK)) {
00687       set_bit(U_BASIC_LATIN);
00688       set_bit(U_BASIC_GREEK);
00689       retval = TRUE;
00690    }
00691    if (check_cp(FS_TURKISH)) {
00692       set_bit(U_BASIC_LATIN);
00693       set_bit(U_LATIN_1_SUPPLEMENT);
00694       set_bit(U_LATIN_EXTENDED_A);
00695       set_bit(U_CURRENCY_SYMBOLS);
00696       retval = TRUE;
00697    }
00698    if (check_cp(FS_HEBREW)) {
00699       set_bit(U_BASIC_LATIN);
00700       set_bit(U_CURRENCY_SYMBOLS);
00701       set_bit(U_BASIC_HEBREW);
00702       set_bit(U_HEBREW_EXTENDED);
00703       retval = TRUE;
00704    }
00705    if (check_cp(FS_ARABIC)) {
00706       set_bit(U_BASIC_LATIN);
00707       set_bit(U_CURRENCY_SYMBOLS);
00708       set_bit(U_BASIC_ARABIC);
00709       set_bit(U_ARABIC_EXTENDED);
00710       retval = TRUE;
00711    }
00712    if (check_cp(FS_BALTIC)) {
00713       set_bit(U_BASIC_LATIN);
00714       set_bit(U_LATIN_1_SUPPLEMENT);
00715       set_bit(U_CURRENCY_SYMBOLS);
00716       set_bit(U_LATIN_EXTENDED_A);
00717       set_bit(U_LATIN_EXTENDED_B);
00718       retval = TRUE;
00719    }
00720    if (check_cp(FS_VIETNAMESE)) {
00721       /* ??? */
00722       set_bit(U_BASIC_LATIN);
00723       set_bit(U_LATIN_1_SUPPLEMENT);
00724       set_bit(U_CURRENCY_SYMBOLS);
00725       set_bit(U_LATIN_EXTENDED_A);
00726       set_bit(U_LATIN_EXTENDED_B);
00727       set_bit(U_LATIN_EXTENDED_ADDITIONAL);
00728       retval = TRUE;
00729    }
00730    if (check_cp(FS_THAI)) {
00731       set_bit(U_BASIC_LATIN);
00732       set_bit(U_THAI);
00733       retval = TRUE;
00734    }
00735    if (check_cp(FS_JISJAPAN)) {
00736       /* Based on MS Gothic */
00737       set_bit(U_BASIC_LATIN);
00738       set_bit(U_CJK_SYMBOLS_AND_PUNCTUATION);
00739       set_bit(U_HIRAGANA);
00740       set_bit(U_KATAKANA);
00741       set_bit(U_CJK_UNIFIED_IDEOGRAPHS);
00742       set_bit(U_HALFWIDTH_AND_FULLWIDTH_FORMS);
00743       retval = TRUE;
00744    }
00745    if (check_cp(FS_CHINESESIMP)) {
00746       /* Based on MS Hei */
00747       set_bit(U_BASIC_LATIN);
00748       set_bit(U_HIRAGANA);
00749       set_bit(U_KATAKANA);
00750       set_bit(U_BOPOMOFO);
00751       set_bit(U_CJK_UNIFIED_IDEOGRAPHS);
00752       retval = TRUE;
00753    }
00754    if (check_cp(FS_WANSUNG)
00755        || check_cp(FS_JOHAB)) { /* ??? */
00756       /* Based on GulimChe. I wonder if all Korean fonts
00757        * really support this large range of Unicode subranges?
00758        */
00759       set_bit(U_BASIC_LATIN);
00760       set_bit(U_LATIN_1_SUPPLEMENT);
00761       set_bit(U_LATIN_EXTENDED_A);
00762       set_bit(U_SPACING_MODIFIER_LETTERS);
00763       set_bit(U_BASIC_GREEK);
00764       set_bit(U_CYRILLIC);
00765       set_bit(U_HANGUL_JAMO);
00766       set_bit(U_GENERAL_PUNCTUATION);
00767       set_bit(U_SUPERSCRIPTS_AND_SUBSCRIPTS);
00768       set_bit(U_CURRENCY_SYMBOLS);
00769       set_bit(U_LETTERLIKE_SYMBOLS);
00770       set_bit(U_NUMBER_FORMS);
00771       set_bit(U_ARROWS);
00772       set_bit(U_MATHEMATICAL_OPERATORS);
00773       set_bit(U_MISCELLANEOUS_TECHNICAL);
00774       set_bit(U_ENCLOSED_ALPHANUMERICS);
00775       set_bit(U_BOX_DRAWING);
00776       set_bit(U_BLOCK_ELEMENTS);
00777       set_bit(U_GEOMETRIC_SHAPES);
00778       set_bit(U_MISCELLANEOUS_SYMBOLS);
00779       set_bit(U_CJK_SYMBOLS_AND_PUNCTUATION);
00780       set_bit(U_HIRAGANA);
00781       set_bit(U_KATAKANA);
00782       set_bit(U_HANGUL_COMPATIBILITY_JAMO);
00783       set_bit(U_ENCLOSED_CJK);
00784       set_bit(U_CJK_COMPATIBILITY_FORMS);
00785       set_bit(U_HANGUL);
00786       set_bit(U_CJK_UNIFIED_IDEOGRAPHS);
00787       set_bit(U_CJK_COMPATIBILITY_IDEOGRAPHS);
00788       set_bit(U_HALFWIDTH_AND_FULLWIDTH_FORMS);
00789       retval = TRUE;
00790    }
00791    if (check_cp(FS_CHINESETRAD)) {
00792       /* Based on MingLiU */
00793       set_bit(U_BASIC_LATIN);
00794       set_bit(U_GENERAL_PUNCTUATION);
00795       set_bit(U_BOX_DRAWING);
00796       set_bit(U_BLOCK_ELEMENTS);
00797       set_bit(U_CJK_SYMBOLS_AND_PUNCTUATION);
00798       set_bit(U_BOPOMOFO);
00799       set_bit(U_CJK_UNIFIED_IDEOGRAPHS);
00800       set_bit(U_CJK_COMPATIBILITY_IDEOGRAPHS);
00801       set_bit(U_SMALL_FORM_VARIANTS);
00802       set_bit(U_HALFWIDTH_AND_FULLWIDTH_FORMS);
00803       retval = TRUE;
00804    }
00805    if (check_cp(FS_SYMBOL) || charset == MAC_CHARSET) {
00806       /* Non-Unicode encoding, I guess. Pretend it covers
00807        * the single-byte range of values.
00808        */
00809       set_bit(U_BASIC_LATIN);
00810       set_bit(U_LATIN_1_SUPPLEMENT);
00811       retval = TRUE;
00812    }
00813 
00814    if (retval)
00815       return TRUE;
00816 
00817    GDK_NOTE(MISC, g_print("... No code page bits set!\n"));
00818 
00819    /* Sigh. Not even any code page bits were set. Guess based on
00820     * charset, then. These somewhat optimistic guesses are based on the
00821     * table in Appendix M in the book "Developing ..."  mentioned
00822     * above.
00823     */
00824    switch (charset) {
00825    case ANSI_CHARSET:
00826       set_bit(U_BASIC_LATIN);
00827       set_bit(U_LATIN_1_SUPPLEMENT);
00828       set_bit(U_LATIN_EXTENDED_A);
00829       set_bit(U_LATIN_EXTENDED_B);
00830       set_bit(U_SPACING_MODIFIER_LETTERS);
00831       set_bit(U_COMBINING_DIACRITICAL_MARKS);
00832       set_bit(U_GENERAL_PUNCTUATION);
00833       set_bit(U_SUPERSCRIPTS_AND_SUBSCRIPTS);
00834       set_bit(U_CURRENCY_SYMBOLS);
00835 #if 0                           /* I find this too hard to believe... */
00836       set_bit(U_BASIC_GREEK);
00837       set_bit(U_CYRILLIC);
00838       set_bit(U_BASIC_HEBREW);
00839       set_bit(U_HEBREW_EXTENDED);
00840       set_bit(U_BASIC_ARABIC);
00841       set_bit(U_ARABIC_EXTENDED);
00842       set_bit(U_LETTERLIKE_SYMBOLS);
00843       set_bit(U_NUMBER_FORMS);
00844       set_bit(U_ARROWS);
00845       set_bit(U_MATHEMATICAL_OPERATORS);
00846       set_bit(U_MISCELLANEOUS_TECHNICAL);
00847       set_bit(U_ENCLOSED_ALPHANUMERICS);
00848       set_bit(U_BOX_DRAWING);
00849       set_bit(U_BLOCK_ELEMENTS);
00850       set_bit(U_GEOMETRIC_SHAPES);
00851       set_bit(U_MISCELLANEOUS_SYMBOLS);
00852       set_bit(U_HIRAGANA);
00853       set_bit(U_KATAKANA);
00854       set_bit(U_BOPOMOFO);
00855       set_bit(U_HANGUL_COMPATIBILITY_JAMO);
00856       set_bit(U_CJK_MISCELLANEOUS);
00857       set_bit(U_CJK_COMPATIBILITY);
00858       set_bit(U_HANGUL);
00859       set_bit(U_HANGUL_SUPPLEMENTARY_A);
00860       set_bit(U_CJK_COMPATIBILITY_IDEOGRAPHS);
00861       set_bit(U_ALPHABETIC_PRESENTATION_FORMS);
00862       set_bit(U_SMALL_FORM_VARIANTS);
00863       set_bit(U_ARABIC_PRESENTATION_FORMS_B);
00864       set_bit(U_HALFWIDTH_AND_FULLWIDTH_FORMS);
00865       set_bit(U_SPECIALS);
00866 #endif
00867       retval = TRUE;
00868       break;
00869    case SYMBOL_CHARSET:
00870       /* Unggh */
00871       set_bit(U_BASIC_LATIN);
00872       set_bit(U_LATIN_1_SUPPLEMENT);
00873       retval = TRUE;
00874       break;
00875    case SHIFTJIS_CHARSET:
00876    case HANGEUL_CHARSET:
00877    case GB2312_CHARSET:
00878    case CHINESEBIG5_CHARSET:
00879    case JOHAB_CHARSET:
00880       /* The table really does claim these "locales" (it doesn't
00881        * talk about charsets per se) cover the same Unicode
00882        * subranges
00883        */
00884       set_bit(U_BASIC_LATIN);
00885       set_bit(U_LATIN_1_SUPPLEMENT);
00886       set_bit(U_LATIN_EXTENDED_A);
00887       set_bit(U_LATIN_EXTENDED_B);
00888       set_bit(U_SPACING_MODIFIER_LETTERS);
00889       set_bit(U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS);
00890       set_bit(U_BASIC_GREEK);
00891       set_bit(U_CYRILLIC);
00892       set_bit(U_HANGUL_JAMO);
00893       set_bit(U_GENERAL_PUNCTUATION);
00894       set_bit(U_SUPERSCRIPTS_AND_SUBSCRIPTS);
00895       set_bit(U_CURRENCY_SYMBOLS);
00896       set_bit(U_LETTERLIKE_SYMBOLS);
00897       set_bit(U_NUMBER_FORMS);
00898       set_bit(U_ARROWS);
00899       set_bit(U_MATHEMATICAL_OPERATORS);
00900       set_bit(U_MISCELLANEOUS_TECHNICAL);
00901       set_bit(U_ENCLOSED_ALPHANUMERICS);
00902       set_bit(U_BOX_DRAWING);
00903       set_bit(U_BLOCK_ELEMENTS);
00904       set_bit(U_GEOMETRIC_SHAPES);
00905       set_bit(U_MISCELLANEOUS_SYMBOLS);
00906       set_bit(U_CJK_SYMBOLS_AND_PUNCTUATION);
00907       set_bit(U_HIRAGANA);
00908       set_bit(U_KATAKANA);
00909       set_bit(U_BOPOMOFO);
00910       set_bit(U_HANGUL_COMPATIBILITY_JAMO);
00911       set_bit(U_CJK_MISCELLANEOUS);
00912       set_bit(U_CJK_COMPATIBILITY);
00913       set_bit(U_HANGUL);
00914       set_bit(U_HANGUL_SUPPLEMENTARY_A);
00915       set_bit(U_CJK_UNIFIED_IDEOGRAPHS);
00916       set_bit(U_CJK_COMPATIBILITY_IDEOGRAPHS);
00917       set_bit(U_ALPHABETIC_PRESENTATION_FORMS);
00918       set_bit(U_SMALL_FORM_VARIANTS);
00919       set_bit(U_ARABIC_PRESENTATION_FORMS_B);
00920       set_bit(U_SPECIALS);
00921       retval = TRUE;
00922       break;
00923    case HEBREW_CHARSET:
00924       set_bit(U_BASIC_LATIN);
00925       set_bit(U_LATIN_1_SUPPLEMENT);
00926       set_bit(U_LATIN_EXTENDED_B);
00927       set_bit(U_SPACING_MODIFIER_LETTERS);
00928       set_bit(U_BASIC_HEBREW);
00929       set_bit(U_HEBREW_EXTENDED);
00930       set_bit(U_GENERAL_PUNCTUATION);
00931       set_bit(U_LETTERLIKE_SYMBOLS);
00932       retval = TRUE;
00933       break;
00934    case ARABIC_CHARSET:
00935       set_bit(U_BASIC_LATIN);
00936       set_bit(U_LATIN_1_SUPPLEMENT);
00937       set_bit(U_LATIN_EXTENDED_A);
00938       set_bit(U_LATIN_EXTENDED_B);
00939       set_bit(U_SPACING_MODIFIER_LETTERS);
00940       set_bit(U_BASIC_GREEK);
00941       set_bit(U_BASIC_ARABIC);
00942       set_bit(U_ARABIC_EXTENDED);
00943       set_bit(U_GENERAL_PUNCTUATION);
00944       set_bit(U_LETTERLIKE_SYMBOLS);
00945       set_bit(U_ARROWS);
00946       set_bit(U_MATHEMATICAL_OPERATORS);
00947       set_bit(U_MISCELLANEOUS_TECHNICAL);
00948       set_bit(U_BOX_DRAWING);
00949       set_bit(U_BLOCK_ELEMENTS);
00950       set_bit(U_GEOMETRIC_SHAPES);
00951       set_bit(U_MISCELLANEOUS_SYMBOLS);
00952       set_bit(U_HALFWIDTH_AND_FULLWIDTH_FORMS);
00953       retval = TRUE;
00954       break;
00955    case GREEK_CHARSET:
00956       set_bit(U_BASIC_LATIN);
00957       set_bit(U_LATIN_1_SUPPLEMENT);
00958       set_bit(U_LATIN_EXTENDED_B);
00959       set_bit(U_BASIC_GREEK);
00960       set_bit(U_GENERAL_PUNCTUATION);
00961       set_bit(U_SUPERSCRIPTS_AND_SUBSCRIPTS);
00962       set_bit(U_LETTERLIKE_SYMBOLS);
00963       set_bit(U_ARROWS);
00964       set_bit(U_MATHEMATICAL_OPERATORS);
00965       set_bit(U_MISCELLANEOUS_TECHNICAL);
00966       set_bit(U_BOX_DRAWING);
00967       set_bit(U_BLOCK_ELEMENTS);
00968       set_bit(U_GEOMETRIC_SHAPES);
00969       set_bit(U_MISCELLANEOUS_SYMBOLS);
00970       retval = TRUE;
00971       break;
00972    case TURKISH_CHARSET:
00973       set_bit(U_BASIC_LATIN);
00974       set_bit(U_LATIN_1_SUPPLEMENT);
00975       set_bit(U_LATIN_EXTENDED_A);
00976       set_bit(U_LATIN_EXTENDED_B);
00977       set_bit(U_SPACING_MODIFIER_LETTERS);
00978       set_bit(U_BASIC_GREEK);
00979       set_bit(U_GENERAL_PUNCTUATION);
00980       set_bit(U_SUPERSCRIPTS_AND_SUBSCRIPTS);
00981       set_bit(U_CURRENCY_SYMBOLS);
00982       set_bit(U_LETTERLIKE_SYMBOLS);
00983       set_bit(U_ARROWS);
00984       set_bit(U_MATHEMATICAL_OPERATORS);
00985       set_bit(U_MISCELLANEOUS_TECHNICAL);
00986       set_bit(U_BOX_DRAWING);
00987       set_bit(U_BLOCK_ELEMENTS);
00988       set_bit(U_GEOMETRIC_SHAPES);
00989       set_bit(U_MISCELLANEOUS_SYMBOLS);
00990       retval = TRUE;
00991       break;
00992    case VIETNAMESE_CHARSET:
00993    case THAI_CHARSET:
00994       /* These are not in the table, so I have no idea */
00995       break;
00996    case BALTIC_CHARSET:
00997       set_bit(U_BASIC_LATIN);
00998       set_bit(U_LATIN_1_SUPPLEMENT);
00999       set_bit(U_LATIN_EXTENDED_A);
01000       set_bit(U_LATIN_EXTENDED_B);
01001       set_bit(U_SPACING_MODIFIER_LETTERS);
01002       set_bit(U_BASIC_GREEK);
01003       set_bit(U_GENERAL_PUNCTUATION);
01004       set_bit(U_SUPERSCRIPTS_AND_SUBSCRIPTS);
01005       set_bit(U_CURRENCY_SYMBOLS);
01006       set_bit(U_LETTERLIKE_SYMBOLS);
01007       set_bit(U_ARROWS);
01008       set_bit(U_MATHEMATICAL_OPERATORS);
01009       set_bit(U_MISCELLANEOUS_TECHNICAL);
01010       set_bit(U_BOX_DRAWING);
01011       set_bit(U_BLOCK_ELEMENTS);
01012       set_bit(U_GEOMETRIC_SHAPES);
01013       set_bit(U_MISCELLANEOUS_SYMBOLS);
01014       retval = TRUE;
01015       break;
01016    case EASTEUROPE_CHARSET:
01017       set_bit(U_BASIC_LATIN);
01018       set_bit(U_LATIN_1_SUPPLEMENT);
01019       set_bit(U_LATIN_EXTENDED_A);
01020       set_bit(U_LATIN_EXTENDED_B);
01021       set_bit(U_SPACING_MODIFIER_LETTERS);
01022       set_bit(U_BASIC_GREEK);
01023       set_bit(U_GENERAL_PUNCTUATION);
01024       set_bit(U_SUPERSCRIPTS_AND_SUBSCRIPTS);
01025       set_bit(U_CURRENCY_SYMBOLS);
01026       set_bit(U_LETTERLIKE_SYMBOLS);
01027       set_bit(U_ARROWS);
01028       set_bit(U_MATHEMATICAL_OPERATORS);
01029       set_bit(U_MISCELLANEOUS_TECHNICAL);
01030       set_bit(U_BOX_DRAWING);
01031       set_bit(U_BLOCK_ELEMENTS);
01032       set_bit(U_GEOMETRIC_SHAPES);
01033       set_bit(U_MISCELLANEOUS_SYMBOLS);
01034       retval = TRUE;
01035       break;
01036    case RUSSIAN_CHARSET:
01037       set_bit(U_BASIC_LATIN);
01038       set_bit(U_LATIN_1_SUPPLEMENT);
01039       set_bit(U_CYRILLIC);
01040       set_bit(U_GENERAL_PUNCTUATION);
01041       set_bit(U_LETTERLIKE_SYMBOLS);
01042       set_bit(U_ARROWS);
01043       set_bit(U_MATHEMATICAL_OPERATORS);
01044       set_bit(U_MISCELLANEOUS_TECHNICAL);
01045       set_bit(U_BOX_DRAWING);
01046       set_bit(U_BLOCK_ELEMENTS);
01047       set_bit(U_GEOMETRIC_SHAPES);
01048       set_bit(U_MISCELLANEOUS_SYMBOLS);
01049       retval = TRUE;
01050       break;
01051    }
01052 
01053 #undef set_bit
01054    return retval;
01055 }
01056 
01057 //-----------------------------------------------------------------------------
01058 
01059 GdkWin32SingleFont *gdk_font_load_internal(const gchar * font_name)
01060 {
01061    GdkWin32SingleFont *singlefont;
01062    HFONT hfont;
01063    LOGFONT logfont;
01064    CHARSETINFO csi;
01065    DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
01066        fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
01067    HGDIOBJ oldfont;
01068    char *lpszFace;
01069    gchar face[100];
01070 
01071    int numfields, n1, n2, tries;
01072    char foundry[32], family[100], weight[32], slant[32], set_width[32],
01073        spacing[32], registry[32], encoding[32];
01074    char pixel_size[10], point_size[10], res_x[10], res_y[10],
01075        avg_width[10];
01076    int c;
01077    char *p;
01078    int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
01079    int logpixelsy;
01080 
01081    g_return_val_if_fail(font_name != NULL, NULL);
01082 
01083    GDK_NOTE(MISC, g_print("gdk_font_load_internal: %s\n", font_name));
01084 
01085    numfields = sscanf(font_name,
01086                       "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
01087                       foundry, family, weight, slant, set_width, &n1);
01088    if (numfields == 0) {
01089       /* Probably a plain Windows font name */
01090       nHeight = 0;
01091       nWidth = 0;
01092 //      nEscapement = 0;
01093 //      nOrientation = 0;
01094       gfont_angle = atoi(set_width);
01095       nOrientation = (int) gfont_angle;
01096       nEscapement = (int) gfont_angle;
01097       fnWeight = FW_DONTCARE;
01098       fdwItalic = FALSE;
01099       fdwUnderline = FALSE;
01100       fdwStrikeOut = FALSE;
01101       fdwCharSet = ANSI_CHARSET;
01102       fdwOutputPrecision = OUT_TT_PRECIS;
01103       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
01104       fdwQuality = PROOF_QUALITY;
01105       fdwPitchAndFamily = DEFAULT_PITCH;
01106       lpszFace = g_filename_from_utf8(font_name, NULL);
01107    } else if (numfields != 5) {
01108       g_warning("gdk_font_load: font name %s illegal", font_name);
01109       return NULL;
01110    } else {
01111       /* It must be a XLFD name */
01112 
01113       /* Check for hex escapes in the font family,
01114        * put in there by logfont_to_xlfd. Convert them in-place.
01115        */
01116       p = family;
01117       while (*p) {
01118          if (*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) {
01119             sscanf(p + 1, "%2x", &c);
01120             *p = c;
01121             strcpy(p + 1, p + 3);
01122          }
01123          p++;
01124       }
01125 
01126       /* Skip add_style which often is empty in the requested font name */
01127       while (font_name[n1] && font_name[n1] != '-')
01128          n1++;
01129       numfields++;
01130 
01131       numfields += sscanf(font_name + n1,
01132                           "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
01133                           pixel_size,
01134                           point_size,
01135                           res_x,
01136                           res_y,
01137                           spacing, avg_width, registry, encoding, &n2);
01138 
01139       if (numfields != 14 || font_name[n1 + n2] != '\0') {
01140          g_warning("gdk_font_load: font name %s illegal", font_name);
01141          return NULL;
01142       }
01143 
01144       logpixelsy = GetDeviceCaps(gdk_DC, LOGPIXELSY);
01145 
01146       if (strcmp(pixel_size, "*") == 0) {
01147          if (strcmp(point_size, "*") == 0) {
01148             nHeight = 0;
01149          }
01150          else {
01151             nHeight = -MulDiv(atoi(point_size), GetDeviceCaps(gdk_DC, LOGPIXELSY), 72);
01152 //                (int) (((double) atoi(point_size)) / 720. * logpixelsy);
01153          }
01154       }
01155       else {
01156          nHeight = -1 * atoi(pixel_size);
01157       }
01158 
01159       nWidth = 0;
01160 //      nEscapement = 0;
01161 //      nOrientation = 0;
01162       gfont_angle = atoi(avg_width);
01163       nOrientation = (int) gfont_angle; // bb change
01164       nEscapement = (int) gfont_angle;  // bb change
01165 
01166       if (g_strcasecmp(weight, "thin") == 0)
01167          fnWeight = FW_THIN;
01168       else if (g_strcasecmp(weight, "extralight") == 0)
01169          fnWeight = FW_EXTRALIGHT;
01170       else if (g_strcasecmp(weight, "ultralight") == 0)
01171 #ifdef FW_ULTRALIGHT
01172          fnWeight = FW_ULTRALIGHT;
01173 #else
01174          fnWeight = FW_EXTRALIGHT;      /* In fact, FW_ULTRALIGHT really is 
01175          * defined as FW_EXTRALIGHT anyway.
01176          */
01177 #endif
01178       else if (g_strcasecmp(weight, "light") == 0)
01179          fnWeight = FW_LIGHT;
01180       else if (g_strcasecmp(weight, "normal") == 0)
01181          fnWeight = FW_NORMAL;
01182       else if (g_strcasecmp(weight, "regular") == 0)
01183          fnWeight = FW_REGULAR;
01184       else if (g_strcasecmp(weight, "medium") == 0)
01185          fnWeight = FW_MEDIUM;
01186       else if (g_strcasecmp(weight, "semibold") == 0)
01187          fnWeight = FW_SEMIBOLD;
01188       else if (g_strcasecmp(weight, "demibold") == 0)
01189 #ifdef FW_DEMIBOLD
01190          fnWeight = FW_DEMIBOLD;
01191 #else
01192          fnWeight = FW_SEMIBOLD;        /* As above */
01193 #endif
01194       else if (g_strcasecmp(weight, "bold") == 0)
01195          fnWeight = FW_BOLD;
01196       else if (g_strcasecmp(weight, "extrabold") == 0)
01197          fnWeight = FW_EXTRABOLD;
01198       else if (g_strcasecmp(weight, "ultrabold") == 0)
01199 #ifdef FW_ULTRABOLD
01200          fnWeight = FW_ULTRABOLD;
01201 #else
01202          fnWeight = FW_EXTRABOLD;       /* As above */
01203 #endif
01204       else if (g_strcasecmp(weight, "heavy") == 0)
01205          fnWeight = FW_HEAVY;
01206       else if (g_strcasecmp(weight, "black") == 0)
01207 #ifdef FW_BLACK
01208          fnWeight = FW_BLACK;
01209 #else
01210          fnWeight = FW_HEAVY;   /* As above */
01211 #endif
01212       else
01213          fnWeight = FW_DONTCARE;
01214 
01215       if (g_strcasecmp(slant, "italic") == 0
01216           || g_strcasecmp(slant, "oblique") == 0
01217           || g_strcasecmp(slant, "i") == 0
01218           || g_strcasecmp(slant, "o") == 0)
01219          fdwItalic = TRUE;
01220       else
01221          fdwItalic = FALSE;
01222       fdwUnderline = FALSE;
01223       fdwStrikeOut = FALSE;
01224       if (g_strcasecmp(registry, "iso8859") == 0)
01225          if (strcmp(encoding, "1") == 0)
01226             fdwCharSet = ANSI_CHARSET;
01227          else if (strcmp(encoding, "2") == 0)
01228             fdwCharSet = EASTEUROPE_CHARSET;
01229          else if (strcmp(encoding, "7") == 0)
01230             fdwCharSet = GREEK_CHARSET;
01231          else if (strcmp(encoding, "8") == 0)
01232             fdwCharSet = HEBREW_CHARSET;
01233          else if (strcmp(encoding, "9") == 0)
01234             fdwCharSet = TURKISH_CHARSET;
01235          else
01236             fdwCharSet = ANSI_CHARSET;  /* XXX ??? */
01237       else if (g_strcasecmp(registry, "jisx0208.1983") == 0)
01238          fdwCharSet = SHIFTJIS_CHARSET;
01239       else if (g_strcasecmp(registry, "ksc5601.1987") == 0)
01240          fdwCharSet = HANGEUL_CHARSET;
01241       else if (g_strcasecmp(registry, "gb2312.1980") == 0)
01242          fdwCharSet = GB2312_CHARSET;
01243       else if (g_strcasecmp(registry, "big5") == 0)
01244          fdwCharSet = CHINESEBIG5_CHARSET;
01245       else if (g_strcasecmp(registry, "windows") == 0
01246                || g_strcasecmp(registry, "microsoft") == 0)
01247          if (g_strcasecmp(encoding, "symbol") == 0)
01248             fdwCharSet = SYMBOL_CHARSET;
01249          else if (g_strcasecmp(encoding, "shiftjis") == 0)
01250             fdwCharSet = SHIFTJIS_CHARSET;
01251          else if (g_strcasecmp(encoding, "gb2312") == 0)
01252             fdwCharSet = GB2312_CHARSET;
01253          else if (g_strcasecmp(encoding, "hangeul") == 0)
01254             fdwCharSet = HANGEUL_CHARSET;
01255          else if (g_strcasecmp(encoding, "big5") == 0)
01256             fdwCharSet = CHINESEBIG5_CHARSET;
01257          else if (g_strcasecmp(encoding, "johab") == 0)
01258             fdwCharSet = JOHAB_CHARSET;
01259          else if (g_strcasecmp(encoding, "hebrew") == 0)
01260             fdwCharSet = HEBREW_CHARSET;
01261          else if (g_strcasecmp(encoding, "arabic") == 0)
01262             fdwCharSet = ARABIC_CHARSET;
01263          else if (g_strcasecmp(encoding, "greek") == 0)
01264             fdwCharSet = GREEK_CHARSET;
01265          else if (g_strcasecmp(encoding, "turkish") == 0)
01266             fdwCharSet = TURKISH_CHARSET;
01267          else if (g_strcasecmp(encoding, "easteurope") == 0)
01268             fdwCharSet = EASTEUROPE_CHARSET;
01269          else if (g_strcasecmp(encoding, "russian") == 0)
01270             fdwCharSet = RUSSIAN_CHARSET;
01271          else if (g_strcasecmp(encoding, "mac") == 0)
01272             fdwCharSet = MAC_CHARSET;
01273          else if (g_strcasecmp(encoding, "baltic") == 0)
01274             fdwCharSet = BALTIC_CHARSET;
01275          else if (g_strcasecmp(encoding, "cp1251") == 0)
01276             fdwCharSet = RUSSIAN_CHARSET;
01277          else
01278             fdwCharSet = ANSI_CHARSET;  /* XXX ??? */
01279       else
01280          fdwCharSet = ANSI_CHARSET;     /* XXX ??? */
01281       fdwOutputPrecision = OUT_TT_PRECIS;       //OUT_TT_ONLY_PRECIS;
01282       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
01283       fdwQuality = PROOF_QUALITY;       //ANTIALIASED_QUALITY;
01284       if (g_strcasecmp(spacing, "m") == 0)
01285          fdwPitchAndFamily = FIXED_PITCH;
01286       else if (g_strcasecmp(spacing, "p") == 0)
01287          fdwPitchAndFamily = VARIABLE_PITCH;
01288       else
01289          fdwPitchAndFamily = DEFAULT_PITCH;
01290       lpszFace = g_filename_from_utf8(family, NULL);
01291    }
01292 
01293    for (tries = 0;; tries++) {
01294       GDK_NOTE(MISC, g_print("... trying CreateFont(%d,%d,%d,%d,"
01295                              "%d,%d,%d,%d,"
01296                              "%d,%d,%d,"
01297                              "%d,%#.02x,\"%s\")\n",
01298                              nHeight, nWidth, nEscapement, nOrientation,
01299                              fnWeight, fdwItalic, fdwUnderline,
01300                              fdwStrikeOut, fdwCharSet, fdwOutputPrecision,
01301                              fdwClipPrecision, fdwQuality,
01302                              fdwPitchAndFamily, lpszFace));
01303       hfont =
01304           CreateFont(nHeight, nWidth, nEscapement, nOrientation, fnWeight,
01305                      fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
01306                      fdwOutputPrecision, fdwClipPrecision, fdwQuality,
01307                      fdwPitchAndFamily, lpszFace);
01308       /* After the first try lpszFace contains a return value
01309        * from g_filename_from_utf8(), so free it.
01310        */
01311       if (tries == 0)
01312          g_free(lpszFace);
01313 
01314       if (hfont != NULL)
01315          break;
01316 
01317       /* If we fail, try some similar fonts often found on Windows. */
01318       if (tries == 0) {
01319          if (g_strcasecmp(family, "helvetica") == 0)
01320             lpszFace = "arial";
01321          else if (g_strcasecmp(family, "new century schoolbook") == 0)
01322             lpszFace = "century schoolbook";
01323          else if (g_strcasecmp(family, "courier") == 0)
01324             lpszFace = "courier new";
01325          else if (g_strcasecmp(family, "lucida") == 0)
01326             lpszFace = "lucida sans unicode";
01327          else if (g_strcasecmp(family, "lucidatypewriter") == 0)
01328             lpszFace = "lucida console";
01329          else if (g_strcasecmp(family, "times") == 0)
01330             lpszFace = "times new roman";
01331       } else if (tries == 1) {
01332          if (g_strcasecmp(family, "courier") == 0) {
01333             lpszFace = "";
01334             fdwPitchAndFamily |= FF_MODERN;
01335          } else if (g_strcasecmp(family, "times new roman") == 0) {
01336             lpszFace = "";
01337             fdwPitchAndFamily |= FF_ROMAN;
01338          } else if (g_strcasecmp(family, "helvetica") == 0
01339                     || g_strcasecmp(family, "lucida") == 0) {
01340             lpszFace = "";
01341             fdwPitchAndFamily |= FF_SWISS;
01342          } else {
01343             lpszFace = "";
01344             fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
01345          }
01346       } else
01347          break;
01348       tries++;
01349    }
01350 
01351    if (!hfont)
01352       return NULL;
01353 
01354    singlefont = g_new(GdkWin32SingleFont, 1);
01355    singlefont->xfont = hfont;
01356    GetObject(singlefont->xfont, sizeof(logfont), &logfont);
01357    oldfont = SelectObject(gdk_DC, singlefont->xfont);
01358    memset(&singlefont->fs, 0, sizeof(singlefont->fs));
01359    singlefont->charset = GetTextCharsetInfo(gdk_DC, &singlefont->fs, 0);
01360    GetTextFace(gdk_DC, sizeof(face), face);
01361    SelectObject(gdk_DC, oldfont);
01362    if (TranslateCharsetInfo((DWORD *) singlefont->charset, &csi,
01363                             TCI_SRCCHARSET)
01364        && singlefont->charset != MAC_CHARSET)
01365       singlefont->codepage = csi.ciACP;
01366    else
01367       singlefont->codepage = 0;
01368 
01369    GDK_NOTE(MISC, (g_print("... = %#x %s cs %s cp%d\n",
01370                            singlefont->xfont, face,
01371                            charset_name(singlefont->charset),
01372                            singlefont->codepage),
01373                    g_print("... Unicode subranges:"),
01374                    print_unicode_subranges(&singlefont->fs)));
01375    if (check_unicode_subranges(singlefont->charset, &singlefont->fs))
01376       GDK_NOTE(MISC, (g_print("... Guesstimated Unicode subranges:"),
01377                       print_unicode_subranges(&singlefont->fs)));
01378 
01379    return singlefont;
01380 }
01381 
01382 GdkFont *gdk_font_load(const gchar * font_name)
01383 {
01384    GdkFont *font;
01385    GdkFontPrivateWin32 *private;
01386    GdkWin32SingleFont *singlefont;
01387    HGDIOBJ oldfont;
01388    HANDLE *f;
01389    TEXTMETRIC textmetric;
01390 
01391    g_return_val_if_fail(font_name != NULL, NULL);
01392 
01393    font = gdk_font_hash_lookup(GDK_FONT_FONTSET, font_name);
01394    if (font)
01395       return font;
01396 
01397    singlefont = gdk_font_load_internal(font_name);
01398 
01399    private = g_new(GdkFontPrivateWin32, 1);
01400    font = (GdkFont *) private;
01401 
01402    private->base.ref_count = 1;
01403    private->names = NULL;
01404    private->fonts = g_slist_append(NULL, singlefont);
01405 
01406    /* Pretend all fonts are fontsets... Gtktext and gtkentry work better
01407     * that way, they use wide chars, which is necessary for non-ASCII
01408     * chars to work. (Yes, even Latin-1, as we use Unicode internally.)
01409     */
01410    font->type = GDK_FONT_FONTSET;
01411    oldfont = SelectObject(gdk_DC, singlefont->xfont);
01412    GetTextMetrics(gdk_DC, &textmetric);
01413    SelectObject(gdk_DC, oldfont);
01414    font->ascent = textmetric.tmAscent;
01415    font->descent = textmetric.tmDescent;
01416 
01417    GDK_NOTE(MISC, g_print("... asc %d desc %d\n",
01418                           font->ascent, font->descent));
01419 
01420    gdk_font_hash_insert(GDK_FONT_FONTSET, font, font_name);
01421 
01422    return font;
01423 }
01424 
01425 GdkFont *gdk_fontset_load(const gchar * fontset_name)
01426 {
01427    GdkFont *font;
01428    GdkFontPrivateWin32 *private;
01429    GdkWin32SingleFont *singlefont;
01430    HGDIOBJ oldfont;
01431    HANDLE *f;
01432    TEXTMETRIC textmetric;
01433    GSList *base_font_list = NULL;
01434    gchar *fs;
01435    gchar *b, *p, *s;
01436 
01437    g_return_val_if_fail(fontset_name != NULL, NULL);
01438 
01439    font = gdk_font_hash_lookup(GDK_FONT_FONTSET, fontset_name);
01440    if (font)
01441       return font;
01442 
01443    s = fs = g_strdup(fontset_name);
01444    while (*s && isspace(*s))
01445       s++;
01446 
01447    g_return_val_if_fail(*s, NULL);
01448 
01449    private = g_new(GdkFontPrivateWin32, 1);
01450    font = (GdkFont *) private;
01451 
01452    private->base.ref_count = 1;
01453    private->names = NULL;
01454    private->fonts = NULL;
01455 
01456    font->type = GDK_FONT_FONTSET;
01457    font->ascent = 0;
01458    font->descent = 0;
01459 
01460    while (TRUE) {
01461       if ((p = strchr(s, ',')) != NULL)
01462          b = p;
01463       else
01464          b = s + strlen(s);
01465 
01466       while (isspace(b[-1]))
01467          b--;
01468       *b = '\0';
01469       singlefont = gdk_font_load_internal(s);
01470       if (singlefont) {
01471          private->fonts = g_slist_append(private->fonts, singlefont);
01472          oldfont = SelectObject(gdk_DC, singlefont->xfont);
01473          GetTextMetrics(gdk_DC, &textmetric);
01474          SelectObject(gdk_DC, oldfont);
01475          font->ascent = MAX(font->ascent, textmetric.tmAscent);
01476          font->descent = MAX(font->descent, textmetric.tmDescent);
01477       }
01478       if (p) {
01479          s = p + 1;
01480          while (*s && isspace(*s))
01481             s++;
01482       } else
01483          break;
01484       if (!*s)
01485          break;
01486    }
01487 
01488    g_free(fs);
01489 
01490    gdk_font_hash_insert(GDK_FONT_FONTSET, font, fontset_name);
01491 
01492    return font;
01493 }
01494 
01495 void _gdk_font_destroy(GdkFont * font)
01496 {
01497    GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
01498    GdkWin32SingleFont *singlefont;
01499    GSList *list;
01500 
01501    singlefont = (GdkWin32SingleFont *) private->fonts->data;
01502    GDK_NOTE(MISC, g_print("_gdk_font_destroy %#x\n", singlefont->xfont));
01503 
01504    gdk_font_hash_remove(font->type, font);
01505 
01506    switch (font->type) {
01507    case GDK_FONT_FONT:
01508       DeleteObject(singlefont->xfont);
01509       break;
01510 
01511    case GDK_FONT_FONTSET:
01512       list = private->fonts;
01513       while (list) {
01514          singlefont = (GdkWin32SingleFont *) list->data;
01515          DeleteObject(singlefont->xfont);
01516 
01517          list = list->next;
01518       }
01519       g_slist_free(private->fonts);
01520       break;
01521    }
01522    g_free(font);
01523 }
01524 
01525 gint _gdk_font_strlen(GdkFont * font, const gchar * str)
01526 {
01527    g_return_val_if_fail(font != NULL, -1);
01528    g_return_val_if_fail(str != NULL, -1);
01529 
01530    return strlen(str);
01531 }
01532 
01533 gint gdk_font_id(const GdkFont * font)
01534 {
01535    const GdkFontPrivateWin32 *private;
01536 
01537    g_return_val_if_fail(font != NULL, 0);
01538 
01539    private = (const GdkFontPrivateWin32 *) font;
01540 
01541    if (font->type == GDK_FONT_FONT)
01542       return (gint) ((GdkWin32SingleFont *) private->fonts->data)->xfont;
01543    else
01544       return 0;
01545 }
01546 
01547 gint gdk_font_equal(const GdkFont * fonta, const GdkFont * fontb)
01548 {
01549    const GdkFontPrivateWin32 *privatea;
01550    const GdkFontPrivateWin32 *privateb;
01551 
01552    g_return_val_if_fail(fonta != NULL, FALSE);
01553    g_return_val_if_fail(fontb != NULL, FALSE);
01554 
01555    privatea = (const GdkFontPrivateWin32 *) fonta;
01556    privateb = (const GdkFontPrivateWin32 *) fontb;
01557 
01558    if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
01559       return (((GdkWin32SingleFont *) privatea->fonts->data)->xfont
01560               == ((GdkWin32SingleFont *) privateb->fonts->data)->xfont);
01561    else if (fonta->type == GDK_FONT_FONTSET
01562             && fontb->type == GDK_FONT_FONTSET) {
01563       GSList *lista = privatea->fonts;
01564       GSList *listb = privateb->fonts;
01565 
01566       while (lista && listb) {
01567          if (((GdkWin32SingleFont *) lista->data)->xfont
01568              != ((GdkWin32SingleFont *) listb->data)->xfont)
01569             return 0;
01570          lista = lista->next;
01571          listb = listb->next;
01572       }
01573       if (lista || listb)
01574          return 0;
01575       else
01576          return 1;
01577    } else
01578       return 0;
01579 }
01580 
01581 /* Return the Unicode Subset bitfield number for a Unicode character */
01582 
01583 static int unicode_classify(wchar_t wc)
01584 {
01585    int min = 0;
01586    int max = sizeof(utab) / sizeof(utab[0]) - 1;
01587    int mid;
01588 
01589    while (max >= min) {
01590       mid = (min + max) / 2;
01591       if (utab[mid].high < wc)
01592          min = mid + 1;
01593       else if (wc < utab[mid].low)
01594          max = mid - 1;
01595       else if (utab[mid].low <= wc && wc <= utab[mid].high)
01596          return utab[mid].bit;
01597       else
01598          return -1;
01599    }
01600    return -1;
01601 }
01602 
01603 void
01604 gdk_wchar_text_handle(GdkFont * font,
01605                       const wchar_t * wcstr,
01606                       int wclen,
01607                       void (*handler) (GdkWin32SingleFont *,
01608                                        const wchar_t *,
01609                                        int, void *), void *arg)
01610 {
01611    GdkFontPrivateWin32 *private;
01612    GdkWin32SingleFont *singlefont;
01613    GSList *list;
01614    int i, block;
01615    const wchar_t *start, *end, *wcp;
01616 
01617    wcp = wcstr;
01618    end = wcp + wclen;
01619    private = (GdkFontPrivateWin32 *) font;
01620 
01621    g_assert(private->base.ref_count > 0);
01622 
01623    GDK_NOTE(MISC, g_print("gdk_wchar_text_handle: "));
01624 
01625    while (wcp < end) {
01626       /* Split Unicode string into pieces of the same class */
01627       start = wcp;
01628       block = unicode_classify(*wcp);
01629       while (wcp + 1 < end && unicode_classify(wcp[1]) == block)
01630          wcp++;
01631 
01632       /* Find a font in the fontset that can handle this class */
01633       list = private->fonts;
01634       while (list) {
01635          singlefont = (GdkWin32SingleFont *) list->data;
01636 
01637          if (singlefont->fs.fsUsb[block / 32] & (1 << (block % 32)))
01638             break;
01639 
01640          list = list->next;
01641       }
01642 
01643       if (!list)
01644          singlefont = NULL;
01645 
01646       GDK_NOTE(MISC,
01647                g_print("%d:%d:%d ", start - wcstr, wcp - wcstr, block));
01648 
01649       /* Call the callback function */
01650       (*handler) (singlefont, start, wcp + 1 - start, arg);
01651       wcp++;
01652    }
01653    GDK_NOTE(MISC, g_print("\n"));
01654 }
01655 
01656 typedef struct {
01657    SIZE total;
01658 } gdk_text_size_arg;
01659 
01660 static void
01661 gdk_text_size_handler(GdkWin32SingleFont * singlefont,
01662                       const wchar_t * wcstr, int wclen, void *argp)
01663 {
01664    SIZE this_size;
01665    HGDIOBJ oldfont;
01666    gdk_text_size_arg *arg = (gdk_text_size_arg *) argp;
01667 
01668    if (!singlefont)
01669       return;
01670 
01671    if ((oldfont = SelectObject(gdk_DC, singlefont->xfont)) == NULL) {
01672       WIN32_GDI_FAILED("SelectObject");
01673       return;
01674    }
01675    GetTextExtentPoint32W(gdk_DC, wcstr, wclen, &this_size);
01676    SelectObject(gdk_DC, oldfont);
01677 
01678    arg->total.cx += this_size.cx;
01679    arg->total.cy = MAX(arg->total.cy, this_size.cy);
01680 }
01681 
01682 static gboolean
01683 gdk_text_size(GdkFont * font,
01684               const gchar * text,
01685               gint text_length, gdk_text_size_arg * arg)
01686 {
01687    gint wlen;
01688    wchar_t *wcstr;
01689 
01690    g_return_val_if_fail(font != NULL, FALSE);
01691    g_return_val_if_fail(text != NULL, FALSE);
01692 
01693    if (text_length == 0)
01694       return 0;
01695 
01696    g_assert(font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
01697 
01698    wcstr = g_new(wchar_t, text_length);
01699    if (text_length == 1) {
01700       /* For single characters, don't try to interpret as UTF-8.
01701        */
01702       wcstr[0] = (guchar) text[0];
01703       gdk_wchar_text_handle(font, wcstr, 1, gdk_text_size_handler, arg);
01704    } else {
01705       if ((wlen =
01706            gdk_nmbstowchar_ts(wcstr, text, text_length,
01707                               text_length)) == -1)
01708          g_warning("gdk_text_size: gdk_nmbstowchar_ts failed");
01709       else
01710          gdk_wchar_text_handle(font, wcstr, wlen, gdk_text_size_handler,
01711                                arg);
01712    }
01713 
01714    g_free(wcstr);
01715 
01716    return TRUE;
01717 }
01718 
01719 gint gdk_text_width(GdkFont * font, const gchar * text, gint text_length)
01720 {
01721    gdk_text_size_arg arg;
01722 
01723    arg.total.cx = arg.total.cy = 0;
01724 
01725    if (!gdk_text_size(font, text, text_length, &arg))
01726       return -1;
01727 
01728    return arg.total.cx;
01729 }
01730 
01731 gint
01732 gdk_text_width_wc(GdkFont * font, const GdkWChar * text, gint text_length)
01733 {
01734    gdk_text_size_arg arg;
01735    wchar_t *wcstr;
01736    gint i;
01737 
01738    g_return_val_if_fail(font != NULL, -1);
01739    g_return_val_if_fail(text != NULL, -1);
01740 
01741    if (text_length == 0)
01742       return 0;
01743 
01744    g_assert(font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
01745 
01746    if (sizeof(wchar_t) != sizeof(GdkWChar)) {
01747       wcstr = g_new(wchar_t, text_length);
01748       for (i = 0; i < text_length; i++)
01749          wcstr[i] = text[i];
01750    } else
01751       wcstr = (wchar_t *) text;
01752 
01753    arg.total.cx = arg.total.cy = 0;
01754 
01755    gdk_wchar_text_handle(font, wcstr, text_length,
01756                          gdk_text_size_handler, &arg);
01757 
01758    if (sizeof(wchar_t) != sizeof(GdkWChar))
01759       g_free(wcstr);
01760 
01761    return arg.total.cx;
01762 }
01763 
01764 void
01765 gdk_text_extents(GdkFont * font,
01766                  const gchar * text,
01767                  gint text_length,
01768                  gint * lbearing,
01769                  gint * rbearing,
01770                  gint * width, gint * ascent, gint * descent)
01771 {
01772    gdk_text_size_arg arg;
01773    gint wlen;
01774    wchar_t *wcstr;
01775 
01776    g_return_if_fail(font != NULL);
01777    g_return_if_fail(text != NULL);
01778 
01779    if (text_length == 0) {
01780       if (lbearing)
01781          *lbearing = 0;
01782       if (rbearing)
01783          *rbearing = 0;
01784       if (width)
01785          *width = 0;
01786       if (ascent)
01787          *ascent = 0;
01788       if (descent)
01789          *descent = 0;
01790       return;
01791    }
01792 
01793    g_assert(font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
01794 
01795    arg.total.cx = arg.total.cy = 0;
01796 
01797    wcstr = g_new(wchar_t, text_length);
01798    if (text_length == 1) {
01799       wcstr[0] = (guchar) text[0];
01800       gdk_wchar_text_handle(font, wcstr, 1, gdk_text_size_handler, &arg);
01801    } else {
01802       if ((wlen =
01803            gdk_nmbstowchar_ts(wcstr, text, text_length,
01804                               text_length)) == -1)
01805          g_warning("gdk_text_extents: gdk_nmbstowchar_ts failed");
01806       else
01807          gdk_wchar_text_handle(font, wcstr, wlen, gdk_text_size_handler,
01808                                &arg);
01809    }
01810 
01811    g_free(wcstr);
01812 
01813    /* XXX This is quite bogus */
01814    if (lbearing)
01815       *lbearing = 0;
01816    if (rbearing)
01817       *rbearing = arg.total.cx;
01818    /* What should be the difference between width and rbearing? */
01819    if (width)
01820       *width = arg.total.cx;
01821    if (ascent)
01822       *ascent = arg.total.cy + 1;
01823    if (descent)
01824       *descent = font->descent + 1;
01825 }
01826 
01827 void
01828 gdk_text_extents_wc(GdkFont * font,
01829                     const GdkWChar * text,
01830                     gint text_length,
01831                     gint * lbearing,
01832                     gint * rbearing,
01833                     gint * width, gint * ascent, gint * descent)
01834 {
01835    gdk_text_size_arg arg;
01836    wchar_t *wcstr;
01837    gint i;
01838 
01839    g_return_if_fail(font != NULL);
01840    g_return_if_fail(text != NULL);
01841 
01842    if (text_length == 0) {
01843       if (lbearing)
01844          *lbearing = 0;
01845       if (rbearing)
01846          *rbearing = 0;
01847       if (width)
01848          *width = 0;
01849       if (ascent)
01850          *ascent = 0;
01851       if (descent)
01852          *descent = 0;
01853       return;
01854    }
01855 
01856    g_assert(font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
01857 
01858    if (sizeof(wchar_t) != sizeof(GdkWChar)) {
01859       wcstr = g_new(wchar_t, text_length);
01860       for (i = 0; i < text_length; i++)
01861          wcstr[i] = text[i];
01862    } else
01863       wcstr = (wchar_t *) text;
01864 
01865    arg.total.cx = arg.total.cy = 0;
01866 
01867    gdk_wchar_text_handle(font, wcstr, text_length,
01868                          gdk_text_size_handler, &arg);
01869 
01870    if (sizeof(wchar_t) != sizeof(GdkWChar))
01871       g_free(wcstr);
01872 
01873    /* XXX This is quite bogus */
01874    if (lbearing)
01875       *lbearing = 0;
01876    if (rbearing)
01877       *rbearing = arg.total.cx;
01878    if (width)
01879       *width = arg.total.cx;
01880    if (ascent)
01881       *ascent = arg.total.cy + 1;
01882    if (descent)
01883       *descent = font->descent + 1;
01884 }

Generated on Tue Jul 5 14:14:39 2011 for ROOT_528-00b_version by  doxygen 1.5.1