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/.
33 #include "gdkprivate.h"
35 static GHashTable *font_name_hash = NULL;
36 static GHashTable *fontset_name_hash = NULL;
39 gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name)
41 GdkFontPrivate *private = (GdkFontPrivate *)font;
42 GHashTable **hashp = (type == GDK_FONT_FONT) ?
43 &font_name_hash : &fontset_name_hash;
46 *hashp = g_hash_table_new (g_str_hash, g_str_equal);
48 private->names = g_slist_prepend (private->names, g_strdup (font_name));
49 g_hash_table_insert (*hashp, private->names->data, font);
53 gdk_font_hash_remove (GdkFontType type, GdkFont *font)
55 GdkFontPrivate *private = (GdkFontPrivate *)font;
57 GHashTable *hash = (type == GDK_FONT_FONT) ?
58 font_name_hash : fontset_name_hash;
60 tmp_list = private->names;
63 g_hash_table_remove (hash, tmp_list->data);
64 g_free (tmp_list->data);
66 tmp_list = tmp_list->next;
69 g_slist_free (private->names);
70 private->names = NULL;
74 gdk_font_hash_lookup (GdkFontType type, const gchar *font_name)
77 GHashTable *hash = (type == GDK_FONT_FONT) ?
78 font_name_hash : fontset_name_hash;
84 result = g_hash_table_lookup (hash, font_name);
86 gdk_font_ref (result);
93 charset_name (DWORD charset)
97 case ANSI_CHARSET: return "ANSI";
98 case DEFAULT_CHARSET: return "DEFAULT";
99 case SYMBOL_CHARSET: return "SYMBOL";
100 case SHIFTJIS_CHARSET: return "SHIFTJIS";
101 case HANGEUL_CHARSET: return "HANGEUL";
102 case GB2312_CHARSET: return "GB2312";
103 case CHINESEBIG5_CHARSET: return "CHINESEBIG5";
104 case JOHAB_CHARSET: return "JOHAB";
105 case HEBREW_CHARSET: return "HEBREW";
106 case ARABIC_CHARSET: return "ARABIC";
107 case GREEK_CHARSET: return "GREEK";
108 case TURKISH_CHARSET: return "TURKISH";
109 case VIETNAMESE_CHARSET: return "VIETNAMESE";
110 case THAI_CHARSET: return "THAI";
111 case EASTEUROPE_CHARSET: return "EASTEUROPE";
112 case RUSSIAN_CHARSET: return "RUSSIAN";
113 case MAC_CHARSET: return "MAC";
114 case BALTIC_CHARSET: return "BALTIC";
120 gdk_font_load (const gchar *font_name)
123 GdkFontPrivate *private;
127 TEXTMETRIC textmetric;
130 DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
131 fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
132 const char *lpszFace;
134 int numfields, n1, n2, tries;
135 char foundry[32], family[100], weight[32], slant[32], set_width[32],
136 spacing[32], registry[32], encoding[32];
137 char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
140 int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
143 g_return_val_if_fail (font_name != NULL, NULL);
145 GDK_NOTE (MISC, g_print ("gdk_font_load: %s\n", font_name));
147 font = gdk_font_hash_lookup (GDK_FONT_FONT, font_name);
151 numfields = sscanf (font_name,
152 "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
161 /* Probably a plain Windows font name */
166 fnWeight = FW_DONTCARE;
168 fdwUnderline = FALSE;
169 fdwStrikeOut = FALSE;
170 fdwCharSet = ANSI_CHARSET;
171 fdwOutputPrecision = OUT_TT_PRECIS;
172 fdwClipPrecision = CLIP_DEFAULT_PRECIS;
173 fdwQuality = PROOF_QUALITY;
174 fdwPitchAndFamily = DEFAULT_PITCH;
175 lpszFace = font_name;
177 else if (numfields != 5)
179 g_warning ("gdk_font_load: font name %s illegal", font_name);
185 /* It must be a XLFD name */
187 /* Check for hex escapes in the font family,
188 * put in there by gtkfontsel.
193 if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
195 sscanf (p+1, "%2x", &c);
202 /* Skip add_style which often is empty in the requested font name */
203 while (font_name[n1] && font_name[n1] != '-')
207 numfields += sscanf (font_name + n1,
208 "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
219 if (numfields != 14 || font_name[n1 + n2] != '\0')
221 g_warning ("gdk_font_load: font name %s illegal", font_name);
226 logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
228 if (strcmp (pixel_size, "*") == 0)
229 if (strcmp (point_size, "*") == 0)
232 nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
234 nHeight = atoi (pixel_size);
240 if (g_strcasecmp (weight, "thin") == 0)
242 else if (g_strcasecmp (weight, "extralight") == 0)
243 fnWeight = FW_EXTRALIGHT;
244 else if (g_strcasecmp (weight, "ultralight") == 0)
246 fnWeight = FW_ULTRALIGHT;
248 fnWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is
249 * defined as FW_EXTRALIGHT anyway.
252 else if (g_strcasecmp (weight, "light") == 0)
254 else if (g_strcasecmp (weight, "normal") == 0)
255 fnWeight = FW_NORMAL;
256 else if (g_strcasecmp (weight, "regular") == 0)
257 fnWeight = FW_REGULAR;
258 else if (g_strcasecmp (weight, "medium") == 0)
259 fnWeight = FW_MEDIUM;
260 else if (g_strcasecmp (weight, "semibold") == 0)
261 fnWeight = FW_SEMIBOLD;
262 else if (g_strcasecmp (weight, "demibold") == 0)
264 fnWeight = FW_DEMIBOLD;
266 fnWeight = FW_SEMIBOLD; /* As above */
268 else if (g_strcasecmp (weight, "bold") == 0)
270 else if (g_strcasecmp (weight, "extrabold") == 0)
271 fnWeight = FW_EXTRABOLD;
272 else if (g_strcasecmp (weight, "ultrabold") == 0)
274 fnWeight = FW_ULTRABOLD;
276 fnWeight = FW_EXTRABOLD; /* As above */
278 else if (g_strcasecmp (weight, "heavy") == 0)
280 else if (g_strcasecmp (weight, "black") == 0)
284 fnWeight = FW_HEAVY; /* As above */
287 fnWeight = FW_DONTCARE;
289 if (g_strcasecmp (slant, "italic") == 0
290 || g_strcasecmp (slant, "oblique") == 0
291 || g_strcasecmp (slant, "i") == 0
292 || g_strcasecmp (slant, "o") == 0)
296 fdwUnderline = FALSE;
297 fdwStrikeOut = FALSE;
298 if (g_strcasecmp (registry, "iso8859") == 0)
299 if (strcmp (encoding, "1") == 0)
300 fdwCharSet = ANSI_CHARSET;
302 fdwCharSet = ANSI_CHARSET; /* XXX ??? */
303 else if (g_strcasecmp (registry, "windows") == 0)
304 if (g_strcasecmp (encoding, "symbol") == 0)
305 fdwCharSet = SYMBOL_CHARSET;
306 else if (g_strcasecmp (encoding, "shiftjis") == 0)
307 fdwCharSet = SHIFTJIS_CHARSET;
308 else if (g_strcasecmp (encoding, "gb2312") == 0)
309 fdwCharSet = GB2312_CHARSET;
310 else if (g_strcasecmp (encoding, "hangeul") == 0)
311 fdwCharSet = HANGEUL_CHARSET;
312 else if (g_strcasecmp (encoding, "chinesebig5") == 0)
313 fdwCharSet = CHINESEBIG5_CHARSET;
314 else if (g_strcasecmp (encoding, "johab") == 0)
315 fdwCharSet = JOHAB_CHARSET;
316 else if (g_strcasecmp (encoding, "hebrew") == 0)
317 fdwCharSet = HEBREW_CHARSET;
318 else if (g_strcasecmp (encoding, "arabic") == 0)
319 fdwCharSet = ARABIC_CHARSET;
320 else if (g_strcasecmp (encoding, "greek") == 0)
321 fdwCharSet = GREEK_CHARSET;
322 else if (g_strcasecmp (encoding, "turkish") == 0)
323 fdwCharSet = TURKISH_CHARSET;
324 else if (g_strcasecmp (encoding, "easteurope") == 0)
325 fdwCharSet = EASTEUROPE_CHARSET;
326 else if (g_strcasecmp (encoding, "russian") == 0)
327 fdwCharSet = RUSSIAN_CHARSET;
328 else if (g_strcasecmp (encoding, "mac") == 0)
329 fdwCharSet = MAC_CHARSET;
330 else if (g_strcasecmp (encoding, "baltic") == 0)
331 fdwCharSet = BALTIC_CHARSET;
333 fdwCharSet = ANSI_CHARSET; /* XXX ??? */
335 fdwCharSet = ANSI_CHARSET; /* XXX ??? */
336 fdwOutputPrecision = OUT_TT_PRECIS;
337 fdwClipPrecision = CLIP_DEFAULT_PRECIS;
338 fdwQuality = PROOF_QUALITY;
339 if (g_strcasecmp (spacing, "m") == 0)
340 fdwPitchAndFamily = FIXED_PITCH;
341 else if (g_strcasecmp (spacing, "p") == 0)
342 fdwPitchAndFamily = VARIABLE_PITCH;
344 fdwPitchAndFamily = DEFAULT_PITCH;
348 for (tries = 0; ; tries++)
350 GDK_NOTE (MISC, g_print ("...trying CreateFont(%d,%d,%d,%d,"
353 "%d,%#.02x,\"%s\")\n",
354 nHeight, nWidth, nEscapement, nOrientation,
355 fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
356 fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
357 fdwQuality, fdwPitchAndFamily, lpszFace));
359 CreateFont (nHeight, nWidth, nEscapement, nOrientation,
360 fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
361 fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
362 fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
365 /* If we fail, try some similar fonts often found on Windows. */
369 if (g_strcasecmp (family, "helvetica") == 0)
371 else if (g_strcasecmp (family, "new century schoolbook") == 0)
372 lpszFace = "century schoolbook";
373 else if (g_strcasecmp (family, "courier") == 0)
374 lpszFace = "courier new";
375 else if (g_strcasecmp (family, "lucida") == 0)
376 lpszFace = "lucida sans unicode";
377 else if (g_strcasecmp (family, "lucidatypewriter") == 0)
378 lpszFace = "lucida console";
379 else if (g_strcasecmp (family, "times") == 0)
380 lpszFace = "times new roman";
384 if (g_strcasecmp (family, "courier") == 0)
387 fdwPitchAndFamily |= FF_MODERN;
389 else if (g_strcasecmp (family, "times new roman") == 0)
392 fdwPitchAndFamily |= FF_ROMAN;
394 else if (g_strcasecmp (family, "helvetica") == 0
395 || g_strcasecmp (family, "lucida") == 0)
398 fdwPitchAndFamily |= FF_SWISS;
403 fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
414 private = g_new (GdkFontPrivate, 1);
415 font = (GdkFont*) private;
417 private->xfont = hfont;
418 private->ref_count = 1;
419 private->names = NULL;
420 font->type = GDK_FONT_FONT;
421 GetObject (private->xfont, sizeof (logfont), &logfont);
422 oldfont = SelectObject (gdk_DC, private->xfont);
423 GetTextMetrics (gdk_DC, &textmetric);
424 private->charset = GetTextCharsetInfo (gdk_DC, &private->fs, 0);
425 SelectObject (gdk_DC, oldfont);
426 TranslateCharsetInfo ((DWORD *) private->charset, &csi, TCI_SRCCHARSET);
427 private->codepage = csi.ciACP;
428 GetCPInfo (private->codepage, &private->cpinfo);
429 font->ascent = textmetric.tmAscent;
430 font->descent = textmetric.tmDescent;
432 GDK_NOTE (MISC, g_print ("... = %#x charset %s codepage %d (max %d bytes) "
435 charset_name (private->charset),
437 private->cpinfo.MaxCharSize,
438 font->ascent, font->descent));
440 /* This memory is leaked, so shoot me. */
441 f = g_new (HANDLE, 1);
442 *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER);
443 gdk_xid_table_insert (f, font);
445 gdk_font_hash_insert (GDK_FONT_FONT, font, font_name);
451 gdk_fontset_load (gchar *fontset_name)
453 g_warning ("gdk_fontset_load: Not implemented");
459 gdk_font_ref (GdkFont *font)
461 GdkFontPrivate *private;
463 g_return_val_if_fail (font != NULL, NULL);
465 private = (GdkFontPrivate*) font;
466 private->ref_count += 1;
468 GDK_NOTE (MISC, g_print ("gdk_font_ref %#x %d\n",
469 private->xfont, private->ref_count));
474 gdk_font_unref (GdkFont *font)
476 GdkFontPrivate *private;
477 private = (GdkFontPrivate*) font;
479 g_return_if_fail (font != NULL);
480 g_return_if_fail (private->ref_count > 0);
482 private->ref_count -= 1;
484 GDK_NOTE (MISC, g_print ("gdk_font_unref %#x %d%s\n",
487 (private->ref_count == 0 ? " freeing" : "")));
489 if (private->ref_count == 0)
491 gdk_font_hash_remove (font->type, font);
496 gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER));
497 DeleteObject (private->xfont);
501 g_assert_not_reached ();
508 gdk_font_id (const GdkFont *font)
510 const GdkFontPrivate *font_private;
512 g_return_val_if_fail (font != NULL, 0);
514 font_private = (const GdkFontPrivate*) font;
516 if (font->type == GDK_FONT_FONT)
517 return (gint) font_private->xfont;
519 g_assert_not_reached ();
524 gdk_font_equal (const GdkFont *fonta,
525 const GdkFont *fontb)
527 const GdkFontPrivate *privatea;
528 const GdkFontPrivate *privateb;
530 g_return_val_if_fail (fonta != NULL, FALSE);
531 g_return_val_if_fail (fontb != NULL, FALSE);
533 privatea = (const GdkFontPrivate*) fonta;
534 privateb = (const GdkFontPrivate*) fontb;
536 if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
537 return (privatea->xfont == privateb->xfont);
539 g_assert_not_reached ();
544 gdk_string_width (GdkFont *font,
547 return gdk_text_width (font, string, strlen (string));
551 gdk_text_width (GdkFont *font,
555 GdkFontPrivate *private;
561 g_return_val_if_fail (font != NULL, -1);
562 g_return_val_if_fail (text != NULL, -1);
564 if (text_length == 0)
567 private = (GdkFontPrivate*) font;
572 oldfont = SelectObject (gdk_DC, private->xfont);
573 if (private->cpinfo.MaxCharSize > 1)
575 wcstr = g_new (wchar_t, text_length);
576 if ((wlen = MultiByteToWideChar (private->codepage, 0,
578 wcstr, text_length)) == 0)
580 g_warning ("gdk_text_width: MultiByteToWideChar failed");
584 GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
589 GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
591 SelectObject (gdk_DC, oldfont);
596 g_assert_not_reached ();
602 gdk_text_width_wc (GdkFont *font,
603 const GdkWChar *text,
606 GdkFontPrivate *private;
613 g_return_val_if_fail (font != NULL, -1);
614 g_return_val_if_fail (text != NULL, -1);
616 if (text_length == 0)
619 private = (GdkFontPrivate*) font;
624 oldfont = SelectObject (gdk_DC, private->xfont);
625 #if 0 /* No. Don't assume Unicode here either.
626 * (Read the comments in gdk_draw_text_wc.)
628 wcstr = g_new (wchar_t, text_length);
629 for (i = 0; i < text_length; i++)
631 GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
634 str = g_new (guchar, text_length);
635 for (i = 0; i < text_length; i++)
637 if (private->cpinfo.MaxCharSize > 1)
639 wcstr = g_new (wchar_t, text_length);
640 if ((wlen = MultiByteToWideChar (private->codepage, 0,
642 wcstr, text_length)) == 0)
644 g_warning ("gdk_text_width_wc: MultiByteToWideChar failed");
648 GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
653 GetTextExtentPoint32A (gdk_DC, str, text_length, &size);
657 SelectObject (gdk_DC, oldfont);
668 gdk_char_width (GdkFont *font,
671 return gdk_text_width (font, &character, 1);
675 gdk_char_width_wc (GdkFont *font,
678 return gdk_text_width_wc (font, &character, 1);
682 gdk_string_measure (GdkFont *font,
685 g_return_val_if_fail (font != NULL, -1);
686 g_return_val_if_fail (string != NULL, -1);
688 return gdk_text_measure (font, string, strlen (string));
692 gdk_text_extents (GdkFont *font,
701 GdkFontPrivate *private;
707 g_return_if_fail (font != NULL);
708 g_return_if_fail (text != NULL);
710 if (text_length == 0)
725 private = (GdkFontPrivate*) font;
730 oldfont = SelectObject (gdk_DC, private->xfont);
731 if (private->cpinfo.MaxCharSize > 1)
733 wcstr = g_new (wchar_t, text_length);
734 if ((wlen = MultiByteToWideChar (private->codepage, 0,
736 wcstr, text_length)) == 0)
738 g_warning ("gdk_text_extents: MultiByteToWideChar failed");
743 GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
748 GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
750 SelectObject (gdk_DC, oldfont);
751 /* XXX This is all quite bogus */
759 *ascent = size.cy + 1;
761 *descent = font->descent + 1;
765 g_assert_not_reached ();
770 gdk_text_extents_wc (GdkFont *font,
771 const GdkWChar *text,
779 GdkFontPrivate *private;
785 g_return_if_fail (font != NULL);
786 g_return_if_fail (text != NULL);
788 if (text_length == 0)
803 private = (GdkFontPrivate*) font;
808 wcstr = g_new (wchar_t, text_length);
809 for (i = 0; i < text_length; i++)
811 oldfont = SelectObject (gdk_DC, private->xfont);
812 GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
814 SelectObject (gdk_DC, oldfont);
816 /* XXX This is all quite bogus */
824 *ascent = size.cy + 1;
826 *descent = font->descent + 1;
830 g_assert_not_reached ();
835 gdk_string_extents (GdkFont *font,
843 g_return_if_fail (font != NULL);
844 g_return_if_fail (string != NULL);
846 gdk_text_extents (font, string, strlen (string),
847 lbearing, rbearing, width, ascent, descent);
852 gdk_text_measure (GdkFont *font,
856 GdkFontPrivate *private;
859 g_return_val_if_fail (font != NULL, -1);
860 g_return_val_if_fail (text != NULL, -1);
862 private = (GdkFontPrivate*) font;
867 return gdk_text_width (font, text, text_length); /* ??? */
871 g_assert_not_reached ();
877 gdk_char_measure (GdkFont *font,
880 return gdk_text_measure (font, &character, 1);
884 gdk_string_height (GdkFont *font,
887 g_return_val_if_fail (font != NULL, -1);
888 g_return_val_if_fail (string != NULL, -1);
890 return gdk_text_height (font, string, strlen (string));
894 gdk_text_height (GdkFont *font,
898 GdkFontPrivate *private;
904 g_return_val_if_fail (font != NULL, -1);
905 g_return_val_if_fail (text != NULL, -1);
907 if (text_length == 0)
910 private = (GdkFontPrivate*) font;
915 oldfont = SelectObject (gdk_DC, private->xfont);
916 if (private->cpinfo.MaxCharSize > 1)
918 wcstr = g_new (wchar_t, text_length);
919 if ((wlen = MultiByteToWideChar (private->codepage, 0,
921 wcstr, text_length)) == 0)
923 g_warning ("gdk_text_height: MultiByteToWideChar failed "
925 text_length, text, text_length);
929 GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
934 GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
936 SelectObject (gdk_DC, oldfont);
941 g_error ("font->type = %d", font->type);
947 gdk_char_height (GdkFont *font,
950 return gdk_text_height (font, &character, 1);