X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Ftable.c;h=09d45af7c5721107e8b6221febfa812439617de2;hb=bcaaee5f0bd21f443c8dcb5f67114e63d43673af;hp=b7afb8f81f24fe4542bedbd6f9e484302de1f3cf;hpb=d3fef25674baf4f4e25502f257c680b5090535c6;p=pspp diff --git a/src/output/table.c b/src/output/table.c index b7afb8f81f..09d45af7c5 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2009, 2011, 2014 Free Software Foundation, Inc. + Copyright (C) 2009, 2011, 2014, 2016 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,11 +20,17 @@ #include "output/table-provider.h" #include +#include #include +#include "data/format.h" +#include "libpspp/assertion.h" #include "libpspp/cast.h" #include "libpspp/compiler.h" +#include "libpspp/pool.h" +#include "libpspp/str.h" #include "output/table-item.h" +#include "output/tab.h" #include "gl/xalloc.h" @@ -128,6 +134,26 @@ table_set_nr (struct table *table, int nr) table->n[TABLE_VERT] = nr; } +struct area_style * +area_style_clone (struct pool *pool, const struct area_style *old) +{ + struct area_style *new = pool_malloc (pool, sizeof *new); + *new = *old; + if (new->font_style.typeface) + new->font_style.typeface = pool_strdup (pool, new->font_style.typeface); + return new; +} + +void +area_style_free (struct area_style *style) +{ + if (style) + { + free (style->font_style.typeface); + free (style); + } +} + /* Initializes CELL with the contents of the table cell at column X and row Y within TABLE. When CELL is no longer needed, the caller is responsible for freeing it by calling table_cell_free(CELL). @@ -139,6 +165,10 @@ table_get_cell (const struct table *table, int x, int y, { assert (x >= 0 && x < table->n[TABLE_HORZ]); assert (y >= 0 && y < table->n[TABLE_VERT]); + + static const struct area_style default_style = AREA_STYLE_INITIALIZER; + cell->style = &default_style; + table->klass->get_cell (table, x, y, cell); } @@ -189,234 +219,231 @@ table_cell_free (struct table_cell *cell) between that cell and cell (0,1); and so on, up to (0,NR), which runs horizontally below cell (0,NR-1). */ int -table_get_rule (const struct table *table, enum table_axis axis, int x, int y) +table_get_rule (const struct table *table, enum table_axis axis, int x, int y, + struct cell_color *color) { assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ)); assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT)); - return table->klass->get_rule (table, axis, x, y); + *color = (struct cell_color) CELL_COLOR_BLACK; + return table->klass->get_rule (table, axis, x, y, color); } - -struct table_unshared - { - struct table table; - struct table *subtable; - }; -static const struct table_class table_unshared_class; - -/* Takes ownership of TABLE and returns a table with the same contents but - which is guaranteed not to be shared (as returned by table_is_shared()). - - If TABLE is unshared, just returns TABLE. - - The only real use for this function is to create a copy of TABLE in which - the headers can be adjusted, which is a pretty specialized use case. */ -struct table * -table_unshare (struct table *table) +void +table_cell_format_footnote_markers (const struct table_cell *cell, + struct string *s) { - if (!table_is_shared (table)) - return table; - else + for (size_t i = 0; i < cell->n_footnotes; i++) { - struct table_unshared *tiu = xmalloc (sizeof *tiu); - table_init (&tiu->table, &table_unshared_class); - table_set_nc (&tiu->table, table_nc (table)); - table_set_nr (&tiu->table, table_nr (table)); - table_set_hl (&tiu->table, table_hl (table)); - table_set_hr (&tiu->table, table_hr (table)); - table_set_ht (&tiu->table, table_ht (table)); - table_set_hb (&tiu->table, table_hb (table)); - tiu->subtable = table; - return &tiu->table; + if (i) + ds_put_byte (s, ','); + ds_put_cstr (s, cell->footnotes[i]->marker); } } -static struct table_unshared * -table_unshared_cast (const struct table *table) +static const struct footnote ** +add_footnotes (const struct footnote **refs, size_t n_refs, + const struct footnote **footnotes, size_t *allocated, size_t *n) { - assert (table->klass == &table_unshared_class); - return UP_CAST (table, struct table_unshared, table); + for (size_t i = 0; i < n_refs; i++) + { + const struct footnote *f = refs[i]; + if (f->idx >= *allocated) + { + size_t new_allocated = (f->idx + 1) * 2; + footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes); + while (*allocated < new_allocated) + footnotes[(*allocated)++] = NULL; + } + footnotes[f->idx] = f; + if (f->idx >= *n) + *n = f->idx + 1; + } + return footnotes; } -static void -table_unshared_destroy (struct table *tiu_) +size_t +table_collect_footnotes (const struct table_item *item, + const struct footnote ***footnotesp) { - struct table_unshared *tiu = table_unshared_cast (tiu_); - table_unref (tiu->subtable); - free (tiu); -} + const struct footnote **footnotes = NULL; + size_t allocated = 0; + size_t n = 0; -static void -table_unshared_get_cell (const struct table *tiu_, int x, int y, - struct table_cell *cell) -{ - struct table_unshared *tiu = table_unshared_cast (tiu_); - table_get_cell (tiu->subtable, x, y, cell); -} + struct table *t = item->table; + for (int y = 0; y < table_nr (t); y++) + { + struct table_cell cell; + for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1]) + { + table_get_cell (t, x, y, &cell); + + if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0]) + footnotes = add_footnotes (cell.footnotes, cell.n_footnotes, + footnotes, &allocated, &n); + table_cell_free (&cell); + } + } -static int -table_unshared_get_rule (const struct table *tiu_, - enum table_axis axis, int x, int y) -{ - struct table_unshared *tiu = table_unshared_cast (tiu_); - return table_get_rule (tiu->subtable, axis, x, y); -} + const struct table_item_text *title = table_item_get_title (item); + if (title) + footnotes = add_footnotes (title->footnotes, title->n_footnotes, + footnotes, &allocated, &n); -static const struct table_class table_unshared_class = - { - table_unshared_destroy, - table_unshared_get_cell, - table_unshared_get_rule, - NULL, /* paste */ - NULL, /* select */ - }; - -struct table_string - { - struct table table; - char *string; - unsigned int options; - }; + const struct table_item_layers *layers = table_item_get_layers (item); + if (layers) + { + for (size_t i = 0; i < layers->n_layers; i++) + footnotes = add_footnotes (layers->layers[i].footnotes, + layers->layers[i].n_footnotes, + footnotes, &allocated, &n); + } -static const struct table_class table_string_class; + const struct table_item_text *caption = table_item_get_caption (item); + if (caption) + footnotes = add_footnotes (caption->footnotes, caption->n_footnotes, + footnotes, &allocated, &n); -/* Returns a table that contains a single cell, whose contents are S with - options OPTIONS (a combination of TAB_* values). */ -struct table * -table_from_string (unsigned int options, const char *s) + size_t n_nonnull = 0; + for (size_t i = 0; i < n; i++) + if (footnotes[i]) + footnotes[n_nonnull++] = footnotes[i]; + + *footnotesp = footnotes; + return n_nonnull; +} + +const char * +table_halign_to_string (enum table_halign halign) { - struct table_string *ts = xmalloc (sizeof *ts); - table_init (&ts->table, &table_string_class); - ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1; - ts->string = xstrdup (s); - ts->options = options; - return &ts->table; + switch (halign) + { + case TABLE_HALIGN_LEFT: return "left"; + case TABLE_HALIGN_CENTER: return "center"; + case TABLE_HALIGN_RIGHT: return "right"; + case TABLE_HALIGN_DECIMAL: return "decimal"; + case TABLE_HALIGN_MIXED: return "mixed"; + default: return "**error**"; + } } -static struct table_string * -table_string_cast (const struct table *table) +const char * +table_valign_to_string (enum table_valign valign) { - assert (table->klass == &table_string_class); - return UP_CAST (table, struct table_string, table); + switch (valign) + { + case TABLE_VALIGN_TOP: return "top"; + case TABLE_VALIGN_CENTER: return "center"; + case TABLE_VALIGN_BOTTOM: return "bottom"; + default: return "**error**"; + } } -static void -table_string_destroy (struct table *ts_) +enum table_halign +table_halign_interpret (enum table_halign halign, bool numeric) { - struct table_string *ts = table_string_cast (ts_); - free (ts->string); - free (ts); + switch (halign) + { + case TABLE_HALIGN_LEFT: + case TABLE_HALIGN_CENTER: + case TABLE_HALIGN_RIGHT: + return halign; + + case TABLE_HALIGN_MIXED: + return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT; + + case TABLE_HALIGN_DECIMAL: + return TABLE_HALIGN_DECIMAL; + + default: + NOT_REACHED (); + } } -static void -table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED, - struct table_cell *cell) +void +font_style_copy (struct font_style *dst, const struct font_style *src) { - struct table_string *ts = table_string_cast (ts_); - cell->d[TABLE_HORZ][0] = 0; - cell->d[TABLE_HORZ][1] = 1; - cell->d[TABLE_VERT][0] = 0; - cell->d[TABLE_VERT][1] = 1; - cell->contents = &cell->inline_contents; - cell->inline_contents.options = ts->options; - cell->inline_contents.text = ts->string; - cell->inline_contents.table = NULL; - cell->inline_contents.n_footnotes = 0; - cell->n_contents = 1; - cell->destructor = NULL; + *dst = *src; + if (dst->typeface) + dst->typeface = xstrdup (dst->typeface); } - -static int -table_string_get_rule (const struct table *ts UNUSED, - enum table_axis axis UNUSED, int x UNUSED, int y UNUSED) +void +font_style_uninit (struct font_style *font) { - return TAL_0; + if (font) + free (font->typeface); } -static const struct table_class table_string_class = - { - table_string_destroy, - table_string_get_cell, - table_string_get_rule, - NULL, /* paste */ - NULL, /* select */ - }; - -struct table_nested - { - struct table table; - struct table_item *inner; - }; - -static const struct table_class table_nested_class; - -/* Creates and returns a table with a single cell that contains INNER. - Takes ownership of INNER. */ -struct table * -table_create_nested (struct table *inner) +void +area_style_copy (struct area_style *dst, const struct area_style *src) { - return table_create_nested_item (table_item_create (inner, NULL)); + font_style_copy (&dst->font_style, &src->font_style); + dst->cell_style = src->cell_style; } -/* Creates and returns a table with a single cell that contains INNER. - Takes ownership of INNER. */ -struct table * -table_create_nested_item (struct table_item *inner) +void +area_style_uninit (struct area_style *area) { - struct table_nested *tn = xmalloc (sizeof *tn); - table_init (&tn->table, &table_nested_class); - tn->table.n[TABLE_HORZ] = tn->table.n[TABLE_VERT] = 1; - tn->inner = table_item_ref (inner); - return &tn->table; + if (area) + font_style_uninit (&area->font_style); } -static struct table_nested * -table_nested_cast (const struct table *table) +const char * +table_stroke_to_string (enum table_stroke stroke) { - assert (table->klass == &table_nested_class); - return UP_CAST (table, struct table_nested, table); + switch (stroke) + { + case TABLE_STROKE_NONE: return "none"; + case TABLE_STROKE_SOLID: return "solid"; + case TABLE_STROKE_DASHED: return "dashed"; + case TABLE_STROKE_THICK: return "thick"; + case TABLE_STROKE_THIN: return "thin"; + case TABLE_STROKE_DOUBLE: return "double"; + default: + return "**error**"; + } } -static void -table_nested_destroy (struct table *tn_) +void +cell_color_dump (const struct cell_color *c) { - struct table_nested *tn = table_nested_cast (tn_); - table_item_unref (tn->inner); - free (tn); + if (c->alpha != 255) + printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha); + else + printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b); } -static void -table_nested_get_cell (const struct table *tn_, int x UNUSED, int y UNUSED, - struct table_cell *cell) +void +font_style_dump (const struct font_style *f) { - struct table_nested *tn = table_nested_cast (tn_); - cell->d[TABLE_HORZ][0] = 0; - cell->d[TABLE_HORZ][1] = 1; - cell->d[TABLE_VERT][0] = 0; - cell->d[TABLE_VERT][1] = 1; - cell->contents = &cell->inline_contents; - cell->inline_contents.options = TAB_LEFT; - cell->inline_contents.text = NULL; - cell->inline_contents.table = tn->inner; - cell->inline_contents.n_footnotes = 0; - cell->n_contents = 1; - cell->destructor = NULL; + printf ("%s %dpx ", f->typeface, f->size); + cell_color_dump (&f->fg[0]); + putchar ('/'); + cell_color_dump (&f->bg[0]); + if (!cell_color_equal (&f->fg[0], &f->fg[1]) + || !cell_color_equal (&f->bg[0], &f->bg[1])) + { + printf (" alt="); + cell_color_dump (&f->fg[1]); + putchar ('/'); + cell_color_dump (&f->bg[1]); + } + if (f->bold) + fputs (" bold", stdout); + if (f->italic) + fputs (" italic", stdout); + if (f->underline) + fputs (" underline", stdout); } -static int -table_nested_get_rule (const struct table *tn UNUSED, - enum table_axis axis UNUSED, int x UNUSED, int y UNUSED) +void +cell_style_dump (const struct cell_style *c) { - return TAL_0; + fputs (table_halign_to_string (c->halign), stdout); + if (c->halign == TABLE_HALIGN_DECIMAL) + printf ("(%.2gpx)", c->decimal_offset); + printf (" %s", table_valign_to_string (c->valign)); + printf (" %d,%d,%d,%dpx", + c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1], + c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]); } - -static const struct table_class table_nested_class = - { - table_nested_destroy, - table_nested_get_cell, - table_nested_get_rule, - NULL, /* paste */ - NULL, /* select */ - }; -