diff options
author | Tor Lillqvist <tml@iki.fi> | 1999-11-08 00:09:29 +0000 |
---|---|---|
committer | Tor Lillqvist <tml@src.gnome.org> | 1999-11-08 00:09:29 +0000 |
commit | 0ad4aa57d696dbff96e35e571925330afa1ad2d1 (patch) | |
tree | 8d5d782a4e903a2dd97c3194ef247bf7ca271465 /gdk/win32/gdkfont-win32.c | |
parent | 559a8c86912e1cbdf06e6a441a0a6e5576337341 (diff) | |
download | gdk-pixbuf-0ad4aa57d696dbff96e35e571925330afa1ad2d1.tar.gz |
New font private structures, related to fontsets.
1999-11-07 Tor Lillqvist <tml@iki.fi>
* gdk/win32/gdkprivate.h: New font private structures, related to
fontsets.
* gdk/win32/gdkfont.c: New functions gdk_font_list_new() and
gdk_font_list_free(). On X11, will just be wrappers to
XListFonts() and XFreeFontNames(). On Win32, the code previously
in gtkfontsel.c is now here.
New function gdk_font_xlfd_create(). On X11 will get the FONT
property of the font (for GDK_FONT_FONTs), or call
XBaseFontNameListOfFontSet (for GDK_FONT_FONTSETs), on Win32
builds a XLFD style name from the font information in the LOGFONT
struct(s).
New function gdk_font_xlfd_free(), which correspondingly frees the
string returned by gdk_font_xlfd_create().
Implement fontsets on Win32. Add a function that iterates over a
wide char string and calls a callback function for each substring
of wide chars from the same Unicode subrange (and thus probably
available in the same real font).
Improve the XLFD emulation a bit.
* gdk/win32/gdkim.c (gdk_nmbstowchar_ts): Small bugfix.
* gdk/win32/gdkevents.c: Workaround for suspected bug on Win2k
Beta3, WM_IME_CHAR messages don't seem to contain the composed
multi-byte char as with the Active IMM on Win9x. Oh well, handle
WM_IME_COMPOSITION with GCS_RESULTSTR instead, use
ImmGetCompositionStringW() to get the composed Unicode chars.
* gdk/win32/gdkgc.c
* gdk/win32/gdkdraw.c: Changes needed because of the font private
struct changes.
* gdk/win32/gdk.def: Add the new functions.
Diffstat (limited to 'gdk/win32/gdkfont-win32.c')
-rw-r--r-- | gdk/win32/gdkfont-win32.c | 896 |
1 files changed, 749 insertions, 147 deletions
diff --git a/gdk/win32/gdkfont-win32.c b/gdk/win32/gdkfont-win32.c index 59791945b..f6b768bac 100644 --- a/gdk/win32/gdkfont-win32.c +++ b/gdk/win32/gdkfont-win32.c @@ -30,15 +30,17 @@ #include <ctype.h> #include "gdkfont.h" -#include "gdkprivate.h" +#include "gdkx.h" static GHashTable *font_name_hash = NULL; static GHashTable *fontset_name_hash = NULL; static void -gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name) +gdk_font_hash_insert (GdkFontType type, + GdkFont *font, + const gchar *font_name) { - GdkFontPrivate *private = (GdkFontPrivate *)font; + GdkFontPrivate *private = (GdkFontPrivate *) font; GHashTable **hashp = (type == GDK_FONT_FONT) ? &font_name_hash : &fontset_name_hash; @@ -50,9 +52,10 @@ gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name) } static void -gdk_font_hash_remove (GdkFontType type, GdkFont *font) +gdk_font_hash_remove (GdkFontType type, + GdkFont *font) { - GdkFontPrivate *private = (GdkFontPrivate *)font; + GdkFontPrivate *private = (GdkFontPrivate *) font; GSList *tmp_list; GHashTable *hash = (type == GDK_FONT_FONT) ? font_name_hash : fontset_name_hash; @@ -71,7 +74,8 @@ gdk_font_hash_remove (GdkFontType type, GdkFont *font) } static GdkFont * -gdk_font_hash_lookup (GdkFontType type, const gchar *font_name) +gdk_font_hash_lookup (GdkFontType type, + const gchar *font_name) { GdkFont *result; GHashTable *hash = (type == GDK_FONT_FONT) ? @@ -94,40 +98,353 @@ charset_name (DWORD charset) { switch (charset) { - case ANSI_CHARSET: return "ANSI"; - case DEFAULT_CHARSET: return "DEFAULT"; - case SYMBOL_CHARSET: return "SYMBOL"; - case SHIFTJIS_CHARSET: return "SHIFTJIS"; - case HANGEUL_CHARSET: return "HANGEUL"; - case GB2312_CHARSET: return "GB2312"; - case CHINESEBIG5_CHARSET: return "CHINESEBIG5"; - case JOHAB_CHARSET: return "JOHAB"; - case HEBREW_CHARSET: return "HEBREW"; - case ARABIC_CHARSET: return "ARABIC"; - case GREEK_CHARSET: return "GREEK"; - case TURKISH_CHARSET: return "TURKISH"; - case VIETNAMESE_CHARSET: return "VIETNAMESE"; - case THAI_CHARSET: return "THAI"; - case EASTEUROPE_CHARSET: return "EASTEUROPE"; - case RUSSIAN_CHARSET: return "RUSSIAN"; - case MAC_CHARSET: return "MAC"; - case BALTIC_CHARSET: return "BALTIC"; + case ANSI_CHARSET: return "ansi"; + case DEFAULT_CHARSET: return "default"; + case SYMBOL_CHARSET: return "symbol"; + case SHIFTJIS_CHARSET: return "shiftjis"; + case HANGEUL_CHARSET: return "hangeul"; + case GB2312_CHARSET: return "gb2312"; + case CHINESEBIG5_CHARSET: return "big5"; + case JOHAB_CHARSET: return "johab"; + case HEBREW_CHARSET: return "hebrew"; + case ARABIC_CHARSET: return "arabic"; + case GREEK_CHARSET: return "greek"; + case TURKISH_CHARSET: return "turkish"; + case VIETNAMESE_CHARSET: return "vietnamese"; + case THAI_CHARSET: return "thai"; + case EASTEUROPE_CHARSET: return "easteurope"; + case RUSSIAN_CHARSET: return "russian"; + case MAC_CHARSET: return "mac"; + case BALTIC_CHARSET: return "baltic"; } return "unknown"; } -GdkFont* -gdk_font_load_internal (GdkFontType type, - const gchar *font_name) +static gint num_fonts; +static gint font_names_size; +static gchar **xfontnames; + +static gchar * +logfont_to_xlfd (const LOGFONT *lfp, + int size, + int res, + int avg_width) +{ + const gchar *weight; + const gchar *registry, *encoding; + int point_size; + static int logpixelsy = 0; + gchar facename[LF_FACESIZE*3]; + gchar *p; + const gchar *q; + + if (logpixelsy == 0) + { + logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY); + } + + if (lfp->lfWeight >= FW_HEAVY) + weight = "heavy"; + else if (lfp->lfWeight >= FW_EXTRABOLD) + weight = "extrabold"; + else if (lfp->lfWeight >= FW_BOLD) + weight = "bold"; +#ifdef FW_DEMIBOLD + else if (lfp->lfWeight >= FW_DEMIBOLD) + weight = "demibold"; +#endif + else if (lfp->lfWeight >= FW_MEDIUM) + weight = "medium"; + else if (lfp->lfWeight >= FW_NORMAL) + weight = "normal"; + else if (lfp->lfWeight >= FW_LIGHT) + weight = "light"; + else if (lfp->lfWeight >= FW_EXTRALIGHT) + weight = "extralight"; + else if (lfp->lfWeight >= FW_THIN) + weight = "thin"; + else + weight = "regular"; + + switch (lfp->lfCharSet) + { + case ANSI_CHARSET: + registry = "iso8859"; + encoding = "1"; + break; + case SHIFTJIS_CHARSET: + registry = "jisx0208.1983"; + encoding = "0"; + break; + case HANGEUL_CHARSET: + registry = "ksc5601.1987"; + encoding = "0"; + break; + case GB2312_CHARSET: + registry = "gb2312.1980"; + encoding = "0"; + break; + case CHINESEBIG5_CHARSET: + registry = "big5"; + encoding = "0"; + break; + case GREEK_CHARSET: + registry = "iso8859"; + encoding = "7"; + break; + case TURKISH_CHARSET: + registry = "iso8859"; + encoding = "9"; + break; +#if 0 /* Not a good idea, I think, to use ISO8859-8 and -6 for the Windows + * hebrew and arabic codepages, they differ too much. + */ + case HEBREW_CHARSET: + registry = "iso8859"; + encoding = "8"; + break; + case ARABIC_CHARSET: + registry = "iso8859"; + encoding = "6"; + break; +#endif + default: + registry = "microsoft"; + encoding = charset_name (lfp->lfCharSet); + } + + point_size = (int) (((double) size/logpixelsy) * 720.); + + if (res == -1) + res = logpixelsy; + + /* Replace illegal characters with hex escapes. */ + p = facename; + q = lfp->lfFaceName; + while (*q) + { + if (*q == '-' || *q == '*' || *q == '?' || *q == '%') + p += sprintf (p, "%%%.02x", *q); + else + *p++ = *q; + q++; + } + *p = '\0'; + + return g_strdup_printf + ("-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s", + "unknown", + facename, + weight, + (lfp->lfItalic ? + ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN + || (lfp->lfPitchAndFamily & 0xF0) == FF_SCRIPT ? + "i" : "o") : "r"), + "normal", + "", + size, + point_size, + res, + res, + ((lfp->lfPitchAndFamily & 0x03) == FIXED_PITCH ? "m" : "p"), + avg_width, + registry, encoding); +} + +gchar * +gdk_font_xlfd_create (GdkFont *font) { - GdkFont *font; GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + GString *string; + gchar *result; + LOGFONT logfont; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate *) font; + + list = private->fonts; + string = g_string_new (""); + + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + + if (GetObject (singlefont->xfont, sizeof (LOGFONT), &logfont) == 0) + { + g_warning ("gdk_win32_font_xlfd: GetObject failed"); + return NULL; + } + + string = + g_string_append (string, + logfont_to_xlfd (&logfont, logfont.lfHeight, -1, 0)); + list = list->next; + if (list) + string = g_string_append_c (string, ','); + } + result = string->str; + g_string_free (string, FALSE); + return result; +} + +void +gdk_font_xlfd_free (gchar *xlfd) +{ + g_free (xlfd); +} + +static gboolean +pattern_match (const gchar *pattern, + const gchar *string) +{ + const gchar *p = pattern, *n = string; + gchar c, c1; + + /* Common case first */ + if ((pattern[0] == '*' + && pattern[1] == '\0') + || (pattern[0] == '-' + && pattern[1] == '*' + && pattern[2] == '\0')) + return TRUE; + + while ((c = *p++) != '\0') + { + c = tolower (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FALSE; + break; + + case '*': + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (c == '?' && *n == '\0') + return FALSE; + + if (c == '\0') + return TRUE; + + c1 = tolower (c); + for (--p; *n != '\0'; ++n) + if (tolower (*n) == c1 + && pattern_match (p, n)) + return TRUE; + return FALSE; + + default: + if (c != tolower (*n)) + return FALSE; + } + + ++n; + } + + if (*n == '\0') + return TRUE; + + return FALSE; +} + +int CALLBACK +InnerEnumFontFamExProc (const LOGFONT *lfp, + const TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + int size; + gchar *xlfd; + + if (fontType == TRUETYPE_FONTTYPE) + { + size = 0; + } + else + { + size = lfp->lfHeight; + } + + xlfd = logfont_to_xlfd (lfp, size, 0, 0); + + if (!pattern_match ((gchar *) lParam, xlfd)) + { + g_free (xlfd); + return 1; + } + + num_fonts++; + if (num_fonts == font_names_size) + { + font_names_size *= 2; + xfontnames = g_realloc (xfontnames, font_names_size * sizeof (gchar *)); + } + xfontnames[num_fonts-1] = xlfd; + + return 1; +} + +int CALLBACK +EnumFontFamExProc (const LOGFONT *lfp, + const TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + if (fontType == TRUETYPE_FONTTYPE) + { + LOGFONT lf; + + lf = *lfp; + + EnumFontFamiliesEx (gdk_DC, &lf, InnerEnumFontFamExProc, lParam, 0); + } + else + InnerEnumFontFamExProc (lfp, metrics, fontType, lParam); + + return 1; +} + +gchar ** +gdk_font_list_new (const gchar *font_pattern, + gint *n_returned) +{ + LOGFONT logfont; + gchar **result; + + num_fonts = 0; + font_names_size = 100; + xfontnames = g_new (gchar *, font_names_size); + memset (&logfont, 0, sizeof (logfont)); + logfont.lfCharSet = DEFAULT_CHARSET; + EnumFontFamiliesEx (gdk_DC, &logfont, EnumFontFamExProc, + (LPARAM) font_pattern, 0); + + result = g_new (gchar *, num_fonts + 1); + memmove (result, xfontnames, num_fonts * sizeof (gchar *)); + result[num_fonts] = NULL; + g_free (xfontnames); + + *n_returned = num_fonts; + return result; +} + +void +gdk_font_list_free (gchar **font_list) +{ + g_strfreev (font_list); +} + +GdkWin32SingleFont* +gdk_font_load_internal (const gchar *font_name) +{ + GdkWin32SingleFont *singlefont; HFONT hfont; LOGFONT logfont; - HGDIOBJ oldfont; - TEXTMETRIC textmetric; CHARSETINFO csi; - HANDLE *f; DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily; const char *lpszFace; @@ -145,10 +462,6 @@ gdk_font_load_internal (GdkFontType type, GDK_NOTE (MISC, g_print ("gdk_font_load_internal: %s\n", font_name)); - font = gdk_font_hash_lookup (type, font_name); - if (font) - return font; - numfields = sscanf (font_name, "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n", foundry, @@ -178,7 +491,6 @@ gdk_font_load_internal (GdkFontType type, else if (numfields != 5) { g_warning ("gdk_font_load: font name %s illegal", font_name); - g_free (font); return NULL; } else @@ -220,7 +532,6 @@ gdk_font_load_internal (GdkFontType type, if (numfields != 14 || font_name[n1 + n2] != '\0') { g_warning ("gdk_font_load: font name %s illegal", font_name); - g_free (font); return NULL; } @@ -299,9 +610,26 @@ gdk_font_load_internal (GdkFontType type, if (g_strcasecmp (registry, "iso8859") == 0) if (strcmp (encoding, "1") == 0) fdwCharSet = ANSI_CHARSET; + else if (strcmp (encoding, "2") == 0) + fdwCharSet = EASTEUROPE_CHARSET; + else if (strcmp (encoding, "7") == 0) + fdwCharSet = GREEK_CHARSET; + else if (strcmp (encoding, "8") == 0) + fdwCharSet = HEBREW_CHARSET; + else if (strcmp (encoding, "9") == 0) + fdwCharSet = TURKISH_CHARSET; else fdwCharSet = ANSI_CHARSET; /* XXX ??? */ - else if (g_strcasecmp (registry, "windows") == 0) + else if (g_strcasecmp (registry, "jisx0208.1983") == 0) + fdwCharSet = SHIFTJIS_CHARSET; + else if (g_strcasecmp (registry, "ksc5601.1987") == 0) + fdwCharSet = HANGEUL_CHARSET; + else if (g_strcasecmp (registry, "gb2312.1980") == 0) + fdwCharSet = GB2312_CHARSET; + else if (g_strcasecmp (registry, "big5") == 0) + fdwCharSet = CHINESEBIG5_CHARSET; + else if (g_strcasecmp (registry, "windows") == 0 + || g_strcasecmp (registry, "microsoft") == 0) if (g_strcasecmp (encoding, "symbol") == 0) fdwCharSet = SYMBOL_CHARSET; else if (g_strcasecmp (encoding, "shiftjis") == 0) @@ -310,7 +638,7 @@ gdk_font_load_internal (GdkFontType type, fdwCharSet = GB2312_CHARSET; else if (g_strcasecmp (encoding, "hangeul") == 0) fdwCharSet = HANGEUL_CHARSET; - else if (g_strcasecmp (encoding, "chinesebig5") == 0) + else if (g_strcasecmp (encoding, "big5") == 0) fdwCharSet = CHINESEBIG5_CHARSET; else if (g_strcasecmp (encoding, "johab") == 0) fdwCharSet = JOHAB_CHARSET; @@ -330,6 +658,8 @@ gdk_font_load_internal (GdkFontType type, fdwCharSet = MAC_CHARSET; else if (g_strcasecmp (encoding, "baltic") == 0) fdwCharSet = BALTIC_CHARSET; + else if (g_strcasecmp (encoding, "cp1251") == 0) + fdwCharSet = RUSSIAN_CHARSET; else fdwCharSet = ANSI_CHARSET; /* XXX ??? */ else @@ -412,56 +742,140 @@ gdk_font_load_internal (GdkFontType type, if (!hfont) return NULL; + singlefont = g_new (GdkWin32SingleFont, 1); + singlefont->xfont = hfont; + GetObject (singlefont->xfont, sizeof (logfont), &logfont); + TranslateCharsetInfo ((DWORD *) singlefont->charset, &csi, TCI_SRCCHARSET); + singlefont->codepage = csi.ciACP; + GetCPInfo (singlefont->codepage, &singlefont->cpinfo); + + return singlefont; +} + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + HGDIOBJ oldfont; + HANDLE *f; + TEXTMETRIC textmetric; + + g_return_val_if_fail (font_name != NULL, NULL); + + font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name); + if (font) + return font; + + singlefont = gdk_font_load_internal (font_name); + private = g_new (GdkFontPrivate, 1); font = (GdkFont*) private; - private->xfont = hfont; private->ref_count = 1; private->names = NULL; - GetObject (private->xfont, sizeof (logfont), &logfont); - oldfont = SelectObject (gdk_DC, private->xfont); + private->fonts = g_slist_append (NULL, singlefont); + + /* Pretend all fonts are fontsets... Gtktext and gtkentry work better + * that way, they use wide chars, which is necessary for non-ASCII + * chars to work. (Yes, even Latin-1, as we use Unicode internally.) + */ + font->type = GDK_FONT_FONTSET; + oldfont = SelectObject (gdk_DC, singlefont->xfont); GetTextMetrics (gdk_DC, &textmetric); - private->charset = GetTextCharsetInfo (gdk_DC, &private->fs, 0); + singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0); SelectObject (gdk_DC, oldfont); - TranslateCharsetInfo ((DWORD *) private->charset, &csi, TCI_SRCCHARSET); - private->codepage = csi.ciACP; - GetCPInfo (private->codepage, &private->cpinfo); - font->type = type; font->ascent = textmetric.tmAscent; font->descent = textmetric.tmDescent; GDK_NOTE (MISC, g_print ("... = %#x charset %s codepage %d (max %d bytes) " "asc %d desc %d\n", - private->xfont, - charset_name (private->charset), - private->codepage, - private->cpinfo.MaxCharSize, + singlefont->xfont, + charset_name (singlefont->charset), + singlefont->codepage, + singlefont->cpinfo.MaxCharSize, font->ascent, font->descent)); - /* This memory is leaked, so shoot me. */ - f = g_new (HANDLE, 1); - *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER); - gdk_xid_table_insert (f, font); - - gdk_font_hash_insert (type, font, font_name); + gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name); return font; } GdkFont* -gdk_font_load (const gchar *font_name) -{ - /* Load all fonts as fontsets... Gtktext and gtkentry work better - * that way, they use wide chars, which is necessary for non-ASCII - * chars to work. (Yes, even Latin-1, as we use Unicode internally.) - */ - return gdk_font_load_internal (GDK_FONT_FONTSET, font_name); -} - -GdkFont* gdk_fontset_load (gchar *fontset_name) { - return gdk_font_load_internal (GDK_FONT_FONTSET, fontset_name); + GdkFont *font; + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + HGDIOBJ oldfont; + HANDLE *f; + TEXTMETRIC textmetric; + GSList *base_font_list = NULL; + gchar *fs; + gchar *b, *p, *s; + + g_return_val_if_fail (fontset_name != NULL, NULL); + + font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name); + if (font) + return font; + + s = fs = g_strdup (fontset_name); + while (*s && isspace (*s)) + s++; + + g_return_val_if_fail (*s, NULL); + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->ref_count = 1; + private->names = NULL; + private->fonts = NULL; + + font->type = GDK_FONT_FONTSET; + font->ascent = 0; + font->descent = 0; + + while (TRUE) + { + if ((p = strchr (s, ',')) != NULL) + b = p; + else + b = s + strlen (s); + + while (isspace (b[-1])) + b--; + *b = '\0'; + singlefont = gdk_font_load_internal (s); + if (singlefont) + { + private->fonts = g_slist_append (private->fonts, singlefont); + oldfont = SelectObject (gdk_DC, singlefont->xfont); + GetTextMetrics (gdk_DC, &textmetric); + singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0); + SelectObject (gdk_DC, oldfont); + font->ascent = MAX (font->ascent, textmetric.tmAscent); + font->descent = MAX (font->descent, textmetric.tmDescent); + } + if (p) + { + s = p + 1; + while (*s && isspace (*s)) + s++; + } + else + break; + if (!*s) + break; + } + + g_free (fs); + + gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name); + + return font; } GdkFont* @@ -474,8 +888,10 @@ gdk_font_ref (GdkFont *font) private = (GdkFontPrivate*) font; private->ref_count += 1; - GDK_NOTE (MISC, g_print ("gdk_font_ref %#x %d\n", - private->xfont, private->ref_count)); + GDK_NOTE (MISC, + g_print ("gdk_font_ref %#x %d\n", + ((GdkWin32SingleFont *) private->fonts->data)->xfont, + private->ref_count)); return font; } @@ -483,6 +899,8 @@ void gdk_font_unref (GdkFont *font) { GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; private = (GdkFontPrivate*) font; g_return_if_fail (font != NULL); @@ -490,9 +908,9 @@ gdk_font_unref (GdkFont *font) private->ref_count -= 1; + singlefont = (GdkWin32SingleFont *) private->fonts->data; GDK_NOTE (MISC, g_print ("gdk_font_unref %#x %d%s\n", - private->xfont, - private->ref_count, + singlefont->xfont, private->ref_count, (private->ref_count == 0 ? " freeing" : ""))); if (private->ref_count == 0) @@ -502,9 +920,18 @@ gdk_font_unref (GdkFont *font) switch (font->type) { case GDK_FONT_FONT: - case GDK_FONT_FONTSET: /* XXX */ - gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER)); - DeleteObject (private->xfont); + DeleteObject (singlefont->xfont); + break; + + case GDK_FONT_FONTSET: + list = private->fonts; + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + DeleteObject (singlefont->xfont); + + list = list->next; + } break; default: @@ -524,7 +951,7 @@ gdk_font_id (const GdkFont *font) font_private = (const GdkFontPrivate*) font; if (font->type == GDK_FONT_FONT) - return (gint) font_private->xfont; + return (gint) ((GdkWin32SingleFont *) font_private->fonts->data)->xfont; else return 0; } @@ -543,9 +970,26 @@ gdk_font_equal (const GdkFont *fonta, privateb = (const GdkFontPrivate*) fontb; if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) - return (privatea->xfont == privateb->xfont); + return (((GdkWin32SingleFont *) privatea->fonts->data)->xfont + == ((GdkWin32SingleFont *) privateb->fonts->data)->xfont); else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) - return (privatea->xfont == privateb->xfont); + { + GSList *lista = privatea->fonts; + GSList *listb = privateb->fonts; + + while (lista && listb) + { + if (((GdkWin32SingleFont *) lista->data)->xfont + != ((GdkWin32SingleFont *) listb->data)->xfont) + return 0; + lista = lista->next; + listb = listb->next; + } + if (lista || listb) + return 0; + else + return 1; + } else return 0; } @@ -557,14 +1001,200 @@ gdk_string_width (GdkFont *font, return gdk_text_width (font, string, strlen (string)); } -static gboolean -gdk_text_size (GdkFont *font, - const gchar *text, - gint text_length, - SIZE *sizep) +/* This table classifies Unicode characters according to the Microsoft + * Unicode subset numbering. This is from the table in "Developing + * International Software for Windows 95 and Windows NT". This is almost, + * but not quite, the same as the official Unicode block table in + * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield + * number as in the FONTSIGNATURE struct's fsUsb field. + */ +static struct { + wchar_t low, high; + guint bit; + gchar *name; +} utab[] = +{ + { 0x0000, 0x007E, 0, "Basic Latin" }, + { 0x00A0, 0x00FF, 1, "Latin-1 Supplement" }, + { 0x0100, 0x017F, 2, "Latin Extended-A" }, + { 0x0180, 0x024F, 3, "Latin Extended-B" }, + { 0x0250, 0x02AF, 4, "IPA Extensions" }, + { 0x02B0, 0x02FF, 5, "Spacing Modifier Letters" }, + { 0x0300, 0x036F, 6, "Combining Diacritical Marks" }, + { 0x0370, 0x03CF, 7, "Basic Greek" }, + { 0x03D0, 0x03FF, 8, "Greek Symbols and Coptic" }, + { 0x0400, 0x04FF, 9, "Cyrillic" }, + { 0x0530, 0x058F, 10, "Armenian" }, + { 0x0590, 0x05CF, 12, "Hebrew Extended" }, + { 0x05D0, 0x05FF, 11, "Basic Hebrew" }, + { 0x0600, 0x0652, 13, "Basic Arabic" }, + { 0x0653, 0x06FF, 14, "Arabic Extended" }, + { 0x0900, 0x097F, 15, "Devanagari" }, + { 0x0980, 0x09FF, 16, "Bengali" }, + { 0x0A00, 0x0A7F, 17, "Gurmukhi" }, + { 0x0A80, 0x0AFF, 18, "Gujarati" }, + { 0x0B00, 0x0B7F, 19, "Oriya" }, + { 0x0B80, 0x0BFF, 20, "Tamil" }, + { 0x0C00, 0x0C7F, 21, "Telugu" }, + { 0x0C80, 0x0CFF, 22, "Kannada" }, + { 0x0D00, 0x0D7F, 23, "Malayalam" }, + { 0x0E00, 0x0E7F, 24, "Thai" }, + { 0x0E80, 0x0EFF, 25, "Lao" }, + { 0x10A0, 0x10CF, 27, "Georgian Extended" }, + { 0x10D0, 0x10FF, 26, "Basic Georgian" }, + { 0x1100, 0x11FF, 28, "Hangul Jamo" }, + { 0x1E00, 0x1EFF, 29, "Latin Extended Additional" }, + { 0x1F00, 0x1FFF, 30, "Greek Extended" }, + { 0x2000, 0x206F, 31, "General Punctuation" }, + { 0x2070, 0x209F, 32, "Superscripts and Subscripts" }, + { 0x20A0, 0x20CF, 33, "Currency Symbols" }, + { 0x20D0, 0x20FF, 34, "Combining Diacritical Marks for Symbols" }, + { 0x2100, 0x214F, 35, "Letterlike Symbols" }, + { 0x2150, 0x218F, 36, "Number Forms" }, + { 0x2190, 0x21FF, 37, "Arrows" }, + { 0x2200, 0x22FF, 38, "Mathematical Operators" }, + { 0x2300, 0x23FF, 39, "Miscellaneous Technical" }, + { 0x2400, 0x243F, 40, "Control Pictures" }, + { 0x2440, 0x245F, 41, "Optical Character Recognition" }, + { 0x2460, 0x24FF, 42, "Enclosed Alphanumerics" }, + { 0x2500, 0x257F, 43, "Box Drawing" }, + { 0x2580, 0x259F, 44, "Block Elements" }, + { 0x25A0, 0x25FF, 45, "Geometric Shapes" }, + { 0x2600, 0x26FF, 46, "Miscellaneous Symbols" }, + { 0x2700, 0x27BF, 47, "Dingbats" }, + { 0x3000, 0x303F, 48, "CJK Symbols and Punctuation" }, + { 0x3040, 0x309F, 49, "Hiragana" }, + { 0x30A0, 0x30FF, 50, "Katakana" }, + { 0x3100, 0x312F, 51, "Bopomofo" }, + { 0x3130, 0x318F, 52, "Hangul Compatibility Jamo" }, + { 0x3190, 0x319F, 53, "CJK Miscellaneous" }, + { 0x3200, 0x32FF, 54, "Enclosed CJK" }, + { 0x3300, 0x33FF, 55, "CJK Compatibility" }, + { 0x3400, 0x3D2D, 56, "Hangul" }, + { 0x3D2E, 0x44B7, 57, "Hangul Supplementary-A" }, + { 0x44B8, 0x4DFF, 58, "Hangul Supplementary-B" }, + { 0x4E00, 0x9FFF, 59, "CJK Unified Ideographs" }, + { 0xE000, 0xF8FF, 60, "Private Use Area" }, + { 0xF900, 0xFAFF, 61, "CJK Compatibility Ideographs" }, + { 0xFB00, 0xFB4F, 62, "Alphabetic Presentation Forms" }, + { 0xFB50, 0xFDFF, 63, "Arabic Presentation Forms-A" }, + { 0xFE20, 0xFE2F, 64, "Combining Half Marks" }, + { 0xFE30, 0xFE4F, 65, "CJK Compatibility Forms" }, + { 0xFE50, 0xFE6F, 66, "Small Form Variants" }, + { 0xFE70, 0xFEFE, 67, "Arabic Presentation Forms-B" }, + { 0xFEFF, 0xFEFF, 69, "Specials" }, + { 0xFF00, 0xFFEF, 68, "Halfwidth and Fullwidth Forms" }, + { 0xFFF0, 0xFFFD, 69, "Specials" } +}; + +/* Return the Unicode Subset bitfield number for a Unicode character */ + +static int +unicode_classify (wchar_t wc) +{ + int min = 0; + int max = sizeof (utab) / sizeof (utab[0]) - 1; + int mid; + + while (max >= min) + { + mid = (min + max) / 2; + if (utab[mid].high < wc) + min = mid + 1; + else if (wc < utab[mid].low) + max = mid - 1; + else if (utab[mid].low <= wc && wc <= utab[mid].high) + return utab[mid].bit; + else + return -1; + } +} + +void +gdk_wchar_text_handle (GdkFont *font, + const wchar_t *wcstr, + int wclen, + void (*handler)(GdkWin32SingleFont *, + const wchar_t *, + int, + void *), + void *arg) { GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + int i, block; + const wchar_t *start, *end, *wcp; + + wcp = wcstr; + end = wcp + wclen; + private = (GdkFontPrivate *) font; + + while (wcp < end) + { + /* Split Unicode string into pieces of the same class */ + start = wcp; + block = unicode_classify (*wcp); + while (wcp + 1 < end && unicode_classify (wcp[1]) == block) + wcp++; + + /* Find a font in the fontset that can handle this class */ + list = private->fonts; + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + + if (singlefont->fs.fsUsb[block/32] & (1 << (block % 32))) + break; + + list = list->next; + } + + if (!list) + singlefont = NULL; + + /* Call the callback function */ + (*handler) (singlefont, start, wcp+1 - start, arg); + wcp++; + } +} + +typedef struct +{ + SIZE total; + SIZE max; +} gdk_text_size_arg; + +static void +gdk_text_size_handler (GdkWin32SingleFont *singlefont, + const wchar_t *wcstr, + int wclen, + void *argp) +{ + SIZE this_size; HGDIOBJ oldfont; + gdk_text_size_arg *arg = (gdk_text_size_arg *) argp; + + if ((oldfont = SelectObject (gdk_DC, singlefont->xfont)) == NULL) + { + g_warning ("gdk_text_size_handler: SelectObject failed"); + return; + } + GetTextExtentPoint32W (gdk_DC, wcstr, wclen, &this_size); + SelectObject (gdk_DC, oldfont); + + arg->total.cx += this_size.cx; + arg->total.cy += this_size.cy; + arg->max.cx = MAX (this_size.cx, arg->max.cx); + arg->max.cy = MAX (this_size.cy, arg->max.cy); +} + +static gboolean +gdk_text_size (GdkFont *font, + const gchar *text, + gint text_length, + gdk_text_size_arg *arg) +{ gint wlen; wchar_t *wcstr; @@ -574,16 +1204,8 @@ gdk_text_size (GdkFont *font, if (text_length == 0) return 0; - private = (GdkFontPrivate*) font; - g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); - if ((oldfont = SelectObject (gdk_DC, private->xfont)) == NULL) - { - g_warning ("gdk_text_width: SelectObject failed"); - return FALSE; - } - wcstr = g_new (wchar_t, text_length); if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) { @@ -591,10 +1213,9 @@ gdk_text_size (GdkFont *font, return FALSE; } - GetTextExtentPoint32W (gdk_DC, wcstr, wlen, sizep); + gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, arg); g_free (wcstr); - SelectObject (gdk_DC, oldfont); return TRUE; } @@ -604,12 +1225,15 @@ gdk_text_width (GdkFont *font, const gchar *text, gint text_length) { - SIZE size; + gdk_text_size_arg arg; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; - if (!gdk_text_size (font, text, text_length, &size)) + if (!gdk_text_size (font, text, text_length, &arg)) return -1; - return size.cx; + return arg.total.cx; } gint @@ -617,11 +1241,8 @@ gdk_text_width_wc (GdkFont *font, const GdkWChar *text, gint text_length) { - GdkFontPrivate *private; - HGDIOBJ oldfont; - SIZE size; + gdk_text_size_arg arg; wchar_t *wcstr; - guchar *str; gint i; g_return_val_if_fail (font != NULL, -1); @@ -632,12 +1253,6 @@ gdk_text_width_wc (GdkFont *font, g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); - private = (GdkFontPrivate*) font; - - if ((oldfont = SelectObject (gdk_DC, private->xfont)) == NULL) - - g_warning ("gdk_text_width_wc: SelectObject failed"); - if (sizeof (wchar_t) != sizeof (GdkWChar)) { wcstr = g_new (wchar_t, text_length); @@ -647,15 +1262,16 @@ gdk_text_width_wc (GdkFont *font, else wcstr = (wchar_t *) text; - GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size); + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_text_size_handler, &arg); if (sizeof (wchar_t) != sizeof (GdkWChar)) g_free (wcstr); - if (oldfont != NULL) - SelectObject (gdk_DC, oldfont); - - return size.cx; + return arg.total.cx; } gint @@ -698,9 +1314,7 @@ gdk_text_extents (GdkFont *font, gint *ascent, gint *descent) { - GdkFontPrivate *private; - HGDIOBJ oldfont; - SIZE size; + gdk_text_size_arg arg; gint wlen; wchar_t *wcstr; @@ -724,33 +1338,24 @@ gdk_text_extents (GdkFont *font, g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); - private = (GdkFontPrivate*) font; - - if ((oldfont = SelectObject (gdk_DC, private->xfont)) == NULL) - g_warning ("gdk_text_extents: SelectObject failed"); + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; wcstr = g_new (wchar_t, text_length); if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) - { - g_warning ("gdk_text_extents: gdk_nmbstowchar_ts failed"); - size.cx = 0; - size.cy = 0; - } + g_warning ("gdk_text_extents: gdk_nmbstowchar_ts failed"); else - GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size); + gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, &arg); - if (oldfont != NULL) - SelectObject (gdk_DC, oldfont); - - /* XXX This is all quite bogus */ + /* XXX This is quite bogus */ if (lbearing) *lbearing = 0; if (rbearing) *rbearing = 0; if (width) - *width = size.cx; + *width = arg.total.cx; if (ascent) - *ascent = size.cy + 1; + *ascent = arg.max.cy + 1; if (descent) *descent = font->descent + 1; } @@ -765,9 +1370,7 @@ gdk_text_extents_wc (GdkFont *font, gint *ascent, gint *descent) { - GdkFontPrivate *private; - HGDIOBJ oldfont; - SIZE size; + gdk_text_size_arg arg; wchar_t *wcstr; gint i; @@ -791,8 +1394,6 @@ gdk_text_extents_wc (GdkFont *font, g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); - private = (GdkFontPrivate*) font; - if (sizeof (wchar_t) != sizeof (GdkWChar)) { wcstr = g_new (wchar_t, text_length); @@ -802,26 +1403,24 @@ gdk_text_extents_wc (GdkFont *font, else wcstr = (wchar_t *) text; - if ((oldfont = SelectObject (gdk_DC, private->xfont)) == NULL) - g_warning ("gdk_text_extents_wc: SelectObject failed"); + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; - GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size); + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_text_size_handler, &arg); if (sizeof (wchar_t) != sizeof (GdkWChar)) g_free (wcstr); - if (oldfont != NULL) - SelectObject (gdk_DC, oldfont); - - /* XXX This is all quite bogus */ + /* XXX This is quite bogus */ if (lbearing) *lbearing = 0; if (rbearing) *rbearing = 0; if (width) - *width = size.cx; + *width = arg.total.cx; if (ascent) - *ascent = size.cy + 1; + *ascent = arg.max.cy + 1; if (descent) *descent = font->descent + 1; } @@ -873,12 +1472,15 @@ gdk_text_height (GdkFont *font, const gchar *text, gint text_length) { - SIZE size; + gdk_text_size_arg arg; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; - if (!gdk_text_size (font, text, text_length, &size)) + if (!gdk_text_size (font, text, text_length, &arg)) return -1; - return size.cy; + return arg.max.cy; } gint |