2 #ifndef EL__DOCUMENT_DOM_STACK_H
3 #define EL__DOCUMENT_DOM_STACK_H
5 #include "document/document.h"
6 #include "document/dom/node.h"
7 #include "util/error.h"
12 typedef struct dom_node
*
13 (*dom_stack_callback_T
)(struct dom_stack
*, struct dom_node
*, void *);
15 #define DOM_STACK_MAX_DEPTH 4096
17 struct dom_stack_state
{
18 struct dom_node
*node
;
20 /* Used for recording which node list are currently being 'decended'
21 * into. E.g. whether we are iterating all child elements or attributes
23 struct dom_node_list
*list
;
24 /* The index (in the list above) which are currently being handled. */
27 /* A callback registered to be called when the node is popped. Used for
28 * correctly highlighting ending elements (e.g. </a>). */
29 dom_stack_callback_T callback
;
31 /* The depth of the state in the stack. This is amongst other things
32 * used to get the state object data. */
36 /* The DOM stack is a convenient way to traverse DOM trees. Also it
37 * maintains needed state info and is therefore also a holder of the current
38 * context since the stack is used to when the DOM tree is manipulated. */
40 /* The stack of nodes */
41 struct dom_stack_state
*states
;
44 /* This is one big array of parser specific objects. */
45 /* The objects hold parser specific data. For the SGML parser this
46 * holds DTD-oriented info about the node (recorded in struct
47 * sgml_node_info). E.g. whether an element node is optional. */
48 unsigned char *state_objects
;
51 /* Parser and document specific stuff */
52 dom_stack_callback_T callbacks
[DOM_NODES
];
58 #define dom_stack_has_parents(nav) \
59 ((nav)->states && (nav)->depth > 0)
61 static inline struct dom_stack_state
*
62 get_dom_stack_state(struct dom_stack
*stack
, int top_offset
)
64 assertm(stack
->depth
- 1 - top_offset
>= 0,
65 "Attempting to access invalid state");
66 return &stack
->states
[stack
->depth
- 1 - top_offset
];
69 #define get_dom_stack_parent(nav) get_dom_stack_state(nav, 1)
70 #define get_dom_stack_top(nav) get_dom_stack_state(nav, 0)
72 #define get_dom_stack_state_data(stack, state) \
73 ((void *) &(stack)->state_objects[(state)->depth * (stack)->object_size])
75 /* The state iterators do not include the bottom state */
77 #define foreach_dom_state(nav, item, pos) \
78 for ((pos) = 1; (pos) < (nav)->depth; (pos)++) \
79 if (((item) = &(nav)->states[(pos)]))
81 #define foreachback_dom_state(nav, item, pos) \
82 for ((pos) = (nav)->depth - 1; (pos) > 0; (pos)--) \
83 if (((item) = &(nav)->states[(pos)]))
85 /* Dive through the stack states in search for the specified match. */
86 static inline struct dom_stack_state
*
87 search_dom_stack(struct dom_stack
*stack
, enum dom_node_type type
,
88 unsigned char *string
, uint16_t length
)
90 struct dom_stack_state
*state
;
93 /* FIXME: Take node subtype and compare if non-zero or something. */
94 foreachback_dom_state (stack
, state
, pos
) {
95 struct dom_node
*parent
= state
->node
;
97 if (parent
->type
== type
98 && parent
->length
== length
99 && !strncasecmp(parent
->string
, string
, length
))
107 /* Life cycle functions. */
109 /* The @object_size arg tells whether the stack should allocate objects for each
110 * state to be assigned to the state's @data member. Zero means no state data should
112 void init_dom_stack(struct dom_stack
*stack
, void *parser
, void *renderer
,
113 dom_stack_callback_T callbacks
[DOM_NODES
],
115 void done_dom_stack(struct dom_stack
*stack
);
117 /* Decends down to the given node making it the current parent */
118 /* If an error occurs the node is free()d and NULL is returned */
119 struct dom_node
*push_dom_node(struct dom_stack
*stack
, struct dom_node
*node
);
121 /* Ascends the stack to the current parent */
122 void pop_dom_node(struct dom_stack
*stack
);
124 /* Ascends the stack looking for specific parent */
125 void pop_dom_nodes(struct dom_stack
*stack
, enum dom_node_type type
,
126 unsigned char *string
, uint16_t length
);
128 /* Visit each node in the tree rooted at @root pre-order */
129 void walk_dom_nodes(struct dom_stack
*stack
, struct dom_node
*root
);