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 = &stack->contexts[stack->contexts_size++]; + context = mem_calloc(1, sizeof(*context)); + if (!context) + return NULL; + + 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); }