TextLine first implementation.
[dia.git] / lib / font.c
blobdb14583fb1570e1b63880e0bc447da21c2f09b9d
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
3 * Font code completely reworked for the Pango conversion
4 * Copyright (C) 2002 Cyrille Chepelov
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h> /* strlen */
28 #include <time.h>
30 #include <pango/pango.h>
31 #ifdef HAVE_FREETYPE
32 #include <pango/pangoft2.h>
33 #endif
34 #include <gdk/gdk.h>
35 #include <gtk/gtk.h> /* just for gtk_get_default_language() */
36 #ifdef GDK_WINDOWING_WIN32
37 /* avoid namespace clashes caused by inclusion of windows.h */
38 #define Rectangle Win32Rectangle
39 #include <pango/pangowin32.h>
40 #undef Rectangle
41 #endif
42 #include "font.h"
43 #include "message.h"
44 #include "intl.h"
46 static PangoContext* pango_context = NULL;
48 struct _DiaFont
50 GObject parent_instance;
52 PangoFontDescription* pfd;
53 /* mutable */ char* legacy_name;
57 /* This is the global factor that says what zoom factor is 100%. It's
58 * normally 20.0 (and likely to stay that way). It is defined by how many
59 * pixels one cm is represented as.
61 static real global_zoom_factor = 20.0;
63 #if 0
64 /* For debugging: Sort families */
65 static int
66 cmp_families (const void *a, const void *b)
68 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
69 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
71 return g_utf8_collate (a_name, b_name);
74 /* For debugging: List all font families */
75 static void
76 list_families()
78 PangoFontFamily **families;
79 int nfamilies;
80 int i;
82 pango_context_list_families(dia_font_get_context(), &families, &nfamilies);
83 qsort (families, nfamilies, sizeof (PangoFontFamily *), cmp_families);
84 for (i = 0; i < nfamilies; i++) {
85 puts(pango_font_family_get_name(families[i]));
87 g_free(families);
89 #endif
91 static void
92 dia_font_check_for_font(int font) {
93 DiaFont *check;
94 PangoFont *loaded;
96 check = dia_font_new_from_style(font, 1.0);
97 loaded = pango_context_load_font(dia_font_get_context(),
98 check->pfd);
99 if (loaded == NULL) {
100 message_error(_("Can't load font %s.\n"), dia_font_get_family(check));
104 void
105 dia_font_init(PangoContext* pcontext)
107 pango_context = pcontext;
108 /* We must have these three fonts! */
109 dia_font_check_for_font(DIA_FONT_SANS);
110 dia_font_check_for_font(DIA_FONT_SERIF);
111 dia_font_check_for_font(DIA_FONT_MONOSPACE);
114 /* We might not need these anymore, when using FT2/Win32 fonts only */
115 static GList *pango_contexts;
117 void
118 dia_font_push_context(PangoContext *pcontext) {
119 pango_contexts = g_list_prepend(pango_contexts, pango_context);
120 pango_context = pcontext;
121 pango_context_set_language (pango_context, gtk_get_default_language ());
122 g_object_ref(pcontext);
125 void
126 dia_font_pop_context() {
127 g_object_unref(pango_context);
128 pango_context = (PangoContext*)pango_contexts->data;
129 pango_context_set_language (pango_context, gtk_get_default_language ());
130 pango_contexts = g_list_next(pango_contexts);
133 PangoContext *
134 dia_font_get_context() {
135 if (pango_context == NULL) {
136 #ifdef HAVE_FREETYPE
137 /* This is suggested by new Pango (1.2.4+), but doesn't get us the
138 * right resolution:(
139 dia_font_push_context(pango_ft2_font_map_create_context(pango_ft2_font_map_new()));
141 dia_font_push_context(pango_ft2_get_context(75,75));
142 #else
143 if (gdk_display_get_default ())
144 dia_font_push_context(gdk_pango_context_get());
145 else {
146 # ifdef GDK_WINDOWING_WIN32
147 dia_font_push_context(pango_win32_get_context ());
148 # else
149 g_warning ("dia_font_get_context() : not font context w/o display. Crashing soon.");
150 # endif
152 #endif
154 return pango_context;
157 /* dia centimetres to pango device units */
158 static gint
159 dcm_to_pdu(real dcm) { return dcm * global_zoom_factor * PANGO_SCALE; }
160 /* pango device units to dia centimetres */
161 static real
162 pdu_to_dcm(gint pdu) { return (real)pdu / (global_zoom_factor * PANGO_SCALE); }
164 static void dia_font_class_init(DiaFontClass* class);
165 static void dia_font_finalize(GObject* object);
166 static void dia_font_init_instance(DiaFont*);
168 GType
169 dia_font_get_type (void)
171 static GType object_type = 0;
173 if (!object_type) {
174 static const GTypeInfo object_info =
176 sizeof (DiaFontClass),
177 (GBaseInitFunc) NULL,
178 (GBaseFinalizeFunc) NULL,
179 (GClassInitFunc) dia_font_class_init, /* class_init */
180 NULL, /* class_finalize */
181 NULL, /* class_data */
182 sizeof (DiaFont),
183 0, /* n_preallocs */
184 (GInstanceInitFunc)dia_font_init_instance
186 object_type = g_type_register_static (G_TYPE_OBJECT,
187 "DiaFont",
188 &object_info, 0);
190 return object_type;
192 static gpointer parent_class;
194 static void
195 dia_font_class_init(DiaFontClass* klass)
197 GObjectClass* object_class = G_OBJECT_CLASS(klass);
198 parent_class = g_type_class_peek_parent(klass);
199 object_class->finalize = dia_font_finalize;
202 static void
203 dia_font_init_instance(DiaFont* font)
205 /*GObject *gobject = G_OBJECT(font); */
208 DiaFont*
209 dia_font_new(const char *family, DiaFontStyle style, real height)
211 DiaFont* retval = dia_font_new_from_style(style, height);
213 pango_font_description_set_family(retval->pfd,family);
215 pango_context_load_font(dia_font_get_context(), retval->pfd);
217 return retval;
220 static void
221 dia_pfd_set_family(PangoFontDescription* pfd, DiaFontFamily fam) {
222 switch (fam) {
223 case DIA_FONT_SANS :
224 pango_font_description_set_family(pfd, "sans");
225 break;
226 case DIA_FONT_SERIF :
227 pango_font_description_set_family(pfd, "serif");
228 break;
229 case DIA_FONT_MONOSPACE :
230 pango_font_description_set_family(pfd, "monospace");
231 break;
232 default :
233 /* Pango does allow fonts without a name */
238 static void
239 dia_pfd_set_weight(PangoFontDescription* pfd, DiaFontWeight fw) {
240 switch (fw) {
241 case DIA_FONT_ULTRALIGHT :
242 pango_font_description_set_weight(pfd, PANGO_WEIGHT_ULTRALIGHT);
243 break;
244 case DIA_FONT_LIGHT :
245 pango_font_description_set_weight(pfd, PANGO_WEIGHT_LIGHT);
246 break;
247 case DIA_FONT_WEIGHT_NORMAL :
248 pango_font_description_set_weight(pfd, PANGO_WEIGHT_NORMAL);
249 break;
250 case DIA_FONT_MEDIUM : /* Pango doesn't have this, but
251 'intermediate values are possible' */
252 pango_font_description_set_weight(pfd, 500);
253 break;
254 case DIA_FONT_DEMIBOLD : /* Pango doesn't have this, ... */
255 pango_font_description_set_weight(pfd, 600);
256 break;
257 case DIA_FONT_BOLD :
258 pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
259 break;
260 case DIA_FONT_ULTRABOLD :
261 pango_font_description_set_weight(pfd, PANGO_WEIGHT_ULTRABOLD);
262 break;
263 case DIA_FONT_HEAVY :
264 pango_font_description_set_weight(pfd, PANGO_WEIGHT_HEAVY);
265 break;
266 default :
267 g_assert_not_reached();
271 static void
272 dia_pfd_set_slant(PangoFontDescription* pfd, DiaFontSlant fo) {
273 switch (fo) {
274 case DIA_FONT_NORMAL :
275 pango_font_description_set_style(pfd,PANGO_STYLE_NORMAL);
276 break;
277 case DIA_FONT_OBLIQUE :
278 pango_font_description_set_style(pfd,PANGO_STYLE_OBLIQUE);
279 break;
280 case DIA_FONT_ITALIC :
281 pango_font_description_set_style(pfd,PANGO_STYLE_ITALIC);
282 break;
283 default :
284 g_assert_not_reached();
288 static void dia_pfd_set_size(PangoFontDescription* pfd, real height)
289 { /* inline candidate... */
290 pango_font_description_set_size(pfd, dcm_to_pdu(height) );
294 DiaFont*
295 dia_font_new_from_style(DiaFontStyle style, real height)
297 DiaFont* retval;
298 /* in the future we could establish Dia's own default font
299 * matching to be as (font-)system independent as possible.
300 * For now fall back to Pangos configuration --hb
302 PangoFontDescription* pfd = pango_font_description_new();
303 dia_pfd_set_family(pfd,DIA_FONT_STYLE_GET_FAMILY(style));
304 dia_pfd_set_weight(pfd,DIA_FONT_STYLE_GET_WEIGHT(style));
305 dia_pfd_set_slant(pfd,DIA_FONT_STYLE_GET_SLANT(style));
306 dia_pfd_set_size(pfd,height);
308 retval = DIA_FONT(g_object_new(DIA_TYPE_FONT, NULL));
310 retval->pfd = pfd;
311 retval->legacy_name = NULL;
312 return retval;
315 DiaFont* dia_font_copy(const DiaFont* font)
317 if (!font) return NULL;
318 return dia_font_new(dia_font_get_family(font),
319 dia_font_get_style(font),
320 dia_font_get_height(font));
323 void
324 dia_font_finalize(GObject* object)
326 DiaFont* font;
327 font = DIA_FONT(object);
328 if (font->pfd) pango_font_description_free(font->pfd);
329 G_OBJECT_CLASS(parent_class)->finalize(object);
332 DiaFont* dia_font_ref(DiaFont* font)
334 g_object_ref(G_OBJECT(font));
335 return font;
338 void dia_font_unref(DiaFont* font)
340 g_object_unref(G_OBJECT(font));
343 DiaFontStyle
344 dia_font_get_style(const DiaFont* font)
346 guint style;
348 static int weight_map[] = {
349 DIA_FONT_ULTRALIGHT, DIA_FONT_LIGHT,
350 DIA_FONT_WEIGHT_NORMAL, /* intentionaly ==0 */
351 DIA_FONT_MEDIUM, DIA_FONT_DEMIBOLD, /* not yet in Pango */
352 DIA_FONT_BOLD, DIA_FONT_ULTRABOLD, DIA_FONT_HEAVY
355 PangoStyle pango_style = pango_font_description_get_style(font->pfd);
356 PangoWeight pango_weight = pango_font_description_get_weight(font->pfd);
358 g_assert(PANGO_WEIGHT_ULTRALIGHT <= pango_weight && pango_weight <= PANGO_WEIGHT_HEAVY);
359 g_assert(PANGO_WEIGHT_ULTRALIGHT == 200);
360 g_assert(PANGO_WEIGHT_NORMAL == 400);
361 g_assert(PANGO_WEIGHT_BOLD == 700);
363 style = weight_map[(pango_weight - PANGO_WEIGHT_ULTRALIGHT) / 100];
364 style |= (pango_style << 2);
366 return style;
369 G_CONST_RETURN char*
370 dia_font_get_family(const DiaFont* font)
372 return pango_font_description_get_family(font->pfd);
375 G_CONST_RETURN PangoFontDescription *
376 dia_font_get_description(const DiaFont* font)
378 return font->pfd;
381 real
382 dia_font_get_height(const DiaFont* font)
384 return pdu_to_dcm(pango_font_description_get_size(font->pfd));
387 void
388 dia_font_set_height(DiaFont* font, real height)
390 pango_font_description_set_size(font->pfd, dcm_to_pdu(height));
394 G_CONST_RETURN char*
395 dia_font_get_psfontname(const DiaFont *font)
397 /* FIXME: this will very likely not work ! */
398 return dia_font_get_legacy_name(font);
401 void dia_font_set_any_family(DiaFont* font, const char* family)
403 g_assert(font != NULL);
404 pango_font_description_set_family(font->pfd, family);
405 if (font->legacy_name) {
406 g_free(font->legacy_name);
407 font->legacy_name = NULL;
411 void dia_font_set_family(DiaFont* font, DiaFontFamily family)
413 g_assert(font != NULL);
414 dia_pfd_set_family(font->pfd,family);
415 if (font->legacy_name) {
416 g_free(font->legacy_name);
417 font->legacy_name = NULL;
421 void dia_font_set_weight(DiaFont* font, DiaFontWeight weight)
423 g_assert(font != NULL);
424 dia_pfd_set_weight(font->pfd,weight);
427 void dia_font_set_slant(DiaFont* font, DiaFontSlant slant)
429 g_assert(font != NULL);
430 dia_pfd_set_slant(font->pfd,slant);
434 struct weight_name { DiaFontWeight fw; const char *name; };
435 static const struct weight_name weight_names[] = {
436 {DIA_FONT_ULTRALIGHT, "200"},
437 {DIA_FONT_LIGHT,"300"},
438 {DIA_FONT_WEIGHT_NORMAL,"normal"},
439 {DIA_FONT_WEIGHT_NORMAL,"400"},
440 {DIA_FONT_MEDIUM, "500"},
441 {DIA_FONT_DEMIBOLD, "600"},
442 {DIA_FONT_BOLD, "700"},
443 {DIA_FONT_ULTRABOLD, "800"},
444 {DIA_FONT_HEAVY, "900"},
445 {0,NULL}};
447 G_CONST_RETURN char *dia_font_get_weight_string(const DiaFont* font)
449 const struct weight_name* p;
450 DiaFontWeight fw = DIA_FONT_STYLE_GET_WEIGHT(dia_font_get_style(font));
452 for (p = weight_names; p->name != NULL; ++p) {
453 if (p->fw == fw) return p->name;
455 return "normal";
458 void dia_font_set_weight_from_string(DiaFont* font, const char* weight) {
459 DiaFontWeight fw = DIA_FONT_WEIGHT_NORMAL;
460 const struct weight_name* p;
462 for (p = weight_names; p->name != NULL; ++p) {
463 if (0 == strncmp(weight,p->name,8)) {
464 fw = p->fw;
465 break;
469 dia_font_set_weight(font,fw);
473 struct slant_name { DiaFontSlant fo; const char *name; };
474 static const struct slant_name slant_names[] = {
475 { DIA_FONT_NORMAL, "normal"},
476 { DIA_FONT_OBLIQUE, "oblique"},
477 { DIA_FONT_ITALIC, "italic"},
478 { 0, NULL} };
480 G_CONST_RETURN char *
481 dia_font_get_slant_string(const DiaFont* font)
483 const struct slant_name* p;
484 DiaFontSlant fo =
485 DIA_FONT_STYLE_GET_SLANT(dia_font_get_style(font));
487 for (p = slant_names; p->name != NULL; ++p) {
488 if (p->fo == fo) return p->name;
490 return "normal";
493 void dia_font_set_slant_from_string(DiaFont* font, const char* obli) {
494 DiaFontSlant fo = DIA_FONT_NORMAL;
495 const struct slant_name* p;
497 DiaFontStyle old_style;
498 DiaFontSlant old_fo;
499 old_style = dia_font_get_style(font);
500 old_fo = DIA_FONT_STYLE_GET_SLANT(old_style);
502 for (p = slant_names; p->name != NULL; ++p) {
503 if (0 == strncmp(obli,p->name,8)) {
504 fo = p->fo;
505 break;
508 dia_font_set_slant(font,fo);
512 /* ************************************************************************ */
513 /* Non-scaled versions of the utility routines */
514 /* ************************************************************************ */
516 real
517 dia_font_string_width(const char* string, DiaFont *font, real height)
519 return dia_font_scaled_string_width(string,font,height,global_zoom_factor);
522 real
523 dia_font_ascent(const char* string, DiaFont* font, real height)
525 return dia_font_scaled_ascent(string,font,height,global_zoom_factor);
528 real dia_font_descent(const char* string, DiaFont* font, real height)
530 return dia_font_scaled_descent(string,font,height,global_zoom_factor);
534 PangoLayout*
535 dia_font_build_layout(const char* string, DiaFont* font, real height)
537 PangoLayout* layout;
538 PangoAttrList* list;
539 PangoAttribute* attr;
540 guint length;
541 gchar *desc = NULL;
543 height *= 0.7;
544 dia_font_set_height(font, height);
547 /* This could should account for DPI, but it doesn't do right. Grrr...
549 GdkScreen *screen = gdk_screen_get_default();
550 real dpi = gdk_screen_get_width(screen)/
551 (gdk_screen_get_width_mm(screen)/25.4);
552 printf("height = %f, dpi = %f, new height = %f\n",
553 height, dpi, height * (dpi/100));
554 height *= dpi/100;
558 layout = pango_layout_new(dia_font_get_context());
560 length = string ? strlen(string) : 0;
561 pango_layout_set_text(layout, string, length);
563 list = pango_attr_list_new();
564 desc = g_utf8_strdown(pango_font_description_get_family(font->pfd), -1);
565 pango_font_description_set_family(font->pfd, desc);
566 g_free(desc);
567 attr = pango_attr_font_desc_new(font->pfd);
568 attr->start_index = 0;
569 attr->end_index = length;
570 pango_attr_list_insert(list,attr); /* eats attr */
572 pango_layout_set_attributes(layout,list);
573 pango_attr_list_unref(list);
575 pango_layout_set_indent(layout,0);
576 pango_layout_set_justify(layout,FALSE);
577 pango_layout_set_alignment(layout,PANGO_ALIGN_LEFT);
579 return layout;
582 /* ************************************************************************ */
583 /* scaled versions of the utility routines */
584 /* ************************************************************************ */
586 void
587 dia_font_set_nominal_zoom_factor(real size_one)
588 { global_zoom_factor = size_one; }
592 real
593 dia_font_scaled_string_width(const char* string, DiaFont *font, real height,
594 real zoom_factor)
596 int lw,lh;
597 real result;
598 PangoLayout* layout;
600 if (string == NULL || string[0] == '\0') {
601 return 0.0;
604 layout = dia_font_scaled_build_layout(string, font, height, zoom_factor);
605 pango_layout_get_size(layout,&lw,&lh);
606 g_object_unref(G_OBJECT(layout));
608 result = pdu_to_dcm(lw);
609 /* Scale the result back for the zoom factor */
610 result /= (zoom_factor/global_zoom_factor);
611 return result;
614 static gboolean
615 dia_font_vertical_extents(const char* string, DiaFont* font,
616 real height, real zoom_factor,
617 guint line_no,
618 real* top, real* baseline, real* bottom)
620 PangoRectangle ink_rect,logical_rect;
621 PangoLayout* layout;
622 PangoLayoutIter* iter;
623 guint i;
625 if (string == NULL || string[0] == '\0') {
626 return FALSE;
629 layout = dia_font_scaled_build_layout(string, font,
630 height, zoom_factor);
631 iter = pango_layout_get_iter(layout);
632 for (i = 0; i < line_no; ++i) {
633 if (!pango_layout_iter_next_line(iter)) {
634 pango_layout_iter_free(iter);
635 g_object_unref(G_OBJECT(layout));
636 return FALSE;
640 pango_layout_iter_get_line_extents(iter,&ink_rect,&logical_rect);
642 *top = pdu_to_dcm(logical_rect.y);
643 *bottom = pdu_to_dcm(logical_rect.y + logical_rect.height);
644 *baseline = pdu_to_dcm(pango_layout_iter_get_baseline(iter));
646 pango_layout_iter_free(iter);
647 g_object_unref(G_OBJECT(layout));
649 return TRUE;
653 real
654 dia_font_scaled_ascent(const char* string, DiaFont* font, real height,
655 real zoom_factor)
657 real top,bline,bottom;
658 if (!string || string[0] == '\0') {
659 /* This hack won't work for fonts that don't cover ASCII */
660 dia_font_vertical_extents("XjgM149",font,height,zoom_factor,
661 0,&top,&bline,&bottom);
662 } else {
663 dia_font_vertical_extents(string,font,height,zoom_factor,
664 0,&top,&bline,&bottom);
666 return (bline-top)/(zoom_factor/global_zoom_factor);
669 real dia_font_scaled_descent(const char* string, DiaFont* font,
670 real height, real zoom_factor)
672 real top,bline,bottom;
674 if (!string || string[0] == '\0') {
675 /* This hack won't work for fonts that don't cover ASCII */
676 dia_font_vertical_extents("XjgM149",font,height,zoom_factor,
677 0,&top,&bline,&bottom);
678 } else {
679 dia_font_vertical_extents(string,font,height,zoom_factor,
680 0,&top,&bline,&bottom);
682 return (bottom-bline)/(zoom_factor/global_zoom_factor);
685 /** Find the offsets of the individual letters in the iter and place them
686 * in an array.
687 * This currently assumes only one run per iter, which is all we can input.
688 * @param iter The PangoLayoutIter to count characters in.
689 * @param offsets The place to return the offsets
690 * @param n_offsets The place to return the number of offsets
692 static void
693 get_string_offsets(PangoLayoutIter *iter, real** offsets, int* n_offsets)
695 int i;
696 PangoLayoutLine* line = pango_layout_iter_get_line(iter);
697 PangoGlyphItem* item = (PangoGlyphItem*)line->runs->data;
698 PangoGlyphString* string = item->glyphs;
700 *n_offsets = string->num_glyphs;
701 *offsets = g_new(real, *n_offsets);
703 for (i = 0; i < string->num_glyphs; i++) {
704 PangoGlyphGeometry geom = string->glyphs[i].geometry;
706 (*offsets)[i] = pdu_to_dcm(geom.width);
710 /** Get size information for the given string, font and height.
712 * @returns an array of offsets of the individual glyphs in the layout.
714 real*
715 dia_font_get_sizes(const char* string, DiaFont *font, real height,
716 real *width, real *ascent, real *descent, int *n_offsets)
718 real dummy;
719 PangoLayout* layout;
720 PangoLayoutIter* iter;
721 real top, bline, bottom;
722 gchar* non_empty_string;
723 PangoRectangle ink_rect,logical_rect;
724 real* offsets;
725 int i;
727 if (string == NULL || string[0] == '\0') {
728 non_empty_string = "XjgM149";
729 } else {
730 non_empty_string = string;
732 layout = dia_font_build_layout(non_empty_string, font, height);
734 /* Only one line here */
735 iter = pango_layout_get_iter(layout);
737 pango_layout_iter_get_line_extents(iter, &ink_rect, &logical_rect);
739 top = pdu_to_dcm(logical_rect.y);
740 bottom = pdu_to_dcm(logical_rect.y + logical_rect.height);
741 bline = pdu_to_dcm(pango_layout_iter_get_baseline(iter));
743 get_string_offsets(iter, &offsets, n_offsets);
745 pango_layout_iter_free(iter);
746 g_object_unref(G_OBJECT(layout));
748 *ascent = bline-top;
749 *descent = bottom-bline;
750 if (non_empty_string != string) {
751 *width = 0.0;
752 } else {
753 *width = pdu_to_dcm(logical_rect.width);
755 return offsets;
758 PangoLayout*
759 dia_font_scaled_build_layout(const char* string, DiaFont* font,
760 real height, real zoom_factor)
762 DiaFont* altered_font;
763 real scaling;
764 real nozoom_width;
765 real target_zoomed_width;
766 PangoLayout* layout;
767 real altered_scaling;
768 real real_width;
770 scaling = zoom_factor / global_zoom_factor;
771 if (fabs(1.0 - scaling) < 1E-7) {
772 return dia_font_build_layout(string,font,height);
775 nozoom_width = dia_font_string_width(string,font,height);
776 target_zoomed_width = nozoom_width * scaling;
778 /* First try: no tweaks. */
779 real_width = dia_font_string_width(string,font, height * scaling);
780 if (real_width <= target_zoomed_width) {
781 return dia_font_build_layout(string,font,height*scaling);
784 altered_font = dia_font_copy(font);
786 /* Last try. Using the "reduce overall size" strategy. */
787 for (altered_scaling = scaling;
788 altered_scaling > (scaling / 2);
789 altered_scaling *= (target_zoomed_width/real_width>0.98?0.98:
790 target_zoomed_width/real_width) ) {
791 real_width = dia_font_string_width(string,font,
792 height * altered_scaling);
794 if (real_width <= target_zoomed_width) {
795 layout = dia_font_build_layout(string,altered_font,
796 height*altered_scaling);
797 dia_font_unref(altered_font);
798 return layout;
802 /* Everything has failed. Returning non-tweaked variant. */
803 g_warning("Failed to appropriately tweak zoomed font for zoom factor %f.", zoom_factor);
804 dia_font_unref(altered_font);
805 return dia_font_build_layout(string,font,height*scaling);
809 * Compatibility with older files out of pre Pango Time.
810 * Make old files look as similar as possible
811 * List should be kept alphabetically sorted by oldname, in case of
812 * duplicates the one with the preferred newname comes first.
814 * FIXME: DIA_FONT_FAMILY_ANY in the list below does mean noone knows better
816 static struct _legacy_font {
817 gchar* oldname;
818 gchar* newname;
819 DiaFontStyle style; /* the DIA_FONT_FAMILY() is used as falback only */
820 } legacy_fonts[] = {
821 { "AvantGarde-Book", "AvantGarde", DIA_FONT_SERIF },
822 { "AvantGarde-BookOblique", "AvantGarde", DIA_FONT_SERIF | DIA_FONT_OBLIQUE },
823 { "AvantGarde-Demi", "AvantGarde", DIA_FONT_SERIF | DIA_FONT_DEMIBOLD },
824 { "AvantGarde-DemiOblique", "AvantGarde", DIA_FONT_SERIF | DIA_FONT_OBLIQUE | DIA_FONT_DEMIBOLD },
825 { "Batang", "Batang", DIA_FONT_FAMILY_ANY },
826 { "Bookman-Demi", "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_DEMIBOLD },
827 { "Bookman-DemiItalic", "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_DEMIBOLD | DIA_FONT_ITALIC },
828 { "Bookman-Light", "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_LIGHT },
829 { "Bookman-LightItalic", "Bookman Old Style", DIA_FONT_SERIF | DIA_FONT_LIGHT | DIA_FONT_ITALIC },
830 { "BousungEG-Light-GB", "BousungEG-Light-GB", DIA_FONT_FAMILY_ANY },
831 { "Courier", "monospace", DIA_FONT_MONOSPACE },
832 { "Courier", "Courier New", DIA_FONT_MONOSPACE },
833 { "Courier-Bold", "monospace", DIA_FONT_MONOSPACE | DIA_FONT_BOLD },
834 { "Courier-Bold", "Courier New", DIA_FONT_MONOSPACE | DIA_FONT_BOLD },
835 { "Courier-BoldOblique", "monospace", DIA_FONT_MONOSPACE | DIA_FONT_ITALIC | DIA_FONT_BOLD },
836 { "Courier-BoldOblique", "Courier New", DIA_FONT_MONOSPACE | DIA_FONT_ITALIC | DIA_FONT_BOLD },
837 { "Courier-Oblique", "monospace", DIA_FONT_MONOSPACE | DIA_FONT_ITALIC},
838 { "Courier-Oblique", "Courier New", DIA_FONT_MONOSPACE | DIA_FONT_ITALIC },
839 { "Dotum", "Dotum", DIA_FONT_FAMILY_ANY },
840 { "GBZenKai-Medium", "GBZenKai-Medium", DIA_FONT_FAMILY_ANY },
841 { "GothicBBB-Medium", "GothicBBB-Medium", DIA_FONT_FAMILY_ANY },
842 { "Gulim", "Gulim", DIA_FONT_FAMILY_ANY },
843 { "Headline", "Headline", DIA_FONT_FAMILY_ANY },
844 { "Helvetica", "sans", DIA_FONT_SANS },
845 { "Helvetica", "Arial", DIA_FONT_SANS },
846 { "Helvetica-Bold", "sans", DIA_FONT_SANS | DIA_FONT_BOLD },
847 { "Helvetica-Bold", "Arial", DIA_FONT_SANS | DIA_FONT_BOLD },
848 { "Helvetica-BoldOblique", "sans", DIA_FONT_SANS | DIA_FONT_BOLD | DIA_FONT_ITALIC },
849 { "Helvetica-BoldOblique", "Arial", DIA_FONT_SANS | DIA_FONT_BOLD | DIA_FONT_ITALIC },
850 { "Helvetica-Narrow", "Arial Narrow", DIA_FONT_SANS | DIA_FONT_MEDIUM },
851 { "Helvetica-Narrow-Bold", "Arial Narrow", DIA_FONT_SANS | DIA_FONT_DEMIBOLD },
852 { "Helvetica-Narrow-BoldOblique", "Arial Narrow", DIA_FONT_SANS | DIA_FONT_MEDIUM | DIA_FONT_OBLIQUE },
853 { "Helvetica-Narrow-Oblique", "Arial Narrow", DIA_FONT_SANS | DIA_FONT_MEDIUM | DIA_FONT_OBLIQUE },
854 { "Helvetica-Oblique", "sans", DIA_FONT_SANS | DIA_FONT_ITALIC },
855 { "Helvetica-Oblique", "Arial", DIA_FONT_SANS | DIA_FONT_ITALIC },
856 { "MOESung-Medium", "MOESung-Medium", DIA_FONT_FAMILY_ANY },
857 { "NewCenturySchoolbook-Bold", "Century Schoolbook SWA", DIA_FONT_SERIF | DIA_FONT_BOLD },
858 { "NewCenturySchoolbook-BoldItalic", "Century Schoolbook SWA", DIA_FONT_SERIF | DIA_FONT_BOLD | DIA_FONT_ITALIC },
859 { "NewCenturySchoolbook-Italic", "Century Schoolbook SWA", DIA_FONT_SERIF | DIA_FONT_ITALIC },
860 { "NewCenturySchoolbook-Roman", "Century Schoolbook SWA", DIA_FONT_SERIF },
861 { "Palatino-Bold", "Palatino", DIA_FONT_FAMILY_ANY | DIA_FONT_BOLD },
862 { "Palatino-BoldItalic", "Palatino", DIA_FONT_FAMILY_ANY | DIA_FONT_BOLD | DIA_FONT_ITALIC },
863 { "Palatino-Italic", "Palatino", DIA_FONT_FAMILY_ANY | DIA_FONT_ITALIC },
864 { "Palatino-Roman", "Palatino", DIA_FONT_FAMILY_ANY },
865 { "Ryumin-Light", "Ryumin", DIA_FONT_FAMILY_ANY | DIA_FONT_LIGHT },
866 { "ShanHeiSun-Light", "ShanHeiSun", DIA_FONT_FAMILY_ANY | DIA_FONT_LIGHT },
867 { "Song-Medium", "Song-Medium", DIA_FONT_FAMILY_ANY | DIA_FONT_MEDIUM },
868 { "Symbol", "Symbol", DIA_FONT_SANS | DIA_FONT_MEDIUM },
869 { "Times-Bold", "serif", DIA_FONT_SERIF | DIA_FONT_BOLD },
870 { "Times-Bold", "Times New Roman", DIA_FONT_SERIF | DIA_FONT_BOLD },
871 { "Times-BoldItalic", "serif", DIA_FONT_SERIF | DIA_FONT_ITALIC | DIA_FONT_BOLD },
872 { "Times-BoldItalic", "Times New Roman", DIA_FONT_SERIF | DIA_FONT_ITALIC | DIA_FONT_BOLD },
873 { "Times-Italic", "serif", DIA_FONT_SERIF | DIA_FONT_ITALIC },
874 { "Times-Italic", "Times New Roman", DIA_FONT_SERIF | DIA_FONT_ITALIC },
875 { "Times-Roman", "serif", DIA_FONT_SERIF },
876 { "Times-Roman", "Times New Roman", DIA_FONT_SERIF },
877 { "ZapfChancery-MediumItalic", "Zapf Calligraphic 801 SWA", DIA_FONT_SERIF | DIA_FONT_MEDIUM },
878 { "ZapfDingbats", "Zapf Calligraphic 801 SWA", DIA_FONT_SERIF },
879 { "ZenKai-Medium", "ZenKai", DIA_FONT_FAMILY_ANY | DIA_FONT_MEDIUM },
884 * Given a legacy name as stored until Dia-0.90 construct
885 * a new DiaFont which is as similar as possible
887 DiaFont*
888 dia_font_new_from_legacy_name(const char* name)
890 /* do NOT translate anything here !!! */
891 DiaFont* retval;
892 struct _legacy_font* found = NULL;
893 real height = 1.0;
894 int i;
896 for (i = 0; i < G_N_ELEMENTS(legacy_fonts); i++) {
897 if (!strcmp(name, legacy_fonts[i].oldname)) {
898 found = &legacy_fonts[i];
899 break;
902 if (found) {
903 retval = dia_font_new (found->newname, found->style, height);
904 retval->legacy_name = found->oldname;
905 } else {
906 /* We tried our best, let Pango complain */
907 retval = dia_font_new (name, DIA_FONT_WEIGHT_NORMAL, height);
908 retval->legacy_name = NULL;
911 return retval;
914 G_CONST_RETURN char*
915 dia_font_get_legacy_name(const DiaFont *font)
917 const char* matched_name = NULL;
918 const char* family;
919 DiaFontStyle style;
920 int i;
922 /* if we have loaded it from an old file, use the old name */
923 if (font->legacy_name)
924 return font->legacy_name;
926 family = dia_font_get_family (font);
927 style = dia_font_get_style (font);
928 for (i = 0; i < G_N_ELEMENTS(legacy_fonts); i++) {
929 if (0 == g_strcasecmp (legacy_fonts[i].newname, family)) {
930 /* match weight and slant */
931 DiaFontStyle st = legacy_fonts[i].style;
932 if ((DIA_FONT_STYLE_GET_SLANT(style) | DIA_FONT_STYLE_GET_WEIGHT(style))
933 == (DIA_FONT_STYLE_GET_SLANT(st) | DIA_FONT_STYLE_GET_WEIGHT(st))) {
934 return legacy_fonts[i].oldname; /* exact match */
935 } else if (0 == (DIA_FONT_STYLE_GET_SLANT(st) | DIA_FONT_STYLE_GET_WEIGHT(st))) {
936 matched_name = legacy_fonts[i].oldname;
937 /* 'unmodified' font, continue matching */
941 return matched_name ? matched_name : "Courier";