Reduce number of page reflows and viewport

redraws as images are fetched:
+ Flag known-sized boxes generated by images.
+ Treat them as replaced all through layout.
+ Only reflow the document for fetched images
  if we don't already have the box at the
  right size.

svn path=/trunk/netsurf/; revision=12243
This commit is contained in:
Michael Drake 2011-04-27 13:50:49 +00:00
parent d0e7a5ecac
commit 1304964f92
5 changed files with 85 additions and 28 deletions

View File

@ -126,7 +126,8 @@ typedef enum {
MEASURED = 1 << 5, /* text box width has been measured */
HAS_HEIGHT = 1 << 6, /* box has height (perhaps due to children) */
MAKE_HEIGHT = 1 << 7, /* box causes its own height */
NEED_MIN = 1 << 8 /* minimum width is required for layout */
NEED_MIN = 1 << 8, /* minimum width is required for layout */
REPLACE_DIM = 1 << 9 /* replaced element has given dimensions */
} box_flags;
/* Sides of a box */

View File

@ -1159,6 +1159,11 @@ bool box_image(BOX_SPECIAL_PARAMS)
bool ok;
char *s, *url;
xmlChar *alt, *src;
enum css_width_e wtype;
enum css_height_e htype;
css_fixed value = 0;
css_unit wunit = CSS_UNIT_PX;
css_unit hunit = CSS_UNIT_PX;
if (box->style && css_computed_display(box->style,
n->parent == NULL) == CSS_DISPLAY_NONE)
@ -1196,6 +1201,17 @@ bool box_image(BOX_SPECIAL_PARAMS)
ok = html_fetch_object(content, url, box, image_types,
content->available_width, 1000, false);
free(url);
wtype = css_computed_width(box->style, &value, &wunit);
htype = css_computed_height(box->style, &value, &hunit);
if (wtype == CSS_WIDTH_SET && wunit != CSS_UNIT_PCT &&
htype == CSS_HEIGHT_SET && hunit != CSS_UNIT_PCT) {
/* We know the dimensions the image will be shown at before it's
* fetched. */
box->flags |= REPLACE_DIM;
}
return ok;
}

View File

