From 5085bfbf99ff3885acb2e23f8a48d18f150e294a Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sun, 1 Jun 2014 18:36:22 +0100 Subject: [PATCH] Handle overflow-x and overflow-y properties. Fixes display of BBC Sport. Requires LibCSS with support for overflow-x and overflow-y. --- css/dump.c | 29 ++++++++-- render/box.c | 12 +++- render/html_redraw.c | 105 +++++++++++++++++++++++----------- render/layout.c | 132 +++++++++++++++++++++++++++++++------------ 4 files changed, 201 insertions(+), 77 deletions(-) diff --git a/css/dump.c b/css/dump.c index fa34284e0..d3ebc9481 100644 --- a/css/dump.c +++ b/css/dump.c @@ -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; diff --git a/render/box.c b/render/box.c index 295308b5a..53f6c75d0 100644 --- a/render/box.c +++ b/render/box.c @@ -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; diff --git a/render/html_redraw.c b/render/html_redraw.c index 13cffe6ed..46d38dafe 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -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); diff --git a/render/layout.c b/render/layout.c index 7de049080..891fc4283 100644 --- a/render/layout.c +++ b/render/layout.c @@ -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;