mirror of
https://github.com/rkd77/elinks.git
synced 2024-11-04 08:17:17 -05:00
CSS: new struct css_selector_set
This commit is contained in:
parent
8097929290
commit
ace03d5093
@ -117,7 +117,7 @@ static css_applier_T css_appliers[CSS_PT_LAST] = {
|
||||
static void
|
||||
examine_element(struct html_context *html_context, struct css_selector *base,
|
||||
enum css_selector_type seltype, enum css_selector_relation rel,
|
||||
struct list_head *selectors, struct html_element *element)
|
||||
struct css_selector_set *selectors, struct html_element *element)
|
||||
{
|
||||
struct css_selector *selector;
|
||||
|
||||
@ -129,7 +129,7 @@ examine_element(struct html_context *html_context, struct css_selector *base,
|
||||
|
||||
DBG("examine_element(%p, %s, %d, %d, %p, %.*s);", html_context, base->name, seltype, rel, selectors, element->namelen, element->name);
|
||||
#define dbginfo(sel, type_, base) \
|
||||
dbg_has_leaves = !list_empty(sel->leaves), \
|
||||
dbg_has_leaves = !css_selector_set_empty(&sel->leaves), \
|
||||
dbg_has_properties = !list_empty(sel->properties), \
|
||||
DBG("Matched selector %s (rel %d type %d [m%d])! Children %p !!%d, props !!%d", sel->name, sel->relation, sel->type, sel->type == type_, &sel->leaves, dbg_has_leaves, dbg_has_properties)
|
||||
#else
|
||||
|
@ -112,7 +112,7 @@ import_default_css(void)
|
||||
{
|
||||
unsigned char *url = get_opt_str("document.css.stylesheet");
|
||||
|
||||
if (!list_empty(default_stylesheet.selectors))
|
||||
if (!css_selector_set_empty(&default_stylesheet.selectors))
|
||||
done_css_stylesheet(&default_stylesheet);
|
||||
|
||||
if (!*url) return;
|
||||
|
@ -170,21 +170,21 @@ struct selector_pkg {
|
||||
struct css_selector *selector;
|
||||
};
|
||||
|
||||
/** Move a CSS selector and its leaves into a new list. If a similar
|
||||
* selector already exists in the list, merge them.
|
||||
/** Move a CSS selector and its leaves into a new set. If a similar
|
||||
* selector already exists in the set, merge them.
|
||||
*
|
||||
* \param sels
|
||||
* The list to which \a selector should be moved. Must not be NULL.
|
||||
* The set to which \a selector should be moved. Must not be NULL.
|
||||
* \param selector
|
||||
* The selector that should be moved. Must not be NULL. If it is
|
||||
* already in some list, this function removes it from there.
|
||||
* already in some set, this function removes it from there.
|
||||
* \param watch
|
||||
* This function updates \a *watch if it merges that selector into
|
||||
* another one. \a watch must not be NULL but \a *watch may be.
|
||||
*
|
||||
* \return \a selector or the one into which it was merged. */
|
||||
static struct css_selector *
|
||||
reparent_selector(struct list_head *sels, struct css_selector *selector,
|
||||
reparent_selector(struct css_selector_set *sels, struct css_selector *selector,
|
||||
struct css_selector **watch)
|
||||
{
|
||||
struct css_selector *twin = find_css_selector(sels, selector->type,
|
||||
@ -194,8 +194,8 @@ reparent_selector(struct list_head *sels, struct css_selector *selector,
|
||||
if (twin) {
|
||||
merge_css_selectors(twin, selector);
|
||||
/* Reparent leaves. */
|
||||
while (selector->leaves.next != &selector->leaves) {
|
||||
struct css_selector *leaf = selector->leaves.next;
|
||||
while (!css_selector_set_empty(&selector->leaves)) {
|
||||
struct css_selector *leaf = css_selector_set_front(&selector->leaves);
|
||||
|
||||
reparent_selector(&twin->leaves, leaf, watch);
|
||||
}
|
||||
@ -203,8 +203,9 @@ reparent_selector(struct list_head *sels, struct css_selector *selector,
|
||||
*watch = twin;
|
||||
done_css_selector(selector);
|
||||
} else {
|
||||
if (selector->next) del_from_list(selector);
|
||||
add_to_list(*sels, selector);
|
||||
if (css_selector_is_in_set(selector))
|
||||
del_css_selector_from_set(selector);
|
||||
add_css_selector_to_set(selector, sels);
|
||||
}
|
||||
|
||||
return twin ? twin : selector;
|
||||
@ -368,9 +369,9 @@ css_parse_selector(struct css_stylesheet *css, struct scanner *scanner,
|
||||
/* The situation is like: 'div p#x', now it was
|
||||
* 'p -> div', but we need to redo that as
|
||||
* '(p ->) #x -> div'. */
|
||||
del_from_list(last_chained_selector);
|
||||
add_to_list(selector->leaves,
|
||||
last_chained_selector);
|
||||
del_css_selector_from_set(last_chained_selector);
|
||||
add_css_selector_to_set(last_chained_selector,
|
||||
&selector->leaves);
|
||||
}
|
||||
|
||||
if (pkg->selector == base_sel) {
|
||||
@ -403,7 +404,8 @@ css_parse_selector(struct css_stylesheet *css, struct scanner *scanner,
|
||||
if (!selector) continue;
|
||||
|
||||
assert(prev_element_selector);
|
||||
add_to_list(selector->leaves, prev_element_selector);
|
||||
add_css_selector_to_set(prev_element_selector,
|
||||
&selector->leaves);
|
||||
last_chained_selector = prev_element_selector;
|
||||
|
||||
prev_element_selector->relation = reltype;
|
||||
@ -496,7 +498,7 @@ css_parse_ruleset(struct css_stylesheet *css, struct scanner *scanner)
|
||||
* because GCC 4.1 "warning: operation on `errfile'
|
||||
* may be undefined" breaks the build with -Werror. */
|
||||
int dbg_has_properties = !list_empty(properties);
|
||||
int dbg_has_leaves = !list_empty(pkg->selector->leaves);
|
||||
int dbg_has_leaves = !css_selector_set_empty(&pkg->selector->leaves);
|
||||
|
||||
DBG("Binding properties (!!%d) to selector %s (type %d, relation %d, children %d)",
|
||||
dbg_has_properties,
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
struct css_selector *
|
||||
find_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
find_css_selector(struct css_selector_set *sels, enum css_selector_type type,
|
||||
enum css_selector_relation rel,
|
||||
const unsigned char *name, int namelen)
|
||||
{
|
||||
@ -33,7 +33,7 @@ find_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
|
||||
assert(sels && name);
|
||||
|
||||
foreach (selector, *sels) {
|
||||
foreach_css_selector (selector, sels) {
|
||||
if (type != selector->type || rel != selector->relation)
|
||||
continue;
|
||||
if (strlcasecmp(name, namelen, selector->name, -1))
|
||||
@ -45,7 +45,7 @@ find_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
}
|
||||
|
||||
struct css_selector *
|
||||
init_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
init_css_selector(struct css_selector_set *sels, enum css_selector_type type,
|
||||
unsigned char *name, int namelen)
|
||||
{
|
||||
struct css_selector *selector;
|
||||
@ -54,7 +54,7 @@ init_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
if (!selector) return NULL;
|
||||
|
||||
selector->relation = CSR_ROOT; /* Default */
|
||||
init_list(selector->leaves);
|
||||
init_css_selector_set(&selector->leaves);
|
||||
|
||||
selector->type = type;
|
||||
init_list(selector->properties);
|
||||
@ -64,6 +64,7 @@ init_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
namelen = strlen(name);
|
||||
selector->name = memacpy(name, namelen);
|
||||
if (!selector->name) {
|
||||
done_css_selector_set(&selector->leaves);
|
||||
mem_free(selector);
|
||||
return NULL;
|
||||
}
|
||||
@ -71,14 +72,14 @@ init_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
}
|
||||
|
||||
if (sels) {
|
||||
add_to_list(*sels, selector);
|
||||
add_css_selector_to_set(selector, sels);
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
struct css_selector *
|
||||
get_css_selector(struct list_head *sels, enum css_selector_type type,
|
||||
get_css_selector(struct css_selector_set *sels, enum css_selector_type type,
|
||||
enum css_selector_relation rel,
|
||||
unsigned char *name, int namelen)
|
||||
{
|
||||
@ -173,23 +174,30 @@ merge_css_selectors(struct css_selector *sel1, struct css_selector *sel2)
|
||||
void
|
||||
done_css_selector(struct css_selector *selector)
|
||||
{
|
||||
while (selector->leaves.next != &selector->leaves) {
|
||||
done_css_selector(selector->leaves.next);
|
||||
}
|
||||
done_css_selector_set(&selector->leaves);
|
||||
|
||||
if (selector->next) del_from_list(selector);
|
||||
if (css_selector_is_in_set(selector))
|
||||
del_css_selector_from_set(selector);
|
||||
free_list(selector->properties);
|
||||
mem_free_if(selector->name);
|
||||
mem_free(selector);
|
||||
}
|
||||
|
||||
void
|
||||
done_css_selector_set(struct css_selector_set *set)
|
||||
{
|
||||
while (!css_selector_set_empty(set)) {
|
||||
done_css_selector(css_selector_set_front(set));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CSS
|
||||
void
|
||||
dump_css_selector_tree_iter(struct list_head *sels, int level)
|
||||
dump_css_selector_tree_iter(struct css_selector_set *sels, int level)
|
||||
{
|
||||
struct css_selector *sel;
|
||||
|
||||
foreach (sel, *sels) {
|
||||
foreach_css_selector (sel, sels) {
|
||||
struct css_property *prop;
|
||||
|
||||
fprintf(stderr, "%*s +- [%s] type %d rel %d props",
|
||||
@ -204,7 +212,7 @@ dump_css_selector_tree_iter(struct list_head *sels, int level)
|
||||
}
|
||||
|
||||
void
|
||||
dump_css_selector_tree(struct list_head *sels)
|
||||
dump_css_selector_tree(struct css_selector_set *sels)
|
||||
{
|
||||
dump_css_selector_tree_iter(sels, 0);
|
||||
}
|
||||
@ -221,7 +229,7 @@ init_css_stylesheet(css_stylesheet_importer_T importer, void *import_data)
|
||||
return NULL;
|
||||
css->import = importer;
|
||||
css->import_data = import_data;
|
||||
init_list(css->selectors);
|
||||
init_css_selector_set(&css->selectors);
|
||||
return css;
|
||||
}
|
||||
|
||||
@ -230,7 +238,7 @@ mirror_css_stylesheet(struct css_stylesheet *css1, struct css_stylesheet *css2)
|
||||
{
|
||||
struct css_selector *selector;
|
||||
|
||||
foreach (selector, css1->selectors) {
|
||||
foreach_css_selector (selector, &css1->selectors) {
|
||||
clone_css_selector(css2, selector);
|
||||
}
|
||||
}
|
||||
@ -261,7 +269,7 @@ merge_css_stylesheets(struct css_stylesheet *css1,
|
||||
* O(N^2) where we could be much smarter (ie. sort it once and then
|
||||
* always be O(N)). */
|
||||
|
||||
foreach (selector, css2->selectors) {
|
||||
foreach_css_selector (selector, &css2->selectors) {
|
||||
struct css_selector *origsel;
|
||||
|
||||
origsel = find_css_selector(&css1->selectors, selector->name,
|
||||
@ -278,7 +286,5 @@ merge_css_stylesheets(struct css_stylesheet *css1,
|
||||
void
|
||||
done_css_stylesheet(struct css_stylesheet *css)
|
||||
{
|
||||
while (!list_empty(css->selectors)) {
|
||||
done_css_selector(css->selectors.next);
|
||||
}
|
||||
done_css_selector_set(&css->selectors);
|
||||
}
|
||||
|
@ -31,6 +31,29 @@
|
||||
* in particular. Is it obsolete now when we grok 'td.foo p#x>a:hover' without
|
||||
* hesitation? --pasky */
|
||||
|
||||
/* A set of struct css_selector. This is currently represented as a
|
||||
* list but that may be changed later. Therefore please try not to
|
||||
* access the contents directly; instead define new wrapper macros.
|
||||
*
|
||||
* According to CSS2 section 7.1 "Cascading order", if two rules have
|
||||
* the same weight, then the latter specified wins. Regardless, the
|
||||
* order of rules need not be represented in struct css_selector_set,
|
||||
* because all rules for the same selector have already been merged
|
||||
* into one struct css_selector. */
|
||||
struct css_selector_set {
|
||||
#ifdef CONFIG_DEBUG
|
||||
/* Cause a crash if struct css_selector_set * is cast to
|
||||
* struct list_head *. */
|
||||
char dummy;
|
||||
#endif
|
||||
|
||||
struct list_head list; /* -> struct css_selector */
|
||||
};
|
||||
#ifdef CONFIG_DEBUG
|
||||
# define INIT_CSS_SELECTOR_SET(set) { 0, { D_LIST_HEAD(set.list) } }
|
||||
#else
|
||||
# define INIT_CSS_SELECTOR_SET(set) { { D_LIST_HEAD(set.list) } }
|
||||
#endif
|
||||
|
||||
/* The {struct css_selector} is used for mapping elements (or nodes) in the
|
||||
* document structure to properties. See README for some hints about how the
|
||||
@ -49,7 +72,7 @@ struct css_selector {
|
||||
CSR_ANCESTOR, /* Ancestor, i.e. the "p" in "p a". */
|
||||
CSR_PARENT, /* Direct parent, i.e. the "div" in "div>img". */
|
||||
} relation;
|
||||
struct list_head leaves; /* -> struct css_selector */
|
||||
struct css_selector_set leaves;
|
||||
|
||||
enum css_selector_type {
|
||||
CST_ELEMENT,
|
||||
@ -79,16 +102,16 @@ struct css_stylesheet {
|
||||
/* The import callback's data. */
|
||||
void *import_data;
|
||||
|
||||
/* The list of basic element selectors (which can then somehow
|
||||
/* The set of basic element selectors (which can then somehow
|
||||
* tree up on inside). */
|
||||
struct list_head selectors; /* -> struct css_selector */
|
||||
struct css_selector_set selectors;
|
||||
|
||||
/* How deeply nested are we. Limited by MAX_REDIRECTS. */
|
||||
int import_level;
|
||||
};
|
||||
|
||||
#define INIT_CSS_STYLESHEET(css, import) \
|
||||
{ import, NULL, { D_LIST_HEAD(css.selectors) } }
|
||||
{ import, NULL, INIT_CSS_SELECTOR_SET(css.selectors) }
|
||||
|
||||
/* Dynamically allocates a stylesheet. */
|
||||
struct css_stylesheet *init_css_stylesheet(css_stylesheet_importer_T importer,
|
||||
@ -105,8 +128,8 @@ void done_css_stylesheet(struct css_stylesheet *css);
|
||||
|
||||
|
||||
/* Returns a new freshly made selector adding it to the given selector
|
||||
* list, or NULL. */
|
||||
struct css_selector *get_css_selector(struct list_head *selector_list,
|
||||
* set, or NULL. */
|
||||
struct css_selector *get_css_selector(struct css_selector_set *set,
|
||||
enum css_selector_type type,
|
||||
enum css_selector_relation rel,
|
||||
unsigned char *name, int namelen);
|
||||
@ -116,8 +139,8 @@ struct css_selector *get_css_selector(struct list_head *selector_list,
|
||||
type, rel, name, namelen)
|
||||
|
||||
/* Looks up the selector of the name @name and length @namelen in the
|
||||
* given list of selectors. */
|
||||
struct css_selector *find_css_selector(struct list_head *selector_list,
|
||||
* given set of selectors. */
|
||||
struct css_selector *find_css_selector(struct css_selector_set *set,
|
||||
enum css_selector_type type,
|
||||
enum css_selector_relation rel,
|
||||
const unsigned char *name, int namelen);
|
||||
@ -127,7 +150,7 @@ struct css_selector *find_css_selector(struct list_head *selector_list,
|
||||
|
||||
/* Initialize the selector structure. This is a rather low-level function from
|
||||
* your POV. */
|
||||
struct css_selector *init_css_selector(struct list_head *selector_list,
|
||||
struct css_selector *init_css_selector(struct css_selector_set *set,
|
||||
enum css_selector_type type,
|
||||
unsigned char *name, int namelen);
|
||||
|
||||
@ -141,9 +164,18 @@ void merge_css_selectors(struct css_selector *sel1, struct css_selector *sel2);
|
||||
/* Destroy a selector. done_css_stylesheet() normally does that for you. */
|
||||
void done_css_selector(struct css_selector *selector);
|
||||
|
||||
#define init_css_selector_set(set) init_list((set)->list)
|
||||
void done_css_selector_set(struct css_selector_set *set);
|
||||
#define css_selector_set_empty(set) list_empty((set)->list)
|
||||
#define css_selector_set_front(set) ((struct css_selector *) ((set)->list.next))
|
||||
#define del_css_selector_from_set(selector) del_from_list(selector)
|
||||
#define add_css_selector_to_set(selector, set) add_to_list((set)->list, (selector))
|
||||
#define css_selector_is_in_set(selector) ((selector)->next != NULL)
|
||||
#define foreach_css_selector(selector, set) foreach (selector, (set)->list)
|
||||
|
||||
#ifdef DEBUG_CSS
|
||||
/* Dumps the selector tree to stderr. */
|
||||
void dump_css_selector_tree(struct list_head *selector_list);
|
||||
void dump_css_selector_tree(struct css_selector_set *set);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -771,7 +771,7 @@ init_html_parser(struct uri *uri, struct document_options *options,
|
||||
|
||||
#ifdef CONFIG_CSS
|
||||
html_context->css_styles.import = import_css_stylesheet;
|
||||
init_list(html_context->css_styles.selectors);
|
||||
init_css_selector_set(&html_context->css_styles.selectors);
|
||||
#endif
|
||||
|
||||
init_list(html_context->stack);
|
||||
|
Loading…
Reference in New Issue
Block a user