From cc416b22343bdb0c0fcd8cd4e28d49d883196b62 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 10:26:55 +0100
Subject: [PATCH 01/13] Prospone pushing of DOM nodes on the stack until they
 are fully initialized

Goes for both attributes and elements.
---
 src/document/sgml/parser.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index a09af3e10..1714feb19 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -46,18 +46,22 @@ add_sgml_element(struct dom_stack *stack, struct scanner_token *token)
 	struct dom_stack_state *state;
 	struct sgml_parser_state *pstate;
 	struct dom_node *node;
+	struct sgml_node_info *node_info;
 
 	node = add_dom_element(parent, token->string, token->length);
+	if (!node) return NULL;
 
-	if (!node || !push_dom_node(stack, node))
+	node_info = get_sgml_node_info(parser->info->elements, node);
+	node->data.element.type = node_info->type;
+
+	if (!push_dom_node(stack, node))
 		return NULL;
 
 	state = get_dom_stack_top(stack);
 	assert(node == state->node && state->data);
 
 	pstate = state->data;
-	pstate->info = get_sgml_node_info(parser->info->elements, node);
-	node->data.element.type = pstate->info->type;
+	pstate->info = node_info;
 
 	return node;
 }
@@ -77,9 +81,6 @@ add_sgml_attribute(struct dom_stack *stack,
 	node = add_dom_attribute(parent, token->string, token->length,
 				 value, valuelen);
 
-	if (!node || !push_dom_node(stack, node))
-		return;
-
 	info = get_sgml_node_info(parser->info->attributes, node);
 
 	node->data.attribute.type      = info->type;
@@ -89,6 +90,9 @@ add_sgml_attribute(struct dom_stack *stack,
 	if (valtoken && valtoken->type == SGML_TOKEN_STRING)
 		node->data.attribute.quoted = 1;
 
+	if (!node || !push_dom_node(stack, node))
+		return;
+
 	pop_dom_node(stack);
 }
 

From 208515c82f6f2debeb2dd89ab9d79578e74bf191 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 11:11:06 +0100
Subject: [PATCH 02/13] Fix access to free()d memory in the DOM stack state
 data

There already was one work-around in the code related to clearing of the
state data after popping. Instead of storing a pointer to the state data in
the state we now store the depth of the state (in the stack) and use a
macro to access the state data. The bug occurred when reallocating the
stack state objects and the stack data pointers wasn't updated to point to
the newly allocated data.
---
 src/document/dom/stack.c   | 20 ++++++++++----------
 src/document/dom/stack.h   | 16 ++++++++++------
 src/document/sgml/parser.c |  4 ++--
 3 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/src/document/dom/stack.c b/src/document/dom/stack.c
index 560cb90d9..da59ec480 100644
--- a/src/document/dom/stack.c
+++ b/src/document/dom/stack.c
@@ -94,7 +94,6 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node)
 
 	if (stack->object_size) {
 		unsigned char *state_objects;
-		size_t offset = stack->depth * stack->object_size;
 
 		state_objects = realloc_dom_stack_state_objects(stack);
 		if (!state_objects) {
@@ -102,7 +101,7 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node)
 			return NULL;
 		}
 
-		state->data = (void *) &state_objects[offset];
+		state->depth = stack->depth;
 	}
 
 	state->node = node;
