From f8825b81e4e671abbf7f4cbc730030be9c265f69 Mon Sep 17 00:00:00 2001
From: James Bursa <james@netsurf-browser.org>
Date: Sun, 20 Jun 2004 23:09:52 +0000
Subject: [PATCH] [project @ 2004-06-20 23:09:51 by bursa] Implement
 content_stop() and html_stop().

svn path=/import/netsurf/; revision=982
---
 content/content.c | 86 ++++++++++++++++++++++++++++++++++++++++++-----
 content/content.h | 11 ++++++
 desktop/browser.c |  3 +-
 render/html.c     | 41 +++++++++++++++++++---
 render/html.h     |  1 +
 5 files changed, 127 insertions(+), 15 deletions(-)

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 @@
  *
  * - <i>type</i>_redraw(): called to plot the content to screen.
  *
+ * - <i>type</i>_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.
+ *
  * - <i>type</i>_(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,