📄 tables.c
字号:
static inline intstretch_columns(struct table *table, int widths[], int max_widths[], int spare_width, int total_width){ int total_spare_width = spare_width; while (spare_width) { int stretch_width = 0; int stretch_col = -1; int col; for (col = 0; col < table->cols; col++) { int col_spare_width; if (!widths[col]) continue; col_spare_width = total_spare_width * widths[col] / total_width; int_bounds(&col_spare_width, 1, max_widths[col]); if (col_spare_width > stretch_width) { stretch_width = col_spare_width; stretch_col = col; } } /* Got stretch column? */ if (stretch_col == -1) break; /* Mark the column as visited */ widths[stretch_col] = 0; if (stretch_width > spare_width) stretch_width = spare_width; assertm(stretch_width >= 0, "shrinking cell"); table->cols_widths[stretch_col] += stretch_width; spare_width -= stretch_width; } return total_spare_width - spare_width;}/* This function distributes space evenly between @table columns so that it * stretches to @width. */static voiddistribute_widths(struct table *table, int width){ int col; int spare_width = width - table->min_width; int stretch_method = 0; int *widths, *max_widths; int max_cols_width = 0; int cols_array_size; if (!table->cols) return; assertm(spare_width >= 0, "too small width %d, required %d", width, table->min_width); for (col = 0; col < table->cols; col++) int_lower_bound(&max_cols_width, table->max_cols_widths[col]); cols_array_size = table->cols * sizeof(*table->cols_widths); memcpy(table->cols_widths, table->min_cols_widths, cols_array_size); table->real_width = width; widths = fmem_alloc(cols_array_size); if (!widths) return; max_widths = fmem_alloc(cols_array_size); if (!max_widths) goto free_widths; while (spare_width) { int stretched, total_width; memset(widths, 0, cols_array_size); memset(max_widths, 0, cols_array_size); total_width = apply_stretch_method(table, widths, max_widths, stretch_method, max_cols_width); assertm(total_width != -1, "Could not expand table"); if_assert_failed break; if (!total_width) { stretch_method++; continue; } stretched = stretch_columns(table, widths, max_widths, spare_width, total_width); if (!stretched) stretch_method++; else spare_width -= stretched; } fmem_free(max_widths);free_widths: fmem_free(widths);}static intget_table_cellpadding(struct table *table){ struct part *part = table->part; int cpd_pass = 0, cpd_width = 0, cpd_last = table->cellpadding; int margins = par_format.leftmargin + par_format.rightmargin;again: get_cell_widths(table); if (get_column_widths(table)) return -1; get_table_width(table); if (!part->document && !part->box.x) { if (!table->full_width) int_upper_bound(&table->max_width, table->width); int_lower_bound(&table->max_width, table->min_width); int_lower_bound(&part->max_width, table->max_width + margins); int_lower_bound(&part->box.width, table->min_width + margins); return -1; } if (!cpd_pass && table->min_width > table->width && table->cellpadding) { table->cellpadding = 0; cpd_pass = 1; cpd_width = table->min_width; goto again; } if (cpd_pass == 1 && table->min_width > cpd_width) { table->cellpadding = cpd_last; cpd_pass = 2; goto again; } return 0;}#ifdef HTML_TABLE_2ND_PASS /* This is by default ON! (<setup.h>) */static voidcheck_table_widths(struct table *table){ int col, row; int colspan; int width, new_width; int max, max_index = 0; /* go away, warning! */ int *widths = mem_calloc(table->cols, sizeof(*widths)); if (!widths) return; for (row = 0; row < table->rows; row++) for (col = 0; col < table->cols; col++) { struct table_cell *cell = CELL(table, col, row); int k, p = 0; if (!cell->start) continue; for (k = 0; k < cell->colspan; k++) { p += table->cols_widths[col + k] + (k && has_vline_width(table, col + k)); } get_cell_width(cell->start, cell->end, table->cellpadding, p, 1, &cell->width, NULL, cell->link_num, NULL); int_upper_bound(&cell->width, p); } colspan = 1; do { int new_colspan = INT_MAX; for (col = 0; col < table->cols; col++) for (row = 0; row < table->rows; row++) { struct table_cell *cell = CELL(table, col, row); if (!cell->start) continue; assertm(cell->colspan + col <= table->cols, "colspan out of table"); if_assert_failed goto end; if (cell->colspan == colspan) { int k, p = 0; for (k = 1; k < colspan; k++) p += has_vline_width(table, col + k); distribute_values(&widths[col], colspan, cell->width - p, &table->max_cols_widths[col]); } else if (cell->colspan > colspan && cell->colspan < new_colspan) { new_colspan = cell->colspan; } } colspan = new_colspan; } while (colspan != INT_MAX); width = new_width = 0; for (col = 0; col < table->cols; col++) { width += table->cols_widths[col]; new_width += widths[col]; } if (new_width > width) { /* INTERNAL("new width(%d) is larger than previous(%d)", new_width, width); */ goto end; } max = -1; for (col = 0; col < table->cols; col++) if (table->max_cols_widths[col] > max) { max = table->max_cols_widths[col]; max_index = col; } if (max != -1) { widths[max_index] += width - new_width; if (widths[max_index] <= table->max_cols_widths[max_index]) { mem_free(table->cols_widths); table->cols_widths = widths; return; } }end: mem_free(widths);}#endifstatic voidcheck_table_height(struct table *table, struct table_frames *frames, int y){#ifndef CONFIG_FASTMEM /* XXX: Cannot we simply use the @yp value we just calculated * in draw_table_cells()? --pasky */ int old_height = table->real_height + table->part->cy; int our_height = frames->top + y + frames->bottom + table->caption_height; int row; /* XXX: We cannot use get_table_real_height() because we are * looking one row ahead - which is completely arcane to me. * It makes a difference only when a table uses ruler="groups" * and has non-zero cellspacing or vcellpadding. --pasky */ for (row = 0; row < table->rows; row++) { our_height += table->rows_heights[row] + (row < table->rows - 1 && has_hline_width(table, row + 1)); } assertm(old_height == our_height, "size not matching! %d vs %d", old_height, our_height);#endif}static intget_table_caption_height(struct table *table){ unsigned char *start = table->caption.start; unsigned char *end = table->caption.end; struct part *part; if (!start || !end) return 0; while (start < end && isspace(*start)) start++; while (start < end && isspace(end[-1])) end--; if (start >= end) return 0; part = format_html_part(start, end, table->align, 0, table->real_width, NULL, 0, 0, NULL, table->link_num); if (!part) { return 0; } else { int height = part->box.height; mem_free(part); return height; }}static intget_table_real_height(struct table *table){ struct table_frames table_frames; int height; int row; get_table_frames(table, &table_frames); height = table_frames.top + table_frames.bottom; height += table->caption_height; for (row = 0; row < table->rows; row++) { height += table->rows_heights[row]; if (row && has_hline_width(table, row)) height++; } return height;}static voidget_table_heights(struct table *table){ int rowspan; int col, row; table->caption_height = get_table_caption_height(table); for (row = 0; row < table->rows; row++) { for (col = 0; col < table->cols; col++) { struct table_cell *cell = CELL(table, col, row); struct part *part; int width = 0, sp; if (!cell->is_used || cell->is_spanned) continue; for (sp = 0; sp < cell->colspan; sp++) { width += table->cols_widths[col + sp] + (sp < cell->colspan - 1 && has_vline_width(table, col + sp + 1)); } part = format_cell(table, cell, NULL, 2, 2, width); if (!part) return; cell->height = part->box.height; /* DBG("%d, %d.", width, cell->height); */ mem_free(part); } } rowspan = 1; do { int new_rowspan = INT_MAX; for (row = 0; row < table->rows; row++) { for (col = 0; col < table->cols; col++) { struct table_cell *cell = CELL(table, col, row); if (!cell->is_used || cell->is_spanned) continue; if (cell->rowspan == rowspan) { int k, p = 0; for (k = 1; k < rowspan; k++) p += has_hline_width(table, row + k); distribute_values(&table->rows_heights[row], rowspan, cell->height - p, NULL); } else if (cell->rowspan > rowspan && cell->rowspan < new_rowspan) { new_rowspan = cell->rowspan; } } } rowspan = new_rowspan; } while (rowspan != INT_MAX); table->real_height = get_table_real_height(table);}static voiddraw_table_cell(struct table *table, int col, int row, int x, int y){ struct table_cell *cell = CELL(table, col, row); struct document *document = table->part->document; struct part *part; int width = 0; int height = 0; int s, tmpy = y; struct html_element *state; if (!cell->start) return; for (s = 0; s < cell->colspan; s++) { width += table->cols_widths[col + s] + (s < cell->colspan - 1 && has_vline_width(table, col + s + 1)); } for (s = 0; s < cell->rowspan; s++) { height += table->rows_heights[row + s] + (s < cell->rowspan - 1 && has_hline_width(table, row + s + 1)); } state = init_html_parser_state(ELEMENT_DONT_KILL, cell->align, 0, 0); if (cell->is_header) format.style.attr |= AT_BOLD; format.style.bg = cell->bgcolor; par_format.bgcolor = cell->bgcolor; if (cell->valign == VALIGN_MIDDLE) tmpy += (height - cell->height) / 2; else if (cell->valign == VALIGN_BOTTOM) tmpy += (height - cell->height); part = format_cell(table, cell, document, x, tmpy, width); if (part) { /* The cell content doesn't necessarily fill out the whole cell * height so use the calculated @height because it is an upper * bound. */ assert(height >= cell->height); /* The line expansion draws the _remaining_ background color of * both untouched lines and lines that doesn't stretch the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -