Support HTML alignment hints.

svn path=/trunk/netsurf/; revision=9381
This commit is contained in:
John Mark Bell 2009-08-21 17:05:22 +00:00
parent e57eaed1ad
commit b0f127aa2c
4 changed files with 422 additions and 94 deletions

View File

@ -69,11 +69,8 @@ dir { display: block; padding-left: 1.5em; margin: 1.12em 0; }
menu { display: block; padding-left: 1.5em; margin: 1.12em 0; }
table { display: table; border-spacing: 2px; }
table[align=left] { float: left; }
table[align=center] { margin-left: auto; margin-right: auto; text-align: left; }
table[align=right] { float: right; text-align: left; }
caption { display: table-caption; text-align: center; }
caption { display: table-caption; }
thead { display: table-header-group; vertical-align: middle; }
tfoot { display: table-footer-group; vertical-align: middle; }
@ -82,34 +79,19 @@ tbody { display: table-row-group; vertical-align: middle; }
colgroup { display: table-column-group; }
col { display: table-column; }
tr { display: table-row; vertical-align: middle; }
table > tr { vertical-align: middle; }
tr { display: table-row; vertical-align: inherit; }
td, th { display: table-cell; vertical-align: inherit; padding: 1px; }
td { text-align: left; }
th { font-weight: bold; text-align: center; }
td[nowrap], th[nowrap] { white-space: nowrap; }
tr[align=left] > td, tr[align=left] > th { text-align: left; }
tr[align=center] > td, tr[align=center] > th { text-align: center; }
tr[align=right] > td, tr[align=right] > th { text-align: right; }
col[valign=top], colgroup[valign=top], tbody[valign=top], td[valign=top], tfoot[valign=top], th[valign=top], thead[valign=top], tr[valign=top] { vertical-align: top; }
col[valign=middle], colgroup[valign=middle], tbody[valign=middle], td[valign=middle], tfoot[valign=middle], th[valign=middle], thead[valign=middle], tr[valign=middle] { vertical-align: middle; }
col[valign=bottom], colgroup[valign=bottom], tbody[valign=bottom], td[valign=bottom], tfoot[valign=bottom], th[valign=bottom], thead[valign=bottom], tr[valign=bottom] { vertical-align: bottom; }
a:link { color: #00f; text-decoration: underline; }
img { color: #888; }
img[align=left] { float: left; }
img[align=right] { float: right; }
object[align=left] { float: left; }
object[align=right] { float: right; }
applet[align=left] { float: left; }
applet[align=right] { float: right; }
center { display: block; text-align: center; }
center { display: block; }
tt { font-family: monospace; }
i { font-style: italic; }
@ -136,15 +118,11 @@ font[size="+4"] { font-size: xx-large }
hr { display: block; background-color: #000; height: 1px;
margin: 4px auto; border: 1px #d9d9d9 inset; }
hr[align=left] { margin-left: 0; }
hr[align=right] { margin-right: 0; }
hr[noshade] { background-color: #888; height: 2px; border: none; }
noframes { display: none; }
iframe { width: 19em; height: 10em; }
iframe[align=left] { float: left; }
iframe[align=right] { float: right; }
form { display: block; }
@ -175,8 +153,4 @@ textarea { background-color: #fff; color: #000; text-align: left;
fieldset { display: block; border: thin solid #888; margin: 1.12em 0; }
[align=left] { text-align: left; }
[align=center] { text-align: center; }
[align=right] { text-align: right; }
noembed, script, style, title { display: none; }

View File

@ -1688,6 +1688,28 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
break;
}
/* -libcss-align */
val = css_computed_libcss_align(style);
switch (val) {
case CSS_LIBCSS_ALIGN_LEFT:
fprintf(stream, "-libcss-align: left ");
break;
case CSS_LIBCSS_ALIGN_RIGHT:
fprintf(stream, "-libcss-align: right ");
break;
case CSS_LIBCSS_ALIGN_CENTER:
fprintf(stream, "-libcss-align: center ");
break;
case CSS_LIBCSS_ALIGN_JUSTIFY:
fprintf(stream, "-libcss-align: justify ");
break;
case CSS_LIBCSS_ALIGN_DEFAULT:
fprintf(stream, "-libcss-align: default ");
break;
default:
break;
}
fprintf(stream, "}");
}

View File

@ -1306,6 +1306,25 @@ css_error node_presentational_hint(void *pw, void *node,
xmlFree(bgcol);
return CSS_OK;
} else if (property == CSS_PROP_CAPTION_SIDE) {
xmlChar *align = NULL;
if (strcmp((const char *) n->name, "caption") == 0)
align = xmlGetProp(n, (const xmlChar *) "align");
if (align == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) align, "bottom") == 0) {
hint->status = CSS_CAPTION_SIDE_BOTTOM;
} else {
xmlFree(align);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(align);
return CSS_OK;
} else if (property == CSS_PROP_COLOR) {
xmlChar *col;
@ -1353,6 +1372,33 @@ css_error node_presentational_hint(void *pw, void *node,
xmlFree(col);
return CSS_OK;
} else if (property == CSS_PROP_FLOAT) {
xmlChar *align = NULL;
/** \todo input[type=image][align=*] - $11.3.3 */
if (strcmp((const char *) n->name, "table") == 0 ||
strcmp((const char *) n->name, "applet") == 0 ||
strcmp((const char *) n->name, "embed") == 0 ||
strcmp((const char *) n->name, "iframe") == 0 ||
strcmp((const char *) n->name, "img") == 0 ||
strcmp((const char *) n->name, "object") == 0)
align = xmlGetProp(n, (const xmlChar *) "align");
if (align == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) align, "left") == 0) {
hint->status = CSS_FLOAT_LEFT;
} else if (strcmp((const char *) align, "right") == 0) {
hint->status = CSS_FLOAT_RIGHT;
} else {
xmlFree(align);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(align);
return CSS_OK;
} else if (property == CSS_PROP_HEIGHT) {
xmlChar *height;
@ -1592,29 +1638,84 @@ css_error node_presentational_hint(void *pw, void *node,
return CSS_OK;
} else if (property == CSS_PROP_MARGIN_RIGHT ||
property == CSS_PROP_MARGIN_LEFT) {
xmlChar *hspace;
xmlChar *hspace = NULL;
xmlChar *align = NULL;
if (strcmp((const char *) n->name, "img") == 0 ||
strcmp((const char *) n->name, "applet") == 0)
strcmp((const char *) n->name, "applet") == 0) {
hspace = xmlGetProp(n, (const xmlChar *) "hspace");
else
hspace = NULL;
if (hspace == NULL)
return CSS_PROPERTY_NOT_SET;
if (hspace == NULL)
return CSS_PROPERTY_NOT_SET;
if (parse_dimension((const char *) hspace, false,
&hint->data.length.value,
&hint->data.length.unit)) {
hint->status = CSS_MARGIN_SET;
} else {
xmlFree(hspace);
return CSS_PROPERTY_NOT_SET;
}
if (parse_dimension((const char *) hspace, false,
&hint->data.length.value,
&hint->data.length.unit)) {
hint->status = CSS_MARGIN_SET;
} else {
xmlFree(hspace);
return CSS_PROPERTY_NOT_SET;
return CSS_OK;
} else if (strcmp((const char *) n->name, "table") == 0) {
align = xmlGetProp(n, (const xmlChar *) "align");
if (align == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) align, "center") == 0 ||
strcmp((const char *) align,
"abscenter") == 0 ||
strcmp((const char *) align,
"middle") == 0 ||
strcmp((const char *) align,
"absmiddle") == 0) {
hint->status = CSS_MARGIN_AUTO;
} else {
xmlFree(align);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(align);
return CSS_OK;
} else if (strcmp((const char *) n->name, "hr") == 0) {
align = xmlGetProp(n, (const xmlChar *) "align");
if (align == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) align, "left") == 0) {
if (property == CSS_PROP_MARGIN_LEFT) {
hint->data.length.value = 0;
hint->data.length.unit = CSS_UNIT_PX;
hint->status = CSS_MARGIN_SET;
} else {
hint->status = CSS_MARGIN_AUTO;
}
} else if (strcmp((const char *) align,
"center") == 0) {
hint->status = CSS_MARGIN_AUTO;
} else if (strcmp((const char *) align, "right") == 0) {
if (property == CSS_PROP_MARGIN_RIGHT) {
hint->data.length.value = 0;
hint->data.length.unit = CSS_UNIT_PX;
hint->status = CSS_MARGIN_SET;
} else {
hint->status = CSS_MARGIN_AUTO;
}
} else {
xmlFree(align);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(align);
return CSS_OK;
}
xmlFree(hspace);
return CSS_OK;
} else if (property == CSS_PROP_PADDING_TOP ||
property == CSS_PROP_PADDING_RIGHT ||
property == CSS_PROP_PADDING_BOTTOM ||
@ -1652,6 +1753,172 @@ css_error node_presentational_hint(void *pw, void *node,
xmlFree(cellpadding);
return CSS_OK;
} else if (property == CSS_PROP_TEXT_ALIGN) {
xmlChar *align = NULL;
if (strcmp((const char *) n->name, "p") == 0 ||
strcmp((const char *) n->name, "h1") == 0 ||
strcmp((const char *) n->name, "h2") == 0 ||
strcmp((const char *) n->name, "h3") == 0 ||
strcmp((const char *) n->name, "h4") == 0 ||
strcmp((const char *) n->name, "h5") == 0 ||
strcmp((const char *) n->name, "h6") == 0)
align = xmlGetProp(n, (const xmlChar *) "align");
if (align == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) align, "left") == 0) {
hint->status = CSS_TEXT_ALIGN_LEFT;
} else if (strcmp((const char *) align, "center") == 0) {
hint->status = CSS_TEXT_ALIGN_CENTER;
} else if (strcmp((const char *) align, "right") == 0) {
hint->status = CSS_TEXT_ALIGN_RIGHT;
} else if (strcmp((const char *) align, "justify") == 0) {
hint->status = CSS_TEXT_ALIGN_JUSTIFY;
} else {
xmlFree(align);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(align);
return CSS_OK;
} else if (property == CSS_PROP_VERTICAL_ALIGN) {
xmlChar *valign = NULL;
if (strcmp((const char *) n->name, "col") == 0 ||
strcmp((const char *) n->name, "thead") == 0 ||
strcmp((const char *) n->name, "tbody") == 0 ||
strcmp((const char *) n->name, "tfoot") == 0 ||
strcmp((const char *) n->name, "tr") == 0 ||
strcmp((const char *) n->name, "td") == 0 ||
strcmp((const char *) n->name, "th") == 0) {
valign = xmlGetProp(n, (const xmlChar *) "valign");
if (valign == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) valign, "top") == 0) {
hint->status = CSS_VERTICAL_ALIGN_TOP;
} else if (strcmp((const char *) valign,
"middle") == 0) {
hint->status = CSS_VERTICAL_ALIGN_MIDDLE;
} else if (strcmp((const char *) valign,
"bottom") == 0) {
hint->status = CSS_VERTICAL_ALIGN_BOTTOM;
} else if (strcmp((const char *) valign,
"baseline") == 0) {
hint->status = CSS_VERTICAL_ALIGN_BASELINE;
} else {
xmlFree(valign);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(valign);
return CSS_OK;
} else if (strcmp((const char *) n->name, "applet") == 0 ||
strcmp((const char *) n->name, "embed") == 0 ||
strcmp((const char *) n->name, "iframe") == 0 ||
strcmp((const char *) n->name, "img") == 0 ||
strcmp((const char *) n->name, "object") == 0) {
/** \todo input[type=image][align=*] - $11.3.3 */
valign = xmlGetProp(n, (const xmlChar *) "align");
if (valign == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) valign, "top") == 0) {
hint->status = CSS_VERTICAL_ALIGN_TOP;
} else if (strcmp((const char *) valign,
"bottom") == 0 ||
strcmp((const char *) valign,
"baseline") == 0) {
hint->status = CSS_VERTICAL_ALIGN_BASELINE;
} else if (strcmp((const char *) valign,
"texttop") == 0) {
hint->status = CSS_VERTICAL_ALIGN_TEXT_TOP;
} else if (strcmp((const char *) valign,
"absmiddle") == 0 ||
strcmp((const char *) valign,
"abscenter") == 0) {
hint->status = CSS_VERTICAL_ALIGN_MIDDLE;
} else {
xmlFree(valign);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(valign);
return CSS_OK;
}
} else if (property == CSS_PROP_LIBCSS_ALIGN) {
xmlChar *align = NULL;
if (strcmp((const char *) n->name, "center") == 0) {
hint->status = CSS_LIBCSS_ALIGN_CENTER;
return CSS_OK;
} else if (strcmp((const char *) n->name, "caption") == 0) {
align = xmlGetProp(n, (const xmlChar *) "align");
if (align == NULL || strcmp((const char *) align,
"center") == 0) {
hint->status = CSS_LIBCSS_ALIGN_CENTER;
} else if (strcmp((const char *) align, "left") == 0) {
hint->status = CSS_LIBCSS_ALIGN_LEFT;
} else if (strcmp((const char *) align, "right") == 0) {
hint->status = CSS_LIBCSS_ALIGN_RIGHT;
} else if (strcmp((const char *) align,
"justify") == 0) {
hint->status = CSS_LIBCSS_ALIGN_JUSTIFY;
} else {
xmlFree(align);
return CSS_PROPERTY_NOT_SET;
}
if (align != NULL)
xmlFree(align);
return CSS_OK;
} else if (strcmp((const char *) n->name, "div") == 0 ||
strcmp((const char *) n->name, "thead") == 0 ||
strcmp((const char *) n->name, "tbody") == 0 ||
strcmp((const char *) n->name, "tfoot") == 0 ||
strcmp((const char *) n->name, "tr") == 0 ||
strcmp((const char *) n->name, "td") == 0 ||
strcmp((const char *) n->name, "th") == 0) {
align = xmlGetProp(n, (const xmlChar *) "align");
if (align == NULL)
return CSS_PROPERTY_NOT_SET;
if (strcmp((const char *) align, "center") == 0) {
hint->status = CSS_LIBCSS_ALIGN_CENTER;
} else if (strcmp((const char *) align, "left") == 0) {
hint->status = CSS_LIBCSS_ALIGN_LEFT;
} else if (strcmp((const char *) align, "right") == 0) {
hint->status = CSS_LIBCSS_ALIGN_RIGHT;
} else if (strcmp((const char *) align,
"justify") == 0) {
hint->status = CSS_LIBCSS_ALIGN_JUSTIFY;
} else {
xmlFree(align);
return CSS_PROPERTY_NOT_SET;
}
xmlFree(align);
return CSS_OK;
} else if (strcmp((const char *) n->name, "table") == 0) {
/* Tables reset HTML alignment */
hint->status = CSS_LIBCSS_ALIGN_DEFAULT;
return CSS_OK;
} else {
return CSS_PROPERTY_NOT_SET;
}
}
return CSS_PROPERTY_NOT_SET;