@ -1415,8 +1415,29 @@ nserror html_object_callback(hlcache_handle *object,
break;
case CONTENT_MSG_DONE:
html_object_done(box, object, o->background);
c->active--;
if (box->flags & REPLACE_DIM) {
union content_msg_data data;
c->active--;
html_object_done(box, object, o->background);
if (!box_visible(box))
break;
box_coords(box, &x, &y);
data.redraw.x = x + box->padding[LEFT];
data.redraw.y = y + box->padding[TOP];
data.redraw.width = box->width;
data.redraw.height = box->height;
data.redraw.full_redraw = true;
content_broadcast(c, CONTENT_MSG_REDRAW, data);
} else {
c->active--;
html_object_done(box, object, o->background);
}
break;
case CONTENT_MSG_ERROR:
@ -1500,12 +1521,14 @@ nserror html_object_callback(hlcache_handle *object,
/* If 1) the configuration option to reflow pages while objects are
* fetched is set
* 2) an object is newly fetched & converted,
* 3) the object's parent HTML is ready for reformat,
* 4) the time since the previous reformat is more than the
* 3) the box's dimensions need to change due to being replaced
* 4) the object's parent HTML is ready for reformat,
* 5) the time since the previous reformat is more than the
* configured minimum time between reformats
* then reformat the page to display newly fetched objects */
else if (option_incremental_reflow &&
event->type == CONTENT_MSG_DONE &&
!(box->flags & REPLACE_DIM) &&
(c->status == CONTENT_STATUS_READY ||
c->status == CONTENT_STATUS_DONE) &&
(wallclock() > c->reformat_time)) {
@ -1532,14 +1555,16 @@ void html_object_done(struct box *box, hlcache_handle *object,
box->object = object;
/* invalidate parent min, max widths */
for (b = box; b; b = b->parent)
b->max_width = UNKNOWN_MAX_WIDTH;
if (!(box->flags & REPLACE_DIM)) {
/* invalidate parent min, max widths */
for (b = box; b; b = b->parent)
b->max_width = UNKNOWN_MAX_WIDTH;
/* delete any clones of this box */
while (box->next && (box->next->flags & CLONE)) {
/* box_free_box(box->next); */
box->next = box->next->next;
/* delete any clones of this box */
while (box->next && (box->next->flags & CLONE)) {
/* box_free_box(box->next); */
box->next = box->next->next;
}
}
}

View File

@ -427,7 +427,8 @@ bool html_redraw_box(struct box *box, int x_parent, int y_parent,
if (bg_box && bg_box->type != BOX_BR &&
bg_box->type != BOX_TEXT &&
bg_box->type != BOX_INLINE_END &&
(bg_box->type != BOX_INLINE || bg_box->object)) {
(bg_box->type != BOX_INLINE || bg_box->object ||
box->flags & REPLACE_DIM)) {
/* find intersection of clip box and border edge */
struct rect p;
p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left;
@ -471,7 +472,8 @@ bool html_redraw_box(struct box *box, int x_parent, int y_parent,
/* borders for block level content and replaced inlines */
if (box->style && box->type != BOX_TEXT &&
box->type != BOX_INLINE_END &&
(box->type != BOX_INLINE || box->object) &&
(box->type != BOX_INLINE || box->object ||
box->flags & REPLACE_DIM) &&
(border_top || border_right ||
border_bottom || border_left)) {
if (!html_redraw_borders(box, x_parent, y_parent,

View File

@ -270,6 +270,8 @@ bool layout_block_context(struct box *block, int viewport_height,
layout_get_object_dimensions(block, &block->width,
&block->height, false, true);
return true;
} else if (block->flags & REPLACE_DIM) {
return true;
}
/* special case if the block contains an radio button or checkbox */
@ -359,8 +361,9 @@ bool layout_block_context(struct box *block, int viewport_height,
* left and right margins to avoid any floats. */
lm = rm = 0;
if (box->type == BOX_BLOCK || box->object) {
if (!box->object && box->style &&
if (box->type == BOX_BLOCK || box->object) {
if (!box->object && !(box->flags & REPLACE_DIM) &&
box->style &&
css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
/* box establishes new block formatting context
@ -1115,7 +1118,8 @@ void layout_block_find_dimensions(int available_width, int viewport_height,
&width, &height, &max_width, &min_width,
margin, padding, border);
if (box->object && content_get_type(box->object) != CONTENT_HTML) {
if (box->object && !(box->flags & REPLACE_DIM) &&
content_get_type(box->object) != CONTENT_HTML) {
/* block-level replaced element, see 10.3.4 and 10.6.2 */
layout_get_object_dimensions(box, &width, &height,
true, true);
@ -1432,7 +1436,8 @@ void layout_float_find_dimensions(int available_width,
padding[RIGHT] += scrollbar_width;
padding[BOTTOM] += scrollbar_width;
if (box->object && content_get_type(box->object) != CONTENT_HTML) {
if (box->object && !(box->flags & REPLACE_DIM) &&
content_get_type(box->object) != CONTENT_HTML) {
/* Floating replaced element, with intrinsic width or height.
* See 10.3.6 and 10.6.2 */
layout_get_object_dimensions(box, &width, &height,
@ -2011,7 +2016,8 @@ bool layout_inline_container(struct box *inline_container, int width,
whitespace == CSS_WHITE_SPACE_PRE_WRAP);
}
if ((!c->object && c->text && (c->length || is_pre)) ||
if ((!c->object && !(c->flags & REPLACE_DIM) && c->text &&
(c->length || is_pre)) ||
c->type == BOX_BR)
has_text_children = true;
}
@ -2363,7 +2369,8 @@ bool layout_line(struct box *first, int *width, int *y,
continue;
}
if (!b->object && !b->gadget) {
if (!b->object && !b->gadget &&
!(b->flags & REPLACE_DIM)) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
b->height = line_height(b->style ? b->style :
b->parent->parent->style);
@ -2458,7 +2465,7 @@ bool layout_line(struct box *first, int *width, int *y,
b->height = AUTO;
}
if (b->object) {
if (b->object && !(b->flags & REPLACE_DIM)) {
layout_get_object_dimensions(b, &b->width, &b->height,
true, true);
} else {
@ -2551,7 +2558,7 @@ bool layout_line(struct box *first, int *width, int *y,
}
space_before = space_after;
if (b->object)
if (b->object || b->flags & REPLACE_DIM)
space_after = 0;
else if (b->text || b->type == BOX_INLINE_END) {
if (b->space == UNKNOWN_WIDTH) {
@ -2705,6 +2712,7 @@ bool layout_line(struct box *first, int *width, int *y,
if ((split_box->type == BOX_INLINE ||
split_box->type == BOX_TEXT) &&
!split_box->object &&
!(split_box->flags & REPLACE_DIM) &&
!split_box->gadget && split_box->text) {
/* skip leading spaces, otherwise code gets fooled into
* thinking it's all one long word */
@ -2858,7 +2866,8 @@ bool layout_line(struct box *first, int *width, int *y,
d->y = *y;
continue;
} else if ((d->type == BOX_INLINE &&
((d->object || d->gadget) == false)) ||
((d->object || d->gadget) == false) &&
!(d->flags & REPLACE_DIM)) ||
d->type == BOX_BR ||
d->type == BOX_TEXT ||
d->type == BOX_INLINE_END) {
@ -3012,7 +3021,8 @@ struct box *layout_minmax_line(struct box *first,
assert(b->style);
font_plot_style_from_css(b->style, &fstyle);
if (b->type == BOX_INLINE && !b->object) {
if (b->type == BOX_INLINE && !b->object &&
!(b->flags & REPLACE_DIM)) {
fixed = frac = 0;
calculate_mbp_width(b->style, LEFT, true, true, true,
&fixed, &frac);
@ -3040,7 +3050,8 @@ struct box *layout_minmax_line(struct box *first,
continue;
}
if (!b->object && !b->gadget) {
if (!b->object && !b->gadget &&
!(b->flags & REPLACE_DIM)) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
if (!b->text)
continue;
@ -3140,9 +3151,11 @@ struct box *layout_minmax_line(struct box *first,
height = AUTO;
}
if (b->object) {
layout_get_object_dimensions(b, &width, &height,
true, false);
if (b->object || (b->flags & REPLACE_DIM)) {
if (b->object) {
layout_get_object_dimensions(b, &width, &height,
true, false);
}
fixed = frac = 0;
calculate_mbp_width(b->style, LEFT, true, true, true,