1 /* gtkpsfont - PostScript Fonts handling
2 * Copyright 1999-2006 Adrian E. Feiguin <feiguin@ifir.edu.ar>
3 *
4 * Some code borrowed from
5 * DiaCanvas -- a technical canvas widget
6 * Copyright (C) 1999 Arjan Molenaar
7 * Dia -- an diagram creation/manipulation program
8 * Copyright (C) 1998 Alexander Larsson
9 *
10 * and Xfig
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
26 */
27
28 /**
29 * SECTION: gtkpsfont
30 * @short_description: PostScript Fonts handling.
31 *
32 * Handles Postscript fonts.
33 */
34
35
36 #include <gtk/gtk.h>
37 #include <stdio.h>
38 #include <string.h>
39 #ifndef G_PLATFORM_WIN32
40 #include <fontconfig/fontconfig.h>
41 #endif //G_PLATFORM_WIN32
42 #include <pango/pango.h>
43 #include "gtkpsfont.h"
44
45 #define FONTCACHE_SIZE 17
46 #define NUM_X11_FONTS 2
47
48
49 #if defined __GNUC__ && 7 <= __GNUC__
50 # pragma GCC diagnostic push
51 # pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
52 #endif
53 static GtkPSFont font_data[] =
54 {
55 { "Times-Roman",
56 "Times-Roman",
57 "Times-Roman",
58 "Nimbus Roman No9 L, Regular",
59 NULL,
60 FALSE, FALSE
61 },
62 { "Times-Italic",
63 "Times-Italic",
64 "Times-Roman",
65 "Nimbus Roman No9 L, Italic",
66 NULL,
67 TRUE, FALSE
68 },
69 { "Times-Bold",
70 "Times-Bold",
71 "Times-Roman",
72 "Nimbus Roman No9 L, Bold",
73 NULL,
74 FALSE, TRUE
75 },
76 { "Times-BoldItalic",
77 "Times-BoldItalic",
78 "Times-Roman",
79 "Nimbus Roman No9 L, Bold Italic",
80 NULL,
81 TRUE, TRUE
82 },
83 { "AvantGarde-Book",
84 "AvantGarde-Book",
85 "AvantGarde",
86 "URW Gothic L, Book",
87 NULL,
88 FALSE, FALSE
89 },
90 { "AvantGarde-BookOblique",
91 "AvantGarde-BookOblique",
92 "AvantGarde",
93 "URW Gothic L, Book Oblique",
94 NULL,
95 TRUE, FALSE
96 },
97 { "AvantGarde-Demi",
98 "AvantGarde-Demi",
99 "AvantGarde",
100 "URW Gothic L, Demi",
101 NULL,
102 FALSE, TRUE
103 },
104 { "AvantGarde-DemiOblique",
105 "AvantGarde-DemiOblique",
106 "AvantGarde",
107 "URW Gothic L, Demi Oblique",
108 NULL,
109 TRUE, TRUE
110 },
111 { "Bookman-Light",
112 "Bookman-Light",
113 "Bookman",
114 "URW Bookman L, Light",
115 NULL,
116 FALSE, FALSE
117 },
118 { "Bookman-LightItalic",
119 "Bookman-LightItalic",
120 "Bookman",
121 "URW Bookman L, Light Italic",
122 NULL,
123 TRUE, FALSE
124 },
125 { "Bookman-Demi",
126 "Bookman-Demi",
127 "Bookman",
128 "URW Bookman L, Demi Bold",
129 NULL,
130 FALSE, TRUE
131 },
132 { "Bookman-DemiItalic",
133 "Bookman-DemiItalic",
134 "Bookman",
135 "URW Bookman L, Demi Bold Italic",
136 NULL,
137 TRUE, TRUE
138 },
139 { "Courier",
140 "Courier",
141 "Courier",
142 "Nimbus Mono L, Regular",
143 NULL,
144 FALSE, FALSE
145 },
146 { "Courier-Oblique",
147 "Courier-Oblique",
148 "Courier",
149 "Nimbus Mono L, Regular Oblique",
150 NULL,
151 TRUE, FALSE
152 },
153 { "Courier-Bold",
154 "Courier-Bold",
155 "Courier",
156 "Nimbus Mono L, Bold",
157 NULL,
158 FALSE, TRUE
159 },
160 { "Courier-BoldOblique",
161 "Courier-BoldOblique",
162 "Courier",
163 "Nimbus Mono L, Bold Oblique",
164 NULL,
165 TRUE, TRUE
166 },
167 { "Helvetica",
168 "Helvetica",
169 "Helvetica",
170 "Sans, Regular",
171 NULL,
172 FALSE, FALSE
173 },
174 { "Helvetica-Oblique",
175 "Helvetica-Oblique",
176 "Helvetica",
177 "Sans, Regular Italic",
178 NULL,
179 TRUE, FALSE
180 },
181 { "Helvetica-Bold",
182 "Helvetica-Bold",
183 "Helvetica",
184 "Sans, Bold",
185 NULL,
186 FALSE, TRUE
187 },
188 { "Helvetica-BoldOblique",
189 "Helvetica-BoldOblique",
190 "Helvetica",
191 "Sans, Bold Italic",
192 NULL,
193 TRUE, TRUE
194 },
195 { "Helvetica-Narrow",
196 "Helvetica-Narrow",
197 "Helvetica-Narrow",
198 "Sans, Regular Condensed",
199 NULL,
200 FALSE, FALSE
201 },
202 { "Helvetica-Narrow-Oblique",
203 "Helvetica-Narrow-Oblique",
204 "Helvetica-Narrow",
205 "Sans, Regular Condensed Italic",
206 NULL,
207 TRUE, FALSE
208 },
209 { "Helvetica-Narrow-Bold",
210 "Helvetica-Narrow-Bold",
211 "Helvetica-Narrow",
212 "Sans, Bold Condensed",
213 NULL,
214 FALSE, TRUE
215 },
216 { "Helvetica-Narrow-BoldOblique",
217 "Helvetica-Narrow-BoldOblique",
218 "Helvetica-Narrow",
219 "Sans, Bold Condensed Italic",
220 NULL,
221 TRUE, TRUE
222 },
223 { "NewCenturySchoolbook-Roman",
224 "NewCenturySchlbk-Roman",
225 "NewCenturySchlbk",
226 "Century Schoolbook L, Roman",
227 NULL,
228 FALSE, FALSE
229 },
230 { "NewCenturySchoolbook-Italic",
231 "NewCenturySchlbk-Italic",
232 "NewCenturySchlbk",
233 "Century Schoolbook L, Italic",
234 NULL,
235 TRUE, FALSE
236 },
237 { "NewCenturySchoolbook-Bold",
238 "NewCenturySchlbk-Bold",
239 "NewCenturySchlbk",
240 "Century Schoolbook L, Bold",
241 NULL,
242 FALSE, TRUE
243 },
244 { "NewCenturySchoolbook-BoldItalic",
245 "NewCenturySchlbk-BoldItalic",
246 "NewCenturySchlbk",
247 "Century Schoolbook L, Bold Italic",
248 NULL,
249 TRUE, TRUE
250 },
251 { "Palatino-Roman",
252 "Palatino-Roman",
253 "Palatino",
254 "URW Palladio L, Roman",
255 NULL,
256 FALSE, FALSE
257 },
258 { "Palatino-Italic",
259 "Palatino-Italic",
260 "Palatino",
261 "URW Palladio L, Italic",
262 NULL,
263 TRUE, FALSE
264 },
265 { "Palatino-Bold",
266 "Palatino-Bold",
267 "Palatino",
268 "URW Palladio L, Bold",
269 NULL,
270 FALSE, TRUE
271 },
272 { "Palatino-BoldItalic",
273 "Palatino-BoldItalic",
274 "Palatino",
275 "URW Palladio L, Bold Italic",
276 NULL,
277 TRUE, TRUE
278 },
279 { "Symbol",
280 "Symbol",
281 "Symbol",
282 "Standard Symbols L, Regular",
283 NULL,
284 FALSE, FALSE
285 },
286 { "ZapfChancery-MediumItalic",
287 "ZapfChancery-MediumItalic",
288 "ZapfChancery",
289 "URW Chancery L, Medium Italic",
290 NULL,
291 FALSE, FALSE
292 },
293 { "ZapfDingbats",
294 "ZapfDingbats",
295 "ZapfDingbats",
296 "Dingbats, Regular",
297 NULL,
298 FALSE, FALSE
299 },
300 };
301 #if defined __GNUC__ && 7 <= __GNUC__
302 # pragma GCC diagnostic pop
303 #endif
304
305
306 #define NUM_FONTS (sizeof(font_data)/sizeof(GtkPSFont))
307
308 static GList *user_fonts;
309 static gboolean psfont_init = FALSE;
310 static GList *psfont_families;
311 static gint numf;
312 static gint psfont_refcount = 0;
313
314 #ifdef G_PLATFORM_WIN32
315 static const char *default_font = "sans";
316 #else
317 static const char *default_font = "fixed";
318 #endif
319
320 static GtkPSFont *find_psfont (const gchar *name);
321
322 gint
gtk_psfont_init(void)323 gtk_psfont_init(void)
324 {
325 GtkPSFont *data = NULL;
326 GList *fonts;
327 gint i, j;
328 gboolean new_family = TRUE;
329
330 psfont_refcount++;
331
332 /* if(psfont_refcount > 1) printf("PS fonts already initilized\n");;
333 */
334 if(psfont_refcount > 1) return FALSE;
335
336 /* printf("Initializing PS fonts\n");;
337 */
338
339 psfont_init = TRUE;
340 psfont_families = NULL;
341 numf = 0;
342
343 for(i = 0; i < (int)NUM_FONTS; i++){
344 new_family = TRUE;
345 for(j = 0; j < numf; j++){
346 if(strcmp(font_data[i].family, (gchar *)g_list_nth_data(psfont_families, j)) == 0)
347 new_family = FALSE;
348 }
349 if(new_family){
350 numf = numf + 1;
351 psfont_families = g_list_append(psfont_families, font_data[i].family);
352 }
353 }
354
355 fonts = user_fonts;
356 while(fonts){
357 data = (GtkPSFont *) fonts->data;
358 new_family = TRUE;
359 for(j = 0; j < numf; j++){
360 if(strcmp(data->family, (gchar *)g_list_nth_data(psfont_families, j)) == 0)
361 new_family = FALSE;
362 }
363 if(new_family){
364 numf = numf + 1;
365 psfont_families = g_list_append(psfont_families, data->family);
366 }
367 fonts = fonts->next;
368 }
369
370 return TRUE;
371 }
372
373 /**
374 * gtk_psfont_unref:
375 *
376 * Unref ps fonts.
377 */
378 void
gtk_psfont_unref(void)379 gtk_psfont_unref(void)
380 {
381 GList *list;
382
383 if(psfont_refcount <= 0) return;
384
385 psfont_refcount--;
386
387 if(psfont_refcount > 0) return;
388
389 list = psfont_families;
390 while(list){
391 psfont_families = g_list_remove_link(psfont_families, list);
392 g_list_free_1(list);
393 list = psfont_families;
394 }
395
396 list = user_fonts;
397 while(list){
398 user_fonts = g_list_remove_link(user_fonts, list);
399 g_list_free_1(list);
400 list = user_fonts;
401 }
402
403 psfont_init = FALSE;
404 }
405
406 /*
407 * gtk_psfont_init:
408 *
409 * Unref ps fonts.
410 *
411 void
412 gtk_psfont_unref()
413 {
414 GList *list;
415
416 if(psfont_refcount <= 0) return;
417
418 psfont_refcount--;
419
420 if(psfont_refcount > 0) return;
421
422 list = psfont_families;
423 while(list){
424 psfont_families = g_list_remove_link(psfont_families, list);
425 g_list_free_1(list);
426 list = psfont_families;
427 }
428 */
429
430 /**
431 * gtk_psfont_get_by_name:
432 * @name: font name
433 *
434 * Get PS Font by font name.
435 *
436 * Returns: (transfer none) a #GtkPSFont pointer.
437 */
438 GtkPSFont *
gtk_psfont_get_by_name(const gchar * name)439 gtk_psfont_get_by_name(const gchar *name)
440 {
441 GtkPSFont *font;
442
443 font = find_psfont(name);
444
445 if (font == NULL) {
446 font = find_psfont(default_font);
447 if (font == NULL) {
448 g_warning ("Error, couldn't locate default font. Shouldn't happen.");
449 } else {
450 g_message ("Postscript font %s not found, using %s instead.",
451 name, default_font);
452 }
453 }
454
455 return font;
456 }
457
458 /**
459 * gtk_psfont_get_font_description:
460 * @font: a #GtkPSFont
461 * @height: font height
462 *
463 * Get a #PangoDescriptionFont from PS Font.
464 *
465 * Returns: a #PangoFontDescription pointer.
466 */
467 PangoFontDescription *
gtk_psfont_get_font_description(GtkPSFont * font,gint height)468 gtk_psfont_get_font_description(GtkPSFont *font, gint height)
469 {
470 PangoFontDescription *font_desc;
471 gchar *font_string;
472 GtkSettings *settings = gtk_settings_get_for_screen(gdk_screen_get_default());
473 GObjectClass *klass;
474 gdouble dpi;
475
476 g_return_val_if_fail (font != NULL, NULL);
477
478 if (height <= 0) height = 1;
479
480 /* Dirty hack to get the correct font size for this device
481 http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html
482 */
483
484 klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings));
485 /* Check that the properties we're looking at are defined. */
486 if (!g_object_class_find_property(klass, "gtk-xft-dpi")) {
487 dpi = 96.;
488 } else {
489 /* Read the settings. */
490 gint int_dpi;
491 g_object_get(G_OBJECT(settings),
492 "gtk-xft-dpi", &int_dpi,
493 NULL);
494 if(int_dpi <= 0)
495 dpi = 96;
496 else
497 dpi = int_dpi / PANGO_SCALE;
498 }
499
500 /*
501 {
502 GdkScreen *screen = gdk_screen_get_default ();
503 FcPattern *pattern;
504
505 pattern = FcPatternCreate();
506 if (pattern)
507 {
508 XftDefaultSubstitute (GDK_SCREEN_XDISPLAY (screen),
509 GDK_SCREEN_XNUMBER (screen),
510 pattern);
511 FcPatternGetDouble (pattern, FC_DPI, 0, &dpi);
512 FcPatternDestroy (pattern);
513 }
514 }
515 */
516 height *= 75./dpi;
517
518 font_string = g_strdup_printf("%s %i", font->pango_description, height);
519 font_desc = pango_font_description_from_string(font_string);
520 g_free(font_string);
521
522 if (!font_desc) {
523 font_string = g_strdup_printf("%s %i", default_font, height);
524 font_desc = pango_font_description_from_string(font_string);
525 g_free(font_string);
526 if (font_desc)
527 g_message ("Font %s not describable, using %s instead.",
528 font->fontname, default_font);
529 else
530 g_warning ("Error, couldn't describe default font. Shouldn't happen.");
531 }
532
533 /* Loading via the pango fontset facility means that pango.aliases is used */
534 /* This is not working */
535 /* It is screwing up the whole thing */
536 /*
537 if (font_desc) {
538 PangoContext *context = gdk_pango_context_get();
539 PangoFontset *pffontset;
540 PangoFont *pffont;
541
542 pffontset = pango_context_load_fontset(context, font_desc,
543 pango_context_get_language(context));
544 if (pffontset) {
545 pffont = pango_fontset_get_font(pffontset, g_utf8_get_char(" "));
546 if (pffont) {
547 PangoFontDescription *font_desc;
548 desc = pango_font_describe(pffont);
549 g_object_unref(G_OBJECT(pffont));
550 if (desc) {
551 pango_font_description_free(font_desc);
552 font_desc = desc;
553 }
554 }
555 g_object_unref(G_OBJECT(pffontset));
556 }
557 }
558 */
559 return font_desc;
560 }
561
562
563 /**
564 * gtk_psfont_get_psfontname:
565 * @psfont: a #GtkPSFont
566 *
567 * Get font name from PS Font.
568 *
569 * Returns: font name.
570 */
571 const gchar *
gtk_psfont_get_psfontname(GtkPSFont * psfont)572 gtk_psfont_get_psfontname(GtkPSFont *psfont)
573 {
574
575 g_return_val_if_fail (psfont != NULL, NULL);
576
577 return psfont->psname;
578 }
579
580 /**
581 * gtk_psfont_add_font:
582 * @fontname: font name
583 * @psname: PS font name
584 * @family: font family
585 * @pango_description: font Pango description
586 * @italic: TRUE or FALSE
587 * @bold: TRUE or FALSE
588 *
589 * Add font in user font list.
590 */
591 void
gtk_psfont_add_font(const gchar * fontname,const gchar * psname,const gchar * family,const gchar * pango_description,gboolean italic,gboolean bold)592 gtk_psfont_add_font (const gchar *fontname,
593 const gchar *psname, const gchar *family,
594 const gchar *pango_description,
595 gboolean italic, gboolean bold)
596 {
597 GtkPSFont *font;
598
599 font = g_new0(GtkPSFont, 1);
600
601 font->fontname = g_strdup(fontname);
602 font->psname = g_strdup(psname);
603 font->family = g_strdup(family);
604 font->pango_description = g_strdup(pango_description);
605 font->i18n_latinfamily = NULL;
606 font->italic = italic;
607 font->bold = bold;
608 font->vertical = FALSE;
609
610 user_fonts = g_list_append(user_fonts, font);
611 }
612
613 /**
614 * gtk_psfont_add_i18n_font:
615 * @fontname: font name
616 * @psname: PS font name
617 * @family: font family
618 * @i18n_latinfamily: International font family
619 * @pango_description: font Pango description
620 * @italic: TRUE or FALSE
621 * @bold: TRUE or FALSE
622 * @vertical: TRUE or FALSE
623 *
624 * Add international font in user font list.
625 */
626 void
gtk_psfont_add_i18n_font(const gchar * fontname,const gchar * psname,const gchar * family,const gchar * i18n_latinfamily,const gchar * pango_description,gboolean italic,gboolean bold,gboolean vertical)627 gtk_psfont_add_i18n_font (const gchar *fontname,
628 const gchar *psname, const gchar *family,
629 const gchar *i18n_latinfamily,
630 const gchar *pango_description,
631 gboolean italic, gboolean bold, gboolean vertical)
632 {
633 GtkPSFont *font;
634
635 font = g_new0(GtkPSFont, 1);
636
637 font->fontname = g_strdup(fontname);
638 font->psname = g_strdup(psname);
639 font->family = g_strdup(family);
640 font->pango_description = g_strdup(pango_description);
641 font->i18n_latinfamily = g_strdup(i18n_latinfamily);
642 font->italic = italic;
643 font->bold = bold;
644 font->vertical = vertical;
645
646 user_fonts = g_list_append(user_fonts, font);
647 }
648
649 static GtkPSFont *
find_psfont(const gchar * name)650 find_psfont(const gchar *name)
651 {
652 GtkPSFont *fontdata = NULL;
653 GtkPSFont *data = NULL;
654 GList *fonts;
655 gint i;
656
657 /* user_fonts should be superior to font_data, the built-in default
658 settings because user_fonts is supposed to store a more appropriate
659 existent xfont than font_data.
660 */
661
662 fonts = user_fonts;
663 while(fonts){
664 data = (GtkPSFont *) fonts->data;
665 if(strcmp(name, data->fontname) == 0) {
666 fontdata = data;
667 break;
668 }
669 if(strcmp(name, data->psname) == 0) {
670 fontdata = data;
671 break;
672 }
673 fonts = fonts->next;
674 }
675
676 if(fontdata == NULL) {
677 for(i = 0; i < (int)NUM_FONTS; i++){
678 if(strcmp(name, font_data[i].fontname) == 0) {
679 fontdata = &font_data[i];
680 break;
681 }
682 if(strcmp(name, font_data[i].psname) == 0) {
683 fontdata = &font_data[i];
684 break;
685 }
686 }
687 }
688
689 return fontdata;
690 }
691
692 /**
693 * gtk_psfont_get_by_family:
694 * @family_name: font name
695 * @italic: TRUE or FALSE
696 * @bold: TRUE or FALSE
697 *
698 * Get #GtkPSFont by family.
699 *
700 * Returns: (transfer none) the #GtkPSFont
701 */
702 GtkPSFont *
gtk_psfont_get_by_family(const gchar * family_name,gboolean italic,gboolean bold)703 gtk_psfont_get_by_family(const gchar *family_name, gboolean italic, gboolean bold)
704 {
705 GtkPSFont *fontdata = NULL;
706 GtkPSFont *data = NULL;
707 GtkPSFont *return_data = NULL;
708 GList *fonts;
709 gint i;
710
711 /* user_fonts should be superior to font_data, the built-in default
712 settings because user_fonts is supposed to store a more appropriate
713 existent xfont than font_data.
714 */
715
716 fonts = user_fonts;
717 while(fonts){
718 data = (GtkPSFont *) fonts->data;
719 if(strcmp(family_name, data->family) == 0) {
720 return_data = data;
721 if(data->italic == italic && data->bold == bold){
722 fontdata = data;
723 break;
724 }
725 }
726 fonts = fonts->next;
727 }
728
729 if(fontdata == NULL) {
730 for(i = 0; i < (int)NUM_FONTS; i++){
731 if(strcmp(family_name, font_data[i].family) == 0) {
732 return_data = &font_data[i];
733 if(font_data[i].italic == italic && font_data[i].bold == bold){
734 fontdata = &font_data[i];
735 break;
736 }
737 }
738 }
739 }
740
741 if(!fontdata) fontdata = return_data;
742 return fontdata;
743 }
744
745
746 /**
747 * gtk_psfont_get_families:
748 * @families: (element-type gchar*) font families
749 * @num_families: families number
750 *
751 * Get #GtkPSFont by family.
752 */
753 void
gtk_psfont_get_families(GList ** families,gint * num_families)754 gtk_psfont_get_families(GList **families, gint *num_families)
755 {
756 if(!psfont_init || psfont_refcount == 0){
757 g_warning("PS fonts have not been initialized. Use gtk_psfont_init first.");
758 return;
759 }
760
761 *families = psfont_families;
762 *num_families = numf;
763 }
764