2 * Style.c: Style resource management
5 * Miguel de Icaza (miguel@gnu.org)
6 * (C) 1998-2004 Miguel de Icaza
8 #include <gnumeric-config.h>
9 #include <glib/gi18n-lib.h>
12 #include <style-font.h>
14 #include <gnm-format.h>
15 #include <style-color.h>
16 #include <application.h>
23 #include <gnumeric-conf.h>
25 #include <pango/pangocairo.h>
28 #include <goffice/goffice.h>
30 #undef DEBUG_REF_COUNT
33 static GHashTable
*style_font_hash
;
34 static GHashTable
*style_font_negative_hash
;
36 double gnm_font_default_width
;
37 static char *gnumeric_default_font_name
;
38 static double gnumeric_default_font_size
;
40 /* This is very ad hoc - throw it away when something better comes along */
41 /* See also wine/dlls/winex11.drv/xfont.c */
43 static struct FontInfo
{
44 const char *font_name
;
45 const char *font_substitute_name
;
46 int override_codepage
;
48 { "Times New Roman", "Times", -1 },
49 { "Times New Roman CYR", "Times", 1251 },
50 { "Times New Roman Greek", "Times", 1253 },
51 { "Times New Roman Tur", "Times", 1254 },
52 { "Times New Roman Baltic", "Times", 1257 },
53 { "Tms Rmn", "Times", -1 },
54 { "Arial", "Sans", -1 },
55 { "Arial CYR", "Sans", 1251 },
56 { "Arial Greek", "Sans", 1253 },
57 { "Arial Tur", "Sans", 1254 },
58 { "Arial Baltic", "Sans", 1257 },
59 { "Albany", "Sans", -1 },
60 { "Helvetica", "Sans", -1 },
61 { "Courier New", "Courier", -1 },
62 { "Courier New CYR", "Courier", 1251 },
63 { "Courier New Greek", "Courier", 1253 },
64 { "Courier New Tur", "Courier", 1254 },
65 { "Courier New Baltic", "Courier", 1257 },
66 { "£Í£Ó £Ð¥´¥·¥Ã¥¯", "Kochi Gothic", -1 },
67 { "£Í£Ó ¥´¥·¥Ã¥¯", "Kochi Gothic", -1 },
68 { "¥´¥·¥Ã¥¯", "Kochi Gothic", -1 },
69 { "MS UI Gothic", "Kochi Gothic", -1 },
70 { "£Í£Ó £ÐÌÀÄ«", "Kochi Mincho", -1 },
71 { "£Í£Ó ÌÀÄ«", "Kochi Mincho", -1 },
72 { "ÌÀÄ«", "Kochi Mincho", -1 },
73 { "GulimChe", NULL
, 949 }
76 static struct FontInfo
*
77 find_font (const char *font_name
)
84 for (ui
= 0; ui
< G_N_ELEMENTS (font_info
); ui
++) {
85 if (!g_ascii_strcasecmp (font_info
[ui
].font_name
, font_name
))
86 return font_info
+ ui
;
92 * gnm_font_override_codepage:
93 * @font_name: The win32 font name
95 * Returns a codepage for the named Win32 font, or -1 if no such codepage
99 gnm_font_override_codepage (gchar
const *font_name
)
101 struct FontInfo
*fi
= find_font (font_name
);
102 return fi
? fi
->override_codepage
: -1;
107 * get_substitute_font:
108 * @font_name The font name
110 * Tries to find a gnome font which matches the Excel font.
111 * Returns the name of the substitute font if found. Otherwise returns NULL
114 get_substitute_font (gchar
const *font_name
)
116 struct FontInfo
*fi
= find_font (font_name
);
117 return fi
? fi
->font_substitute_name
: NULL
;
121 style_font_new_simple (PangoContext
*context
,
122 char const *font_name
, double size_pts
,
123 gboolean bold
, gboolean italic
)
128 if (font_name
== NULL
) {
129 g_warning ("font_name == NULL, using %s", DEFAULT_FONT
);
130 font_name
= DEFAULT_FONT
;
133 g_warning ("font_size <= 0, using %f", DEFAULT_SIZE
);
134 size_pts
= DEFAULT_SIZE
;
137 /* This cast does not mean we will change the name. */
138 key
.font_name
= (char *)font_name
;
139 key
.size_pts
= size_pts
;
141 key
.is_italic
= italic
;
142 key
.context
= context
;
144 font
= (GnmFont
*) g_hash_table_lookup (style_font_hash
, &key
);
146 PangoFontDescription
*desc
;
147 PangoFont
*pango_font
;
149 if (g_hash_table_lookup (style_font_negative_hash
, &key
))
152 font
= g_new0 (GnmFont
, 1);
153 font
->font_name
= g_strdup (font_name
);
154 font
->size_pts
= size_pts
;
155 font
->is_bold
= bold
;
156 font
->is_italic
= italic
;
157 font
->context
= g_object_ref (context
);
158 /* One reference for the cache, one for the caller. */
161 desc
= pango_font_description_new ();
163 pango_font_description_set_family (desc
, font_name
);
164 pango_font_description_set_weight (desc
,
165 bold
? PANGO_WEIGHT_BOLD
: PANGO_WEIGHT_NORMAL
);
166 pango_font_description_set_style (desc
,
167 italic
? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
);
168 pango_font_description_set_size (desc
, size_pts
* PANGO_SCALE
);
170 pango_font
= pango_context_load_font (context
, desc
);
171 if (pango_font
== NULL
) {
172 /* if we fail, try to be smart and map to something similar */
173 char const *sub
= get_substitute_font (font_name
);
175 pango_font_description_set_family (desc
, font_name
);
176 pango_font
= pango_context_load_font (context
,
180 if (pango_font
== NULL
) {
181 pango_font_description_free (desc
);
182 g_hash_table_insert (style_font_negative_hash
,
189 g_object_unref (pango_font
);
191 font
->go
.font
= go_font_new_by_desc (desc
);
192 font
->go
.metrics
= go_font_metrics_new (context
, font
->go
.font
);
193 g_hash_table_insert (style_font_hash
, font
, font
);
197 #ifdef DEBUG_REF_COUNT
198 g_message (__FUNCTION__
" font=%p name=%s%s%s ref_count=%d\n",
199 font
, font
->font_name
,
200 font
->is_bold
? " bold" : "",
201 font
->is_italic
? " italic" : "",
208 gnm_font_new (PangoContext
*context
,
209 char const *font_name
, double size_pts
,
210 gboolean bold
, gboolean italic
)
214 g_return_val_if_fail (font_name
!= NULL
, NULL
);
215 g_return_val_if_fail (size_pts
> 0, NULL
);
217 font
= style_font_new_simple (context
, font_name
, size_pts
,
219 if (font
) return font
;
221 font_name
= gnumeric_default_font_name
;
222 font
= style_font_new_simple (context
, font_name
, size_pts
,
224 if (font
) return font
;
226 size_pts
= gnumeric_default_font_size
;
227 font
= style_font_new_simple (context
, font_name
, size_pts
,
229 if (font
) return font
;
232 font
= style_font_new_simple (context
, font_name
, size_pts
,
234 if (font
) return font
;
237 font
= style_font_new_simple (context
, font_name
, size_pts
,
239 if (font
) return font
;
242 * This should not be possible to reach as we have reverted all the way
243 * back to the default font.
245 g_assert_not_reached ();
250 gnm_font_ref (GnmFont
*sf
)
252 g_return_val_if_fail (sf
!= NULL
, NULL
);
255 #ifdef DEBUG_REF_COUNT
256 g_message (__FUNCTION__
" font=%p name=%s%s%s ref_count=%d\n",
258 sf
->is_bold
? " bold" : "",
259 sf
->is_italic
? " italic" : "",
267 gnm_font_unref (GnmFont
*sf
)
269 g_return_if_fail (sf
!= NULL
);
270 g_return_if_fail (sf
->ref_count
> 0);
273 #ifdef DEBUG_REF_COUNT
274 g_message (__FUNCTION__
" font=%p name=%s%s%s ref_count=%d\n",
276 sf
->is_bold
? " bold" : "",
277 sf
->is_italic
? " italic" : "",
280 if (sf
->ref_count
!= 0)
283 g_hash_table_remove (style_font_hash
, sf
);
284 /* hash-changing operations after above line. */
287 go_font_unref (sf
->go
.font
);
291 if (sf
->go
.metrics
) {
292 go_font_metrics_free (sf
->go
.metrics
);
293 sf
->go
.metrics
= NULL
;
296 g_object_unref (sf
->context
);
299 g_free (sf
->font_name
);
300 sf
->font_name
= NULL
;
306 gnm_font_get_type (void)
311 t
= g_boxed_type_register_static ("GnmFont",
312 (GBoxedCopyFunc
)gnm_font_ref
,
313 (GBoxedFreeFunc
)gnm_font_unref
);
319 gnm_font_equal (gconstpointer v
, gconstpointer v2
)
321 GnmFont
const *k1
= (GnmFont
const *) v
;
322 GnmFont
const *k2
= (GnmFont
const *) v2
;
324 return (k1
->size_pts
== k2
->size_pts
&&
325 k1
->is_bold
== k2
->is_bold
&&
326 k1
->is_italic
== k2
->is_italic
&&
327 k1
->context
== k2
->context
&&
328 strcmp (k1
->font_name
, k2
->font_name
) == 0);
332 gnm_font_hash (gconstpointer v
)
334 GnmFont
const *k
= (GnmFont
const *) v
;
335 return (guint
)k
->size_pts
^
336 g_str_hash (k
->font_name
) ^
337 (k
->is_bold
? 0x33333333 : 0) ^
338 (k
->is_italic
? 0xcccccccc : 0) ^
339 GPOINTER_TO_UINT (k
->context
);
343 gnm_align_h_get_type (void)
345 static GType etype
= 0;
347 static GEnumValue
const values
[] = {
348 {GNM_HALIGN_GENERAL
, "GNM_HALIGN_GENERAL", "general"},
349 {GNM_HALIGN_LEFT
, "GNM_HALIGN_LEFT", "left"},
350 {GNM_HALIGN_RIGHT
, "GNM_HALIGN_RIGHT", "right"},
351 {GNM_HALIGN_CENTER
, "GNM_HALIGN_CENTER", "center"},
352 {GNM_HALIGN_FILL
, "GNM_HALIGN_FILL", "fill"},
353 {GNM_HALIGN_JUSTIFY
, "GNM_HALIGN_JUSTIFY", "justify"},
354 {GNM_HALIGN_CENTER_ACROSS_SELECTION
,
355 "GNM_HALIGN_CENTER_ACROSS_SELECTION",
357 {GNM_HALIGN_DISTRIBUTED
,
358 "GNM_HALIGN_DISTRIBUTED", "distributed"},
361 etype
= g_enum_register_static ("GnmHAlign",
368 gnm_align_v_get_type (void)
370 static GType etype
= 0;
372 static GEnumValue
const values
[] = {
373 {GNM_VALIGN_TOP
, "GNM_VALIGN_TOP", "top"},
374 {GNM_VALIGN_BOTTOM
, "GNM_VALIGN_BOTTOM", "bottom"},
375 {GNM_VALIGN_CENTER
, "GNM_VALIGN_CENTER", "center"},
376 {GNM_VALIGN_JUSTIFY
, "GNM_VALIGN_JUSTIFY", "justify"},
377 {GNM_VALIGN_DISTRIBUTED
,
378 "GNM_VALIGN_DISTRIBUTED", "distributed"},
381 etype
= g_enum_register_static ("GnmVAlign",
389 static PangoFontMap
*fontmap
;
390 static PangoContext
*context
;
393 * gnm_pango_context_get:
395 * Simple wrapper to handle windowless operation
396 * Returns: (transfer full):
399 gnm_pango_context_get (void)
402 GdkScreen
*screen
= gdk_screen_get_default ();
404 if (screen
!= NULL
) {
405 context
= gdk_pango_context_get_for_screen (screen
);
408 fontmap
= pango_cairo_font_map_new ();
409 pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap
), 96);
410 context
= pango_font_map_create_context (PANGO_FONT_MAP (fontmap
));
412 pango_context_set_language (context
, gtk_get_default_language ());
413 pango_context_set_base_dir (context
, PANGO_DIRECTION_LTR
);
416 return g_object_ref (context
);
420 * gnm_font_init: (skip)
425 PangoContext
*context
;
426 GnmFont
*gnumeric_default_font
= NULL
;
427 double pts_scale
= 72. / gnm_app_display_dpi_get (TRUE
);
429 style_font_hash
= g_hash_table_new (
430 gnm_font_hash
, gnm_font_equal
);
431 style_font_negative_hash
= g_hash_table_new (
432 gnm_font_hash
, gnm_font_equal
);
434 gnumeric_default_font_name
= g_strdup (gnm_conf_get_core_defaultfont_name ());
435 gnumeric_default_font_size
= gnm_conf_get_core_defaultfont_size ();
437 context
= gnm_pango_context_get ();
438 if (gnumeric_default_font_name
&& gnumeric_default_font_size
>= 1)
439 gnumeric_default_font
= style_font_new_simple (context
,
440 gnumeric_default_font_name
, gnumeric_default_font_size
,
442 if (gnumeric_default_font
== NULL
) {
443 g_warning ("Configured default font '%s %f' not available, trying fallback...",
444 gnumeric_default_font_name
, gnumeric_default_font_size
);
445 gnumeric_default_font
= style_font_new_simple (context
,
446 DEFAULT_FONT
, DEFAULT_SIZE
, FALSE
, FALSE
);
447 if (gnumeric_default_font
!= NULL
) {
448 g_free (gnumeric_default_font_name
);
449 gnumeric_default_font_name
= g_strdup (DEFAULT_FONT
);
450 gnumeric_default_font_size
= DEFAULT_SIZE
;
452 g_warning ("Fallback font '%s %f' not available, trying 'fixed'...",
453 DEFAULT_FONT
, DEFAULT_SIZE
);
454 gnumeric_default_font
= style_font_new_simple (context
,
455 "fixed", 10, FALSE
, FALSE
);
456 if (gnumeric_default_font
!= NULL
) {
457 g_free (gnumeric_default_font_name
);
458 gnumeric_default_font_name
= g_strdup ("fixed");
459 gnumeric_default_font_size
= 10;
461 g_warning ("Even 'fixed 10' failed ?? We're going to exit now,"
462 "there is something wrong with your font configuration");
468 gnm_font_default_width
= pts_scale
*
469 PANGO_PIXELS (gnumeric_default_font
->go
.metrics
->avg_digit_width
);
470 gnm_font_unref (gnumeric_default_font
);
471 g_object_unref (context
);
475 delete_neg_font (GnmFont
*sf
, G_GNUC_UNUSED gpointer value
,
476 G_GNUC_UNUSED gpointer user_data
)
478 g_object_unref (sf
->context
);
479 g_free (sf
->font_name
);
484 list_cached_fonts (GnmFont
*font
, G_GNUC_UNUSED gpointer value
, GSList
**lp
)
486 *lp
= g_slist_prepend (*lp
, font
);
490 * gnm_font_shutdown: (skip)
492 * Release all resources allocated by gnm_font_init.
495 gnm_font_shutdown (void)
497 GSList
*fonts
= NULL
, *tmp
;
499 g_free (gnumeric_default_font_name
);
500 gnumeric_default_font_name
= NULL
;
502 /* Make a list of the fonts, then unref them. */
503 g_hash_table_foreach (style_font_hash
, (GHFunc
) list_cached_fonts
, &fonts
);
504 for (tmp
= fonts
; tmp
; tmp
= tmp
->next
) {
505 GnmFont
*sf
= tmp
->data
;
506 if (sf
->ref_count
!= 1)
507 g_warning ("Font %s has %d references instead of the expected single.",
508 sf
->font_name
, sf
->ref_count
);
511 g_slist_free (fonts
);
513 g_hash_table_destroy (style_font_hash
);
514 style_font_hash
= NULL
;
516 g_hash_table_foreach (style_font_negative_hash
, (GHFunc
) delete_neg_font
, NULL
);
517 g_hash_table_destroy (style_font_negative_hash
);
518 style_font_negative_hash
= NULL
;
521 g_object_unref (context
);
526 /* Do this late -- see bugs 558100 and 558254. */
527 /* and not at all on win32, where the life cycle is different */
529 g_object_unref (fontmap
);
537 * gnm_style_required_spanflags:
540 * What changes are required after applying the supplied style.
543 gnm_style_required_spanflags (GnmStyle
const *style
)
545 GnmSpanCalcFlags res
= GNM_SPANCALC_SIMPLE
;
547 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
))
548 /* Note that style->cond_styles may not be set yet */
549 /* More importantly, even if the conditions are empty we */
550 /* have to rerender everything since we do not know what changed. */
551 res
|= GNM_SPANCALC_RE_RENDER
| GNM_SPANCALC_RESIZE
| GNM_SPANCALC_ROW_HEIGHT
;
553 gboolean
const row_height
=
554 gnm_style_is_element_set (style
, MSTYLE_FONT_SIZE
) ||
555 gnm_style_is_element_set (style
, MSTYLE_WRAP_TEXT
) ||
556 gnm_style_is_element_set (style
, MSTYLE_ROTATION
) ||
557 gnm_style_is_element_set (style
, MSTYLE_FONT_SCRIPT
);
558 gboolean
const size_change
= row_height
||
559 gnm_style_is_element_set (style
, MSTYLE_FONT_NAME
) ||
560 gnm_style_is_element_set (style
, MSTYLE_FONT_BOLD
) ||
561 gnm_style_is_element_set (style
, MSTYLE_FONT_ITALIC
);
562 gboolean
const format_change
=
563 gnm_style_is_element_set (style
, MSTYLE_FORMAT
) ||
564 gnm_style_is_element_set (style
, MSTYLE_INDENT
) ||
565 gnm_style_is_element_set (style
, MSTYLE_ALIGN_H
) ||
566 gnm_style_is_element_set (style
, MSTYLE_ALIGN_V
) ||
567 gnm_style_is_element_set (style
, MSTYLE_FONT_STRIKETHROUGH
) ||
568 gnm_style_is_element_set (style
, MSTYLE_FONT_UNDERLINE
) ||
569 gnm_style_is_element_set (style
, MSTYLE_FONT_COLOR
);
572 res
|= GNM_SPANCALC_ROW_HEIGHT
;
573 if (format_change
|| size_change
)
574 res
|= GNM_SPANCALC_RE_RENDER
| GNM_SPANCALC_RESIZE
;
580 * gnm_style_default_halign:
584 * Select the appropriate horizontal alignment depending on the style and cell
588 gnm_style_default_halign (GnmStyle
const *style
, GnmCell
const *c
)
590 GnmHAlign align
= gnm_style_get_align_h (style
);
593 if (align
!= GNM_HALIGN_GENERAL
)
595 g_return_val_if_fail (c
!= NULL
, GNM_HALIGN_RIGHT
);
597 if (c
->base
.sheet
&& c
->base
.sheet
->display_formulas
&&
598 gnm_cell_has_expr (c
))
599 return GNM_HALIGN_LEFT
;
601 for (v
= c
->value
; v
!= NULL
; )
602 switch (v
->v_any
.type
) {
605 return GNM_HALIGN_CENTER
;
608 double a
= gnm_style_get_rotation (style
);
609 if (a
> 0 && a
< 180)
610 return GNM_HALIGN_LEFT
;
611 return GNM_HALIGN_RIGHT
;
615 /* Tail recurse into the array */
616 if (v
->v_array
.x
> 0 && v
->v_array
.y
> 0) {
617 v
= v
->v_array
.vals
[0][0];
622 if (gnm_style_get_rotation (style
) > 180)
623 return GNM_HALIGN_RIGHT
;
624 return GNM_HALIGN_LEFT
;
626 return GNM_HALIGN_RIGHT
;
630 gnm_translate_underline_to_pango (GnmUnderline ul
)
632 g_return_val_if_fail (ul
>= UNDERLINE_NONE
, PANGO_UNDERLINE_NONE
);
633 g_return_val_if_fail (ul
<= UNDERLINE_DOUBLE_LOW
, PANGO_UNDERLINE_NONE
);
636 case UNDERLINE_SINGLE
:
637 return PANGO_UNDERLINE_SINGLE
;
638 case UNDERLINE_DOUBLE
:
639 case UNDERLINE_DOUBLE_LOW
:
640 return PANGO_UNDERLINE_DOUBLE
;
641 case UNDERLINE_SINGLE_LOW
:
642 return PANGO_UNDERLINE_LOW
;
645 return PANGO_UNDERLINE_NONE
;
650 gnm_translate_underline_from_pango (PangoUnderline pul
)
652 g_return_val_if_fail (pul
>= PANGO_UNDERLINE_NONE
, UNDERLINE_NONE
);
653 g_return_val_if_fail (pul
<= PANGO_UNDERLINE_ERROR
, UNDERLINE_NONE
);
656 case PANGO_UNDERLINE_SINGLE
:
657 return UNDERLINE_SINGLE
;
658 case PANGO_UNDERLINE_DOUBLE
:
659 return UNDERLINE_DOUBLE
;
660 case PANGO_UNDERLINE_LOW
:
661 return UNDERLINE_SINGLE_LOW
;
662 case PANGO_UNDERLINE_ERROR
:
664 case PANGO_UNDERLINE_NONE
:
666 return UNDERLINE_NONE
;