summaryrefslogtreecommitdiff
path: root/gdk/win32/gdkfont-win32.c
diff options
context:
space:
mode:
authorTor Lillqvist <tml@iki.fi>1999-11-08 00:09:29 +0000
committerTor Lillqvist <tml@src.gnome.org>1999-11-08 00:09:29 +0000
commit0ad4aa57d696dbff96e35e571925330afa1ad2d1 (patch)
tree8d5d782a4e903a2dd97c3194ef247bf7ca271465 /gdk/win32/gdkfont-win32.c
parent559a8c86912e1cbdf06e6a441a0a6e5576337341 (diff)
downloadgdk-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.c896
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