View File

@ -70,9 +70,8 @@ static void layout_block_find_dimensions(int available_width,
struct box *box);
static bool layout_apply_minmax_height(struct box *box, struct box *container);
static void layout_block_add_scrollbar(struct box *box, int which);
static int layout_solve_width(int available_width, int width, int lm, int rm,
int max_width, int min_width,
int margin[4], int padding[4], struct box_border border[4]);
static int layout_solve_width(struct box *box, int available_width, int width,
int lm, int rm, int max_width, int min_width);
static void layout_float_find_dimensions(int available_width,
const css_computed_style *style, struct box *box);
static void layout_find_dimensions(int available_width, int viewport_height,
@ -420,9 +419,8 @@ bool layout_block_context(struct box *block, int viewport_height,
if (!layout_table(box, box->parent->width - lm - rm,
content))
return false;
layout_solve_width(box->parent->width, box->width,
lm, rm, -1, -1, box->margin,
box->padding, box->border);
layout_solve_width(box, box->parent->width, box->width,
lm, rm, -1, -1);
}
/* Position box: horizontal. */
@ -856,8 +854,8 @@ void layout_block_find_dimensions(int available_width, int viewport_height,
}
}
box->width = layout_solve_width(available_width, width, lm, rm,
max_width, min_width, margin, padding, border);
box->width = layout_solve_width(box, available_width, width, lm, rm,
max_width, min_width);
box->height = height;
if (margin[TOP] == AUTO)
@ -1012,6 +1010,7 @@ void layout_block_add_scrollbar(struct box *box, int which)
/**
* Solve the width constraint as given in CSS 2.1 section 10.3.3.
*
* \param box Box to solve constraint for
* \param available_width Max width available in pixels
* \param width Current box width
* \param lm Min left margin required to avoid floats in px.
@ -1020,74 +1019,111 @@ void layout_block_add_scrollbar(struct box *box, int which)
* zero if not applicable
* \param max_width Box max-width ( -ve means no max-width to apply)
* \param min_width Box min-width ( <=0 means no min-width to apply)
* \param margin[4] Current box margins. Updated with new box
* left / right margins
* \param padding[4] Current box paddings.
* \param border[4] Current box border widths.
* \return New box width
*
* \post \a box's left/right margins will be updated.
*/
int layout_solve_width(int available_width, int width, int lm, int rm,
int max_width, int min_width,
int margin[4], int padding[4], struct box_border border[4])
int layout_solve_width(struct box *box, int available_width, int width,
int lm, int rm, int max_width, int min_width)
{
bool auto_width = false;
/* Increase specified left/right margins */
if (margin[LEFT] != AUTO && margin[LEFT] < lm && margin[LEFT] >= 0)
margin[LEFT] = lm;
if (margin[RIGHT] != AUTO && margin[RIGHT] < rm && margin[RIGHT] >= 0)
margin[RIGHT] = rm;
if (box->margin[LEFT] != AUTO && box->margin[LEFT] < lm &&
box->margin[LEFT] >= 0)
box->margin[LEFT] = lm;
if (box->margin[RIGHT] != AUTO && box->margin[RIGHT] < rm &&
box->margin[RIGHT] >= 0)
box->margin[RIGHT] = rm;
/* Find width */
if (width == AUTO) {
/* any other 'auto' become 0 or the minimum required values */
if (margin[LEFT] == AUTO) margin[LEFT] = lm;
if (margin[RIGHT] == AUTO) margin[RIGHT] = rm;
if (box->margin[LEFT] == AUTO)
box->margin[LEFT] = lm;
if (box->margin[RIGHT] == AUTO)
box->margin[RIGHT] = rm;
width = available_width -
(margin[LEFT] + border[LEFT].width +
padding[LEFT] + padding[RIGHT] +
border[RIGHT].width + margin[RIGHT]);
(box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
box->border[RIGHT].width + box->margin[RIGHT]);
width = width < 0 ? 0 : width;
auto_width = true;
}
if (max_width >= 0 && width > max_width) {
/* max-width is admissable and width exceeds max-width */
width = max_width;
auto_width = false;
}
if (min_width > 0 && width < min_width) {
/* min-width is admissable and width is less than max-width */
width = min_width;
auto_width = false;
}
if (!auto_width && margin[LEFT] == AUTO && margin[RIGHT] == AUTO) {
/* make the margins equal, centering the element */
margin[LEFT] = margin[RIGHT] = (available_width - lm - rm -
(border[LEFT].width + padding[LEFT] + width +
padding[RIGHT] + border[RIGHT].width)) / 2;
/* Width was auto, and unconstrained by min/max width, so we're done */
if (auto_width)
return width;
if (margin[LEFT] < 0) {
margin[RIGHT] += margin[LEFT];
margin[LEFT] = 0;
/* Width was not auto, or was constrained by min/max width
* Need to compute left/right margins */
/* HTML alignment (only applies to over-constrained boxes)
* Additionally, we ignore HTML alignment for any boxes whose
* parent has non-default text-align. */
if (box->margin[LEFT] != AUTO && box->margin[RIGHT] != AUTO &&
box->parent != NULL && box->parent->style != NULL &&
css_computed_text_align(box->parent->style) ==
CSS_TEXT_ALIGN_DEFAULT) {
switch (css_computed_libcss_align(box->parent->style)) {
case CSS_LIBCSS_ALIGN_RIGHT:
box->margin[LEFT] = AUTO;
box->margin[RIGHT] = 0;
break;
case CSS_LIBCSS_ALIGN_CENTER:
box->margin[LEFT] = box->margin[RIGHT] = AUTO;
break;
case CSS_LIBCSS_ALIGN_LEFT:
case CSS_LIBCSS_ALIGN_JUSTIFY:
box->margin[LEFT] = 0;
box->margin[RIGHT] = AUTO;
break;
}
}
if (box->margin[LEFT] == AUTO && box->margin[RIGHT] == AUTO) {
/* make the margins equal, centering the element */
box->margin[LEFT] = box->margin[RIGHT] =
(available_width - lm - rm -
(box->border[LEFT].width + box->padding[LEFT] +
width + box->padding[RIGHT] +
box->border[RIGHT].width)) / 2;
if (box->margin[LEFT] < 0) {
box->margin[RIGHT] += box->margin[LEFT];
box->margin[LEFT] = 0;
}
margin[LEFT] += lm;
box->margin[LEFT] += lm;
} else if (!auto_width && margin[LEFT] == AUTO) {
margin[LEFT] = available_width - lm -
(border[LEFT].width + padding[LEFT] + width +
padding[RIGHT] + border[RIGHT].width +
margin[RIGHT]);
margin[LEFT] = margin[LEFT] < lm ? lm : margin[LEFT];
} else if (!auto_width) {
} else if (box->margin[LEFT] == AUTO) {
box->margin[LEFT] = available_width - lm -
(box->border[LEFT].width + box->padding[LEFT] +
width + box->padding[RIGHT] +
box->border[RIGHT].width + box->margin[RIGHT]);
box->margin[LEFT] = box->margin[LEFT] < lm
? lm : box->margin[LEFT];
} else {
/* margin-right auto or "over-constrained" */
margin[RIGHT] = available_width - rm -
(margin[LEFT] + border[LEFT].width +
padding[LEFT] + width + padding[RIGHT] +
border[RIGHT].width);
box->margin[RIGHT] = available_width - rm -
(box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + width +
box->padding[RIGHT] +
box->border[RIGHT].width);
}
return width;
@ -2416,9 +2452,38 @@ bool layout_line(struct box *first, int *width, int *y,
case CSS_TEXT_ALIGN_CENTER:
x0 = (x0 + (x1 - x)) / 2;
break;
default:
case CSS_TEXT_ALIGN_LEFT:
case CSS_TEXT_ALIGN_JUSTIFY:
/* leave on left */
break;
case CSS_TEXT_ALIGN_DEFAULT:
/* No specified text-align; consider html alignment */
switch (css_computed_libcss_align(
first->parent->parent->style)) {
case CSS_LIBCSS_ALIGN_RIGHT:
x0 = x1 - x;
break;
case CSS_LIBCSS_ALIGN_CENTER:
x0 = (x0 + (x1 - x)) / 2;
break;
case CSS_LIBCSS_ALIGN_LEFT:
case CSS_LIBCSS_ALIGN_JUSTIFY:
/* leave on left */
break;
case CSS_LIBCSS_ALIGN_DEFAULT:
/* None; consider text direction */
switch (css_computed_direction(
first->parent->parent->style)) {
case CSS_DIRECTION_LTR:
/* leave on left */
break;
case CSS_DIRECTION_RTL:
x0 = x1 - x;
break;
}
break;
}
break;
}
for (d = first; d != b; d = d->next) {
@ -4177,8 +4242,8 @@ bool layout_absolute(struct box *box, struct box *containing_block,
/* \todo layout_table considers margins etc. again */
if (!layout_table(box, width, content))
return false;
layout_solve_width(box->parent->width, box->width, 0, 0, -1, -1,
box->margin, box->padding, box->border);
layout_solve_width(box, box->parent->width, box->width, 0, 0,
-1, -1);
}
/* 10.6.4 */