Update Spanish translation
[gnumeric.git] / src / rendered-value.c
blob3d399201c9ceb2ba09c55c2a64bfcc174c8c0749
2 /*
3 * rendered-value.c: Management & utility routines for formated
4 * colored text.
6 * Copyright (C) 2000, 2001 Jody Goldberg (jody@gnome.org)
7 * Copyright (C) 2001-2009 Morten Welinder (terra@gnome.org)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 * USA
24 #include <gnumeric-config.h>
25 #include <gnumeric.h>
26 #include <rendered-value.h>
28 #include <expr.h>
29 #include <cell.h>
30 #include <style.h>
31 #include <style-color.h>
32 #include <style-font.h>
33 #include <style-border.h>
34 #include <style-conditions.h>
35 #include <sheet.h>
36 #include <sheet-merge.h>
37 #include <gnm-format.h>
38 #include <value.h>
39 #include <parse-util.h>
40 #include <workbook.h>
41 #include <gutils.h>
43 #include <string.h>
44 #include <goffice/goffice.h>
46 #undef DEBUG_BOUNDING_BOX
48 #ifndef USE_RV_POOLS
49 #define USE_RV_POOLS 0
50 #endif
52 #if USE_RV_POOLS
53 /* Memory pool for GnmRenderedValue. */
54 static GOMemChunk *rendered_value_pool;
55 static GOMemChunk *rendered_rotated_value_pool;
56 #define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
57 #define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
58 #else
59 static int rv_allocations;
60 #define CHUNK_ALLOC(T,c) (rv_allocations++, g_slice_new (T))
61 #define CHUNK_FREE(p,v) (rv_allocations--, g_slice_free1 (sizeof(*v),(v)))
62 #endif
64 // Number of decimal digits in a gnm_float rounded down to an integer.
65 static int sane_digits;
67 static gboolean
68 debug_rv (void)
70 static int res = -1;
71 if (res == -1) {
72 res = gnm_debug_flag ("rendered-value");
74 return res > 0;
78 * Some valgrind versions have a hard time with signed bitfields,
79 * such as GnmRenderedValue::rotation.
81 static gboolean
82 valgrind_bitfield_workarounds (void)
84 static int res = -1;
85 if (res == -1) {
86 res = gnm_debug_flag ("valgrind-bitfield-workarounds");
88 return res > 0;
92 static guint16
93 calc_indent (PangoContext *context, const GnmStyle *mstyle)
95 int indent = 0;
96 if (gnm_style_is_element_set (mstyle, MSTYLE_INDENT)) {
97 int n = gnm_style_get_indent (mstyle);
98 if (n) {
99 GnmFont *style_font = gnm_style_get_font (mstyle, context);
100 indent = PANGO_PIXELS (n * style_font->go.metrics->avg_digit_width);
103 return MIN (indent, 65535);
107 void
108 gnm_rendered_value_remeasure (GnmRenderedValue *rv)
110 if (rv->rotation) {
111 GnmRenderedRotatedValue *rrv = (GnmRenderedRotatedValue *)rv;
112 PangoContext *context = pango_layout_get_context (rv->layout);
113 double sin_a, abs_sin_a, cos_a;
114 int sdx = 0;
115 int x0 = 0, x1 = 0;
116 PangoLayoutIter *iter;
117 int l = 0;
118 int lwidth;
119 PangoMatrix rotmat = PANGO_MATRIX_INIT;
121 pango_matrix_rotate (&rotmat, rv->rotation);
123 sin_a = rotmat.xy;
124 rrv->sin_a_neg = (sin_a < 0);
125 abs_sin_a = fabs (sin_a);
126 cos_a = rotmat.xx;
127 pango_context_set_matrix (context, &rotmat);
128 pango_layout_context_changed (rv->layout);
130 rrv->linecount = pango_layout_get_line_count (rv->layout);
131 rrv->lines = g_new (struct GnmRenderedRotatedValueInfo, rrv->linecount);
132 pango_layout_get_size (rv->layout, &lwidth, NULL);
134 rv->layout_natural_height = 0;
136 iter = pango_layout_get_iter (rv->layout);
137 do {
138 PangoRectangle logical;
139 int x, dx, dy, indent;
140 int h, ytop, ybot, baseline;
142 pango_layout_iter_get_line_extents (iter, NULL, &logical);
143 pango_layout_iter_get_line_yrange (iter, &ytop, &ybot);
144 baseline = pango_layout_iter_get_baseline (iter);
145 indent = logical.x;
146 if (sin_a < 0)
147 indent -= lwidth;
149 if (l == 0 && rv->noborders)
150 sdx = (int)(baseline * sin_a - ybot / sin_a);
151 dx = sdx + (int)(ybot / sin_a + indent * cos_a);
152 dy = (int)((baseline - ybot) * cos_a - indent * sin_a);
154 rrv->lines[l].dx = dx;
155 rrv->lines[l].dy = dy;
157 /* Left edge. */
158 x = dx - (int)((baseline - ytop) * sin_a);
159 x0 = MIN (x0, x);
161 /* Right edge. */
162 x = dx + (int)(logical.width * cos_a + (ybot - baseline) * sin_a);
163 x1 = MAX (x1, x);
165 h = logical.width * abs_sin_a + logical.height * cos_a;
166 if (h > rv->layout_natural_height)
167 rv->layout_natural_height = h;
169 l++;
170 } while (pango_layout_iter_next_line (iter));
171 pango_layout_iter_free (iter);
173 rv->layout_natural_width = x1 - x0;
174 if (sin_a < 0) {
175 int dx = rv->layout_natural_width;
176 for (l = 0; l < rrv->linecount; l++)
177 rrv->lines[l].dx += dx;
179 for (l = 0; l < rrv->linecount; l++)
180 rrv->lines[l].dy += rv->layout_natural_height;
182 #if 0
183 g_print ("Natural size: %d x %d\n", rv->layout_natural_width, rv->layout_natural_height);
184 #endif
186 pango_context_set_matrix (context, NULL);
187 pango_layout_context_changed (rv->layout);
188 } else
189 pango_layout_get_size (rv->layout,
190 &rv->layout_natural_width,
191 &rv->layout_natural_height);
194 typedef struct {
195 double zoom;
196 double scale;
197 int rise;
198 } rv_adjust_attributes_t;
200 static gboolean
201 rv_adjust_filter (PangoAttribute *attribute, rv_adjust_attributes_t *raat)
203 if (attribute->klass->type == PANGO_ATTR_RISE) {
204 PangoAttrInt *pa_rise = (PangoAttrInt *)attribute;
205 pa_rise->value = raat->scale * pa_rise->value + raat->rise;
207 if (attribute->klass->type == PANGO_ATTR_SCALE && raat->scale != 1.) {
208 PangoAttrFloat *pa_scale = (PangoAttrFloat *)attribute;
209 pa_scale->value = pa_scale->value * raat->zoom;
211 return FALSE;
214 static void
215 rv_adjust_attributes (PangoAttrList *markup, double zoom, double scale, int rise)
217 rv_adjust_attributes_t raat = {zoom, scale, rise};
219 pango_attr_list_filter (markup, (PangoAttrFilterFunc) rv_adjust_filter,
220 &raat);
223 static gboolean
224 too_many_digits (const char *s)
226 int count = 0;
227 const char *p;
229 // Count significant digits
230 for (p = s; *p; p = g_utf8_next_char (p)) {
231 gunichar uc = g_utf8_get_char (p);
232 if (uc == '0' && count == 0)
233 continue;
234 if (g_unichar_isdigit (uc))
235 count++;
236 if (uc == 'e' || uc == 'E')
237 break;
240 return count > sane_digits;
244 * gnm_rendered_value_new: (skip)
245 * @cell: The cell
246 * @variable_width: Allow format to depend on column width.
248 * Formats the value of the cell according to the format style given in @mstyle
250 * Returns: a new GnmRenderedValue
252 GnmRenderedValue *
253 gnm_rendered_value_new (GnmCell const *cell,
254 PangoContext *context,
255 gboolean allow_variable_width,
256 double zoom)
258 GnmRenderedValue *res;
259 PangoLayout *layout;
260 PangoAttrList *attrs;
261 int rotation;
262 Sheet const *sheet;
263 gboolean displayed_formula;
264 GnmStyle const *mstyle;
265 PangoDirection dir;
266 char const *text;
267 gboolean debug = debug_rv ();
268 GnmStyleConditions *conds;
270 g_return_val_if_fail (cell != NULL, NULL);
272 /* sheet->workbook can be NULL when called from preview-grid.c */
273 sheet = cell->base.sheet;
275 if (debug)
276 g_printerr ("Rendering %s value [%s]\n",
277 cell_name (cell),
278 value_peek_string (cell->value));
280 displayed_formula =
281 gnm_cell_has_expr (cell) && sheet->display_formulas;
283 /* Special handling for manual recalc.
284 * If a cell has a new expression and something tries to display it we
285 * need to recalc the value */
286 if (cell->base.flags & GNM_CELL_HAS_NEW_EXPR) {
287 gnm_cell_eval ((GnmCell *)cell);
290 /* Must come after above gnm_cell_eval. */
291 g_return_val_if_fail (cell->value != NULL, NULL);
293 mstyle = gnm_cell_get_style (cell);
295 conds = gnm_style_get_conditions (mstyle);
296 if (conds) {
297 GnmEvalPos ep;
298 int res;
299 eval_pos_init_cell (&ep, cell);
301 res = gnm_style_conditions_eval (conds, &ep);
302 if (res >= 0)
303 mstyle = gnm_style_get_cond_style (mstyle, res);
306 rotation = gnm_style_get_rotation (mstyle);
307 if (rotation) {
308 GnmRenderedRotatedValue *rrv;
309 GnmStyleElement e;
311 rrv = CHUNK_ALLOC (GnmRenderedRotatedValue, rendered_rotated_value_pool);
312 res = &rrv->rv;
313 if (valgrind_bitfield_workarounds ()) {
314 memset (&res->go_fore_color + 1,
316 (char *)(res + 1) - (char *)(&res->go_fore_color + 1));
319 rrv->linecount = 0;
320 rrv->lines = NULL;
322 res->noborders = TRUE;
323 /* Deliberately exclude diagonals. */
324 for (e = MSTYLE_BORDER_TOP; e <= MSTYLE_BORDER_RIGHT; e++) {
325 GnmBorder *b = gnm_style_get_border (mstyle, e);
326 if (!gnm_style_border_is_blank (b)) {
327 res->noborders = FALSE;
328 break;
331 } else {
332 res = CHUNK_ALLOC (GnmRenderedValue, rendered_value_pool);
333 res->noborders = FALSE;
335 res->rotation = rotation;
337 res->layout = layout = pango_layout_new (context);
338 res->hfilled = FALSE;
339 res->vfilled = FALSE;
340 res->variable_width = FALSE;
341 res->drawn = FALSE;
343 /* ---------------------------------------- */
345 attrs = gnm_style_get_pango_attrs (mstyle, context, zoom);
346 #ifdef DEBUG_BOUNDING_BOX
347 /* Make the whole layout end up with a red background. */
349 PangoAttrList *new_attrs = pango_attr_list_copy (attrs);
350 PangoAttribute *attr;
352 pango_attr_list_unref (attrs);
353 attrs = new_attrs;
354 attr = pango_attr_background_new (0xffff, 0, 0);
355 attr->start_index = 0;
356 attr->end_index = -1;
357 pango_attr_list_insert (attrs, attr);
359 #endif
361 /* Add markup. */
363 GOFormat const *fmt = VALUE_FMT (cell->value);
364 if (fmt != NULL && go_format_is_markup (fmt)) {
365 PangoAttrList *orig = attrs;
366 const PangoAttrList *markup = go_format_get_markup (fmt);
367 PangoAttrList *c_markup = NULL;
368 PangoAttrIterator *iter;
369 GSList *extra_attrs = NULL, *l;
370 PangoFontDescription *desc = pango_font_description_new ();
371 double font_size, scale = 1., tscale;
372 int rise = 0;
374 if (debug)
375 g_printerr (" Markup on value: %s\n", go_format_as_XL (fmt));
377 attrs = pango_attr_list_copy (attrs);
379 iter = pango_attr_list_get_iterator (attrs);
380 pango_attr_iterator_get_font (iter,
381 desc,
382 NULL,
383 &extra_attrs);
384 font_size = pango_font_description_get_size (desc)/
385 (double)PANGO_SCALE;
387 for (l = extra_attrs; l != NULL; l = l->next) {
388 PangoAttribute *pa = l->data;
389 if (pa->klass->type == PANGO_ATTR_RISE) {
390 PangoAttrInt *pa_rise = l->data;
391 rise = pa_rise->value;
394 if (pa->klass->type == PANGO_ATTR_SCALE) {
395 PangoAttrFloat *pa_scale = l->data;
396 scale = pa_scale->value;
399 g_slist_free_full (extra_attrs,
400 (GFreeFunc) pango_attribute_destroy);
401 pango_font_description_free (desc);
402 pango_attr_iterator_destroy (iter);
404 tscale = font_size/10. * scale;
405 if (tscale != 1|| rise != 0) {
406 markup = c_markup = pango_attr_list_copy
407 ((PangoAttrList *)markup);
408 rv_adjust_attributes (c_markup, zoom, tscale, rise);
411 pango_attr_list_splice (attrs, (PangoAttrList *)markup, 0, 0);
412 pango_attr_list_unref (orig);
413 pango_attr_list_unref (c_markup);
417 pango_layout_set_attributes (res->layout, attrs);
418 pango_attr_list_unref (attrs);
420 /* Store foreground color. */
421 /* Wrapping this colour around the attribute list drops performance! */
422 res->go_fore_color = (gnm_style_get_font_color (mstyle))->go_color;
424 /* ---------------------------------------- */
427 * Excel actually does something rather weird. Just like
428 * everywhere else we just see displayed formulas as
429 * strings.
431 res->wrap_text =
432 (VALUE_IS_STRING (cell->value) || displayed_formula) &&
433 gnm_style_get_effective_wrap_text (mstyle);
435 res->effective_valign = gnm_style_get_align_v (mstyle);
436 res->effective_halign = gnm_style_default_halign (mstyle, cell);
437 res->indent_left = res->indent_right = 0;
439 if (res->effective_halign == GNM_HALIGN_FILL) {
440 pango_layout_set_single_paragraph_mode (layout, TRUE);
441 res->variable_width = TRUE;
444 /* ---------------------------------------- */
446 res->numeric_overflow = FALSE;
448 if (displayed_formula) {
449 GnmParsePos pp;
450 GnmConventionsOut out;
451 gboolean is_array = gnm_expr_top_is_array (cell->base.texpr);
453 out.accum = g_string_new (is_array ? "{=" : "=");
454 out.convs = sheet->convs;
455 out.pp = &pp;
457 parse_pos_init_cell (&pp, cell),
458 gnm_expr_top_as_gstring (cell->base.texpr, &out);
459 if (is_array)
460 g_string_append_c (out.accum, '}');
461 pango_layout_set_text (layout, out.accum->str, out.accum->len);
462 g_string_free (out.accum, TRUE);
463 res->might_overflow = FALSE;
464 } else if (sheet->hide_zero && gnm_cell_is_zero (cell)) {
465 pango_layout_set_text (layout, "", 0);
466 res->might_overflow = FALSE;
467 } else {
468 int col_width = -1;
469 GOFormat const *format = gnm_style_get_format (mstyle);
470 GODateConventions const *date_conv = sheet->workbook
471 ? sheet_date_conv (sheet)
472 : NULL;
473 GnmFont *font = gnm_style_get_font (mstyle, context);
474 gboolean is_rotated = (rotation != 0);
475 gboolean variable;
476 GOFormatNumberError err;
478 if (go_format_is_general (format) && VALUE_FMT (cell->value))
479 format = VALUE_FMT (cell->value);
481 res->might_overflow = !is_rotated &&
482 VALUE_IS_FLOAT (cell->value);
484 if (go_format_is_general (format))
485 variable = !is_rotated && VALUE_IS_FLOAT (cell->value);
486 else
487 variable = !is_rotated && go_format_is_var_width (format);
489 if (variable)
490 res->variable_width = TRUE;
492 if (variable && allow_variable_width) {
493 int col_width_pixels;
495 if (gnm_cell_is_merged (cell)) {
496 GnmRange const *merged =
497 gnm_sheet_merge_is_corner (sheet, &cell->pos);
499 col_width_pixels = sheet_col_get_distance_pixels
500 (sheet,
501 merged->start.col, merged->end.col + 1);
502 } else {
503 ColRowInfo const *ci = sheet_col_get_info (sheet, cell->pos.col);
504 col_width_pixels = ci->size_pixels;
506 col_width_pixels -= (GNM_COL_MARGIN + GNM_COL_MARGIN + 1);
507 if (col_width_pixels < 0)
508 col_width_pixels = 0;
509 col_width = col_width_pixels * PANGO_SCALE;
512 err = gnm_format_layout (layout, font->go.metrics, format,
513 cell->value,
514 col_width, date_conv, TRUE);
516 // If we are formatting a number as General without a limit
517 // on size [i.e., we autofitting a column] then avoid excess
518 // precision. This is somewhat hacky.
519 if (col_width == -1 &&
520 go_format_is_general (format) &&
521 VALUE_IS_FLOAT (cell->value) &&
522 font->go.metrics->min_digit_width > 0 &&
523 too_many_digits (pango_layout_get_text (layout))) {
524 int width;
525 int delta = (font->go.metrics->min_digit_width + 1) / 2;
526 pango_layout_get_size (layout, &width, NULL);
527 col_width = width - delta;
528 err = gnm_format_layout (layout,
529 font->go.metrics, format,
530 cell->value,
531 col_width, date_conv, TRUE);
534 switch (err) {
535 case GO_FORMAT_NUMBER_DATE_ERROR:
536 pango_layout_set_text (layout, "", -1);
537 pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
538 res->numeric_overflow = TRUE;
539 res->effective_halign = GNM_HALIGN_LEFT;
540 break;
541 default:
542 break;
546 /* ---------------------------------------- */
548 text = pango_layout_get_text (layout);
549 dir = (text && *text)? pango_find_base_dir (text, -1): PANGO_DIRECTION_LTR;
550 if (gnm_style_get_align_h (mstyle) == GNM_HALIGN_GENERAL && dir == PANGO_DIRECTION_RTL) {
551 switch (res->effective_halign) {
552 case GNM_HALIGN_LEFT:
553 res->effective_halign = GNM_HALIGN_RIGHT;
554 break;
555 case GNM_HALIGN_RIGHT:
556 res->effective_halign = GNM_HALIGN_LEFT;
557 break;
560 switch (res->effective_halign) {
561 case GNM_HALIGN_LEFT:
562 res->indent_left = calc_indent (context, mstyle);
563 pango_layout_set_alignment (layout, (dir == PANGO_DIRECTION_RTL)? PANGO_ALIGN_RIGHT: PANGO_ALIGN_LEFT);
564 break;
566 case GNM_HALIGN_JUSTIFY:
567 pango_layout_set_justify (layout, TRUE);
568 pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
569 break;
571 case GNM_HALIGN_FILL:
572 break;
574 case GNM_HALIGN_RIGHT:
575 res->indent_right = calc_indent (context, mstyle);
576 pango_layout_set_alignment (layout, (dir == PANGO_DIRECTION_RTL)? PANGO_ALIGN_LEFT: PANGO_ALIGN_RIGHT);
577 break;
579 case GNM_HALIGN_DISTRIBUTED:
580 pango_layout_set_justify (layout, TRUE);
581 pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
582 break;
584 case GNM_HALIGN_CENTER:
585 case GNM_HALIGN_CENTER_ACROSS_SELECTION:
586 pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
587 break;
589 default:
590 g_warning ("Line justification style not supported.");
592 /* ---------------------------------------- */
594 go_pango_translate_layout (layout);
595 gnm_rendered_value_remeasure (res);
597 return res;
600 void
601 gnm_rendered_value_destroy (GnmRenderedValue *rv)
603 if (rv->layout) {
604 g_object_unref (rv->layout);
605 rv->layout = NULL;
608 if (rv->rotation) {
609 GnmRenderedRotatedValue *rrv = (GnmRenderedRotatedValue *)rv;
610 g_free (rrv->lines);
611 CHUNK_FREE (rendered_rotated_value_pool, rrv);
612 } else
613 CHUNK_FREE (rendered_value_pool, rv);
616 /* Return the value as a single string without format infomation.
618 char const *
619 gnm_rendered_value_get_text (GnmRenderedValue const *rv)
621 g_return_val_if_fail (rv != NULL, "ERROR");
622 return pango_layout_get_text (rv->layout);
625 GOColor
626 gnm_rendered_value_get_color (GnmRenderedValue const * rv)
628 return rv->go_fore_color;
631 /* ------------------------------------------------------------------------- */
633 static gboolean
634 debug_rvc (void)
636 static int res = -1;
637 if (res == -1) {
638 res = gnm_debug_flag ("rvc");
640 return res > 0;
644 * gnm_rvc_new: (skip)
645 * @context: The context
646 * @size:
648 * Returns: a new GnmRenderedValueCollection
650 GnmRenderedValueCollection *
651 gnm_rvc_new (PangoContext *context, gsize size)
653 GnmRenderedValueCollection *res = g_new0 (GnmRenderedValueCollection, 1);
655 res->context = g_object_ref (context);
657 res->size = size;
658 res->values = g_hash_table_new_full
659 (g_direct_hash, g_direct_equal,
660 NULL,
661 (GDestroyNotify)gnm_rendered_value_destroy);
663 if (debug_rvc ())
664 g_printerr ("Created rendered value cache %p of size %u\n",
665 res, (unsigned)size);
667 return res;
670 void
671 gnm_rvc_free (GnmRenderedValueCollection *rvc)
673 g_return_if_fail (rvc != NULL);
675 if (debug_rvc ())
676 g_printerr ("Destroying rendered value cache %p\n", rvc);
678 g_object_unref (rvc->context);
679 g_hash_table_destroy (rvc->values);
680 g_free (rvc);
684 * gnm_rvc_query: (skip)
685 * @rvc: The rendered value collection
686 * @cell: #GnmCell
688 * Returns: the rendered value for @cell.
690 GnmRenderedValue *
691 gnm_rvc_query (GnmRenderedValueCollection *rvc, GnmCell const *cell)
693 g_return_val_if_fail (rvc != NULL, NULL);
695 return g_hash_table_lookup (rvc->values, cell);
698 void
699 gnm_rvc_store (GnmRenderedValueCollection *rvc,
700 GnmCell const *cell,
701 GnmRenderedValue *rv)
703 g_return_if_fail (rvc != NULL);
705 /* Crude cache management: */
706 if (g_hash_table_size (rvc->values) >= rvc->size) {
707 if (debug_rvc ())
708 g_printerr ("Clearing rendered value cache %p\n", rvc);
709 g_hash_table_remove_all (rvc->values);
712 g_hash_table_insert (rvc->values, (gpointer)cell, rv);
715 void
716 gnm_rvc_remove (GnmRenderedValueCollection *rvc, GnmCell const *cell)
718 g_return_if_fail (rvc != NULL);
719 g_hash_table_remove (rvc->values, (gpointer)cell);
722 /* ------------------------------------------------------------------------- */
725 * gnm_rendered_value_init: (skip)
727 void
728 gnm_rendered_value_init (void)
730 sane_digits = (int)gnm_floor (GNM_MANT_DIG * gnm_log10 (FLT_RADIX));
732 #if USE_RV_POOLS
733 rendered_value_pool =
734 go_mem_chunk_new ("rendered value pool",
735 sizeof (GnmRenderedValue),
736 16 * 1024 - 128);
737 rendered_rotated_value_pool =
738 go_mem_chunk_new ("rendered rotated value pool",
739 sizeof (GnmRenderedRotatedValue),
740 16 * 1024 - 128);
741 #endif
744 #if USE_RV_POOLS
745 static void
746 cb_rendered_value_pool_leak (gpointer data, G_GNUC_UNUSED gpointer user)
748 GnmRenderedValue *rendered_value = data;
749 g_printerr ("Leaking rendered value at %p [%s].\n",
750 rendered_value, pango_layout_get_text (rendered_value->layout));
752 #endif
755 * gnm_rendered_value_shutdown: (skip)
757 void
758 gnm_rendered_value_shutdown (void)
760 #if USE_RV_POOLS
761 go_mem_chunk_foreach_leak (rendered_value_pool, cb_rendered_value_pool_leak, NULL);
762 go_mem_chunk_destroy (rendered_value_pool, FALSE);
763 rendered_value_pool = NULL;
765 go_mem_chunk_foreach_leak (rendered_rotated_value_pool, cb_rendered_value_pool_leak, NULL);
766 go_mem_chunk_destroy (rendered_rotated_value_pool, FALSE);
767 rendered_rotated_value_pool = NULL;
768 #else
769 if (rv_allocations)
770 g_printerr ("Leaking %d rendered values.\n", rv_allocations);
771 #endif