From 6499a5881aeaa1e53b761f624e341652015d795e Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 21 Nov 2018 09:32:23 -0800 Subject: [PATCH] output: Add support for colors for rules. --- src/output/ascii.c | 6 ++- src/output/cairo.c | 73 ++++++++++++++++++++++------------- src/output/html.c | 11 ++++-- src/output/render.c | 20 ++++++---- src/output/render.h | 3 +- src/output/tab.c | 13 +++++-- src/output/tab.h | 11 ++++-- src/output/table-casereader.c | 3 +- src/output/table-paste.c | 15 +++---- src/output/table-provider.h | 6 ++- src/output/table-select.c | 4 +- src/output/table-stomp.c | 6 ++- src/output/table-transpose.c | 4 +- src/output/table.c | 14 ++++--- 14 files changed, 121 insertions(+), 68 deletions(-) diff --git a/src/output/ascii.c b/src/output/ascii.c index 72c628871c..c2c5dd54fd 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -214,7 +214,8 @@ static int parse_page_size (struct driver_option *); static bool ascii_open_page (struct ascii_driver *); static void ascii_draw_line (void *, int bb[TABLE_N_AXES][2], - enum render_line_style styles[TABLE_N_AXES][2]); + enum render_line_style styles[TABLE_N_AXES][2], + struct cell_color colors[TABLE_N_AXES][2]); static void ascii_measure_cell_width (void *, const struct table_cell *, int *min, int *max); static int ascii_measure_cell_height (void *, const struct table_cell *, @@ -533,7 +534,8 @@ static void ascii_layout_cell (struct ascii_driver *, static void ascii_draw_line (void *a_, int bb[TABLE_N_AXES][2], - enum render_line_style styles[TABLE_N_AXES][2]) + enum render_line_style styles[TABLE_N_AXES][2], + struct cell_color colors[TABLE_N_AXES][2] UNUSED) { struct ascii_driver *a = a_; char mbchar[6]; diff --git a/src/output/cairo.c b/src/output/cairo.c index b3ab780ba6..49d8f0bc88 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -166,7 +166,8 @@ static void xr_driver_destroy_fsm (struct xr_driver *); static void xr_driver_run_fsm (struct xr_driver *); static void xr_draw_line (void *, int bb[TABLE_N_AXES][2], - enum render_line_style styles[TABLE_N_AXES][2]); + enum render_line_style styles[TABLE_N_AXES][2], + struct cell_color colors[TABLE_N_AXES][2]); static void xr_measure_cell_width (void *, const struct table_cell *, int *min, int *max); static int xr_measure_cell_height (void *, const struct table_cell *, @@ -658,9 +659,12 @@ xr_layout_cell (struct xr_driver *, const struct table_cell *, int *width, int *height, int *brk); static void -dump_line (struct xr_driver *xr, int x0, int y0, int x1, int y1, int style) +dump_line (struct xr_driver *xr, int x0, int y0, int x1, int y1, int style, + const struct cell_color *color) { cairo_new_path (xr->cairo); + cairo_set_source_rgb (xr->cairo, + color->r / 255.0, color->g / 255.0, color->b / 255.0); cairo_set_line_width ( xr->cairo, xr_to_pt (style == RENDER_LINE_THICK ? xr->line_width * 2 @@ -702,16 +706,19 @@ fill_rectangle (struct xr_driver *xr, int x0, int y0, int x1, int y1) static void horz_line (struct xr_driver *xr, int x0, int x1, int x2, int x3, int y, enum render_line_style left, enum render_line_style right, + const struct cell_color *left_color, + const struct cell_color *right_color, bool shorten) { - if (left != RENDER_LINE_NONE && right != RENDER_LINE_NONE && !shorten) - dump_line (xr, x0, y, x3, y, left); + if (left != RENDER_LINE_NONE && right != RENDER_LINE_NONE && !shorten + && cell_color_equal (left_color, right_color)) + dump_line (xr, x0, y, x3, y, left, left_color); else { if (left != RENDER_LINE_NONE) - dump_line (xr, x0, y, shorten ? x1 : x2, y, left); + dump_line (xr, x0, y, shorten ? x1 : x2, y, left, left_color); if (right != RENDER_LINE_NONE) - dump_line (xr, shorten ? x2 : x1, y, x3, y, right); + dump_line (xr, shorten ? x2 : x1, y, x3, y, right, right_color); } } @@ -722,22 +729,26 @@ horz_line (struct xr_driver *xr, int x0, int x1, int x2, int x3, int y, static void vert_line (struct xr_driver *xr, int y0, int y1, int y2, int y3, int x, enum render_line_style top, enum render_line_style bottom, + const struct cell_color *top_color, + const struct cell_color *bottom_color, bool shorten) { - if (top != RENDER_LINE_NONE && bottom != RENDER_LINE_NONE && !shorten) - dump_line (xr, x, y0, x, y3, top); + if (top != RENDER_LINE_NONE && bottom != RENDER_LINE_NONE && !shorten + && cell_color_equal (top_color, bottom_color)) + dump_line (xr, x, y0, x, y3, top, top_color); else { if (top != RENDER_LINE_NONE) - dump_line (xr, x, y0, x, shorten ? y1 : y2, top); + dump_line (xr, x, y0, x, shorten ? y1 : y2, top, top_color); if (bottom != RENDER_LINE_NONE) - dump_line (xr, x, shorten ? y2 : y1, x, y3, bottom); + dump_line (xr, x, shorten ? y2 : y1, x, y3, bottom, bottom_color); } } static void xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2], - enum render_line_style styles[TABLE_N_AXES][2]) + enum render_line_style styles[TABLE_N_AXES][2], + struct cell_color colors[TABLE_N_AXES][2]) { const int x0 = bb[H][0]; const int y0 = bb[V][0]; @@ -745,8 +756,15 @@ xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2], const int y3 = bb[V][1]; const int top = styles[H][0]; const int bottom = styles[H][1]; - const int start_of_line = render_direction_rtl() ? styles[V][1]: styles[V][0]; - const int end_of_line = render_direction_rtl() ? styles[V][0]: styles[V][1]; + + int start_side = render_direction_rtl(); + int end_side = !start_side; + const int start_of_line = styles[V][start_side]; + const int end_of_line = styles[V][end_side]; + const struct cell_color *top_color = &colors[H][0]; + const struct cell_color *bottom_color = &colors[H][1]; + const struct cell_color *start_color = &colors[V][start_side]; + const struct cell_color *end_color = &colors[V][end_side]; /* The algorithm here is somewhat subtle, to allow it to handle all the kinds of intersections that we need. @@ -830,19 +848,25 @@ xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2], int y2 = yc + vert_line_ofs; if (!double_horz) - horz_line (xr, x0, x1, x2, x3, yc, start_of_line, end_of_line, shorten_yc_line); + horz_line (xr, x0, x1, x2, x3, yc, start_of_line, end_of_line, + start_color, end_color, shorten_yc_line); else { - horz_line (xr, x0, x1, x2, x3, y1, start_of_line, end_of_line, shorten_y1_lines); - horz_line (xr, x0, x1, x2, x3, y2, start_of_line, end_of_line, shorten_y2_lines); + horz_line (xr, x0, x1, x2, x3, y1, start_of_line, end_of_line, + start_color, end_color, shorten_y1_lines); + horz_line (xr, x0, x1, x2, x3, y2, start_of_line, end_of_line, + start_color, end_color, shorten_y2_lines); } if (!double_vert) - vert_line (xr, y0, y1, y2, y3, xc, top, bottom, shorten_xc_line); + vert_line (xr, y0, y1, y2, y3, xc, top, bottom, top_color, bottom_color, + shorten_xc_line); else { - vert_line (xr, y0, y1, y2, y3, x1, top, bottom, shorten_x1_lines); - vert_line (xr, y0, y1, y2, y3, x2, top, bottom, shorten_x2_lines); + vert_line (xr, y0, y1, y2, y3, x1, top, bottom, top_color, bottom_color, + shorten_x1_lines); + vert_line (xr, y0, y1, y2, y3, x2, top, bottom, top_color, bottom_color, + shorten_x2_lines); } } @@ -1172,14 +1196,9 @@ xr_layout_cell_text (struct xr_driver *xr, if (0) { if (best && !xr->nest) - { - cairo_save (xr->cairo); - cairo_set_source_rgb (xr->cairo, 0, 1, 0); - dump_line (xr, -xr->left_margin, best, - xr->width + xr->right_margin, best, - RENDER_LINE_SINGLE); - cairo_restore (xr->cairo); - } + dump_line (xr, -xr->left_margin, best, + xr->width + xr->right_margin, best, + RENDER_LINE_SINGLE, &CELL_COLOR (0, 255, 0)); } } diff --git a/src/output/html.c b/src/output/html.c index f9d45736ef..7cc2fecab7 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -540,21 +540,24 @@ html_output_table (struct html_driver *html, const struct table_item *item) /* Cell borders. */ int n_borders = 0; - top = table_get_rule (t, TABLE_VERT, x, y); + struct cell_color color; + top = table_get_rule (t, TABLE_VERT, x, y, &color); put_border (html->file, &n_borders, top, "top"); if (y + rowspan == table_nr (t)) { - bottom = table_get_rule (t, TABLE_VERT, x, y + rowspan); + bottom = table_get_rule (t, TABLE_VERT, x, y + rowspan, + &color); put_border (html->file, &n_borders, bottom, "bottom"); } - left = table_get_rule (t, TABLE_HORZ, x, y); + left = table_get_rule (t, TABLE_HORZ, x, y, &color); put_border (html->file, &n_borders, left, "left"); if (x + colspan == table_nc (t)) { - right = table_get_rule (t, TABLE_HORZ, x + colspan, y); + right = table_get_rule (t, TABLE_HORZ, x + colspan, y, + &color); put_border (html->file, &n_borders, right, "right"); } diff --git a/src/output/render.c b/src/output/render.c index 418193b87e..c3a59a6c42 100644 --- a/src/output/render.c +++ b/src/output/render.c @@ -488,10 +488,11 @@ measure_rule (const struct render_params *params, const struct table *table, /* Determine all types of rules that are present, as a bitmap in 'rules' where rule type 't' is present if bit 2**t is set. */ + struct cell_color color; rules = 0; d[a] = z; for (d[b] = 0; d[b] < table->n[b]; d[b]++) - rules |= 1u << table_get_rule (table, a, d[H], d[V]); + rules |= 1u << table_get_rule (table, a, d[H], d[V], &color); /* Turn off TAL_NONE because it has width 0 and we needn't bother. However, if the device doesn't support margins, make sure that there is at least a @@ -870,10 +871,11 @@ render_page_get_best_breakpoint (const struct render_page *page, int height) static inline enum render_line_style get_rule (const struct render_page *page, enum table_axis axis, - const int d[TABLE_N_AXES]) + const int d[TABLE_N_AXES], struct cell_color *color) { return rule_to_render_type (table_get_rule (page->table, - axis, d[H] / 2, d[V] / 2)); + axis, d[H] / 2, d[V] / 2, + color)); } static bool @@ -904,6 +906,7 @@ render_rule (const struct render_page *page, const int ofs[TABLE_N_AXES], const int d[TABLE_N_AXES]) { enum render_line_style styles[TABLE_N_AXES][2]; + struct cell_color colors[TABLE_N_AXES][2]; enum table_axis a; for (a = 0; a < TABLE_N_AXES; a++) @@ -925,14 +928,17 @@ render_rule (const struct render_page *page, const int ofs[TABLE_N_AXES], e[H] = d[H]; e[V] = d[V]; e[b]--; - styles[a][0] = get_rule (page, a, e); + styles[a][0] = get_rule (page, a, e, &colors[a][0]); } if (d[b] / 2 < page->table->n[b]) - styles[a][1] = get_rule (page, a, d); + styles[a][1] = get_rule (page, a, d, &colors[a][1]); } else - styles[a][0] = styles[a][1] = get_rule (page, a, d); + { + styles[a][0] = styles[a][1] = get_rule (page, a, d, &colors[a][0]); + colors[a][1] = colors[a][0]; + } } if (styles[H][0] != RENDER_LINE_NONE || styles[H][1] != RENDER_LINE_NONE @@ -950,7 +956,7 @@ render_rule (const struct render_page *page, const int ofs[TABLE_N_AXES], } bb[V][0] = ofs[V] + page->cp[V][d[V]]; bb[V][1] = ofs[V] + page->cp[V][d[V] + 1]; - page->params->draw_line (page->params->aux, bb, styles); + page->params->draw_line (page->params->aux, bb, styles, colors); } } diff --git a/src/output/render.h b/src/output/render.h index f04eb79005..cceea9e723 100644 --- a/src/output/render.h +++ b/src/output/render.h @@ -93,7 +93,8 @@ struct render_params STYLES[TABLE_VERT][0]: style of line from left of BB to its center. STYLES[TABLE_VERT][1]: style of line from right of BB to its center. */ void (*draw_line) (void *aux, int bb[TABLE_N_AXES][2], - enum render_line_style styles[TABLE_N_AXES][2]); + enum render_line_style styles[TABLE_N_AXES][2], + struct cell_color colors[TABLE_N_AXES][2]); /* Draws CELL within bounding box BB. CLIP is the same as BB (the common case) or a subregion enclosed by BB. In the latter case only the part diff --git a/src/output/tab.c b/src/output/tab.c index a158b22979..23fccd6f9c 100644 --- a/src/output/tab.c +++ b/src/output/tab.c @@ -106,6 +106,7 @@ tab_create (int nc, int nr) t->fmtmap[RC_OTHER] = *settings_get_format (); memset (t->styles, 0, sizeof t->styles); + memset (t->rule_colors, 0, sizeof t->rule_colors); t->col_ofs = t->row_ofs = 0; @@ -833,11 +834,17 @@ tab_get_cell (const struct table *table, int x, int y, } static int -tab_get_rule (const struct table *table, enum table_axis axis, int x, int y) +tab_get_rule (const struct table *table, enum table_axis axis, int x, int y, + struct cell_color *color) { const struct tab_table *t = tab_cast (table); - return (axis == TABLE_VERT - ? t->rh[x + t->cf * y] : t->rv[x + (t->cf + 1) * y]); + uint8_t raw = (axis == TABLE_VERT + ? t->rh[x + t->cf * y] : t->rv[x + (t->cf + 1) * y]); + struct cell_color *p = t->rule_colors[(raw & TAB_RULE_STYLE_MASK) + >> TAB_RULE_STYLE_SHIFT]; + if (p) + *color = *p; + return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT; } static const struct table_class tab_table_class = { diff --git a/src/output/tab.h b/src/output/tab.h index 43f0278964..178607aa2b 100644 --- a/src/output/tab.h +++ b/src/output/tab.h @@ -54,6 +54,12 @@ enum result_class #define TAB_STYLE_MASK (7u << (TAB_FIRST_AVAILABLE + 3)) #define TAB_STYLE_SHIFT (TAB_FIRST_AVAILABLE + 3) +/* Rule masks. */ +#define TAB_RULE_TYPE_MASK 7 +#define TAB_RULE_TYPE_SHIFT 0 +#define TAB_RULE_STYLE_MASK (31 << TAB_RULE_STYLE_SHIFT) +#define TAB_RULE_STYLE_SHIFT 3 + /* A table. */ struct tab_table { @@ -72,13 +78,12 @@ struct tab_table points to a struct tab_joined_cell. */ void **cc; /* Cell contents; void *[nr][nc]. */ unsigned short *ct; /* Cell types; unsigned short[nr][nc]. */ + struct cell_style *styles[8]; /* Rules. */ unsigned char *rh; /* Horiz rules; unsigned char[nr+1][nc]. */ unsigned char *rv; /* Vert rules; unsigned char[nr][nc+1]. */ - - /* Cell styles. */ - struct cell_style *styles[8]; + struct cell_color *rule_colors[32]; /* X and Y offsets. */ int col_ofs, row_ofs; diff --git a/src/output/table-casereader.c b/src/output/table-casereader.c index 5acb1a928d..ecd85a1df4 100644 --- a/src/output/table-casereader.c +++ b/src/output/table-casereader.c @@ -142,7 +142,8 @@ table_casereader_get_cell (const struct table *t, int x, int y, static int table_casereader_get_rule (const struct table *t, enum table_axis axis, - int x UNUSED, int y) + int x UNUSED, int y, + struct cell_color *color UNUSED) { struct table_casereader *tc = table_casereader_cast (t); if (axis == TABLE_VERT) diff --git a/src/output/table-paste.c b/src/output/table-paste.c index c1054d1369..05c8987ce6 100644 --- a/src/output/table-paste.c +++ b/src/output/table-paste.c @@ -227,7 +227,8 @@ table_paste_get_cell (const struct table *t, int x, int y, static int table_paste_get_rule (const struct table *t, - enum table_axis axis, int x, int y) + enum table_axis axis, int x, int y, + struct cell_color *color) { struct table_paste *tp = table_paste_cast (t); int h = tp->orientation == TABLE_HORZ ? x : y; @@ -241,9 +242,9 @@ table_paste_get_rule (const struct table *t, ps = paste_subtable_lookup (tp, h == 0 ? 0 : h - 1, &start); if (tp->orientation == TABLE_HORZ) /* XXX */ - r = table_get_rule (ps->table, axis, h - start, k); + r = table_get_rule (ps->table, axis, h - start, k, color); else - r = table_get_rule (ps->table, axis, k, h - start); + r = table_get_rule (ps->table, axis, k, h - start, color); if (h == start + tower_node_get_size (&ps->node)) { struct tower_node *ps2_ = tower_next (&tp->subtables, &ps->node); @@ -253,9 +254,9 @@ table_paste_get_rule (const struct table *t, int r2; if (tp->orientation == TABLE_HORZ) /* XXX */ - r2 = table_get_rule (ps2->table, axis, 0, k); + r2 = table_get_rule (ps2->table, axis, 0, k, color); else - r2 = table_get_rule (ps2->table, axis, k, 0); + r2 = table_get_rule (ps2->table, axis, k, 0, color); return table_rule_combine (r, r2); } } @@ -265,9 +266,9 @@ table_paste_get_rule (const struct table *t, { ps = paste_subtable_lookup (tp, h, &start); if (tp->orientation == TABLE_HORZ) /* XXX */ - return table_get_rule (ps->table, axis, h - start, k); + return table_get_rule (ps->table, axis, h - start, k, color); else - return table_get_rule (ps->table, axis, k, h - start); + return table_get_rule (ps->table, axis, k, h - start, color); } } diff --git a/src/output/table-provider.h b/src/output/table-provider.h index ae7f77d420..d875462c9c 100644 --- a/src/output/table-provider.h +++ b/src/output/table-provider.h @@ -192,7 +192,8 @@ struct table_class See table_get_rule() in table.c for a detailed explanation of the meaning of AXIS and X and Y, including a diagram. */ int (*get_rule) (const struct table *table, - enum table_axis axis, int x, int y); + enum table_axis axis, int x, int y, + struct cell_color *color); /* This function is optional and most table classes will not implement it. @@ -248,7 +249,8 @@ void table_set_nr (struct table *, int nr); /* For use primarily by output drivers. */ void table_get_cell (const struct table *, int x, int y, struct table_cell *); -int table_get_rule (const struct table *, enum table_axis, int x, int y); +int table_get_rule (const struct table *, enum table_axis, int x, int y, + struct cell_color *); size_t table_collect_footnotes (const struct table_item *, const struct footnote ***); diff --git a/src/output/table-select.c b/src/output/table-select.c index 5bbc8caa1e..b7e431a28f 100644 --- a/src/output/table-select.c +++ b/src/output/table-select.c @@ -194,12 +194,12 @@ table_select_get_cell (const struct table *ti, int x, int y, static int table_select_get_rule (const struct table *ti, enum table_axis axis, - int x, int y) + int x, int y, struct cell_color *color) { struct table_select *ts = table_select_cast (ti); return table_get_rule (ts->subtable, axis, x + ts->ofs[TABLE_HORZ], - y + ts->ofs[TABLE_VERT]); + y + ts->ofs[TABLE_VERT], color); } static struct table * diff --git a/src/output/table-stomp.c b/src/output/table-stomp.c index e9df26a95f..075a2d2ba2 100644 --- a/src/output/table-stomp.c +++ b/src/output/table-stomp.c @@ -146,12 +146,14 @@ table_stomp_get_cell (const struct table *t, int x, int y UNUSED, static int table_stomp_get_rule (const struct table *t, - enum table_axis axis, int x, int y) + enum table_axis axis, int x, int y, + struct cell_color *color) { struct table_stomp *ts = table_stomp_cast (t); return table_get_rule (ts->subtable, axis, x, - axis == H || y == 0 ? y : ts->subtable->n[V]); + axis == H || y == 0 ? y : ts->subtable->n[V], + color); } static const struct table_class table_stomp_class = diff --git a/src/output/table-transpose.c b/src/output/table-transpose.c index f2db939f5a..aa617b3aaa 100644 --- a/src/output/table-transpose.c +++ b/src/output/table-transpose.c @@ -103,10 +103,10 @@ table_transpose_get_cell (const struct table *ti, int x, int y, static int table_transpose_get_rule (const struct table *ti, enum table_axis axis, - int x, int y) + int x, int y, struct cell_color *color) { struct table_transpose *tt = table_transpose_cast (ti); - return table_get_rule (tt->subtable, !axis, y, x); + return table_get_rule (tt->subtable, !axis, y, x, color); } static const struct table_class table_transpose_class = diff --git a/src/output/table.c b/src/output/table.c index 3fccde9c98..44efa3abc3 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -214,11 +214,13 @@ 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 = CELL_COLOR_BLACK; + return table->klass->get_rule (table, axis, x, y, color); } void @@ -355,10 +357,11 @@ table_unshared_get_cell (const struct table *tiu_, int x, int y, 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 = @@ -427,7 +430,8 @@ table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED, 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; } -- 2.30.2