1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program 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
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /* Some of the font-definitions were borrowed from xfig.
20 Here is the original copyright text from that code:
22 * FIG : Facility for Interactive Generation of figures
23 * Copyright (c) 1991 by Brian V. Smith
25 * The X Consortium, and any party obtaining a copy of these files from
26 * the X Consortium, directly or indirectly, is granted, free of charge, a
27 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
28 * nonexclusive right and license to deal in this software and
29 * documentation files (the "Software"), including without limitation the
30 * rights to use, copy, modify, merge, publish, distribute, sublicense,
31 * and/or sell copies of the Software subject to the restriction stated
32 * below, and to permit persons who receive copies from any such party to
33 * do so, with the only requirement being that this copyright notice remain
35 * This license includes without limitation a license to do the foregoing
36 * actions under any patents of the party supplying this software to the
41 * The font suck code was taken from the gnome canvas text object
42 * bearing the following copyright header:
43 * Copyright (C) 1998 The Free Software Foundation
45 * Author: Federico Mena <federico@nuclecu.unam.mx>
59 #define FONTCACHE_SIZE 17
61 #define NUM_X11_FONTS 2
63 typedef struct _FontPrivate FontPrivate
;
64 typedef struct _FontCacheItem FontCacheItem
;
66 struct _FontCacheItem
{
75 char **fontname_x11_vec
;
77 FontCacheItem
*cache
[FONTCACHE_SIZE
];
78 real ascent_ratio
, descent_ratio
;
82 typedef struct _FontData
{
85 char *fontname_x11
[NUM_X11_FONTS
]; /* First choice */
88 FontData font_data
[] = {
91 { "-adobe-times-medium-r-normal-*-%d-*-*-*-*-*-*-*",
97 { "-adobe-times-medium-i-normal-*-%d-*-*-*-*-*-*-*",
103 { "-adobe-times-bold-r-normal-*-%d-*-*-*-*-*-*-*",
107 { "Times-BoldItalic",
109 { "-adobe-times-bold-i-normal-*-%d-*-*-*-*-*-*-*",
115 { "-adobe-avantgarde-book-r-normal-*-%d-*-*-*-*-*-*-*",
116 "-schumacher-clean-medium-r-normal-*-%d-*-*-*-*-*-*-*"
119 { "AvantGarde-BookOblique",
120 "AvantGarde-BookOblique",
121 { "-adobe-avantgarde-book-o-normal-*-%d-*-*-*-*-*-*-*",
122 "-schumacher-clean-medium-i-normal-*-%d-*-*-*-*-*-*-*"
127 { "-adobe-avantgarde-demibold-r-normal-*-%d-*-*-*-*-*-*-*",
128 "-schumacher-clean-bold-r-normal-*-%d-*-*-*-*-*-*-*"
131 { "AvantGarde-DemiOblique",
132 "AvantGarde-DemiOblique",
133 { "-adobe-avantgarde-demibold-o-normal-*-%d-*-*-*-*-*-*-*",
134 "-schumacher-clean-bold-i-normal-*-%d-*-*-*-*-*-*-*"
139 { "-adobe-bookman-light-r-normal-*-%d-*-*-*-*-*-*-*",
140 "-adobe-times-medium-r-normal-*-%d-*-*-*-*-*-*-*"
143 { "Bookman-LightItalic",
144 "Bookman-LightItalic",
145 { "-adobe-bookman-light-i-normal-*-%d-*-*-*-*-*-*-*",
146 "-adobe-times-medium-i-normal-*-%d-*-*-*-*-*-*-*"
151 { "-adobe-bookman-demibold-r-normal-*-%d-*-*-*-*-*-*-*",
152 "-adobe-times-bold-r-normal-*-%d-*-*-*-*-*-*-*"
155 { "Bookman-DemiItalic",
156 "Bookman-DemiItalic",
157 { "-adobe-bookman-demibold-i-normal-*-%d-*-*-*-*-*-*-*",
158 "-adobe-times-bold-i-normal-*-%d-*-*-*-*-*-*-*"
164 { "-adobe-courier-medium-r-normal-*-%d-*-*-*-*-*-*-*",
170 { "-adobe-courier-medium-o-normal-*-%d-*-*-*-*-*-*-*",
176 { "-adobe-courier-bold-r-normal-*-%d-*-*-*-*-*-*-*",
180 { "Courier-BoldOblique",
181 "Courier-BoldOblique",
182 { "-adobe-courier-bold-o-normal-*-%d-*-*-*-*-*-*-*",
186 #else /* G_OS_WIN32 */
187 /* HB: force usage of true type font "Courier New", using the bitmap
188 * version causes scaling problems mainly with uml. FIXME: there
189 * must be a better way to do this ?
193 { "-adobe-courier new-medium-r-normal-*-%d-*-*-*-*-*-*-*",
199 { "-adobe-courier new-medium-o-normal-*-%d-*-*-*-*-*-*-*",
205 { "-adobe-courier new-bold-r-normal-*-%d-*-*-*-*-*-*-*",
209 { "Courier-BoldOblique",
210 "Courier-BoldOblique",
211 { "-adobe-courier new-bold-o-normal-*-%d-*-*-*-*-*-*-*",
218 { "-adobe-helvetica-medium-r-normal-*-%d-*-*-*-*-*-*-*",
222 { "Helvetica-Oblique",
224 { "-adobe-helvetica-medium-o-normal-*-%d-*-*-*-*-*-*-*",
230 { "-adobe-helvetica-bold-r-normal-*-%d-*-*-*-*-*-*-*",
234 { "Helvetica-BoldOblique",
235 "Helvetica-BoldOblique",
236 { "-adobe-helvetica-bold-o-normal-*-%d-*-*-*-*-*-*-*",
240 { "Helvetica-Narrow",
242 { "-adobe-helvetica-medium-r-normal-*-%d-*-*-*-*-*-*-*",
246 { "Helvetica-Narrow-Oblique",
247 "Helvetica-Narrow-Oblique",
248 { "-adobe-helvetica-medium-o-normal-*-%d-*-*-*-*-*-*-*",
252 { "Helvetica-Narrow-Bold",
253 "Helvetica-Narrow-Bold",
254 { "-adobe-helvetica-bold-r-normal-*-%d-*-*-*-*-*-*-*",
258 { "Helvetica-Narrow-BoldOblique",
259 "Helvetica-Narrow-BoldOblique",
260 { "-adobe-helvetica-bold-o-normal-*-%d-*-*-*-*-*-*-*",
264 { "NewCenturySchoolbook-Roman",
265 "NewCenturySchlbk-Roman",
266 { "-adobe-new century schoolbook-medium-r-normal-*-%d-*-*-*-*-*-*-*",
270 { "NewCenturySchoolbook-Italic",
271 "NewCenturySchlbk-Italic",
272 { "-adobe-new century schoolbook-medium-i-normal-*-%d-*-*-*-*-*-*-*",
276 { "NewCenturySchoolbook-Bold",
277 "NewCenturySchlbk-Bold",
278 { "-adobe-new century schoolbook-bold-r-normal-*-%d-*-*-*-*-*-*-*",
282 { "NewCenturySchoolbook-BoldItalic",
283 "NewCenturySchlbk-BoldItalic",
284 { "-adobe-new century schoolbook-bold-i-normal-*-%d-*-*-*-*-*-*-*",
290 { "-adobe-palatino-medium-r-normal-*-%d-*-*-*-*-*-*-*",
291 "-*-lucidabright-medium-r-normal-*-%d-*-*-*-*-*-*-*"
296 { "-adobe-palatino-medium-i-normal-*-%d-*-*-*-*-*-*-*",
297 "-*-lucidabright-medium-i-normal-*-%d-*-*-*-*-*-*-*"
302 { "-adobe-palatino-bold-r-normal-*-%d-*-*-*-*-*-*-*",
303 "-*-lucidabright-demibold-r-normal-*-%d-*-*-*-*-*-*-*"
306 { "Palatino-BoldItalic",
307 "Palatino-BoldItalic",
308 { "-adobe-palatino-bold-i-normal-*-%d-*-*-*-*-*-*-*",
309 "-*-lucidabright-demibold-i-normal-*-%d-*-*-*-*-*-*-*"
315 "-adobe-symbol-medium-r-normal-*-%d-*-*-*-*-*-*-*",
316 "-*-symbol-medium-r-normal-*-%d-*-*-*-*-*-*-*"
319 { "ZapfChancery-MediumItalic",
320 "ZapfChancery-MediumItalic",
321 { "-adobe-zapf chancery-medium-i-normal-*-%d-*-*-*-*-*-*-*",
322 "-*-itc zapf chancery-medium-i-normal-*-%d-*-*-*-*-*-*-*"
327 { "-adobe-zapf dingbats-medium-r-normal-*-%d-*-*-*-*-*-*-*",
328 "-*-itc zapf dingbats-*-*-*-*-%d-*-*-*-*-*-*-*"
333 #define NUM_FONTS (sizeof(font_data)/sizeof(FontData))
337 GHashTable
*fonts_hash
= NULL
;
339 char *last_resort_fonts
[] = {
340 "-adobe-courier-medium-r-normal-*-%d-*-*-*-*-*-*-*",
341 "fixed" /* Must be last. This is guaranteed to exist on an X11 system. */
343 #define NUM_LAST_RESORT_FONTS (sizeof(last_resort_fonts)/sizeof(char *))
345 static void suck_font_free (SuckFont
*suckfont
);
346 static SuckFont
*suck_font (GdkFont
*font
);
349 init_x11_font(FontPrivate
*font
)
352 GdkFont
*gdk_font
= NULL
;
358 for (i
=0;i
<NUM_X11_FONTS
;i
++) {
359 x11_font
= font
->fontname_x11_vec
[i
];
360 if (x11_font
== NULL
)
362 bufsize
= strlen(x11_font
)+6; /* Should be enought*/
363 buffer
= (char *)g_malloc(bufsize
);
364 g_snprintf(buffer
, bufsize
, x11_font
, 100);
366 gdk_font
= gdk_font_load(buffer
);
367 if (gdk_font
!=NULL
) {
368 font
->fontname_x11
= x11_font
;
372 if (font
->fontname_x11
!=NULL
)
376 if (font
->fontname_x11
== NULL
) {
377 for (i
=0;i
<NUM_LAST_RESORT_FONTS
;i
++) {
378 x11_font
= last_resort_fonts
[i
];
379 bufsize
= strlen(x11_font
)+6; /* Should be enought*/
380 buffer
= (char *)g_malloc(bufsize
);
381 g_snprintf(buffer
, bufsize
, x11_font
, 100);
383 gdk_font
= gdk_font_load(buffer
);
385 if (gdk_font
!=NULL
) {
386 message_warning(_("Warning no X Font for %s found, \nusing %s instead.\n"), font
->public.name
, x11_font
);
387 font
->fontname_x11
= x11_font
;
393 height
= (real
)gdk_font
->ascent
+ gdk_font
->descent
;
394 font
->ascent_ratio
= gdk_font
->ascent
/height
;
395 font
->descent_ratio
= gdk_font
->descent
/height
;
397 gdk_font_unref(gdk_font
);
406 fonts_hash
= g_hash_table_new((GHashFunc
)g_str_hash
,
407 (GCompareFunc
)g_str_equal
);
409 for (i
=0;i
<NUM_FONTS
;i
++) {
410 font
= g_new(FontPrivate
, 1);
411 font
->public.name
= font_data
[i
].fontname
;
412 font
->fontname_ps
= font_data
[i
].fontname_ps
;
414 font
->fontname_x11
= NULL
;
415 font
->fontname_x11_vec
= font_data
[i
].fontname_x11
;
417 for (j
=0;j
<FONTCACHE_SIZE
;j
++) {
418 font
->cache
[j
] = NULL
;
421 fonts
= g_list_append(fonts
, font
);
422 font_names
= g_list_append(font_names
, font
->public.name
);
423 g_hash_table_insert(fonts_hash
, font
->public.name
, font
);
429 font_getfont(const char *name
)
433 font
= (FontPrivate
*)g_hash_table_lookup(fonts_hash
, (char *)name
);
436 font
= g_hash_table_lookup(fonts_hash
, "Courier");
438 message_error("Error, couldn't locate font. Shouldn't happend.\n");
440 message_notice(_("Font %s not found, using Courier instead.\n"), name
);
444 if (font
->fontname_x11
== NULL
)
450 static FontCacheItem
*
451 font_get_cache(FontPrivate
*font
, int height
)
458 index
= height
% FONTCACHE_SIZE
;
460 if (font
->cache
[index
]==NULL
) {
461 font
->cache
[index
] = g_new(FontCacheItem
, 1);
462 font
->cache
[index
]->height
= height
;
463 font
->cache
[index
]->gdk_font
= NULL
;
464 font
->cache
[index
]->suck_font
= NULL
;
465 } else if (font
->cache
[index
]->height
!= height
) {
466 gdk_font_unref(font
->cache
[index
]->gdk_font
);
467 if (font
->cache
[index
]->suck_font
)
468 suck_font_free(font
->cache
[index
]->suck_font
);
469 font
->cache
[index
]->height
= height
;
470 font
->cache
[index
]->gdk_font
= NULL
;
471 font
->cache
[index
]->suck_font
= NULL
;
473 return font
->cache
[index
];
477 font_get_gdkfont_helper(FontPrivate
*font
, int height
)
483 bufsize
= strlen(font
->fontname_x11
)+6; /* Should be enought*/
484 buffer
= (char *)malloc(bufsize
);
485 g_snprintf(buffer
, bufsize
, font
->fontname_x11
, height
);
486 gdk_font
= gdk_font_load(buffer
);
494 font_get_gdkfont(Font
*font
, int height
)
496 FontCacheItem
*cache_item
;
497 FontPrivate
*fontprivate
;
499 fontprivate
= (FontPrivate
*)font
;
501 cache_item
= font_get_cache(fontprivate
, height
);
503 if (cache_item
->gdk_font
)
504 return cache_item
->gdk_font
;
508 cache_item
->gdk_font
= font_get_gdkfont_helper(fontprivate
, cache_item
->height
);
510 return cache_item
->gdk_font
;
514 font_get_suckfont(Font
*font
, int height
)
516 FontCacheItem
*cache_item
;
517 FontPrivate
*fontprivate
;
519 fontprivate
= (FontPrivate
*)font
;
521 cache_item
= font_get_cache(fontprivate
, height
);
523 if (!cache_item
->gdk_font
) {
524 /* gdk_font not in cache: */
525 cache_item
->gdk_font
= font_get_gdkfont_helper(fontprivate
, cache_item
->height
);
528 if (!cache_item
->suck_font
) {
530 cache_item
->suck_font
= suck_font(cache_item
->gdk_font
);
533 return cache_item
->suck_font
;
537 font_get_psfontname(Font
*font
)
539 FontPrivate
*fontprivate
;
541 fontprivate
= (FontPrivate
*)font
;
543 return fontprivate
->fontname_ps
;
547 font_string_width(const char *string
, Font
*font
, real height
)
553 /* Note: This is an ugly hack. It tries to overestimate the width with
554 some magic stuff. No guarantees. */
555 gdk_font
= font_get_gdkfont(font
, 100);
556 iwidth
= gdk_string_width(gdk_font
, string
);
557 iheight
= gdk_string_height(gdk_font
, string
);
559 if ((iwidth
==0) || (iheight
==0))
562 width_height
= ((real
)iwidth
)/((real
)iheight
);
563 width_height
*= 1.01;
564 return width_height
*height
*(iheight
/100.0) + 0.2;
568 font_ascent(Font
*font
, real height
)
570 FontPrivate
*fontprivate
;
571 fontprivate
= (FontPrivate
*)font
;
572 return height
*fontprivate
->ascent_ratio
;
576 font_descent(Font
*font
, real height
)
578 FontPrivate
*fontprivate
;
579 fontprivate
= (FontPrivate
*)font
;
580 return height
*fontprivate
->descent_ratio
;
583 /* Routines for sucking fonts from the X server */
586 suck_font (GdkFont
*font
)
592 int lbearing
, rbearing
, ch_width
, ascent
, descent
;
594 GdkColor black
, white
;
599 int black_pixel
, pixel
;
604 suckfont
= g_new (SuckFont
, 1);
606 height
= font
->ascent
+ font
->descent
;
608 for (i
= 0; i
< 256; i
++) {
610 gdk_text_extents (font
, text
, 1,
611 &lbearing
, &rbearing
, &ch_width
, &ascent
, &descent
);
612 suckfont
->chars
[i
].left_sb
= lbearing
;
613 suckfont
->chars
[i
].right_sb
= ch_width
- rbearing
;
614 suckfont
->chars
[i
].width
= rbearing
- lbearing
;
615 suckfont
->chars
[i
].ascent
= ascent
;
616 suckfont
->chars
[i
].descent
= descent
;
617 suckfont
->chars
[i
].bitmap_offset
= x
;
618 x
+= (ch_width
+ 31) & -32;
623 suckfont
->bitmap_width
= width
;
624 suckfont
->bitmap_height
= height
+1;
625 suckfont
->ascent
= font
->ascent
+1;
627 pixmap
= gdk_pixmap_new (NULL
, suckfont
->bitmap_width
,
628 suckfont
->bitmap_height
, 1);
629 gc
= gdk_gc_new (pixmap
);
630 gdk_gc_set_font (gc
, font
);
632 /* this is a black and white pixmap: */
635 black_pixel
= black
.pixel
;
636 gdk_gc_set_foreground (gc
, &white
);
637 gdk_draw_rectangle (pixmap
, gc
, 1, 0, 0, suckfont
->bitmap_width
, suckfont
->bitmap_height
);
639 gdk_gc_set_foreground (gc
, &black
);
640 for (i
= 0; i
< 256; i
++) {
642 gdk_draw_text (pixmap
, font
, gc
,
643 suckfont
->chars
[i
].bitmap_offset
- suckfont
->chars
[i
].left_sb
,
648 /* The handling of the image leaves me with distinct unease. But this
649 * is more or less copied out of gimp/app/text_tool.c, so it _ought_ to
653 image
= gdk_image_get (pixmap
, 0, 0, suckfont
->bitmap_width
, suckfont
->bitmap_height
);
654 suckfont
->bitmap
= g_malloc0 ((width
>> 3) * suckfont
->bitmap_height
);
656 line
= suckfont
->bitmap
;
657 for (y
= 0; y
< suckfont
->bitmap_height
; y
++) {
658 for (x
= 0; x
< suckfont
->bitmap_width
; x
++) {
659 pixel
= gdk_image_get_pixel (image
, x
, y
);
660 if (pixel
== black_pixel
)
661 line
[x
>> 3] |= 128 >> (x
& 7);
666 gdk_image_destroy (image
);
668 /* free the pixmap */
669 gdk_pixmap_unref (pixmap
);
678 suck_font_free (SuckFont
*suckfont
)
680 g_free (suckfont
->bitmap
);