#include "output/table-provider.h"
#include <assert.h>
+#include <inttypes.h>
#include <stdlib.h>
+#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 "gl/xalloc.h"
table->n[TABLE_VERT] = nr;
}
\f
+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).
{
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);
}
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);
+}
+
+void
+table_cell_format_footnote_markers (const struct table_cell *cell,
+ struct string *s)
+{
+ for (size_t i = 0; i < cell->n_footnotes; i++)
+ {
+ if (i)
+ ds_put_byte (s, ',');
+ ds_put_cstr (s, cell->footnotes[i]->marker);
+ }
+}
+
+static const struct footnote **
+add_footnotes (const struct footnote **refs, size_t n_refs,
+ const struct footnote **footnotes, size_t *allocated, size_t *n)
+{
+ 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;
+}
+
+size_t
+table_collect_footnotes (const struct table_item *item,
+ const struct footnote ***footnotesp)
+{
+ const struct footnote **footnotes = NULL;
+ size_t allocated = 0;
+ size_t n = 0;
+
+ 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);
+ }
+ }
+
+ const struct table_item_text *title = table_item_get_title (item);
+ if (title)
+ footnotes = add_footnotes (title->footnotes, title->n_footnotes,
+ footnotes, &allocated, &n);
+
+ const struct table_item_text *caption = table_item_get_caption (item);
+ if (caption)
+ footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
+ footnotes, &allocated, &n);
+
+ *footnotesp = footnotes;
+ return n;
}
\f
struct table_unshared
static int
table_unshared_get_rule (const struct table *tiu_,
- enum table_axis axis, int x, int y)
+ enum table_axis axis, int x, int y,
+ struct cell_color *color)
{
struct table_unshared *tiu = table_unshared_cast (tiu_);
- return table_get_rule (tiu->subtable, axis, x, y);
+ return table_get_rule (tiu->subtable, axis, x, y, color);
}
static const struct table_class table_unshared_class =
{
struct table table;
char *string;
- unsigned int options;
+ enum table_halign halign;
};
static const struct table_class table_string_class;
/* 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)
+table_from_string (enum table_halign halign, const char *s)
{
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;
+ ts->halign = halign;
return &ts->table;
}
table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
struct table_cell *cell)
{
+ static const struct area_style styles[] = {
+#define S(H) [H] = { AREA_STYLE_INITIALIZER__, .cell_style.halign = H }
+ S(TABLE_HALIGN_LEFT),
+ S(TABLE_HALIGN_CENTER),
+ S(TABLE_HALIGN_RIGHT),
+ S(TABLE_HALIGN_MIXED),
+ S(TABLE_HALIGN_DECIMAL),
+ };
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->options = 0;
+ cell->style = &styles[table_halign_interpret (ts->halign, false)];
+ cell->text = ts->string;
+ cell->n_footnotes = 0;
cell->destructor = NULL;
}
static int
table_string_get_rule (const struct table *ts UNUSED,
- enum table_axis axis UNUSED, int x UNUSED, int y UNUSED)
+ enum table_axis axis UNUSED, int x UNUSED, int y UNUSED,
+ struct cell_color *color UNUSED)
{
return TAL_0;
}
NULL, /* select */
};
\f
-struct table_nested
- {
- struct table table;
- struct table_item *inner;
- };
+const char *
+table_halign_to_string (enum table_halign halign)
+{
+ 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 const struct table_class table_nested_class;
+const char *
+table_valign_to_string (enum table_valign valign)
+{
+ switch (valign)
+ {
+ case TABLE_VALIGN_TOP: return "top";
+ case TABLE_VALIGN_CENTER: return "center";
+ case TABLE_VALIGN_BOTTOM: return "bottom";
+ default: return "**error**";
+ }
+}
-/* Creates and returns a table with a single cell that contains INNER.
- Takes ownership of INNER. */
-struct table *
-table_create_nested (struct table *inner)
+enum table_halign
+table_halign_interpret (enum table_halign halign, bool numeric)
{
- return table_create_nested_item (table_item_create (inner, NULL, NULL));
+ 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 ();
+ }
}
-/* 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
+font_style_copy (struct font_style *dst, const struct font_style *src)
{
- 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 = inner;
- return &tn->table;
+ *dst = *src;
+ if (dst->typeface)
+ dst->typeface = xstrdup (dst->typeface);
}
-static struct table_nested *
-table_nested_cast (const struct table *table)
+void
+font_style_uninit (struct font_style *font)
{
- assert (table->klass == &table_nested_class);
- return UP_CAST (table, struct table_nested, table);
+ if (font)
+ free (font->typeface);
}
-static void
-table_nested_destroy (struct table *tn_)
+void
+area_style_copy (struct area_style *dst, const struct area_style *src)
{
- struct table_nested *tn = table_nested_cast (tn_);
- table_item_unref (tn->inner);
- free (tn);
+ font_style_copy (&dst->font_style, &src->font_style);
+ dst->cell_style = src->cell_style;
}
-static void
-table_nested_get_cell (const struct table *tn_, int x UNUSED, int y UNUSED,
- struct table_cell *cell)
+void
+area_style_uninit (struct area_style *area)
{
- 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;
+ if (area)
+ font_style_uninit (&area->font_style);
}
-static int
-table_nested_get_rule (const struct table *tn UNUSED,
- enum table_axis axis UNUSED, int x UNUSED, int y UNUSED)
+const char *
+table_stroke_to_string (enum table_stroke stroke)
{
- return TAL_0;
+ 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 const struct table_class table_nested_class =
- {
- table_nested_destroy,
- table_nested_get_cell,
- table_nested_get_rule,
- NULL, /* paste */
- NULL, /* select */
- };
+void
+cell_color_dump (const struct cell_color *c)
+{
+ 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);
+}
+
+void
+font_style_dump (const struct font_style *f)
+{
+ 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);
+}
+void
+cell_style_dump (const struct cell_style *c)
+{
+ 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]);
+}