2 #ifndef EL__DOCUMENT_CSS_STYLESHEET_H
3 #define EL__DOCUMENT_CSS_STYLESHEET_H
5 #include "protocol/uri.h"
6 #include "util/lists.h"
8 /* #define DEBUG_CSS */
11 * @todo TODO: We need a memory efficient and fast way to define how
12 * properties cascade. What we are interested in is making it fast and
13 * easy to find all properties we need.
16 * struct css_cascade {
17 * struct css_cascade *parent;
18 * struct list_head properties;
20 * - Can later be turned into a table to not waste memory:
21 * struct css_property properties[1];
25 * And the selector should then only map a document element into this
28 * All the CSS applier has to do is require the css_cascade of the current
29 * element and it should nicely inherit any style from parent cascades.
30 * Question is in what direction to apply. It should be possible for the user
31 * to overwrite any document provided stylesheet using "!important" so we need
32 * to keep track in some table what properties was already applied so we only
33 * overwrite when we have to. --jonas
35 * XXX: This is one of the TODOs where I have no clue what is it talking about
36 * in particular. Is it obsolete now when we grok 'td.foo p#x>a:hover' without
37 * hesitation? --pasky */
39 /** A set of struct css_selector. This is currently represented as a
40 * list but that may be changed later. Therefore please try not to
41 * access the contents directly; instead define new wrapper macros.
43 * According to CSS2 section 7.1 "Cascading order", if two rules have
44 * the same weight, then the latter specified wins. Regardless, the
45 * order of rules need not be represented in struct css_selector_set,
46 * because all rules for the same selector have already been merged
47 * into one struct css_selector. */
48 struct css_selector_set
{
49 unsigned char may_contain_rel_ancestor_or_parent
;
51 /** The list of selectors in this set.
53 * Sets are currently represented as lists that
54 * find_css_selector() then has to search linearly.
55 * Hashing was also tested but did not help in practice:
56 * each find_css_selector() call runs approximately one
57 * strcasecmp(), and a hash function is unlikely to be
58 * faster than that. See ELinks bug 789 for details.
60 * Keep this away from the beginning of the structure,
61 * so that nobody can cast the struct css_selector_set *
62 * to LIST_OF(struct css_selector) * and get away with it. */
63 LIST_OF(struct css_selector
) list
;
65 #define INIT_CSS_SELECTOR_SET(set) { 0, { D_LIST_HEAD(set.list) } }
67 /** The struct css_selector is used for mapping elements (or nodes) in the
68 * document structure to properties. See README for some hints about how the
69 * trees of these span. */
71 LIST_HEAD(struct css_selector
);
73 /** This defines relation between this selector fragment and its
74 * parent in the selector tree.
75 * Update with set_css_selector_relation(). */
76 enum css_selector_relation
{
77 CSR_ROOT
, /**< First class stylesheet member. */
78 CSR_SPECIFITY
, /**< Narrowing-down, i.e. the "x" in "foo#x". */
79 CSR_ANCESTOR
, /**< Ancestor, i.e. the "p" in "p a". */
80 CSR_PARENT
, /**< Direct parent, i.e. the "div" in "div>img". */
82 struct css_selector_set leaves
;
84 enum css_selector_type
{
89 CST_INVALID
, /**< Auxiliary for the parser */
93 LIST_OF(struct css_property
) properties
;
97 struct css_stylesheet
;
98 typedef void (*css_stylesheet_importer_T
)(struct css_stylesheet
*, struct uri
*,
99 const unsigned char *url
, int urllen
);
101 /** The struct css_stylesheet describes all the useful data that was extracted
102 * from the CSS source. Currently we don't cache anything but the default user
103 * stylesheet so it can contain stuff from both @<style> tags and @@import'ed
105 struct css_stylesheet
{
106 /** The import callback function. The caller must check the
107 * media types first. */
108 css_stylesheet_importer_T import
;
110 /** The import callback's data. */
113 /** The set of basic element selectors (which can then somehow
114 * tree up on inside). */
115 struct css_selector_set selectors
;
117 /** How deeply nested are we. Limited by MAX_REDIRECTS. */
121 #define INIT_CSS_STYLESHEET(css, import) \
122 { import, NULL, INIT_CSS_SELECTOR_SET(css.selectors) }
124 /** Dynamically allocates a stylesheet. */
125 struct css_stylesheet
*init_css_stylesheet(css_stylesheet_importer_T importer
,
128 /** Mirror given CSS stylesheet @a css1 to an identical copy of itself
129 * (including all the selectors), @a css2. */
130 void mirror_css_stylesheet(struct css_stylesheet
*css1
,
131 struct css_stylesheet
*css2
);
133 /** Releases all the content of the stylesheet (but not the stylesheet
135 void done_css_stylesheet(struct css_stylesheet
*css
);
138 /** Returns a new freshly made selector adding it to the given selector
140 struct css_selector
*get_css_selector(struct css_selector_set
*set
,
141 enum css_selector_type type
,
142 enum css_selector_relation rel
,
143 const unsigned char *name
, int namelen
);
145 #define get_css_base_selector(stylesheet, type, rel, name, namelen) \
146 get_css_selector((stylesheet) ? &(stylesheet)->selectors : NULL, \
147 type, rel, name, namelen)
149 /** Looks up the selector of the name @a name and length @a namelen in
150 * the given set of selectors. */
151 struct css_selector
*find_css_selector(struct css_selector_set
*set
,
152 enum css_selector_type type
,
153 enum css_selector_relation rel
,
154 const unsigned char *name
, int namelen
);
156 #define find_css_base_selector(stylesheet, type, rel, name, namelen) \
157 find_css_selector(&stylesheet->selectors, rel, type, name, namelen)
159 /** Initialize the selector structure. This is a rather low-level
160 * function from your POV. */
161 struct css_selector
*init_css_selector(struct css_selector_set
*set
,
162 enum css_selector_type type
,
163 enum css_selector_relation relation
,
164 const unsigned char *name
, int namelen
);
166 /** Add all properties from the list to the given @a selector. */
167 void add_selector_properties(struct css_selector
*selector
,
168 LIST_OF(struct css_property
) *properties
);
170 /** Join @a sel2 to @a sel1, @a sel1 taking precedence in all conflicts. */
171 void merge_css_selectors(struct css_selector
*sel1
, struct css_selector
*sel2
);
173 /** Use this function instead of modifying css_selector.relation directly. */
174 void set_css_selector_relation(struct css_selector
*,
175 enum css_selector_relation
);
177 /** Destroy a selector. done_css_stylesheet() normally does that for you. */
178 void done_css_selector(struct css_selector
*selector
);
180 void init_css_selector_set(struct css_selector_set
*set
);
181 void done_css_selector_set(struct css_selector_set
*set
);
182 #define css_selector_set_empty(set) list_empty((set)->list)
183 #define css_selector_set_front(set) ((struct css_selector *) ((set)->list.next))
184 void add_css_selector_to_set(struct css_selector
*, struct css_selector_set
*);
185 void del_css_selector_from_set(struct css_selector
*);
186 #define css_selector_is_in_set(selector) ((selector)->next != NULL)
187 #define foreach_css_selector(selector, set) foreach (selector, (set)->list)
190 /** Dumps the selector tree to stderr. */
191 void dump_css_selector_tree(struct css_selector_set
*set
);