Clipboard: check mime type before pasting image.
[gnumeric.git] / src / style.c
blob0ed777ffea5d2772a43374bad211407b538cb86a
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Style.c: Style resource management
5 * Author:
6 * Miguel de Icaza (miguel@gnu.org)
7 * (C) 1998-2004 Miguel de Icaza
8 */
9 #include <gnumeric-config.h>
10 #include <glib/gi18n-lib.h>
11 #include "gnumeric.h"
12 #include "style.h"
13 #include "style-font.h"
15 #include "gnm-format.h"
16 #include "style-color.h"
17 #include "application.h"
18 #include "sheet.h"
19 #include "cell.h"
20 #include "value.h"
22 #include "gui-util.h"
23 #include "mathfunc.h"
24 #include "gnumeric-conf.h"
26 #include <pango/pangocairo.h>
27 #include <gdk/gdk.h>
28 #include <gtk/gtk.h>
29 #include <string.h>
30 #include <goffice/goffice.h>
32 #undef DEBUG_REF_COUNT
33 #undef DEBUG_FONTS
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;
49 } font_info[] = {
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)
81 unsigned ui;
83 if (!font_name)
84 return NULL;
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;
90 return NULL;
93 /**
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
98 * is known.
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
115 static gchar const *
116 get_substitute_font (gchar const *font_name)
118 struct FontInfo *fi = find_font (font_name);
119 return fi ? fi->font_substitute_name : NULL;
122 static GnmFont *
123 style_font_new_simple (PangoContext *context,
124 char const *font_name, double size_pts,
125 gboolean bold, gboolean italic)
127 GnmFont *font;
128 GnmFont key;
130 if (font_name == NULL) {
131 g_warning ("font_name == NULL, using %s", DEFAULT_FONT);
132 font_name = DEFAULT_FONT;
134 if (size_pts <= 0) {
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;
142 key.is_bold = bold;
143 key.is_italic = italic;
144 key.context = context;
146 font = (GnmFont *) g_hash_table_lookup (style_font_hash, &key);
147 if (font == NULL) {
148 PangoFontDescription *desc;
149 PangoFont *pango_font;
151 if (g_hash_table_lookup (style_font_negative_hash, &key))
152 return NULL;
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. */
161 font->ref_count = 2;
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);
176 if (sub != NULL) {
177 pango_font_description_set_family (desc, font_name);
178 pango_font = pango_context_load_font (context,
179 desc);
182 if (pango_font == NULL) {
183 pango_font_description_free (desc);
184 g_hash_table_insert (style_font_negative_hash,
185 font, font);
186 return NULL;
190 if (pango_font)
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);
196 } else
197 font->ref_count++;
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" : "",
204 font->ref_count);
205 #endif
206 return font;
209 GnmFont *
210 gnm_font_new (PangoContext *context,
211 char const *font_name, double size_pts,
212 gboolean bold, gboolean italic)
214 GnmFont *font;
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,
220 bold, italic);
221 if (font) return font;
223 font_name = gnumeric_default_font_name;
224 font = style_font_new_simple (context, font_name, size_pts,
225 bold, italic);
226 if (font) return font;
228 size_pts = gnumeric_default_font_size;
229 font = style_font_new_simple (context, font_name, size_pts,
230 bold, italic);
231 if (font) return font;
233 bold = FALSE;
234 font = style_font_new_simple (context, font_name, size_pts,
235 bold, italic);
236 if (font) return font;
238 italic = FALSE;
239 font = style_font_new_simple (context, font_name, size_pts,
240 bold, italic);
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 ();
248 abort ();
251 GnmFont *
252 gnm_font_ref (GnmFont *sf)
254 g_return_val_if_fail (sf != NULL, NULL);
256 sf->ref_count++;
257 #ifdef DEBUG_REF_COUNT
258 g_message (__FUNCTION__ " font=%p name=%s%s%s ref_count=%d\n",
259 sf, sf->font_name,
260 sf->is_bold ? " bold" : "",
261 sf->is_italic ? " italic" : "",
262 sf->ref_count);
263 #endif
265 return sf;
268 void
269 gnm_font_unref (GnmFont *sf)
271 g_return_if_fail (sf != NULL);
272 g_return_if_fail (sf->ref_count > 0);
274 sf->ref_count--;
275 #ifdef DEBUG_REF_COUNT
276 g_message (__FUNCTION__ " font=%p name=%s%s%s ref_count=%d\n",
277 sf, sf->font_name,
278 sf->is_bold ? " bold" : "",
279 sf->is_italic ? " italic" : "",
280 sf->ref_count);
281 #endif
282 if (sf->ref_count != 0)
283 return;
285 g_hash_table_remove (style_font_hash, sf);
286 /* hash-changing operations after above line. */
288 if (sf->go.font) {
289 go_font_unref (sf->go.font);
290 sf->go.font = NULL;
293 if (sf->go.metrics) {
294 go_font_metrics_free (sf->go.metrics);
295 sf->go.metrics = NULL;
298 g_object_unref (sf->context);
299 sf->context = NULL;
301 g_free (sf->font_name);
302 sf->font_name = NULL;
304 g_free (sf);
307 GType
308 gnm_font_get_type (void)
310 static GType t = 0;
312 if (t == 0) {
313 t = g_boxed_type_register_static ("GnmFont",
314 (GBoxedCopyFunc)gnm_font_ref,
315 (GBoxedFreeFunc)gnm_font_unref);
317 return t;
320 gint
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);
333 guint
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);
344 GType
345 gnm_align_h_get_type (void)
347 static GType etype = 0;
348 if (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",
358 "across-selection"},
359 {GNM_HALIGN_DISTRIBUTED,
360 "GNM_HALIGN_DISTRIBUTED", "distributed"},
361 { 0, NULL, NULL }
363 etype = g_enum_register_static ("GnmHAlign",
364 values);
366 return etype;
369 GType
370 gnm_align_v_get_type (void)
372 static GType etype = 0;
373 if (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"},
381 { 0, NULL, NULL }
383 etype = g_enum_register_static ("GnmVAlign",
384 values);
386 return etype;
391 static PangoFontMap *fontmap;
392 static PangoContext *context;
395 * gnm_pango_context_get:
397 * Simple wrapper to handle windowless operation
398 * Returns: (transfer full):
400 PangoContext *
401 gnm_pango_context_get (void)
403 if (!context) {
404 GdkScreen *screen = gdk_screen_get_default ();
406 if (screen != NULL) {
407 context = gdk_pango_context_get_for_screen (screen);
408 } else {
409 if (!fontmap)
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)
424 void
425 gnm_font_init (void)
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,
443 FALSE, FALSE);
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;
453 } else {
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;
462 } else {
463 g_warning ("Even 'fixed 10' failed ?? We're going to exit now,"
464 "there is something wrong with your font configuration");
465 exit (1);
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);
476 static void
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);
482 g_free (sf);
485 static void
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.
496 void
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);
511 gnm_font_unref (sf);
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;
522 if (context) {
523 g_object_unref (context);
524 context = NULL;
527 if (fontmap) {
528 /* Do this late -- see bugs 558100 and 558254. */
529 /* and not at all on win32, where the life cycle is different */
530 #ifndef G_OS_WIN32
531 g_object_unref (fontmap);
532 #endif
533 fontmap = NULL;
539 * gnm_style_required_spanflags:
540 * @style: the style
542 * What changes are required after applying the supplied style.
544 GnmSpanCalcFlags
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;
554 else {
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);
573 if (row_height)
574 res |= GNM_SPANCALC_ROW_HEIGHT;
575 if (format_change || size_change)
576 res |= GNM_SPANCALC_RE_RENDER | GNM_SPANCALC_RESIZE;
578 return res;
582 * gnm_style_default_halign:
583 * @style:
584 * @c:
586 * Select the appropriate horizontal alignment depending on the style and cell
587 * value.
589 GnmHAlign
590 gnm_style_default_halign (GnmStyle const *style, GnmCell const *c)
592 GnmHAlign align = gnm_style_get_align_h (style);
593 GnmValue *v;
595 if (align != GNM_HALIGN_GENERAL)
596 return align;
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) {
605 case VALUE_BOOLEAN:
606 case VALUE_ERROR:
607 return GNM_HALIGN_CENTER;
609 case VALUE_FLOAT: {
610 double a = gnm_style_get_rotation (style);
611 if (a > 0 && a < 180)
612 return GNM_HALIGN_LEFT;
613 return GNM_HALIGN_RIGHT;
616 case VALUE_ARRAY:
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];
620 continue;
623 default:
624 if (gnm_style_get_rotation (style) > 180)
625 return GNM_HALIGN_RIGHT;
626 return GNM_HALIGN_LEFT;
628 return GNM_HALIGN_RIGHT;
631 PangoUnderline
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);
637 switch (ul) {
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;
645 case UNDERLINE_NONE:
646 default:
647 return PANGO_UNDERLINE_NONE;
651 GnmUnderline
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);
657 switch (pul) {
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:
665 /* What? */
666 case PANGO_UNDERLINE_NONE:
667 default:
668 return UNDERLINE_NONE;