summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2011-01-31 00:18:15 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2011-01-31 00:18:15 +0000
commit9fa9b9d104c730ef6d84b19245b61ebc9554b432 (patch)
treefb4f28285283241da6490b482dc61aac731f48a8 /test
parent6ba000db056d7e9b70a7e154a003644046bf7e98 (diff)
downloadlibcss-9fa9b9d104c730ef6d84b19245b61ebc9554b432.tar.gz
libcss-9fa9b9d104c730ef6d84b19245b61ebc9554b432.tar.bz2
CSS3 Selectors
svn path=/trunk/libcss/; revision=11557
Diffstat (limited to 'test')
-rw-r--r--test/data/parse/INDEX1
-rw-r--r--test/data/parse/nth.dat246
-rw-r--r--test/data/parse/selectors.dat224
-rw-r--r--test/dump.h73
-rw-r--r--test/parse-auto.c81
-rw-r--r--test/select-auto.c284
6 files changed, 882 insertions, 27 deletions
diff --git a/test/data/parse/INDEX b/test/data/parse/INDEX
index 6019062..ced33a3 100644
--- a/test/data/parse/INDEX
+++ b/test/data/parse/INDEX
@@ -7,4 +7,5 @@ selectors.dat Selectors
atrules.dat @-rules
colours.dat Colour values
colours-hsl.dat HSL Colour values
+nth.dat :nth-* expressions
properties.dat Properties
diff --git a/test/data/parse/nth.dat b/test/data/parse/nth.dat
new file mode 100644
index 0000000..fa5744c
--- /dev/null
+++ b/test/data/parse/nth.dat
@@ -0,0 +1,246 @@
+# Test data for nth-* expressions
+
+# Odd and Even
+
+#data
+E:nth-child(odd) {}
+#errors
+#expected
+| 1 E:nth-child(2n+1)
+#reset
+
+#data
+E:nth-child(even) {}
+#errors
+#expected
+| 1 E:nth-child(2n+0)
+#reset
+
+# Basic numbers
+
+#data
+E:nth-child(1) {}
+#errors
+#expected
+| 1 E:nth-child(0n+1)
+#reset
+
+#data
+E:nth-child(-1) {}
+#errors
+#expected
+| 1 E:nth-child(0n+-1)
+#reset
+
+# IDENT ws [ NUMBER ws ]?
+
+#data
+E:nth-child(n) {}
+#errors
+#expected
+| 1 E:nth-child(1n+0)
+#reset
+
+#data
+E:nth-child(-n) {}
+#errors
+#expected
+| 1 E:nth-child(-1n+0)
+#reset
+
+#data
+E:nth-child(-n- 1) {}
+#errors
+#expected
+| 1 E:nth-child(-1n+-1)
+#reset
+
+#data
+E:nth-child(-n-1) {}
+#errors
+#expected
+| 1 E:nth-child(-1n+-1)
+#reset
+
+# DIMENSION ws [ NUMBER ws ]?
+
+#data
+E:nth-child(2n) {}
+#errors
+#expected
+| 1 E:nth-child(2n+0)
+#reset
+
+#data
+E:nth-child(-2n) {}
+#errors
+#expected
+| 1 E:nth-child(-2n+0)
+#reset
+
+#data
+E:nth-child(2n- 1) {}
+#errors
+#expected
+| 1 E:nth-child(2n+-1)
+#reset
+
+#data
+E:nth-child(-2n- 1) {}
+#errors
+#expected
+| 1 E:nth-child(-2n+-1)
+#reset
+
+#data
+E:nth-child(2n-1) {}
+#errors
+#expected
+| 1 E:nth-child(2n+-1)
+#reset
+
+#data
+E:nth-child(-2n-1) {}
+#errors
+#expected
+| 1 E:nth-child(-2n+-1)
+#reset
+
+# IDENT ws CHAR ws NUMBER ws
+
+#data
+E:nth-child(n - 1) {}
+#errors
+#expected
+| 1 E:nth-child(1n+-1)
+#reset
+
+#data
+E:nth-child(n+1) {}
+#errors
+#expected
+| 1 E:nth-child(1n+1)
+#reset
+
+#data
+E:nth-child(n + 1) {}
+#errors
+#expected
+| 1 E:nth-child(1n+1)
+#reset
+
+# DIMENSION ws CHAR ws NUMBER ws
+
+#data
+E:nth-child(2n - 1) {}
+#errors
+#expected
+| 1 E:nth-child(2n+-1)
+#reset
+
+#data
+E:nth-child(2n+1) {}
+#errors
+#expected
+| 1 E:nth-child(2n+1)
+#reset
+
+#data
+E:nth-child(2n + 1) {}
+#errors
+#expected
+| 1 E:nth-child(2n+1)
+#reset
+
+# Illegal inputs
+
+#data
+E:nth-child(n--1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(n-+1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(n- -1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(n- +1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(n + -1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(n - +1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(2n--1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(2n-+1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(2n- -1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(2n- +1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(2n + -1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(2n - +1) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(3 n) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(+2 n) {}
+#errors
+#expected
+#reset
+
+#data
+E:nth-child(+ 2) {}
+#errors
+#expected
+#reset
+
diff --git a/test/data/parse/selectors.dat b/test/data/parse/selectors.dat
index e58d8ac..b77b18a 100644
--- a/test/data/parse/selectors.dat
+++ b/test/data/parse/selectors.dat
@@ -99,6 +99,111 @@ E:first {}
#reset
#data
+E:root {}
+#errors
+#expected
+| 1 E:root
+#reset
+
+#data
+E:nth-child(2n+1) {}
+#errors
+#expected
+| 1 E:nth-child(2n+1)
+#reset
+
+#data
+E:nth-last-child(2n+1) {}
+#errors
+#expected
+| 1 E:nth-last-child(2n+1)
+#reset
+
+#data
+E:nth-of-type(2n+1) {}
+#errors
+#expected
+| 1 E:nth-of-type(2n+1)
+#reset
+
+#data
+E:nth-last-of-type(2n+1) {}
+#errors
+#expected
+| 1 E:nth-last-of-type(2n+1)
+#reset
+
+#data
+E:last-child {}
+#errors
+#expected
+| 1 E:last-child
+#reset
+
+#data
+E:first-of-type {}
+#errors
+#expected
+| 1 E:first-of-type
+#reset
+
+#data
+E:last-of-type {}
+#errors
+#expected
+| 1 E:last-of-type
+#reset
+
+#data
+E:only-child {}
+#errors
+#expected
+| 1 E:only-child
+#reset
+
+#data
+E:only-of-type {}
+#errors
+#expected
+| 1 E:only-of-type
+#reset
+
+#data
+E:empty {}
+#errors
+#expected
+| 1 E:empty
+#reset
+
+#data
+E:target {}
+#errors
+#expected
+| 1 E:target
+#reset
+
+#data
+E:enabled {}
+#errors
+#expected
+| 1 E:enabled
+#reset
+
+#data
+E:disabled {}
+#errors
+#expected
+| 1 E:disabled
+#reset
+
+#data
+E:checked {}
+#errors
+#expected
+| 1 E:checked
+#reset
+
+#data
E:first-line {}
#errors
#expected
@@ -127,6 +232,34 @@ E:after {}
#reset
#data
+E::first-line {}
+#errors
+#expected
+| 1 E:first-line
+#reset
+
+#data
+E::first-letter {}
+#errors
+#expected
+| 1 E:first-letter
+#reset
+
+#data
+E::before {}
+#errors
+#expected
+| 1 E:before
+#reset
+
+#data
+E::after {}
+#errors
+#expected
+| 1 E:after
+#reset
+
+#data
E + F {}
#errors
#expected
@@ -134,6 +267,13 @@ E + F {}
#reset
#data
+E ~ F {}
+#errors
+#expected
+| 1 E ~ F
+#reset
+
+#data
E[foo] {}
#errors
#expected
@@ -162,6 +302,27 @@ E[lang|="en"] {}
#reset
#data
+E[foo^="warning"] {}
+#errors
+#expected
+| 1 E[foo^="warning"]
+#reset
+
+#data
+E[foo$="warning"] {}
+#errors
+#expected
+| 1 E[foo$="warning"]
+#reset
+
+#data
+E[foo*="warning"] {}
+#errors
+#expected
+| 1 E[foo*="warning"]
+#reset
+
+#data
DIV.warning {}
#errors
#expected
@@ -368,3 +529,66 @@ E#myid,bar {}
| 1 #myid, bar
#reset
+# Not pseudo class
+
+#data
+E:not(bar) {}
+#errors
+#expected
+| 1 E:not(bar)
+#reset
+
+#data
+E:not(*) {}
+#errors
+#expected
+| 1 E:not(*)
+#reset
+
+#data
+E:not(#foo) {}
+#errors
+#expected
+| 1 E:not(#foo)
+#reset
+
+#data
+E:not(.bar) {}
+#errors
+#expected
+| 1 E:not(.bar)
+#reset
+
+#data
+E:not([bar]) {}
+#errors
+#expected
+| 1 E:not([bar])
+#reset
+
+#data
+E:not(:first-child) {}
+#errors
+#expected
+| 1 E:not(:first-child)
+#reset
+
+#data
+E:not(:nth-child(2n+1)) {}
+#errors
+#expected
+| 1 E:not(:nth-child(2n+1))
+#reset
+
+#data
+E:not(:first-line) {}
+#errors
+#expected
+#reset
+
+#data
+E:not(:not(bar)) {}
+#errors
+#expected
+#reset
+
diff --git a/test/dump.h b/test/dump.h
index 602530a..85f65b8 100644
--- a/test/dump.h
+++ b/test/dump.h
@@ -178,6 +178,10 @@ void dump_selector_list(css_selector *list, char **ptr)
memcpy(*ptr, " + ", 3);
*ptr += 3;
break;
+ case CSS_COMBINATOR_GENERIC_SIBLING:
+ memcpy(*ptr, " + ", 3);
+ *ptr += 3;
+ break;
}
dump_selector(list, ptr);
@@ -200,6 +204,9 @@ void dump_selector(css_selector *selector, char **ptr)
void dump_selector_detail(css_selector_detail *detail, char **ptr)
{
+ if (detail->negate)
+ *ptr += sprintf(*ptr, ":not(");
+
switch (detail->type) {
case CSS_SELECTOR_ELEMENT:
if (lwc_string_length(detail->name) == 1 &&
@@ -226,12 +233,18 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
**ptr = ':';
*ptr += 1;
dump_string(detail->name, ptr);
- if (detail->value != NULL) {
- **ptr = '(';
- *ptr += 1;
- dump_string(detail->value, ptr);
- **ptr = ')';
- *ptr += 1;
+ if (detail->value_type == CSS_SELECTOR_DETAIL_VALUE_STRING) {
+ if (detail->value.string != NULL) {
+ **ptr = '(';
+ *ptr += 1;
+ dump_string(detail->value.string, ptr);
+ **ptr = ')';
+ *ptr += 1;
+ }
+ } else {
+ *ptr += sprintf(*ptr, "(%dn+%d)",
+ detail->value.nth.a,
+ detail->value.nth.b);
}
break;
case CSS_SELECTOR_ATTRIBUTE:
@@ -248,7 +261,7 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
(*ptr)[0] = '=';
(*ptr)[1] = '"';
*ptr += 2;
- dump_string(detail->value, ptr);
+ dump_string(detail->value.string, ptr);
(*ptr)[0] = '"';
(*ptr)[1] = ']';
*ptr += 2;
@@ -261,7 +274,7 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
(*ptr)[1] = '=';
(*ptr)[2] = '"';
*ptr += 3;
- dump_string(detail->value, ptr);
+ dump_string(detail->value.string, ptr);
(*ptr)[0] = '"';
(*ptr)[1] = ']';
*ptr += 2;
@@ -274,12 +287,54 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
(*ptr)[1] = '=';
(*ptr)[2] = '"';
*ptr += 3;
- dump_string(detail->value, ptr);
+ dump_string(detail->value.string, ptr);
+ (*ptr)[0] = '"';
+ (*ptr)[1] = ']';
+ *ptr += 2;
+ break;
+ case CSS_SELECTOR_ATTRIBUTE_PREFIX:
+ **ptr = '[';
+ *ptr += 1;
+ dump_string(detail->name, ptr);
+ (*ptr)[0] = '^';
+ (*ptr)[1] = '=';
+ (*ptr)[2] = '"';
+ *ptr += 3;
+ dump_string(detail->value.string, ptr);
+ (*ptr)[0] = '"';
+ (*ptr)[1] = ']';
+ *ptr += 2;
+ break;
+ case CSS_SELECTOR_ATTRIBUTE_SUFFIX:
+ **ptr = '[';
+ *ptr += 1;
+ dump_string(detail->name, ptr);
+ (*ptr)[0] = '$';
+ (*ptr)[1] = '=';
+ (*ptr)[2] = '"';
+ *ptr += 3;
+ dump_string(detail->value.string, ptr);
+ (*ptr)[0] = '"';
+ (*ptr)[1] = ']';
+ *ptr += 2;
+ break;
+ case CSS_SELECTOR_ATTRIBUTE_SUBSTRING:
+ **ptr = '[';
+ *ptr += 1;
+ dump_string(detail->name, ptr);
+ (*ptr)[0] = '*';
+ (*ptr)[1] = '=';
+ (*ptr)[2] = '"';
+ *ptr += 3;
+ dump_string(detail->value.string, ptr);
(*ptr)[0] = '"';
(*ptr)[1] = ']';
*ptr += 2;
break;
}
+
+ if (detail->negate)
+ *ptr += sprintf(*ptr, ")");
}
/**
diff --git a/test/parse-auto.c b/test/parse-auto.c
index e268c3b..3c3e011 100644
--- a/test/parse-auto.c
+++ b/test/parse-auto.c
@@ -619,12 +619,15 @@ void dump_selector_list(css_selector *list, char **ptr)
memcpy(*ptr, " + ", 3);
*ptr += 3;
break;
+ case CSS_COMBINATOR_GENERIC_SIBLING:
+ memcpy(*ptr, " ~ ", 3);
+ *ptr += 3;
+ break;
}
dump_selector(list, ptr);
}
-
void dump_selector(css_selector *selector, char **ptr)
{
css_selector_detail *d = &selector->data;
@@ -641,14 +644,17 @@ void dump_selector(css_selector *selector, char **ptr)
void dump_selector_detail(css_selector_detail *detail, char **ptr)
{
+ if (detail->negate)
+ *ptr += sprintf(*ptr, ":not(");
+
switch (detail->type) {
case CSS_SELECTOR_ELEMENT:
- if (lwc_string_length(detail->name) == 1 &&
- lwc_string_data(detail->name)[0] == '*' &&
+ if (lwc_string_length(detail->name) == 1 &&
+ lwc_string_data(detail->name)[0] == '*' &&
detail->next == 0) {
dump_string(detail->name, ptr);
} else if (lwc_string_length(detail->name) != 1 ||
- lwc_string_data(detail->name)[0] != '*') {
+ lwc_string_data(detail->name)[0] != '*') {
dump_string(detail->name, ptr);
}
break;
@@ -667,12 +673,18 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
**ptr = ':';
*ptr += 1;
dump_string(detail->name, ptr);
- if (detail->value != NULL) {
- **ptr = '(';
- *ptr += 1;
- dump_string(detail->value, ptr);
- **ptr = ')';
- *ptr += 1;
+ if (detail->value_type == CSS_SELECTOR_DETAIL_VALUE_STRING) {
+ if (detail->value.string != NULL) {
+ **ptr = '(';
+ *ptr += 1;
+ dump_string(detail->value.string, ptr);
+ **ptr = ')';
+ *ptr += 1;
+ }
+ } else {
+ *ptr += sprintf(*ptr, "(%dn+%d)",
+ detail->value.nth.a,
+ detail->value.nth.b);
}
break;
case CSS_SELECTOR_ATTRIBUTE:
@@ -689,7 +701,7 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
(*ptr)[0] = '=';
(*ptr)[1] = '"';
*ptr += 2;
- dump_string(detail->value, ptr);
+ dump_string(detail->value.string, ptr);
(*ptr)[0] = '"';
(*ptr)[1] = ']';
*ptr += 2;
@@ -702,7 +714,7 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
(*ptr)[1] = '=';
(*ptr)[2] = '"';
*ptr += 3;
- dump_string(detail->value, ptr);
+ dump_string(detail->value.string, ptr);
(*ptr)[0] = '"';
(*ptr)[1] = ']';
*ptr += 2;
@@ -715,12 +727,54 @@ void dump_selector_detail(css_selector_detail *detail, char **ptr)
(*ptr)[1] = '=';
(*ptr)[2] = '"';
*ptr += 3;
- dump_string(detail->value, ptr);
+ dump_string(detail->value.string, ptr);
+ (*ptr)[0] = '"';
+ (*ptr)[1] = ']';
+ *ptr += 2;
+ break;
+ case CSS_SELECTOR_ATTRIBUTE_PREFIX:
+ **ptr = '[';
+ *ptr += 1;
+ dump_string(detail->name, ptr);
+ (*ptr)[0] = '^';
+ (*ptr)[1] = '=';
+ (*ptr)[2] = '"';
+ *ptr += 3;
+ dump_string(detail->value.string, ptr);
+ (*ptr)[0] = '"';
+ (*ptr)[1] = ']';
+ *ptr += 2;
+ break;
+ case CSS_SELECTOR_ATTRIBUTE_SUFFIX:
+ **ptr = '[';
+ *ptr += 1;
+ dump_string(detail->name, ptr);
+ (*ptr)[0] = '$';
+ (*ptr)[1] = '=';
+ (*ptr)[2] = '"';
+ *ptr += 3;
+ dump_string(detail->value.string, ptr);
+ (*ptr)[0] = '"';
+ (*ptr)[1] = ']';
+ *ptr += 2;
+ break;
+ case CSS_SELECTOR_ATTRIBUTE_SUBSTRING:
+ **ptr = '[';
+ *ptr += 1;
+ dump_string(detail->name, ptr);
+ (*ptr)[0] = '*';
+ (*ptr)[1] = '=';
+ (*ptr)[2] = '"';
+ *ptr += 3;
+ dump_string(detail->value.string, ptr);
(*ptr)[0] = '"';
(*ptr)[1] = ']';
*ptr += 2;
break;
}
+
+ if (detail->negate)
+ *ptr += sprintf(*ptr, ")");
}
void dump_string(lwc_string *string, char **ptr)
@@ -728,4 +782,3 @@ void dump_string(lwc_string *string, char **ptr)
*ptr += sprintf(*ptr, "%.*s", (int) lwc_string_length(string),
lwc_string_data(string));
}
-
diff --git a/test/select-auto.c b/test/select-auto.c
index 12fdb5f..3f43898 100644
--- a/test/select-auto.c
+++ b/test/select-auto.c
@@ -90,6 +90,9 @@ static css_error named_parent_node(void *pw, void *node,
static css_error named_sibling_node(void *pw, void *node,
lwc_string *name,
void **sibling);
+static css_error named_generic_sibling_node(void *pw, void *node,
+ lwc_string *name,
+ void **sibling);
static css_error parent_node(void *pw, void *node, void **parent);
static css_error sibling_node(void *pw, void *node, void **sibling);
static css_error node_has_name(void *pw, void *node,
@@ -116,12 +119,31 @@ static css_error node_has_attribute_includes(void *pw, void *node,
lwc_string *name,
lwc_string *value,
bool *match);
-static css_error node_is_first_child(void *pw, void *node, bool *match);
+static css_error node_has_attribute_prefix(void *pw, void *node,
+ lwc_string *name,
+ lwc_string *value,
+ bool *match);
+static css_error node_has_attribute_suffix(void *pw, void *node,
+ lwc_string *name,
+ lwc_string *value,
+ bool *match);
+static css_error node_has_attribute_substring(void *pw, void *node,
+ lwc_string *name,
+ lwc_string *value,
+ bool *match);
+static css_error node_is_root(void *pw, void *node, bool *match);
+static css_error node_count_siblings(void *pw, void *node,
+ bool same_name, bool after, int32_t *count);
+static css_error node_is_empty(void *pw, void *node, bool *match);
static css_error node_is_link(void *pw, void *node, bool *match);
static css_error node_is_visited(void *pw, void *node, bool *match);
static css_error node_is_hover(void *pw, void *node, bool *match);
static css_error node_is_active(void *pw, void *node, bool *match);
static css_error node_is_focus(void *pw, void *node, bool *match);
+static css_error node_is_enabled(void *pw, void *node, bool *match);
+static css_error node_is_disabled(void *pw, void *node, bool *match);
+static css_error node_is_checked(void *pw, void *node, bool *match);
+static css_error node_is_target(void *pw, void *node, bool *match);
static css_error node_is_lang(void *pw, void *node,
lwc_string *lang, bool *match);
static css_error node_presentational_hint(void *pw, void *node,
@@ -138,6 +160,7 @@ static css_select_handler select_handler = {
named_ancestor_node,
named_parent_node,
named_sibling_node,
+ named_generic_sibling_node,
parent_node,
sibling_node,
node_has_name,
@@ -147,12 +170,21 @@ static css_select_handler select_handler = {
node_has_attribute_equal,
node_has_attribute_dashmatch,
node_has_attribute_includes,
- node_is_first_child,
+ node_has_attribute_prefix,
+ node_has_attribute_suffix,
+ node_has_attribute_substring,
+ node_is_root,
+ node_count_siblings,
+ node_is_empty,
node_is_link,
node_is_visited,
node_is_hover,
node_is_active,
node_is_focus,
+ node_is_enabled,
+ node_is_disabled,
+ node_is_checked,
+ node_is_target,
node_is_lang,
node_presentational_hint,
ua_default_for_property,
@@ -882,6 +914,26 @@ css_error named_sibling_node(void *pw, void *n,
return CSS_OK;
}
+css_error named_generic_sibling_node(void *pw, void *n,
+ lwc_string *name,
+ void **sibling)
+{
+ node *node = n;
+ UNUSED(pw);
+
+ for (node = node->prev; node != NULL; node = node->prev) {
+ bool match;
+ assert(lwc_string_caseless_isequal(
+ name, node->name, &match) == lwc_error_ok);
+ if (match == true)
+ break;
+ }
+
+ *sibling = (void *) node;
+
+ return CSS_OK;
+}
+
css_error parent_node(void *pw, void *n, void **parent)
{
node *node = n;
@@ -1109,13 +1161,189 @@ css_error node_has_attribute_dashmatch(void *pw, void *n,
return CSS_OK;
}
-css_error node_is_first_child(void *pw, void *n, bool *match)
+css_error node_has_attribute_prefix(void *pw, void *n,
+ lwc_string *name,
+ lwc_string *value,
+ bool *match)
+{
+ node *node = n;
+ uint32_t i;
+ UNUSED(pw);
+
+ *match = false;
+
+ for (i = 0; i < node->n_attrs; i++) {
+ assert(lwc_string_caseless_isequal(
+ node->attrs[i].name, name, match) ==
+ lwc_error_ok);
+ if (*match == true)
+ break;
+ }
+
+ if (*match == true) {
+ size_t len = lwc_string_length(node->attrs[i].value);
+ const char *data = lwc_string_data(node->attrs[i].value);
+
+ size_t vlen = lwc_string_length(value);
+ const char *vdata = lwc_string_data(value);
+
+ if (len < vlen)
+ *match = false;
+ else
+ *match = (strncasecmp(data, vdata, vlen) == 0);
+ }
+
+ return CSS_OK;
+}
+
+css_error node_has_attribute_suffix(void *pw, void *n,
+ lwc_string *name,
+ lwc_string *value,
+ bool *match)
+{
+ node *node = n;
+ uint32_t i;
+ UNUSED(pw);
+
+ *match = false;
+
+ for (i = 0; i < node->n_attrs; i++) {
+ assert(lwc_string_caseless_isequal(
+ node->attrs[i].name, name, match) ==
+ lwc_error_ok);
+ if (*match == true)
+ break;
+ }
+
+ if (*match == true) {
+ size_t len = lwc_string_length(node->attrs[i].value);
+ const char *data = lwc_string_data(node->attrs[i].value);
+
+ size_t vlen = lwc_string_length(value);
+ const char *vdata = lwc_string_data(value);
+
+ size_t suffix_start = len - vlen;
+
+ if (len < vlen)
+ *match = false;
+ else {
+ *match = (strncasecmp(data + suffix_start,
+ vdata, vlen) == 0);
+ }
+ }
+
+ return CSS_OK;
+}
+
+css_error node_has_attribute_substring(void *pw, void *n,
+ lwc_string *name,
+ lwc_string *value,
+ bool *match)
+{
+ node *node = n;
+ uint32_t i;
+ UNUSED(pw);
+
+ *match = false;
+
+ for (i = 0; i < node->n_attrs; i++) {
+ assert(lwc_string_caseless_isequal(
+ node->attrs[i].name, name, match) ==
+ lwc_error_ok);
+ if (*match == true)
+ break;
+ }
+
+ if (*match == true) {
+ size_t len = lwc_string_length(node->attrs[i].value);
+ const char *data = lwc_string_data(node->attrs[i].value);
+
+ size_t vlen = lwc_string_length(value);
+ const char *vdata = lwc_string_data(value);
+
+ const char *last_start = data + len - vlen;
+
+ if (len < vlen)
+ *match = false;
+ else {
+ while (data <= last_start) {
+ if (strncasecmp(data, vdata, vlen) == 0) {
+ *match = true;
+ break;
+ }
+
+ data++;
+ }
+
+ if (data > last_start)
+ *match = false;
+ }
+ }
+
+ return CSS_OK;
+}
+
+css_error node_is_root(void *pw, void *n, bool *match)
{
node *node = n;
+ UNUSED(pw);
+
+ *match = (node->parent == NULL);
+
+ return CSS_OK;
+}
+
+css_error node_count_siblings(void *pw, void *n,
+ bool same_name, bool after, int32_t *count)
+{
+ int32_t cnt = 0;
+ bool match = false;
+ node *node = n;
+ UNUSED(pw);
+
+ if (after) {
+ while (node->next != NULL) {
+ if (same_name) {
+ assert(lwc_string_caseless_isequal(
+ node->name, node->next->name, &match) ==
+ lwc_error_ok);
+
+ if (match)
+ cnt++;
+ } else {
+ cnt++;
+ }
+
+ node = node->next;
+ }
+ } else {
+ while (node->prev != NULL) {
+ if (same_name) {
+ assert(lwc_string_caseless_isequal(
+ node->name, node->prev->name, &match) ==
+ lwc_error_ok);
+
+ if (match)
+ cnt++;
+ } else {
+ cnt++;
+ }
+
+ node = node->prev;
+ }
+ }
+
+ *count = cnt;
+
+ return CSS_OK;
+}
+css_error node_is_empty(void *pw, void *n, bool *match)
+{
+ node *node = n;
UNUSED(pw);
- *match = (node->parent != NULL && node->parent->children == node);
+ *match = (node->children == NULL);
return CSS_OK;
}
@@ -1180,6 +1408,54 @@ css_error node_is_focus(void *pw, void *n, bool *match)
return CSS_OK;
}
+css_error node_is_enabled(void *pw, void *n, bool *match)
+{
+ node *node = n;
+
+ UNUSED(pw);
+ UNUSED(node);
+
+ *match = false;
+
+ return CSS_OK;
+}
+
+css_error node_is_disabled(void *pw, void *n, bool *match)
+{
+ node *node = n;
+
+ UNUSED(pw);
+ UNUSED(node);
+
+ *match = false;
+
+ return CSS_OK;
+}
+
+css_error node_is_checked(void *pw, void *n, bool *match)
+{
+ node *node = n;
+
+ UNUSED(pw);
+ UNUSED(node);
+
+ *match = false;
+
+ return CSS_OK;
+}
+
+css_error node_is_target(void *pw, void *n, bool *match)
+{
+ node *node = n;
+
+ UNUSED(pw);
+ UNUSED(node);
+
+ *match = false;
+
+ return CSS_OK;
+}
+
css_error node_is_lang(void *pw, void *n,
lwc_string *lang,
bool *match)