1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Style.c: Style resource management
6 * Miguel de Icaza (miguel@gnu.org)
7 * (C) 1998-2004 Miguel de Icaza
9 #include <gnumeric-config.h>
10 #include <glib/gi18n-lib.h>
13 #include "style-font.h"
15 #include "gnm-format.h"
16 #include "style-color.h"
17 #include "application.h"
24 #include "gnumeric-conf.h"
26 #include <pango/pangocairo.h>
30 #include <goffice/goffice.h>
32 #undef DEBUG_REF_COUNT
35 static GHashTable
*style_font_hash
;
36 static GHashTable
*style_font_negative_hash
;
38 double gnm_font_default_width
;
39 static char *gnumeric_default_font_name
;
40 static double gnumeric_default_font_size
;
42 /* This is very ad hoc - throw it away when something better comes along */
43 /* See also wine/dlls/winex11.drv/xfont.c */
45 static struct FontInfo
{
46 const char *font_name
;
47 const char *font_substitute_name
;
48 int override_codepage
;
50 { "Times New Roman", "Times", -1 },
51 { "Times New Roman CYR", "Times", 1251 },
52 { "Times New Roman Greek", "Times", 1253 },
53 { "Times New Roman Tur", "Times", 1254 },
54 { "Times New Roman Baltic", "Times", 1257 },
55 { "Tms Rmn", "Times", -1 },
56 { "Arial", "Sans", -1 },
57 { "Arial CYR", "Sans", 1251 },
58 { "Arial Greek", "Sans", 1253 },
59 { "Arial Tur", "Sans", 1254 },
60 { "Arial Baltic", "Sans", 1257 },
61 { "Albany", "Sans", -1 },
62 { "Helvetica", "Sans", -1 },
63 { "Courier New", "Courier", -1 },
64 { "Courier New CYR", "Courier", 1251 },
65 { "Courier New Greek", "Courier", 1253 },
66 { "Courier New Tur", "Courier", 1254 },
67 { "Courier New Baltic", "Courier", 1257 },
68 { "£Í£Ó £Ð¥´¥·¥Ã¥¯", "Kochi Gothic", -1 },
69 { "£Í£Ó ¥´¥·¥Ã¥¯", "Kochi Gothic", -1 },
70 { "¥´¥·¥Ã¥¯", "Kochi Gothic", -1 },
71 { "MS UI Gothic", "Kochi Gothic", -1 },
72 { "£Í£Ó £ÐÌÀÄ«", "Kochi Mincho", -1 },
73 { "£Í£Ó ÌÀÄ«", "Kochi Mincho", -1 },
74 { "ÌÀÄ«", "Kochi Mincho", -1 },
75 { "GulimChe", NULL
, 949 }
78 static struct FontInfo
*
79 find_font (const char *font_name
)
86 for (ui
= 0; ui
< G_N_ELEMENTS (font_info
); ui
++) {
87 if (!g_ascii_strcasecmp (font_info
[ui
].font_name
, font_name
))
88 return font_info
+ ui
;
94 * gnm_font_override_codepage:
95 * @font_name: The win32 font name
97 * Returns a codepage for the named Win32 font, or -1 if no such codepage
101 gnm_font_override_codepage (gchar
const *font_name
)
103 struct FontInfo
*fi
= find_font (font_name
);
104 return fi
? fi
->override_codepage
: -1;
109 * get_substitute_font:
110 * @font_name The font name
112 * Tries to find a gnome font which matches the Excel font.
113 * Returns the name of the substitute font if found. Otherwise returns NULL
116 get_substitute_font (gchar
const *font_name
)
118 struct FontInfo
*fi
= find_font (font_name
);
119 return fi
? fi
->font_substitute_name
: NULL
;
123 style_font_new_simple (PangoContext
*context
,
124 char const *font_name
, double size_pts
,
125 gboolean bold
, gboolean italic
)
130 if (font_name
== NULL
) {
131 g_warning ("font_name == NULL, using %s", DEFAULT_FONT
);
132 font_name
= DEFAULT_FONT
;
135 g_warning ("font_size <= 0, using %f", DEFAULT_SIZE
);
136 size_pts
= DEFAULT_SIZE
;
139 /* This cast does not mean we will change the name. */
140 key
.font_name
= (char *)font_name
;
141 key
.size_pts
= size_pts
;
143 key
.is_italic
= italic
;
144 key
.context
= context
;
146 font
= (GnmFont
*) g_hash_table_lookup (style_font_hash
, &key
);
148 PangoFontDescription
*desc
;
149 PangoFont
*pango_font
;
151 if (g_hash_table_lookup (style_font_negative_hash
, &key
))
154 font
= g_new0 (GnmFont
, 1);
155 font
->font_name
= g_strdup (font_name
);
156 font
->size_pts
= size_pts
;
157 font
->is_bold
= bold
;
158 font
->is_italic
= italic
;
159 font
->context
= g_object_ref (context
);
160 /* One reference for the cache, one for the caller. */
163 desc
= pango_font_description_new ();
165 pango_font_description_set_family (desc
, font_name
);
166 pango_font_description_set_weight (desc
,
167 bold
? PANGO_WEIGHT_BOLD
: PANGO_WEIGHT_NORMAL
);
168 pango_font_description_set_style (desc
,
169 italic
? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
);
170 pango_font_description_set_size (desc
, size_pts
* PANGO_SCALE
);
172 pango_font
= pango_context_load_font (context
, desc
);
173 if (pango_font
== NULL
) {
174 /* if we fail, try to be smart and map to something similar */
175 char const *sub
= get_substitute_font (font_name
);
177 pango_font_description_set_family (desc
, font_name
);
178 pango_font
= pango_context_load_font (context
,
182 if (pango_font
== NULL
) {
183 pango_font_description_free (desc
);
184 g_hash_table_insert (style_font_negative_hash
,
191 g_object_unref (pango_font
);
193 font
->go
.font
= go_font_new_by_desc (desc
);
194 font
->go
.metrics
= go_font_metrics_new (context
, font
->go
.font
);
195 g_hash_table_insert (style_font_hash
, font
, font
);
199 #ifdef DEBUG_REF_COUNT
200 g_message (__FUNCTION__
" font=%p name=%s%s%s ref_count=%d\n",
201 font
, font
->font_name
,
202 font
->is_bold
? " bold" : "",
203 font
->is_italic
? " italic" : "",
210 gnm_font_new (PangoContext
*context
,
211 char const *font_name
, double size_pts
,
212 gboolean bold
, gboolean italic
)
216 g_return_val_if_fail (font_name
!= NULL
, NULL
);
217 g_return_val_if_fail (size_pts
> 0, NULL
);
219 font
= style_font_new_simple (context
, font_name
, size_pts
,
221 if (font
) return font
;
223 font_name
= gnumeric_default_font_name
;
224 font
= style_font_new_simple (context
, font_name
, size_pts
,
226 if (font
) return font
;
228 size_pts
= gnumeric_default_font_size
;
229 font
= style_font_new_simple (context
, font_name
, size_pts
,
231 if (font
) return font
;
234 font
= style_font_new_simple (context
, font_name
, size_pts
,
236 if (font
) return font
;
239 font
= style_font_new_simple (context
, font_name
, size_pts
,
241 if (font
) return font
;
244 * This should not be possible to reach as we have reverted all the way
245 * back to the default font.
247 g_assert_not_reached ();
252 gnm_font_ref (GnmFont
*sf
)
254 g_return_val_if_fail (sf
!= NULL
, NULL
);
257 #ifdef DEBUG_REF_COUNT
258 g_message (__FUNCTION__
" font=%p name=%s%s%s ref_count=%d\n",
260 sf
->is_bold
? " bold" : "",
261 sf
->is_italic
? " italic" : "",
269 gnm_font_unref (GnmFont
*sf
)
271 g_return_if_fail (sf
!= NULL
);
272 g_return_if_fail (sf
->ref_count
> 0);
275 #ifdef DEBUG_REF_COUNT
276 g_message (__FUNCTION__
" font=%p name=%s%s%s ref_count=%d\n",
278 sf
->is_bold
? " bold" : "",
279 sf
->is_italic
? " italic" : "",
282 if (sf
->ref_count
!= 0)
285 g_hash_table_remove (style_font_hash
, sf
);
286 /* hash-changing operations after above line. */
289 go_font_unref (sf
->go
.font
);
293 if (sf
->go
.metrics
) {
294 go_font_metrics_free (sf
->go
.metrics
);
295 sf
->go
.metrics
= NULL
;
298 g_object_unref (sf
->context
);
301 g_free (sf
->font_name
);
302 sf
->font_name
= NULL
;
308 gnm_font_get_type (void)
313 t
= g_boxed_type_register_static ("GnmFont",
314 (GBoxedCopyFunc
)gnm_font_ref
,
315 (GBoxedFreeFunc
)gnm_font_unref
);
321 gnm_font_equal (gconstpointer v
, gconstpointer v2
)
323 GnmFont
const *k1
= (GnmFont
const *) v
;
324 GnmFont
const *k2
= (GnmFont
const *) v2
;
326 return (k1
->size_pts
== k2
->size_pts
&&
327 k1
->is_bold
== k2
->is_bold
&&
328 k1
->is_italic
== k2
->is_italic
&&
329 k1
->context
== k2
->context
&&
330 strcmp (k1
->font_name
, k2
->font_name
) == 0);
334 gnm_font_hash (gconstpointer v
)
336 GnmFont
const *k
= (GnmFont
const *) v
;
337 return (guint
)k
->size_pts
^
338 g_str_hash (k
->font_name
) ^
339 (k
->is_bold
? 0x33333333 : 0) ^
340 (k
->is_italic
? 0xcccccccc : 0) ^
341 GPOINTER_TO_UINT (k
->context
);
345 gnm_align_h_get_type (void)
347 static GType etype
= 0;
349 static GEnumValue
const values
[] = {
350 {GNM_HALIGN_GENERAL
, "GNM_HALIGN_GENERAL", "general"},
351 {GNM_HALIGN_LEFT
, "GNM_HALIGN_LEFT", "left"},
352 {GNM_HALIGN_RIGHT
, "GNM_HALIGN_RIGHT", "right"},
353 {GNM_HALIGN_CENTER
, "GNM_HALIGN_CENTER", "center"},
354 {GNM_HALIGN_FILL
, "GNM_HALIGN_FILL", "fill"},
355 {GNM_HALIGN_JUSTIFY
, "GNM_HALIGN_JUSTIFY", "justify"},
356 {GNM_HALIGN_CENTER_ACROSS_SELECTION
,
357 "GNM_HALIGN_CENTER_ACROSS_SELECTION",
359 {GNM_HALIGN_DISTRIBUTED
,
360 "GNM_HALIGN_DISTRIBUTED", "distributed"},
363 etype
= g_enum_register_static ("GnmHAlign",
370 gnm_align_v_get_type (void)
372 static GType etype
= 0;
374 static GEnumValue
const values
[] = {
375 {GNM_VALIGN_TOP
, "GNM_VALIGN_TOP", "top"},
376 {GNM_VALIGN_BOTTOM
, "GNM_VALIGN_BOTTOM", "bottom"},
377 {GNM_VALIGN_CENTER
, "GNM_VALIGN_CENTER", "center"},
378 {GNM_VALIGN_JUSTIFY
, "GNM_VALIGN_JUSTIFY", "justify"},
379 {GNM_VALIGN_DISTRIBUTED
,
380 "GNM_VALIGN_DISTRIBUTED", "distributed"},
383 etype
= g_enum_register_static ("GnmVAlign",
391 static PangoFontMap
*fontmap
;
392 static PangoContext
*context
;
395 * gnm_pango_context_get:
397 * Simple wrapper to handle windowless operation
398 * Returns: (transfer full):
401 gnm_pango_context_get (void)
404 GdkScreen
*screen
= gdk_screen_get_default ();
406 if (screen
!= NULL
) {
407 context
= gdk_pango_context_get_for_screen (screen
);
410 fontmap
= pango_cairo_font_map_new ();
411 pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap
), 96);
412 context
= pango_font_map_create_context (PANGO_FONT_MAP (fontmap
));
414 pango_context_set_language (context
, gtk_get_default_language ());
415 pango_context_set_base_dir (context
, PANGO_DIRECTION_LTR
);
418 return g_object_ref (context
);
422 * gnm_font_init: (skip)
427 PangoContext
*context
;
428 GnmFont
*gnumeric_default_font
= NULL
;
429 double pts_scale
= 72. / gnm_app_display_dpi_get (TRUE
);
431 style_font_hash
= g_hash_table_new (
432 gnm_font_hash
, gnm_font_equal
);
433 style_font_negative_hash
= g_hash_table_new (
434 gnm_font_hash
, gnm_font_equal
);
436 gnumeric_default_font_name
= g_strdup (gnm_conf_get_core_defaultfont_name ());
437 gnumeric_default_font_size
= gnm_conf_get_core_defaultfont_size ();
439 context
= gnm_pango_context_get ();
440 if (gnumeric_default_font_name
&& gnumeric_default_font_size
>= 1)
441 gnumeric_default_font
= style_font_new_simple (context
,
442 gnumeric_default_font_name
, gnumeric_default_font_size
,
444 if (gnumeric_default_font
== NULL
) {
445 g_warning ("Configured default font '%s %f' not available, trying fallback...",
446 gnumeric_default_font_name
, gnumeric_default_font_size
);
447 gnumeric_default_font
= style_font_new_simple (context
,
448 DEFAULT_FONT
, DEFAULT_SIZE
, FALSE
, FALSE
);
449 if (gnumeric_default_font
!= NULL
) {
450 g_free (gnumeric_default_font_name
);
451 gnumeric_default_font_name
= g_strdup (DEFAULT_FONT
);
452 gnumeric_default_font_size
= DEFAULT_SIZE
;
454 g_warning ("Fallback font '%s %f' not available, trying 'fixed'...",
455 DEFAULT_FONT
, DEFAULT_SIZE
);
456 gnumeric_default_font
= style_font_new_simple (context
,
457 "fixed", 10, FALSE
, FALSE
);
458 if (gnumeric_default_font
!= NULL
) {
459 g_free (gnumeric_default_font_name
);
460 gnumeric_default_font_name
= g_strdup ("fixed");
461 gnumeric_default_font_size
= 10;
463 g_warning ("Even 'fixed 10' failed ?? We're going to exit now,"
464 "there is something wrong with your font configuration");
470 gnm_font_default_width
= pts_scale
*
471 PANGO_PIXELS (gnumeric_default_font
->go
.metrics
->avg_digit_width
);
472 gnm_font_unref (gnumeric_default_font
);
473 g_object_unref (context
);
477 delete_neg_font (GnmFont
*sf
, G_GNUC_UNUSED gpointer value
,
478 G_GNUC_UNUSED gpointer user_data
)
480 g_object_unref (sf
->context
);
481 g_free (sf
->font_name
);
486 list_cached_fonts (GnmFont
*font
, G_GNUC_UNUSED gpointer value
, GSList
**lp
)
488 *lp
= g_slist_prepend (*lp
, font
);
492 * gnm_font_shutdown: (skip)
494 * Release all resources allocated by gnm_font_init.
497 gnm_font_shutdown (void)
499 GSList
*fonts
= NULL
, *tmp
;
501 g_free (gnumeric_default_font_name
);
502 gnumeric_default_font_name
= NULL
;
504 /* Make a list of the fonts, then unref them. */
505 g_hash_table_foreach (style_font_hash
, (GHFunc
) list_cached_fonts
, &fonts
);
506 for (tmp
= fonts
; tmp
; tmp
= tmp
->next
) {
507 GnmFont
*sf
= tmp
->data
;
508 if (sf
->ref_count
!= 1)
509 g_warning ("Font %s has %d references instead of the expected single.",
510 sf
->font_name
, sf
->ref_count
);
513 g_slist_free (fonts
);
515 g_hash_table_destroy (style_font_hash
);
516 style_font_hash
= NULL
;
518 g_hash_table_foreach (style_font_negative_hash
, (GHFunc
) delete_neg_font
, NULL
);
519 g_hash_table_destroy (style_font_negative_hash
);
520 style_font_negative_hash
= NULL
;
523 g_object_unref (context
);
528 /* Do this late -- see bugs 558100 and 558254. */
529 /* and not at all on win32, where the life cycle is different */
531 g_object_unref (fontmap
);
539 * gnm_style_required_spanflags:
542 * What changes are required after applying the supplied style.
545 gnm_style_required_spanflags (GnmStyle
const *style
)
547 GnmSpanCalcFlags res
= GNM_SPANCALC_SIMPLE
;
549 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
))
550 /* Note that style->cond_styles may not be set yet */
551 /* More importantly, even if the conditions are empty we */
552 /* have to rerender everything since we do not know what changed. */
553 res
|= GNM_SPANCALC_RE_RENDER
| GNM_SPANCALC_RESIZE
| GNM_SPANCALC_ROW_HEIGHT
;
555 gboolean
const row_height
=
556 gnm_style_is_element_set (style
, MSTYLE_FONT_SIZE
) ||
557 gnm_style_is_element_set (style
, MSTYLE_WRAP_TEXT
) ||
558 gnm_style_is_element_set (style
, MSTYLE_ROTATION
) ||
559 gnm_style_is_element_set (style
, MSTYLE_FONT_SCRIPT
);
560 gboolean
const size_change
= row_height
||
561 gnm_style_is_element_set (style
, MSTYLE_FONT_NAME
) ||
562 gnm_style_is_element_set (style
, MSTYLE_FONT_BOLD
) ||
563 gnm_style_is_element_set (style
, MSTYLE_FONT_ITALIC
);
564 gboolean
const format_change
=
565 gnm_style_is_element_set (style
, MSTYLE_FORMAT
) ||
566 gnm_style_is_element_set (style
, MSTYLE_INDENT
) ||
567 gnm_style_is_element_set (style
, MSTYLE_ALIGN_H
) ||
568 gnm_style_is_element_set (style
, MSTYLE_ALIGN_V
) ||
569 gnm_style_is_element_set (style
, MSTYLE_FONT_STRIKETHROUGH
) ||
570 gnm_style_is_element_set (style
, MSTYLE_FONT_UNDERLINE
) ||
571 gnm_style_is_element_set (style
, MSTYLE_FONT_COLOR
);
574 res
|= GNM_SPANCALC_ROW_HEIGHT
;
575 if (format_change
|| size_change
)
576 res
|= GNM_SPANCALC_RE_RENDER
| GNM_SPANCALC_RESIZE
;
582 * gnm_style_default_halign:
586 * Select the appropriate horizontal alignment depending on the style and cell
590 gnm_style_default_halign (GnmStyle
const *style
, GnmCell
const *c
)
592 GnmHAlign align
= gnm_style_get_align_h (style
);
595 if (align
!= GNM_HALIGN_GENERAL
)
597 g_return_val_if_fail (c
!= NULL
, GNM_HALIGN_RIGHT
);
599 if (c
->base
.sheet
&& c
->base
.sheet
->display_formulas
&&
600 gnm_cell_has_expr (c
))
601 return GNM_HALIGN_LEFT
;
603 for (v
= c
->value
; v
!= NULL
; )
604 switch (v
->v_any
.type
) {
607 return GNM_HALIGN_CENTER
;
610 double a
= gnm_style_get_rotation (style
);
611 if (a
> 0 && a
< 180)
612 return GNM_HALIGN_LEFT
;
613 return GNM_HALIGN_RIGHT
;
617 /* Tail recurse into the array */
618 if (v
->v_array
.x
> 0 && v
->v_array
.y
> 0) {
619 v
= v
->v_array
.vals
[0][0];
624 if (gnm_style_get_rotation (style
) > 180)
625 return GNM_HALIGN_RIGHT
;
626 return GNM_HALIGN_LEFT
;
628 return GNM_HALIGN_RIGHT
;
632 gnm_translate_underline_to_pango (GnmUnderline ul
)
634 g_return_val_if_fail (ul
>= UNDERLINE_NONE
, PANGO_UNDERLINE_NONE
);
635 g_return_val_if_fail (ul
<= UNDERLINE_DOUBLE_LOW
, PANGO_UNDERLINE_NONE
);
638 case UNDERLINE_SINGLE
:
639 return PANGO_UNDERLINE_SINGLE
;
640 case UNDERLINE_DOUBLE
:
641 case UNDERLINE_DOUBLE_LOW
:
642 return PANGO_UNDERLINE_DOUBLE
;
643 case UNDERLINE_SINGLE_LOW
:
644 return PANGO_UNDERLINE_LOW
;
647 return PANGO_UNDERLINE_NONE
;
652 gnm_translate_underline_from_pango (PangoUnderline pul
)
654 g_return_val_if_fail (pul
>= PANGO_UNDERLINE_NONE
, UNDERLINE_NONE
);
655 g_return_val_if_fail (pul
<= PANGO_UNDERLINE_ERROR
, UNDERLINE_NONE
);
658 case PANGO_UNDERLINE_SINGLE
:
659 return UNDERLINE_SINGLE
;
660 case PANGO_UNDERLINE_DOUBLE
:
661 return UNDERLINE_DOUBLE
;
662 case PANGO_UNDERLINE_LOW
:
663 return UNDERLINE_SINGLE_LOW
;
664 case PANGO_UNDERLINE_ERROR
:
666 case PANGO_UNDERLINE_NONE
:
668 return UNDERLINE_NONE
;