From a4831fef2d47b4d13c0829090a3c0a938ae6a6d0 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Tue, 27 Dec 2005 05:59:12 +0100 Subject: [PATCH] Make it easier to work with DOM stack contexts outside of the callbacks The problem is to get access to the context when it is not the first one and it has to happen outside of the context callbacks. This changes the memory management so that the context adder returns the context. To further improve the use of contexts add a context destructor which makes it possible to unregister (temporary) contexts. --- src/document/dom/renderer.c | 2 +- src/document/dom/select.c | 2 +- src/document/dom/stack.c | 49 ++++++++++++++++++++++++++++++++++++--------- src/document/dom/stack.h | 12 ++++++++--- src/document/sgml/parser.c | 6 +++--- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c index 7e3ff791..015effa5 100644 --- a/src/document/dom/renderer.c +++ b/src/document/dom/renderer.c @@ -505,7 +505,7 @@ render_dom_element_end_source(struct dom_stack *stack, struct dom_node *node, vo { struct dom_renderer *renderer = stack->current->data; struct dom_stack_state *state = get_dom_stack_top(stack); - struct sgml_parser_state *pstate = get_dom_stack_state_data(stack->contexts, state); + struct sgml_parser_state *pstate = get_dom_stack_state_data(stack->contexts[0], state); struct scanner_token *token = &pstate->end_token; unsigned char *string = token->string; int length = token->length; diff --git a/src/document/dom/select.c b/src/document/dom/select.c index 80c33a48..231e9f92 100644 --- a/src/document/dom/select.c +++ b/src/document/dom/select.c @@ -770,7 +770,7 @@ match_attribute_selectors(struct dom_select_node *base, struct dom_node *node) /* XXX: Assume the first context is the one! */ #define get_dom_select_state(stack, state) \ - ((struct dom_select_state *) get_dom_stack_state_data((stack)->contexts, state)) + ((struct dom_select_state *) get_dom_stack_state_data((stack)->contexts[0], state)) static int match_element_relation(struct dom_select_node *selector, struct dom_node *node, diff --git a/src/document/dom/stack.c b/src/document/dom/stack.c index b719d295..f2be5485 100644 --- a/src/document/dom/stack.c +++ b/src/document/dom/stack.c @@ -29,10 +29,10 @@ realloc_dom_stack_states(struct dom_stack_state **states, size_t size) } static inline struct dom_stack_state * -realloc_dom_stack_context(struct dom_stack_context **contexts, size_t size) +realloc_dom_stack_context(struct dom_stack_context ***contexts, size_t size) { return mem_align_alloc(contexts, size, size + 1, - struct dom_stack_context, + struct dom_stack_context *, DOM_STACK_STATE_GRANULARITY); } @@ -70,7 +70,8 @@ done_dom_stack(struct dom_stack *stack) assert(stack); for (i = 0; i < stack->contexts_size; i++) { - mem_free_if(stack->contexts[i].state_objects); + mem_free_if(stack->contexts[i]->state_objects); + mem_free(stack->contexts[i]); } mem_free_if(stack->contexts); @@ -79,18 +80,48 @@ done_dom_stack(struct dom_stack *stack) memset(stack, 0, sizeof(*stack)); } -void +struct dom_stack_context * add_dom_stack_context(struct dom_stack *stack, void *data, struct dom_stack_context_info *context_info) { struct dom_stack_context *context; if (!realloc_dom_stack_context(&stack->contexts, stack->contexts_size)) - return; + return NULL; + + context = mem_calloc(1, sizeof(*context)); + if (!context) + return NULL; - context = &stack->contexts[stack->contexts_size++]; + stack->contexts[stack->contexts_size++] = context; context->info = context_info; context->data = data; + + return context; +} + +void +done_dom_stack_context(struct dom_stack *stack, struct dom_stack_context *context) +{ + size_t i; + + mem_free_if(context->state_objects); + mem_free(context); + + /* Handle the trivial case of temporary contexts optimally by iteration last added first. */ + for (i = stack->contexts_size - 1; i >= 0; i--) { + if (stack->contexts[i] != context) + continue; + + stack->contexts_size--; + if (i < stack->contexts_size) { + struct dom_stack_context **pos = &stack->contexts[i]; + size_t size = stack->contexts_size - i; + + memmove(pos, pos + 1, size * sizeof(*pos)); + } + break; + } } enum dom_stack_action { @@ -105,7 +136,7 @@ call_dom_stack_callbacks(struct dom_stack *stack, struct dom_stack_state *state, int i; for (i = 0; i < stack->contexts_size; i++) { - struct dom_stack_context *context = &stack->contexts[i]; + struct dom_stack_context *context = stack->contexts[i]; void *state_data = get_dom_stack_state_data(context, state); dom_stack_callback_T callback; @@ -144,7 +175,7 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node) state += stack->depth; for (i = 0; i < stack->contexts_size; i++) { - struct dom_stack_context *context = &stack->contexts[i]; + struct dom_stack_context *context = stack->contexts[i]; if (context->info->object_size && !realloc_dom_stack_state_objects(context, stack->depth)) { @@ -188,7 +219,7 @@ pop_dom_node(struct dom_stack *stack) assert(stack->depth >= 0); for (i = 0; i < stack->contexts_size; i++) { - struct dom_stack_context *context = &stack->contexts[i]; + struct dom_stack_context *context = stack->contexts[i]; if (context->info->object_size) { void *state_data = get_dom_stack_state_data(context, state); diff --git a/src/document/dom/stack.h b/src/document/dom/stack.h index f987041d..ddac5e3b 100644 --- a/src/document/dom/stack.h +++ b/src/document/dom/stack.h @@ -70,7 +70,7 @@ struct dom_stack { enum dom_stack_flag flags; /* Contexts for the pushed and popped nodes. */ - struct dom_stack_context *contexts; + struct dom_stack_context **contexts; size_t contexts_size; /* The current context. */ @@ -136,8 +136,14 @@ void done_dom_stack(struct dom_stack *stack); /* Add a context to the stack. This is needed if either you want to have the * stack allocated objects for created states and/or if you want to install * callbacks for pushing or popping. . */ -void add_dom_stack_context(struct dom_stack *stack, void *data, - struct dom_stack_context_info *context_info); +struct dom_stack_context * +add_dom_stack_context(struct dom_stack *stack, void *data, + struct dom_stack_context_info *context_info); + +/* Unregister a stack @context. This should be done especially for temporary + * stack contexts (without any callbacks) so that they do not increasing the + * memory usage. */ +void done_dom_stack_context(struct dom_stack *stack, struct dom_stack_context *context); /* Decends down to the given node making it the current parent */ /* If an error occurs the node is free()d and NULL is returned */ diff --git a/src/document/sgml/parser.c b/src/document/sgml/parser.c index b9f91a48..11d7a949 100644 --- a/src/document/sgml/parser.c +++ b/src/document/sgml/parser.c @@ -29,10 +29,10 @@ init_sgml_parsing_state(struct sgml_parser *parser, struct string *buffer); * is the first to add it's context, which it is since it initializes the * stack. */ -#define get_sgml_parser(stack) ((stack)->contexts->data) +#define get_sgml_parser(stack) ((stack)->contexts[0]->data) #define get_sgml_parser_state(stack, state) \ - get_dom_stack_state_data(stack->contexts, state) + get_dom_stack_state_data(stack->contexts[0], state) /* Functions for adding new nodes to the DOM tree: */ @@ -432,7 +432,7 @@ init_sgml_parsing_state(struct sgml_parser *parser, struct string *buffer) state = get_dom_stack_top(&parser->parsing); - return get_dom_stack_state_data(parser->parsing.contexts, state); + return get_dom_stack_state_data(parser->parsing.contexts[0], state); } -- 2.11.4.GIT