GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / rendered-value.c
blob9387a14664663529ea6d8cda6a8460d31998f280
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * rendered-value.c: Management & utility routines for formated
5 * colored text.
7 * Copyright (C) 2000, 2001 Jody Goldberg (jody@gnome.org)
8 * Copyright (C) 2001-2009 Morten Welinder (terra@gnome.org)
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 * USA
25 #include <gnumeric-config.h>
26 #include "gnumeric.h"
27 #include "rendered-value.h"
29 #include "expr.h"
30 #include "cell.h"
31 #include "style.h"
32 #include "style-color.h"
33 #include "style-font.h"
34 #include "style-border.h"
35 #include "style-conditions.h"
36 #include "sheet.h"
37 #include "sheet-merge.h"
38 #include "gnm-format.h"
39 #include "value.h"
40 #include "parse-util.h"
41 #include "workbook.h"
42 #include "gutils.h"
44 #include <string.h>
45 #include <goffice/goffice.h>
47 #undef DEBUG_BOUNDING_BOX
49 #ifndef USE_RV_POOLS
50 #define USE_RV_POOLS 0
51 #endif
53 #if USE_RV_POOLS
54 /* Memory pool for GnmRenderedValue. */
55 static GOMemChunk *rendered_value_pool;
56 static GOMemChunk *rendered_rotated_value_pool;
57 #define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
58 #define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
59 #else
60 static int rv_allocations;
61 #define CHUNK_ALLOC(T,c) (rv_allocations++, g_slice_new (T))
62 #define CHUNK_FREE(p,v) (rv_allocations--, g_slice_free1 (sizeof(*v),(v)))
63 #endif
65 // Number of decimal digits in a gnm_float rounded down to an integer.
66 static int sane_digits;
68 static gboolean
69 debug_rv (void)
71 static int res = -1;
72 if (res == -1) {
73 res = gnm_debug_flag ("rendered-value");
75 return res > 0;
79 * Some valgrind versions have a hard time with signed bitfields,
80 * such as GnmRenderedValue::rotation.
82 static gboolean
83 valgrind_bitfield_workarounds (void)
85 static int res = -1;
86 if (res == -1) {
87 res = gnm_debug_flag ("valgrind-bitfield-workarounds");
89 return res > 0;
93 static guint16
94 calc_indent (PangoContext *context, const GnmStyle *mstyle)
96 int indent = 0;
97 if (gnm_style_is_element_set (mstyle, MSTYLE_INDENT)) {
98 int n = gnm_style_get_indent (mstyle);
99 if (n) {
100 GnmFont *style_font = gnm_style_get_font (mstyle, context);
101 indent = PANGO_PIXELS (n * style_font->go.metrics->avg_digit_width);
104 return MIN (indent, 65535);
108 void
109 gnm_rendered_value_remeasure (GnmRenderedValue *rv)
111 if (rv->rotation) {
112 GnmRenderedRotatedValue *rrv = (GnmRenderedRotatedValue *)rv;
113 PangoContext *context = pango_layout_get_context (rv->layout);
114 double sin_a, abs_sin_a, cos_a;
115 int sdx = 0;
116 int x0 = 0, x1 = 0;
117 PangoLayoutIter *iter;
118 int l = 0;
119 int lwidth;
120 PangoMatrix rotmat = PANGO_MATRIX_INIT;
122 pango_matrix_rotate (&rotmat, rv->rotation);
124 sin_a = rotmat.xy;
125 rrv->sin_a_neg = (sin_a < 0);
126 abs_sin_a = fabs (sin_a);
127 cos_a = rotmat.xx;
128 pango_context_set_matrix (context, &rotmat);
129 pango_layout_context_changed (rv->layout);
131 rrv->linecount = pango_layout_get_line_count (rv->layout);
132 rrv->lines = g_new (struct GnmRenderedRotatedValueInfo, rrv->linecount);
133 pango_layout_get_size (rv->layout, &lwidth, NULL);
135 rv->layout_natural_height = 0;
137 iter = pango_layout_get_iter (rv->layout);
138 do {
139 PangoRectangle logical;
140 int x, dx, dy, indent;
141 int h, ytop, ybot, baseline;
143 pango_layout_iter_get_line_extents (iter, NULL, &logical);
144 pango_layout_iter_get_line_yrange (iter, &ytop, &ybot);
145 baseline = pango_layout_iter_get_baseline (iter);
146 indent = logical.x;
147 if (sin_a < 0)
148 indent -= lwidth;
150 if (l == 0 && rv->noborders)
151 sdx = (int)(baseline * sin_a - ybot / sin_a);
152 dx = sdx + (int)(ybot / sin_a + indent * cos_a);
153 dy = (int)((baseline - ybot) * cos_a - indent * sin_a);
155 rrv->lines[l].dx = dx;
156 rrv->lines[l].dy = dy;
158 /* Left edge. */
159 x = dx - (int)((baseline - ytop) * sin_a);
160 x0 = MIN (x0, x);
162 /* Right edge. */
163 x = dx + (int)(logical.width * cos_a + (ybot - baseline) * sin_a);
164 x1 = MAX (x1, x);
166 h = logical.width * abs_sin_a + logical.height * cos_a;
167 if (h > rv->layout_natural_height)
168 rv->layout_natural_height = h;
170 l++;
171 } while (pango_layout_iter_next_line (iter));
172 pango_layout_iter_free (iter);
174 rv->layout_natural_width = x1 - x0;
175 if (sin_a < 0) {
176 int dx = rv->layout_natural_width;
177 for (l = 0; l < rrv->linecount; l++)
178 rrv->lines[l].dx += dx;
180 for (l = 0; l < rrv->linecount; l++)
181 rrv->lines[l].dy += rv->layout_natural_height;
183 #if 0
184 g_print ("Natural size: %d x %d\n", rv->layout_natural_width, rv->layout_natural_height);
185 #endif
187 pango_context_set_matrix (context, NULL);
188 pango_layout_context_changed (rv->layout);
189 } else
190 pango_layout_get_size (rv->layout,
191 &rv->layout_natural_width,
192 &rv->layout_natural_height);
195 typedef struct {
196 double zoom;
197 double scale;
198 int rise;
199 } rv_adjust_attributes_t;
201 static gboolean
202 rv_adjust_filter (PangoAttribute *attribute, rv_adjust_attributes_t *raat)
204 if (attribute->klass->type == PANGO_ATTR_RISE) {
205 PangoAttrInt *pa_rise = (PangoAttrInt *)attribute;
206 pa_rise->value = raat->scale * pa_rise->value + raat->rise;
208 if (attribute->klass->type == PANGO_ATTR_SCALE && raat->scale != 1.) {
209 PangoAttrFloat *pa_scale = (PangoAttrFloat *)attribute;
210 pa_scale->value = pa_scale->value * raat->zoom;
212 return FALSE;
215 static void
216 rv_adjust_attributes (PangoAttrList *markup, double zoom, double scale, int rise)
218 rv_adjust_attributes_t raat = {zoom, scale, rise};
220 pango_attr_list_filter (markup, (PangoAttrFilterFunc) rv_adjust_filter,
221 &raat);
224 static gboolean
225 too_many_digits (const char *s)
227 int count = 0;
228 const char *p;
230 // Count significant digits
231 for (p = s; *p; p = g_utf8_next_char (p)) {
232 gunichar uc = g_utf8_get_char (p);
233 if (uc == '0' && count == 0)
234 continue;
235 if (g_unichar_isdigit (uc))
236 count++;
237 if (uc == 'e' || uc == 'E')
238 break;
241 return count > sane_digits;
245 * gnm_rendered_value_new: (skip)
246 * @cell: The cell
247 * @variable_width: Allow format to depend on column width.
249 * Formats the value of the cell according to the format style given in @mstyle
251 * Returns: a new GnmRenderedValue
253 GnmRenderedValue *
254 gnm_rendered_value_new (GnmCell const *cell,
255 PangoContext *context,
256 gboolean allow_variable_width,
257 double zoom)
259 GnmRenderedValue *res;
260 PangoLayout *layout;
261 PangoAttrList *attrs;
262 int rotation;
263 Sheet const *sheet;
264 gboolean displayed_formula;
265 GnmStyle const *mstyle;
266 PangoDirection dir;
267 char const *text;
268 gboolean debug = debug_rv ();
269 GnmStyleConditions *conds;
271 g_return_val_if_fail (cell != NULL, NULL);
273 /* sheet->workbook can be NULL when called from preview-grid.c */
274 sheet = cell->base.sheet;
276 if (debug)
277 g_printerr ("Rendering %s value [%s]\n",
278 cell_name (cell),
279 value_peek_string (cell->value));
281 displayed_formula =
282 gnm_cell_has_expr (cell) && sheet->display_formulas;
284 /* Special handling for manual recalc.
285 * If a cell has a new expression and something tries to display it we
286 * need to recalc the value */
287 if (cell->base.flags & GNM_CELL_HAS_NEW_EXPR) {
288 gnm_cell_eval ((GnmCell *)cell);
291 /* Must come after above gnm_cell_eval. */
292 g_return_val_if_fail (cell->value != NULL, NULL);
294 mstyle = gnm_cell_get_style (cell);
296 conds = gnm_style_get_conditions (mstyle);
297 if (conds) {
298 GnmEvalPos ep;
299 int res;
300 eval_pos_init_cell (&ep, cell);
302 res = gnm_style_conditions_eval (conds, &ep);
303 if (res >= 0)
304 mstyle = gnm_style_get_cond_style (mstyle, res);
307 rotation = gnm_style_get_rotation (mstyle);
308 if (rotation) {
309 GnmRenderedRotatedValue *rrv;
310 GnmStyleElement e;
312 rrv = CHUNK_ALLOC (GnmRenderedRotatedValue, rendered_rotated_value_pool);
313 res = &rrv->rv;
314 if (valgrind_bitfield_workarounds ()) {
315 memset (&res->go_fore_color + 1,
317 (char *)(res + 1) - (char *)(&res->go_fore_color + 1));
320 rrv->linecount = 0;
321 rrv->lines = NULL;
323 res->noborders = TRUE;
324 /* Deliberately exclude diagonals. */
325 for (e = MSTYLE_BORDER_TOP; e <= MSTYLE_BORDER_RIGHT; e++) {
326 GnmBorder *b = gnm_style_get_border (mstyle, e);
327 if (!gnm_style_border_is_blank (b)) {
328 res->noborders = FALSE;
329 break;
332 } else {
333 res = CHUNK_ALLOC (GnmRenderedValue, rendered_value_pool);
334 res->noborders = FALSE;
336 res->rotation = rotation;
338 res->layout = layout = pango_layout_new (context);
339 res->hfilled = FALSE;
340 res->vfilled = FALSE;
341 res->variable_width = FALSE;
342 res->drawn = FALSE;
344 /* ---------------------------------------- */
346 attrs = gnm_style_get_pango_attrs (mstyle, context, zoom);
347 #ifdef DEBUG_BOUNDING_BOX
348 /* Make the whole layout end up with a red background. */
350 PangoAttrList *new_attrs = pango_attr_list_copy (attrs);
351 PangoAttribute *attr;
353 pango_attr_list_unref (attrs);
354 attrs = new_attrs;
355 attr = pango_attr_background_new (0xffff, 0, 0);
356 attr->start_index = 0;
357 attr->end_index = -1;
358 pango_attr_list_insert (attrs, attr);
360 #endif
362 /* Add markup. */
364 GOFormat const *fmt = VALUE_FMT (cell->value);
365 if (fmt != NULL && go_format_is_markup (fmt)) {
366 PangoAttrList *orig = attrs;
367 const PangoAttrList *markup = go_format_get_markup (fmt);
368 PangoAttrList *c_markup = NULL;
369 PangoAttrIterator *iter;
370 GSList *extra_attrs = NULL, *l;
371 PangoFontDescription *desc = pango_font_description_new ();
372 double font_size, scale = 1., tscale;
373 int rise = 0;
375 if (debug)
376 g_printerr (" Markup on value: %s\n", go_format_as_XL (fmt));
378 attrs = pango_attr_list_copy (attrs);
380 iter = pango_attr_list_get_iterator (attrs);
381 pango_attr_iterator_get_font (iter,
382 desc,
383 NULL,
384 &extra_attrs);
385 font_size = pango_font_description_get_size (desc)/
386 (double)PANGO_SCALE;
388 for (l = extra_attrs; l != NULL; l = l->next) {
389 PangoAttribute *pa = l->data;
390 if (pa->klass->type == PANGO_ATTR_RISE) {
391 PangoAttrInt *pa_rise = l->data;
392 rise = pa_rise->value;
395 if (pa->klass->type == PANGO_ATTR_SCALE) {
396 PangoAttrFloat *pa_scale = l->data;
397 scale = pa_scale->value;
400 g_slist_free_full (extra_attrs,
401 (GFreeFunc) pango_attribute_destroy);
402 pango_font_description_free (desc);
403 pango_attr_iterator_destroy (iter);
405 tscale = font_size/10. * scale;
406 if (tscale != 1|| rise != 0) {
407 markup = c_markup = pango_attr_list_copy
408 ((PangoAttrList *)markup);
409 rv_adjust_attributes (c_markup, zoom, tscale, rise);
412 pango_attr_list_splice (attrs, (PangoAttrList *)markup, 0, 0);
413 pango_attr_list_unref (orig);
414 pango_attr_list_unref (c_markup);
418 pango_layout_set_attributes (res->layout, attrs);
419 pango_attr_list_unref (attrs);
421 /* Store foreground color. */
422 /* Wrapping this colour around the attribute list drops performance! */
423 res->go_fore_color = (gnm_style_get_font_color (mstyle))->go_color;
425 /* ---------------------------------------- */
428 * Excel actually does something rather weird. Just like
429 * everywhere else we just see displayed formulas as
430 * strings.
432 res->wrap_text =
433 (VALUE_IS_STRING (cell->value) || displayed_formula) &&
434 gnm_style_get_effective_wrap_text (mstyle);
436 res->effective_valign = gnm_style_get_align_v (mstyle);
437 res->effective_halign = gnm_style_default_halign (mstyle, cell);
438 res->indent_left = res->indent_right = 0;
440 if (res->effective_halign == GNM_HALIGN_FILL) {
441 pango_layout_set_single_paragraph_mode (layout, TRUE);
442 res->variable_width = TRUE;
445 /* ---------------------------------------- */
447 res->numeric_overflow = FALSE;
449 if (displayed_formula) {
450 GnmParsePos pp;
451 GnmConventionsOut out;
452 gboolean is_array = gnm_expr_top_is_array (cell->base.texpr);
454 out.accum = g_string_new (is_array ? "{=" : "=");
455 out.convs = sheet->convs;
456 out.pp = &pp;
458 parse_pos_init_cell (&pp, cell),
459 gnm_expr_top_as_gstring (cell->base.texpr, &out);
460 if (is_array)
461 g_string_append_c (out.accum, '}');
462 pango_layout_set_text (layout, out.accum->str, out.accum->len);
463 g_string_free (out.accum, TRUE);
464 res->might_overflow = FALSE;
465 } else if (sheet->hide_zero && gnm_cell_is_zero (cell)) {
466 pango_layout_set_text (layout, "", 0);
467 res->might_overflow = FALSE;
468 } else {
469 int col_width = -1;
470 GOFormat const *format = gnm_style_get_format (mstyle);
471 GODateConventions const *date_conv = sheet->workbook
472 ? sheet_date_conv (sheet)
473 : NULL;
474 GnmFont *font = gnm_style_get_font (mstyle, context);
475 gboolean is_rotated = (rotation != 0);
476 gboolean variable;
477 GOFormatNumberError err;
479 if (go_format_is_general (format) && VALUE_FMT (cell->value))
480 format = VALUE_FMT (cell->value);
482 res->might_overflow = !is_rotated &&
483 VALUE_IS_FLOAT (cell->value);
485 if (go_format_is_general (format))
486 variable = !is_rotated && VALUE_IS_FLOAT (cell->value);
487 else
488 variable = !is_rotated && go_format_is_var_width (format);
490 if (variable)
491 res->variable_width = TRUE;
493 if (variable && allow_variable_width) {
494 int col_width_pixels;
496 if (gnm_cell_is_merged (cell)) {
497 GnmRange const *merged =
498 gnm_sheet_merge_is_corner (sheet, &cell->pos);
500 col_width_pixels = sheet_col_get_distance_pixels
501 (sheet,
502 merged->start.col, merged->end.col + 1);
503 } else {
504 ColRowInfo const *ci = sheet_col_get_info (sheet, cell->pos.col);
505 col_width_pixels = ci->size_pixels;
507 col_width_pixels -= (GNM_COL_MARGIN + GNM_COL_MARGIN + 1);
508 if (col_width_pixels < 0)
509 col_width_pixels = 0;
510 col_width = col_width_pixels * PANGO_SCALE;
513 err = gnm_format_layout (layout, font->go.metrics, format,
514 cell->value,
515 col_width, date_conv, TRUE);
517 // If we are formatting a number as General without a limit
518 // on size [i.e., we autofitting a column] then avoid excess
519 // precision. This is somewhat hacky.
520 if (col_width == -1 &&
521 go_format_is_general (format) &&
522 VALUE_IS_FLOAT (cell->value) &&
523 font->go.metrics->min_digit_width > 0 &&
524 too_many_digits (pango_layout_get_text (layout))) {
525 int width;
526 int delta = (font->go.metrics->min_digit_width + 1) / 2;
527 pango_layout_get_size (layout, &width, NULL);
528 col_width = width - delta;
529 err = gnm_format_layout (layout,
530 font->go.metrics, format,
531 cell->value,
532 col_width, date_conv, TRUE);
535 switch (err) {
536 case GO_FORMAT_NUMBER_DATE_ERROR:
537 pango_layout_set_text (layout, "", -1);
538 pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
539 res->numeric_overflow = TRUE;
540 res->effective_halign = GNM_HALIGN_LEFT;
541 break;
542 default:
543 break;
547 /* ---------------------------------------- */
549 text = pango_layout_get_text (layout);
550 dir = (text && *text)? pango_find_base_dir (text, -1): PANGO_DIRECTION_LTR;
551 if (gnm_style_get_align_h (mstyle) == GNM_HALIGN_GENERAL && dir == PANGO_DIRECTION_RTL) {
552 switch (res->effective_halign) {
553 case GNM_HALIGN_LEFT:
554 res->effective_halign = GNM_HALIGN_RIGHT;
555 break;
556 case GNM_HALIGN_RIGHT:
557 res->effective_halign = GNM_HALIGN_LEFT;
558 break;
561 switch (res->effective_halign) {
562 case GNM_HALIGN_LEFT:
563 res->indent_left = calc_indent (context, mstyle);
564 pango_layout_set_alignment (layout, (dir == PANGO_DIRECTION_RTL)? PANGO_ALIGN_RIGHT: PANGO_ALIGN_LEFT);
565 break;
567 case GNM_HALIGN_JUSTIFY:
568 pango_layout_set_justify (layout, TRUE);
569 pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
570 break;
572 case GNM_HALIGN_FILL:
573 break;
575 case GNM_HALIGN_RIGHT:
576 res->indent_right = calc_indent (context, mstyle);
577 pango_layout_set_alignment (layout, (dir == PANGO_DIRECTION_RTL)? PANGO_ALIGN_LEFT: PANGO_ALIGN_RIGHT);
578 break;
580 case GNM_HALIGN_DISTRIBUTED:
581 pango_layout_set_justify (layout, TRUE);
582 pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
583 break;
585 case GNM_HALIGN_CENTER:
586 case GNM_HALIGN_CENTER_ACROSS_SELECTION:
587 pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
588 break;
590 default:
591 g_warning ("Line justification style not supported.");
593 /* ---------------------------------------- */
595 go_pango_translate_layout (layout);
596 gnm_rendered_value_remeasure (res);
598 return res;
601 void
602 gnm_rendered_value_destroy (GnmRenderedValue *rv)
604 if (rv->layout) {
605 g_object_unref (rv->layout);
606 rv->layout = NULL;
609 if (rv->rotation) {
610 GnmRenderedRotatedValue *rrv = (GnmRenderedRotatedValue *)rv;
611 g_free (rrv->lines);
612 CHUNK_FREE (rendered_rotated_value_pool, rrv);
613 } else
614 CHUNK_FREE (rendered_value_pool, rv);
617 /* Return the value as a single string without format infomation.
619 char const *
620 gnm_rendered_value_get_text (GnmRenderedValue const *rv)
622 g_return_val_if_fail (rv != NULL, "ERROR");
623 return pango_layout_get_text (rv->layout);
626 GOColor
627 gnm_rendered_value_get_color (GnmRenderedValue const * rv)
629 return rv->go_fore_color;
632 /* ------------------------------------------------------------------------- */
634 static gboolean
635 debug_rvc (void)
637 static int res = -1;
638 if (res == -1) {
639 res = gnm_debug_flag ("rvc");
641 return res > 0;
645 * gnm_rvc_new: (skip)
646 * @context: The context
647 * @size:
649 * Returns: a new GnmRenderedValueCollection
651 GnmRenderedValueCollection *
652 gnm_rvc_new (PangoContext *context, gsize size)
654 GnmRenderedValueCollection *res = g_new0 (GnmRenderedValueCollection, 1);
656 res->context = g_object_ref (context);
658 res->size = size;
659 res->values = g_hash_table_new_full
660 (g_direct_hash, g_direct_equal,
661 NULL,
662 (GDestroyNotify)gnm_rendered_value_destroy);
664 if (debug_rvc ())
665 g_printerr ("Created rendered value cache %p of size %u\n",
666 res, (unsigned)size);
668 return res;
671 void
672 gnm_rvc_free (GnmRenderedValueCollection *rvc)
674 g_return_if_fail (rvc != NULL);
676 if (debug_rvc ())
677 g_printerr ("Destroying rendered value cache %p\n", rvc);
679 g_object_unref (rvc->context);
680 g_hash_table_destroy (rvc->values);
681 g_free (rvc);
685 * gnm_rvc_query: (skip)
686 * @rvc: The rendered value collection
687 * @cell: #GnmCell
689 * Returns: the rendered value for @cell.
691 GnmRenderedValue *
692 gnm_rvc_query (GnmRenderedValueCollection *rvc, GnmCell const *cell)
694 g_return_val_if_fail (rvc != NULL, NULL);
696 return g_hash_table_lookup (rvc->values, cell);
699 void
700 gnm_rvc_store (GnmRenderedValueCollection *rvc,
701 GnmCell const *cell,
702 GnmRenderedValue *rv)
704 g_return_if_fail (rvc != NULL);
706 /* Crude cache management: */
707 if (g_hash_table_size (rvc->values) >= rvc->size) {
708 if (debug_rvc ())
709 g_printerr ("Clearing rendered value cache %p\n", rvc);
710 g_hash_table_remove_all (rvc->values);
713 g_hash_table_insert (rvc->values, (gpointer)cell, rv);
716 void
717 gnm_rvc_remove (GnmRenderedValueCollection *rvc, GnmCell const *cell)
719 g_return_if_fail (rvc != NULL);
720 g_hash_table_remove (rvc->values, (gpointer)cell);
723 /* ------------------------------------------------------------------------- */
726 * gnm_rendered_value_init: (skip)
728 void
729 gnm_rendered_value_init (void)
731 sane_digits = (int)gnm_floor (GNM_MANT_DIG * gnm_log10 (FLT_RADIX));
733 #if USE_RV_POOLS
734 rendered_value_pool =
735 go_mem_chunk_new ("rendered value pool",
736 sizeof (GnmRenderedValue),
737 16 * 1024 - 128);
738 rendered_rotated_value_pool =
739 go_mem_chunk_new ("rendered rotated value pool",
740 sizeof (GnmRenderedRotatedValue),
741 16 * 1024 - 128);
742 #endif
745 #if USE_RV_POOLS
746 static void
747 cb_rendered_value_pool_leak (gpointer data, G_GNUC_UNUSED gpointer user)
749 GnmRenderedValue *rendered_value = data;
750 g_printerr ("Leaking rendered value at %p [%s].\n",
751 rendered_value, pango_layout_get_text (rendered_value->layout));
753 #endif
756 * gnm_rendered_value_shutdown: (skip)
758 void
759 gnm_rendered_value_shutdown (void)
761 #if USE_RV_POOLS
762 go_mem_chunk_foreach_leak (rendered_value_pool, cb_rendered_value_pool_leak, NULL);
763 go_mem_chunk_destroy (rendered_value_pool, FALSE);
764 rendered_value_pool = NULL;
766 go_mem_chunk_foreach_leak (rendered_rotated_value_pool, cb_rendered_value_pool_leak, NULL);
767 go_mem_chunk_destroy (rendered_rotated_value_pool, FALSE);
768 rendered_rotated_value_pool = NULL;
769 #else
770 if (rv_allocations)
771 g_printerr ("Leaking %d rendered values.\n", rv_allocations);
772 #endif