summaryrefslogtreecommitdiff
path: root/css
diff options
context:
space:
mode:
Diffstat (limited to 'css')
-rw-r--r--css/css.c84
-rw-r--r--css/css.h62
-rw-r--r--css/ruleset.c251
3 files changed, 394 insertions, 3 deletions
diff --git a/css/css.c b/css/css.c
index 009d71f94..d54f03229 100644
--- a/css/css.c
+++ b/css/css.c
@@ -133,6 +133,9 @@ const struct css_style css_base_style = {
{ CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
{ CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } } } },
0x000000,
+ { CSS_CONTENT_NORMAL, 0 },
+ { CSS_COUNTER_RESET_NONE, 0 },
+ { CSS_COUNTER_INCREMENT_NONE, 0 },
CSS_CURSOR_AUTO,
CSS_DIRECTION_LTR,
CSS_DISPLAY_BLOCK,
@@ -215,6 +218,9 @@ const struct css_style css_empty_style = {
{ CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
{ CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } } } },
CSS_COLOR_NOT_SET,
+ { CSS_CONTENT_NOT_SET, 0 },
+ { CSS_COUNTER_RESET_NOT_SET, 0 },
+ { CSS_COUNTER_INCREMENT_NOT_SET, 0 },
CSS_CURSOR_NOT_SET,
CSS_DIRECTION_NOT_SET,
CSS_DISPLAY_NOT_SET,
@@ -298,6 +304,9 @@ const struct css_style css_blank_style = {
{ CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
{ CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } } } },
CSS_COLOR_INHERIT,
+ { CSS_CONTENT_NORMAL, 0 },
+ { CSS_COUNTER_RESET_NONE, 0 },
+ { CSS_COUNTER_INCREMENT_NONE, 0 },
CSS_CURSOR_INHERIT,
CSS_DIRECTION_INHERIT,
CSS_DISPLAY_INLINE,
@@ -516,10 +525,70 @@ void css_deep_free_style(struct css_style *style)
if (style->list_style_image.type == CSS_LIST_STYLE_IMAGE_URI)
free(style->list_style_image.uri);
+ if (style->content.type == CSS_CONTENT_INTERPRET)
+ css_deep_free_content(style->content.content);
+
+ if (style->counter_reset.type == CSS_COUNTER_RESET_INTERPRET)
+ css_deep_free_counter_control(style->counter_reset.data);
+
+ if (style->counter_increment.type == CSS_COUNTER_INCREMENT_INTERPRET)
+ css_deep_free_counter_control(style->counter_increment.data);
+
free(style);
}
/**
+ * Free all auto-generated content data
+ *
+ * \param content the auto-generated content data to free
+ */
+void css_deep_free_content(struct css_content *content) {
+ struct css_content *next;
+
+ while (content) {
+ next = content->next;
+ switch (content->type) {
+ case CSS_CONTENT_STRING:
+ free(content->data.string);
+ break;
+ case CSS_CONTENT_URI:
+ free(content->data.uri);
+ break;
+ case CSS_CONTENT_COUNTER:
+ free(content->data.counter.name);
+ free(content->data.counter.separator);
+ break;
+ case CSS_CONTENT_ATTR:
+ free(content->data.attr);
+ break;
+ case CSS_CONTENT_OPEN_QUOTE:
+ case CSS_CONTENT_CLOSE_QUOTE:
+ case CSS_CONTENT_NO_OPEN_QUOTE:
+ case CSS_CONTENT_NO_CLOSE_QUOTE:
+ break;
+ }
+ free(content);
+ content = next;
+ }
+}
+
+/**
+ * Free all counter control data
+ *
+ * \param counter the counter control data to free
+ */
+void css_deep_free_counter_control(struct css_counter_control *control) {
+ struct css_counter_control *next;
+
+ while (control) {
+ next = control->next;
+ free(control->name);
+ free(control);
+ control = next;
+ }
+}
+
+/**
* Create a new struct css_node.
*
* \param stylesheet content of type CONTENT_CSS
@@ -2340,6 +2409,15 @@ void css_cascade(struct css_style * const style,
if (apply->color != CSS_COLOR_INHERIT &&
apply->color != CSS_COLOR_NOT_SET)
style->color = apply->color;
+ if (apply->content.type != CSS_CONTENT_INHERIT &&
+ apply->content.type != CSS_CONTENT_NOT_SET)
+ style->content = apply->content;
+ if (apply->counter_reset.type != CSS_COUNTER_RESET_INHERIT &&
+ apply->counter_reset.type != CSS_COUNTER_RESET_NOT_SET)
+ style->counter_reset = apply->counter_reset;
+ if (apply->counter_increment.type != CSS_COUNTER_INCREMENT_INHERIT &&
+ apply->counter_increment.type != CSS_COUNTER_INCREMENT_NOT_SET)
+ style->counter_increment = apply->counter_increment;
if (apply->cursor != CSS_CURSOR_INHERIT &&
apply->cursor != CSS_CURSOR_NOT_SET)
style->cursor = apply->cursor;
@@ -2606,6 +2684,12 @@ void css_merge(struct css_style * const style,
style->clear = apply->clear;
if (apply->color != CSS_COLOR_NOT_SET)
style->color = apply->color;
+ if (apply->content.type != CSS_CONTENT_NOT_SET)
+ style->content = apply->content;
+ if (apply->counter_reset.type != CSS_COUNTER_RESET_NOT_SET)
+ style->counter_reset = apply->counter_reset;
+ if (apply->counter_increment.type != CSS_COUNTER_INCREMENT_NOT_SET)
+ style->counter_increment = apply->counter_increment;
if (apply->cursor != CSS_CURSOR_NOT_SET)
style->cursor = apply->cursor;
if (apply->direction != CSS_DIRECTION_NOT_SET)
diff --git a/css/css.h b/css/css.h
index 9c02cf26e..d795ff17a 100644
--- a/css/css.h
+++ b/css/css.h
@@ -85,6 +85,17 @@ struct css_border_width {
};
typedef enum {
+ CSS_CONTENT_STRING,
+ CSS_CONTENT_URI,
+ CSS_CONTENT_COUNTER,
+ CSS_CONTENT_ATTR,
+ CSS_CONTENT_OPEN_QUOTE,
+ CSS_CONTENT_CLOSE_QUOTE,
+ CSS_CONTENT_NO_OPEN_QUOTE,
+ CSS_CONTENT_NO_CLOSE_QUOTE
+} css_content_type_generated;
+
+typedef enum {
CSS_LIST_STYLE_IMAGE_INHERIT,
CSS_LIST_STYLE_IMAGE_NONE,
CSS_LIST_STYLE_IMAGE_URI,
@@ -113,10 +124,27 @@ typedef enum {
CSS_VERTICAL_ALIGN_NOT_SET
} css_vertical_align_type;
+struct css_counter_control {
+ char *name;
+ int value;
+ struct css_counter_control *next;
+};
+
struct css_counter {
- const char *name;
+ char *name;
css_list_style_type style;
- const char *separator; /** NULL for counter() */
+ char *separator; /** NULL for counter() */
+};
+
+struct css_content {
+ css_content_type_generated type;
+ union {
+ char *string;
+ char *uri;
+ struct css_counter counter;
+ char *attr;
+ } data;
+ struct css_content *next;
};
/** Representation of a complete CSS 2 style. */
@@ -166,7 +194,33 @@ struct css_style {
colour color;
- /** \todo content and counters */
+ /* generated content */
+ struct {
+ enum {
+ CSS_CONTENT_NORMAL,
+ CSS_CONTENT_INHERIT,
+ CSS_CONTENT_INTERPRET,
+ CSS_CONTENT_NOT_SET } type;
+ struct css_content *content;
+ } content;
+
+ /* counter controls */
+ struct {
+ enum {
+ CSS_COUNTER_RESET_NONE,
+ CSS_COUNTER_RESET_INHERIT,
+ CSS_COUNTER_RESET_INTERPRET,
+ CSS_COUNTER_RESET_NOT_SET } type;
+ struct css_counter_control *data;
+ } counter_reset;
+ struct {
+ enum {
+ CSS_COUNTER_INCREMENT_NONE,
+ CSS_COUNTER_INCREMENT_INHERIT,
+ CSS_COUNTER_INCREMENT_INTERPRET,
+ CSS_COUNTER_INCREMENT_NOT_SET } type;
+ struct css_counter_control *data;
+ } counter_increment;
css_cursor cursor;
css_direction direction;
@@ -562,6 +616,8 @@ const char *css_parser_TokenName(int tokenType);
void css_get_style(struct content *c, xmlNode *n, struct css_style * style);
struct css_style *css_duplicate_style(const struct css_style * const style);
void css_free_style(struct css_style *style);
+void css_deep_free_content(struct css_content *content);
+void css_deep_free_counter_control(struct css_counter_control *control);
void css_cascade(struct css_style * const style,
const struct css_style * const apply);
void css_merge(struct css_style * const style,
diff --git a/css/ruleset.c b/css/ruleset.c
index 50ed75743..84074a06e 100644
--- a/css/ruleset.c
+++ b/css/ruleset.c
@@ -40,6 +40,11 @@ static int parse_length(struct css_length * const length,
static colour parse_colour(const struct css_node * const v);
static colour css_parse_rgb(struct css_node *v);
static bool parse_uri(const struct css_node *v, char **uri);
+static struct css_content *parse_content_new(struct css_content **current, css_content_type_generated generated);
+static bool parse_content_counter(struct css_content **current, struct css_node *t, bool counters);
+bool parse_counter_control_data(struct css_counter_control **current, const struct css_node * v, int empty);
+struct css_counter_control *parse_counter_control_new(struct css_counter_control **current);
+
static void parse_background(struct css_style * const s,
const struct css_node * v);
static void parse_background_attachment(struct css_style * const s, const struct css_node * const v);
@@ -91,6 +96,9 @@ static void parse_caption_side(struct css_style * const s, const struct css_node
static void parse_clear(struct css_style * const s, const struct css_node * const v);
static void parse_clip(struct css_style * const s, const struct css_node * v);
static void parse_color(struct css_style * const s, const struct css_node * const v);
+static void parse_content(struct css_style * const s, const struct css_node * v);
+static void parse_counter_increment(struct css_style * const s, const struct css_node * v);
+static void parse_counter_reset(struct css_style * const s, const struct css_node * v);
static void parse_cursor(struct css_style * const s, const struct css_node * v);
static void parse_direction(struct css_style * const s, const struct css_node * v);
static void parse_display(struct css_style * const s, const struct css_node * const v);
@@ -203,6 +211,9 @@ static const struct css_property_entry css_property_table[] = {
{ "clear", parse_clear },
{ "clip", parse_clip },
{ "color", parse_color },
+ { "content", parse_content },
+ { "counter-increment", parse_counter_increment },
+ { "counter-reset", parse_counter_reset },
{ "cursor", parse_cursor },
{ "direction", parse_direction },
{ "display", parse_display },
@@ -1614,6 +1625,246 @@ void parse_color(struct css_style * const s, const struct css_node * const v)
s->color = c;
}
+void parse_content(struct css_style * const s, const struct css_node * v)
+{
+ struct css_content *new_content = NULL;
+ struct css_content *content;
+ struct css_node *t;
+ bool first = true;
+
+ for (; v; v = v->next) {
+ switch (v->type) {
+ case CSS_NODE_STRING:
+ content = parse_content_new(&new_content, CSS_CONTENT_STRING);
+ if (!content)
+ return;
+ content->data.string = strndup(v->data, v->data_length);
+ if (!content->data.string) {
+ css_deep_free_content(new_content);
+ return;
+ }
+ break;
+ case CSS_NODE_URI:
+ content = parse_content_new(&new_content, CSS_CONTENT_URI);
+ if (!content)
+ return;
+ if (!parse_uri(v, &content->data.uri)) {
+ css_deep_free_content(new_content);
+ return;
+ }
+ break;
+ case CSS_NODE_IDENT:
+ if (v->data_length == 7 &&
+ strncasecmp(v->data, "inherit", 7) == 0) {
+ if ((!first) || (v->next))
+ return;
+ css_deep_free_content(s->content.content);
+ s->content.content = NULL;
+ s->content.type = CSS_CONTENT_INHERIT;
+ return;
+ } else if (v->data_length == 6 &&
+ strncasecmp(v->data, "normal", 6) == 0) {
+ if ((!first) || (v->next))
+ return;
+ css_deep_free_content(s->content.content);
+ s->content.content = NULL;
+ s->content.type = CSS_CONTENT_NORMAL;
+ return;
+ } else if (v->data_length == 10 &&
+ strncasecmp(v->data, "open-quote", 10) == 0) {
+ if (!parse_content_new(&new_content, CSS_CONTENT_OPEN_QUOTE))
+ return;
+ } else if (v->data_length == 11 &&
+ strncasecmp(v->data, "close-quote", 11) == 0) {
+ if (!parse_content_new(&new_content, CSS_CONTENT_CLOSE_QUOTE))
+ return;
+ } else if (v->data_length == 13 &&
+ strncasecmp(v->data, "no-open-quote", 13) == 0) {
+ if (!parse_content_new(&new_content, CSS_CONTENT_NO_OPEN_QUOTE))
+ return;
+ } else if (v->data_length == 14 &&
+ strncasecmp(v->data, "no-close-quote", 14) == 0) {
+ if (!parse_content_new(&new_content, CSS_CONTENT_NO_CLOSE_QUOTE))
+ return;
+ } else {
+ css_deep_free_content(new_content);
+ return;
+ }
+ break;
+ case CSS_NODE_FUNCTION:
+ if (v->data_length == 5 &&
+ strncasecmp(v->data, "attr", 4) == 0) {
+ content = parse_content_new(&new_content, CSS_CONTENT_URI);
+ if (!content)
+ return;
+ t = v->value;
+ if ((t->type == CSS_NODE_STRING) && (!t->next)) {
+ content->data.string = strndup(t->data, t->data_length);
+ if (!content->data.string) {
+ css_deep_free_content(new_content);
+ return;
+ }
+ } else {
+ css_deep_free_content(new_content);
+ return;
+ }
+ } else if (v->data_length == 8 &&
+ strncasecmp(v->data, "counter", 7) == 0) {
+ if (!parse_content_counter(&new_content, v->value, false))
+ return;
+ } else if (v->data_length == 9 &&
+ strncasecmp(v->data, "counters", 8) == 0) {
+ if (!parse_content_counter(&new_content, v->value, true))
+ return;
+ } else {
+ css_deep_free_content(new_content);
+ return;
+ }
+ default:
+ css_deep_free_content(new_content);
+ return;
+ }
+ first = false;
+ }
+
+ if (new_content) {
+ css_deep_free_content(s->content.content);
+ s->content.type = CSS_CONTENT_INTERPRET;
+ s->content.content = new_content;
+ }
+}
+
+struct css_content *parse_content_new(struct css_content **current, css_content_type_generated generated) {
+ struct css_content *content;
+ struct css_content *link;
+
+ content = (struct css_content *)calloc(1, sizeof(struct css_content));
+ if (!content) {
+ css_deep_free_content(*current);
+ return NULL;
+ }
+
+ content->type = generated;
+ if (!*current) {
+ *current = content;
+ } else {
+ for (link = *current; link->next; link = link->next);
+ link->next = content;
+ }
+ return content;
+}
+
+bool parse_content_counter(struct css_content **current, struct css_node *t, bool counters) {
+ struct css_content *content;
+ css_list_style_type z;
+
+ content = parse_content_new(current, CSS_CONTENT_COUNTER);
+ if ((!content) || (t->type != CSS_NODE_IDENT))
+ return false;
+
+ content->data.counter.name = strndup(t->data, t->data_length);
+ content->data.counter.style = CSS_LIST_STYLE_TYPE_DECIMAL;
+ t = t->next;
+
+ if (counters) {
+ if ((!t) || (t->type != CSS_NODE_STRING)) {
+ css_deep_free_content(*current);
+ return false;
+ }
+ content->data.counter.separator = strndup(t->data, t->data_length);
+ t = t->next;
+ }
+
+ if (!t)
+ return true;
+
+ if ((t->type != CSS_NODE_IDENT) || (t->next)) {
+ css_deep_free_content(*current);
+ return false;
+ }
+ z = css_list_style_type_parse(t->data, t->data_length);
+ if (z != CSS_LIST_STYLE_TYPE_UNKNOWN)
+ content->data.counter.style = z;
+ return true;
+}
+
+void parse_counter_reset(struct css_style * const s, const struct css_node * v) {
+ struct css_counter_control *counter = NULL;
+
+ if (!parse_counter_control_data(&counter, v, 0))
+ return;
+
+ if (counter) {
+ css_deep_free_counter_control(s->counter_reset.data);
+ s->counter_reset.type = CSS_COUNTER_RESET_INTERPRET;
+ s->counter_reset.data = counter;
+ }
+}
+
+void parse_counter_increment(struct css_style * const s, const struct css_node * v) {
+ struct css_counter_control *counter = NULL;
+
+ if (!parse_counter_control_data(&counter, v, 1))
+ return;
+
+ if (counter) {
+ css_deep_free_counter_control(s->counter_increment.data);
+ s->counter_increment.type = CSS_COUNTER_INCREMENT_INTERPRET;
+ s->counter_increment.data = counter;
+ }
+}
+
+bool parse_counter_control_data(struct css_counter_control **current, const struct css_node * v, int empty) {
+ struct css_counter_control *open = NULL;
+
+ for (; v; v = v->next) {
+ switch (v->type) {
+ case CSS_NODE_IDENT:
+ open = parse_counter_control_new(current);
+ if (!open)
+ return false;
+ open->name = strndup(v->data, v->data_length);
+ open->value = empty;
+ if (!open->name) {
+ css_deep_free_counter_control(*current);
+ return false;
+ }
+ break;
+ case CSS_NODE_NUMBER:
+ if (!open) {
+ css_deep_free_counter_control(*current);
+ return false;
+ }
+ open->value = atoi(v->data);
+ open = NULL;
+ break;
+ default:
+ css_deep_free_counter_control(*current);
+ return false;
+ }
+ }
+ return true;
+}
+
+struct css_counter_control *parse_counter_control_new(struct css_counter_control **current) {
+ struct css_counter_control *counter;
+ struct css_counter_control *link;
+
+ counter = (struct css_counter_control *)calloc(1, sizeof(struct css_counter_control));
+ if (!counter) {
+ css_deep_free_counter_control(*current);
+ return NULL;
+ }
+
+ if (!*current) {
+ *current = counter;
+ } else {
+ for (link = *current; link->next; link = link->next);
+ link->next = counter;
+ }
+ return counter;
+}
+
void parse_cursor(struct css_style * const s, const struct css_node * v)
{
css_cursor z;