📄 tables.c
字号:
* whole cell width. */ expand_lines(table->part, x + width - 1, y, height, cell->bgcolor); if (cell->fragment_id) add_fragment_identifier(part, cell->fragment_id); } done_html_parser_state(state); if (part) mem_free(part);}static voiddraw_table_cells(struct table *table, int x, int y){ int col, row; int xp; color_t bgcolor = par_format.bgcolor; struct table_frames table_frames; get_table_frames(table, &table_frames); if (table->fragment_id) add_fragment_identifier(table->part, table->fragment_id); /* Expand using the background color of the ``parent context'' all the * way down the start of the left edge of the table. */ expand_lines(table->part, x - 1, y, table->real_height, bgcolor); xp = x + table_frames.left; for (col = 0; col < table->cols; col++) { int yp = y + table_frames.top; for (row = 0; row < table->rows; row++) { int row_height = table->rows_heights[row] + (row < table->rows - 1 && has_hline_width(table, row + 1)); draw_table_cell(table, col, row, xp, yp); yp += row_height; } if (col < table->cols - 1) { xp += table->cols_widths[col] + has_vline_width(table, col + 1); } } /* Finish the table drawing by aligning the right and bottom edge of * the table */ x += table->real_width - 1; expand_lines(table->part, x, y, table->real_height, table->bgcolor); /* Tables are renderer column-wise which breaks forms where the * form items appears in a column before the actual form tag is * parsed. Consider the folloing example: * * +--------+--------+ Where cell 2 has a <form>-tag * | cell 1 | cell 2 | and cell 3 has an <input>-tag. * +--------+--------+ * | cell 3 | cell 4 | The table is rendered by drawing * +--------+--------+ the cells in the order: 1, 3, 2, 4. * * That is the <input>-tag form-item is added before the <form>-tag, * which means a ``dummy'' form to hold it is added too. * Calling check_html_form_hierarchy() will join the the form-item * to the correct form from cell 2. */ check_html_form_hierarchy(table->part); /* Do a sanity check whether the height is correct */ check_table_height(table, &table_frames, y);}static inline intget_frame_pos(int a, int a_size, int b, int b_size){ assert(a >= -1 || a < a_size + 2 || b >= 0 || b <= b_size); if_assert_failed return 0; return a + 1 + (a_size + 2) * b;}#define H_FRAME_POSITION(table, col, row) frame[0][get_frame_pos(col, (table)->cols, row, (table)->rows)]#define V_FRAME_POSITION(table, col, row) frame[1][get_frame_pos(row, (table)->rows, col, (table)->cols)]static inline voiddraw_frame_point(struct table *table, signed char *frame[2], int x, int y, int col, int row){ /* TODO: Use /BORDER._.* / macros ! --pasky */ static unsigned char const border_chars[81] = { 0x00, 0xb3, 0xba, 0xc4, 0xc0, 0xd3, 0xcd, 0xd4, 0xc8, 0xc4, 0xd9, 0xbd, 0xc4, 0xc1, 0xd0, 0xcd, 0xd4, 0xc8, 0xcd, 0xbe, 0xbc, 0xcd, 0xbe, 0xbc, 0xcd, 0xcf, 0xca, 0xb3, 0xb3, 0xba, 0xda, 0xc3, 0xd3, 0xd5, 0xc6, 0xc8, 0xbf, 0xb4, 0xbd, 0xc2, 0xc5, 0xd0, 0xd5, 0xc6, 0xc8, 0xb8, 0xb5, 0xbc, 0xb8, 0xb5, 0xbc, 0xd1, 0xd8, 0xca, 0xba, 0xba, 0xba, 0xd6, 0xd6, 0xc7, 0xc9, 0xc9, 0xcc, 0xb7, 0xb7, 0xb6, 0xd2, 0xd2, 0xd7, 0xc9, 0xc9, 0xcc, 0xbb, 0xbb, 0xb9, 0xbb, 0xbb, 0xb9, 0xcb, 0xcb, 0xce, }; /* Note: I have no clue wether any of these names are suitable but they * should give an idea of what is going on. --jonas */ signed char left = H_FRAME_POSITION(table, col - 1, row); signed char right = H_FRAME_POSITION(table, col, row); signed char top = V_FRAME_POSITION(table, col, row - 1); signed char bottom = V_FRAME_POSITION(table, col, row); int pos; if (left < 0 && right < 0 && top < 0 && bottom < 0) return; pos = int_max(top, 0) + 3 * int_max(right, 0) + 9 * int_max(left, 0) + 27 * int_max(bottom, 0); draw_frame_hchars(table->part, x, y, 1, border_chars[pos], par_format.bgcolor, table->bordercolor);}static inline voiddraw_frame_hline(struct table *table, signed char *frame[2], int x, int y, int col, int row){ static unsigned char const hltable[] = { ' ', BORDER_SHLINE, BORDER_DHLINE }; int pos = H_FRAME_POSITION(table, col, row); assertm(pos < 3, "Horizontal table position out of bound [%d]", pos); if_assert_failed return; if (pos < 0 || table->cols_widths[col] <= 0) return; draw_frame_hchars(table->part, x, y, table->cols_widths[col], hltable[pos], par_format.bgcolor, table->bordercolor);}static inline voiddraw_frame_vline(struct table *table, signed char *frame[2], int x, int y, int col, int row){ static unsigned char const vltable[] = { ' ', BORDER_SVLINE, BORDER_DVLINE }; int pos = V_FRAME_POSITION(table, col, row); assertm(pos < 3, "Vertical table position out of bound [%d]", pos); if_assert_failed return; if (pos < 0 || table->rows_heights[row] <= 0) return; draw_frame_vchars(table->part, x, y, table->rows_heights[row], vltable[pos], par_format.bgcolor, table->bordercolor);}static inline inttable_row_has_group(struct table *table, int row){ int col; for (col = 0; col < table->cols; col++) if (CELL(table, col, row)->is_group) return 1; return 0;}static voidinit_table_rules(struct table *table, signed char *frame[2]){ int col, row; for (row = 0; row < table->rows; row++) for (col = 0; col < table->cols; col++) { int xsp, ysp; struct table_cell *cell = CELL(table, col, row); if (!cell->is_used || cell->is_spanned) continue; xsp = cell->colspan ? cell->colspan : table->cols - col; ysp = cell->rowspan ? cell->rowspan : table->rows - row; if (table->rules != TABLE_RULE_COLS) { memset(&H_FRAME_POSITION(table, col, row), table->cellspacing, xsp); memset(&H_FRAME_POSITION(table, col, row + ysp), table->cellspacing, xsp); } if (table->rules != TABLE_RULE_ROWS) { memset(&V_FRAME_POSITION(table, col, row), table->cellspacing, ysp); memset(&V_FRAME_POSITION(table, col + xsp, row), table->cellspacing, ysp); } } if (table->rules == TABLE_RULE_GROUPS) { for (col = 1; col < table->cols; col++) { if (table->cols_x[col]) continue; memset(&V_FRAME_POSITION(table, col, 0), 0, table->rows); } for (row = 1; row < table->rows; row++) { if (table_row_has_group(table, row)) continue; memset(&H_FRAME_POSITION(table, 0, row), 0, table->cols); } }}static voiddraw_table_frames(struct table *table, int indent, int y){ struct table_frames table_frames; signed char *frame[2]; int col, row; int cx, cy; int fh_size = (table->cols + 2) * (table->rows + 1); int fv_size = (table->cols + 1) * (table->rows + 2); frame[0] = fmem_alloc(fh_size + fv_size); if (!frame[0]) return; memset(frame[0], -1, fh_size + fv_size); frame[1] = &frame[0][fh_size]; if (table->rules != TABLE_RULE_NONE) init_table_rules(table, frame); get_table_frames(table, &table_frames); memset(&H_FRAME_POSITION(table, 0, 0), table_frames.top, table->cols); memset(&H_FRAME_POSITION(table, 0, table->rows), table_frames.bottom, table->cols); memset(&V_FRAME_POSITION(table, 0, 0), table_frames.left, table->rows); memset(&V_FRAME_POSITION(table, table->cols, 0), table_frames.right, table->rows); cy = y; for (row = 0; row <= table->rows; row++) { cx = indent; if ((row > 0 && row < table->rows && has_hline_width(table, row)) || (row == 0 && table_frames.top) || (row == table->rows && table_frames.bottom)) { int w = table_frames.left ? table->border : -1; for (col = 0; col < table->cols; col++) { if (col > 0) w = get_vline_width(table, col); if (w >= 0) { draw_frame_point(table, frame, cx, cy, col, row); if (row < table->rows) draw_frame_vline(table, frame, cx, cy + 1, col, row); cx++; } draw_frame_hline(table, frame, cx, cy, col, row); cx += table->cols_widths[col]; } if (table_frames.right) { draw_frame_point(table, frame, cx, cy, col, row); if (row < table->rows) draw_frame_vline(table, frame, cx, cy + 1, col, row); cx++; } cy++; } else if (row < table->rows) { for (col = 0; col <= table->cols; col++) { if ((col > 0 && col < table->cols && has_vline_width(table, col)) || (col == 0 && table_frames.left) || (col == table->cols && table_frames.right)) { draw_frame_vline(table, frame, cx, cy, col, row); cx++; } if (col < table->cols) cx += table->cols_widths[col]; } } if (row < table->rows) cy += table->rows_heights[row]; } fmem_free(frame[0]);}static voiddraw_table_caption(struct table *table, int x, int y){ unsigned char *start = table->caption.start; unsigned char *end = table->caption.end; struct part *part; if (!start || !end) return; while (start < end && isspace(*start)) start++; while (start < end && isspace(end[-1])) end--; if (start >= end) return; part = format_html_part(start, end, table->align, 0, table->real_width, table->part->document, x, y, NULL, table->link_num); if (part) { table->part->cy += part->box.height; table->part->cx = -1; table->part->link_num = part->link_num; mem_free(part); }}/* This renders tag soup elements that the parser detected while chewing it's * way through the table HTML. */static voiddraw_table_bad_html(struct table *table){ int i; for (i = 0; i < table->bad_html_size; i++) { struct html_start_end *html = &table->bad_html[i]; unsigned char *start = html->start; unsigned char *end = html->end; while (start < end && isspace(*start)) start++; while (start < end && isspace(end[-1])) end--; if (start >= end) continue; parse_html(start, end, table->part, NULL); }}voidformat_table(unsigned char *attr, unsigned char *html, unsigned char *eof, unsigned char **end, struct part *part){ struct table *table; struct node *node, *new_node; struct html_element *state; int indent, margins; html_context.table_level++; table = parse_table(html, eof, end, attr, (part->document || part->box.x)); if (!table) goto ret0; table->part = part; /* XXX: This tag soup handling needs to be done outside the create * parser state. Something to do with link numbering. */ /* It needs to be done _before_ processing the actual table, too. * Otherwise i.e. <form> tags between <table> and <tr> are broken. */ draw_table_bad_html(table); state = init_html_parser_state(ELEMENT_DONT_KILL, ALIGN_LEFT, 0, 0); margins = par_format.leftmargin + par_format.rightmargin; if (get_table_cellpadding(table)) goto ret2; /* DBG("%d %d %d", t->min_width, t->max_width, table->width); */ if (table->min_width >= table->width) distribute_widths(table, table->min_width); else if (table->max_width < table->width && table->full_width) distribute_widths(table, table->max_width); else distribute_widths(table, table->width); if (!part->document && part->box.x == 1) { int total_width = table->real_width + margins; int_bounds(&total_width, table->real_width, par_format.width); int_lower_bound(&part->box.width, total_width); part->cy += table->real_height; goto ret2; }#ifdef HTML_TABLE_2ND_PASS check_table_widths(table);#endif get_table_heights(table); if (!part->document) { int_lower_bound(&part->box.width, table->real_width + margins); part->cy += table->real_height; goto ret2; } node = part->document->nodes.next; node->box.height = part->box.y - node->box.y + part->cy; indent = get_table_indent(table); /* FIXME: See bug 432. It should be possible to align the caption at * the top, bottom or the sides. */ draw_table_caption(table, indent + part->box.x, part->box.y + part->cy); draw_table_cells(table, indent, part->cy); draw_table_frames(table, indent, part->cy); part->cy += table->real_height; part->cx = -1; new_node = mem_alloc(sizeof(*new_node)); if (new_node) { set_box(&new_node->box, node->box.x, part->box.y + part->cy, node->box.width, 0); add_to_list(part->document->nodes, new_node); }ret2: part->link_num = table->link_num; int_lower_bound(&part->box.height, part->cy); html_context.part = part; /* Might've changed in draw_table_cells(). */ done_html_parser_state(state); free_table(table);ret0: html_context.table_level--; if (!html_context.table_level) free_table_cache();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -