1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
35 static GHashTable *font_name_hash = NULL;
36 static GHashTable *fontset_name_hash = NULL;
39 gdk_font_hash_insert (GdkFontType type,
41 const gchar *font_name)
43 GdkFontPrivate *private = (GdkFontPrivate *) font;
44 GHashTable **hashp = (type == GDK_FONT_FONT) ?
45 &font_name_hash : &fontset_name_hash;
48 *hashp = g_hash_table_new (g_str_hash, g_str_equal);
50 private->names = g_slist_prepend (private->names, g_strdup (font_name));
51 g_hash_table_insert (*hashp, private->names->data, font);
55 gdk_font_hash_remove (GdkFontType type,
58 GdkFontPrivate *private = (GdkFontPrivate *) font;
60 GHashTable *hash = (type == GDK_FONT_FONT) ?
61 font_name_hash : fontset_name_hash;
63 tmp_list = private->names;
66 g_hash_table_remove (hash, tmp_list->data);
67 g_free (tmp_list->data);
69 tmp_list = tmp_list->next;
72 g_slist_free (private->names);
73 private->names = NULL;
77 gdk_font_hash_lookup (GdkFontType type,
78 const gchar *font_name)
81 GHashTable *hash = (type == GDK_FONT_FONT) ?
82 font_name_hash : fontset_name_hash;
88 result = g_hash_table_lookup (hash, font_name);
90 gdk_font_ref (result);
97 charset_name (DWORD charset)
101 case ANSI_CHARSET: return "ansi";
102 case DEFAULT_CHARSET: return "default";
103 case SYMBOL_CHARSET: return "symbol";
104 case SHIFTJIS_CHARSET: return "shiftjis";
105 case HANGEUL_CHARSET: return "hangeul";
106 case GB2312_CHARSET: return "gb2312";
107 case CHINESEBIG5_CHARSET: return "big5";
108 case JOHAB_CHARSET: return "johab";
109 case HEBREW_CHARSET: return "hebrew";
110 case ARABIC_CHARSET: return "arabic";
111 case GREEK_CHARSET: return "greek";
112 case TURKISH_CHARSET: return "turkish";
113 case VIETNAMESE_CHARSET: return "vietnamese";
114 case THAI_CHARSET: return "thai";
115 case EASTEUROPE_CHARSET: return "easteurope";
116 case RUSSIAN_CHARSET: return "russian";
117 case MAC_CHARSET: return "mac";
118 case BALTIC_CHARSET: return "baltic";
123 static gint num_fonts;
124 static gint font_names_size;
125 static gchar **xfontnames;
128 logfont_to_xlfd (const LOGFONT *lfp,
134 const gchar *registry, *encoding;
136 static int logpixelsy = 0;
137 gchar facename[LF_FACESIZE*3];
143 logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
146 if (lfp->lfWeight >= FW_HEAVY)
148 else if (lfp->lfWeight >= FW_EXTRABOLD)
149 weight = "extrabold";
150 else if (lfp->lfWeight >= FW_BOLD)
153 else if (lfp->lfWeight >= FW_DEMIBOLD)
156 else if (lfp->lfWeight >= FW_MEDIUM)
158 else if (lfp->lfWeight >= FW_NORMAL)
160 else if (lfp->lfWeight >= FW_LIGHT)
162 else if (lfp->lfWeight >= FW_EXTRALIGHT)
163 weight = "extralight";
164 else if (lfp->lfWeight >= FW_THIN)
169 switch (lfp->lfCharSet)
172 registry = "iso8859";
175 case SHIFTJIS_CHARSET:
176 registry = "jisx0208.1983";
179 case HANGEUL_CHARSET:
180 registry = "ksc5601.1987";
184 registry = "gb2312.1980";
187 case CHINESEBIG5_CHARSET:
192 registry = "iso8859";
195 case TURKISH_CHARSET:
196 registry = "iso8859";
199 #if 0 /* Not a good idea, I think, to use ISO8859-8 and -6 for the Windows
200 * hebrew and arabic codepages, they differ too much.
203 registry = "iso8859";
207 registry = "iso8859";
212 registry = "microsoft";
213 encoding = charset_name (lfp->lfCharSet);
216 point_size = (int) (((double) size/logpixelsy) * 720.);
221 /* Replace illegal characters with hex escapes. */
226 if (*q == '-' || *q == '*' || *q == '?' || *q == '%')
227 p += sprintf (p, "%%%.02x", *q);
234 return g_strdup_printf
235 ("-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s",
240 ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN
241 || (lfp->lfPitchAndFamily & 0xF0) == FF_SCRIPT ?
249 ((lfp->lfPitchAndFamily & 0x03) == FIXED_PITCH ? "m" : "p"),
255 gdk_font_xlfd_create (GdkFont *font)
257 GdkFontPrivate *private;
258 GdkWin32SingleFont *singlefont;
264 g_return_val_if_fail (font != NULL, NULL);
266 private = (GdkFontPrivate *) font;
268 list = private->fonts;
269 string = g_string_new ("");
273 singlefont = (GdkWin32SingleFont *) list->data;
275 if (GetObject (singlefont->xfont, sizeof (LOGFONT), &logfont) == 0)
277 g_warning ("gdk_win32_font_xlfd: GetObject failed");
282 g_string_append (string,
283 logfont_to_xlfd (&logfont, logfont.lfHeight, -1, 0));
286 string = g_string_append_c (string, ',');
288 result = string->str;
289 g_string_free (string, FALSE);
294 gdk_font_xlfd_free (gchar *xlfd)
300 pattern_match (const gchar *pattern,
303 const gchar *p = pattern, *n = string;
306 /* Common case first */
307 if ((pattern[0] == '*'
308 && pattern[1] == '\0')
309 || (pattern[0] == '-'
311 && pattern[2] == '\0'))
314 while ((c = *p++) != '\0')
326 for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
327 if (c == '?' && *n == '\0')
334 for (--p; *n != '\0'; ++n)
335 if (tolower (*n) == c1
336 && pattern_match (p, n))
341 if (c != tolower (*n))
355 InnerEnumFontFamExProc (const LOGFONT *lfp,
356 const TEXTMETRIC *metrics,
363 if (fontType == TRUETYPE_FONTTYPE)
369 size = lfp->lfHeight;
372 xlfd = logfont_to_xlfd (lfp, size, 0, 0);
374 if (!pattern_match ((gchar *) lParam, xlfd))
381 if (num_fonts == font_names_size)
383 font_names_size *= 2;
384 xfontnames = g_realloc (xfontnames, font_names_size * sizeof (gchar *));
386 xfontnames[num_fonts-1] = xlfd;
392 EnumFontFamExProc (const LOGFONT *lfp,
393 const TEXTMETRIC *metrics,
397 if (fontType == TRUETYPE_FONTTYPE)
403 EnumFontFamiliesEx (gdk_DC, &lf, InnerEnumFontFamExProc, lParam, 0);
406 InnerEnumFontFamExProc (lfp, metrics, fontType, lParam);
412 gdk_font_list_new (const gchar *font_pattern,
419 font_names_size = 100;
420 xfontnames = g_new (gchar *, font_names_size);
421 memset (&logfont, 0, sizeof (logfont));
422 logfont.lfCharSet = DEFAULT_CHARSET;
423 EnumFontFamiliesEx (gdk_DC, &logfont, EnumFontFamExProc,
424 (LPARAM) font_pattern, 0);
426 result = g_new (gchar *, num_fonts + 1);
427 memmove (result, xfontnames, num_fonts * sizeof (gchar *));
428 result[num_fonts] = NULL;
431 *n_returned = num_fonts;
436 gdk_font_list_free (gchar **font_list)
438 g_strfreev (font_list);
442 gdk_font_load_internal (const gchar *font_name)
444 GdkWin32SingleFont *singlefont;
448 DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
449 fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
450 const char *lpszFace;
452 int numfields, n1, n2, tries;
453 char foundry[32], family[100], weight[32], slant[32], set_width[32],
454 spacing[32], registry[32], encoding[32];
455 char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
458 int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
461 g_return_val_if_fail (font_name != NULL, NULL);
463 GDK_NOTE (MISC, g_print ("gdk_font_load_internal: %s\n", font_name));
465 numfields = sscanf (font_name,
466 "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
475 /* Probably a plain Windows font name */
480 fnWeight = FW_DONTCARE;
482 fdwUnderline = FALSE;
483 fdwStrikeOut = FALSE;
484 fdwCharSet = ANSI_CHARSET;
485 fdwOutputPrecision = OUT_TT_PRECIS;
486 fdwClipPrecision = CLIP_DEFAULT_PRECIS;
487 fdwQuality = PROOF_QUALITY;
488 fdwPitchAndFamily = DEFAULT_PITCH;
489 lpszFace = font_name;
491 else if (numfields != 5)
493 g_warning ("gdk_font_load: font name %s illegal", font_name);
498 /* It must be a XLFD name */
500 /* Check for hex escapes in the font family,
501 * put in there by gtkfontsel.
506 if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
508 sscanf (p+1, "%2x", &c);
515 /* Skip add_style which often is empty in the requested font name */
516 while (font_name[n1] && font_name[n1] != '-')
520 numfields += sscanf (font_name + n1,
521 "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
532 if (numfields != 14 || font_name[n1 + n2] != '\0')
534 g_warning ("gdk_font_load: font name %s illegal", font_name);
538 logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
540 if (strcmp (pixel_size, "*") == 0)
541 if (strcmp (point_size, "*") == 0)
544 nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
546 nHeight = atoi (pixel_size);
552 if (g_strcasecmp (weight, "thin") == 0)
554 else if (g_strcasecmp (weight, "extralight") == 0)
555 fnWeight = FW_EXTRALIGHT;
556 else if (g_strcasecmp (weight, "ultralight") == 0)
558 fnWeight = FW_ULTRALIGHT;
560 fnWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is
561 * defined as FW_EXTRALIGHT anyway.
564 else if (g_strcasecmp (weight, "light") == 0)
566 else if (g_strcasecmp (weight, "normal") == 0)
567 fnWeight = FW_NORMAL;
568 else if (g_strcasecmp (weight, "regular") == 0)
569 fnWeight = FW_REGULAR;
570 else if (g_strcasecmp (weight, "medium") == 0)
571 fnWeight = FW_MEDIUM;
572 else if (g_strcasecmp (weight, "semibold") == 0)
573 fnWeight = FW_SEMIBOLD;
574 else if (g_strcasecmp (weight, "demibold") == 0)
576 fnWeight = FW_DEMIBOLD;
578 fnWeight = FW_SEMIBOLD; /* As above */
580 else if (g_strcasecmp (weight, "bold") == 0)
582 else if (g_strcasecmp (weight, "extrabold") == 0)
583 fnWeight = FW_EXTRABOLD;
584 else if (g_strcasecmp (weight, "ultrabold") == 0)
586 fnWeight = FW_ULTRABOLD;
588 fnWeight = FW_EXTRABOLD; /* As above */
590 else if (g_strcasecmp (weight, "heavy") == 0)
592 else if (g_strcasecmp (weight, "black") == 0)
596 fnWeight = FW_HEAVY; /* As above */
599 fnWeight = FW_DONTCARE;
601 if (g_strcasecmp (slant, "italic") == 0
602 || g_strcasecmp (slant, "oblique") == 0
603 || g_strcasecmp (slant, "i") == 0
604 || g_strcasecmp (slant, "o") == 0)
608 fdwUnderline = FALSE;
609 fdwStrikeOut = FALSE;
610 if (g_strcasecmp (registry, "iso8859") == 0)
611 if (strcmp (encoding, "1") == 0)
612 fdwCharSet = ANSI_CHARSET;
613 else if (strcmp (encoding, "2") == 0)
614 fdwCharSet = EASTEUROPE_CHARSET;
615 else if (strcmp (encoding, "7") == 0)
616 fdwCharSet = GREEK_CHARSET;
617 else if (strcmp (encoding, "8") == 0)
618 fdwCharSet = HEBREW_CHARSET;
619 else if (strcmp (encoding, "9") == 0)
620 fdwCharSet = TURKISH_CHARSET;
622 fdwCharSet = ANSI_CHARSET; /* XXX ??? */
623 else if (g_strcasecmp (registry, "jisx0208.1983") == 0)
624 fdwCharSet = SHIFTJIS_CHARSET;
625 else if (g_strcasecmp (registry, "ksc5601.1987") == 0)
626 fdwCharSet = HANGEUL_CHARSET;
627 else if (g_strcasecmp (registry, "gb2312.1980") == 0)
628 fdwCharSet = GB2312_CHARSET;
629 else if (g_strcasecmp (registry, "big5") == 0)
630 fdwCharSet = CHINESEBIG5_CHARSET;
631 else if (g_strcasecmp (registry, "windows") == 0
632 || g_strcasecmp (registry, "microsoft") == 0)
633 if (g_strcasecmp (encoding, "symbol") == 0)
634 fdwCharSet = SYMBOL_CHARSET;
635 else if (g_strcasecmp (encoding, "shiftjis") == 0)
636 fdwCharSet = SHIFTJIS_CHARSET;
637 else if (g_strcasecmp (encoding, "gb2312") == 0)
638 fdwCharSet = GB2312_CHARSET;
639 else if (g_strcasecmp (encoding, "hangeul") == 0)
640 fdwCharSet = HANGEUL_CHARSET;
641 else if (g_strcasecmp (encoding, "big5") == 0)
642 fdwCharSet = CHINESEBIG5_CHARSET;
643 else if (g_strcasecmp (encoding, "johab") == 0)
644 fdwCharSet = JOHAB_CHARSET;
645 else if (g_strcasecmp (encoding, "hebrew") == 0)
646 fdwCharSet = HEBREW_CHARSET;
647 else if (g_strcasecmp (encoding, "arabic") == 0)
648 fdwCharSet = ARABIC_CHARSET;
649 else if (g_strcasecmp (encoding, "greek") == 0)
650 fdwCharSet = GREEK_CHARSET;
651 else if (g_strcasecmp (encoding, "turkish") == 0)
652 fdwCharSet = TURKISH_CHARSET;
653 else if (g_strcasecmp (encoding, "easteurope") == 0)
654 fdwCharSet = EASTEUROPE_CHARSET;
655 else if (g_strcasecmp (encoding, "russian") == 0)
656 fdwCharSet = RUSSIAN_CHARSET;
657 else if (g_strcasecmp (encoding, "mac") == 0)
658 fdwCharSet = MAC_CHARSET;
659 else if (g_strcasecmp (encoding, "baltic") == 0)
660 fdwCharSet = BALTIC_CHARSET;
661 else if (g_strcasecmp (encoding, "cp1251") == 0)
662 fdwCharSet = RUSSIAN_CHARSET;
664 fdwCharSet = ANSI_CHARSET; /* XXX ??? */
666 fdwCharSet = ANSI_CHARSET; /* XXX ??? */
667 fdwOutputPrecision = OUT_TT_PRECIS;
668 fdwClipPrecision = CLIP_DEFAULT_PRECIS;
669 fdwQuality = PROOF_QUALITY;
670 if (g_strcasecmp (spacing, "m") == 0)
671 fdwPitchAndFamily = FIXED_PITCH;
672 else if (g_strcasecmp (spacing, "p") == 0)
673 fdwPitchAndFamily = VARIABLE_PITCH;
675 fdwPitchAndFamily = DEFAULT_PITCH;
679 for (tries = 0; ; tries++)
681 GDK_NOTE (MISC, g_print ("...trying CreateFont(%d,%d,%d,%d,"
684 "%d,%#.02x,\"%s\")\n",
685 nHeight, nWidth, nEscapement, nOrientation,
686 fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
687 fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
688 fdwQuality, fdwPitchAndFamily, lpszFace));
690 CreateFont (nHeight, nWidth, nEscapement, nOrientation,
691 fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
692 fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
693 fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
696 /* If we fail, try some similar fonts often found on Windows. */
700 if (g_strcasecmp (family, "helvetica") == 0)
702 else if (g_strcasecmp (family, "new century schoolbook") == 0)
703 lpszFace = "century schoolbook";
704 else if (g_strcasecmp (family, "courier") == 0)
705 lpszFace = "courier new";
706 else if (g_strcasecmp (family, "lucida") == 0)
707 lpszFace = "lucida sans unicode";
708 else if (g_strcasecmp (family, "lucidatypewriter") == 0)
709 lpszFace = "lucida console";
710 else if (g_strcasecmp (family, "times") == 0)
711 lpszFace = "times new roman";
715 if (g_strcasecmp (family, "courier") == 0)
718 fdwPitchAndFamily |= FF_MODERN;
720 else if (g_strcasecmp (family, "times new roman") == 0)
723 fdwPitchAndFamily |= FF_ROMAN;
725 else if (g_strcasecmp (family, "helvetica") == 0
726 || g_strcasecmp (family, "lucida") == 0)
729 fdwPitchAndFamily |= FF_SWISS;
734 fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
745 singlefont = g_new (GdkWin32SingleFont, 1);
746 singlefont->xfont = hfont;
747 GetObject (singlefont->xfont, sizeof (logfont), &logfont);
748 TranslateCharsetInfo ((DWORD *) singlefont->charset, &csi, TCI_SRCCHARSET);
749 singlefont->codepage = csi.ciACP;
750 GetCPInfo (singlefont->codepage, &singlefont->cpinfo);
756 gdk_font_load (const gchar *font_name)
759 GdkFontPrivate *private;
760 GdkWin32SingleFont *singlefont;
763 TEXTMETRIC textmetric;
765 g_return_val_if_fail (font_name != NULL, NULL);
767 font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name);
771 singlefont = gdk_font_load_internal (font_name);
773 private = g_new (GdkFontPrivate, 1);
774 font = (GdkFont*) private;
776 private->ref_count = 1;
777 private->names = NULL;
778 private->fonts = g_slist_append (NULL, singlefont);
780 /* Pretend all fonts are fontsets... Gtktext and gtkentry work better
781 * that way, they use wide chars, which is necessary for non-ASCII
782 * chars to work. (Yes, even Latin-1, as we use Unicode internally.)
784 font->type = GDK_FONT_FONTSET;
785 oldfont = SelectObject (gdk_DC, singlefont->xfont);
786 GetTextMetrics (gdk_DC, &textmetric);
787 singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0);
788 SelectObject (gdk_DC, oldfont);
789 font->ascent = textmetric.tmAscent;
790 font->descent = textmetric.tmDescent;
792 GDK_NOTE (MISC, g_print ("... = %#x charset %s codepage %d (max %d bytes) "
795 charset_name (singlefont->charset),
796 singlefont->codepage,
797 singlefont->cpinfo.MaxCharSize,
798 font->ascent, font->descent));
800 gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name);
806 gdk_fontset_load (gchar *fontset_name)
809 GdkFontPrivate *private;
810 GdkWin32SingleFont *singlefont;
813 TEXTMETRIC textmetric;
814 GSList *base_font_list = NULL;
818 g_return_val_if_fail (fontset_name != NULL, NULL);
820 font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name);
824 s = fs = g_strdup (fontset_name);
825 while (*s && isspace (*s))
828 g_return_val_if_fail (*s, NULL);
830 private = g_new (GdkFontPrivate, 1);
831 font = (GdkFont*) private;
833 private->ref_count = 1;
834 private->names = NULL;
835 private->fonts = NULL;
837 font->type = GDK_FONT_FONTSET;
843 if ((p = strchr (s, ',')) != NULL)
848 while (isspace (b[-1]))
851 singlefont = gdk_font_load_internal (s);
854 private->fonts = g_slist_append (private->fonts, singlefont);
855 oldfont = SelectObject (gdk_DC, singlefont->xfont);
856 GetTextMetrics (gdk_DC, &textmetric);
857 singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0);
858 SelectObject (gdk_DC, oldfont);
859 font->ascent = MAX (font->ascent, textmetric.tmAscent);
860 font->descent = MAX (font->descent, textmetric.tmDescent);
865 while (*s && isspace (*s))
876 gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
882 gdk_font_ref (GdkFont *font)
884 GdkFontPrivate *private;
886 g_return_val_if_fail (font != NULL, NULL);
888 private = (GdkFontPrivate*) font;
889 private->ref_count += 1;
892 g_print ("gdk_font_ref %#x %d\n",
893 ((GdkWin32SingleFont *) private->fonts->data)->xfont,
894 private->ref_count));
899 gdk_font_unref (GdkFont *font)
901 GdkFontPrivate *private;
902 GdkWin32SingleFont *singlefont;
904 private = (GdkFontPrivate*) font;
906 g_return_if_fail (font != NULL);
907 g_return_if_fail (private->ref_count > 0);
909 private->ref_count -= 1;
911 singlefont = (GdkWin32SingleFont *) private->fonts->data;
912 GDK_NOTE (MISC, g_print ("gdk_font_unref %#x %d%s\n",
913 singlefont->xfont, private->ref_count,
914 (private->ref_count == 0 ? " freeing" : "")));
916 if (private->ref_count == 0)
918 gdk_font_hash_remove (font->type, font);
923 DeleteObject (singlefont->xfont);
926 case GDK_FONT_FONTSET:
927 list = private->fonts;
930 singlefont = (GdkWin32SingleFont *) list->data;
931 DeleteObject (singlefont->xfont);
938 g_assert_not_reached ();
945 gdk_font_id (const GdkFont *font)
947 const GdkFontPrivate *font_private;
949 g_return_val_if_fail (font != NULL, 0);
951 font_private = (const GdkFontPrivate*) font;
953 if (font->type == GDK_FONT_FONT)
954 return (gint) ((GdkWin32SingleFont *) font_private->fonts->data)->xfont;
960 gdk_font_equal (const GdkFont *fonta,
961 const GdkFont *fontb)
963 const GdkFontPrivate *privatea;
964 const GdkFontPrivate *privateb;
966 g_return_val_if_fail (fonta != NULL, FALSE);
967 g_return_val_if_fail (fontb != NULL, FALSE);
969 privatea = (const GdkFontPrivate*) fonta;
970 privateb = (const GdkFontPrivate*) fontb;
972 if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
973 return (((GdkWin32SingleFont *) privatea->fonts->data)->xfont
974 == ((GdkWin32SingleFont *) privateb->fonts->data)->xfont);
975 else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
977 GSList *lista = privatea->fonts;
978 GSList *listb = privateb->fonts;
980 while (lista && listb)
982 if (((GdkWin32SingleFont *) lista->data)->xfont
983 != ((GdkWin32SingleFont *) listb->data)->xfont)
998 gdk_string_width (GdkFont *font,
1001 return gdk_text_width (font, string, strlen (string));
1004 /* This table classifies Unicode characters according to the Microsoft
1005 * Unicode subset numbering. This is from the table in "Developing
1006 * International Software for Windows 95 and Windows NT". This is almost,
1007 * but not quite, the same as the official Unicode block table in
1008 * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield
1009 * number as in the FONTSIGNATURE struct's fsUsb field.
1017 { 0x0000, 0x007E, 0, "Basic Latin" },
1018 { 0x00A0, 0x00FF, 1, "Latin-1 Supplement" },
1019 { 0x0100, 0x017F, 2, "Latin Extended-A" },
1020 { 0x0180, 0x024F, 3, "Latin Extended-B" },
1021 { 0x0250, 0x02AF, 4, "IPA Extensions" },
1022 { 0x02B0, 0x02FF, 5, "Spacing Modifier Letters" },
1023 { 0x0300, 0x036F, 6, "Combining Diacritical Marks" },
1024 { 0x0370, 0x03CF, 7, "Basic Greek" },
1025 { 0x03D0, 0x03FF, 8, "Greek Symbols and Coptic" },
1026 { 0x0400, 0x04FF, 9, "Cyrillic" },
1027 { 0x0530, 0x058F, 10, "Armenian" },
1028 { 0x0590, 0x05CF, 12, "Hebrew Extended" },
1029 { 0x05D0, 0x05FF, 11, "Basic Hebrew" },
1030 { 0x0600, 0x0652, 13, "Basic Arabic" },
1031 { 0x0653, 0x06FF, 14, "Arabic Extended" },
1032 { 0x0900, 0x097F, 15, "Devanagari" },
1033 { 0x0980, 0x09FF, 16, "Bengali" },
1034 { 0x0A00, 0x0A7F, 17, "Gurmukhi" },
1035 { 0x0A80, 0x0AFF, 18, "Gujarati" },
1036 { 0x0B00, 0x0B7F, 19, "Oriya" },
1037 { 0x0B80, 0x0BFF, 20, "Tamil" },
1038 { 0x0C00, 0x0C7F, 21, "Telugu" },
1039 { 0x0C80, 0x0CFF, 22, "Kannada" },
1040 { 0x0D00, 0x0D7F, 23, "Malayalam" },
1041 { 0x0E00, 0x0E7F, 24, "Thai" },
1042 { 0x0E80, 0x0EFF, 25, "Lao" },
1043 { 0x10A0, 0x10CF, 27, "Georgian Extended" },
1044 { 0x10D0, 0x10FF, 26, "Basic Georgian" },
1045 { 0x1100, 0x11FF, 28, "Hangul Jamo" },
1046 { 0x1E00, 0x1EFF, 29, "Latin Extended Additional" },
1047 { 0x1F00, 0x1FFF, 30, "Greek Extended" },
1048 { 0x2000, 0x206F, 31, "General Punctuation" },
1049 { 0x2070, 0x209F, 32, "Superscripts and Subscripts" },
1050 { 0x20A0, 0x20CF, 33, "Currency Symbols" },
1051 { 0x20D0, 0x20FF, 34, "Combining Diacritical Marks for Symbols" },
1052 { 0x2100, 0x214F, 35, "Letterlike Symbols" },
1053 { 0x2150, 0x218F, 36, "Number Forms" },
1054 { 0x2190, 0x21FF, 37, "Arrows" },
1055 { 0x2200, 0x22FF, 38, "Mathematical Operators" },
1056 { 0x2300, 0x23FF, 39, "Miscellaneous Technical" },
1057 { 0x2400, 0x243F, 40, "Control Pictures" },
1058 { 0x2440, 0x245F, 41, "Optical Character Recognition" },
1059 { 0x2460, 0x24FF, 42, "Enclosed Alphanumerics" },
1060 { 0x2500, 0x257F, 43, "Box Drawing" },
1061 { 0x2580, 0x259F, 44, "Block Elements" },
1062 { 0x25A0, 0x25FF, 45, "Geometric Shapes" },
1063 { 0x2600, 0x26FF, 46, "Miscellaneous Symbols" },
1064 { 0x2700, 0x27BF, 47, "Dingbats" },
1065 { 0x3000, 0x303F, 48, "CJK Symbols and Punctuation" },
1066 { 0x3040, 0x309F, 49, "Hiragana" },
1067 { 0x30A0, 0x30FF, 50, "Katakana" },
1068 { 0x3100, 0x312F, 51, "Bopomofo" },
1069 { 0x3130, 0x318F, 52, "Hangul Compatibility Jamo" },
1070 { 0x3190, 0x319F, 53, "CJK Miscellaneous" },
1071 { 0x3200, 0x32FF, 54, "Enclosed CJK" },
1072 { 0x3300, 0x33FF, 55, "CJK Compatibility" },
1073 { 0x3400, 0x3D2D, 56, "Hangul" },
1074 { 0x3D2E, 0x44B7, 57, "Hangul Supplementary-A" },
1075 { 0x44B8, 0x4DFF, 58, "Hangul Supplementary-B" },
1076 { 0x4E00, 0x9FFF, 59, "CJK Unified Ideographs" },
1077 { 0xE000, 0xF8FF, 60, "Private Use Area" },
1078 { 0xF900, 0xFAFF, 61, "CJK Compatibility Ideographs" },
1079 { 0xFB00, 0xFB4F, 62, "Alphabetic Presentation Forms" },
1080 { 0xFB50, 0xFDFF, 63, "Arabic Presentation Forms-A" },
1081 { 0xFE20, 0xFE2F, 64, "Combining Half Marks" },
1082 { 0xFE30, 0xFE4F, 65, "CJK Compatibility Forms" },
1083 { 0xFE50, 0xFE6F, 66, "Small Form Variants" },
1084 { 0xFE70, 0xFEFE, 67, "Arabic Presentation Forms-B" },
1085 { 0xFEFF, 0xFEFF, 69, "Specials" },
1086 { 0xFF00, 0xFFEF, 68, "Halfwidth and Fullwidth Forms" },
1087 { 0xFFF0, 0xFFFD, 69, "Specials" }
1090 /* Return the Unicode Subset bitfield number for a Unicode character */
1093 unicode_classify (wchar_t wc)
1096 int max = sizeof (utab) / sizeof (utab[0]) - 1;
1101 mid = (min + max) / 2;
1102 if (utab[mid].high < wc)
1104 else if (wc < utab[mid].low)
1106 else if (utab[mid].low <= wc && wc <= utab[mid].high)
1107 return utab[mid].bit;
1114 gdk_wchar_text_handle (GdkFont *font,
1115 const wchar_t *wcstr,
1117 void (*handler)(GdkWin32SingleFont *,
1123 GdkFontPrivate *private;
1124 GdkWin32SingleFont *singlefont;
1127 const wchar_t *start, *end, *wcp;
1131 private = (GdkFontPrivate *) font;
1135 /* Split Unicode string into pieces of the same class */
1137 block = unicode_classify (*wcp);
1138 while (wcp + 1 < end && unicode_classify (wcp[1]) == block)
1141 /* Find a font in the fontset that can handle this class */
1142 list = private->fonts;
1145 singlefont = (GdkWin32SingleFont *) list->data;
1147 if (singlefont->fs.fsUsb[block/32] & (1 << (block % 32)))
1156 /* Call the callback function */
1157 (*handler) (singlefont, start, wcp+1 - start, arg);
1166 } gdk_text_size_arg;
1169 gdk_text_size_handler (GdkWin32SingleFont *singlefont,
1170 const wchar_t *wcstr,
1176 gdk_text_size_arg *arg = (gdk_text_size_arg *) argp;
1178 if ((oldfont = SelectObject (gdk_DC, singlefont->xfont)) == NULL)
1180 g_warning ("gdk_text_size_handler: SelectObject failed");
1183 GetTextExtentPoint32W (gdk_DC, wcstr, wclen, &this_size);
1184 SelectObject (gdk_DC, oldfont);
1186 arg->total.cx += this_size.cx;
1187 arg->total.cy += this_size.cy;
1188 arg->max.cx = MAX (this_size.cx, arg->max.cx);
1189 arg->max.cy = MAX (this_size.cy, arg->max.cy);
1193 gdk_text_size (GdkFont *font,
1196 gdk_text_size_arg *arg)
1201 g_return_val_if_fail (font != NULL, FALSE);
1202 g_return_val_if_fail (text != NULL, FALSE);
1204 if (text_length == 0)
1207 g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1209 wcstr = g_new (wchar_t, text_length);
1210 if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
1212 g_warning ("gdk_text_size: gdk_nmbstowchar_ts failed");
1216 gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, arg);
1224 gdk_text_width (GdkFont *font,
1228 gdk_text_size_arg arg;
1230 arg.total.cx = arg.total.cy = 0;
1231 arg.max.cx = arg.max.cy = 0;
1233 if (!gdk_text_size (font, text, text_length, &arg))
1236 return arg.total.cx;
1240 gdk_text_width_wc (GdkFont *font,
1241 const GdkWChar *text,
1244 gdk_text_size_arg arg;
1248 g_return_val_if_fail (font != NULL, -1);
1249 g_return_val_if_fail (text != NULL, -1);
1251 if (text_length == 0)
1254 g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1256 if (sizeof (wchar_t) != sizeof (GdkWChar))
1258 wcstr = g_new (wchar_t, text_length);
1259 for (i = 0; i < text_length; i++)
1263 wcstr = (wchar_t *) text;
1265 arg.total.cx = arg.total.cy = 0;
1266 arg.max.cx = arg.max.cy = 0;
1268 gdk_wchar_text_handle (font, wcstr, text_length,
1269 gdk_text_size_handler, &arg);
1271 if (sizeof (wchar_t) != sizeof (GdkWChar))
1274 return arg.total.cx;
1278 gdk_char_width (GdkFont *font,
1281 if (((guchar) character) >= 128)
1283 /* gtktext calls us with non-ASCII characters, sigh */
1284 GdkWChar wc = (guchar) character;
1285 return gdk_text_width_wc (font, &wc, 1);
1287 return gdk_text_width (font, &character, 1);
1291 gdk_char_width_wc (GdkFont *font,
1294 return gdk_text_width_wc (font, &character, 1);
1298 gdk_string_measure (GdkFont *font,
1299 const gchar *string)
1301 g_return_val_if_fail (font != NULL, -1);
1302 g_return_val_if_fail (string != NULL, -1);
1304 return gdk_text_measure (font, string, strlen (string));
1308 gdk_text_extents (GdkFont *font,
1317 gdk_text_size_arg arg;
1321 g_return_if_fail (font != NULL);
1322 g_return_if_fail (text != NULL);
1324 if (text_length == 0)
1339 g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1341 arg.total.cx = arg.total.cy = 0;
1342 arg.max.cx = arg.max.cy = 0;
1344 wcstr = g_new (wchar_t, text_length);
1345 if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
1346 g_warning ("gdk_text_extents: gdk_nmbstowchar_ts failed");
1348 gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, &arg);
1350 /* XXX This is quite bogus */
1356 *width = arg.total.cx;
1358 *ascent = arg.max.cy + 1;
1360 *descent = font->descent + 1;
1364 gdk_text_extents_wc (GdkFont *font,
1365 const GdkWChar *text,
1373 gdk_text_size_arg arg;
1377 g_return_if_fail (font != NULL);
1378 g_return_if_fail (text != NULL);
1380 if (text_length == 0)
1395 g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1397 if (sizeof (wchar_t) != sizeof (GdkWChar))
1399 wcstr = g_new (wchar_t, text_length);
1400 for (i = 0; i < text_length; i++)
1404 wcstr = (wchar_t *) text;
1406 arg.total.cx = arg.total.cy = 0;
1407 arg.max.cx = arg.max.cy = 0;
1409 gdk_wchar_text_handle (font, wcstr, text_length,
1410 gdk_text_size_handler, &arg);
1412 if (sizeof (wchar_t) != sizeof (GdkWChar))
1415 /* XXX This is quite bogus */
1421 *width = arg.total.cx;
1423 *ascent = arg.max.cy + 1;
1425 *descent = font->descent + 1;
1429 gdk_string_extents (GdkFont *font,
1430 const gchar *string,
1437 g_return_if_fail (font != NULL);
1438 g_return_if_fail (string != NULL);
1440 gdk_text_extents (font, string, strlen (string),
1441 lbearing, rbearing, width, ascent, descent);
1446 gdk_text_measure (GdkFont *font,
1450 return gdk_text_width (font, text, text_length); /* ??? */
1454 gdk_char_measure (GdkFont *font,
1457 return gdk_text_measure (font, &character, 1);
1461 gdk_string_height (GdkFont *font,
1462 const gchar *string)
1464 g_return_val_if_fail (font != NULL, -1);
1465 g_return_val_if_fail (string != NULL, -1);
1467 return gdk_text_height (font, string, strlen (string));
1471 gdk_text_height (GdkFont *font,
1475 gdk_text_size_arg arg;
1477 arg.total.cx = arg.total.cy = 0;
1478 arg.max.cx = arg.max.cy = 0;
1480 if (!gdk_text_size (font, text, text_length, &arg))
1487 gdk_char_height (GdkFont *font,
1490 return gdk_text_height (font, &character, 1);