Handle overflow-x and overflow-y properties.

Fixes display of BBC Sport.
  Requires LibCSS with support for overflow-x and overflow-y.
This commit is contained in:
Michael Drake 2014-06-01 18:36:22 +01:00
parent 576e93e1f3
commit 5085bfbf99
4 changed files with 201 additions and 77 deletions

View File

@ -1294,19 +1294,38 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
}
/* overflow */
val = css_computed_overflow(style);
val = css_computed_overflow_x(style);
switch (val) {
case CSS_OVERFLOW_VISIBLE:
fprintf(stream, "overflow: visible ");
fprintf(stream, "overflow-x: visible ");
break;
case CSS_OVERFLOW_HIDDEN:
fprintf(stream, "overflow: hidden ");
fprintf(stream, "overflow-x: hidden ");
break;
case CSS_OVERFLOW_SCROLL:
fprintf(stream, "overflow: scroll ");
fprintf(stream, "overflow-x: scroll ");
break;
case CSS_OVERFLOW_AUTO:
fprintf(stream, "overflow: auto ");
fprintf(stream, "overflow-x auto ");
break;
default:
break;
}
/* overflow */
val = css_computed_overflow_y(style);
switch (val) {
case CSS_OVERFLOW_VISIBLE:
fprintf(stream, "overflow-y: visible ");
break;
case CSS_OVERFLOW_HIDDEN:
fprintf(stream, "overflow-y: hidden ");
break;
case CSS_OVERFLOW_SCROLL:
fprintf(stream, "overflow-y: scroll ");
break;
case CSS_OVERFLOW_AUTO:
fprintf(stream, "overflow-y: auto ");
break;
default:
break;

View File

@ -584,11 +584,17 @@ bool box_contains_point(struct box *box, int x, int y, bool *physically)
*physically = true;
return true;
}
if ((box->style && css_computed_overflow(box->style) ==
if ((box->style && css_computed_overflow_x(box->style) ==
CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->x + box->descendant_x0 <= x &&
x < box->x + box->descendant_x1 &&
box->y + box->descendant_y0 <= y &&
x < box->x + box->descendant_x1) {
*physically = false;
return true;
}
}
if ((box->style && css_computed_overflow_y(box->style) ==
CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->y + box->descendant_y0 <= y &&
y < box->y + box->descendant_y1) {
*physically = false;
return true;

View File

@ -1905,10 +1905,18 @@ bool html_redraw_box(const html_content *html, struct box *box,
struct box *bg_box = NULL;
bool has_x_scroll, has_y_scroll;
css_computed_clip_rect css_rect;
enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
bool need_clip;
if (html_redraw_printing && (box->flags & PRINTED))
return true;
if (box->style != NULL) {
overflow_x = css_computed_overflow_x(box->style);
overflow_y = css_computed_overflow_y(box->style);
}
/* avoid trivial FP maths */
if (scale == 1.0) {
x = x_parent + box->x;
@ -1946,49 +1954,64 @@ bool html_redraw_box(const html_content *html, struct box *box,
}
/* calculate rectangle covering this box and descendants */
if (box->style && css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
if (box->style && overflow_x != CSS_OVERFLOW_VISIBLE) {
/* box contents clipped to box size */
r.x0 = x - border_left;
r.y0 = y - border_top;
r.x1 = x + padding_width + border_right;
r.y1 = y + padding_height + border_bottom;
} else {
/* box contents can hang out of the box; use descendant box */
if (scale == 1.0) {
r.x0 = x + box->descendant_x0;
r.y0 = y + box->descendant_y0;
r.x1 = x + box->descendant_x1 + 1;
r.y1 = y + box->descendant_y1 + 1;
} else {
r.x0 = x + box->descendant_x0 * scale;
r.y0 = y + box->descendant_y0 * scale;
r.x1 = x + box->descendant_x1 * scale + 1;
r.y1 = y + box->descendant_y1 * scale + 1;
}
if (!box->parent) {
/* root element */
int margin_left, margin_right;
int margin_top, margin_bottom;
if (scale == 1.0) {
margin_left = box->margin[LEFT];
margin_top = box->margin[TOP];
margin_right = box->margin[RIGHT];
margin_bottom = box->margin[BOTTOM];
} else {
margin_left = box->margin[LEFT] * scale;
margin_top = box->margin[TOP] * scale;
margin_right = box->margin[RIGHT] * scale;
margin_bottom = box->margin[BOTTOM] * scale;
}
r.x0 = x - border_left - margin_left < r.x0 ?
x - border_left - margin_left : r.x0;
r.y0 = y - border_top - margin_top < r.y0 ?
y - border_top - margin_top : r.y0;
r.x1 = x + padding_width + border_right +
margin_right > r.x1 ?
x + padding_width + border_right +
margin_right : r.x1;
}
}
/* calculate rectangle covering this box and descendants */
if (box->style && overflow_y != CSS_OVERFLOW_VISIBLE) {
/* box contents clipped to box size */
r.y0 = y - border_top;
r.y1 = y + padding_height + border_bottom;
} else {
/* box contents can hang out of the box; use descendant box */
if (scale == 1.0) {
r.y0 = y + box->descendant_y0;
r.y1 = y + box->descendant_y1 + 1;
} else {
r.y0 = y + box->descendant_y0 * scale;
r.y1 = y + box->descendant_y1 * scale + 1;
}
if (!box->parent) {
/* root element */
int margin_top, margin_bottom;
if (scale == 1.0) {
margin_top = box->margin[TOP];
margin_bottom = box->margin[BOTTOM];
} else {
margin_top = box->margin[TOP] * scale;
margin_bottom = box->margin[BOTTOM] * scale;
}
r.y0 = y - border_top - margin_top < r.y0 ?
y - border_top - margin_top : r.y0;
r.y1 = y + padding_height + border_bottom +
margin_bottom > r.y1 ?
y + padding_height + border_bottom +
@ -2308,24 +2331,38 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* clip to the padding edge for objects, or boxes with overflow hidden
* or scroll */
if ((box->style && css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) || box->object ||
box->flags & IFRAME) {
need_clip = false;
if (box->object || box->flags & IFRAME ||
(box->style && (overflow_x != CSS_OVERFLOW_VISIBLE ||
overflow_y != CSS_OVERFLOW_VISIBLE))) {
r.x0 = x;
r.y0 = y;
r.x1 = x + padding_width;
r.y1 = y + padding_height;
if (r.x0 < clip->x0) r.x0 = clip->x0;
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (clip->x1 < r.x1) r.x1 = clip->x1;
if (clip->y1 < r.y1) r.y1 = clip->y1;
if (r.x1 <= r.x0 || r.y1 <= r.y0)
if (r.x1 <= r.x0)
return ((!plot->group_end) || (plot->group_end()));
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->type == BOX_TABLE_CELL || box->object) {
if (!plot->clip(&r))
return false;
}
need_clip = true;
}
/* clip to the padding edge for objects, or boxes with overflow hidden
* or scroll */
if (box->object || box->flags & IFRAME ||
(box->style && (overflow_x != CSS_OVERFLOW_VISIBLE ||
overflow_y != CSS_OVERFLOW_VISIBLE))) {
r.y0 = y;
r.y1 = y + padding_height;
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (clip->y1 < r.y1) r.y1 = clip->y1;
if (r.y1 <= r.y0)
return ((!plot->group_end) || (plot->group_end()));
need_clip = true;
}
if (need_clip && (box->type == BOX_BLOCK ||
box->type == BOX_INLINE_BLOCK ||
box->type == BOX_TABLE_CELL || box->object)) {
if (!plot->clip(&r))
return false;
}
/* text decoration */
@ -2440,12 +2477,12 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* scrollbars */
if (((box->style && box->type != BOX_BR &&
box->type != BOX_TABLE && box->type != BOX_INLINE &&
(css_computed_overflow(box->style) ==
CSS_OVERFLOW_SCROLL ||
css_computed_overflow(box->style) ==
CSS_OVERFLOW_AUTO)) || (box->object &&
content_get_type(box->object) == CONTENT_HTML)) &&
box->parent != NULL) {
(overflow_x == CSS_OVERFLOW_SCROLL ||
overflow_x == CSS_OVERFLOW_AUTO ||
overflow_y == CSS_OVERFLOW_SCROLL ||
overflow_y == CSS_OVERFLOW_AUTO)) ||
(box->object && content_get_type(box->object) ==
CONTENT_HTML)) && box->parent != NULL) {
has_x_scroll = box_hscrollbar_present(box);
has_y_scroll = box_vscrollbar_present(box);

View File

@ -281,6 +281,9 @@ bool layout_block_context(struct box *block, int viewport_height,
* then the while loop will visit each box marked with *, setting box
* to each in the order shown. */
while (box) {
enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
box->type == BOX_INLINE_CONTAINER);
@ -321,6 +324,12 @@ bool layout_block_context(struct box *block, int viewport_height,
y = layout_clear(block->float_children,
css_computed_clear(box->style));
/* Find box's overflow properties */
if (box->style) {
overflow_x = css_computed_overflow_x(box->style);
overflow_y = css_computed_overflow_y(box->style);
}
/* Blocks establishing a block formatting context get minimum
* left and right margins to avoid any floats. */
lm = rm = 0;
@ -329,8 +338,8 @@ bool layout_block_context(struct box *block, int viewport_height,
if (!box->object && !(box->flags & IFRAME) &&
!(box->flags & REPLACE_DIM) &&
box->style &&
css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
(overflow_x != CSS_OVERFLOW_VISIBLE ||
overflow_y != CSS_OVERFLOW_VISIBLE)) {
/* box establishes new block formatting context
* so available width may be diminished due to
* floats. */
@ -437,8 +446,8 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Unless the box has an overflow style of visible, the box
* establishes a new block context. */
if (box->type == BOX_BLOCK && box->style &&
css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
(overflow_x != CSS_OVERFLOW_VISIBLE ||
overflow_y != CSS_OVERFLOW_VISIBLE)) {
layout_block_context(box, viewport_height, content);
@ -922,7 +931,7 @@ struct box* layout_next_margin_block(struct box *box, struct box *block,
box->border[TOP].width ||
box->padding[TOP] ||
(box->style &&
css_computed_overflow(box->style) !=
css_computed_overflow_y(box->style) !=
CSS_OVERFLOW_VISIBLE) ||
(box->type == BOX_INLINE_CONTAINER &&
box != box->parent->children)) {
@ -935,7 +944,7 @@ struct box* layout_next_margin_block(struct box *box, struct box *block,
/* Find next box */
if (box->type == BOX_BLOCK && !box->object && box->children &&
box->style &&
css_computed_overflow(box->style) ==
css_computed_overflow_y(box->style) ==
CSS_OVERFLOW_VISIBLE) {
/* Down into children. */
box = box->children;
@ -1286,32 +1295,42 @@ bool layout_apply_minmax_height(struct box *box, struct box *container)
void layout_block_add_scrollbar(struct box *box, int which)
{
enum css_overflow_e overflow;
enum css_overflow_e overflow_x, overflow_y;
assert(box->type == BOX_BLOCK && (which == RIGHT || which == BOTTOM));
if (box->style == NULL)
return;
overflow = css_computed_overflow(box->style);
overflow_x = css_computed_overflow_x(box->style);
overflow_y = css_computed_overflow_y(box->style);
if (overflow == CSS_OVERFLOW_SCROLL || overflow == CSS_OVERFLOW_AUTO ||
(box->object && content_get_type(box->object) ==
CONTENT_HTML)) {
/* make space for scrollbars, unless height/width are AUTO */
if (which == BOTTOM &&
(overflow_x == CSS_OVERFLOW_SCROLL ||
overflow_x == CSS_OVERFLOW_AUTO ||
(box->object &&
content_get_type(box->object) == CONTENT_HTML))) {
/* make space for scrollbar, unless height is AUTO */
if (box->height != AUTO &&
(overflow_x == CSS_OVERFLOW_SCROLL ||
box_hscrollbar_present(box))) {
box->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
} else if (which == RIGHT &&
(overflow_y == CSS_OVERFLOW_SCROLL ||
overflow_y == CSS_OVERFLOW_AUTO ||
(box->object &&
content_get_type(box->object) == CONTENT_HTML))) {
/* make space for scrollbars, unless width is AUTO */
enum css_height_e htype;
css_fixed height = 0;
css_unit hunit = CSS_UNIT_PX;
htype = css_computed_height(box->style, &height, &hunit);
if (which == BOTTOM && box->height != AUTO &&
(overflow == CSS_OVERFLOW_SCROLL ||
box_hscrollbar_present(box))) {
box->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
if (which == RIGHT && box->width != AUTO &&
htype == CSS_HEIGHT_SET &&
(overflow == CSS_OVERFLOW_SCROLL ||
(overflow_y == CSS_OVERFLOW_SCROLL ||
box_vscrollbar_present(box))) {
box->width -= SCROLLBAR_WIDTH;
box->padding[RIGHT] += SCROLLBAR_WIDTH;
@ -1458,9 +1477,15 @@ void layout_float_find_dimensions(int available_width,
int *margin = box->margin;
int *padding = box->padding;
struct box_border *border = box->border;
int scrollbar_width =
(css_computed_overflow(style) == CSS_OVERFLOW_SCROLL ||
css_computed_overflow(style) == CSS_OVERFLOW_AUTO) ?
enum css_overflow_e overflow_x = css_computed_overflow_x(style);
enum css_overflow_e overflow_y = css_computed_overflow_y(style);
int scrollbar_width_x =
(overflow_x == CSS_OVERFLOW_SCROLL ||
overflow_x == CSS_OVERFLOW_AUTO) ?
SCROLLBAR_WIDTH : 0;
int scrollbar_width_y =
(overflow_y == CSS_OVERFLOW_SCROLL ||
overflow_y == CSS_OVERFLOW_AUTO) ?
SCROLLBAR_WIDTH : 0;
layout_find_dimensions(available_width, -1, box, style, &width, &height,
@ -1473,8 +1498,8 @@ void layout_float_find_dimensions(int available_width,
margin[RIGHT] = 0;
if (box->gadget == NULL) {
padding[RIGHT] += scrollbar_width;
padding[BOTTOM] += scrollbar_width;
padding[RIGHT] += scrollbar_width_y;
padding[BOTTOM] += scrollbar_width_x;
}
if (box->object && !(box->flags & REPLACE_DIM) &&
@ -1555,7 +1580,7 @@ void layout_float_find_dimensions(int available_width,
} else {
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
width -= scrollbar_width;
width -= scrollbar_width_y;
}
box->width = width;
@ -3490,17 +3515,27 @@ bool layout_table(struct box *table, int available_width,
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
for (c = row->children; c; c = c->next) {
enum css_overflow_e overflow_x;
enum css_overflow_e overflow_y;
assert(c->style);
table_used_border_for_cell(c);
layout_find_dimensions(available_width, -1,
c, c->style, 0, 0, 0, 0, 0, 0,
0, c->padding, c->border);
if (css_computed_overflow(c->style) ==
CSS_OVERFLOW_SCROLL ||
css_computed_overflow(c->style) ==
overflow_x = css_computed_overflow_x(c->style);
overflow_y = css_computed_overflow_y(c->style);
if (overflow_x == CSS_OVERFLOW_SCROLL ||
overflow_x ==
CSS_OVERFLOW_AUTO) {
c->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
if (overflow_y == CSS_OVERFLOW_SCROLL ||
overflow_y ==
CSS_OVERFLOW_AUTO) {
c->padding[RIGHT] += SCROLLBAR_WIDTH;
c->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
}
}
@ -5024,7 +5059,7 @@ static void layout_get_box_bbox(struct box *box, int *desc_x0, int *desc_y0,
/* To stop the top of text getting clipped when css line-height is
* reduced, we increase the top of the descendant bbox. */
if (box->type == BOX_BLOCK && box->style != NULL &&
css_computed_overflow(box->style) ==
css_computed_overflow_y(box->style) ==
CSS_OVERFLOW_VISIBLE &&
box->object == NULL) {
css_fixed font_size = 0;
@ -5060,22 +5095,47 @@ static void layout_update_descendant_bbox(struct box *box, struct box *child,
bool html_object = (child->object &&
content_get_type(child->object) == CONTENT_HTML);
enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
if (child->style != NULL) {
overflow_x = css_computed_overflow_x(child->style);
overflow_y = css_computed_overflow_y(child->style);
}
if (html_object == true ||
overflow_x != CSS_OVERFLOW_VISIBLE ||
overflow_y != CSS_OVERFLOW_VISIBLE)
layout_get_box_bbox(child, &child_desc_x0, &child_desc_y0,
&child_desc_x1, &child_desc_y1);
if (child->style == NULL ||
(child->style && css_computed_overflow(child->style) ==
CSS_OVERFLOW_VISIBLE && html_object == false)) {
(child->style &&
overflow_x == CSS_OVERFLOW_VISIBLE &&
html_object == false)) {
/* get child's descendant bbox relative to box */
child_desc_x0 = child_x + child->descendant_x0;
child_desc_y0 = child_y + child->descendant_y0;
child_desc_x1 = child_x + child->descendant_x1;
} else {
/* child's descendants don't matter; use child's border edge */
/* get the bbox relative to box */
child_desc_x0 += child_x;
child_desc_x1 += child_x;
}
if (child->style == NULL ||
(child->style &&
overflow_y == CSS_OVERFLOW_VISIBLE &&
html_object == false)) {
/* get child's descendant bbox relative to box */
child_desc_y0 = child_y + child->descendant_y0;
child_desc_y1 = child_y + child->descendant_y1;
} else {
/* child's descendants don't matter; use child's border edge */
layout_get_box_bbox(child, &child_desc_x0, &child_desc_y0,
&child_desc_x1, &child_desc_y1);
/* get the bbox relative to box */
child_desc_x0 += child_x;
child_desc_y0 += child_y;
child_desc_x1 += child_x;
child_desc_y1 += child_y;
}
@ -5159,7 +5219,9 @@ void layout_calculate_descendant_bboxes(struct box *box)
layout_calculate_descendant_bboxes(child);
if (box->style && css_computed_overflow(box->style) ==
if (box->style && css_computed_overflow_x(box->style) ==
CSS_OVERFLOW_HIDDEN &&
css_computed_overflow_y(box->style) ==
CSS_OVERFLOW_HIDDEN)
continue;