mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-23 12:36:51 +03:00
[project @ 2005-04-14 19:54:24 by rjw]
Implement HTML table border setting. Improve support for the collapsing border model. svn path=/import/netsurf/; revision=1632
This commit is contained in:
parent
92b2d46874
commit
487cad486d
80
css/css.c
80
css/css.c
@ -2864,6 +2864,86 @@ float css_len2px(const struct css_length *length,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the most 'eyecatching' border.
|
||||
*
|
||||
* \return the most eyecatching border, favoured towards test2
|
||||
*/
|
||||
|
||||
struct css_border *css_eyecatching_border(struct css_border *test1,
|
||||
struct css_style *style1, struct css_border *test2,
|
||||
struct css_style *style2)
|
||||
{
|
||||
float width1, width2;
|
||||
int impact = 0;
|
||||
|
||||
assert(test1);
|
||||
assert(style1);
|
||||
assert(test2);
|
||||
assert(style2);
|
||||
|
||||
/* hidden border styles always win, none always loses */
|
||||
if ((test1->style == CSS_BORDER_STYLE_HIDDEN) ||
|
||||
(test2->style == CSS_BORDER_STYLE_NONE))
|
||||
return test1;
|
||||
if ((test2->style == CSS_BORDER_STYLE_HIDDEN) ||
|
||||
(test1->style == CSS_BORDER_STYLE_NONE))
|
||||
return test2;
|
||||
|
||||
/* the widest border wins */
|
||||
width1 = css_len2px(&test1->width.value, style1);
|
||||
width2 = css_len2px(&test2->width.value, style2);
|
||||
if (width1 > width2)
|
||||
return test1;
|
||||
if (width2 > width1)
|
||||
return test2;
|
||||
|
||||
/* the closest to a solid line wins */
|
||||
switch (test1->style) {
|
||||
case CSS_BORDER_STYLE_DOUBLE:
|
||||
impact++;
|
||||
case CSS_BORDER_STYLE_SOLID:
|
||||
impact++;
|
||||
case CSS_BORDER_STYLE_DASHED:
|
||||
impact++;
|
||||
case CSS_BORDER_STYLE_DOTTED:
|
||||
impact++;
|
||||
case CSS_BORDER_STYLE_RIDGE:
|
||||
impact++;
|
||||
case CSS_BORDER_STYLE_OUTSET:
|
||||
impact++;
|
||||
case CSS_BORDER_STYLE_GROOVE:
|
||||
impact++;
|
||||
case CSS_BORDER_STYLE_INSET:
|
||||
impact++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (test2->style) {
|
||||
case CSS_BORDER_STYLE_DOUBLE:
|
||||
impact--;
|
||||
case CSS_BORDER_STYLE_SOLID:
|
||||
impact--;
|
||||
case CSS_BORDER_STYLE_DASHED:
|
||||
impact--;
|
||||
case CSS_BORDER_STYLE_DOTTED:
|
||||
impact--;
|
||||
case CSS_BORDER_STYLE_RIDGE:
|
||||
impact--;
|
||||
case CSS_BORDER_STYLE_OUTSET:
|
||||
impact--;
|
||||
case CSS_BORDER_STYLE_GROOVE:
|
||||
impact--;
|
||||
case CSS_BORDER_STYLE_INSET:
|
||||
impact--;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (impact > 0)
|
||||
return test1;
|
||||
return test2;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
int main()
|
||||
|
15
css/css.h
15
css/css.h
@ -84,6 +84,12 @@ struct css_border_width {
|
||||
struct css_length value;
|
||||
};
|
||||
|
||||
struct css_border {
|
||||
colour color;
|
||||
struct css_border_width width;
|
||||
css_border_style style;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CSS_CONTENT_STRING,
|
||||
CSS_CONTENT_URI,
|
||||
@ -163,11 +169,7 @@ struct css_style {
|
||||
css_background_repeat background_repeat;
|
||||
|
||||
/* borders */
|
||||
struct {
|
||||
colour color;
|
||||
struct css_border_width width;
|
||||
css_border_style style;
|
||||
} border[4]; /**< top, right, bottom, left */
|
||||
struct css_border border[4]; /**< top, right, bottom, left */
|
||||
css_border_collapse border_collapse;
|
||||
struct {
|
||||
enum { CSS_BORDER_SPACING_INHERIT,
|
||||
@ -630,5 +632,8 @@ void css_dump_stylesheet(const struct css_stylesheet * stylesheet);
|
||||
|
||||
float css_len2px(const struct css_length *length,
|
||||
const struct css_style *style);
|
||||
struct css_border *css_eyecatching_border(struct css_border *test1,
|
||||
struct css_style *style1, struct css_border *test2,
|
||||
struct css_style *style2);
|
||||
|
||||
#endif
|
||||
|
@ -85,6 +85,7 @@ static struct css_style * box_get_style(struct content *c,
|
||||
xmlNode *n);
|
||||
static void box_solve_display(struct css_style *style, bool root);
|
||||
static void box_set_cellpadding(struct box *box, int value);
|
||||
static void box_set_table_border(struct box *box, int value, colour color);
|
||||
static void box_text_transform(char *s, unsigned int len,
|
||||
css_text_transform tt);
|
||||
#define BOX_SPECIAL_PARAMS xmlNode *n, struct content *content, \
|
||||
@ -263,6 +264,7 @@ bool box_construct_element(xmlNode *n, struct content *content,
|
||||
struct box *inline_container_c;
|
||||
struct css_style *style = 0;
|
||||
struct element_entry *element;
|
||||
colour border_color;
|
||||
xmlChar *title0;
|
||||
xmlNode *c;
|
||||
|
||||
@ -390,13 +392,31 @@ bool box_construct_element(xmlNode *n, struct content *content,
|
||||
box->rows = 1;
|
||||
xmlFree(s);
|
||||
}
|
||||
if (strcmp((const char *) n->name, "table") == 0 &&
|
||||
(s = (char *) xmlGetProp(n,
|
||||
(const xmlChar *) "cellpadding"))) {
|
||||
int value = atoi(s);
|
||||
if (!strrchr(s, '%') && 0 < value) /* % not implemented */
|
||||
box_set_cellpadding(box, value);
|
||||
xmlFree(s);
|
||||
if (strcmp((const char *) n->name, "table") == 0) {
|
||||
border_color = 0x888888; /* default colour */
|
||||
if ((s = (char *) xmlGetProp(n,
|
||||
(const xmlChar *) "cellpadding"))) {
|
||||
int value = atoi(s);
|
||||
if (!strrchr(s, '%') && 0 < value) /* % not implemented */
|
||||
box_set_cellpadding(box, value);
|
||||
xmlFree(s);
|
||||
}
|
||||
if ((s = (char *) xmlGetProp(n,
|
||||
(const xmlChar *) "bordercolor"))) {
|
||||
unsigned int r, g, b;
|
||||
if (s[0] == '#' && sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3)
|
||||
border_color = (b << 16) | (g << 8) | r;
|
||||
else if (s[0] != '#')
|
||||
border_color = named_colour(s);
|
||||
xmlFree(s);
|
||||
}
|
||||
if ((s = (char *) xmlGetProp(n,
|
||||
(const xmlChar *) "border"))) {
|
||||
int value = atoi(s);
|
||||
if (!strrchr(s, '%') && 0 < value) /* % not implemented */
|
||||
box_set_table_border(box, value, border_color);
|
||||
xmlFree(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* fetch any background image for this box */
|
||||
@ -857,6 +877,62 @@ void box_set_cellpadding(struct box *box, int value)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the borders on a table.
|
||||
*
|
||||
* \param box box to set cellpadding on
|
||||
* \param value border in pixels
|
||||
*
|
||||
* The descendants of the box are searched for table cells, and the border is
|
||||
* set on each one.
|
||||
*/
|
||||
|
||||
void box_set_table_border(struct box *box, int value, colour color)
|
||||
{
|
||||
struct box *child;
|
||||
|
||||
if (box->type == BOX_TABLE) {
|
||||
for (unsigned int i = 0; i != 4; i++) {
|
||||
box->style->border[i].color = color;
|
||||
box->style->border[i].width.width =
|
||||
CSS_BORDER_WIDTH_LENGTH;
|
||||
box->style->border[i].width.value.value =
|
||||
value;
|
||||
box->style->border[i].width.value.unit =
|
||||
CSS_UNIT_PX;
|
||||
box->style->border[i].style =
|
||||
CSS_BORDER_STYLE_OUTSET;
|
||||
}
|
||||
}
|
||||
|
||||
/* The tree is not normalized yet, so accept cells not in rows and
|
||||
* rows not in row groups. */
|
||||
for (child = box->children; child; child = child->next) {
|
||||
switch (child->type) {
|
||||
case BOX_TABLE_ROW_GROUP:
|
||||
case BOX_TABLE_ROW:
|
||||
box_set_table_border(child, value, color);
|
||||
break;
|
||||
case BOX_TABLE_CELL:
|
||||
for (unsigned int i = 0; i != 4; i++) {
|
||||
child->style->border[i].color = color;
|
||||
child->style->border[i].width.width =
|
||||
CSS_BORDER_WIDTH_LENGTH;
|
||||
child->style->border[i].width.value.value =
|
||||
1;
|
||||
child->style->border[i].width.value.unit =
|
||||
CSS_UNIT_PX;
|
||||
child->style->border[i].style =
|
||||
CSS_BORDER_STYLE_INSET;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply the CSS text-transform property to given text for its ASCII chars.
|
||||
*
|
||||
|
296
render/layout.c
296
render/layout.c
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
||||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2005 Richard Wilson <info@tinct.net>
|
||||
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
|
||||
@ -70,12 +70,18 @@ static void calculate_inline_replaced_widths(struct box *box, int *min,
|
||||
int *max, int *line_max);
|
||||
static void calculate_inline_widths(struct box *box, int *min, int *line_max);
|
||||
static bool calculate_table_widths(struct box *table);
|
||||
void table_collapse_borders_h(struct box *parent, struct box *child, bool *first);
|
||||
void table_collapse_borders_v(struct box *row, struct box *cell, unsigned int columns);
|
||||
void table_collapse_borders_cell(struct box *cell, struct box *right,
|
||||
struct box *bottom);
|
||||
void table_remove_borders(struct css_style *style);
|
||||
struct box *table_find_cell(struct box *table, unsigned int x, unsigned int y);
|
||||
|
||||
|
||||
/**
|
||||
* Calculate positions of boxes in a document.
|
||||
*
|
||||
* \param doc content of type CONTENT_HTML
|
||||
* \param doc content of type CONTENT_HTML
|
||||
* \param width available page width
|
||||
* \return true on success, false on memory exhaustion
|
||||
*/
|
||||
@ -510,10 +516,10 @@ void layout_float_find_dimensions(int available_width,
|
||||
* Calculate size of margins, paddings, and borders.
|
||||
*
|
||||
* \param available_width width of containing block
|
||||
* \param style style giving margins, paddings, and borders
|
||||
* \param margin[4] filled with margins, may be NULL
|
||||
* \param padding[4] filled with paddings
|
||||
* \param border[4] filled with border widths
|
||||
* \param style style giving margins, paddings, and borders
|
||||
* \param margin[4] filled with margins, may be NULL
|
||||
* \param padding[4] filled with paddings
|
||||
* \param border[4] filled with border widths
|
||||
*/
|
||||
|
||||
void layout_find_dimensions(int available_width,
|
||||
@ -565,7 +571,7 @@ void layout_find_dimensions(int available_width,
|
||||
/**
|
||||
* Find y coordinate which clears all floats on left and/or right.
|
||||
*
|
||||
* \param fl first float in float list
|
||||
* \param fl first float in float list
|
||||
* \param clear type of clear
|
||||
* \return y coordinate relative to ancestor box for floats
|
||||
*/
|
||||
@ -590,12 +596,12 @@ int layout_clear(struct box *fl, css_clear clear)
|
||||
/**
|
||||
* Find left and right edges in a vertical range.
|
||||
*
|
||||
* \param fl first float in float list
|
||||
* \param y0 start of y range to search
|
||||
* \param y1 end of y range to search
|
||||
* \param x0 start left edge, updated to available left edge
|
||||
* \param x1 start right edge, updated to available right edge
|
||||
* \param left returns float on left if present
|
||||
* \param fl first float in float list
|
||||
* \param y0 start of y range to search
|
||||
* \param y1 end of y range to search
|
||||
* \param x0 start left edge, updated to available left edge
|
||||
* \param x1 start right edge, updated to available right edge
|
||||
* \param left returns float on left if present
|
||||
* \param right returns float on right if present
|
||||
*/
|
||||
|
||||
@ -631,11 +637,11 @@ void find_sides(struct box *fl, int y0, int y1,
|
||||
/**
|
||||
* Layout lines of text or inline boxes with floats.
|
||||
*
|
||||
* \param box inline container
|
||||
* \param box inline container
|
||||
* \param width horizontal space available
|
||||
* \param cont ancestor box which defines horizontal space, for floats
|
||||
* \param cx box position relative to cont
|
||||
* \param cy box position relative to cont
|
||||
* \param cont ancestor box which defines horizontal space, for floats
|
||||
* \param cx box position relative to cont
|
||||
* \param cy box position relative to cont
|
||||
* \param content memory pool for any new boxes
|
||||
* \return true on success, false on memory exhaustion
|
||||
*/
|
||||
@ -706,10 +712,10 @@ int line_height(struct css_style *style)
|
||||
*
|
||||
* \param first box at start of line
|
||||
* \param width available width
|
||||
* \param y coordinate of top of line, updated on exit to bottom
|
||||
* \param cx coordinate of left of line relative to cont
|
||||
* \param cy coordinate of top of line relative to cont
|
||||
* \param cont ancestor box which defines horizontal space, for floats
|
||||
* \param y coordinate of top of line, updated on exit to bottom
|
||||
* \param cx coordinate of left of line relative to cont
|
||||
* \param cy coordinate of top of line relative to cont
|
||||
* \param cont ancestor box which defines horizontal space, for floats
|
||||
* \param indent apply any first-line indent
|
||||
* \param next_box updated to first box for next line, or 0 at end
|
||||
* \param content memory pool for any new boxes
|
||||
@ -932,7 +938,7 @@ bool layout_line(struct box *first, int width, int *y,
|
||||
split_box = b;
|
||||
move_y = true;
|
||||
inline_count++;
|
||||
/* fprintf(stderr, "layout_line: '%.*s' %li %li\n", b->length, b->text, xp, x); */
|
||||
/* fprintf(stderr, "layout_line: '%.*s' %li %li\n", b->length, b->text, xp, x); */
|
||||
} else if (b->type == BOX_BR) {
|
||||
b->x = x;
|
||||
b->width = 0;
|
||||
@ -945,7 +951,7 @@ bool layout_line(struct box *first, int width, int *y,
|
||||
/* float */
|
||||
d = b->children;
|
||||
d->float_children = 0;
|
||||
/* css_dump_style(b->style); */
|
||||
/* css_dump_style(b->style); */
|
||||
|
||||
if (!layout_float(d, width, content))
|
||||
return false;
|
||||
@ -971,12 +977,12 @@ bool layout_line(struct box *first, int width, int *y,
|
||||
right = b;
|
||||
}
|
||||
b->y = cy;
|
||||
/* fprintf(stderr, "layout_line: float fits %li %li, edges %li %li\n", */
|
||||
/* b->x, b->y, x0, x1); */
|
||||
/* fprintf(stderr, "layout_line: float fits %li %li, edges %li %li\n", */
|
||||
/* b->x, b->y, x0, x1); */
|
||||
} else {
|
||||
/* doesn't fit: place below */
|
||||
place_float_below(b, width, cx, cy + height + 1, cont);
|
||||
/* fprintf(stderr, "layout_line: float doesn't fit %li %li\n", b->x, b->y); */
|
||||
/* fprintf(stderr, "layout_line: float doesn't fit %li %li\n", b->x, b->y); */
|
||||
}
|
||||
assert(cont->float_children != b);
|
||||
b->next_float = cont->float_children;
|
||||
@ -1052,12 +1058,12 @@ bool layout_line(struct box *first, int width, int *y,
|
||||
b = c2;
|
||||
}
|
||||
x += space_before + w;
|
||||
/* fprintf(stderr, "layout_line: overflow, forcing\n"); */
|
||||
/* fprintf(stderr, "layout_line: overflow, forcing\n"); */
|
||||
} else if (space == 0 || x1 - x0 <= x + space_before + w) {
|
||||
/* first word doesn't fit, but full width not
|
||||
available so leave for later */
|
||||
b = split_box;
|
||||
/* fprintf(stderr, "layout_line: overflow, leaving\n"); */
|
||||
/* fprintf(stderr, "layout_line: overflow, leaving\n"); */
|
||||
} else {
|
||||
/* fit as many words as possible */
|
||||
assert(space != 0);
|
||||
@ -1067,7 +1073,7 @@ bool layout_line(struct box *first, int width, int *y,
|
||||
x1 - x0 - x - space_before, &space, &w);
|
||||
LOG(("'%.*s' %i %u %i", (int) split_box->length,
|
||||
split_box->text, x1 - x0, space, w));
|
||||
/* assert(space == split_box->length || split_box->text[space] = ' '); */
|
||||
/* assert(space == split_box->length || split_box->text[space] = ' '); */
|
||||
if (space == 0)
|
||||
space = 1;
|
||||
if (space != split_box->length) {
|
||||
@ -1096,7 +1102,7 @@ bool layout_line(struct box *first, int width, int *y,
|
||||
b = c2;
|
||||
}
|
||||
x += space_before + w;
|
||||
/* fprintf(stderr, "layout_line: overflow, fit\n"); */
|
||||
/* fprintf(stderr, "layout_line: overflow, fit\n"); */
|
||||
}
|
||||
move_y = true;
|
||||
}
|
||||
@ -1151,7 +1157,7 @@ int layout_text_indent(struct css_style *style, int width)
|
||||
/**
|
||||
* Layout the contents of a float or inline block.
|
||||
*
|
||||
* \param b float or inline block box
|
||||
* \param b float or inline block box
|
||||
* \param width available width
|
||||
* \param content memory pool for any new boxes
|
||||
* \return true on success, false on memory exhaustion
|
||||
@ -1176,11 +1182,11 @@ bool layout_float(struct box *b, int width, struct content *content)
|
||||
/**
|
||||
* Position a float in the first available space.
|
||||
*
|
||||
* \param c float box to position
|
||||
* \param c float box to position
|
||||
* \param width available width
|
||||
* \param cx x coordinate relative to cont to place float right of
|
||||
* \param y y coordinate relative to cont to place float below
|
||||
* \param cont ancestor box which defines horizontal space, for floats
|
||||
* \param cx x coordinate relative to cont to place float right of
|
||||
* \param y y coordinate relative to cont to place float below
|
||||
* \param cont ancestor box which defines horizontal space, for floats
|
||||
*/
|
||||
|
||||
void place_float_below(struct box *c, int width, int cx, int y,
|
||||
@ -1216,9 +1222,9 @@ void place_float_below(struct box *c, int width, int cx, int y,
|
||||
/**
|
||||
* Layout a table.
|
||||
*
|
||||
* \param table table to layout
|
||||
* \param table table to layout
|
||||
* \param available_width width of containing block
|
||||
* \param content memory pool for any new boxes
|
||||
* \param content memory pool for any new boxes
|
||||
* \return true on success, false on memory exhaustion
|
||||
*/
|
||||
|
||||
@ -1321,7 +1327,7 @@ bool layout_table(struct box *table, int available_width,
|
||||
table->padding[RIGHT] +
|
||||
table->border[RIGHT] +
|
||||
(table->margin[RIGHT] == AUTO ? 0 :
|
||||
table->margin[RIGHT]));
|
||||
table->margin[RIGHT]));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1579,8 +1585,8 @@ bool layout_table(struct box *table, int available_width,
|
||||
for (c = row->children; c; c = c->next) {
|
||||
/* unextended bottom padding is in c->descendant_y1, and unextended
|
||||
* cell height is in c->descendant_y0 */
|
||||
spare_height = (c->padding[BOTTOM] - c->descendant_y1) +
|
||||
(c->height - c->descendant_y0);
|
||||
spare_height = (c->padding[BOTTOM] - c->descendant_y1) +
|
||||
(c->height - c->descendant_y0);
|
||||
switch (c->style->vertical_align.type) {
|
||||
case CSS_VERTICAL_ALIGN_SUB:
|
||||
case CSS_VERTICAL_ALIGN_SUPER:
|
||||
@ -1628,8 +1634,8 @@ bool layout_table(struct box *table, int available_width,
|
||||
* Moves the children of a box by a specified amount
|
||||
*
|
||||
* \param box top of tree of boxes
|
||||
* \param x the amount to move children by horizontally
|
||||
* \param y the amount to move children by vertically
|
||||
* \param x the amount to move children by horizontally
|
||||
* \param y the amount to move children by vertically
|
||||
*/
|
||||
|
||||
void layout_move_children(struct box *box, int x, int y) {
|
||||
@ -1729,9 +1735,9 @@ bool calculate_widths(struct box *box)
|
||||
* Find min, max widths for a BOX_BLOCK, BOX_INLINE_BLOCK, BOX_FLOAT_*,
|
||||
* or BOX_TABLE.
|
||||
*
|
||||
* \param box BLOCK, INLINE_BLOCK, FLOAT, or TABLE box
|
||||
* \param min current min, updated to new min
|
||||
* \param max current max, updated to new max
|
||||
* \param box BLOCK, INLINE_BLOCK, FLOAT, or TABLE box
|
||||
* \param min current min, updated to new min
|
||||
* \param max current max, updated to new max
|
||||
* \param max_sum sum of maximum widths, updated, or 0 if not required
|
||||
* \return true on success, false on memory exhaustion
|
||||
*/
|
||||
@ -1918,6 +1924,7 @@ bool calculate_table_widths(struct box *table)
|
||||
struct box *row_group, *row, *cell;
|
||||
int width, min_width = 0, max_width = 0;
|
||||
struct column *col;
|
||||
bool first;
|
||||
|
||||
LOG(("table %p, columns %u", table, table->columns));
|
||||
|
||||
@ -1937,6 +1944,72 @@ bool calculate_table_widths(struct box *table)
|
||||
|
||||
assert(table->children && table->children->children);
|
||||
|
||||
/* handle collapsing border model */
|
||||
assert(table->style);
|
||||
if (table->style->border_collapse == CSS_BORDER_COLLAPSE_COLLAPSE) {
|
||||
|
||||
/* 1st stage: collapse all borders down to the cells */
|
||||
first = true;
|
||||
for (row_group = table->children; row_group;
|
||||
row_group = row_group->next) {
|
||||
assert(row_group->type == BOX_TABLE_ROW_GROUP);
|
||||
assert(row_group->style);
|
||||
table_collapse_borders_h(table, row_group, &first);
|
||||
first = (row_group->children);
|
||||
for (row = row_group->children; row; row = row->next) {
|
||||
assert(row->type == BOX_TABLE_ROW);
|
||||
assert(row->style);
|
||||
table_collapse_borders_h(row_group, row, &first);
|
||||
for (cell = row->children; cell; cell = cell->next) {
|
||||
assert(cell->type == BOX_TABLE_CELL);
|
||||
assert(cell->style);
|
||||
table_collapse_borders_v(row, cell, table->columns);
|
||||
}
|
||||
table_remove_borders(row->style);
|
||||
}
|
||||
table_remove_borders(row_group->style);
|
||||
}
|
||||
table_remove_borders(table->style);
|
||||
|
||||
/* 2nd stage: rather than building a grid of cells, we slowly look up the
|
||||
* cell we want to collapse with */
|
||||
for (i = 0; i < table->columns; i++) {
|
||||
for (j = 0; j < table->rows; j++) {
|
||||
table_collapse_borders_cell(
|
||||
table_find_cell(table, i, j),
|
||||
table_find_cell(table, i + 1, j),
|
||||
table_find_cell(table, i, j + 1));
|
||||
}
|
||||
}
|
||||
|
||||
/* 3rd stage: remove redundant borders */
|
||||
first = true;
|
||||
for (row_group = table->children; row_group;
|
||||
row_group = row_group->next) {
|
||||
for (row = row_group->children; row; row = row->next) {
|
||||
for (cell = row->children; cell; cell = cell->next) {
|
||||
if (!first) {
|
||||
cell->style->border[TOP].style =
|
||||
CSS_BORDER_STYLE_NONE;
|
||||
cell->style->border[TOP].width.value.value =
|
||||
0;
|
||||
cell->style->border[TOP].width.value.unit =
|
||||
CSS_UNIT_PX;
|
||||
}
|
||||
if (cell->start_column > 0) {
|
||||
cell->style->border[LEFT].style =
|
||||
CSS_BORDER_STYLE_NONE;
|
||||
cell->style->border[LEFT].width.value.value =
|
||||
0;
|
||||
cell->style->border[LEFT].width.value.unit =
|
||||
CSS_UNIT_PX;
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 1st pass: consider cells with colspan 1 only */
|
||||
for (row_group = table->children; row_group;
|
||||
row_group = row_group->next) {
|
||||
@ -2080,6 +2153,139 @@ bool calculate_table_widths(struct box *table)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collapse the borders of two boxes together.
|
||||
*/
|
||||
|
||||
void table_collapse_borders_v(struct box *row, struct box *cell, unsigned int columns)
|
||||
{
|
||||
struct css_border *border;
|
||||
|
||||
if (cell->start_column == 0) {
|
||||
border = css_eyecatching_border(&row->style->border[LEFT], row->style,
|
||||
&cell->style->border[LEFT], cell->style);
|
||||
cell->style->border[LEFT] = *border;
|
||||
}
|
||||
border = css_eyecatching_border(&row->style->border[TOP], row->style,
|
||||
&cell->style->border[TOP], cell->style);
|
||||
cell->style->border[TOP] = *border;
|
||||
border = css_eyecatching_border(&row->style->border[BOTTOM], row->style,
|
||||
&cell->style->border[BOTTOM], cell->style);
|
||||
cell->style->border[BOTTOM] = *border;
|
||||
if ((cell->start_column + cell->columns) == columns) {
|
||||
border = css_eyecatching_border(&row->style->border[RIGHT], row->style,
|
||||
&cell->style->border[RIGHT], cell->style);
|
||||
cell->style->border[RIGHT] = *border;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collapse the borders of two boxes together.
|
||||
*/
|
||||
|
||||
void table_collapse_borders_h(struct box *parent, struct box *child, bool *first)
|
||||
{
|
||||
struct css_border *border;
|
||||
|
||||
if (*first) {
|
||||
border = css_eyecatching_border(&parent->style->border[TOP], parent->style,
|
||||
&child->style->border[TOP], child->style);
|
||||
child->style->border[TOP] = *border;
|
||||
*first = false;
|
||||
}
|
||||
border = css_eyecatching_border(&parent->style->border[LEFT], parent->style,
|
||||
&child->style->border[LEFT], child->style);
|
||||
child->style->border[LEFT] = *border;
|
||||
border = css_eyecatching_border(&parent->style->border[RIGHT], parent->style,
|
||||
&child->style->border[RIGHT], child->style);
|
||||
child->style->border[RIGHT] = *border;
|
||||
if (!child->next) {
|
||||
border = css_eyecatching_border(&parent->style->border[BOTTOM], parent->style,
|
||||
&child->style->border[BOTTOM], child->style);
|
||||
child->style->border[BOTTOM] = *border;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collapse the borders of two boxes together.
|
||||
*/
|
||||
|
||||
void table_collapse_borders_cell(struct box *cell, struct box *right,
|
||||
struct box *bottom) {
|
||||
struct css_border *border;
|
||||
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
if ((right) && (right != cell)) {
|
||||
border = css_eyecatching_border(&cell->style->border[RIGHT], cell->style,
|
||||
&right->style->border[LEFT], right->style);
|
||||
cell->style->border[RIGHT] = *border;
|
||||
|
||||
}
|
||||
if ((bottom) && (bottom != cell)) {
|
||||
border = css_eyecatching_border(&cell->style->border[BOTTOM], cell->style,
|
||||
&bottom->style->border[TOP], bottom->style);
|
||||
cell->style->border[BOTTOM] = *border;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes all borders.
|
||||
*/
|
||||
|
||||
void table_remove_borders(struct css_style *style)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
style->border[i].style = CSS_BORDER_STYLE_NONE;
|
||||
style->border[i].width.value.value = 0;
|
||||
style->border[i].width.value.unit = CSS_UNIT_PX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a cell occupying a particular position in a table grid
|
||||
*/
|
||||
|
||||
struct box *table_find_cell(struct box *table, unsigned int x,
|
||||
unsigned int y)
|
||||
{
|
||||
struct box *row_group, *row, *cell;
|
||||
struct box *match = NULL;
|
||||
unsigned int cur_row = 0;
|
||||
|
||||
if ((x > table->columns) || (y > table->rows))
|
||||
return NULL;
|
||||
|
||||
/* this code uses brute-force and should be re-implemented using a faster
|
||||
* algorithm */
|
||||
for (row_group = table->children; row_group;
|
||||
row_group = row_group->next) {
|
||||
for (row = row_group->children; row; row = row->next) {
|
||||
for (cell = row->children; cell; cell = cell->next) {
|
||||
if (cell->start_column > x)
|
||||
break;
|
||||
if ((cell->start_column <= x) &&
|
||||
(x < (cell->start_column +
|
||||
cell->columns)))
|
||||
match = cell;
|
||||
}
|
||||
if (cur_row == y)
|
||||
return match;
|
||||
if (++cur_row > y)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively calculate the descendant_[xy][01] values for a laid-out box tree.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user