diff --git a/content/content.c b/content/content.c index 5b8956ab5..bee8d5350 100644 --- a/content/content.c +++ b/content/content.c @@ -124,6 +124,7 @@ struct handler_entry { bool (*convert)(struct content *c, int width, int height); void (*reformat)(struct content *c, int width, int height); void (*destroy)(struct content *c); + void (*stop)(struct content *c); void (*redraw)(struct content *c, int x, int y, int width, int height, int clip_x0, int clip_y0, int clip_x1, int clip_y1, @@ -142,42 +143,45 @@ struct handler_entry { * Must be ordered as enum ::content_type. */ static const struct handler_entry handler_map[] = { {html_create, html_process_data, html_convert, - html_reformat, html_destroy, html_redraw, + html_reformat, html_destroy, html_stop, html_redraw, html_add_instance, html_remove_instance, html_reshape_instance}, {textplain_create, html_process_data, textplain_convert, 0, 0, 0, 0, 0, 0}, - {0, 0, css_convert, 0, css_destroy, 0, 0, 0, 0}, + {0, 0, css_convert, 0, css_destroy, 0, 0, 0, 0, 0}, #ifdef WITH_JPEG {nsjpeg_create, 0, nsjpeg_convert, - 0, nsjpeg_destroy, nsjpeg_redraw, 0, 0, 0}, + 0, nsjpeg_destroy, 0, nsjpeg_redraw, 0, 0, 0}, #endif #ifdef WITH_GIF {nsgif_create, 0, nsgif_convert, - 0, nsgif_destroy, nsgif_redraw, 0, 0, 0}, + 0, nsgif_destroy, 0, nsgif_redraw, 0, 0, 0}, #endif #ifdef WITH_PNG {nspng_create, nspng_process_data, nspng_convert, - 0, nspng_destroy, nspng_redraw, 0, 0, 0}, + 0, nspng_destroy, 0, nspng_redraw, 0, 0, 0}, #endif #ifdef WITH_SPRITE {sprite_create, sprite_process_data, sprite_convert, - 0, sprite_destroy, sprite_redraw, 0, 0, 0}, + 0, sprite_destroy, 0, sprite_redraw, 0, 0, 0}, #endif #ifdef WITH_DRAW {0, 0, draw_convert, - 0, draw_destroy, draw_redraw, 0, 0, 0}, + 0, draw_destroy, 0, draw_redraw, 0, 0, 0}, #endif #ifdef WITH_PLUGIN {plugin_create, plugin_process_data, plugin_convert, - plugin_reformat, plugin_destroy, plugin_redraw, + plugin_reformat, plugin_destroy, 0, plugin_redraw, plugin_add_instance, plugin_remove_instance, plugin_reshape_instance}, #endif - {0, 0, 0, 0, 0, 0, 0, 0, 0} + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; #define HANDLER_MAP_COUNT (sizeof(handler_map) / sizeof(handler_map[0])) +static void content_stop_check(struct content *c); + + /** * Convert a MIME type to a content_type. * @@ -560,6 +564,7 @@ void content_add_user(struct content *c, user->callback = callback; user->p1 = p1; user->p2 = p2; + user->stop = false; user->next = c->user_list->next; c->user_list->next = user; } @@ -613,6 +618,8 @@ void content_remove_user(struct content *c, else content_destroy(c); } + } else if (c->status == CONTENT_STATUS_READY) { + content_stop_check(c); } } @@ -636,6 +643,67 @@ void content_broadcast(struct content *c, content_msg msg, } +/** + * Stop a content loading. + * + * May only be called in CONTENT_STATUS_READY only. If all users have requested + * stop, the loading is stopped and the content placed in CONTENT_STATUS_DONE. + */ + +void content_stop(struct content *c, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, union content_msg_data data), + void *p1, void *p2) +{ + struct content_user *user; + + assert(c->status == CONTENT_STATUS_READY); + + /* user_list starts with a sentinel */ + for (user = c->user_list; user->next != 0 && + !(user->next->callback == callback && + user->next->p1 == p1 && + user->next->p2 == p2); user = user->next) + ; + if (user->next == 0) { + LOG(("user not found in list")); + assert(0); + return; + } + user = user->next; + + user->stop = true; + + content_stop_check(c); +} + + +/** + * Check if all users have requested a stop, and do it if so. + */ + +void content_stop_check(struct content *c) +{ + struct content_user *user; + union content_msg_data data; + + assert(c->status == CONTENT_STATUS_READY); + + /* user_list starts with a sentinel */ + for (user = c->user_list->next; user; user = user->next) + if (!user->stop) + return; + + /* all users have requested stop */ + assert(handler_map[c->type].stop); + handler_map[c->type].stop(c); + assert(c->status == CONTENT_STATUS_DONE); + + content_set_status(c, messages_get("Stopped")); + content_broadcast(c, CONTENT_MSG_DONE, data); +} + + /** * Add an instance to a content. * diff --git a/content/content.h b/content/content.h index 3fcbd39fe..478e16b9e 100644 --- a/content/content.h +++ b/content/content.h @@ -45,6 +45,8 @@ * content_convert -> ERROR [label=MSG_ERROR]; * READY -> READY [style=bold]; * READY -> DONE [label=MSG_DONE, style=bold]; + * READY -> content_stop; + * content_stop -> DONE [label=MSG_DONE]; * * TYPE_UNKNOWN [shape=ellipse]; * LOADING [shape=ellipse]; @@ -74,6 +76,10 @@ * * - type_redraw(): called to plot the content to screen. * + * - type_stop(): called when the user interrupts in status + * CONTENT_STATUS_READY. Must stop any processing and set the status to + * CONTENT_STATUS_DONE. Required iff the status can be CONTENT_STATUS_READY. + * * - type_(add|remove|reshape)_instance: ask James, this will probably * be redesigned sometime. * @@ -157,6 +163,7 @@ struct content_user void *p2, union content_msg_data data); void *p1; void *p2; + bool stop; struct content_user *next; }; @@ -266,6 +273,10 @@ void content_remove_user(struct content *c, void *p1, void *p2); void content_broadcast(struct content *c, content_msg msg, union content_msg_data data); +void content_stop(struct content *c, + void (*callback)(content_msg msg, struct content *c, void *p1, + void *p2, union content_msg_data data), + void *p1, void *p2); void content_add_instance(struct content *c, struct browser_window *bw, struct content *page, struct box *box, struct object_params *params, void **state); diff --git a/desktop/browser.c b/desktop/browser.c index fb924e2df..10ad64ac2 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -388,7 +388,8 @@ void browser_window_stop(struct browser_window *bw) if (bw->current_content && bw->current_content->status != CONTENT_STATUS_DONE) { assert(bw->current_content->status == CONTENT_STATUS_READY); - /** \todo implement content_stop */ + content_stop(bw->current_content, + browser_window_callback, bw, 0); } browser_window_stop_throbber(bw); diff --git a/render/html.c b/render/html.c index 827660add..a96869313 100644 --- a/render/html.c +++ b/render/html.c @@ -668,15 +668,15 @@ void html_object_callback(content_msg msg, struct content *object, case CONTENT_MSG_REDRAW: box_coords(box, &x, &y); - if (box->object == data.redraw.object) { + if (object == data.redraw.object) { data.redraw.x = data.redraw.x * - box->width / box->object->width; + box->width / object->width; data.redraw.y = data.redraw.y * - box->height / box->object->height; + box->height / object->height; data.redraw.width = data.redraw.width * - box->width / box->object->width; + box->width / object->width; data.redraw.height = data.redraw.height * - box->height / box->object->height; + box->height / object->height; data.redraw.object_width = box->width; data.redraw.object_height = box->height; } @@ -771,6 +771,37 @@ bool html_object_type_permitted(const content_type type, } +/** + * Stop loading a CONTENT_HTML in state READY. + */ + +void html_stop(struct content *c) +{ + unsigned int i; + struct content *object; + + assert(c->status == CONTENT_STATUS_READY); + + for (i = 0; i != c->data.html.object_count; i++) { + object = c->data.html.object[i].content; + if (!object) + continue; + + if (object->status == CONTENT_STATUS_DONE) + ; /* already loaded: do nothing */ + else if (object->status == CONTENT_STATUS_READY) + content_stop(object, html_object_callback, + c, (void *) i); + else { + content_remove_user(c->data.html.object[i].content, + html_object_callback, c, (void *) i); + c->data.html.object[i].content = 0; + } + } + c->status = CONTENT_STATUS_DONE; +} + + /** * Reformat a CONTENT_HTML to a new width. */ diff --git a/render/html.h b/render/html.h index 9580beacb..6d9ad8b80 100644 --- a/render/html.h +++ b/render/html.h @@ -92,6 +92,7 @@ void html_fetch_object(struct content *c, char *url, struct box *box, const content_type *permitted_types, int available_width, int available_height, bool background); +void html_stop(struct content *c); /* in riscos/htmlinstance.c */ void html_add_instance(struct content *c, struct browser_window *bw,