@@ -113,7 +112,9 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node)
 
 	callback = stack->callbacks[node->type];
 	if (callback) {
-		node = callback(stack, node, state->data);
+		void *state_data = get_dom_stack_state_data(stack, state);
+
+		node = callback(stack, node, state_data);
 
 		/* If the callback returned NULL pop the state immediately */
 		if (!node) {
@@ -136,20 +137,19 @@ do_pop_dom_node(struct dom_stack *stack, struct dom_stack_state *parent)
 
 	state = get_dom_stack_top(stack);
 	if (state->callback) {
+		void *state_data = get_dom_stack_state_data(stack, state);
+
 		/* Pass the node we are popping to and _not_ the state->node */
-		state->callback(stack, parent->node, state->data);
+		state->callback(stack, parent->node, state_data);
 	}
 
 	stack->depth--;
 	assert(stack->depth >= 0);
 
-	if (stack->object_size && state->data) {
-		size_t offset = stack->depth * stack->object_size;
+	if (stack->object_size) {
+		void *state_data = get_dom_stack_state_data(stack, state);
 
-		/* I tried to use item->data here but it caused a memory
-		 * corruption bug on fm. This is also less trustworthy in that
-		 * the state->data pointer could have been mangled. --jonas */
-		memset(&stack->state_objects[offset], 0, stack->object_size);
+		memset(state_data, 0, stack->object_size);
 	}
 
 	memset(state, 0, sizeof(*state));
diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h
index 1b6137eb8..ab2282383 100644
--- a/src/document/dom/stack.h
+++ b/src/document/dom/stack.h
@@ -28,10 +28,9 @@ struct dom_stack_state {
 	 * correctly highlighting ending elements (e.g. </a>). */
 	dom_stack_callback_T callback;
 
-	/* Parser specific data. For the SGML parser this holds DTD-oriented
-	 * info about the node (recorded in struct sgml_node_info). E.g.
-	 * whether an element node is optional. */
-	void *data;
+	/* The depth of the state in the stack. This is amongst other things
+	 * used to get the state object data. */
+	unsigned int depth;
 };
 
 /* The DOM stack is a convenient way to traverse DOM trees. Also it
@@ -42,8 +41,10 @@ struct dom_stack {
 	struct dom_stack_state *states;
 	size_t depth;
 
-	/* This is one big array of parser specific objects which will be
-	 * assigned to the data member of the individual dom_stack_states. */
+	/* This is one big array of parser specific objects. */
+	/* The objects hold parser specific data. For the SGML parser this
+	 * holds DTD-oriented info about the node (recorded in struct
+	 * sgml_node_info). E.g.  whether an element node is optional. */
 	unsigned char *state_objects;
 	size_t object_size;
 
@@ -66,6 +67,9 @@ get_dom_stack_state(struct dom_stack *stack, int top_offset)
 #define get_dom_stack_parent(nav)	get_dom_stack_state(nav, 1)
 #define get_dom_stack_top(nav)		get_dom_stack_state(nav, 0)
 
+#define get_dom_stack_state_data(stack, state) \
+	((void *) &(stack)->state_objects[(state)->depth * (stack)->object_size])
+
 /* The state iterators do not include the bottom state */
 
 #define foreach_dom_state(nav, item, pos)			\
diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index 1714feb19..dfeff6d1f 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -58,9 +58,9 @@ add_sgml_element(struct dom_stack *stack, struct scanner_token *token)
 		return NULL;
 
 	state = get_dom_stack_top(stack);
-	assert(node == state->node && state->data);
+	assert(node == state->node);
 
-	pstate = state->data;
+	pstate = get_dom_stack_state_data(stack, state);
 	pstate->info = node_info;
 
 	return node;

From f85b498375c0c497630a927804477898e8d9f7eb Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 11:11:40 +0100
Subject: [PATCH 03/13] Add FIXME about using DOM node subtypes when searching
 the DOM stack

---
 src/document/dom/stack.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h
index ab2282383..dd2e7f9b2 100644
--- a/src/document/dom/stack.h
+++ b/src/document/dom/stack.h
@@ -88,6 +88,7 @@ search_dom_stack(struct dom_stack *stack, enum dom_node_type type,
 	struct dom_stack_state *state;
 	int pos;
 
+	/* FIXME: Take node subtype and compare if non-zero or something. */
 	foreachback_dom_state (stack, state, pos) {
 		struct dom_node *parent = state->node;
 

From 8f25d73013606ee76255a15f4ca4270807c798b4 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 11:16:05 +0100
Subject: [PATCH 04/13] Use separate data variables for storing DOM stack data

They will eventually have to share the stack.
---
 src/document/dom/renderer.c   | 18 +++++++++---------
 src/document/dom/stack.c      |  5 +++--
 src/document/dom/stack.h      |  6 ++++--
 src/document/sgml/html/html.c |  4 ++--
 src/document/sgml/parser.c    |  6 +++---
 5 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c
index 08462ef57..c1ce2467c 100644
--- a/src/document/dom/renderer.c
+++ b/src/document/dom/renderer.c
@@ -387,7 +387,7 @@ add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length)
 static struct dom_node *
 render_dom_tree(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 	struct screen_char *template = &renderer->styles[node->type];
 	unsigned char *name, *value;
 
@@ -407,7 +407,7 @@ render_dom_tree(struct dom_stack *stack, struct dom_node *node, void *data)
 static struct dom_node *
 render_dom_tree_id_leaf(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 	struct document *document = renderer->document;
 	struct screen_char *template = &renderer->styles[node->type];
 	unsigned char *name, *value, *id;
@@ -430,7 +430,7 @@ render_dom_tree_id_leaf(struct dom_stack *stack, struct dom_node *node, void *da
 static struct dom_node *
 render_dom_tree_leaf(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 	struct document *document = renderer->document;
 	struct screen_char *template = &renderer->styles[node->type];
 	unsigned char *name, *value;
@@ -452,7 +452,7 @@ render_dom_tree_leaf(struct dom_stack *stack, struct dom_node *node, void *data)
 static struct dom_node *
 render_dom_tree_branch(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 	struct document *document = renderer->document;
 	struct screen_char *template = &renderer->styles[node->type];
 	unsigned char *name, *id;
@@ -536,7 +536,7 @@ render_dom_node_text(struct dom_renderer *renderer, struct screen_char *template
 static struct dom_node *
 render_dom_node_source(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 
 	assert(node && renderer && renderer->document);
 
@@ -550,7 +550,7 @@ render_dom_node_source(struct dom_stack *stack, struct dom_node *node, void *dat
 static struct dom_node *
 render_dom_proc_instr_source(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 	unsigned char *value;
 	int valuelen;
 
@@ -577,7 +577,7 @@ render_dom_proc_instr_source(struct dom_stack *stack, struct dom_node *node, voi
 static struct dom_node *
 render_dom_element_source(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 
 	assert(node && renderer && renderer->document);
 
@@ -590,7 +590,7 @@ static struct dom_node *
 render_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void *data)
 {
 	struct dom_stack_state *state = get_dom_stack_parent(stack);
-	struct dom_renderer *renderer = stack->data;
+	struct dom_renderer *renderer = stack->renderer;
 	struct screen_char *template = &renderer->styles[node->type];
 	struct dom_node *attribute = NULL;
 	int i;
@@ -714,7 +714,7 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 					  document->options.hard_assume);
 
 	init_dom_renderer(&renderer, document, buffer, convert_table);
-	init_dom_stack(&stack, &renderer, callbacks, 0);
+	init_dom_stack(&stack, NULL, &renderer, callbacks, 0);
 
 	document->bgcolor = document->options.default_bg;
 
diff --git a/src/document/dom/stack.c b/src/document/dom/stack.c
index da59ec480..cc184a432 100644
--- a/src/document/dom/stack.c
+++ b/src/document/dom/stack.c
@@ -45,7 +45,7 @@ realloc_dom_stack_state_objects(struct dom_stack *stack)
 }
 
 void
-init_dom_stack(struct dom_stack *stack, void *data,
+init_dom_stack(struct dom_stack *stack, void *parser, void *renderer,
 	       dom_stack_callback_T callbacks[DOM_NODES],
 	       size_t object_size)
 {
@@ -53,7 +53,8 @@ init_dom_stack(struct dom_stack *stack, void *data,
 
 	memset(stack, 0, sizeof(*stack));
 
-	stack->data        = data;
+	stack->parser      = parser;
+	stack->renderer    = renderer;
 	stack->object_size = object_size;
 
 	if (callbacks)
diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h
index dd2e7f9b2..4833521b3 100644
--- a/src/document/dom/stack.h
+++ b/src/document/dom/stack.h
@@ -50,7 +50,9 @@ struct dom_stack {
 
 	/* Parser and document specific stuff */
 	dom_stack_callback_T callbacks[DOM_NODES];
-	void *data;
+	void *renderer;
+
+	void *parser;
 };
 
 #define dom_stack_has_parents(nav) \
@@ -107,7 +109,7 @@ search_dom_stack(struct dom_stack *stack, enum dom_node_type type,
 /* The @object_size arg tells whether the stack should allocate objects for each
  * state to be assigned to the state's @data member. Zero means no state data should
  * be allocated. */
-void init_dom_stack(struct dom_stack *stack, void *data,
+void init_dom_stack(struct dom_stack *stack, void *parser, void *renderer,
 		    dom_stack_callback_T callbacks[DOM_NODES],
 		    size_t object_size);
 void done_dom_stack(struct dom_stack *stack);
diff --git a/src/document/sgml/html/html.c b/src/document/sgml/html/html.c
index b1df7d4df..28cad646c 100644
--- a/src/document/sgml/html/html.c
+++ b/src/document/sgml/html/html.c
@@ -40,7 +40,7 @@ static struct sgml_node_info html_elements[HTML_ELEMENTS] = {
 static struct dom_node *
 add_html_element_end_node(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct sgml_parser *parser = stack->data;
+	struct sgml_parser *parser = stack->parser;
 	struct dom_node *parent;
 	struct scanner_token *token;
 
@@ -67,7 +67,7 @@ add_html_element_end_node(struct dom_stack *stack, struct dom_node *node, void *
 static struct dom_node *
 add_html_element_node(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct sgml_parser *parser = stack->data;
+	struct sgml_parser *parser = stack->parser;
 
 	assert(stack && node);
 	assert(dom_stack_has_parents(stack));
diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index dfeff6d1f..6770825d0 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -41,7 +41,7 @@ add_sgml_document(struct dom_stack *stack, struct uri *uri)
 static inline struct dom_node *
 add_sgml_element(struct dom_stack *stack, struct scanner_token *token)
 {
-	struct sgml_parser *parser = stack->data;
+	struct sgml_parser *parser = stack->parser;
 	struct dom_node *parent = get_dom_stack_top(stack)->node;
 	struct dom_stack_state *state;
 	struct sgml_parser_state *pstate;
@@ -71,7 +71,7 @@ static inline void
 add_sgml_attribute(struct dom_stack *stack,
 		  struct scanner_token *token, struct scanner_token *valtoken)
 {
-	struct sgml_parser *parser = stack->data;
+	struct sgml_parser *parser = stack->parser;
 	struct dom_node *parent = get_dom_stack_top(stack)->node;
 	unsigned char *value = valtoken ? valtoken->string : NULL;
 	uint16_t valuelen = valtoken ? valtoken->length : 0;
@@ -309,7 +309,7 @@ init_sgml_parser(struct cache_entry *cached, struct document *document)
 	parser->cache_entry = cached;
 	parser->info	    = &sgml_html_info;
 
-	init_dom_stack(&parser->stack, parser, parser->info->callbacks, obj_size);
+	init_dom_stack(&parser->stack, parser, NULL, parser->info->callbacks, obj_size);
 
 	if (document->options.plain)
 		parser->flags |= SGML_PARSER_ADD_ELEMENT_ENDS;

From 05a61cd16a00d9d5bc1adad876d00e39fab9b4bc Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 11:16:52 +0100
Subject: [PATCH 05/13] Update the DOM stack comment for things to come

---
 src/document/dom/stack.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h
index 4833521b3..126bce0f9 100644
--- a/src/document/dom/stack.h
+++ b/src/document/dom/stack.h
@@ -48,10 +48,11 @@ struct dom_stack {
 	unsigned char *state_objects;
 	size_t object_size;
 
-	/* Parser and document specific stuff */
+	/* Renderer specific callbacks for the streaming parser mode. */
 	dom_stack_callback_T callbacks[DOM_NODES];
-	void *renderer;
 
+	/* Data specific to the parser and renderer. */
+	void *renderer;
 	void *parser;
 };
 

From 4c8d87140438110493d254672ceed67ab383fb44 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 11:19:13 +0100
Subject: [PATCH 06/13] Introduce sgml_parser_type for specifying tree and
 streaming parsers

Mostly added for the future, since currently only one parser type is
supported.
---
 src/document/dom/renderer.c |  2 +-
 src/document/sgml/parser.c  |  4 +++-
 src/document/sgml/parser.h  | 16 +++++++++++++++-
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c
index c1ce2467c..cb3168610 100644
--- a/src/document/dom/renderer.c
+++ b/src/document/dom/renderer.c
@@ -700,7 +700,7 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 
 	assert(document->options.plain);
 
-	parser = init_sgml_parser(cached, document);
+	parser = init_sgml_parser(SGML_PARSER_STREAM, cached, document);
 	if (!parser) return;
 
 	root = parse_sgml(parser, buffer);
diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index 6770825d0..0f86a77c4 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -297,7 +297,8 @@ parse_sgml_document(struct dom_stack *stack, struct scanner *scanner)
 
 
 struct sgml_parser *
-init_sgml_parser(struct cache_entry *cached, struct document *document)
+init_sgml_parser(enum sgml_parser_type type, struct cache_entry *cached,
+		 struct document *document)
 {
 	size_t obj_size = sizeof(struct sgml_parser_state);
 	struct sgml_parser *parser;
@@ -305,6 +306,7 @@ init_sgml_parser(struct cache_entry *cached, struct document *document)
 	parser = mem_calloc(1, sizeof(*parser));
 	if (!parser) return NULL;
 
+	parser->type	    = type;
 	parser->document    = document;
 	parser->cache_entry = cached;
 	parser->info	    = &sgml_html_info;
diff --git a/src/document/sgml/parser.h b/src/document/sgml/parser.h
index 21801787d..101a5afe3 100644
--- a/src/document/sgml/parser.h
+++ b/src/document/sgml/parser.h
@@ -11,11 +11,24 @@ struct cache_entry;
 struct document;
 struct string;
 
+enum sgml_parser_type {
+	/* The first one is a DOM tree builder. */
+	SGML_PARSER_TREE,
+	/* The second one will simply push nodes on the stack, not building a
+	 * DOM tree. This interface is similar to that of SAX (Simple API for
+	 * XML) where events are fired when nodes are entered and exited. It is
+	 * useful when you are not actually interested in the DOM tree, but can
+	 * do all processing in a stream-like manner, such as when highlighting
+	 * HTML code. */
+	SGML_PARSER_STREAM,
+};
+
 enum sgml_parser_flags {
 	SGML_PARSER_ADD_ELEMENT_ENDS = 1,
 };
 
 struct sgml_parser {
+	enum sgml_parser_type type;
 	/* The parser flags controls what gets added to the DOM tree */
 	enum sgml_parser_flags flags;
 	struct sgml_info *info;
@@ -33,7 +46,8 @@ struct sgml_parser_state {
 };
 
 struct sgml_parser *
-init_sgml_parser(struct cache_entry *cached, struct document *document);
+init_sgml_parser(enum sgml_parser_type type,
+		 struct cache_entry *cached, struct document *document);
 
 void done_sgml_parser(struct sgml_parser *parser);
 

From 65b504f093c84d50a652652e005aa6867f29eb86 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 11:21:08 +0100
Subject: [PATCH 07/13] Remove all traces of the element end-tag hilighting
 hack

End-tags will stay uncolored for the next few commits.
---
 src/document/dom/stack.c      |  6 ----
 src/document/dom/stack.h      |  4 ---
 src/document/sgml/html/html.c | 59 -----------------------------------
 src/document/sgml/parser.c    |  5 +--
 src/document/sgml/parser.h    |  7 +----
 src/document/sgml/sgml.h      |  1 -
 6 files changed, 2 insertions(+), 80 deletions(-)

diff --git a/src/document/dom/stack.c b/src/document/dom/stack.c
index cc184a432..a0d788069 100644
--- a/src/document/dom/stack.c
+++ b/src/document/dom/stack.c
@@ -137,12 +137,6 @@ do_pop_dom_node(struct dom_stack *stack, struct dom_stack_state *parent)
 	if (!dom_stack_has_parents(stack)) return 0;
 
 	state = get_dom_stack_top(stack);
-	if (state->callback) {
-		void *state_data = get_dom_stack_state_data(stack, state);
-
-		/* Pass the node we are popping to and _not_ the state->node */
-		state->callback(stack, parent->node, state_data);
-	}
 
 	stack->depth--;
 	assert(stack->depth >= 0);
diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h
index 126bce0f9..57bb7726c 100644
--- a/src/document/dom/stack.h
+++ b/src/document/dom/stack.h
@@ -24,10 +24,6 @@ struct dom_stack_state {
 	/* The index (in the list above) which are currently being handled. */
 	size_t index;
 
-	/* A callback registered to be called when the node is popped. Used for
-	 * correctly highlighting ending elements (e.g. </a>). */
-	dom_stack_callback_T callback;
-
 	/* The depth of the state in the stack. This is amongst other things
 	 * used to get the state object data. */
 	unsigned int depth;
diff --git a/src/document/sgml/html/html.c b/src/document/sgml/html/html.c
index 28cad646c..63157fc56 100644
--- a/src/document/sgml/html/html.c
+++ b/src/document/sgml/html/html.c
@@ -37,66 +37,7 @@ static struct sgml_node_info html_elements[HTML_ELEMENTS] = {
 };
 
 
-static struct dom_node *
-add_html_element_end_node(struct dom_stack *stack, struct dom_node *node, void *data)
-{
-	struct sgml_parser *parser = stack->parser;
-	struct dom_node *parent;
-	struct scanner_token *token;
-
-	assert(stack && parser && node);
-	assert(dom_stack_has_parents(stack));
-
-	/* Are we the actual node being popped? */
-	if (node != get_dom_stack_top(stack)->node)
-		return NULL;
-
-	parent = get_dom_stack_parent(stack)->node;
-	token  = get_scanner_token(&parser->scanner);
-
-	assertm(token, "No token found in callback");
-	assertm(token->type == SGML_TOKEN_ELEMENT_END, "Bad token found in callback");
-
-	if (!token->length) return NULL;
-
-	return add_dom_element(parent, token->string, token->length);
-}
-
-/* TODO: We need to handle ascending of <br> and "<p>text1<p>text2" using data
- * from sgml_node_info. */
-static struct dom_node *
-add_html_element_node(struct dom_stack *stack, struct dom_node *node, void *data)
-{
-	struct sgml_parser *parser = stack->parser;
-
-	assert(stack && node);
-	assert(dom_stack_has_parents(stack));
-
-	/* TODO: Move to SGML parser main loop and disguise these element ends
-	 * in some internal processing instruction. */
-	if (parser->flags & SGML_PARSER_ADD_ELEMENT_ENDS)
-		get_dom_stack_top(stack)->callback = add_html_element_end_node;
-
-	return node;
-}
-
-
 struct sgml_info sgml_html_info = {
 	html_attributes,
 	html_elements,
-	{
-		/*				*/ NULL,
-		/* DOM_NODE_ELEMENT		*/ add_html_element_node,
-		/* DOM_NODE_ATTRIBUTE		*/ NULL,
-		/* DOM_NODE_TEXT		*/ NULL,
-		/* DOM_NODE_CDATA_SECTION	*/ NULL,
-		/* DOM_NODE_ENTITY_REFERENCE	*/ NULL,
-		/* DOM_NODE_ENTITY		*/ NULL,
-		/* DOM_NODE_PROC_INSTRUCTION	*/ NULL,
-		/* DOM_NODE_COMMENT		*/ NULL,
-		/* DOM_NODE_DOCUMENT		*/ NULL,
-		/* DOM_NODE_DOCUMENT_TYPE	*/ NULL,
-		/* DOM_NODE_DOCUMENT_FRAGMENT	*/ NULL,
-		/* DOM_NODE_NOTATION		*/ NULL,
-	}
 };
diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index 0f86a77c4..7f1ef015d 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -311,10 +311,7 @@ init_sgml_parser(enum sgml_parser_type type, struct cache_entry *cached,
 	parser->cache_entry = cached;
 	parser->info	    = &sgml_html_info;
 
-	init_dom_stack(&parser->stack, parser, NULL, parser->info->callbacks, obj_size);
-
-	if (document->options.plain)
-		parser->flags |= SGML_PARSER_ADD_ELEMENT_ENDS;
+	init_dom_stack(&parser->stack, parser, NULL, NULL, obj_size);
 
 	return parser;
 }
diff --git a/src/document/sgml/parser.h b/src/document/sgml/parser.h
index 101a5afe3..2225fafd3 100644
--- a/src/document/sgml/parser.h
+++ b/src/document/sgml/parser.h
@@ -23,14 +23,9 @@ enum sgml_parser_type {
 	SGML_PARSER_STREAM,
 };
 
-enum sgml_parser_flags {
-	SGML_PARSER_ADD_ELEMENT_ENDS = 1,
-};
-
 struct sgml_parser {
 	enum sgml_parser_type type;
-	/* The parser flags controls what gets added to the DOM tree */
-	enum sgml_parser_flags flags;
+
 	struct sgml_info *info;
 
 	struct document *document;
diff --git a/src/document/sgml/sgml.h b/src/document/sgml/sgml.h
index a33e54b68..a2b5ccba0 100644
--- a/src/document/sgml/sgml.h
+++ b/src/document/sgml/sgml.h
@@ -76,7 +76,6 @@ get_sgml_node_info(struct sgml_node_info list[], struct dom_node *node)
 struct sgml_info {
 	struct sgml_node_info *attributes;
 	struct sgml_node_info *elements;
-	dom_stack_callback_T callbacks[DOM_NODES];
 };
 
 #endif

From 2dddf86accaf93fe709a1f72163a034d6e828735 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 19:20:48 +0100
Subject: [PATCH 08/13] Initialize the renderer before initializing the parser

... so it is ready when/if the parser will push any initial states.
---
 src/document/dom/renderer.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c
index cb3168610..5a83bb3fb 100644
--- a/src/document/dom/renderer.c
+++ b/src/document/dom/renderer.c
@@ -700,13 +700,6 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 
 	assert(document->options.plain);
 
-	parser = init_sgml_parser(SGML_PARSER_STREAM, cached, document);
-	if (!parser) return;
-
-	root = parse_sgml(parser, buffer);
-	done_sgml_parser(parser);
-	if (!root) return;
-
 	convert_table = get_convert_table(head, document->options.cp,
 					  document->options.assume_cp,
 					  &document->cp,
@@ -718,6 +711,19 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 
 	document->bgcolor = document->options.default_bg;
 
+	parser = init_sgml_parser(SGML_PARSER_STREAM, cached, document);
+	if (!parser) {
+		done_dom_stack(&stack);
+		return;
+	}
+
+	root = parse_sgml(parser, buffer);
+	done_sgml_parser(parser);
+	if (!root) {
+		done_dom_stack(&stack);
+		return;
+	}
+
 	walk_dom_nodes(&stack, root);
 	/* If there are no non-element nodes after the last element node make
 	 * sure that we flush to the end of the cache entry source including

From 7a912795e1c8acac296b9189df51eca65bc62318 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 19:25:13 +0100
Subject: [PATCH 09/13] Make the parser stream mode work as intended

This makes the parser and renderer share the stack, most importantly the
callbacks are now those of the renderer. Disable node attribute rendering
code that worked around the attributes being visited in sorted order.
---
 src/document/dom/renderer.c | 52 ++++++++++++++++++-------------------
 src/document/sgml/parser.c  |  7 ++---
 src/document/sgml/parser.h  |  5 ++--
 3 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c
index 5a83bb3fb..cfd826c7f 100644
--- a/src/document/dom/renderer.c
+++ b/src/document/dom/renderer.c
@@ -589,25 +589,34 @@ render_dom_element_source(struct dom_stack *stack, struct dom_node *node, void *
 static struct dom_node *
 render_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void *data)
 {
-	struct dom_stack_state *state = get_dom_stack_parent(stack);
 	struct dom_renderer *renderer = stack->renderer;
 	struct screen_char *template = &renderer->styles[node->type];
-	struct dom_node *attribute = NULL;
-	int i;
 
 	assert(node && renderer->document);
-	assert(state && state->list);
 
-	/* The attributes are sorted but we want them in the original order */
-	foreach_dom_node(i, node, state->list) {
-		if (node->string >= renderer->position
-		    && (!attribute || node->string < attribute->string))
-			attribute = node;
+#if 0
+	/* Disabled since the DOM source highlighter uses the stream parser and
+	 * therefore the attributes is pushed to it in order. However, if/when
+	 * we will support rendering (read saving) of loaded DOM trees this one
+	 * small hack is needed to get the attributes in the original order. */
+	{
+		struct dom_stack_state *state = get_dom_stack_parent(stack);
+		struct dom_node *attribute = NULL;
+		int i;
+
+		assert(state && state->list);
+
+		/* The attributes are sorted but we want them in the original order */
+		foreach_dom_node(i, node, state->list) {
+			if (node->string >= renderer->position
+				&& (!attribute || node->string < attribute->string))
+				attribute = node;
+		}
+
+		assert(attribute);
+		node = attribute;
 	}
-
-	assert(attribute);
-	node = attribute;
-
+#endif
 	render_dom_node_text(renderer, template, node);
 
 	if (node->data.attribute.value) {
@@ -696,7 +705,6 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 	struct conv_table *convert_table;
 	dom_stack_callback_T *callbacks = dom_source_renderer_callbacks;
 	struct sgml_parser *parser;
-	struct dom_stack stack;
 
 	assert(document->options.plain);
 
@@ -707,24 +715,17 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 					  document->options.hard_assume);
 
 	init_dom_renderer(&renderer, document, buffer, convert_table);
-	init_dom_stack(&stack, NULL, &renderer, callbacks, 0);
 
 	document->bgcolor = document->options.default_bg;
 
-	parser = init_sgml_parser(SGML_PARSER_STREAM, cached, document);
-	if (!parser) {
-		done_dom_stack(&stack);
-		return;
-	}
+	parser = init_sgml_parser(SGML_PARSER_STREAM, &renderer, cached,
+				  document, callbacks);
+	if (!parser) return;
 
 	root = parse_sgml(parser, buffer);
 	done_sgml_parser(parser);
-	if (!root) {
-		done_dom_stack(&stack);
-		return;
-	}
+	if (!root) return;
 
-	walk_dom_nodes(&stack, root);
 	/* If there are no non-element nodes after the last element node make
 	 * sure that we flush to the end of the cache entry source including
 	 * the '>' of the last element tag if it has one. (bug 519) */
@@ -733,5 +734,4 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 	}
 
 	done_dom_node(root);
-	done_dom_stack(&stack);
 }
diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index 7f1ef015d..288208c1e 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -297,8 +297,9 @@ parse_sgml_document(struct dom_stack *stack, struct scanner *scanner)
 
 
 struct sgml_parser *
-init_sgml_parser(enum sgml_parser_type type, struct cache_entry *cached,
-		 struct document *document)
+init_sgml_parser(enum sgml_parser_type type, void *renderer,
+		 struct cache_entry *cached, struct document *document,
+		 dom_stack_callback_T callbacks[DOM_NODES])
 {
 	size_t obj_size = sizeof(struct sgml_parser_state);
 	struct sgml_parser *parser;
@@ -311,7 +312,7 @@ init_sgml_parser(enum sgml_parser_type type, struct cache_entry *cached,
 	parser->cache_entry = cached;
 	parser->info	    = &sgml_html_info;
 
-	init_dom_stack(&parser->stack, parser, NULL, NULL, obj_size);
+	init_dom_stack(&parser->stack, parser, renderer, callbacks, obj_size);
 
 	return parser;
 }
diff --git a/src/document/sgml/parser.h b/src/document/sgml/parser.h
index 2225fafd3..2883d5a06 100644
--- a/src/document/sgml/parser.h
+++ b/src/document/sgml/parser.h
@@ -41,8 +41,9 @@ struct sgml_parser_state {
 };
 
 struct sgml_parser *
-init_sgml_parser(enum sgml_parser_type type,
-		 struct cache_entry *cached, struct document *document);
+init_sgml_parser(enum sgml_parser_type type, void *renderer,
+		 struct cache_entry *cached, struct document *document,
+		 dom_stack_callback_T callbacks[DOM_NODES]);
 
 void done_sgml_parser(struct sgml_parser *parser);
 

From d7d5fcab4d7e268f957af6641995cc6d6fa05a4e Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 19:28:23 +0100
Subject: [PATCH 10/13] Save the end tag token in the SGML parser state

... so that the renderer eventually can pick it up and highlight it.
---
 src/document/sgml/parser.c | 12 ++++++++++++
 src/document/sgml/parser.h |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index 288208c1e..238db88ac 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -247,6 +247,18 @@ parse_sgml_document(struct dom_stack *stack, struct scanner *scanner)
 			if (!token->length) {
 				pop_dom_node(stack);
 			} else {
+				struct dom_stack_state *state;
+
+				state = search_dom_stack(stack, DOM_NODE_ELEMENT,
+							 token->string, token->length);
+				if (state) {
+					struct sgml_parser_state *pstate;
+
+					pstate = get_dom_stack_state_data(stack, state);
+
+					copy_struct(&pstate->end_token, token);
+				}
+
 				pop_dom_nodes(stack, DOM_NODE_ELEMENT,
 					      token->string, token->length);
 			}
diff --git a/src/document/sgml/parser.h b/src/document/sgml/parser.h
index 2883d5a06..fbacc0886 100644
--- a/src/document/sgml/parser.h
+++ b/src/document/sgml/parser.h
@@ -38,6 +38,9 @@ struct sgml_parser {
 
 struct sgml_parser_state {
 	struct sgml_node_info *info;
+	/* This is used by the DOM source renderer for highlighting the
+	 * end-tag of an element. */
+	struct scanner_token end_token;
 };
 
 struct sgml_parser *

From 9aebb66bce7cde98368adc20596977cd4059a33c Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 19:31:42 +0100
Subject: [PATCH 11/13] Introduce separate push/pop callbacks

This should make it possible to do the SAX (parser stream thing) for XBEL.
And will also be used for fixing the end-tag highlighting.
---
 src/document/dom/renderer.c | 23 ++++++++++++++++++++---
 src/document/dom/stack.c    | 18 ++++++++++++++----
 src/document/dom/stack.h    |  6 ++++--
 src/document/sgml/parser.c  |  6 ++++--
 src/document/sgml/parser.h  |  3 ++-
 5 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c
index cfd826c7f..6cc70e0ec 100644
--- a/src/document/dom/renderer.c
+++ b/src/document/dom/renderer.c
@@ -677,7 +677,7 @@ render_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void
 	return node;
 }
 
-static dom_stack_callback_T dom_source_renderer_callbacks[DOM_NODES] = {
+static dom_stack_callback_T dom_source_renderer_push_callbacks[DOM_NODES] = {
 	/*				*/ NULL,
 	/* DOM_NODE_ELEMENT		*/ render_dom_element_source,
 	/* DOM_NODE_ATTRIBUTE		*/ render_dom_attribute_source,
@@ -693,6 +693,22 @@ static dom_stack_callback_T dom_source_renderer_callbacks[DOM_NODES] = {
 	/* DOM_NODE_NOTATION		*/ render_dom_node_source,
 };
 
+static dom_stack_callback_T dom_source_renderer_pop_callbacks[DOM_NODES] = {
+	/*				*/ NULL,
+	/* DOM_NODE_ELEMENT		*/ NULL,
+	/* DOM_NODE_ATTRIBUTE		*/ NULL,
+	/* DOM_NODE_TEXT		*/ NULL,
+	/* DOM_NODE_CDATA_SECTION	*/ NULL,
+	/* DOM_NODE_ENTITY_REFERENCE	*/ NULL,
+	/* DOM_NODE_ENTITY		*/ NULL,
+	/* DOM_NODE_PROC_INSTRUCTION	*/ NULL,
+	/* DOM_NODE_COMMENT		*/ NULL,
+	/* DOM_NODE_DOCUMENT		*/ NULL,
+	/* DOM_NODE_DOCUMENT_TYPE	*/ NULL,
+	/* DOM_NODE_DOCUMENT_FRAGMENT	*/ NULL,
+	/* DOM_NODE_NOTATION		*/ NULL,
+};
+
 
 /* Shared multiplexor between renderers */
 void
@@ -703,7 +719,6 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 	struct dom_node *root;
 	struct dom_renderer renderer;
 	struct conv_table *convert_table;
-	dom_stack_callback_T *callbacks = dom_source_renderer_callbacks;
 	struct sgml_parser *parser;
 
 	assert(document->options.plain);
@@ -719,7 +734,9 @@ render_dom_document(struct cache_entry *cached, struct document *document,
 	document->bgcolor = document->options.default_bg;
 
 	parser = init_sgml_parser(SGML_PARSER_STREAM, &renderer, cached,
-				  document, callbacks);
+				  document,
+				  dom_source_renderer_push_callbacks,
+				  dom_source_renderer_pop_callbacks);
 	if (!parser) return;
 
 	root = parse_sgml(parser, buffer);
diff --git a/src/document/dom/stack.c b/src/document/dom/stack.c
index a0d788069..c6be1b61a 100644
--- a/src/document/dom/stack.c
+++ b/src/document/dom/stack.c
@@ -46,7 +46,8 @@ realloc_dom_stack_state_objects(struct dom_stack *stack)
 
 void
 init_dom_stack(struct dom_stack *stack, void *parser, void *renderer,
-	       dom_stack_callback_T callbacks[DOM_NODES],
+	       dom_stack_callback_T push_callbacks[DOM_NODES],
+	       dom_stack_callback_T pop_callbacks[DOM_NODES],
 	       size_t object_size)
 {
 	assert(stack);
@@ -57,8 +58,10 @@ init_dom_stack(struct dom_stack *stack, void *parser, void *renderer,
 	stack->renderer    = renderer;
 	stack->object_size = object_size;
 
-	if (callbacks)
-		memcpy(stack->callbacks, callbacks, DOM_STACK_CALLBACKS_SIZE);
+	if (push_callbacks)
+		memcpy(stack->push_callbacks, push_callbacks, DOM_STACK_CALLBACKS_SIZE);
+	if (pop_callbacks)
+		memcpy(stack->pop_callbacks, pop_callbacks, DOM_STACK_CALLBACKS_SIZE);
 }
 
 void
@@ -111,7 +114,7 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node)
 	 * in the callbacks */
 	stack->depth++;
 
-	callback = stack->callbacks[node->type];
+	callback = stack->push_callbacks[node->type];
 	if (callback) {
 		void *state_data = get_dom_stack_state_data(stack, state);
 
@@ -132,11 +135,18 @@ static int
 do_pop_dom_node(struct dom_stack *stack, struct dom_stack_state *parent)
 {
 	struct dom_stack_state *state;
+	dom_stack_callback_T callback;
 
 	assert(stack);
 	if (!dom_stack_has_parents(stack)) return 0;
 
 	state = get_dom_stack_top(stack);
+	callback = stack->pop_callbacks[state->node->type];
+	if (callback) {
+		void *state_data = get_dom_stack_state_data(stack, state);
+
+		callback(stack, state->node, state_data);
+	}
 
 	stack->depth--;
 	assert(stack->depth >= 0);
diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h
index 57bb7726c..a147ada28 100644
--- a/src/document/dom/stack.h
+++ b/src/document/dom/stack.h
@@ -45,7 +45,8 @@ struct dom_stack {
 	size_t object_size;
 
 	/* Renderer specific callbacks for the streaming parser mode. */
-	dom_stack_callback_T callbacks[DOM_NODES];
+	dom_stack_callback_T push_callbacks[DOM_NODES];
+	dom_stack_callback_T pop_callbacks[DOM_NODES];
 
 	/* Data specific to the parser and renderer. */
 	void *renderer;
@@ -107,7 +108,8 @@ search_dom_stack(struct dom_stack *stack, enum dom_node_type type,
  * state to be assigned to the state's @data member. Zero means no state data should
  * be allocated. */
 void init_dom_stack(struct dom_stack *stack, void *parser, void *renderer,
-		    dom_stack_callback_T callbacks[DOM_NODES],
+		    dom_stack_callback_T push_callbacks[DOM_NODES],
+		    dom_stack_callback_T pop_callbacks[DOM_NODES],
 		    size_t object_size);
 void done_dom_stack(struct dom_stack *stack);
 
diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index 238db88ac..4d1b59677 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -311,7 +311,8 @@ parse_sgml_document(struct dom_stack *stack, struct scanner *scanner)
 struct sgml_parser *
 init_sgml_parser(enum sgml_parser_type type, void *renderer,
 		 struct cache_entry *cached, struct document *document,
-		 dom_stack_callback_T callbacks[DOM_NODES])
+		 dom_stack_callback_T push_callbacks[DOM_NODES],
+		 dom_stack_callback_T pop_callbacks[DOM_NODES])
 {
 	size_t obj_size = sizeof(struct sgml_parser_state);
 	struct sgml_parser *parser;
@@ -324,7 +325,8 @@ init_sgml_parser(enum sgml_parser_type type, void *renderer,
 	parser->cache_entry = cached;
 	parser->info	    = &sgml_html_info;
 
-	init_dom_stack(&parser->stack, parser, renderer, callbacks, obj_size);
+	init_dom_stack(&parser->stack, parser, renderer,
+		       push_callbacks, pop_callbacks, obj_size);
 
 	return parser;
 }
diff --git a/src/document/sgml/parser.h b/src/document/sgml/parser.h
index fbacc0886..688ebc27a 100644
--- a/src/document/sgml/parser.h
+++ b/src/document/sgml/parser.h
@@ -46,7 +46,8 @@ struct sgml_parser_state {
 struct sgml_parser *
 init_sgml_parser(enum sgml_parser_type type, void *renderer,
 		 struct cache_entry *cached, struct document *document,
-		 dom_stack_callback_T callbacks[DOM_NODES]);
+		 dom_stack_callback_T push_callbacks[DOM_NODES],
+		 dom_stack_callback_T pop_callbacks[DOM_NODES]);
 
 void done_sgml_parser(struct sgml_parser *parser);
 

From 1c4a0d67ce1efa0ef9298a97aa4bb571aee78071 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 19:33:15 +0100
Subject: [PATCH 12/13] Restore highlighting of element end-tags

... by installing a pop-callback for elements and responding to whatever
the parser has put in the end_token parser state member.
---
 src/document/dom/renderer.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c
index 6cc70e0ec..d8e5d8de3 100644
--- a/src/document/dom/renderer.c
+++ b/src/document/dom/renderer.c
@@ -28,6 +28,7 @@
 #include "util/box.h"
 #include "util/error.h"
 #include "util/memory.h"
+#include "util/scanner.h"
 #include "util/snprintf.h"
 #include "util/string.h"
 
@@ -586,6 +587,31 @@ render_dom_element_source(struct dom_stack *stack, struct dom_node *node, void *
 	return node;
 }
 
+static struct dom_node *
+render_dom_element_end_source(struct dom_stack *stack, struct dom_node *node, void *data)
+{
+	struct dom_renderer *renderer = stack->renderer;
+	struct sgml_parser_state *pstate = data;
+	struct scanner_token *token = &pstate->end_token;
+	unsigned char *string = token->string;
+	int length = token->length;
+
+	assert(node && renderer && renderer->document);
+
+	if (!string || !length)
+		return node;
+
+	if (check_dom_node_source(renderer, string, length)) {
+		render_dom_flush(renderer, string);
+		renderer->position = string + length;
+		assert_source(renderer, renderer->position, 0);
+	}
+
+	render_dom_text(renderer, &renderer->styles[node->type], string, length);
+
+	return node;
+}
+
 static struct dom_node *
 render_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void *data)
 {
@@ -695,7 +721,7 @@ static dom_stack_callback_T dom_source_renderer_push_callbacks[DOM_NODES] = {
 
 static dom_stack_callback_T dom_source_renderer_pop_callbacks[DOM_NODES] = {
 	/*				*/ NULL,
-	/* DOM_NODE_ELEMENT		*/ NULL,
+	/* DOM_NODE_ELEMENT		*/ render_dom_element_end_source,
 	/* DOM_NODE_ATTRIBUTE		*/ NULL,
 	/* DOM_NODE_TEXT		*/ NULL,
 	/* DOM_NODE_CDATA_SECTION	*/ NULL,

From c7ad6f967b13236a3ca06e11a51ae95ea6b551c7 Mon Sep 17 00:00:00 2001
From: Jonas Fonseca <fonseca@diku.dk>
Date: Mon, 5 Dec 2005 19:40:35 +0100
Subject: [PATCH 13/13] Introduce new pop_dom_state()

It's basically pop_dom_nodes() without the search part and is now used as a
backend in pop_dom_nodes(). Use it in parse_sgml_document() to avoid two
DOM stack searches in a row.
---
 src/document/dom/stack.c   | 22 +++++++++++++++++-----
 src/document/dom/stack.h   |  5 +++++
 src/document/sgml/parser.c |  6 ++----
 3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/src/document/dom/stack.c b/src/document/dom/stack.c
index c6be1b61a..d1dc11a65 100644
--- a/src/document/dom/stack.c
+++ b/src/document/dom/stack.c
@@ -175,16 +175,28 @@ void
 pop_dom_nodes(struct dom_stack *stack, enum dom_node_type type,
 	      unsigned char *string, uint16_t length)
 {
-	struct dom_stack_state *state, *parent;
-	unsigned int pos;
+	struct dom_stack_state *state;
 
 	if (!dom_stack_has_parents(stack)) return;
 
-	parent = search_dom_stack(stack, type, string, length);
-	if (!parent) return;
+	state = search_dom_stack(stack, type, string, length);
+	if (state)
+		pop_dom_state(stack, type, state);
+}
+
+void
+pop_dom_state(struct dom_stack *stack, enum dom_node_type type,
+	      struct dom_stack_state *target)
+{
+	struct dom_stack_state *state;
+	unsigned int pos;
+
+	if (!target) return;
+
+	if (!dom_stack_has_parents(stack)) return;
 
 	foreachback_dom_state (stack, state, pos) {
-		if (do_pop_dom_node(stack, parent))
+		if (do_pop_dom_node(stack, target))
 			break;;
 	}
 }
diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h
index a147ada28..b3d603ad5 100644
--- a/src/document/dom/stack.h
+++ b/src/document/dom/stack.h
@@ -124,6 +124,11 @@ void pop_dom_node(struct dom_stack *stack);
 void pop_dom_nodes(struct dom_stack *stack, enum dom_node_type type,
 		   unsigned char *string, uint16_t length);
 
+/* Pop all stack states until a specific state is reached. */
+void
+pop_dom_state(struct dom_stack *stack, enum dom_node_type type,
+	      struct dom_stack_state *target);
+
 /* Visit each node in the tree rooted at @root pre-order */
 void walk_dom_nodes(struct dom_stack *stack, struct dom_node *root);
 
diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c
index 4d1b59677..a2205ae8d 100644
--- a/src/document/sgml/parser.c
+++ b/src/document/sgml/parser.c
@@ -255,12 +255,10 @@ parse_sgml_document(struct dom_stack *stack, struct scanner *scanner)
 					struct sgml_parser_state *pstate;
 
 					pstate = get_dom_stack_state_data(stack, state);
-
 					copy_struct(&pstate->end_token, token);
-				}
 
-				pop_dom_nodes(stack, DOM_NODE_ELEMENT,
-					      token->string, token->length);
+					pop_dom_state(stack, DOM_NODE_ELEMENT, state);
+				}
 			}
 			skip_scanner_token(scanner);
 			break;