summaryrefslogtreecommitdiff
path: root/css
diff options
context:
space:
mode:
Diffstat (limited to 'css')
-rw-r--r--css/Makefile44
-rw-r--r--css/css.c3446
-rw-r--r--css/css.h705
-rw-r--r--css/css_enums29
-rw-r--r--css/dump.c1791
-rw-r--r--css/dump.h26
-rw-r--r--css/internal.c82
-rw-r--r--css/internal.h27
-rwxr-xr-xcss/makeenum46
-rw-r--r--css/parser.y441
-rw-r--r--css/ruleset.c3152
-rw-r--r--css/scanner.l112
-rw-r--r--css/select.c1981
-rw-r--r--css/select.h51
-rw-r--r--css/testcss.c181
-rw-r--r--css/utils.c124
-rw-r--r--css/utils.h44
17 files changed, 4379 insertions, 7903 deletions
diff --git a/css/Makefile b/css/Makefile
deleted file mode 100644
index 6be322a6f..000000000
--- a/css/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-# Makefile for CSS test code
-
-AR := ar
-CC := gcc
-LD := gcc
-
-CFLAGS := -O2 -I.. -I/usr/include/libxml2 -std=c99
-LDFLAGS := -lxml2 -lz -lcurl
-
-LIBOBJS := css.o css_enum.o parser.o ruleset.o scanner.o \
- messages.o hashtable.o talloc.o url.o utils.o
-
-.PHONY: default lib clean
-
-default:
- $(error "You probably wanted 'make test'")
-
-test: lib testcss.o
- $(LD) -o $@ testcss.o $(LDFLAGS) -L. -lnscss
-
-lib: $(LIBOBJS)
- $(AR) -cru libnscss.a $^
-
-clean:
- $(RM) $(LIBOBJS) testcss.o test libnscss.a
-
-messages.o: ../utils/messages.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-hashtable.o: ../utils/hashtable.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-talloc.o: ../utils/talloc.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-url.o: ../utils/url.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-utils.o: ../utils/utils.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-%.o : %.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
diff --git a/css/css.c b/css/css.c
index b035323d4..dbb4f53be 100644
--- a/css/css.c
+++ b/css/css.c
@@ -1,7 +1,5 @@
/*
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -18,3313 +16,337 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * CSS handling (implementation).
- *
- * See CSS 2.1 chapter 5 for the terms used here.
- *
- * CSS style sheets are stored as a hash table mapping selectors to styles.
- * Selectors are hashed by the <em>type selector</em> of the last <em>simple
- * selector</em> in the selector. The <em>universal selector</em> is hashed to
- * chain 0.
- *
- * A <em>simple selector</em> is a struct css_selector with type
- * CSS_SELECTOR_ELEMENT. The data field is the <em>type selector</em>, or 0 for
- * the <em>universal selector</em>. Any <em>attribute selectors</em>, <em>ID
- * selectors</em>, or <em>pseudo-classes</em> form a linked list of
- * css_selector hanging from detail.
- *
- * A <em>selector</em> is a linked list by the combiner field of these simple
- * selectors, in reverse order that they appear in the concrete syntax. The last
- * simple selector is first, then the previous one is linked at combiner and has
- * relationship comb to the last, etc.
- *
- * Selectors are then linked in each hash chain by next, in order of increasing
- * specificity.
- *
- * As an example, the stylesheet
- * \code
- * th { [1] }
- * div#id1 > h4.class1 { [2] }
- * center * { [3] } \endcode
- *
- * would result in a struct css_stylesheet (content::data.css.css) like this
- * \dot
- * digraph example {
- * node [shape=record, fontname=Helvetica, fontsize=9];
- * edge [fontname=Helvetica, fontsize=9];
- * css -> n0 [label="rule[0]"];
- * css -> n2 [label="rule[29]"];
- *
- * n0 [label="css_selector\ntype CSS_SELECTOR_ELEMENT\ldata 0\lcomb CSS_COMB_ANCESTOR\lspecificity 2\l"];
- * n0 -> n1 [label="combiner"];
- * n0 -> n0style [label="style"]; n0style [label="[3]"];
- *
- * n1 [label="css_selector\ntype CSS_SELECTOR_ELEMENT\ldata \"center\"\lcomb CSS_COMB_NONE\lspecificity 1\l"];
- *
- * n2 [label="css_selector\ntype CSS_SELECTOR_ELEMENT\ldata \"th\"\lcomb CSS_COMB_NONE\lspecificity 1\l"];
- * n2 -> n3 [label="next"];
- * n2 -> n2style [label="style"]; n2style [label="[1]"];
- *
- * n3 [label="css_selector\ntype CSS_SELECTOR_ELEMENT\ldata \"h4\"\lcomb CSS_COMB_PARENT\lspecificity 0x10102\l"];
- * n3 -> n4 [label="detail"];
- * n3 -> n5 [label="combiner"];
- * n3 -> n3style [label="style"]; n3style [label="[2]"];
- *
- * n4 [label="css_selector\ntype CSS_SELECTOR_CLASS\ldata \"class1\"\lcomb CSS_COMB_NONE\lspecificity 0x100\l"];
- *
- * n5 [label="css_selector\ntype CSS_SELECTOR_ELEMENT\ldata \"div\"\lcomb CSS_COMB_NONE\lspecificity 0x10001\l"];
- * n5 -> n6 [label="detail"];
- *
- * n6 [label="css_selector\ntype CSS_SELECTOR_ID\ldata \"#id1\"\lcomb CSS_COMB_NONE\lspecificity 0x10000\l"];
- * }
- * \enddot
- *
- * (any fields not shown are 0). In this example the first two rules happen to
- * have hashed to the same value.
- */
-
-#define _GNU_SOURCE /* for strndup */
#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <math.h>
-#include <limits.h>
-#define CSS_INTERNALS
-#include "utils/config.h"
+
+#include <libwapcaplet/libwapcaplet.h>
+
#include "content/content.h"
#include "content/fetch.h"
#include "content/fetchcache.h"
#include "css/css.h"
-#include "css/parser.h"
+#include "css/internal.h"
#include "desktop/gui.h"
-#include "desktop/options.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/talloc.h"
-#include "utils/url.h"
-#include "utils/utils.h"
-
-/* Define this to debug the working stylesheet */
-#undef DEBUG_WORKING_STYLESHEET
-struct css_working_stylesheet {
- struct css_selector **rule[HASH_SIZE];
-};
+#include "render/html.h"
-
-static void css_deep_free_style(struct css_style *style);
-static void css_atimport_callback(content_msg msg, struct content *css,
+static void nscss_import(content_msg msg, struct content *c,
intptr_t p1, intptr_t p2, union content_msg_data data);
-static bool css_working_list_imports(struct content **import,
- unsigned int import_count,
- struct content ***css, unsigned int *css_count);
-static bool css_working_merge_chains(
- struct css_working_stylesheet *working_stylesheet,
- struct content **css, unsigned int css_count,
- unsigned int chain,
- struct css_selector **rule);
-static bool css_match_rule(struct css_selector *rule, xmlNode *element);
-static bool css_match_detail(const struct css_selector *detail,
- xmlNode *element);
-static bool css_match_first_child(const struct css_selector *detail,
- xmlNode *element);
-static void css_dump_length(FILE *stream,
- const struct css_length * const length);
-static void css_dump_selector(const struct css_selector *r);
-#ifdef DEBUG_WORKING_STYLESHEET
-static void css_dump_working_stylesheet(
- const struct css_working_stylesheet *ws);
-#endif
-static void css_importance_reset(struct css_importance *i);
-
-/** Default style for a document. These are the 'Initial values' from the
- * spec. */
-const struct css_style css_base_style = {
- CSS_BACKGROUND_ATTACHMENT_SCROLL,
- 0xffffff,
- { CSS_BACKGROUND_IMAGE_NONE, 0 },
- { { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } },
- { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } } },
- CSS_BACKGROUND_REPEAT_REPEAT,
- { { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE },
- { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE },
- { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE },
- { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE } },
- CSS_BORDER_COLLAPSE_SEPARATE,
- { CSS_BORDER_SPACING_LENGTH,
- { 0, CSS_UNIT_PX }, { 0, CSS_UNIT_PX } },
- CSS_CAPTION_SIDE_TOP,
- CSS_CLEAR_NONE,
- { CSS_CLIP_AUTO, { { CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
- { CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
- { 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,
- CSS_EMPTY_CELLS_SHOW,
- CSS_FLOAT_NONE,
- CSS_FONT_FAMILY_SANS_SERIF,
- { CSS_FONT_SIZE_LENGTH, { { 10, CSS_UNIT_PT } } },
- CSS_FONT_STYLE_NORMAL,
- CSS_FONT_VARIANT_NORMAL,
- CSS_FONT_WEIGHT_NORMAL,
- { CSS_HEIGHT_AUTO, { { 1, CSS_UNIT_EM } } },
- { CSS_LETTER_SPACING_NORMAL, { 0, CSS_UNIT_PX } },
- { CSS_LINE_HEIGHT_ABSOLUTE, { 1.33 } },
- { CSS_LIST_STYLE_IMAGE_NONE, 0 },
- CSS_LIST_STYLE_POSITION_OUTSIDE,
- CSS_LIST_STYLE_TYPE_DISC,
- { { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } } },
- { CSS_MAX_HEIGHT_NONE, { { 0, CSS_UNIT_PX } } },
- { CSS_MAX_WIDTH_NONE, { { 0, CSS_UNIT_PX } } },
- { CSS_MIN_HEIGHT_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MIN_WIDTH_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_ORPHANS_INTEGER, 2 },
- { { CSS_OUTLINE_COLOR_INVERT, 0x000000 },
- { CSS_BORDER_WIDTH_LENGTH, { 2, CSS_UNIT_PX } },
- CSS_BORDER_STYLE_NONE },
- CSS_OVERFLOW_VISIBLE,
- { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } } },
- CSS_PAGE_BREAK_AFTER_AUTO,
- CSS_PAGE_BREAK_BEFORE_AUTO,
- CSS_PAGE_BREAK_INSIDE_AUTO,
- { { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } } },
- CSS_POSITION_STATIC,
- CSS_TABLE_LAYOUT_AUTO,
- CSS_TEXT_ALIGN_LEFT,
- CSS_TEXT_DECORATION_NONE,
- { CSS_TEXT_INDENT_LENGTH, { { 0, CSS_UNIT_EM } } },
- CSS_TEXT_TRANSFORM_NONE,
- CSS_UNICODE_BIDI_NORMAL,
- { CSS_VERTICAL_ALIGN_BASELINE, { { 0, CSS_UNIT_PX } } },
- CSS_VISIBILITY_VISIBLE,
- CSS_WHITE_SPACE_NORMAL,
- { CSS_WIDOWS_INTEGER, 2 },
- { CSS_WIDTH_AUTO, { { 1, CSS_UNIT_EM } } },
- { CSS_WORD_SPACING_NORMAL, { 0, CSS_UNIT_PX } },
- { CSS_Z_INDEX_AUTO, 0 }
-};
-
-/** Style with no values set. */
-const struct css_style css_empty_style = {
- CSS_BACKGROUND_ATTACHMENT_NOT_SET,
- CSS_COLOR_NOT_SET,
- { CSS_BACKGROUND_IMAGE_NOT_SET, 0 },
- { { CSS_BACKGROUND_POSITION_NOT_SET, { 0.0 } },
- { CSS_BACKGROUND_POSITION_NOT_SET, { 0.0 } } },
- CSS_BACKGROUND_REPEAT_NOT_SET,
- { { CSS_COLOR_NOT_SET, { CSS_BORDER_WIDTH_NOT_SET,
- { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NOT_SET },
- { CSS_COLOR_NOT_SET, { CSS_BORDER_WIDTH_NOT_SET,
- { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NOT_SET },
- { CSS_COLOR_NOT_SET, { CSS_BORDER_WIDTH_NOT_SET,
- { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NOT_SET },
- { CSS_COLOR_NOT_SET, { CSS_BORDER_WIDTH_NOT_SET,
- { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NOT_SET } },
- CSS_BORDER_COLLAPSE_NOT_SET,
- { CSS_BORDER_SPACING_NOT_SET,
- { 0, CSS_UNIT_PX }, { 0, CSS_UNIT_PX } },
- CSS_CAPTION_SIDE_NOT_SET,
- CSS_CLEAR_NOT_SET,
- { CSS_CLIP_NOT_SET, { { CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
- { CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
- { 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,
- CSS_EMPTY_CELLS_NOT_SET,
- CSS_FLOAT_NOT_SET,
- CSS_FONT_FAMILY_NOT_SET,
- { CSS_FONT_SIZE_NOT_SET, { { 1, CSS_UNIT_PT } } },
- CSS_FONT_STYLE_NOT_SET,
- CSS_FONT_VARIANT_NOT_SET,
- CSS_FONT_WEIGHT_NOT_SET,
- { CSS_HEIGHT_NOT_SET, { { 1, CSS_UNIT_EM } } },
- { CSS_LETTER_SPACING_NOT_SET, { 0, CSS_UNIT_PX } },
- { CSS_LINE_HEIGHT_NOT_SET, { 1.33 } },
- { CSS_LIST_STYLE_IMAGE_NOT_SET, 0 },
- CSS_LIST_STYLE_POSITION_NOT_SET,
- CSS_LIST_STYLE_TYPE_NOT_SET,
- { { CSS_MARGIN_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_NOT_SET, { { 0, CSS_UNIT_PX } } } },
- { CSS_MAX_HEIGHT_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_MAX_WIDTH_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_MIN_HEIGHT_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_MIN_WIDTH_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_ORPHANS_NOT_SET, 0 },
- { { CSS_OUTLINE_COLOR_NOT_SET, CSS_COLOR_NOT_SET },
- { CSS_BORDER_WIDTH_NOT_SET, { 0, CSS_UNIT_PX } },
- CSS_BORDER_STYLE_NOT_SET },
- CSS_OVERFLOW_NOT_SET,
- { { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } } },
- CSS_PAGE_BREAK_AFTER_NOT_SET,
- CSS_PAGE_BREAK_BEFORE_NOT_SET,
- CSS_PAGE_BREAK_INSIDE_NOT_SET,
- { { CSS_POS_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_NOT_SET, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_NOT_SET, { { 0, CSS_UNIT_PX } } } },
- CSS_POSITION_NOT_SET,
- CSS_TABLE_LAYOUT_NOT_SET,
- CSS_TEXT_ALIGN_NOT_SET,
- CSS_TEXT_DECORATION_NOT_SET,
- { CSS_TEXT_INDENT_NOT_SET, { { 0, CSS_UNIT_EM } } },
- CSS_TEXT_TRANSFORM_NOT_SET,
- CSS_UNICODE_BIDI_NOT_SET,
- { CSS_VERTICAL_ALIGN_NOT_SET, { { 0, CSS_UNIT_PX } } },
- CSS_VISIBILITY_NOT_SET,
- CSS_WHITE_SPACE_NOT_SET,
- { CSS_WIDOWS_NOT_SET, 0 },
- { CSS_WIDTH_NOT_SET, { { 1, CSS_UNIT_EM } } },
- { CSS_WORD_SPACING_NOT_SET, { 0, CSS_UNIT_PX } },
- { CSS_Z_INDEX_NOT_SET, 0 }
-};
-
-/** Default style for an element. These should be INHERIT if 'Inherited' is yes,
- * and the 'Initial value' otherwise. */
-const struct css_style css_blank_style = {
- CSS_BACKGROUND_ATTACHMENT_SCROLL,
- NS_TRANSPARENT,
- { CSS_BACKGROUND_IMAGE_NONE, 0 },
- { { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } },
- { CSS_BACKGROUND_POSITION_PERCENT, { 0.0 } } },
- CSS_BACKGROUND_REPEAT_REPEAT,
- { { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE },
- { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE },
- { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE },
- { 0x000000, { CSS_BORDER_WIDTH_LENGTH,
- { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE } },
- CSS_BORDER_COLLAPSE_INHERIT,
- { CSS_BORDER_SPACING_INHERIT,
- { 0, CSS_UNIT_PX }, { 0, CSS_UNIT_PX } },
- CSS_CAPTION_SIDE_INHERIT,
- CSS_CLEAR_NONE,
- { CSS_CLIP_AUTO, { { CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
- { CSS_CLIP_RECT_AUTO, { 0, CSS_UNIT_PX } },
- { 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,
- CSS_EMPTY_CELLS_INHERIT,
- CSS_FLOAT_NONE,
- CSS_FONT_FAMILY_INHERIT,
- { CSS_FONT_SIZE_INHERIT, { { 1, CSS_UNIT_EM } } },
- CSS_FONT_STYLE_INHERIT,
- CSS_FONT_VARIANT_INHERIT,
- CSS_FONT_WEIGHT_INHERIT,
- { CSS_HEIGHT_AUTO, { { 1, CSS_UNIT_EM } } },
- { CSS_LETTER_SPACING_INHERIT, { 0, CSS_UNIT_PX } },
- { CSS_LINE_HEIGHT_INHERIT, { 1.33 } },
- { CSS_LIST_STYLE_IMAGE_INHERIT, 0 },
- CSS_LIST_STYLE_POSITION_INHERIT,
- CSS_LIST_STYLE_TYPE_INHERIT,
- { { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MARGIN_LENGTH, { { 0, CSS_UNIT_PX } } } },
- { CSS_MAX_HEIGHT_NONE, { { 0, CSS_UNIT_PX } } },
- { CSS_MAX_WIDTH_NONE, { { 0, CSS_UNIT_PX } } },
- { CSS_MIN_HEIGHT_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_MIN_WIDTH_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_ORPHANS_INHERIT, 0 },
- { { CSS_OUTLINE_COLOR_INVERT, 0x000000 },
- { CSS_BORDER_WIDTH_LENGTH, { 2, CSS_UNIT_PX } },
- CSS_BORDER_STYLE_NONE },
- CSS_OVERFLOW_VISIBLE,
- { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } },
- { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } } },
- CSS_PAGE_BREAK_AFTER_AUTO,
- CSS_PAGE_BREAK_BEFORE_AUTO,
- CSS_PAGE_BREAK_INSIDE_INHERIT,
- { { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } },
- { CSS_POS_AUTO, { { 0, CSS_UNIT_PX } } } },
- CSS_POSITION_STATIC,
- CSS_TABLE_LAYOUT_AUTO,
- CSS_TEXT_ALIGN_INHERIT,
- CSS_TEXT_DECORATION_NONE,
- { CSS_TEXT_INDENT_INHERIT, { { 0, CSS_UNIT_EM } } },
- CSS_TEXT_TRANSFORM_INHERIT,
- CSS_UNICODE_BIDI_NORMAL,
- { CSS_VERTICAL_ALIGN_BASELINE, { { 0, CSS_UNIT_PX } } },
- CSS_VISIBILITY_INHERIT,
- CSS_WHITE_SPACE_INHERIT,
- { CSS_WIDOWS_INHERIT, 0 },
- { CSS_WIDTH_AUTO, { { 1, CSS_UNIT_EM } } },
- { CSS_WORD_SPACING_INHERIT, { 0, CSS_UNIT_PX } },
- { CSS_Z_INDEX_AUTO, 0 }
-};
-
-/** Dots per inch for the display device.
- *
- * This is the number of pixels per inch of the display device.
- * This variable should be treated as constant during the runtime of
- * the program unless the core can be persuaded to re-layout fully
- * on change.
- *
- * We default to 90.0 because RISC OS defaults to 90.0 dpi.
- */
-float css_screen_dpi = 90.0;
-
-/**
- * Convert a CONTENT_CSS for use.
- */
-
-bool css_convert(struct content *c, int width, int height)
-{
- unsigned char *source_data;
- unsigned char *current, *end, *token_text;
- unsigned int i;
- int token;
- void *parser;
- struct css_parser_params param = {false, c, 0, false, false, false};
- struct css_parser_token token_data;
- union content_msg_data msg_data;
-
- /* css_parser_Trace(stderr, "CSS: "); */
-
- c->data.css.css = malloc(sizeof *c->data.css.css);
- parser = css_parser_Alloc(malloc);
- source_data = (unsigned char *) talloc_realloc(c, c->source_data, char,
- c->source_size + 10);
-
- if (!c->data.css.css || !parser || !source_data) {
- free(c->data.css.css);
- css_parser_Free(parser, free);
-
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
- }
-
- for (i = 0; i != HASH_SIZE; i++)
- c->data.css.css->rule[i] = 0;
- c->data.css.import_count = 0;
- c->data.css.import_content = 0;
- c->data.css.origin = CSS_ORIGIN_UA;
- c->active = 0;
- c->source_data = (char *) source_data;
-
- for (i = 0; i != 10; i++)
- source_data[c->source_size + i] = 0;
-
- current = source_data;
- end = source_data + c->source_size;
- while (current < end
- && (token = css_tokenise(&current, end + 10,
- &token_text))) {
- token_data.text = (char *) token_text;
- token_data.length = current - token_text;
- css_parser_(parser, token, token_data, &param);
- if (param.syntax_error) {
- LOG(("syntax error near offset %li (%s)",
- (unsigned long) (token_text - source_data),
- c->url));
- param.syntax_error = false;
- } else if (param.memory_error) {
- LOG(("out of memory"));
- break;
- }
- }
-
- css_parser_(parser, 0, token_data, &param);
- css_parser_Free(parser, free);
-
- if (param.memory_error) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
- }
-
- /*css_dump_stylesheet(c->data.css.css);*/
-
- /* complete fetch of any imported stylesheets */
- while (c->active != 0) {
- fetch_poll();
- gui_multitask();
- }
-
- c->status = CONTENT_STATUS_DONE;
- return true;
-}
-
-
-/**
- * Destroy a CONTENT_CSS and free all resources it owns.
- */
-
-void css_destroy(struct content *c)
-{
- unsigned int i;
- struct css_selector *r;
-
- if (c->data.css.css) {
- for (i = 0; i != HASH_SIZE; i++) {
- for (r = c->data.css.css->rule[i]; r != 0;
- r = r->next) {
- css_deep_free_style(r->style);
- }
- css_free_selector(c->data.css.css->rule[i]);
- }
- free(c->data.css.css);
- }
-
- /* imported stylesheets */
- for (i = 0; i != c->data.css.import_count; i++)
- if (c->data.css.import_content[i] != 0) {
- content_remove_user(c->data.css.import_content[i],
- css_atimport_callback, (intptr_t) c, i);
- }
- free(c->data.css.import_content);
-}
-
-
-/**
- * Set the origin of a stylesheet.
- *
- * \param c content of type CONTENT_CSS
- * \param origin new origin
- *
- * This may only be called once per stylesheet.
- */
-
-void css_set_origin(struct content *c, css_origin origin)
-{
- unsigned int chain, i;
- unsigned long specificity = 0;
- struct css_selector *selector;
-
- assert(c->type == CONTENT_CSS);
-
- if (origin == c->data.css.origin)
- return;
-
- switch (origin)
- {
- case CSS_ORIGIN_AUTHOR: specificity = CSS_SPECIFICITY_AUTHOR; break;
- case CSS_ORIGIN_USER: specificity = CSS_SPECIFICITY_USER; break;
- case CSS_ORIGIN_UA: specificity = CSS_SPECIFICITY_UA; break;
- }
-
- for (chain = 0; chain != HASH_SIZE; chain++)
- for (selector = c->data.css.css->rule[chain];
- selector;
- selector = selector->next)
- selector->specificity += specificity;
- c->data.css.origin = origin;
-
- for (i = 0; i != c->data.css.import_count; i++)
- if (c->data.css.import_content[i])
- css_set_origin(c->data.css.import_content[i], origin);
-}
-
-
-/**
- * Duplicate a CSS style struct.
- *
- * \param style The style to duplicate
- * \return The duplicate style, or NULL if out of memory.
- */
-
-struct css_style *css_duplicate_style(const struct css_style * const style)
-{
- struct css_style *dup;
-
- assert(style);
-
- /* create duplicated style */
- dup = malloc(sizeof (struct css_style));
- if (!dup)
- return NULL;
-
- /* copy all style information into duplicate style */
- memcpy(dup, style, sizeof(struct css_style));
-
- return dup;
-}
-
-
-/**
- * Free a CSS style.
- *
- * \param style The style to free
- */
-
-void css_free_style(struct css_style *style)
-{
- assert(style);
-
- free(style);
-}
-
-
-/**
- * Free a CSS style, deleting all alloced elements.
- *
- * \param style The style to free
- */
-
-void css_deep_free_style(struct css_style *style)
-{
- assert(style);
-
- if (style->background_image.type == CSS_BACKGROUND_IMAGE_URI)
- free(style->background_image.uri);
-
- 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.
+ * Allocation callback for libcss
*
- * \param counter the counter control data to free
+ * \param ptr Pointer to reallocate, or NULL for new allocation
+ * \param size Number of bytes requires
+ * \param pw Allocation context
+ * \return Pointer to allocated block, or NULL on failure
*/
-
-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
- * \param type type of node
- * \param data string for data, not copied
- * \param data_length length of data
- * \return allocated node, or 0 if memory exhausted
- *
- * Used by the parser.
- */
-
-struct css_node * css_new_node(struct content *stylesheet,
- css_node_type type,
- const char *data, unsigned int data_length)
-{
- struct css_node *node = malloc(sizeof *node);
- if (!node)
- return 0;
- node->type = type;
- node->data = data;
- node->data_length = data_length;
- node->value = 0;
- node->next = 0;
- node->comb = CSS_COMB_NONE;
- node->style = 0;
- node->specificity = 0;
- node->stylesheet = stylesheet;
-
- return node;
-}
-
-
-/**
- * Free a struct css_node recursively.
- *
- * \param node css_node to free
- *
- * Used by the parser.
- */
-
-void css_free_node(struct css_node *node)
+static void *myrealloc(void *ptr, size_t size, void *pw)
{
- if (!node)
- return;
- if (node->value)
- css_free_node(node->value);
- if (node->next)
- css_free_node(node->next);
- free(node);
+ return realloc(ptr, size);
}
-
/**
- * Create a new struct css_selector.
+ * Initialise a CSS content
*
- * \param type type of selector
- * \param data string for data, not copied
- * \param data_length length of data
- * \return allocated selector, or 0 if memory exhausted
+ * \param c Content to initialise
+ * \param parent Parent content, or NULL if top-level
+ * \param params Content-Type parameters
+ * \return true on success, false on failure
*/
-
-struct css_selector * css_new_selector(css_selector_type type,
- const char *data, unsigned int data_length)
+bool nscss_create(struct content *c, struct content *parent,
+ const char *params[])
{
- struct css_selector *node = malloc(sizeof *node);
- if (!node)
- return 0;
- node->type = type;
- node->data = data;
- node->data_length = data_length;
- node->data2 = 0;
- node->detail = 0;
- node->combiner = 0;
- node->next = 0;
- node->comb = CSS_COMB_NONE;
- node->style = 0;
- node->specificity = 0;
- return node;
-}
+ css_origin origin = CSS_ORIGIN_AUTHOR;
+ css_media_type media = CSS_MEDIA_ALL;
+ lwc_context *dict = NULL;
+ bool quirks = true;
+ css_error error;
+ /** \todo extract charset from params */
+ /** \todo what happens about the allocator? */
-/**
- * Free a struct css_selector recursively.
- *
- * \param node css_selector to free
- */
+ if (parent != NULL) {
+ assert(parent->type == CONTENT_HTML ||
+ parent->type == CONTENT_CSS);
-void css_free_selector(struct css_selector *node)
-{
- if (!node)
- return;
- if (node->detail)
- css_free_selector(node->detail);
- if (node->combiner)
- css_free_selector(node->combiner);
- if (node->next)
- css_free_selector(node->next);
- free(node);
-}
-
-
-/**
- * Process an \@import rule.
- */
+ if (parent->type == CONTENT_HTML) {
+ assert(parent->data.html.dict != NULL);
-void css_atimport(struct content *c, struct css_node *node)
-{
- const char *s;
- char *t, *url, *url1;
- bool string = false, screen = true;
- unsigned int i;
- struct content **import_content;
- url_func_result res;
+ if (c == parent->data.html.
+ stylesheet_content[STYLESHEET_BASE] ||
+ c == parent->data.html.
+ stylesheet_content[STYLESHEET_QUIRKS] ||
+ c == parent->data.html.
+ stylesheet_content[STYLESHEET_ADBLOCK])
+ origin = CSS_ORIGIN_UA;
- LOG(("@import rule"));
+ /** \todo media types */
- import_content = realloc(c->data.css.import_content,
- (c->data.css.import_count + 1) *
- sizeof(*c->data.css.import_content));
- if (!import_content) {
- /** \todo report to user */
- return;
- }
- c->data.css.import_content = import_content;
+ quirks = (parent->data.html.quirks !=
+ BINDING_QUIRKS_MODE_NONE);
- /* uri(...) or "..." */
- switch (node->type) {
- case CSS_NODE_URI:
- LOG(("URI '%.*s'", node->data_length, node->data));
- for (s = node->data + 4;
- *s == ' ' || *s == '\t' || *s == '\r' ||
- *s == '\n' || *s == '\f';
- s++)
- ;
- if (*s == '\'' || *s == '"') {
- string = true;
- s++;
- }
- url = strndup(s, node->data_length - (s - node->data));
- if (!url) {
- /** \todo report to user */
- return;
- }
- for (t = url + strlen(url) - 2;
- *t == ' ' || *t == '\t' || *t == '\r' ||
- *t == '\n' || *t == '\f';
- t--)
- ;
- if (string)
- *t = 0;
- else
- *(t + 1) = 0;
- break;
- case CSS_NODE_STRING:
- LOG(("STRING '%.*s'", node->data_length, node->data));
- url = strndup(node->data, node->data_length);
- if (!url) {
- /** \todo report to user */
- return;
- }
- break;
- default:
- return;
- }
+ dict = parent->data.html.dict;
+ } else {
+ assert(parent->data.css.sheet != NULL);
+ assert(parent->data.css.dict != NULL);
- /* media not specified, 'screen', or 'all' */
- for (node = node->next; node != 0; node = node->next) {
- screen = false;
- if (node->type != CSS_NODE_IDENT) {
- free(url);
- return;
- }
- LOG(("medium '%s'", node->data));
- if ((node->data_length == 6 &&
- strncmp(node->data, "screen", 6) == 0) ||
- (node->data_length == 3 &&
- strncmp(node->data, "all", 3) == 0)) {
- screen = true;
- break;
- }
- node = node->next;
- if (node == 0 || node->type != CSS_NODE_COMMA) {
- free(url);
- return;
- }
- }
- if (!screen) {
- free(url);
- return;
- }
-
- /* Make URL absolute */
- res = url_join(url, c->url, &url1);
- if (res != URL_FUNC_OK) {
- free(url);
- return;
- }
-
- /* Destroy raw url data */
- free(url);
-
- /* URL must be normalized */
- res = url_normalize(url1, &url);
- if (res != URL_FUNC_OK) {
- free(url1);
- return;
- }
-
- /* Destroy non-normalized data */
- free(url1);
-
- /* start the fetch */
- c->data.css.import_count++;
- i = c->data.css.import_count - 1;
- c->data.css.import_content[i] = fetchcache(url,
- css_atimport_callback, (intptr_t) c, i,
- c->width, c->height, true, 0, 0, false, false);
- if (c->data.css.import_content[i]) {
- c->active++;
- fetchcache_go(c->data.css.import_content[i], c->url,
- css_atimport_callback, (intptr_t) c, i,
- c->width, c->height,
- 0, 0, false, c);
- }
-
- free(url);
-}
-
-
-/**
- * Fetchcache callback for imported stylesheets.
- */
-
-void css_atimport_callback(content_msg msg, struct content *css,
- intptr_t p1, intptr_t p2, union content_msg_data data)
-{
- struct content *c = (struct content *) p1;
- unsigned int i = p2;
-
- switch (msg) {
- case CONTENT_MSG_LOADING:
- if (css->type != CONTENT_CSS) {
- content_remove_user(css, css_atimport_callback,
- (intptr_t) c, i);
- if (!css->user_list->next) {
- /* We were only user and we don't
- * want this content, so stop it
- * fetching and mark it as having
- * an error so it gets removed from
- * the cache next time
- * content_clean() gets called */
- fetch_abort(css->fetch);
- css->fetch = 0;
- css->status = CONTENT_STATUS_ERROR;
- }
- c->data.css.import_content[i] = 0;
- c->active--;
- content_add_error(c, "NotCSS", 0);
- }
- break;
-
- case CONTENT_MSG_READY:
- break;
-
- case CONTENT_MSG_DONE:
- LOG(("got imported stylesheet '%s'", css->url));
- /*css_dump_stylesheet(css->data.css);*/
- c->active--;
- break;
-
- case CONTENT_MSG_AUTH:
- case CONTENT_MSG_SSL:
- /* todo: handle AUTH and SSL */
- case CONTENT_MSG_LAUNCH:
- /* Fall through */
- case CONTENT_MSG_ERROR:
- /* The stylesheet we were fetching may have been
- * redirected, in that case, the object pointers
- * will differ, so ensure that the object that's
- * in error is still in use by us before invalidating
- * the pointer */
- if (c->data.css.import_content[i] == css) {
- c->data.css.import_content[i] = 0;
- c->active--;
- content_add_error(c, "?", 0);
- }
- break;
-
- case CONTENT_MSG_STATUS:
- break;
-
- case CONTENT_MSG_NEWPTR:
- c->data.css.import_content[i] = css;
- break;
-
- default:
- assert(0);
- }
-}
-
-
-/**
- * Prepare a working stylesheet with pre-sorted lists of selectors from an
- * array of stylesheets.
- *
- * \param stylesheet_content array of contents of type CONTENT_CSS (each may
- * be 0)
- * \param stylesheet_count number of entries in css
- * \return working stylesheet, or 0 on memory exhaustion
- *
- * See CSS 2.1 6.4.
- */
-
-struct css_working_stylesheet *css_make_working_stylesheet(
- struct content **stylesheet_content,
- unsigned int stylesheet_count)
-{
- struct content **css = 0;
- unsigned int css_count = 0;
- struct css_working_stylesheet *working_stylesheet;
- unsigned int chain;
- struct css_selector **rule_scratch;
-
- working_stylesheet = talloc(0, struct css_working_stylesheet);
- if (!working_stylesheet)
- return 0;
+ error = css_stylesheet_get_origin(
+ parent->data.css.sheet, &origin);
+ if (error != CSS_OK)
+ return false;
- /* make a complete list of stylesheets involved by walking @imports */
- css_working_list_imports(stylesheet_content, stylesheet_count,
- &css, &css_count);
+ error = css_stylesheet_quirks_allowed(
+ parent->data.css.sheet, &quirks);
+ if (error != CSS_OK)
+ return false;
- rule_scratch = talloc_array(working_stylesheet, struct css_selector *,
- css_count);
- if (!rule_scratch) {
- free(css);
- talloc_free(working_stylesheet);
- return 0;
- }
+ /** \todo media types */
- /* merge the corresponding sorted hash chains from each stylesheet */
- for (chain = 0; chain != HASH_SIZE; chain++) {
- if (!css_working_merge_chains(working_stylesheet, css,
- css_count, chain, rule_scratch)) {
- free(css);
- talloc_free(working_stylesheet);
- return 0;
+ dict = parent->data.css.dict;
}
}
- free(css);
- talloc_free(rule_scratch);
-
-#ifdef DEBUG_WORKING_STYLESHEET
- css_dump_working_stylesheet(working_stylesheet);
-#endif
-
- return working_stylesheet;
-}
-
-
-/**
- * Recursively make a list of stylesheets and their imports.
- *
- * \param import array of contents of type CONTENT_CSS
- * \param import_count number of elements in import
- * \param css pointer to array of contents for result
- * \param css_count number of elements used so far in *css
- */
+ if (dict == NULL) {
+ lwc_error lerror = lwc_create_context(myrealloc, NULL, &dict);
-bool css_working_list_imports(struct content **import,
- unsigned int import_count,
- struct content ***css, unsigned int *css_count)
-{
- unsigned int i, j;
- struct content **css2;
- for (i = 0; i != import_count; i++) {
- if (!import[i])
- continue;
- /* search for import[i] in css[0..css_count) */
- for (j = 0; j != *css_count && (*css)[j] != import[i]; j++)
- ;
- if (j != *css_count)
- /* we've seen this stylesheet already */
- continue;
- /* recurse into imports of import[i] */
- if (!css_working_list_imports(import[i]->data.css.
- import_content,
- import[i]->data.css.import_count,
- css, css_count))
+ if (lerror != lwc_error_ok)
return false;
- css2 = realloc(*css, sizeof *css * (*css_count + 1));
- if (!css2)
- return false;
- *css = css2;
- (*css)[*css_count] = import[i];
- (*css_count)++;
}
- return true;
-}
-
-
-/**
- * Merge hash chains of rules into an array of pointers ordered by specificity.
- *
- * \param working_stylesheet working stylesheet to add array to
- * \param css array of contents of type CONTENT_CSS
- * \param css_count number of elements in css
- * \param chain hash chain index to merge
- * \param rule scratch array of css_selector with css_count entries
- * \return true on success, false if memory exhausted
- */
-bool css_working_merge_chains(struct css_working_stylesheet *working_stylesheet,
- struct content **css, unsigned int css_count,
- unsigned int chain,
- struct css_selector **rule)
-{
- unsigned int sheet, rules, rules_done = 0;
- struct css_selector *selector;
- unsigned int best = 0;
- unsigned long min;
-
- /* count total rules */
- rules = 0;
- for (sheet = 0; sheet != css_count; sheet++)
- for (selector = css[sheet]->data.css.css->rule[chain];
- selector;
- selector = selector->next)
- rules++;
- working_stylesheet->rule[chain] = talloc_array(working_stylesheet,
- struct css_selector *, rules + 1);
- if (!working_stylesheet->rule[chain])
+ c->data.css.dict = lwc_context_ref(dict);
+ c->data.css.import_count = 0;
+ c->data.css.imports = NULL;
+
+ error = css_stylesheet_create(CSS_LEVEL_21, NULL,
+ c->url, NULL, origin, media, quirks, false,
+ c->data.css.dict,
+ myrealloc, NULL,
+ nscss_resolve_url, NULL,
+ &c->data.css.sheet);
+ if (error != CSS_OK) {
+ lwc_context_unref(c->data.css.dict);
+ c->data.css.dict = NULL;
return false;
-
- /* mergesort by specificity (increasing) */
- for (sheet = 0; sheet != css_count; sheet++) {
- rule[sheet] = 0;
- rule[sheet] = css[sheet]->data.css.css->rule[chain];
}
- for (; rules_done != rules; rules_done++) {
- /* find rule with lowest specificity */
- min = ULONG_MAX;
- for (sheet = 0; sheet != css_count; sheet++) {
- if (rule[sheet] && rule[sheet]->specificity < min) {
- min = rule[sheet]->specificity;
- best = sheet;
- }
- }
- assert(min != ULONG_MAX);
- working_stylesheet->rule[chain][rules_done] = rule[best];
- rule[best] = rule[best]->next;
- }
- assert(rules_done == rules);
- working_stylesheet->rule[chain][rules] = 0;
return true;
}
-
/**
- * Find the style which applies to an element.
- *
- * \param working_stylesheet working stylesheet
- * \param element element in xml tree to match
- * \param style style to update
- * \pram author updated to indicate properties with author level css
- * importance
+ * Process CSS source data
*
- * The style is updated with any rules that match the element.
+ * \param c Content structure
+ * \param data Data to process
+ * \param size Number of bytes to process
+ * \return true on success, false on failure
*/
-
-void css_get_style(struct css_working_stylesheet *working_stylesheet,
- xmlNode *element, struct css_style *style,
- struct css_importance *author)
+bool nscss_process_data(struct content *c, char *data, unsigned int size)
{
- unsigned int hash, rule_0 = 0, rule_h = 0;
- struct css_selector *rule;
- css_importance_reset(author); /* initialise to sub-author level */
-
- hash = css_hash((const char *) element->name,
- strlen((const char *) element->name));
+ css_error error;
- /* merge sort rules from special hash chain 0 (universal selector) and
- * rules from hash chain for element name */
- while (working_stylesheet->rule[0] &&
- working_stylesheet->rule[0][rule_0] &&
- working_stylesheet->rule[hash] &&
- working_stylesheet->rule[hash][rule_h]) {
- if (working_stylesheet->rule[0][rule_0]->specificity <
- working_stylesheet->rule[hash][rule_h]->
- specificity) {
- rule = working_stylesheet->rule[0][rule_0];
- rule_0++;
- } else {
- rule = working_stylesheet->rule[hash][rule_h];
- rule_h++;
- }
- if (css_match_rule(rule, element))
- css_merge(style, rule->style, rule->specificity,
- author);
- }
-
- /* remaining rules from hash chain 0 */
- while (working_stylesheet->rule[0] &&
- working_stylesheet->rule[0][rule_0]) {
- rule = working_stylesheet->rule[0][rule_0];
- rule_0++;
- if (css_match_rule(rule, element))
- css_merge(style, rule->style, rule->specificity,
- author);
- }
+ error = css_stylesheet_append_data(c->data.css.sheet,
+ (const uint8_t *) data, size);
- /* remaining rules from hash chain for element name */
- while (working_stylesheet->rule[hash] &&
- working_stylesheet->rule[hash][rule_h]) {
- rule = working_stylesheet->rule[hash][rule_h];
- rule_h++;
- if (css_match_rule(rule, element))
- css_merge(style, rule->style, rule->specificity,
- author);
- }
+ return (error == CSS_OK || error == CSS_NEEDDATA);
}
-
/**
- * Determine if a rule applies to an element.
- */
-
-bool css_match_rule(struct css_selector *rule, xmlNode *element)
-{
- struct css_selector *detail;
- xmlNode *anc, *prev;
-
- assert(element->type == XML_ELEMENT_NODE);
-
- if (rule->data && (rule->data_length !=
- strlen((const char *) element->name) ||
- strncasecmp(rule->data, (const char *) element->name,
- rule->data_length) != 0))
- return false;
-
- for (detail = rule->detail; detail; detail = detail->next) {
- if (!css_match_detail(detail, element))
- return false;
- }
-
- if (!rule->combiner)
- return true;
-
- switch (rule->comb) {
- case CSS_COMB_ANCESTOR:
- for (anc = element->parent; anc; anc = anc->parent)
- if (anc->type == XML_ELEMENT_NODE &&
- css_match_rule(rule->combiner, anc))
- return true;
- break;
-
- case CSS_COMB_PRECEDED:
- for (prev = element->prev;
- prev && prev->type != XML_ELEMENT_NODE;
- prev = prev->prev)
- ;
- if (!prev)
- return false;
- return css_match_rule(rule->combiner, prev);
- break;
-
- case CSS_COMB_PARENT:
- for (anc = element->parent;
- anc && anc->type != XML_ELEMENT_NODE;
- anc = anc->parent)
- ;
- if (!anc)
- return false;
- return css_match_rule(rule->combiner, anc);
- break;
-
- default:
- assert(0);
- }
-
- return false;
-}
-
-
-/**
- * Determine if a selector detail matches an element.
+ * Convert a CSS content ready for use
*
- * \param detail a css_selector of type other than CSS_SELECTOR_ELEMENT
- * \param element element in xml tree to match
- * \return true if the selector matches the element
+ * \param c Content to convert
+ * \param w Width of area content will be displayed in
+ * \param h Height of area content will be displayed in
+ * \return true on success, false on failure
*/
-
-bool css_match_detail(const struct css_selector *detail,
- xmlNode *element)
+bool nscss_convert(struct content *c, int w, int h)
{
- bool match = false;
- char *s = 0;
- char *space, *word;
- size_t length;
-
- switch (detail->type) {
- case CSS_SELECTOR_ID:
- s = (char *) xmlGetProp(element,
- (const xmlChar *) "id");
- /* case sensitive, according to HTML4.01 */
- if (s && strlen(s) == detail->data_length &&
- strncmp(detail->data, s,
- detail->data_length) == 0)
- match = true;
- break;
-
- case CSS_SELECTOR_CLASS:
- s = (char *) xmlGetProp(element,
- (const xmlChar *) "class");
- if (!s)
- break;
- word = s;
- do {
- space = strchr(word, ' ');
- if (space)
- length = space - word;
- else
- length = strlen(word);
- /* case sensitive, according to HTML4.01 */
- if (length == detail->data_length &&
- strncmp(word, detail->data,
- length) == 0) {
- match = true;
- break;
- }
- word = space + 1;
- } while (space);
- break;
-
- case CSS_SELECTOR_ATTRIB:
- /* matches if an attribute is present */
- word = strndup(detail->data, detail->data_length);
- if (!word) {
- /** \todo report to user */
- return false;
- }
- s = (char *) xmlGetProp(element,
- (const xmlChar *) word);
- free(word);
- if (s)
- match = true;
- break;
-
- case CSS_SELECTOR_ATTRIB_EQ:
- /* matches if an attribute has a certain value*/
- word = strndup(detail->data, detail->data_length);
- if (!word) {
- /** \todo report to user */
- return false;
- }
- s = (char *) xmlGetProp(element,
- (const xmlChar *) word);
- free(word);
- if (s && strlen(s) == detail->data2_length &&
- strncasecmp(detail->data2, s,
- detail->data2_length) == 0)
- match = true;
- break;
+ css_error error;
- case CSS_SELECTOR_ATTRIB_INC:
- /* matches if one of the space separated words
- * in the attribute is equal */
- word = strndup(detail->data,
- detail->data_length);
- if (!word) {
- /** \todo report to user */
- return false;
- }
- s = (char *) xmlGetProp(element,
- (const xmlChar *) word);
- free(word);
- if (!s)
- break;
- word = s;
- do {
- space = strchr(word, ' ');
- if (space)
- length = space - word;
- else
- length = strlen(word);
- if (length == detail->data2_length &&
- strncasecmp(word, detail->data2,
- length) == 0) {
- match = true;
- break;
- }
- word = space + 1;
- } while (space);
- break;
-
- case CSS_SELECTOR_ATTRIB_DM:
- /* matches if a prefix up to a hyphen matches */
- word = strndup(detail->data,
- detail->data_length);
- if (!word) {
- /** \todo report to user */
- return false;
- }
- s = (char *) xmlGetProp(element,
- (const xmlChar *) word);
- free(word);
- if (!s)
- break;
- length = detail->data2_length;
- if (strncasecmp(detail->data2, s, length) == 0 &&
- (s[length] == '-' || s[length] == 0))
- match = true;
- break;
-
- case CSS_SELECTOR_ATTRIB_PRE:
- /* matches if the attribute begins with a certain
- * value (CSS3) */
- word = strndup(detail->data, detail->data_length);
- if (!word) {
- /** \todo report to user */
- return false;
- }
- s = (char *)xmlGetProp(element,
- (const xmlChar *) word);
- free(word);
- if (s && strncasecmp(detail->data2, s,
- detail->data2_length) == 0)
- match = true;
- break;
+ error = css_stylesheet_data_done(c->data.css.sheet);
- case CSS_SELECTOR_ATTRIB_SUF:
- /* matches if the attribute ends with a certain
- * value (CSS3) */
- word = strndup(detail->data, detail->data_length);
- if (!word) {
- /** \todo report to user */
- return false;
- }
- s = (char *)xmlGetProp(element,
- (const xmlChar *) word);
- free(word);
- if (!s)
- break;
- length = strlen(s);
- if (detail->data2_length <= length) {
- word = s + (length - detail->data2_length);
- if (s && strncasecmp(detail->data2, word,
- detail->data2_length) == 0)
- match = true;
- }
- break;
-
- case CSS_SELECTOR_ATTRIB_SUB:
- /* matches if the attribute contains a certain
- * value (CSS3) */
- word = strndup(detail->data, detail->data_length);
- if (!word) {
- /** \todo report to user */
- return false;
- }
- s = (char *)xmlGetProp(element,
- (const xmlChar *) word);
- free(word);
- if (!s)
- break;
- /* case insensitive strstr follows */
- /* space -> last possible start position */
- /* word -> start of string to search */
- space = s + (strlen(s) - detail->data2_length);
- word = s;
- while (word <= space) {
- if (strncasecmp(detail->data2, word,
- detail->data2_length) == 0) {
- match = true;
- break;
- }
- word++;
- }
- break;
-
- case CSS_SELECTOR_PSEUDO:
- if (detail->data_length == 11 &&
- strncasecmp(detail->data,
- "first-child", 11) == 0) {
- match = css_match_first_child(detail,
- element);
- }
- break;
-
- default:
- assert(0);
- }
-
- if (s)
- xmlFree(s);
-
- return match;
-}
-
-
-/**
- * Handle :first-child pseudo-class.
- *
- * \param detail a css_selector of type other than CSS_SELECTOR_ELEMENT
- * \param element element in xml tree to match
- * \return true if the selector matches the element
- */
-
-bool css_match_first_child(const struct css_selector *detail,
- xmlNode *element)
-{
- xmlNode *prev;
-
- for (prev = element->prev; prev && prev->type != XML_ELEMENT_NODE;
- prev = prev->prev)
- ;
-
- if (!prev)
- return true;
-
- return false;
-}
-
-
-/**
- * Parse a stand-alone CSS property list.
- *
- * \param c parent content
- * \param style css_style to update
- * \param str property list, as found in HTML style attributes
- */
-
-void css_parse_property_list(struct content *c, struct css_style * style,
- char * str)
-{
- unsigned char *source_data;
- unsigned char *current, *end, *token_text;
- size_t length;
- unsigned int i;
- int token;
- void *parser;
- struct css_parser_params param = {true, c, 0, false, false, false};
- struct css_parser_token token_data;
- const struct css_parser_token token_start = { "{", 1 };
- const struct css_parser_token token_end = { "}", 1 };
-
- length = strlen(str);
-
- parser = css_parser_Alloc(malloc);
- source_data = malloc(length + 10);
-
- if (!parser || !source_data) {
- free(parser);
- css_parser_Free(parser, free);
- return;
- }
-
- strcpy((char *) source_data, str);
- for (i = 0; i != 10; i++)
- source_data[length + i] = 0;
-
- css_parser_(parser, LBRACE, token_start, &param);
-
- current = source_data;
- end = source_data + strlen(str);
- while (current < end
- && (token = css_tokenise(&current, end + 10,
- &token_text))) {
- token_data.text = (char *) token_text;
- token_data.length = current - token_text;
- css_parser_(parser, token, token_data, &param);
- if (param.syntax_error) {
- LOG(("syntax error near offset %li",
- (unsigned long) (token_text - source_data)));
- param.syntax_error = false;
- } else if (param.memory_error) {
- LOG(("out of memory"));
- break;
- }
- }
- css_parser_(parser, RBRACE, token_end, &param);
- css_parser_(parser, 0, token_data, &param);
-
- css_parser_Free(parser, free);
-
- if (param.memory_error) {
- css_free_node(param.declaration);
- return;
- }
-
- css_add_declarations(style, param.declaration);
-
- css_free_node(param.declaration);
-
- free(source_data);
-}
-
-
-/**
- * Dump a css_style to stderr in CSS-like syntax.
- */
-
-void css_dump_style(FILE *stream, const struct css_style * const style)
-{
- unsigned int i;
- fprintf(stream, "{ ");
-
-#define DUMP_COLOR(z, s) \
- if (style->z != CSS_COLOR_NOT_SET) { \
- if (style->z == NS_TRANSPARENT) \
- fprintf(stream, s ": transparent; "); \
- else if (style->z == CSS_COLOR_NONE) \
- fprintf(stream, s ": none; "); \
- else \
- fprintf(stream, s ": #%.6x; ", style->z); \
- }
-
-#define DUMP_KEYWORD(z, s, n) \
- if (style->z != css_empty_style.z) \
- fprintf(stream, s ": %s; ", n[style->z]);
-
- DUMP_COLOR(background_color, "background-color");
- if (style->background_attachment !=
- css_empty_style.background_attachment ||
- style->background_image.type !=
- css_empty_style.background_image.type ||
- style->background_position.horz.pos !=
- css_empty_style.background_position.horz.pos ||
- style->background_position.vert.pos !=
- css_empty_style.background_position.vert.pos ||
- style->background_repeat !=
- css_empty_style.background_repeat) {
- fprintf(stream, "background:");
- switch (style->background_image.type) {
- case CSS_BACKGROUND_IMAGE_NONE:
- fprintf(stream, " none");
- break;
- case CSS_BACKGROUND_IMAGE_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_BACKGROUND_IMAGE_URI:
- fprintf(stream, " (%p) \"%s\"",
- style->background_image.uri,
- style->background_image.uri);
- break;
- case CSS_BACKGROUND_IMAGE_NOT_SET:
- ;
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
- }
-
- if (style->background_repeat ==
- CSS_BACKGROUND_REPEAT_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->background_repeat ==
- CSS_BACKGROUND_REPEAT_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_background_repeat_name[
- style->background_repeat]);
-
- if (style->background_attachment ==
- CSS_BACKGROUND_ATTACHMENT_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->background_attachment == CSS_BACKGROUND_ATTACHMENT_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_background_attachment_name[
- style->background_attachment]);
-
- switch (style->background_position.horz.pos) {
- case CSS_BACKGROUND_POSITION_LENGTH:
- fprintf(stream, " ");
- css_dump_length(stream, &style->background_position.
- horz.value.length);
- break;
- case CSS_BACKGROUND_POSITION_PERCENT:
- fprintf(stream, " %g%%",
- style->background_position.
- horz.value.percent);
- break;
- case CSS_BACKGROUND_POSITION_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_BACKGROUND_POSITION_NOT_SET:
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
- }
- switch (style->background_position.vert.pos) {
- case CSS_BACKGROUND_POSITION_LENGTH:
- fprintf(stream, " ");
- css_dump_length(stream, &style->background_position.
- vert.value.length);
- break;
- case CSS_BACKGROUND_POSITION_PERCENT:
- fprintf(stream, " %g%%",
- style->background_position.
- vert.value.percent);
- break;
- case CSS_BACKGROUND_POSITION_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_BACKGROUND_POSITION_NOT_SET:
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
- for (i = 0; i != 4; i++) {
- if (style->border[i].color != CSS_COLOR_NOT_SET ||
- style->border[i].width.width !=
- CSS_BORDER_WIDTH_NOT_SET ||
- style->border[i].style !=
- CSS_BORDER_STYLE_NOT_SET) {
- fprintf(stream, "border-");
- switch (i) {
- case TOP:
- fprintf(stream, "top:");
- break;
- case RIGHT:
- fprintf(stream, "right:");
- break;
- case BOTTOM:
- fprintf(stream, "bottom:");
- break;
- case LEFT:
- fprintf(stream, "left:");
- break;
- }
- switch (style->border[i].width.width) {
- case CSS_BORDER_WIDTH_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_BORDER_WIDTH_LENGTH:
- fprintf(stream, " ");
- css_dump_length(stream,
- &style->border[i].width.value);
- break;
- case CSS_BORDER_WIDTH_NOT_SET:
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
- }
-
- if (style->border[i].style ==
- CSS_BORDER_STYLE_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->border[i].style ==
- CSS_BORDER_STYLE_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_border_style_name[
- style->border[i].style]);
-
- if (style->border[i].color == NS_TRANSPARENT)
- fprintf(stream, " transparent");
- else if (style->border[i].color == CSS_COLOR_NONE)
- fprintf(stream, " none");
- else if (style->border[i].color == CSS_COLOR_INHERIT)
- fprintf(stream, " inherit");
- else if (style->border[i].color == CSS_COLOR_NOT_SET)
- ;
- else
- fprintf(stream, " #%.6x",
- style->border[i].color);
- fprintf(stream, "; ");
- }
- }
- DUMP_KEYWORD(border_collapse, "border-collapse",
- css_border_collapse_name);
- if (style->border_spacing.border_spacing !=
- CSS_BORDER_SPACING_NOT_SET) {
- fprintf(stream, "border-spacing: ");
- css_dump_length(stream, &style->border_spacing.horz);
- fprintf(stream, " ");
- css_dump_length(stream, &style->border_spacing.vert);
- fprintf(stream, "; ");
- }
-
- DUMP_KEYWORD(caption_side, "caption-side", css_caption_side_name);
- DUMP_KEYWORD(clear, "clear", css_clear_name);
-
- if (style->clip.clip != CSS_CLIP_NOT_SET) {
- fprintf(stream, "clip: ");
- switch (style->clip.clip) {
- case CSS_CLIP_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_CLIP_AUTO:
- fprintf(stream, "auto");
- break;
- case CSS_CLIP_RECT:
- fprintf(stream, "rect(");
- for (i = 0; i != 4; i++) {
- switch (style->clip.rect[i].rect) {
- case CSS_CLIP_RECT_AUTO:
- fprintf(stream, "auto");
- break;
- case CSS_CLIP_RECT_LENGTH:
- css_dump_length(stream,
- &style->clip.rect[i].value);
- break;
- }
- if (i != 3)
- fprintf(stream, ", ");
- }
- fprintf(stream, ")");
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
- DUMP_COLOR(color, "color");
- DUMP_KEYWORD(cursor, "cursor", css_cursor_name);
- DUMP_KEYWORD(direction, "direction", css_direction_name);
- DUMP_KEYWORD(display, "display", css_display_name);
- DUMP_KEYWORD(empty_cells, "empty-cells", css_empty_cells_name);
- DUMP_KEYWORD(float_, "float", css_float_name);
-
- if (style->font_style != CSS_FONT_STYLE_NOT_SET ||
- style->font_weight != CSS_FONT_WEIGHT_NOT_SET ||
- style->font_size.size != CSS_FONT_SIZE_NOT_SET ||
- style->line_height.size != CSS_LINE_HEIGHT_NOT_SET ||
- style->font_family != CSS_FONT_FAMILY_NOT_SET ||
- style->font_variant != CSS_FONT_VARIANT_NOT_SET) {
- fprintf(stream, "font:");
-
- if (style->font_style == CSS_FONT_STYLE_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->font_style == CSS_FONT_STYLE_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_font_style_name[style->font_style]);
-
- if (style->font_weight == CSS_FONT_WEIGHT_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->font_weight == CSS_FONT_WEIGHT_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_font_weight_name[style->font_weight]);
-
- switch (style->font_size.size) {
- case CSS_FONT_SIZE_ABSOLUTE:
- fprintf(stream, " [%g]",
- style->font_size.value.absolute);
- break;
- case CSS_FONT_SIZE_LENGTH:
- fprintf(stream, " ");
- css_dump_length(stream, &style->font_size.value.length);
- break;
- case CSS_FONT_SIZE_PERCENT:
- fprintf(stream, " %g%%",
- style->font_size.value.percent);
- break;
- case CSS_FONT_SIZE_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_FONT_SIZE_NOT_SET:
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
- }
- switch (style->line_height.size) {
- case CSS_LINE_HEIGHT_ABSOLUTE:
- fprintf(stream, "/[%g]",
- style->line_height.value.absolute);
- break;
- case CSS_LINE_HEIGHT_LENGTH:
- fprintf(stream, "/");
- css_dump_length(stream,
- &style->line_height.value.length);
- break;
- case CSS_LINE_HEIGHT_PERCENT:
- fprintf(stream, "/%g%%",
- style->line_height.value.percent);
- break;
- case CSS_LINE_HEIGHT_INHERIT:
- fprintf(stream, "/inherit");
- break;
- case CSS_LINE_HEIGHT_NOT_SET:
- break;
- default:
- fprintf(stream, "/UNKNOWN");
- break;
- }
- if (style->font_family == CSS_FONT_FAMILY_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->font_family == CSS_FONT_FAMILY_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_font_family_name[style->font_family]);
-
- if (style->font_variant == CSS_FONT_VARIANT_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->font_variant == CSS_FONT_VARIANT_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_font_variant_name[style->font_variant]);
- fprintf(stream, "; ");
- }
-
- if (style->height.height != CSS_HEIGHT_NOT_SET) {
- fprintf(stream, "height: ");
- switch (style->height.height) {
- case CSS_HEIGHT_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_HEIGHT_AUTO:
- fprintf(stream, "auto");
- break;
- case CSS_HEIGHT_LENGTH:
- css_dump_length(stream, &style->height.value.length);
- break;
- case CSS_HEIGHT_PERCENT:
- fprintf(stream, "%g%%",
- style->height.value.percent);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->letter_spacing.letter_spacing !=
- CSS_LETTER_SPACING_NOT_SET) {
- fprintf(stream, "letter-spacing: ");
- switch (style->letter_spacing.letter_spacing) {
- case CSS_LETTER_SPACING_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_LETTER_SPACING_NORMAL:
- fprintf(stream, "normal");
- break;
- case CSS_LETTER_SPACING_LENGTH:
- css_dump_length(stream, &style->letter_spacing.length);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->list_style_type != CSS_LIST_STYLE_TYPE_NOT_SET ||
- style->list_style_position !=
- CSS_LIST_STYLE_POSITION_NOT_SET ||
- style->list_style_image.type !=
- CSS_LIST_STYLE_IMAGE_NOT_SET) {
- fprintf(stream, "list-style:");
-
- if (style->list_style_type == CSS_LIST_STYLE_TYPE_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->list_style_type == CSS_LIST_STYLE_TYPE_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_list_style_type_name[
- style->list_style_type]);
-
- if (style->list_style_position ==
- CSS_LIST_STYLE_POSITION_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->list_style_position ==
- CSS_LIST_STYLE_POSITION_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_list_style_position_name[
- style->list_style_position]);
-
- switch (style->list_style_image.type) {
- case CSS_LIST_STYLE_IMAGE_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_LIST_STYLE_IMAGE_NONE:
- fprintf(stream, " none");
- break;
- case CSS_LIST_STYLE_IMAGE_URI:
- fprintf(stream, " url('%s')",
- style->list_style_image.uri);
- break;
- case CSS_LIST_STYLE_IMAGE_NOT_SET:
- break;
- default:
- fprintf(stream, " UNKNOWN");
- }
- fprintf(stream, "; ");
- }
-
- if (style->margin[0].margin != CSS_MARGIN_NOT_SET ||
- style->margin[1].margin != CSS_MARGIN_NOT_SET ||
- style->margin[2].margin != CSS_MARGIN_NOT_SET ||
- style->margin[3].margin != CSS_MARGIN_NOT_SET) {
- fprintf(stream, "margin:");
- for (i = 0; i != 4; i++) {
- switch (style->margin[i].margin) {
- case CSS_MARGIN_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_MARGIN_LENGTH:
- fprintf(stream, " ");
- css_dump_length(stream,
- &style->margin[i].value.length);
- break;
- case CSS_MARGIN_PERCENT:
- fprintf(stream, " %g%%",
- style->margin[i].value.percent);
- break;
- case CSS_MARGIN_AUTO:
- fprintf(stream, " auto");
- break;
- case CSS_MARGIN_NOT_SET:
- fprintf(stream, " .");
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
- }
- }
- fprintf(stream, "; ");
- }
-
- if (style->max_height.max_height != CSS_MAX_HEIGHT_NOT_SET) {
- fprintf(stream, "max-height: ");
- switch (style->max_height.max_height) {
- case CSS_MAX_HEIGHT_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_MAX_HEIGHT_NONE:
- fprintf(stream, "none");
- break;
- case CSS_MAX_HEIGHT_LENGTH:
- css_dump_length(stream,
- &style->max_height.value.length);
- break;
- case CSS_MAX_HEIGHT_PERCENT:
- fprintf(stream, "%g%%",
- style->max_height.value.percent);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->max_width.max_width != CSS_MAX_WIDTH_NOT_SET) {
- fprintf(stream, "max-width: ");
- switch (style->max_width.max_width) {
- case CSS_MAX_WIDTH_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_MAX_WIDTH_NONE:
- fprintf(stream, "none");
- break;
- case CSS_MAX_WIDTH_LENGTH:
- css_dump_length(stream, &style->max_width.value.length);
- break;
- case CSS_MAX_WIDTH_PERCENT:
- fprintf(stream, "%g%%",
- style->max_width.value.percent);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->min_height.min_height != CSS_MIN_HEIGHT_NOT_SET) {
- fprintf(stream, "min-height: ");
- switch (style->min_height.min_height) {
- case CSS_MIN_HEIGHT_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_MIN_HEIGHT_LENGTH:
- css_dump_length(stream,
- &style->min_height.value.length);
- break;
- case CSS_MIN_HEIGHT_PERCENT:
- fprintf(stream, "%g%%",
- style->min_height.value.percent);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->min_width.min_width != CSS_MIN_WIDTH_NOT_SET) {
- fprintf(stream, "min-width: ");
- switch (style->min_width.min_width) {
- case CSS_MIN_WIDTH_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_MIN_WIDTH_LENGTH:
- css_dump_length(stream, &style->min_width.value.length);
- break;
- case CSS_MIN_WIDTH_PERCENT:
- fprintf(stream, "%g%%",
- style->min_width.value.percent);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
+ /* Process pending imports */
+ while (error == CSS_IMPORTS_PENDING) {
+ struct content **imports;
+ uint32_t i;
+ lwc_string *uri;
+ uint64_t media;
+ css_stylesheet *sheet;
+ char *temp_url;
+
+ error = css_stylesheet_next_pending_import(c->data.css.sheet,
+ &uri, &media);
+ if (error != CSS_OK && error != CSS_INVALID) {
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
}
- fprintf(stream, "; ");
- }
- if (style->orphans.orphans != CSS_ORPHANS_NOT_SET) {
- fprintf(stream, "orphans: ");
- switch (style->orphans.orphans) {
- case CSS_ORPHANS_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_ORPHANS_INTEGER:
- fprintf(stream, "%d",
- style->orphans.value);
- break;
- default:
- fprintf(stream, "UNKNOWN");
+ /* Give up if there are no more imports */
+ if (error == CSS_INVALID) {
+ error = CSS_OK;
break;
}
- fprintf(stream, "; ");
- }
- if (style->outline.color.color != CSS_OUTLINE_COLOR_NOT_SET ||
- style->outline.width.width != CSS_BORDER_WIDTH_NOT_SET ||
- style->outline.style != CSS_BORDER_STYLE_NOT_SET) {
- fprintf(stream, "outline:");
- switch (style->outline.color.color) {
- case CSS_OUTLINE_COLOR_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_OUTLINE_COLOR_INVERT:
- fprintf(stream, " invert");
- break;
- case CSS_OUTLINE_COLOR_COLOR:
- if (style->outline.color.value == NS_TRANSPARENT)
- fprintf(stream, " transparent");
- else if (style->outline.color.value == CSS_COLOR_NONE)
- fprintf(stream, " none");
- else if (style->outline.color.value == CSS_COLOR_INHERIT)
- fprintf(stream, " inherit");
- else if (style->outline.color.value == CSS_COLOR_NOT_SET)
- fprintf(stream, " .");
- else
- fprintf(stream, " #%.6x", style->outline.color.value);
- break;
- case CSS_OUTLINE_COLOR_NOT_SET:
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
+ /* Copy URI and ensure it's NUL terminated */
+ temp_url = malloc(lwc_string_length(uri) + 1);
+ if (temp_url == NULL) {
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
}
+ memcpy(temp_url, lwc_string_data(uri), lwc_string_length(uri));
+ temp_url[lwc_string_length(uri)] = '\0';
- if (style->outline.style == CSS_BORDER_STYLE_UNKNOWN)
- fprintf(stream, " UNKNOWN");
- else if (style->outline.style == CSS_BORDER_STYLE_NOT_SET)
- ;
- else
- fprintf(stream, " %s",
- css_border_style_name[style->outline.style]);
-
- switch (style->outline.width.width) {
- case CSS_BORDER_WIDTH_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_BORDER_WIDTH_LENGTH:
- fprintf(stream, " ");
- css_dump_length(stream, &style->outline.width.value);
- break;
- case CSS_BORDER_WIDTH_NOT_SET:
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
+ /* Increase space in table */
+ imports = realloc(c->data.css.imports,
+ (c->data.css.import_count + 1) *
+ sizeof(struct content *));
+ if (imports == NULL) {
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
}
- fprintf(stream, "; ");
- }
-
- DUMP_KEYWORD(overflow, "overflow", css_overflow_name);
-
- if (style->padding[0].padding != CSS_PADDING_NOT_SET ||
- style->padding[1].padding != CSS_PADDING_NOT_SET ||
- style->padding[2].padding != CSS_PADDING_NOT_SET ||
- style->padding[3].padding != CSS_PADDING_NOT_SET) {
- fprintf(stream, "padding:");
- for (i = 0; i != 4; i++) {
- switch (style->padding[i].padding) {
- case CSS_PADDING_INHERIT:
- fprintf(stream, " inherit");
- break;
- case CSS_PADDING_LENGTH:
- fprintf(stream, " ");
- css_dump_length(stream,
- &style->padding[i].value.length);
- break;
- case CSS_PADDING_PERCENT:
- fprintf(stream, " %g%%",
- style->padding[i].value.percent);
- break;
- case CSS_PADDING_NOT_SET:
- fprintf(stream, " .");
- break;
- default:
- fprintf(stream, " UNKNOWN");
- break;
- }
+ c->data.css.imports = imports;
+
+ /* Create content */
+ i = c->data.css.import_count;
+ c->data.css.imports[c->data.css.import_count++] =
+ fetchcache(temp_url,
+ nscss_import, (intptr_t) c, i,
+ c->width, c->height, true, NULL, NULL,
+ false, false);
+ if (c->data.css.imports[i] == NULL) {
+ free(temp_url);
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
}
- fprintf(stream, "; ");
- }
-
- DUMP_KEYWORD(page_break_after, "page-break-after",
- css_page_break_after_name);
- DUMP_KEYWORD(page_break_before, "page-break-before",
- css_page_break_before_name);
- DUMP_KEYWORD(page_break_inside, "page-break-inside",
- css_page_break_inside_name);
- for (i = 0; i != 4; i++) {
- if (style->pos[i].pos != CSS_POS_NOT_SET) {
- switch (i) {
- case TOP:
- fprintf(stream, "top: ");
- break;
- case RIGHT:
- fprintf(stream, "right: ");
- break;
- case BOTTOM:
- fprintf(stream, "bottom: ");
- break;
- case LEFT:
- fprintf(stream, "left: ");
- break;
- }
- switch (style->pos[i].pos) {
- case CSS_POS_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_POS_AUTO:
- fprintf(stream, "auto");
- break;
- case CSS_POS_PERCENT:
- fprintf(stream, "%g%%",
- style->pos[i].value.percent);
- break;
- case CSS_POS_LENGTH:
- css_dump_length(stream,
- &style->pos[i].value.length);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
+ /* Fetch content */
+ c->active++;
+ fetchcache_go(c->data.css.imports[i], c->url,
+ nscss_import, (intptr_t) c, i,
+ c->width, c->height, NULL, NULL, false, c);
+
+ free(temp_url);
+
+ /* Wait for import to fetch + convert */
+ while (c->active > 0) {
+ fetch_poll();
+ gui_multitask();
+ }
+
+ if (c->data.css.imports[i] != NULL) {
+ sheet = c->data.css.imports[i]->data.css.sheet;
+ c->data.css.imports[i]->data.css.sheet = NULL;
+ } else {
+ error = css_stylesheet_create(CSS_LEVEL_DEFAULT,
+ NULL, "", NULL, CSS_ORIGIN_AUTHOR,
+ media, false, false, c->data.css.dict,
+ myrealloc, NULL,
+ nscss_resolve_url, NULL,
+ &sheet);
+ if (error != CSS_OK) {
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
}
- fprintf(stream, "; ");
- }
- }
- DUMP_KEYWORD(position, "position", css_position_name);
-
- DUMP_KEYWORD(table_layout, "table-layout", css_table_layout_name);
- DUMP_KEYWORD(text_align, "text-align", css_text_align_name);
-
- if (style->text_decoration != CSS_TEXT_DECORATION_NOT_SET) {
- fprintf(stream, "text-decoration:");
- if (style->text_decoration == CSS_TEXT_DECORATION_NONE)
- fprintf(stream, " none");
- if (style->text_decoration == CSS_TEXT_DECORATION_INHERIT)
- fprintf(stream, " inherit");
- if (style->text_decoration & CSS_TEXT_DECORATION_UNDERLINE)
- fprintf(stream, " underline");
- if (style->text_decoration & CSS_TEXT_DECORATION_OVERLINE)
- fprintf(stream, " overline");
- if (style->text_decoration & CSS_TEXT_DECORATION_LINE_THROUGH)
- fprintf(stream, " line-through");
- if (style->text_decoration & CSS_TEXT_DECORATION_BLINK)
- fprintf(stream, " blink");
- fprintf(stream, "; ");
- }
-
- if (style->text_indent.size != CSS_TEXT_INDENT_NOT_SET) {
- fprintf(stream, "text-indent: ");
- switch (style->text_indent.size) {
- case CSS_TEXT_INDENT_LENGTH:
- css_dump_length(stream,
- &style->text_indent.value.length);
- break;
- case CSS_TEXT_INDENT_PERCENT:
- fprintf(stream, "%g%%",
- style->text_indent.value.percent);
- break;
- case CSS_TEXT_INDENT_INHERIT:
- fprintf(stream, "inherit");
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- DUMP_KEYWORD(text_transform, "text-transform", css_text_transform_name);
-
- DUMP_KEYWORD(unicode_bidi, "unicode-bidi", css_unicode_bidi_name);
-
- if (style->vertical_align.type != CSS_VERTICAL_ALIGN_NOT_SET) {
- fprintf(stream, "vertical-align: ");
- switch (style->vertical_align.type) {
- case CSS_VERTICAL_ALIGN_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_VERTICAL_ALIGN_BASELINE:
- fprintf(stream, "baseline");
- break;
- case CSS_VERTICAL_ALIGN_SUB:
- fprintf(stream, "sub");
- break;
- case CSS_VERTICAL_ALIGN_SUPER:
- fprintf(stream, "super");
- break;
- case CSS_VERTICAL_ALIGN_TOP:
- fprintf(stream, "top");
- break;
- case CSS_VERTICAL_ALIGN_TEXT_TOP:
- fprintf(stream, "text-top");
- break;
- case CSS_VERTICAL_ALIGN_MIDDLE:
- fprintf(stream, "middle");
- break;
- case CSS_VERTICAL_ALIGN_BOTTOM:
- fprintf(stream, "bottom");
- break;
- case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
- fprintf(stream, "text-bottom");
- break;
- case CSS_VERTICAL_ALIGN_LENGTH:
- css_dump_length(stream,
- &style->vertical_align.value.length);
- break;
- case CSS_VERTICAL_ALIGN_PERCENT:
- fprintf(stream, "%g%%",
- style->vertical_align.value.percent);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- DUMP_KEYWORD(visibility, "visibility", css_visibility_name);
- DUMP_KEYWORD(white_space, "white-space", css_white_space_name);
-
- if (style->widows.widows != CSS_WIDOWS_NOT_SET) {
- fprintf(stream, "widows: ");
- switch (style->widows.widows) {
- case CSS_WIDOWS_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_WIDOWS_INTEGER:
- fprintf(stream, "%d",
- style->widows.value);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->width.width != CSS_WIDTH_NOT_SET) {
- fprintf(stream, "width: ");
- switch (style->width.width) {
- case CSS_WIDTH_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_WIDTH_AUTO:
- fprintf(stream, "auto");
- break;
- case CSS_WIDTH_LENGTH:
- css_dump_length(stream, &style->width.value.length);
- break;
- case CSS_WIDTH_PERCENT:
- fprintf(stream, "%g%%", style->width.value.percent);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->word_spacing.word_spacing != CSS_WORD_SPACING_NOT_SET) {
- fprintf(stream, "word-spacing: ");
- switch (style->word_spacing.word_spacing) {
- case CSS_WORD_SPACING_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_WORD_SPACING_NORMAL:
- fprintf(stream, "normal");
- break;
- case CSS_WORD_SPACING_LENGTH:
- css_dump_length(stream, &style->word_spacing.length);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- if (style->z_index.z_index != CSS_Z_INDEX_NOT_SET) {
- fprintf(stream, "z-index: ");
- switch (style->z_index.z_index) {
- case CSS_Z_INDEX_INHERIT:
- fprintf(stream, "inherit");
- break;
- case CSS_Z_INDEX_AUTO:
- fprintf(stream, "auto");
- break;
- case CSS_Z_INDEX_INTEGER:
- fprintf(stream, "%d",
- style->z_index.value);
- break;
- default:
- fprintf(stream, "UNKNOWN");
- break;
- }
- fprintf(stream, "; ");
- }
-
- fprintf(stream, "}");
-}
-
-
-/**
- * Dump a css_length to the given stream
- */
-
-void css_dump_length(FILE *stream, const struct css_length * const length)
-{
- if (fabs(length->value) < 0.0001)
- fprintf(stream, "0");
- else
- fprintf(stream, "%g%s", length->value,
- css_unit_name[length->unit]);
-}
-
-#ifdef DEBUG_WORKING_STYLESHEET
-/**
- * Dump a complete css_working_stylesheet to stderr in CSS syntax.
- */
-
-void css_dump_working_stylesheet(const struct css_working_stylesheet *ws)
-{
- unsigned int i, j;
-
- for (i = 0; i != HASH_SIZE; i++) {
- /*fprintf(stderr, "hash %i:\n", i);*/
- for (j = 0; ws->rule[i][j]; j++) {
- css_dump_selector(ws->rule[i][j]);
- fprintf(stderr, " <%lx> ", ws->rule[i][j]->specificity);
- css_dump_style(ws->rule[i][j]->style);
- fprintf(stderr, "\n");
- }
- }
-}
-#endif
-
-/**
- * Set all members to false
- */
-void css_importance_reset(struct css_importance *i) {
- int j;
- i->background_color = false;
- i->background_image = false;
- i->border_spacing = false;
- i->color = false;
- i->height = false;
- i->width = false;
-
- /**< top, right, bottom, left */
- for (j = 0; j < 4; j++) {
- i->border_color[j] = false;
- i->border_style[j] = false;
- i->border_width[j] = false;
- i->margin[j] = false;
- i->padding[j] = false;
- }
-}
-
-/**
- * Dump a complete css_stylesheet to stderr in CSS syntax.
- */
-
-void css_dump_stylesheet(const struct css_stylesheet * stylesheet)
-{
- unsigned int i;
- struct css_selector *r;
- for (i = 0; i != HASH_SIZE; i++) {
- /*fprintf(stderr, "hash %i:\n", i);*/
- for (r = stylesheet->rule[i]; r != 0; r = r->next) {
- css_dump_selector(r);
- fprintf(stderr, " <%lx> ", r->specificity);
- css_dump_style(stderr, r->style);
- fprintf(stderr, "\n");
- }
- }
-}
-
-
-/**
- * Dump a css_selector to stderr in CSS syntax.
- */
-
-void css_dump_selector(const struct css_selector *r)
-{
- struct css_selector *m;
-
- if (r->combiner)
- css_dump_selector(r->combiner);
-
- switch (r->comb) {
- case CSS_COMB_NONE: break;
- case CSS_COMB_ANCESTOR: fprintf(stderr, " "); break;
- case CSS_COMB_PARENT: fprintf(stderr, " > "); break;
- case CSS_COMB_PRECEDED: fprintf(stderr, " + "); break;
- }
-
- if (r->data)
- fprintf(stderr, "%.*s", r->data_length, r->data);
- else
- fprintf(stderr, "*");
-
- for (m = r->detail; m; m = m->next) {
- switch (m->type) {
- case CSS_SELECTOR_ID:
- fprintf(stderr, "#%.*s",
- m->data_length, m->data);
- break;
- case CSS_SELECTOR_CLASS:
- fprintf(stderr, ".%.*s",
- m->data_length, m->data);
- break;
- case CSS_SELECTOR_ATTRIB:
- fprintf(stderr, "[%.*s]",
- m->data_length, m->data);
- break;
- case CSS_SELECTOR_ATTRIB_EQ:
- fprintf(stderr, "[%.*s=%.*s]",
- m->data_length, m->data,
- m->data2_length, m->data2);
- break;
- case CSS_SELECTOR_ATTRIB_INC:
- fprintf(stderr, "[%.*s~=%.*s]",
- m->data_length, m->data,
- m->data2_length, m->data2);
- break;
- case CSS_SELECTOR_ATTRIB_DM:
- fprintf(stderr, "[%.*s|=%.*s]",
- m->data_length, m->data,
- m->data2_length, m->data2);
- break;
- case CSS_SELECTOR_ATTRIB_PRE:
- fprintf(stderr, "[%.*s^=%.*s]",
- m->data_length, m->data,
- m->data2_length, m->data2);
- break;
- case CSS_SELECTOR_ATTRIB_SUF:
- fprintf(stderr, "[%.*s$=%.*s]",
- m->data_length, m->data,
- m->data2_length, m->data2);
- break;
- case CSS_SELECTOR_ATTRIB_SUB:
- fprintf(stderr, "[%.*s*=%.*s]",
- m->data_length, m->data,
- m->data2_length, m->data2);
- break;
- case CSS_SELECTOR_PSEUDO:
- fprintf(stderr, ":%.*s",
- m->data_length, m->data);
- break;
- default:
- fprintf(stderr, "(unexpected detail)");
}
- }
-}
-
-/**
- * Cascade styles.
- *
- * \param style css_style to modify
- * \param apply css_style to cascade onto style
- * \param author updated to indicate which properties have greater
- * than author level CSS importance. (NULL if
- * importance isn't required.)
- *
- * Attributes which have the value 'inherit' or 'unset' in apply are
- * unchanged in style.
- * Other attributes are copied to style, calculating percentages relative to
- * style where applicable.
- */
-
-void css_cascade(struct css_style * const style,
- const struct css_style * const apply,
- struct css_importance * const author)
-{
- unsigned int i;
- float f;
-
- if (apply->background_attachment !=
- CSS_BACKGROUND_ATTACHMENT_INHERIT &&
- apply->background_attachment !=
- CSS_BACKGROUND_ATTACHMENT_NOT_SET)
- style->background_attachment = apply->background_attachment;
- if (apply->background_color != CSS_COLOR_INHERIT &&
- apply->background_color != CSS_COLOR_NOT_SET)
- style->background_color = apply->background_color;
- if (apply->background_image.type != CSS_BACKGROUND_IMAGE_INHERIT &&
- apply->background_image.type !=
- CSS_BACKGROUND_IMAGE_NOT_SET)
- style->background_image = apply->background_image;
- if (apply->background_repeat != CSS_BACKGROUND_REPEAT_INHERIT &&
- apply->background_repeat !=
- CSS_BACKGROUND_REPEAT_NOT_SET)
- style->background_repeat = apply->background_repeat;
- if (apply->border_collapse != CSS_BORDER_COLLAPSE_INHERIT &&
- apply->border_collapse != CSS_BORDER_COLLAPSE_NOT_SET)
- style->border_collapse = apply->border_collapse;
- if (apply->border_spacing.border_spacing !=
- CSS_BORDER_SPACING_INHERIT &&
- apply->border_spacing.border_spacing !=
- CSS_BORDER_SPACING_NOT_SET)
- style->border_spacing = apply->border_spacing;
- if (apply->caption_side != CSS_CAPTION_SIDE_INHERIT &&
- apply->caption_side != CSS_CAPTION_SIDE_NOT_SET)
- style->caption_side = apply->caption_side;
- if (apply->clear != CSS_CLEAR_INHERIT &&
- apply->clear != CSS_CLEAR_NOT_SET)
- style->clear = apply->clear;
- 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;
- if (apply->direction != CSS_DIRECTION_INHERIT &&
- apply->direction != CSS_DIRECTION_NOT_SET)
- style->direction = apply->direction;
- if (apply->display != CSS_DISPLAY_INHERIT &&
- apply->display != CSS_DISPLAY_NOT_SET)
- style->display = apply->display;
- if (apply->empty_cells != CSS_EMPTY_CELLS_INHERIT &&
- apply->empty_cells != CSS_EMPTY_CELLS_NOT_SET)
- style->empty_cells = apply->empty_cells;
- if (apply->float_ != CSS_FLOAT_INHERIT &&
- apply->float_ != CSS_FLOAT_NOT_SET)
- style->float_ = apply->float_;
- if (apply->font_family != CSS_FONT_FAMILY_INHERIT &&
- apply->font_family != CSS_FONT_FAMILY_NOT_SET)
- style->font_family = apply->font_family;
- if (apply->font_style != CSS_FONT_STYLE_INHERIT &&
- apply->font_style != CSS_FONT_STYLE_NOT_SET)
- style->font_style = apply->font_style;
- if (apply->font_variant != CSS_FONT_VARIANT_INHERIT &&
- apply->font_variant != CSS_FONT_VARIANT_NOT_SET)
- style->font_variant = apply->font_variant;
- if (apply->font_weight != CSS_FONT_WEIGHT_INHERIT &&
- apply->font_weight != CSS_FONT_WEIGHT_NOT_SET)
- style->font_weight = apply->font_weight;
- if (apply->height.height != CSS_HEIGHT_INHERIT &&
- apply->height.height != CSS_HEIGHT_NOT_SET)
- style->height = apply->height;
- if (apply->letter_spacing.letter_spacing !=
- CSS_LETTER_SPACING_INHERIT &&
- apply->letter_spacing.letter_spacing !=
- CSS_LETTER_SPACING_NOT_SET)
- style->letter_spacing = apply->letter_spacing;
- if (apply->line_height.size != CSS_LINE_HEIGHT_INHERIT &&
- apply->line_height.size != CSS_LINE_HEIGHT_NOT_SET)
- style->line_height = apply->line_height;
- if (apply->list_style_image.type != CSS_LIST_STYLE_IMAGE_INHERIT &&
- apply->list_style_image.type !=
- CSS_LIST_STYLE_IMAGE_NOT_SET)
- style->list_style_image = apply->list_style_image;
- if (apply->list_style_position != CSS_LIST_STYLE_POSITION_INHERIT &&
- apply->list_style_position !=
- CSS_LIST_STYLE_POSITION_NOT_SET)
- style->list_style_position = apply->list_style_position;
- if (apply->list_style_type != CSS_LIST_STYLE_TYPE_INHERIT &&
- apply->list_style_type != CSS_LIST_STYLE_TYPE_NOT_SET)
- style->list_style_type = apply->list_style_type;
- if (apply->max_height.max_height != CSS_MAX_HEIGHT_INHERIT &&
- apply->max_height.max_height != CSS_MAX_HEIGHT_NOT_SET)
- style->max_height = apply->max_height;
- if (apply->max_width.max_width != CSS_MAX_WIDTH_INHERIT &&
- apply->max_width.max_width != CSS_MAX_WIDTH_NOT_SET)
- style->max_width = apply->max_width;
- if (apply->min_height.min_height != CSS_MIN_HEIGHT_INHERIT &&
- apply->min_height.min_height != CSS_MIN_HEIGHT_NOT_SET)
- style->min_height = apply->min_height;
- if (apply->min_width.min_width != CSS_MIN_WIDTH_INHERIT &&
- apply->min_width.min_width != CSS_MIN_WIDTH_NOT_SET)
- style->min_width = apply->min_width;
- if (apply->orphans.orphans != CSS_ORPHANS_INHERIT &&
- apply->orphans.orphans != CSS_ORPHANS_NOT_SET)
- style->orphans = apply->orphans;
- if (apply->overflow != CSS_OVERFLOW_INHERIT &&
- apply->overflow != CSS_OVERFLOW_NOT_SET)
- style->overflow = apply->overflow;
- if (apply->page_break_after != CSS_PAGE_BREAK_AFTER_INHERIT &&
- apply->page_break_after !=
- CSS_PAGE_BREAK_AFTER_NOT_SET)
- style->page_break_after = apply->page_break_after;
- if (apply->page_break_before != CSS_PAGE_BREAK_BEFORE_INHERIT &&
- apply->page_break_before !=
- CSS_PAGE_BREAK_BEFORE_NOT_SET)
- style->page_break_before = apply->page_break_before;
- if (apply->page_break_inside != CSS_PAGE_BREAK_INSIDE_INHERIT &&
- apply->page_break_inside !=
- CSS_PAGE_BREAK_INSIDE_NOT_SET)
- style->page_break_inside = apply->page_break_inside;
- if (apply->position != CSS_POSITION_INHERIT &&
- apply->position != CSS_POSITION_NOT_SET)
- style->position = apply->position;
- if (apply->table_layout != CSS_TABLE_LAYOUT_INHERIT &&
- apply->table_layout != CSS_TABLE_LAYOUT_NOT_SET)
- style->table_layout = apply->table_layout;
- if (apply->text_align != CSS_TEXT_ALIGN_INHERIT &&
- apply->text_align != CSS_TEXT_ALIGN_NOT_SET)
- style->text_align = apply->text_align;
- /* text-decoration: approximate CSS 2.1 by inheriting into inline elements */
- if (apply->text_decoration != CSS_TEXT_DECORATION_INHERIT &&
- apply->text_decoration != CSS_TEXT_DECORATION_NOT_SET)
- style->text_decoration = apply->text_decoration;
- if (apply->text_indent.size != CSS_TEXT_INDENT_INHERIT &&
- apply->text_indent.size != CSS_TEXT_INDENT_NOT_SET)
- style->text_indent = apply->text_indent;
- if (apply->text_transform != CSS_TEXT_TRANSFORM_INHERIT &&
- apply->text_transform != CSS_TEXT_TRANSFORM_NOT_SET)
- style->text_transform = apply->text_transform;
- if (apply->unicode_bidi != CSS_UNICODE_BIDI_INHERIT &&
- apply->unicode_bidi != CSS_UNICODE_BIDI_NOT_SET)
- style->unicode_bidi = apply->unicode_bidi;
- if (apply->vertical_align.type != CSS_VERTICAL_ALIGN_INHERIT &&
- apply->vertical_align.type !=
- CSS_VERTICAL_ALIGN_NOT_SET)
- style->vertical_align = apply->vertical_align;
- if (apply->visibility != CSS_VISIBILITY_INHERIT &&
- apply->visibility != CSS_VISIBILITY_NOT_SET)
- style->visibility = apply->visibility;
- if (apply->white_space != CSS_WHITE_SPACE_INHERIT &&
- apply->white_space != CSS_WHITE_SPACE_NOT_SET)
- style->white_space = apply->white_space;
- if (apply->widows.widows != CSS_WIDOWS_INHERIT &&
- apply->widows.widows != CSS_WIDOWS_NOT_SET)
- style->widows = apply->widows;
- if (apply->width.width != CSS_WIDTH_INHERIT &&
- apply->width.width != CSS_WIDTH_NOT_SET)
- style->width = apply->width;
- if (apply->word_spacing.word_spacing != CSS_WORD_SPACING_INHERIT &&
- apply->word_spacing.word_spacing !=
- CSS_WORD_SPACING_NOT_SET)
- style->word_spacing = apply->word_spacing;
- if (apply->z_index.z_index != CSS_Z_INDEX_INHERIT &&
- apply->z_index.z_index != CSS_Z_INDEX_NOT_SET)
- style->z_index = apply->z_index;
-
-
- /* clip */
- if (apply->clip.clip != CSS_CLIP_INHERIT &&
- apply->clip.clip != CSS_CLIP_NOT_SET) {
- for (i = 0; i != 4; i++) {
- style->clip.rect[i] = apply->clip.rect[i];
+ error = css_stylesheet_register_import(
+ c->data.css.sheet, sheet);
+ if (error != CSS_OK) {
+ c->status = CONTENT_STATUS_ERROR;
+ return false;
}
- }
-
-
- /* background-position */
- if (apply->background_position.horz.pos !=
- CSS_BACKGROUND_POSITION_INHERIT &&
- apply->background_position.horz.pos !=
- CSS_BACKGROUND_POSITION_NOT_SET) {
- style->background_position.horz =
- apply->background_position.horz;
- }
- if (apply->background_position.vert.pos !=
- CSS_BACKGROUND_POSITION_INHERIT &&
- apply->background_position.vert.pos !=
- CSS_BACKGROUND_POSITION_NOT_SET) {
- style->background_position.vert =
- apply->background_position.vert;
- }
-
- /* font-size */
- f = apply->font_size.value.percent / 100;
- switch (apply->font_size.size) {
- case CSS_FONT_SIZE_ABSOLUTE:
- style->font_size = apply->font_size;
- break;
- case CSS_FONT_SIZE_LENGTH:
- switch (apply->font_size.value.length.unit) {
- case CSS_UNIT_EM:
- f = apply->font_size.value.length.value;
- break;
- case CSS_UNIT_EX:
- f = apply->font_size.value.length.value * 0.6 /*?*/;
- break;
- default:
- style->font_size = apply->font_size;
- }
- if ((apply->font_size.value.length.unit != CSS_UNIT_EM) &&
- (apply->font_size.value.length.unit != CSS_UNIT_EX))
- break;
- /* drop through if EM or EX */
- case CSS_FONT_SIZE_PERCENT:
- switch (style->font_size.size) {
- case CSS_FONT_SIZE_ABSOLUTE:
- style->font_size.value.absolute *= f;
- break;
- case CSS_FONT_SIZE_LENGTH:
- style->font_size.value.length.value *= f;
- break;
- default:
- die("attempting percentage of unknown font-size");
- }
- break;
- case CSS_FONT_SIZE_INHERIT:
- case CSS_FONT_SIZE_NOT_SET:
- default: /* leave unchanged */
- break;
- }
- /* outline */
- if (apply->outline.color.color != CSS_OUTLINE_COLOR_INHERIT &&
- apply->outline.color.color !=
- CSS_OUTLINE_COLOR_NOT_SET)
- style->outline.color = apply->outline.color;
- if (apply->outline.width.width != CSS_BORDER_WIDTH_INHERIT &&
- apply->outline.width.width != CSS_BORDER_WIDTH_NOT_SET)
- style->outline.width = apply->outline.width;
- if (apply->outline.style != CSS_BORDER_STYLE_INHERIT &&
- apply->outline.style != CSS_BORDER_STYLE_NOT_SET)
- style->outline.style = apply->outline.style;
-
- /* borders, margins, padding and box position */
- for (i = 0; i != 4; i++) {
- if (apply->border[i].color != CSS_COLOR_INHERIT &&
- apply->border[i].color != CSS_COLOR_NOT_SET)
- style->border[i].color = apply->border[i].color;
- if (apply->border[i].width.width !=
- CSS_BORDER_WIDTH_INHERIT &&
- apply->border[i].width.width !=
- CSS_BORDER_WIDTH_NOT_SET)
- style->border[i].width = apply->border[i].width;
- if (apply->border[i].style != CSS_BORDER_STYLE_INHERIT &&
- apply->border[i].style !=
- CSS_BORDER_STYLE_NOT_SET)
- style->border[i].style = apply->border[i].style;
-
- if (apply->margin[i].margin != CSS_MARGIN_INHERIT &&
- apply->margin[i].margin != CSS_MARGIN_NOT_SET)
- style->margin[i] = apply->margin[i];
-
- if (apply->padding[i].padding != CSS_PADDING_INHERIT &&
- apply->padding[i].padding !=
- CSS_PADDING_NOT_SET)
- style->padding[i] = apply->padding[i];
-
- if (apply->pos[i].pos != CSS_POS_INHERIT &&
- apply->pos[i].pos != CSS_POS_NOT_SET)
- style->pos[i] = apply->pos[i];
+ error = CSS_IMPORTS_PENDING;
}
- /* Set author level CSS importance (used for HTML style attribute) */
- if (author) {
- if (apply->background_color != CSS_COLOR_NOT_SET)
- author->background_color = true;
- if (apply->background_image.type !=
- CSS_BACKGROUND_IMAGE_NOT_SET)
- author->background_image = true;
- if (apply->border_spacing.border_spacing !=
- CSS_BORDER_SPACING_NOT_SET)
- author->border_spacing = true;
- if (apply->color != CSS_COLOR_NOT_SET)
- author->color = true;
- if (apply->height.height != CSS_HEIGHT_NOT_SET)
- author->height = true;
- if (apply->width.width != CSS_WIDTH_NOT_SET)
- author->width = true;
-
- for (i = 0; i != 4; i++) {
- if (apply->border[i].color != CSS_COLOR_NOT_SET)
- author->border_color[i] = true;
- if (apply->border[i].width.width !=
- CSS_BORDER_WIDTH_NOT_SET)
- author->border_width[i] = true;
- if (apply->border[i].style != CSS_BORDER_STYLE_NOT_SET)
- author->border_style[i] = true;
+ c->status = CONTENT_STATUS_DONE;
- if (apply->margin[i].margin != CSS_MARGIN_NOT_SET)
- author->margin[i] = true;
+ /* Filthy hack to stop this content being reused
+ * when whatever is using it has finished with it. */
+ c->fresh = false;
- if (apply->padding[i].padding != CSS_PADDING_NOT_SET)
- author->padding[i] = true;
- }
- }
+ return error == CSS_OK;
}
-
/**
- * Merge styles.
+ * Clean up a CSS content
*
- * \param style css_style to modify
- * \param apply css_style to merge onto style
- * \param specificity specificity of current CSS rule
- * \param author updated to indicate which properties have greater than
- * author level CSS importance
- *
- * Attributes which have the value 'unset' in apply are unchanged in style.
- * Other attributes are copied to style, overwriting it.
+ * \param c Content to clean up
*/
-
-void css_merge(struct css_style * const style,
- const struct css_style * const apply,
- const unsigned long specificity,
- struct css_importance * const author)
+void nscss_destroy(struct content *c)
{
- unsigned int i;
+ uint32_t i;
- if (apply->background_attachment != CSS_BACKGROUND_ATTACHMENT_NOT_SET)
- style->background_attachment = apply->background_attachment;
- if (apply->background_color != CSS_COLOR_NOT_SET) {
- style->background_color = apply->background_color;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->background_color = true;
- }
- if (apply->background_image.type != CSS_BACKGROUND_IMAGE_NOT_SET) {
- style->background_image = apply->background_image;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->background_image = true;
- }
- if (apply->background_repeat != CSS_BACKGROUND_REPEAT_NOT_SET)
- style->background_repeat = apply->background_repeat;
- if (apply->border_collapse != CSS_BORDER_COLLAPSE_NOT_SET)
- style->border_collapse = apply->border_collapse;
- if (apply->border_spacing.border_spacing != CSS_BORDER_SPACING_NOT_SET){
- style->border_spacing = apply->border_spacing;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->border_spacing = true;
- }
- if (apply->caption_side != CSS_CAPTION_SIDE_NOT_SET)
- style->caption_side = apply->caption_side;
- if (apply->clear != CSS_CLEAR_NOT_SET)
- style->clear = apply->clear;
- if (apply->color != CSS_COLOR_NOT_SET) {
- style->color = apply->color;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->color = true;
- }
- 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)
- style->direction = apply->direction;
- if (apply->display != CSS_DISPLAY_NOT_SET)
- style->display = apply->display;
- if (apply->empty_cells != CSS_EMPTY_CELLS_NOT_SET)
- style->empty_cells = apply->empty_cells;
- if (apply->float_ != CSS_FLOAT_NOT_SET)
- style->float_ = apply->float_;
- if (apply->font_family != CSS_FONT_FAMILY_NOT_SET)
- style->font_family = apply->font_family;
- if (apply->font_size.size != CSS_FONT_SIZE_NOT_SET)
- style->font_size = apply->font_size;
- if (apply->font_style != CSS_FONT_STYLE_NOT_SET)
- style->font_style = apply->font_style;
- if (apply->font_variant != CSS_FONT_VARIANT_NOT_SET)
- style->font_variant = apply->font_variant;
- if (apply->font_weight != CSS_FONT_WEIGHT_NOT_SET)
- style->font_weight = apply->font_weight;
- if (apply->height.height != CSS_HEIGHT_NOT_SET) {
- style->height = apply->height;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->height = true;
- }
- if (apply->letter_spacing.letter_spacing != CSS_LETTER_SPACING_NOT_SET)
- style->letter_spacing = apply->letter_spacing;
- if (apply->line_height.size != CSS_LINE_HEIGHT_NOT_SET)
- style->line_height = apply->line_height;
- if (apply->list_style_image.type != CSS_LIST_STYLE_IMAGE_NOT_SET)
- style->list_style_image = apply->list_style_image;
- if (apply->list_style_position != CSS_LIST_STYLE_POSITION_NOT_SET)
- style->list_style_position = apply->list_style_position;
- if (apply->list_style_type != CSS_LIST_STYLE_TYPE_NOT_SET)
- style->list_style_type = apply->list_style_type;
- if (apply->max_height.max_height != CSS_MAX_HEIGHT_NOT_SET)
- style->max_height = apply->max_height;
- if (apply->max_width.max_width != CSS_MAX_WIDTH_NOT_SET)
- style->max_width = apply->max_width;
- if (apply->min_height.min_height != CSS_MIN_HEIGHT_NOT_SET)
- style->min_height = apply->min_height;
- if (apply->min_width.min_width != CSS_MIN_WIDTH_NOT_SET)
- style->min_width = apply->min_width;
- if (apply->orphans.orphans != CSS_ORPHANS_NOT_SET)
- style->orphans = apply->orphans;
- if (apply->overflow != CSS_OVERFLOW_NOT_SET)
- style->overflow = apply->overflow;
- if (apply->page_break_after != CSS_PAGE_BREAK_AFTER_NOT_SET)
- style->page_break_after = apply->page_break_after;
- if (apply->page_break_before != CSS_PAGE_BREAK_BEFORE_NOT_SET)
- style->page_break_before = apply->page_break_before;
- if (apply->page_break_inside != CSS_PAGE_BREAK_INSIDE_NOT_SET)
- style->page_break_inside = apply->page_break_inside;
- if (apply->position != CSS_POSITION_NOT_SET)
- style->position = apply->position;
- if (apply->table_layout != CSS_TABLE_LAYOUT_NOT_SET)
- style->table_layout = apply->table_layout;
- if (apply->text_align != CSS_TEXT_ALIGN_NOT_SET)
- style->text_align = apply->text_align;
- /* text-decoration: approximate CSS 2.1 by inheriting into inline elements */
- if (apply->text_decoration != CSS_TEXT_DECORATION_NOT_SET)
- style->text_decoration = apply->text_decoration;
- if (apply->text_indent.size != CSS_TEXT_INDENT_NOT_SET)
- style->text_indent = apply->text_indent;
- if (apply->text_transform != CSS_TEXT_TRANSFORM_NOT_SET)
- style->text_transform = apply->text_transform;
- if (apply->unicode_bidi != CSS_UNICODE_BIDI_NOT_SET)
- style->unicode_bidi = apply->unicode_bidi;
- if (apply->vertical_align.type != CSS_VERTICAL_ALIGN_NOT_SET)
- style->vertical_align = apply->vertical_align;
- if (apply->visibility != CSS_VISIBILITY_NOT_SET)
- style->visibility = apply->visibility;
- if (apply->white_space != CSS_WHITE_SPACE_NOT_SET)
- style->white_space = apply->white_space;
- if (apply->widows.widows != CSS_WIDOWS_NOT_SET)
- style->widows = apply->widows;
- if (apply->width.width != CSS_WIDTH_NOT_SET) {
- style->width = apply->width;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->width = true;
- }
- if (apply->word_spacing.word_spacing != CSS_WORD_SPACING_NOT_SET)
- style->word_spacing = apply->word_spacing;
- if (apply->z_index.z_index != CSS_Z_INDEX_NOT_SET)
- style->z_index = apply->z_index;
-
-
- /* clip */
- if (apply->clip.clip != CSS_CLIP_NOT_SET) {
- for (i = 0; i != 4; i++) {
- style->clip.rect[i] = apply->clip.rect[i];
+ for (i = 0; i < c->data.css.import_count; i++) {
+ if (c->data.css.imports[i] != NULL) {
+ content_remove_user(c->data.css.imports[i],
+ nscss_import, (uintptr_t) c, i);
}
+ c->data.css.imports[i] = NULL;
}
- /* background-position */
- if (apply->background_position.horz.pos !=
- CSS_BACKGROUND_POSITION_NOT_SET) {
- style->background_position.horz =
- apply->background_position.horz;
- }
- if (apply->background_position.vert.pos !=
- CSS_BACKGROUND_POSITION_NOT_SET) {
- style->background_position.vert =
- apply->background_position.vert;
- }
-
- /* outline */
- if (apply->outline.color.color != CSS_OUTLINE_COLOR_NOT_SET)
- style->outline.color = apply->outline.color;
- if (apply->outline.width.width != CSS_BORDER_WIDTH_NOT_SET)
- style->outline.width = apply->outline.width;
- if (apply->outline.style != CSS_BORDER_STYLE_NOT_SET)
- style->outline.style = apply->outline.style;
+ free(c->data.css.imports);
- /* borders, margins, padding and box position */
- for (i = 0; i != 4; i++) {
- if (apply->border[i].color != CSS_COLOR_NOT_SET) {
- style->border[i].color = apply->border[i].color;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->border_color[i] = true;
- }
- if (apply->border[i].width.width != CSS_BORDER_WIDTH_NOT_SET) {
- style->border[i].width = apply->border[i].width;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->border_width[i] = true;
- }
- if (apply->border[i].style != CSS_BORDER_STYLE_NOT_SET) {
- style->border[i].style = apply->border[i].style;
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->border_style[i] = true;
- }
-
- if (apply->margin[i].margin != CSS_MARGIN_NOT_SET) {
- style->margin[i] = apply->margin[i];
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->margin[i] = true;
- }
-
- if (apply->padding[i].padding != CSS_PADDING_NOT_SET) {
- style->padding[i] = apply->padding[i];
- if (specificity >= CSS_SPECIFICITY_AUTHOR)
- author->padding[i] = true;
- }
-
- if (apply->pos[i].pos != CSS_POS_NOT_SET)
- style->pos[i] = apply->pos[i];
+ if (c->data.css.sheet != NULL) {
+ css_stylesheet_destroy(c->data.css.sheet);
+ c->data.css.sheet = NULL;
}
-}
-
-
-/**
- * Calculate a hash for an element name.
- *
- * The hash is case-insensitive.
- */
-
-unsigned int css_hash(const char *s, int length)
-{
- int i;
- unsigned int z = 0;
- if (s == 0)
- return 0;
- for (i = 0; i != length; i++)
- z += s[i] & 0x1f; /* lower 5 bits, case insensitive */
- return (z % (HASH_SIZE - 1)) + 1;
-}
-
-/**
- * Convert a struct css_length to pixels.
- *
- * \param length css_length to convert
- * \param style css_style applying to length. may be 0 if the length's
- * unit is em or ex
- * \return length in pixels
- *
- * If a length's unit is em or ex, the returned length is subject to the
- * configured option_font_min_size.
- */
-
-float css_len2px(const struct css_length *length,
- const struct css_style *style)
-{
- struct css_length font;
- font.unit = CSS_UNIT_PT;
-
- assert(!((length->unit == CSS_UNIT_EM || length->unit == CSS_UNIT_EX) &&
- style == 0));
- switch (length->unit) {
- case CSS_UNIT_EM:
- if ((font.value = css_len2pt(&style->
- font_size.value.length, style)) <
- option_font_min_size / 10) {
- /* min font size is greater than given length so
- * use min font size for conversion to px */
- font.value = option_font_min_size / 10;
- return length->value * css_len2px(&font, style);
- } else
- /* use given length for conversion to px */
- return length->value * css_len2px(&style->
- font_size.value.length, 0);
- case CSS_UNIT_EX:
- if ((font.value = css_len2pt(&style->
- font_size.value.length, style)) <
- option_font_min_size / 10) {
- /* min font size is greater than given length so
- * use min font size for conversion to px */
- font.value = option_font_min_size / 10;
- return length->value * css_len2px(&font,
- style) * 0.6;
- } else
- /* use given length for conversion to px */
- return length->value * css_len2px(&style->
- font_size.value.length, 0) *
- 0.6;
- case CSS_UNIT_PX: return length->value;
- /* We assume the screen and any other output has the same dpi */
- case CSS_UNIT_IN: return length->value * css_screen_dpi;
- case CSS_UNIT_CM: return length->value * css_screen_dpi / 2.54;
- case CSS_UNIT_MM: return length->value * css_screen_dpi / 25.4;
- /* 1pt = 1in/72 */
- case CSS_UNIT_PT: return length->value * css_screen_dpi / 72;
- /* 1pc = 1pt * 12 */
- case CSS_UNIT_PC: return length->value * css_screen_dpi / 6;
- default: break;
- }
- return 0;
-}
-
-/**
- * Convert a struct css_length to points.
- *
- * \param length css_length to convert
- * \param style css_style applying to length. may be 0 if the length's
- * unit is em or ex
- * \return length in points
- */
-
-float css_len2pt(const struct css_length *length,
- const struct css_style *style)
-{
- assert(!((length->unit == CSS_UNIT_EM || length->unit == CSS_UNIT_EX) &&
- style == 0));
- switch (length->unit) {
- case CSS_UNIT_EM:
- return length->value *
- css_len2pt(&style->font_size.value.length, 0);
- case CSS_UNIT_EX:
- return length->value *
- css_len2pt(&style->font_size.value.length, 0) *
- 0.6;
- /* We assume the screen and any other output has the same dpi */
- case CSS_UNIT_PX: return length->value * 72 / css_screen_dpi;
- /* 1pt = 1in/72 */
- case CSS_UNIT_IN: return length->value * 72;
- case CSS_UNIT_CM: return length->value * 28.452756;
- case CSS_UNIT_MM: return length->value * 2.8452756;
- case CSS_UNIT_PT: return length->value;
- /* 1pc = 1pt * 12 */
- case CSS_UNIT_PC: return length->value * 12.0;
- default: break;
+ if (c->data.css.dict != NULL) {
+ lwc_context_unref(c->data.css.dict);
+ c->data.css.dict = NULL;
}
- return 0;
}
/**
- * Return the most 'eyecatching' border.
+ * Fetchcache handler for imported stylesheets
*
- * \return the most eyecatching border, favoured towards test2
+ * \param msg Message type
+ * \param c Content being fetched
+ * \param p1 Parent content
+ * \param p2 Index into parent's imported stylesheet array
+ * \param data Message data
*/
-
-struct css_border *css_eyecatching_border(struct css_border *test1,
- struct css_style *style1, struct css_border *test2,
- struct css_style *style2)
+void nscss_import(content_msg msg, struct content *c,
+ intptr_t p1, intptr_t p2, union content_msg_data data)
{
- float width1, width2;
- int impact = 0;
-
- assert(test1);
- assert(style1);
- assert(test2);
- assert(style2);
+ struct content *parent = (struct content *) p1;
+ uint32_t i = (uint32_t) p2;
- /* hidden border styles always win, none always loses */
- if ((test1->style == CSS_BORDER_STYLE_HIDDEN) ||
- (test2->style == CSS_BORDER_STYLE_NONE))
- return test1;
- if ((test2->style == CSS_BORDER_STYLE_HIDDEN) ||
- (test1->style == CSS_BORDER_STYLE_NONE))
- return test2;
-
- /* the widest border wins */
- width1 = css_len2px(&test1->width.value, style1);
- width2 = css_len2px(&test2->width.value, style2);
- if (width1 > width2)
- return test1;
- if (width2 > width1)
- return test2;
+ switch (msg) {
+ case CONTENT_MSG_LOADING:
+ if (c->type != CONTENT_CSS) {
+ content_remove_user(c, nscss_import, p1, p2);
+ if (c->user_list->next == NULL) {
+ fetch_abort(c->fetch);
+ c->fetch = NULL;
+ c->status = CONTENT_STATUS_ERROR;
+ }
- /* the closest to a solid line wins */
- switch (test1->style) {
- case CSS_BORDER_STYLE_DOUBLE:
- impact++;
- case CSS_BORDER_STYLE_SOLID:
- impact++;
- case CSS_BORDER_STYLE_DASHED:
- impact++;
- case CSS_BORDER_STYLE_DOTTED:
- impact++;
- case CSS_BORDER_STYLE_RIDGE:
- impact++;
- case CSS_BORDER_STYLE_OUTSET:
- impact++;
- case CSS_BORDER_STYLE_GROOVE:
- impact++;
- case CSS_BORDER_STYLE_INSET:
- impact++;
- default:
- break;
+ parent->data.css.imports[i] = NULL;
+ parent->active--;
+ content_add_error(parent, "NotCSS", 0);
+ }
+ break;
+ case CONTENT_MSG_READY:
+ break;
+ case CONTENT_MSG_DONE:
+ parent->active--;
+ break;
+ case CONTENT_MSG_AUTH:
+ case CONTENT_MSG_SSL:
+ case CONTENT_MSG_LAUNCH:
+ case CONTENT_MSG_ERROR:
+ if (parent->data.css.imports[i] == c) {
+ parent->data.css.imports[i] = NULL;
+ parent->active--;
+ }
+ break;
+ case CONTENT_MSG_STATUS:
+ break;
+ case CONTENT_MSG_NEWPTR:
+ parent->data.css.imports[i] = c;
+ break;
+ default:
+ assert(0);
}
- switch (test2->style) {
- case CSS_BORDER_STYLE_DOUBLE:
- impact--;
- case CSS_BORDER_STYLE_SOLID:
- impact--;
- case CSS_BORDER_STYLE_DASHED:
- impact--;
- case CSS_BORDER_STYLE_DOTTED:
- impact--;
- case CSS_BORDER_STYLE_RIDGE:
- impact--;
- case CSS_BORDER_STYLE_OUTSET:
- impact--;
- case CSS_BORDER_STYLE_GROOVE:
- impact--;
- case CSS_BORDER_STYLE_INSET:
- impact--;
- default:
- break;
- }
- if (impact > 0)
- return test1;
- return test2;
}
-
diff --git a/css/css.h b/css/css.h
index 11aa6a195..e20d2dd9f 100644
--- a/css/css.h
+++ b/css/css.h
@@ -1,6 +1,5 @@
/*
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -17,700 +16,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * CSS handling (interface).
- *
- * This module aims to implement CSS 2.1.
- *
- * CSS stylesheets are held in a struct ::content with type CONTENT_CSS.
- * Creation and parsing should be carried out via the content_* functions.
- *
- * Styles are stored in a struct ::css_style, which can be retrieved from a
- * content using css_get_style().
- *
- * css_parse_property_list() constructs a struct ::css_style from a CSS
- * property list, as found in HTML style attributes.
- */
-
-#ifndef _NETSURF_CSS_CSS_H_
-#define _NETSURF_CSS_CSS_H_
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <libxml/HTMLparser.h>
-#include "css/css_enum.h"
-
-
-typedef uint32_t colour; /* 0xbbggrr */
-#define NS_TRANSPARENT 0x1000000
-#define CSS_COLOR_INHERIT 0x2000000
-#define CSS_COLOR_NONE 0x3000000
-#define CSS_COLOR_NOT_SET 0x4000000
-#define TOP 0
-#define RIGHT 1
-#define BOTTOM 2
-#define LEFT 3
-#define CSS_SPECIFICITY_UA 0x0000000
-#define CSS_SPECIFICITY_USER 0x1000000
-#define CSS_SPECIFICITY_AUTHOR 0x2000000
-#define CSS_SPECIFICITY_ID 0x10000
-#define CSS_SPECIFICITY_CLASS 0x100
-#define CSS_SPECIFICITY_ATTR 0x100
-#define CSS_SPECIFICITY_ELEMENT 0x1
-
-
-struct css_working_stylesheet;
-
-
-/** Representation of a CSS 2 length. */
-struct css_length {
- float value;
- css_unit unit;
-};
-
-typedef enum {
- CSS_TEXT_DECORATION_NONE = 0x0,
- CSS_TEXT_DECORATION_INHERIT = 0x1,
- CSS_TEXT_DECORATION_UNDERLINE = 0x2,
- CSS_TEXT_DECORATION_BLINK = 0x4,
- CSS_TEXT_DECORATION_LINE_THROUGH = 0x8,
- CSS_TEXT_DECORATION_OVERLINE = 0x10,
- CSS_TEXT_DECORATION_UNKNOWN = 0x1000,
- CSS_TEXT_DECORATION_NOT_SET = 0x2000
-} css_text_decoration;
-
-typedef enum {
- CSS_BACKGROUND_IMAGE_NONE,
- CSS_BACKGROUND_IMAGE_INHERIT,
- CSS_BACKGROUND_IMAGE_URI,
- CSS_BACKGROUND_IMAGE_NOT_SET
-} css_background_image_type;
-
-/** Part of struct css_style, for convenience. */
-struct css_background_position {
- enum {
- CSS_BACKGROUND_POSITION_LENGTH,
- CSS_BACKGROUND_POSITION_PERCENT,
- CSS_BACKGROUND_POSITION_INHERIT,
- CSS_BACKGROUND_POSITION_NOT_SET
- } pos;
- union {
- float percent;
- struct css_length length;
- } value;
-};
-
-struct css_border_width {
- enum { CSS_BORDER_WIDTH_INHERIT,
- CSS_BORDER_WIDTH_LENGTH,
- CSS_BORDER_WIDTH_NOT_SET } width;
- struct css_length value;
-};
-
-struct css_border {
- colour color;
- struct css_border_width width;
- css_border_style style;
-};
-
-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,
- CSS_LIST_STYLE_IMAGE_NOT_SET
-} css_list_style_image_type;
-
-typedef enum {
- CSS_OUTLINE_COLOR_INHERIT,
- CSS_OUTLINE_COLOR_COLOR,
- CSS_OUTLINE_COLOR_INVERT,
- CSS_OUTLINE_COLOR_NOT_SET
-} css_outline_color_type;
-
-typedef enum {
- CSS_VERTICAL_ALIGN_INHERIT,
- CSS_VERTICAL_ALIGN_BASELINE,
- CSS_VERTICAL_ALIGN_SUB,
- CSS_VERTICAL_ALIGN_SUPER,
- CSS_VERTICAL_ALIGN_TOP,
- CSS_VERTICAL_ALIGN_TEXT_TOP,
- CSS_VERTICAL_ALIGN_MIDDLE,
- CSS_VERTICAL_ALIGN_BOTTOM,
- CSS_VERTICAL_ALIGN_TEXT_BOTTOM,
- CSS_VERTICAL_ALIGN_LENGTH,
- CSS_VERTICAL_ALIGN_PERCENT,
- CSS_VERTICAL_ALIGN_NOT_SET
-} css_vertical_align_type;
-
-typedef enum {
- CSS_FONT_SIZE_INHERIT,
- CSS_FONT_SIZE_ABSOLUTE,
- CSS_FONT_SIZE_LENGTH,
- CSS_FONT_SIZE_PERCENT,
- CSS_FONT_SIZE_NOT_SET
-} css_font_size_type;
-
-struct css_counter_control {
- char *name;
- int value;
- struct css_counter_control *next;
-};
-
-struct css_counter {
- char *name;
- css_list_style_type style;
- 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. */
-struct css_style {
- /* background properties */
- css_background_attachment background_attachment;
- colour background_color;
- struct {
- css_background_image_type type;
- char *uri;
- } background_image;
- struct {
- struct css_background_position horz;
- struct css_background_position vert;
- } background_position;
- css_background_repeat background_repeat;
-
- /* borders */
- struct css_border border[4]; /**< top, right, bottom, left */
- css_border_collapse border_collapse;
- struct {
- enum { CSS_BORDER_SPACING_INHERIT,
- CSS_BORDER_SPACING_LENGTH,
- CSS_BORDER_SPACING_NOT_SET } border_spacing;
- struct css_length horz;
- struct css_length vert;
- } border_spacing;
-
- css_caption_side caption_side;
- css_clear clear;
-
- struct {
- enum { CSS_CLIP_INHERIT,
- CSS_CLIP_AUTO,
- CSS_CLIP_RECT,
- CSS_CLIP_NOT_SET } clip;
- struct {
- enum { CSS_CLIP_RECT_AUTO,
- CSS_CLIP_RECT_LENGTH } rect;
- struct css_length value;
- } rect[4]; /**< top, right, bottom, left */
- } clip;
-
- colour color;
-
- /* 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;
- css_display display;
- css_empty_cells empty_cells;
- css_float float_;
-
- /* font properties */
- css_font_family font_family;
- struct {
- css_font_size_type size;
- union {
- struct css_length length;
- float absolute;
- float percent;
- } value;
- } font_size;
- css_font_style font_style;
- css_font_variant font_variant;
- css_font_weight font_weight;
-
- struct {
- enum { CSS_HEIGHT_INHERIT,
- CSS_HEIGHT_AUTO,
- CSS_HEIGHT_LENGTH,
- CSS_HEIGHT_PERCENT,
- CSS_HEIGHT_NOT_SET } height;
- union {
- struct css_length length;
- float percent;
- } value;
- } height;
-
- struct {
- enum { CSS_LETTER_SPACING_INHERIT,
- CSS_LETTER_SPACING_NORMAL,
- CSS_LETTER_SPACING_LENGTH,
- CSS_LETTER_SPACING_NOT_SET } letter_spacing;
- struct css_length length;
- } letter_spacing;
-
- struct {
- enum { CSS_LINE_HEIGHT_INHERIT,
- CSS_LINE_HEIGHT_ABSOLUTE,
- CSS_LINE_HEIGHT_LENGTH,
- CSS_LINE_HEIGHT_PERCENT,
- CSS_LINE_HEIGHT_NOT_SET } size;
- union {
- float absolute;
- struct css_length length;
- float percent;
- } value;
- } line_height;
-
- /* list properties */
- struct {
- css_list_style_image_type type;
- char *uri;
- } list_style_image;
- css_list_style_position list_style_position;
- css_list_style_type list_style_type;
-
- /* margins */
- struct {
- enum { CSS_MARGIN_INHERIT,
- CSS_MARGIN_LENGTH,
- CSS_MARGIN_PERCENT,
- CSS_MARGIN_AUTO,
- CSS_MARGIN_NOT_SET } margin;
- union {
- struct css_length length;
- float percent;
- } value;
- } margin[4]; /**< top, right, bottom, left */
-
- /* min/max width/height */
- struct {
- enum { CSS_MAX_HEIGHT_INHERIT,
- CSS_MAX_HEIGHT_NONE,
- CSS_MAX_HEIGHT_LENGTH,
- CSS_MAX_HEIGHT_PERCENT,
- CSS_MAX_HEIGHT_NOT_SET } max_height;
- union {
- struct css_length length;
- float percent;
- } value;
- } max_height;
- struct {
- enum { CSS_MAX_WIDTH_INHERIT,
- CSS_MAX_WIDTH_NONE,
- CSS_MAX_WIDTH_LENGTH,
- CSS_MAX_WIDTH_PERCENT,
- CSS_MAX_WIDTH_NOT_SET } max_width;
- union {
- struct css_length length;
- float percent;
- } value;
- } max_width;
- struct {
- enum { CSS_MIN_HEIGHT_INHERIT,
- CSS_MIN_HEIGHT_LENGTH,
- CSS_MIN_HEIGHT_PERCENT,
- CSS_MIN_HEIGHT_NOT_SET } min_height;
- union {
- struct css_length length;
- float percent;
- } value;
- } min_height;
- struct {
- enum { CSS_MIN_WIDTH_INHERIT,
- CSS_MIN_WIDTH_LENGTH,
- CSS_MIN_WIDTH_PERCENT,
- CSS_MIN_WIDTH_NOT_SET } min_width;
- union {
- struct css_length length;
- float percent;
- } value;
- } min_width;
-
- struct {
- enum { CSS_ORPHANS_INHERIT,
- CSS_ORPHANS_INTEGER,
- CSS_ORPHANS_NOT_SET } orphans;
- int value;
- } orphans;
-
- struct {
- struct {
- css_outline_color_type color;
- colour value;
- } color;
- struct css_border_width width;
- css_border_style style;
- } outline;
-
- css_overflow overflow;
-
- /* padding */
- struct {
- enum { CSS_PADDING_INHERIT,
- CSS_PADDING_LENGTH,
- CSS_PADDING_PERCENT,
- CSS_PADDING_NOT_SET } padding;
- union {
- struct css_length length;
- float percent;
- } value;
- } padding[4]; /**< top, right, bottom, left */
+#ifndef netsurf_css_css_h_
+#define netsurf_css_css_h_
- css_page_break_after page_break_after;
- css_page_break_before page_break_before;
- css_page_break_inside page_break_inside;
+#include <libcss/libcss.h>
- struct {
- enum { CSS_POS_INHERIT,
- CSS_POS_AUTO,
- CSS_POS_PERCENT,
- CSS_POS_LENGTH,
- CSS_POS_NOT_SET } pos;
- union {
- struct css_length length;
- float percent;
- } value;
- } pos[4]; /**< top, right, bottom, left */
-
- css_position position;
-
- /** \todo quotes */
-
- css_table_layout table_layout;
-
- /* text properties */
- css_text_align text_align;
- css_text_decoration text_decoration;
- struct {
- enum { CSS_TEXT_INDENT_INHERIT,
- CSS_TEXT_INDENT_LENGTH,
- CSS_TEXT_INDENT_PERCENT,
- CSS_TEXT_INDENT_NOT_SET } size;
- union {
- struct css_length length;
- float percent;
- } value ;
- } text_indent;
- css_text_transform text_transform;
-
- css_unicode_bidi unicode_bidi;
-
- struct {
- css_vertical_align_type type;
- union {
- struct css_length length;
- float percent;
- } value;
- } vertical_align;
-
- css_visibility visibility;
-
- css_white_space white_space;
-
- struct {
- enum { CSS_WIDOWS_INHERIT,
- CSS_WIDOWS_INTEGER,
- CSS_WIDOWS_NOT_SET } widows;
- int value;
- } widows;
-
- struct {
- enum { CSS_WIDTH_INHERIT,
- CSS_WIDTH_AUTO,
- CSS_WIDTH_LENGTH,
- CSS_WIDTH_PERCENT,
- CSS_WIDTH_NOT_SET } width;
- union {
- struct css_length length;
- float percent;
- } value;
- } width;
-
- struct {
- enum { CSS_WORD_SPACING_INHERIT,
- CSS_WORD_SPACING_NORMAL,
- CSS_WORD_SPACING_LENGTH,
- CSS_WORD_SPACING_NOT_SET } word_spacing;
- struct css_length length;
- } word_spacing;
-
- struct {
- enum { CSS_Z_INDEX_INHERIT,
- CSS_Z_INDEX_AUTO,
- CSS_Z_INDEX_INTEGER,
- CSS_Z_INDEX_NOT_SET } z_index;
- int value;
- } z_index;
-};
-
-/** Author level CSS importance info for properties that may be set in HTML */
-struct css_importance {
- /* background properties */
- bool background_color;
- bool background_image;
-
- /* borders */
- bool border_style[4]; /**< top, right, bottom, left */
- bool border_color[4];
- bool border_width[4];
- bool border_spacing;
-
- bool color;
-
- bool height;
-
- /* margins */
- bool margin[4]; /**< top, right, bottom, left */
-
- /* padding */
- bool padding[4]; /**< top, right, bottom, left */
-
- bool width;
-};
-
-struct css_stylesheet;
-
-typedef enum {
- CSS_ORIGIN_AUTHOR,
- CSS_ORIGIN_USER,
- CSS_ORIGIN_UA
-} css_origin;
-
-/** Data specific to CONTENT_CSS. */
-struct content_css_data {
- struct css_stylesheet *css; /**< Opaque stylesheet data. */
- unsigned int import_count; /**< Number of entries in import_url. */
- struct content **import_content; /**< Imported stylesheet contents. */
- css_origin origin; /**< Origin of stylesheet. */
-};
-
-
-extern const struct css_style css_base_style;
-extern const struct css_style css_empty_style;
-extern const struct css_style css_blank_style;
-extern float css_screen_dpi;
-
-
-#ifdef CSS_INTERNALS
-
-/** Type of a css_selector. */
-typedef enum {
- CSS_SELECTOR_ELEMENT,
- CSS_SELECTOR_ID,
- CSS_SELECTOR_CLASS,
- CSS_SELECTOR_ATTRIB,
- CSS_SELECTOR_ATTRIB_EQ,
- CSS_SELECTOR_ATTRIB_INC,
- CSS_SELECTOR_ATTRIB_DM,
- CSS_SELECTOR_ATTRIB_PRE,
- CSS_SELECTOR_ATTRIB_SUF,
- CSS_SELECTOR_ATTRIB_SUB,
- CSS_SELECTOR_PSEUDO,
-} css_selector_type;
-
-/** Relationship to combiner in a css_selector. */
-typedef enum {
- CSS_COMB_NONE,
- CSS_COMB_ANCESTOR,
- CSS_COMB_PARENT,
- CSS_COMB_PRECEDED,
-} css_combinator;
-
-/** Representation of a CSS selector. */
-struct css_selector {
- css_selector_type type;
- const char *data;
- unsigned int data_length;
- const char *data2;
- unsigned int data2_length;
- struct css_selector *detail;
- struct css_selector *combiner;
- struct css_selector *next;
- css_combinator comb;
- struct css_style *style;
- unsigned long specificity;
-};
-
-/** Type of a css_node. */
-typedef enum {
- CSS_NODE_DECLARATION,
- CSS_NODE_IDENT,
- CSS_NODE_NUMBER,
- CSS_NODE_PERCENTAGE,
- CSS_NODE_DIMENSION,
- CSS_NODE_STRING,
- CSS_NODE_DELIM,
- CSS_NODE_URI,
- CSS_NODE_HASH,
- CSS_NODE_UNICODE_RANGE,
- CSS_NODE_INCLUDES,
- CSS_NODE_FUNCTION,
- CSS_NODE_DASHMATCH,
- CSS_NODE_PREFIX,
- CSS_NODE_SUFFIX,
- CSS_NODE_SUBSTR,
- CSS_NODE_COLON,
- CSS_NODE_COMMA,
- CSS_NODE_DOT,
- CSS_NODE_PLUS,
- CSS_NODE_GT,
- CSS_NODE_PAREN,
- CSS_NODE_BRAC,
-} css_node_type;
-
-/** A node in a CSS parse tree. */
-struct css_node {
- css_node_type type;
- const char *data;
- unsigned int data_length;
- struct css_node *value;
- struct css_node *next;
- css_combinator comb;
- struct css_style *style;
- unsigned long specificity;
- struct content *stylesheet;
-};
-
-
-#define HASH_SIZE (47 + 1)
+struct content;
-/** Representation of a CSS 2 style sheet. */
-struct css_stylesheet {
- struct css_selector *rule[HASH_SIZE];
-};
+/**
+ * CSS content data
+ */
+struct content_css_data
+{
+ lwc_context *dict; /**< Dictionary to intern strings in */
-/** Parameters to and results from the CSS parser. */
-struct css_parser_params {
- bool ruleset_only;
- struct content *stylesheet;
- struct css_node *declaration;
- bool syntax_error;
- bool memory_error;
- bool had_ruleset;
-};
+ css_stylesheet *sheet; /**< Stylesheet object */
-/** Token type for the CSS parser. */
-struct css_parser_token {
- const char *text;
- unsigned int length;
+ uint32_t import_count; /**< Number of sheets imported */
+ struct content **imports; /**< Array of imported sheets */
};
-#endif
-
-
-struct content;
+bool nscss_create(struct content *c, struct content *parent,
+ const char *params[]);
-bool css_convert(struct content *c, int width, int height);
-void css_destroy(struct content *c);
+bool nscss_process_data(struct content *c, char *data, unsigned int size);
-#ifdef CSS_INTERNALS
+bool nscss_convert(struct content *c, int w, int h);
-struct css_node * css_new_node(struct content *stylesheet,
- css_node_type type,
- const char *data, unsigned int data_length);
-void css_free_node(struct css_node *node);
-struct css_selector * css_new_selector(css_selector_type type,
- const char *data, unsigned int data_length);
-void css_free_selector(struct css_selector *node);
-void css_atimport(struct content *c, struct css_node *node);
-void css_add_ruleset(struct content *c,
- struct css_selector *selector,
- struct css_node *declaration);
-void css_add_declarations(struct css_style *style,
- struct css_node *declaration);
-unsigned int css_hash(const char *s, int length);
-
-int css_tokenise(unsigned char **buffer, unsigned char *end,
- unsigned char **token_text);
-
-void css_parser_Trace(FILE *TraceFILE, char *zTracePrompt);
-void *css_parser_Alloc(void *(*mallocProc)(size_t));
-void css_parser_Free(void *p, void (*freeProc)(void*));
-void css_parser_(void *yyp, int yymajor, struct css_parser_token yyminor,
- struct css_parser_params *param);
-const char *css_parser_TokenName(int tokenType);
+void nscss_destroy(struct content *c);
#endif
-void css_set_origin(struct content *c, css_origin origin);
-struct css_working_stylesheet *css_make_working_stylesheet(
- struct content **stylesheet_content,
- unsigned int stylesheet_count);
-void css_get_style(struct css_working_stylesheet *working_stylesheet,
- xmlNode *element, struct css_style *style,
- struct css_importance *author);
-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,
- struct css_importance * const author);
-void css_merge(struct css_style * const style,
- const struct css_style * const apply,
- const unsigned long specificity,
- struct css_importance * const author);
-void css_parse_property_list(struct content *c, struct css_style * style,
- char * str);
-colour named_colour(const char *name);
-colour hex_colour(const char *text, int length);
-
-void css_dump_style(FILE *stream, const struct css_style * const style);
-void css_dump_stylesheet(const struct css_stylesheet * stylesheet);
-
-float css_len2px(const struct css_length *length,
- const struct css_style *style);
-float css_len2pt(const struct css_length *length,
- const struct css_style *style);
-struct css_border *css_eyecatching_border(struct css_border *test1,
- struct css_style *style1, struct css_border *test2,
- struct css_style *style2);
-
-#endif
diff --git a/css/css_enums b/css/css_enums
deleted file mode 100644
index ff41f08b1..000000000
--- a/css/css_enums
+++ /dev/null
@@ -1,29 +0,0 @@
-css_unit em ex px in cm mm pt pc
-css_background_attachment inherit fixed scroll
-css_background_repeat inherit repeat repeat-x repeat-y no-repeat
-css_border_collapse inherit collapse separate
-css_border_style inherit none hidden dotted dashed solid double groove ridge inset outset
-css_caption_side inherit top bottom
-css_clear inherit none both left right
-css_cursor inherit auto crosshair default pointer move e-resize ne-resize nw-resize n-resize se-resize sw-resize s-resize w-resize text wait help no-drop not-allowed progress
-css_direction inherit ltr rtl
-css_display inherit inline block list-item run-in inline-block table inline-table table-row-group table-header-group table-footer-group table-row table-column-group table-column table-cell table-caption none
-css_empty_cells inherit show hide
-css_float inherit none left right
-css_font_family inherit sans-serif serif monospace cursive fantasy
-css_font_style inherit normal italic oblique
-css_font_variant inherit normal small-caps
-css_font_weight inherit normal bold bolder lighter 100 200 300 400 500 600 700 800 900
-css_list_style_position inherit outside inside
-css_list_style_type inherit disc circle square decimal lower-alpha lower-roman upper-alpha upper-roman none
-css_overflow inherit visible hidden scroll auto
-css_page_break_after inherit auto always avoid left right
-css_page_break_before inherit auto always avoid left right
-css_page_break_inside inherit avoid auto
-css_position inherit static relative absolute fixed
-css_table_layout inherit auto fixed
-css_text_align inherit left right center justify
-css_text_transform inherit none capitalize lowercase uppercase
-css_unicode_bidi inherit normal embed bidi-override
-css_visibility inherit visible hidden collapse
-css_white_space inherit normal nowrap pre pre-wrap pre-line
diff --git a/css/dump.c b/css/dump.c
new file mode 100644
index 000000000..430471382
--- /dev/null
+++ b/css/dump.c
@@ -0,0 +1,1791 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "css/dump.h"
+
+static void dump_css_fixed(FILE *stream, css_fixed f);
+static void dump_css_number(FILE *stream, css_fixed val);
+static void dump_css_unit(FILE *stream, css_fixed val, css_unit unit);
+
+/**
+ * Dump a computed style \a style to the give file handle \a stream.
+ *
+ * \param stream Stream to write to
+ * \param style Computed style to dump
+ */
+void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
+{
+ uint8_t val;
+ css_color color = 0;
+ lwc_string *url = NULL;
+ css_fixed len1 = 0, len2 = 0;
+ css_unit unit1 = CSS_UNIT_PX, unit2 = CSS_UNIT_PX;
+ css_computed_clip_rect rect = { 0, 0, 0, 0, CSS_UNIT_PX, CSS_UNIT_PX,
+ CSS_UNIT_PX, CSS_UNIT_PX, true, true,
+ true, true };
+ const css_computed_content_item *content = NULL;
+ const css_computed_counter *counter = NULL;
+ lwc_string **string_list = NULL;
+ int32_t zindex = 0;
+
+ fprintf(stream, "{ ");
+
+ /* background-attachment */
+ val = css_computed_background_attachment(style);
+ switch (val) {
+ case CSS_BACKGROUND_ATTACHMENT_FIXED:
+ fprintf(stream, "background-attachment: fixed ");
+ break;
+ case CSS_BACKGROUND_ATTACHMENT_SCROLL:
+ fprintf(stream, "background-attachment: scroll ");
+ break;
+ default:
+ break;
+ }
+
+ /* background-color */
+ val = css_computed_background_color(style, &color);
+ switch (val) {
+ case CSS_BACKGROUND_COLOR_TRANSPARENT:
+ fprintf(stream, "background-color: transparent ");
+ break;
+ case CSS_BACKGROUND_COLOR_COLOR:
+ fprintf(stream, "background-color: #%08x ", color);
+ break;
+ default:
+ break;
+ }
+
+ /* background-image */
+ val = css_computed_background_image(style, &url);
+ if (val == CSS_BACKGROUND_IMAGE_IMAGE && url != NULL) {
+ fprintf(stream, "background-image: url('%.*s') ",
+ (int) lwc_string_length(url),
+ lwc_string_data(url));
+ } else if (val == CSS_BACKGROUND_IMAGE_NONE) {
+ fprintf(stream, "background-image: none ");
+ }
+
+ /* background-position */
+ val = css_computed_background_position(style, &len1, &unit1,
+ &len2, &unit2);
+ if (val == CSS_BACKGROUND_POSITION_SET) {
+ fprintf(stream, "background-position: ");
+ dump_css_unit(stream, len1, unit1);
+ fprintf(stream, " ");
+ dump_css_unit(stream, len2, unit2);
+ fprintf(stream, " ");
+ }
+
+ /* background-repeat */
+ val = css_computed_background_repeat(style);
+ switch (val) {
+ case CSS_BACKGROUND_REPEAT_REPEAT_X:
+ fprintf(stream, "background-repeat: repeat-x ");
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT_Y:
+ fprintf(stream, "background-repeat: repeat-y ");
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT:
+ fprintf(stream, "background-repeat: repeat ");
+ break;
+ case CSS_BACKGROUND_REPEAT_NO_REPEAT:
+ fprintf(stream, "background-repeat: no-repeat ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-collapse */
+ val = css_computed_border_collapse(style);
+ switch (val) {
+ case CSS_BORDER_COLLAPSE_SEPARATE:
+ fprintf(stream, "border-collapse: separate ");
+ break;
+ case CSS_BORDER_COLLAPSE_COLLAPSE:
+ fprintf(stream, "border-collapse: collapse ");
+ break;
+ default:
+
+ break;
+ }
+
+ /* border-spacing */
+ val = css_computed_border_spacing(style, &len1, &unit1, &len2, &unit2);
+ if (val == CSS_BORDER_SPACING_SET) {
+ fprintf(stream, "border-spacing: ");
+ dump_css_unit(stream, len1, unit1);
+ fprintf(stream, " ");
+ dump_css_unit(stream, len2, unit2);
+ fprintf(stream, " ");
+ }
+
+ /* border-top-color */
+ val = css_computed_border_top_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_INITIAL:
+ fprintf(stream, "border-top-color: initial ");
+ break;
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ fprintf(stream, "border-top-color: transparent ");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ fprintf(stream, "border-top-color: #%08x ", color);
+ break;
+ default:
+ break;
+ }
+
+ /* border-right-color */
+ val = css_computed_border_right_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_INITIAL:
+ fprintf(stream, "border-right-color: initial ");
+ break;
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ fprintf(stream, "border-right-color: transparent ");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ fprintf(stream, "border-right-color: #%08x ", color);
+ break;
+ default:
+ break;
+ }
+
+ /* border-bottom-color */
+ val = css_computed_border_bottom_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_INITIAL:
+ fprintf(stream, "border-bottom-color: initial ");
+ break;
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ fprintf(stream, "border-bottom-color: transparent ");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ fprintf(stream, "border-bottom-color: #%08x ", color);
+ break;
+ default:
+ break;
+ }
+
+ /* border-left-color */
+ val = css_computed_border_left_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_INITIAL:
+ fprintf(stream, "border-left-color: initial ");
+ break;
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ fprintf(stream, "border-left-color: transparent ");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ fprintf(stream, "border-left-color: #%08x ", color);
+ break;
+ default:
+ break;
+ }
+
+ /* border-top-style */
+ val = css_computed_border_top_style(style);
+ switch (val) {
+ case CSS_BORDER_STYLE_NONE:
+ fprintf(stream, "border-top-style: none ");
+ break;
+ case CSS_BORDER_STYLE_HIDDEN:
+ fprintf(stream, "border-top-style: hidden ");
+ break;
+ case CSS_BORDER_STYLE_DOTTED:
+ fprintf(stream, "border-top-style: dotted ");
+ break;
+ case CSS_BORDER_STYLE_DASHED:
+ fprintf(stream, "border-top-style: dashed ");
+ break;
+ case CSS_BORDER_STYLE_SOLID:
+ fprintf(stream, "border-top-style: solid ");
+ break;
+ case CSS_BORDER_STYLE_DOUBLE:
+ fprintf(stream, "border-top-style: double ");
+ break;
+ case CSS_BORDER_STYLE_GROOVE:
+ fprintf(stream, "border-top-style: groove ");
+ break;
+ case CSS_BORDER_STYLE_RIDGE:
+ fprintf(stream, "border-top-style: ridge ");
+ break;
+ case CSS_BORDER_STYLE_INSET:
+ fprintf(stream, "border-top-style: inset ");
+ break;
+ case CSS_BORDER_STYLE_OUTSET:
+ fprintf(stream, "border-top-style: outset ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-right-style */
+ val = css_computed_border_right_style(style);
+ switch (val) {
+ case CSS_BORDER_STYLE_NONE:
+ fprintf(stream, "border-right-style: none ");
+ break;
+ case CSS_BORDER_STYLE_HIDDEN:
+ fprintf(stream, "border-right-style: hidden ");
+ break;
+ case CSS_BORDER_STYLE_DOTTED:
+ fprintf(stream, "border-right-style: dotted ");
+ break;
+ case CSS_BORDER_STYLE_DASHED:
+ fprintf(stream, "border-right-style: dashed ");
+ break;
+ case CSS_BORDER_STYLE_SOLID:
+ fprintf(stream, "border-right-style: solid ");
+ break;
+ case CSS_BORDER_STYLE_DOUBLE:
+ fprintf(stream, "border-right-style: double ");
+ break;
+ case CSS_BORDER_STYLE_GROOVE:
+ fprintf(stream, "border-right-style: groove ");
+ break;
+ case CSS_BORDER_STYLE_RIDGE:
+ fprintf(stream, "border-right-style: ridge ");
+ break;
+ case CSS_BORDER_STYLE_INSET:
+ fprintf(stream, "border-right-style: inset ");
+ break;
+ case CSS_BORDER_STYLE_OUTSET:
+ fprintf(stream, "border-right-style: outset ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-bottom-style */
+ val = css_computed_border_bottom_style(style);
+ switch (val) {
+ case CSS_BORDER_STYLE_NONE:
+ fprintf(stream, "border-bottom-style: none ");
+ break;
+ case CSS_BORDER_STYLE_HIDDEN:
+ fprintf(stream, "border-bottom-style: hidden ");
+ break;
+ case CSS_BORDER_STYLE_DOTTED:
+ fprintf(stream, "border-bottom-style: dotted ");
+ break;
+ case CSS_BORDER_STYLE_DASHED:
+ fprintf(stream, "border-bottom-style: dashed ");
+ break;
+ case CSS_BORDER_STYLE_SOLID:
+ fprintf(stream, "border-bottom-style: solid ");
+ break;
+ case CSS_BORDER_STYLE_DOUBLE:
+ fprintf(stream, "border-bottom-style: double ");
+ break;
+ case CSS_BORDER_STYLE_GROOVE:
+ fprintf(stream, "border-bottom-style: groove ");
+ break;
+ case CSS_BORDER_STYLE_RIDGE:
+ fprintf(stream, "border-bottom-style: ridge ");
+ break;
+ case CSS_BORDER_STYLE_INSET:
+ fprintf(stream, "border-bottom-style: inset ");
+ break;
+ case CSS_BORDER_STYLE_OUTSET:
+ fprintf(stream, "border-bottom-style: outset ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-left-style */
+ val = css_computed_border_left_style(style);
+ switch (val) {
+ case CSS_BORDER_STYLE_NONE:
+ fprintf(stream, "border-left-style: none ");
+ break;
+ case CSS_BORDER_STYLE_HIDDEN:
+ fprintf(stream, "border-left-style: hidden ");
+ break;
+ case CSS_BORDER_STYLE_DOTTED:
+ fprintf(stream, "border-left-style: dotted ");
+ break;
+ case CSS_BORDER_STYLE_DASHED:
+ fprintf(stream, "border-left-style: dashed ");
+ break;
+ case CSS_BORDER_STYLE_SOLID:
+ fprintf(stream, "border-left-style: solid ");
+ break;
+ case CSS_BORDER_STYLE_DOUBLE:
+ fprintf(stream, "border-left-style: double ");
+ break;
+ case CSS_BORDER_STYLE_GROOVE:
+ fprintf(stream, "border-left-style: groove ");
+ break;
+ case CSS_BORDER_STYLE_RIDGE:
+ fprintf(stream, "border-left-style: ridge ");
+ break;
+ case CSS_BORDER_STYLE_INSET:
+ fprintf(stream, "border-left-style: inset ");
+ break;
+ case CSS_BORDER_STYLE_OUTSET:
+ fprintf(stream, "border-left-style: outset ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-top-width */
+ val = css_computed_border_top_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_BORDER_WIDTH_THIN:
+ fprintf(stream, "border-top-width: thin ");
+ break;
+ case CSS_BORDER_WIDTH_MEDIUM:
+ fprintf(stream, "border-top-width: medium ");
+ break;
+ case CSS_BORDER_WIDTH_THICK:
+ fprintf(stream, "border-top-width: thick ");
+ break;
+ case CSS_BORDER_WIDTH_WIDTH:
+ fprintf(stream, "border-top-width: ");
+ dump_css_unit(stream, len1, unit1);
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-right-width */
+ val = css_computed_border_right_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_BORDER_WIDTH_THIN:
+ fprintf(stream, "border-right-width: thin ");
+ break;
+ case CSS_BORDER_WIDTH_MEDIUM:
+ fprintf(stream, "border-right-width: medium ");
+ break;
+ case CSS_BORDER_WIDTH_THICK:
+ fprintf(stream, "border-right-width: thick ");
+ break;
+ case CSS_BORDER_WIDTH_WIDTH:
+ fprintf(stream, "border-right-width: ");
+ dump_css_unit(stream, len1, unit1);
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-bottom-width */
+ val = css_computed_border_bottom_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_BORDER_WIDTH_THIN:
+ fprintf(stream, "border-bottom-width: thin ");
+ break;
+ case CSS_BORDER_WIDTH_MEDIUM:
+ fprintf(stream, "border-bottom-width: medium ");
+ break;
+ case CSS_BORDER_WIDTH_THICK:
+ fprintf(stream, "border-bottom-width: thick ");
+ break;
+ case CSS_BORDER_WIDTH_WIDTH:
+ fprintf(stream, "border-bottom-width: ");
+ dump_css_unit(stream, len1, unit1);
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* border-left-width */
+ val = css_computed_border_left_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_BORDER_WIDTH_THIN:
+ fprintf(stream, "border-left-width: thin ");
+ break;
+ case CSS_BORDER_WIDTH_MEDIUM:
+ fprintf(stream, "border-left-width: medium ");
+ break;
+ case CSS_BORDER_WIDTH_THICK:
+ fprintf(stream, "border-left-width: thick ");
+ break;
+ case CSS_BORDER_WIDTH_WIDTH:
+ fprintf(stream, "border-left-width: ");
+ dump_css_unit(stream, len1, unit1);
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* bottom */
+ val = css_computed_bottom(style, &len1, &unit1);
+ switch (val) {
+ case CSS_BOTTOM_AUTO:
+ fprintf(stream, "bottom: auto ");
+ break;
+ case CSS_BOTTOM_SET:
+ fprintf(stream, "bottom: ");
+ dump_css_unit(stream, len1, unit1);
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* caption-side */
+ val = css_computed_caption_side(style);
+ switch (val) {
+ case CSS_CAPTION_SIDE_TOP:
+ fprintf(stream, "caption_side: top ");
+ break;
+ case CSS_CAPTION_SIDE_BOTTOM:
+ fprintf(stream, "caption_side: bottom ");
+ break;
+ default:
+ break;
+ }
+
+ /* clear */
+ val = css_computed_clear(style);
+ switch (val) {
+ case CSS_CLEAR_NONE:
+ fprintf(stream, "clear: none ");
+ break;
+ case CSS_CLEAR_LEFT:
+ fprintf(stream, "clear: left ");
+ break;
+ case CSS_CLEAR_RIGHT:
+ fprintf(stream, "clear: right ");
+ break;
+ case CSS_CLEAR_BOTH:
+ fprintf(stream, "clear: both ");
+ break;
+ default:
+ break;
+ }
+
+ /* clip */
+ val = css_computed_clip(style, &rect);
+ switch (val) {
+ case CSS_CLIP_AUTO:
+ fprintf(stream, "clip: auto ");
+ break;
+ case CSS_CLIP_RECT:
+ fprintf(stream, "clip: rect( ");
+
+ if (rect.top_auto)
+ fprintf(stream, "auto");
+ else
+ dump_css_unit(stream, rect.top, rect.tunit);
+ fprintf(stream, ", ");
+
+ if (rect.right_auto)
+ fprintf(stream, "auto");
+ else
+ dump_css_unit(stream, rect.right, rect.runit);
+ fprintf(stream, ", ");
+
+ if (rect.bottom_auto)
+ fprintf(stream, "auto");
+ else
+ dump_css_unit(stream, rect.bottom, rect.bunit);
+ fprintf(stream, ", ");
+
+ if (rect.left_auto)
+ fprintf(stream, "auto");
+ else
+ dump_css_unit(stream, rect.left, rect.lunit);
+ fprintf(stream, ") ");
+ break;
+ default:
+ break;
+ }
+
+ /* color */
+ val = css_computed_color(style, &color);
+ if (val == CSS_COLOR_COLOR) {
+ fprintf(stream, "color: #%08x ", color);
+ }
+
+ /* content */
+ val = css_computed_content(style, &content);
+ switch (val) {
+ case CSS_CONTENT_NONE:
+ fprintf(stream, "content: none ");
+ break;
+ case CSS_CONTENT_NORMAL:
+ fprintf(stream, "content: normal ");
+ break;
+ case CSS_CONTENT_SET:
+ fprintf(stream, "content:");
+
+ while (content->type != CSS_COMPUTED_CONTENT_NONE) {
+ fprintf(stream, " ");
+
+ switch (content->type) {
+ case CSS_COMPUTED_CONTENT_STRING:
+ fprintf(stream, "\"%.*s\"",
+ (int) lwc_string_length(
+ content->data.string),
+ lwc_string_data(
+ content->data.string));
+ break;
+ case CSS_COMPUTED_CONTENT_URI:
+ fprintf(stream, "uri(\"%.*s\")",
+ (int) lwc_string_length(
+ content->data.uri),
+ lwc_string_data(
+ content->data.uri));
+ break;
+ case CSS_COMPUTED_CONTENT_COUNTER:
+ fprintf(stream, "counter(%.*s)",
+ (int) lwc_string_length(
+ content->data.counter.name),
+ lwc_string_data(
+ content->data.counter.name));
+ break;
+ case CSS_COMPUTED_CONTENT_COUNTERS:
+ fprintf(stream, "counters(%.*s, \"%.*s\")",
+ (int) lwc_string_length(
+ content->data.counters.name),
+ lwc_string_data(
+ content->data.counters.name),
+ (int) lwc_string_length(
+ content->data.counters.sep),
+ lwc_string_data(
+ content->data.counters.sep));
+ break;
+ case CSS_COMPUTED_CONTENT_ATTR:
+ fprintf(stream, "attr(%.*s)",
+ (int) lwc_string_length(
+ content->data.attr),
+ lwc_string_data(
+ content->data.attr));
+ break;
+ case CSS_COMPUTED_CONTENT_OPEN_QUOTE:
+ fprintf(stream, "open-quote");
+ break;
+ case CSS_COMPUTED_CONTENT_CLOSE_QUOTE:
+ fprintf(stream, "close-quote");
+ break;
+ case CSS_COMPUTED_CONTENT_NO_OPEN_QUOTE:
+ fprintf(stream, "no-open-quote");
+ break;
+ case CSS_COMPUTED_CONTENT_NO_CLOSE_QUOTE:
+ fprintf(stream, "no-close-quote");
+ break;
+ }
+
+ content++;
+ }
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* counter-increment */
+ val = css_computed_counter_increment(style, &counter);
+ if (counter == NULL) {
+ fprintf(stream, "counter-increment: none ");
+ } else {
+ fprintf(stream, "counter-increment:");
+
+ while (counter->name != NULL) {
+ fprintf(stream, " %.*s ",
+ (int) lwc_string_length(counter->name),
+ lwc_string_data(counter->name));
+
+ dump_css_fixed(stream, counter->value);
+
+ counter++;
+ }
+
+ fprintf(stream, " ");
+ }
+
+ /* counter-reset */
+ val = css_computed_counter_reset(style, &counter);
+ if (counter == NULL) {
+ fprintf(stream, "counter-reset: none ");
+ } else {
+ fprintf(stream, "counter-reset:");
+
+ while (counter->name != NULL) {
+ fprintf(stream, " %.*s ",
+ (int) lwc_string_length(counter->name),
+ lwc_string_data(counter->name));
+
+ dump_css_fixed(stream, counter->value);
+
+ counter++;
+ }
+
+ fprintf(stream, " ");
+ }
+
+ /* cursor */
+ val = css_computed_cursor(style, &string_list);
+ fprintf(stream, "cursor:");
+
+ if (string_list != NULL) {
+ while (*string_list != NULL) {
+ fprintf(stream, " url\"%.*s\")",
+ (int) lwc_string_length(*string_list),
+ lwc_string_data(*string_list));
+
+ string_list++;
+ }
+ }
+ switch (val) {
+ case CSS_CURSOR_AUTO:
+ fprintf(stream, " auto ");
+ break;
+ case CSS_CURSOR_CROSSHAIR:
+ fprintf(stream, " crosshair ");
+ break;
+ case CSS_CURSOR_DEFAULT:
+ fprintf(stream, " default ");
+ break;
+ case CSS_CURSOR_POINTER:
+ fprintf(stream, " pointer ");
+ break;
+ case CSS_CURSOR_MOVE:
+ fprintf(stream, " move ");
+ break;
+ case CSS_CURSOR_E_RESIZE:
+ fprintf(stream, " e-resize ");
+ break;
+ case CSS_CURSOR_NE_RESIZE:
+ fprintf(stream, " ne-resize ");
+ break;
+ case CSS_CURSOR_NW_RESIZE:
+ fprintf(stream, " nw-resize ");
+ break;
+ case CSS_CURSOR_N_RESIZE:
+ fprintf(stream, " n-resize ");
+ break;
+ case CSS_CURSOR_SE_RESIZE:
+ fprintf(stream, " se-resize ");
+ break;
+ case CSS_CURSOR_SW_RESIZE:
+ fprintf(stream, " sw-resize ");
+ break;
+ case CSS_CURSOR_S_RESIZE:
+ fprintf(stream, " s-resize ");
+ break;
+ case CSS_CURSOR_W_RESIZE:
+ fprintf(stream, " w-resize ");
+ break;
+ case CSS_CURSOR_TEXT:
+ fprintf(stream, " text ");
+ break;
+ case CSS_CURSOR_WAIT:
+ fprintf(stream, " wait ");
+ break;
+ case CSS_CURSOR_HELP:
+ fprintf(stream, " help ");
+ break;
+ case CSS_CURSOR_PROGRESS:
+ fprintf(stream, " progress ");
+ break;
+ default:
+ break;
+ }
+
+ /* direction */
+ val = css_computed_direction(style);
+ switch (val) {
+ case CSS_DIRECTION_LTR:
+ fprintf(stream, "direction: ltr ");
+ break;
+ case CSS_DIRECTION_RTL:
+ fprintf(stream, "direction: rtl ");
+ break;
+ default:
+ break;
+ }
+
+ /* display */
+ val = css_computed_display_static(style);
+ switch (val) {
+ case CSS_DISPLAY_INLINE:
+ fprintf(stream, "display: inline ");
+ break;
+ case CSS_DISPLAY_BLOCK:
+ fprintf(stream, "display: block ");
+ break;
+ case CSS_DISPLAY_LIST_ITEM:
+ fprintf(stream, "display: list-item ");
+ break;
+ case CSS_DISPLAY_RUN_IN:
+ fprintf(stream, "display: run-in ");
+ break;
+ case CSS_DISPLAY_INLINE_BLOCK:
+ fprintf(stream, "display: inline-block ");
+ break;
+ case CSS_DISPLAY_TABLE:
+ fprintf(stream, "display: table ");
+ break;
+ case CSS_DISPLAY_INLINE_TABLE:
+ fprintf(stream, "display: inline-table ");
+ break;
+ case CSS_DISPLAY_TABLE_ROW_GROUP:
+ fprintf(stream, "display: table-row-group ");
+ break;
+ case CSS_DISPLAY_TABLE_HEADER_GROUP:
+ fprintf(stream, "display: table-header-group ");
+ break;
+ case CSS_DISPLAY_TABLE_FOOTER_GROUP:
+ fprintf(stream, "display: table-footer-group ");
+ break;
+ case CSS_DISPLAY_TABLE_ROW:
+ fprintf(stream, "display: table-row ");
+ break;
+ case CSS_DISPLAY_TABLE_COLUMN_GROUP:
+ fprintf(stream, "display: table-column-group ");
+ break;
+ case CSS_DISPLAY_TABLE_COLUMN:
+ fprintf(stream, "display: table-column ");
+ break;
+ case CSS_DISPLAY_TABLE_CELL:
+ fprintf(stream, "display: table-cell ");
+ break;
+ case CSS_DISPLAY_TABLE_CAPTION:
+ fprintf(stream, "display: table-caption ");
+ break;
+ case CSS_DISPLAY_NONE:
+ fprintf(stream, "display: none ");
+ break;
+ default:
+ break;
+ }
+
+ /* empty-cells */
+ val = css_computed_empty_cells(style);
+ switch (val) {
+ case CSS_EMPTY_CELLS_SHOW:
+ fprintf(stream, "empty-cells: show ");
+ break;
+ case CSS_EMPTY_CELLS_HIDE:
+ fprintf(stream, "empty-cells: hide ");
+ break;
+ default:
+ break;
+ }
+
+ /* float */
+ val = css_computed_float(style);
+ switch (val) {
+ case CSS_FLOAT_LEFT:
+ fprintf(stream, "float: left ");
+ break;
+ case CSS_FLOAT_RIGHT:
+ fprintf(stream, "float: right ");
+ break;
+ case CSS_FLOAT_NONE:
+ fprintf(stream, "float: none ");
+ break;
+ default:
+ break;
+ }
+
+ /* font-family */
+ val = css_computed_font_family(style, &string_list);
+ if (val != CSS_FONT_FAMILY_INHERIT) {
+ fprintf(stream, "font-family:");
+
+ if (string_list != NULL) {
+ while (*string_list != NULL) {
+ fprintf(stream, " \"%.*s\"",
+ (int) lwc_string_length(*string_list),
+ lwc_string_data(*string_list));
+
+ string_list++;
+ }
+ }
+ switch (val) {
+ case CSS_FONT_FAMILY_SERIF:
+ fprintf(stream, " serif ");
+ break;
+ case CSS_FONT_FAMILY_SANS_SERIF:
+ fprintf(stream, " sans-serif ");
+ break;
+ case CSS_FONT_FAMILY_CURSIVE:
+ fprintf(stream, " cursive ");
+ break;
+ case CSS_FONT_FAMILY_FANTASY:
+ fprintf(stream, " fantasy ");
+ break;
+ case CSS_FONT_FAMILY_MONOSPACE:
+ fprintf(stream, " monospace ");
+ break;
+ }
+ }
+
+ /* font-size */
+ val = css_computed_font_size(style, &len1, &unit1);
+ switch (val) {
+ case CSS_FONT_SIZE_XX_SMALL:
+ fprintf(stream, "font-size: xx-small ");
+ break;
+ case CSS_FONT_SIZE_X_SMALL:
+ fprintf(stream, "font-size: x-small ");
+ break;
+ case CSS_FONT_SIZE_SMALL:
+ fprintf(stream, "font-size: small ");
+ break;
+ case CSS_FONT_SIZE_MEDIUM:
+ fprintf(stream, "font-size: medium ");
+ break;
+ case CSS_FONT_SIZE_LARGE:
+ fprintf(stream, "font-size: large ");
+ break;
+ case CSS_FONT_SIZE_X_LARGE:
+ fprintf(stream, "font-size: x-large ");
+ break;
+ case CSS_FONT_SIZE_XX_LARGE:
+ fprintf(stream, "font-size: xx-large ");
+ break;
+ case CSS_FONT_SIZE_LARGER:
+ fprintf(stream, "font-size: larger ");
+ break;
+ case CSS_FONT_SIZE_SMALLER:
+ fprintf(stream, "font-size: smaller ");
+ break;
+ case CSS_FONT_SIZE_DIMENSION:
+ fprintf(stream, "font-size: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* font-style */
+ val = css_computed_font_style(style);
+ switch (val) {
+ case CSS_FONT_STYLE_NORMAL:
+ fprintf(stream, "font-style: normal ");
+ break;
+ case CSS_FONT_STYLE_ITALIC:
+ fprintf(stream, "font-style: italic ");
+ break;
+ case CSS_FONT_STYLE_OBLIQUE:
+ fprintf(stream, "font-style: oblique ");
+ break;
+ default:
+ break;
+ }
+
+ /* font-variant */
+ val = css_computed_font_variant(style);
+ switch (val) {
+ case CSS_FONT_VARIANT_NORMAL:
+ fprintf(stream, "font-variant: normal ");
+ break;
+ case CSS_FONT_VARIANT_SMALL_CAPS:
+ fprintf(stream, "font-variant: small-caps ");
+ break;
+ default:
+ break;
+ }
+
+ /* font-weight */
+ val = css_computed_font_weight(style);
+ switch (val) {
+ case CSS_FONT_WEIGHT_NORMAL:
+ fprintf(stream, "font-weight: normal ");
+ break;
+ case CSS_FONT_WEIGHT_BOLD:
+ fprintf(stream, "font-weight: bold ");
+ break;
+ case CSS_FONT_WEIGHT_BOLDER:
+ fprintf(stream, "font-weight: bolder ");
+ break;
+ case CSS_FONT_WEIGHT_LIGHTER:
+ fprintf(stream, "font-weight: lighter ");
+ break;
+ case CSS_FONT_WEIGHT_100:
+ fprintf(stream, "font-weight: 100 ");
+ break;
+ case CSS_FONT_WEIGHT_200:
+ fprintf(stream, "font-weight: 200 ");
+ break;
+ case CSS_FONT_WEIGHT_300:
+ fprintf(stream, "font-weight: 300 ");
+ break;
+ case CSS_FONT_WEIGHT_400:
+ fprintf(stream, "font-weight: 400 ");
+ break;
+ case CSS_FONT_WEIGHT_500:
+ fprintf(stream, "font-weight: 500 ");
+ break;
+ case CSS_FONT_WEIGHT_600:
+ fprintf(stream, "font-weight: 600 ");
+ break;
+ case CSS_FONT_WEIGHT_700:
+ fprintf(stream, "font-weight: 700 ");
+ break;
+ case CSS_FONT_WEIGHT_800:
+ fprintf(stream, "font-weight: 800 ");
+ break;
+ case CSS_FONT_WEIGHT_900:
+ fprintf(stream, "font-weight: 900 ");
+ break;
+ default:
+ break;
+ }
+
+ /* height */
+ val = css_computed_height(style, &len1, &unit1);
+ switch (val) {
+ case CSS_HEIGHT_AUTO:
+ fprintf(stream, "height: auto ");
+ break;
+ case CSS_HEIGHT_SET:
+ fprintf(stream, "height: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* left */
+ val = css_computed_left(style, &len1, &unit1);
+ switch (val) {
+ case CSS_LEFT_AUTO:
+ fprintf(stream, "left: auto ");
+ break;
+ case CSS_LEFT_SET:
+ fprintf(stream, "left: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* letter-spacing */
+ val = css_computed_letter_spacing(style, &len1, &unit1);
+ switch (val) {
+ case CSS_LETTER_SPACING_NORMAL:
+ fprintf(stream, "letter-spacing: normal ");
+ break;
+ case CSS_LETTER_SPACING_SET:
+ fprintf(stream, "letter-spacing: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* line-height */
+ val = css_computed_line_height(style, &len1, &unit1);
+ switch (val) {
+ case CSS_LINE_HEIGHT_NORMAL:
+ fprintf(stream, "line-height: normal ");
+ break;
+ case CSS_LINE_HEIGHT_NUMBER:
+ fprintf(stream, "line-height: ");
+
+ dump_css_fixed(stream, len1);
+
+ fprintf(stream, " ");
+ break;
+ case CSS_LINE_HEIGHT_DIMENSION:
+ fprintf(stream, "line-height: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* list-style-image */
+ val = css_computed_list_style_image(style, &url);
+ if (url != NULL) {
+ fprintf(stream, "list-style-image: url('%.*s') ",
+ (int) lwc_string_length(url),
+ lwc_string_data(url));
+ } else if (val == CSS_LIST_STYLE_IMAGE_NONE) {
+ fprintf(stream, "list-style-image: none ");
+ }
+
+ /* list-style-position */
+ val = css_computed_list_style_position(style);
+ switch (val) {
+ case CSS_LIST_STYLE_POSITION_INSIDE:
+ fprintf(stream, "list-style-position: inside ");
+ break;
+ case CSS_LIST_STYLE_POSITION_OUTSIDE:
+ fprintf(stream, "list-style-position: outside ");
+ break;
+ default:
+ break;
+ }
+
+ /* list-style-type */
+ val = css_computed_list_style_type(style);
+ switch (val) {
+ case CSS_LIST_STYLE_TYPE_DISC:
+ fprintf(stream, "list-style-type: disc ");
+ break;
+ case CSS_LIST_STYLE_TYPE_CIRCLE:
+ fprintf(stream, "list-style-type: circle ");
+ break;
+ case CSS_LIST_STYLE_TYPE_SQUARE:
+ fprintf(stream, "list-style-type: square ");
+ break;
+ case CSS_LIST_STYLE_TYPE_DECIMAL:
+ fprintf(stream, "list-style-type: decimal ");
+ break;
+ case CSS_LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO:
+ fprintf(stream, "list-style-type: decimal-leading-zero ");
+ break;
+ case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
+ fprintf(stream, "list-style-type: lower-roman ");
+ break;
+ case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
+ fprintf(stream, "list-style-type: upper-roman ");
+ break;
+ case CSS_LIST_STYLE_TYPE_LOWER_GREEK:
+ fprintf(stream, "list-style-type: lower-greek ");
+ break;
+ case CSS_LIST_STYLE_TYPE_LOWER_LATIN:
+ fprintf(stream, "list-style-type: lower-latin ");
+ break;
+ case CSS_LIST_STYLE_TYPE_UPPER_LATIN:
+ fprintf(stream, "list-style-type: upper-latin ");
+ break;
+ case CSS_LIST_STYLE_TYPE_ARMENIAN:
+ fprintf(stream, "list-style-type: armenian ");
+ break;
+ case CSS_LIST_STYLE_TYPE_GEORGIAN:
+ fprintf(stream, "list-style-type: georgian ");
+ break;
+ case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
+ fprintf(stream, "list-style-type: lower-alpha ");
+ break;
+ case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
+ fprintf(stream, "list-style-type: upper-alpha ");
+ break;
+ case CSS_LIST_STYLE_TYPE_NONE:
+ fprintf(stream, "list-style-type: none ");
+ break;
+ default:
+ break;
+ }
+
+ /* margin-top */
+ val = css_computed_margin_top(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MARGIN_AUTO:
+ fprintf(stream, "margin-top: auto ");
+ break;
+ case CSS_MARGIN_SET:
+ fprintf(stream, "margin-top: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* margin-right */
+ val = css_computed_margin_right(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MARGIN_AUTO:
+ fprintf(stream, "margin-right: auto ");
+ break;
+ case CSS_MARGIN_SET:
+ fprintf(stream, "margin-right: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* margin-bottom */
+ val = css_computed_margin_bottom(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MARGIN_AUTO:
+ fprintf(stream, "margin-bottom: auto ");
+ break;
+ case CSS_MARGIN_SET:
+ fprintf(stream, "margin-bottom: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* margin-left */
+ val = css_computed_margin_left(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MARGIN_AUTO:
+ fprintf(stream, "margin-left: auto ");
+ break;
+ case CSS_MARGIN_SET:
+ fprintf(stream, "margin-left: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* max-height */
+ val = css_computed_max_height(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MAX_HEIGHT_NONE:
+ fprintf(stream, "max-height: none ");
+ break;
+ case CSS_MAX_HEIGHT_SET:
+ fprintf(stream, "max-height: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* max-width */
+ val = css_computed_max_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MAX_WIDTH_NONE:
+ fprintf(stream, "max-width: none ");
+ break;
+ case CSS_MAX_WIDTH_SET:
+ fprintf(stream, "max-width: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* min-height */
+ val = css_computed_min_height(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MIN_HEIGHT_SET:
+ fprintf(stream, "min-height: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* min-width */
+ val = css_computed_min_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_MIN_WIDTH_SET:
+ fprintf(stream, "min-width: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* outline-color */
+ val = css_computed_outline_color(style, &color);
+ switch (val) {
+ case CSS_OUTLINE_COLOR_INVERT:
+ fprintf(stream, "outline-color: invert ");
+ break;
+ case CSS_OUTLINE_COLOR_COLOR:
+ fprintf(stream, "outline-color: #%08x ", color);
+ break;
+ default:
+ break;
+ }
+
+ /* outline-style */
+ val = css_computed_outline_style(style);
+ switch (val) {
+ case CSS_OUTLINE_STYLE_NONE:
+ fprintf(stream, "outline-style: none ");
+ break;
+ case CSS_OUTLINE_STYLE_DOTTED:
+ fprintf(stream, "outline-style: dotted ");
+ break;
+ case CSS_OUTLINE_STYLE_DASHED:
+ fprintf(stream, "outline-style: dashed ");
+ break;
+ case CSS_OUTLINE_STYLE_SOLID:
+ fprintf(stream, "outline-style: solid ");
+ break;
+ case CSS_OUTLINE_STYLE_DOUBLE:
+ fprintf(stream, "outline-style: double ");
+ break;
+ case CSS_OUTLINE_STYLE_GROOVE:
+ fprintf(stream, "outline-style: groove ");
+ break;
+ case CSS_OUTLINE_STYLE_RIDGE:
+ fprintf(stream, "outline-style: ridge ");
+ break;
+ case CSS_OUTLINE_STYLE_INSET:
+ fprintf(stream, "outline-style: inset ");
+ break;
+ case CSS_OUTLINE_STYLE_OUTSET:
+ fprintf(stream, "outline-style: outset ");
+ break;
+ default:
+ break;
+ }
+
+ /* outline-width */
+ val = css_computed_outline_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_OUTLINE_WIDTH_THIN:
+ fprintf(stream, "outline-width: thin ");
+ break;
+ case CSS_OUTLINE_WIDTH_MEDIUM:
+ fprintf(stream, "outline-width: medium ");
+ break;
+ case CSS_OUTLINE_WIDTH_THICK:
+ fprintf(stream, "outline-width: thick ");
+ break;
+ case CSS_OUTLINE_WIDTH_WIDTH:
+ fprintf(stream, "outline-width: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* overflow */
+ val = css_computed_overflow(style);
+ switch (val) {
+ case CSS_OVERFLOW_VISIBLE:
+ fprintf(stream, "overflow: visible ");
+ break;
+ case CSS_OVERFLOW_HIDDEN:
+ fprintf(stream, "overflow: hidden ");
+ break;
+ case CSS_OVERFLOW_SCROLL:
+ fprintf(stream, "overflow: scroll ");
+ break;
+ case CSS_OVERFLOW_AUTO:
+ fprintf(stream, "overflow: auto ");
+ break;
+ default:
+ break;
+ }
+
+ /* padding-top */
+ val = css_computed_padding_top(style, &len1, &unit1);
+ switch (val) {
+ case CSS_PADDING_SET:
+ fprintf(stream, "padding-top: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* padding-right */
+ val = css_computed_padding_right(style, &len1, &unit1);
+ switch (val) {
+ case CSS_PADDING_SET:
+ fprintf(stream, "padding-right: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* padding-bottom */
+ val = css_computed_padding_bottom(style, &len1, &unit1);
+ switch (val) {
+ case CSS_PADDING_SET:
+ fprintf(stream, "padding-bottom: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* padding-left */
+ val = css_computed_padding_left(style, &len1, &unit1);
+ switch (val) {
+ case CSS_PADDING_SET:
+ fprintf(stream, "padding-left: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* position */
+ val = css_computed_position(style);
+ switch (val) {
+ case CSS_POSITION_STATIC:
+ fprintf(stream, "position: static ");
+ break;
+ case CSS_POSITION_RELATIVE:
+ fprintf(stream, "position: relative ");
+ break;
+ case CSS_POSITION_ABSOLUTE:
+ fprintf(stream, "position: absolute ");
+ break;
+ case CSS_POSITION_FIXED:
+ fprintf(stream, "position: fixed ");
+ break;
+ default:
+ break;
+ }
+
+ /* quotes */
+ val = css_computed_quotes(style, &string_list);
+ if (val == CSS_QUOTES_STRING && string_list != NULL) {
+ fprintf(stream, "quotes:");
+
+ while (*string_list != NULL) {
+ fprintf(stream, " \"%.*s\"",
+ (int) lwc_string_length(*string_list),
+ lwc_string_data(*string_list));
+
+ string_list++;
+ }
+
+ fprintf(stream, " ");
+ } else {
+ switch (val) {
+ case CSS_QUOTES_NONE:
+ fprintf(stream, "quotes: none ");
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* right */
+ val = css_computed_right(style, &len1, &unit1);
+ switch (val) {
+ case CSS_RIGHT_AUTO:
+ fprintf(stream, "right: auto ");
+ break;
+ case CSS_RIGHT_SET:
+ fprintf(stream, "right: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* table-layout */
+ val = css_computed_table_layout(style);
+ switch (val) {
+ case CSS_TABLE_LAYOUT_AUTO:
+ fprintf(stream, "table-layout: auto ");
+ break;
+ case CSS_TABLE_LAYOUT_FIXED:
+ fprintf(stream, "table-layout: fixed ");
+ break;
+ default:
+ break;
+ }
+
+ /* text-align */
+ val = css_computed_text_align(style);
+ switch (val) {
+ case CSS_TEXT_ALIGN_LEFT:
+ fprintf(stream, "text-align: left ");
+ break;
+ case CSS_TEXT_ALIGN_RIGHT:
+ fprintf(stream, "text-align: right ");
+ break;
+ case CSS_TEXT_ALIGN_CENTER:
+ fprintf(stream, "text-align: center ");
+ break;
+ case CSS_TEXT_ALIGN_JUSTIFY:
+ fprintf(stream, "text-align: justify ");
+ break;
+ case CSS_TEXT_ALIGN_DEFAULT:
+ fprintf(stream, "text-align: default ");
+ break;
+ default:
+ break;
+ }
+
+ /* text-decoration */
+ val = css_computed_text_decoration(style);
+ if (val == CSS_TEXT_DECORATION_NONE) {
+ fprintf(stream, "text-decoration: none ");
+ } else {
+ fprintf(stream, "text-decoration:");
+
+ if (val & CSS_TEXT_DECORATION_BLINK) {
+ fprintf(stream, " blink");
+ }
+ if (val & CSS_TEXT_DECORATION_LINE_THROUGH) {
+ fprintf(stream, " line-through");
+ }
+ if (val & CSS_TEXT_DECORATION_OVERLINE) {
+ fprintf(stream, " overline");
+ }
+ if (val & CSS_TEXT_DECORATION_UNDERLINE) {
+ fprintf(stream, " underline");
+ }
+
+ fprintf(stream, " ");
+ }
+
+ /* text-indent */
+ val = css_computed_text_indent(style, &len1, &unit1);
+ switch (val) {
+ case CSS_TEXT_INDENT_SET:
+ fprintf(stream, "text-indent: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* text-transform */
+ val = css_computed_text_transform(style);
+ switch (val) {
+ case CSS_TEXT_TRANSFORM_CAPITALIZE:
+ fprintf(stream, "text-transform: capitalize ");
+ break;
+ case CSS_TEXT_TRANSFORM_UPPERCASE:
+ fprintf(stream, "text-transform: uppercase ");
+ break;
+ case CSS_TEXT_TRANSFORM_LOWERCASE:
+ fprintf(stream, "text-transform: lowercase ");
+ break;
+ case CSS_TEXT_TRANSFORM_NONE:
+ fprintf(stream, "text-transform: none ");
+ break;
+ default:
+ break;
+ }
+
+ /* top */
+ val = css_computed_top(style, &len1, &unit1);
+ switch (val) {
+ case CSS_TOP_AUTO:
+ fprintf(stream, "top: auto ");
+ break;
+ case CSS_TOP_SET:
+ fprintf(stream, "top: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* unicode-bidi */
+ val = css_computed_unicode_bidi(style);
+ switch (val) {
+ case CSS_UNICODE_BIDI_NORMAL:
+ fprintf(stream, "unicode-bidi: normal ");
+ break;
+ case CSS_UNICODE_BIDI_EMBED:
+ fprintf(stream, "unicode-bidi: embed ");
+ break;
+ case CSS_UNICODE_BIDI_BIDI_OVERRIDE:
+ fprintf(stream, "unicode-bidi: bidi-override ");
+ break;
+ default:
+ break;
+ }
+
+ /* vertical-align */
+ val = css_computed_vertical_align(style, &len1, &unit1);
+ switch (val) {
+ case CSS_VERTICAL_ALIGN_BASELINE:
+ fprintf(stream, "vertical-align: baseline ");
+ break;
+ case CSS_VERTICAL_ALIGN_SUB:
+ fprintf(stream, "vertical-align: sub ");
+ break;
+ case CSS_VERTICAL_ALIGN_SUPER:
+ fprintf(stream, "vertical-align: super ");
+ break;
+ case CSS_VERTICAL_ALIGN_TOP:
+ fprintf(stream, "vertical-align: top ");
+ break;
+ case CSS_VERTICAL_ALIGN_TEXT_TOP:
+ fprintf(stream, "vertical-align: text-top ");
+ break;
+ case CSS_VERTICAL_ALIGN_MIDDLE:
+ fprintf(stream, "vertical-align: middle ");
+ break;
+ case CSS_VERTICAL_ALIGN_BOTTOM:
+ fprintf(stream, "vertical-align: bottom ");
+ break;
+ case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
+ fprintf(stream, "vertical-align: text-bottom ");
+ break;
+ case CSS_VERTICAL_ALIGN_SET:
+ fprintf(stream, "vertical-align: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* visibility */
+ val = css_computed_visibility(style);
+ switch (val) {
+ case CSS_VISIBILITY_VISIBLE:
+ fprintf(stream, "visibility: visible ");
+ break;
+ case CSS_VISIBILITY_HIDDEN:
+ fprintf(stream, "visibility: hidden ");
+ break;
+ case CSS_VISIBILITY_COLLAPSE:
+ fprintf(stream, "visibility: collapse ");
+ break;
+ default:
+ break;
+ }
+
+ /* white-space */
+ val = css_computed_white_space(style);
+ switch (val) {
+ case CSS_WHITE_SPACE_NORMAL:
+ fprintf(stream, "white-space: normal ");
+ break;
+ case CSS_WHITE_SPACE_PRE:
+ fprintf(stream, "white-space: pre ");
+ break;
+ case CSS_WHITE_SPACE_NOWRAP:
+ fprintf(stream, "white-space: nowrap ");
+ break;
+ case CSS_WHITE_SPACE_PRE_WRAP:
+ fprintf(stream, "white-space: pre-wrap ");
+ break;
+ case CSS_WHITE_SPACE_PRE_LINE:
+ fprintf(stream, "white-space: pre-line ");
+ break;
+ default:
+ break;
+ }
+
+ /* width */
+ val = css_computed_width(style, &len1, &unit1);
+ switch (val) {
+ case CSS_WIDTH_AUTO:
+ fprintf(stream, "width: auto ");
+ break;
+ case CSS_WIDTH_SET:
+ fprintf(stream, "width: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* word-spacing */
+ val = css_computed_word_spacing(style, &len1, &unit1);
+ switch (val) {
+ case CSS_WORD_SPACING_NORMAL:
+ fprintf(stream, "word-spacing: normal ");
+ break;
+ case CSS_WORD_SPACING_SET:
+ fprintf(stream, "word-spacing: ");
+
+ dump_css_unit(stream, len1, unit1);
+
+ fprintf(stream, " ");
+ break;
+ default:
+ break;
+ }
+
+ /* z-index */
+ val = css_computed_z_index(style, &zindex);
+ switch (val) {
+ case CSS_Z_INDEX_AUTO:
+ fprintf(stream, "z-index: auto ");
+ break;
+ case CSS_Z_INDEX_SET:
+ fprintf(stream, "z-index: %d ", zindex);
+ break;
+ default:
+ break;
+ }
+
+ fprintf(stream, "}");
+}
+
+/******************************************************************************
+ * Helper functions for nscss_dump_computed_style *
+ ******************************************************************************/
+
+/**
+ * Dump a fixed point value to the stream in a textual form.
+ *
+ * \param stream Stream to write to
+ * \param f Value to write
+ */
+void dump_css_fixed(FILE *stream, css_fixed f)
+{
+#define NSCSS_ABS(x) (uint32_t)((x) < 0 ? -(x) : (x))
+ uint32_t uintpart = FIXTOINT(NSCSS_ABS(f));
+ /* + 500 to ensure round to nearest (division will truncate) */
+ uint32_t fracpart = ((NSCSS_ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10);
+#undef NSCSS_ABS
+
+ fprintf(stream, "%s%d.%03d", f < 0 ? "-" : "", uintpart, fracpart);
+}
+
+/**
+ * Dump a numeric value to the stream in a textual form.
+ *
+ * \param stream Stream to write to
+ * \param val Value to write
+ */
+void dump_css_number(FILE *stream, css_fixed val)
+{
+ if (INTTOFIX(FIXTOINT(val)) == val)
+ fprintf(stream, "%d", FIXTOINT(val));
+ else
+ dump_css_fixed(stream, val);
+}
+
+/**
+ * Dump a dimension to the stream in a textual form.
+ *
+ * \param stream Stream to write to
+ * \param val Value to write
+ * \param unit Unit to write
+ */
+void dump_css_unit(FILE *stream, css_fixed val, css_unit unit)
+{
+ dump_css_number(stream, val);
+
+ switch (unit) {
+ case CSS_UNIT_PX:
+ fprintf(stream, "px");
+ break;
+ case CSS_UNIT_EX:
+ fprintf(stream, "ex");
+ break;
+ case CSS_UNIT_EM:
+ fprintf(stream, "em");
+ break;
+ case CSS_UNIT_IN:
+ fprintf(stream, "in");
+ break;
+ case CSS_UNIT_CM:
+ fprintf(stream, "cm");
+ break;
+ case CSS_UNIT_MM:
+ fprintf(stream, "mm");
+ break;
+ case CSS_UNIT_PT:
+ fprintf(stream, "pt");
+ break;
+ case CSS_UNIT_PC:
+ fprintf(stream, "pc");
+ break;
+ case CSS_UNIT_PCT:
+ fprintf(stream, "%%");
+ break;
+ case CSS_UNIT_DEG:
+ fprintf(stream, "deg");
+ break;
+ case CSS_UNIT_GRAD:
+ fprintf(stream, "grad");
+ break;
+ case CSS_UNIT_RAD:
+ fprintf(stream, "rad");
+ break;
+ case CSS_UNIT_MS:
+ fprintf(stream, "ms");
+ break;
+ case CSS_UNIT_S:
+ fprintf(stream, "s");
+ break;
+ case CSS_UNIT_HZ:
+ fprintf(stream, "Hz");
+ break;
+ case CSS_UNIT_KHZ:
+ fprintf(stream, "kHz");
+ break;
+ }
+}
+
diff --git a/css/dump.h b/css/dump.h
new file mode 100644
index 000000000..25d283e9e
--- /dev/null
+++ b/css/dump.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_CSS_DUMP_H_
+#define NETSURF_CSS_DUMP_H_
+
+#include "css/css.h"
+
+void nscss_dump_computed_style(FILE *stream, const css_computed_style *style);
+
+#endif
diff --git a/css/internal.c b/css/internal.c
new file mode 100644
index 000000000..fd22af628
--- /dev/null
+++ b/css/internal.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include "css/internal.h"
+
+#include "utils/url.h"
+
+/**
+ * URL resolution callback for libcss
+ *
+ * \param pw Resolution context
+ * \param ctx Dictionary to intern result in
+ * \param base Base URI
+ * \param rel Relative URL
+ * \param abs Pointer to location to receive resolved URL
+ * \return CSS_OK on success,
+ * CSS_NOMEM on memory exhaustion,
+ * CSS_INVALID if resolution failed.
+ */
+css_error nscss_resolve_url(void *pw, lwc_context *ctx,
+ const char *base, lwc_string *rel, lwc_string **abs)
+{
+ lwc_error lerror;
+ char *rel_url, *abs_url, *norm_url;
+ url_func_result res;
+
+ /* Copy relative URL and ensure it's NUL terminated */
+ rel_url = malloc(lwc_string_length(rel) + 1);
+ if (rel_url == NULL)
+ return CSS_NOMEM;
+
+ memcpy(rel_url, lwc_string_data(rel), lwc_string_length(rel));
+ rel_url[lwc_string_length(rel)] = '\0';
+
+ /* Resolve URI */
+ res = url_join(rel_url, base, &abs_url);
+ if (res != URL_FUNC_OK) {
+ free(rel_url);
+ return res == URL_FUNC_NOMEM ? CSS_NOMEM : CSS_INVALID;
+ }
+
+ free(rel_url);
+
+ /* Normalise it */
+ res = url_normalize(abs_url, &norm_url);
+ if (res != URL_FUNC_OK) {
+ free(abs_url);
+ return res == URL_FUNC_NOMEM ? CSS_NOMEM : CSS_INVALID;
+ }
+
+ free(abs_url);
+
+ /* Intern it */
+ lerror = lwc_context_intern(ctx, norm_url, strlen(norm_url), abs);
+ if (lerror != lwc_error_ok) {
+ *abs = NULL;
+ free(norm_url);
+ return lerror == lwc_error_oom ? CSS_NOMEM : CSS_INVALID;
+ }
+
+ free(norm_url);
+
+ return CSS_OK;
+}
+
diff --git a/css/internal.h b/css/internal.h
new file mode 100644
index 000000000..e675a4876
--- /dev/null
+++ b/css/internal.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_CSS_INTERNAL_H_
+#define NETSURF_CSS_INTERNAL_H_
+
+#include "css/css.h"
+
+css_error nscss_resolve_url(void *pw, lwc_context *ctx,
+ const char *base, lwc_string *rel, lwc_string **abs);
+
+#endif
diff --git a/css/makeenum b/css/makeenum
deleted file mode 100755
index 54c513d06..000000000
--- a/css/makeenum
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/perl -W
-#
-# This file is part of NetSurf, http://netsurf-browser.org/
-# Licensed under the GNU General Public License,
-# http://www.opensource.org/licenses/gpl-license
-# Copyright 2003 James Bursa <bursa@users.sourceforge.net>
-#
-
-$out = shift or die "usage: makeenum leafname";
-
-open H, ">$out.h" or die "open 'enum.h' failed";
-open C, ">$out.c" or die "open 'enum.c' failed";
-
-print C "#include <strings.h>\n";
-print C "#include \"$out.h\"\n\n";
-
-while (<>) {
- chomp;
- @enum = split;
- $name = shift @enum;
-
- @uc_enum = map uc, @enum;
- s/-/_/g foreach (@uc_enum);
- $uc_name = uc $name;
-
- print H "extern const char * const ${name}_name[];\n";
- print H "typedef enum {\n ${uc_name}_";
- print H join ",\n ${uc_name}_", @uc_enum;
- print H ",\n ${uc_name}_UNKNOWN";
- print H ",\n ${uc_name}_NOT_SET\n";
- print H "} $name;\n";
- print H "$name ${name}_parse(const char * const s, int length);\n\n";
-
- print C "/**\n * $name\n */\n\n";
- print C "const char * const ${name}_name[] = {\n \"";
- print C join "\",\n \"", @enum;
- print C "\"\n};\n\n";
- print C "$name ${name}_parse(const char * const s, int length)\n{\n";
- foreach $x (@enum) {
- $ux = uc $x;
- $ux =~ s/-/_/g;
- $len = length $x;
- print C " if (length == $len && strncasecmp(s, \"$x\", $len) == 0) return ${uc_name}_$ux;\n";
- }
- print C " return ${uc_name}_UNKNOWN;\n}\n\n";
-}
diff --git a/css/parser.y b/css/parser.y
deleted file mode 100644
index 77ab604a5..000000000
--- a/css/parser.y
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * This file is part of NetSurf, http://netsurf-browser.org/
- * Licensed under the GNU General Public License,
- * http://www.opensource.org/licenses/gpl-license
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- */
-
-/** \file
-
-CSS parser using the lemon parser generator.
-
-see CSS2.1 Specification, chapter 4
-http://www.w3.org/TR/CSS21/syndata.html
-
-stylesheet : [ CDO | CDC | S | statement ]*;
-statement : ruleset | at-rule;
-at-rule : ATKEYWORD S* any* [ block | ';' S* ];
-block : '{' S* [ any | block | ATKEYWORD S* | ';' S* ]* '}' S*;
-ruleset : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
-selector : any+;
-declaration : DELIM? property S* ':' S* value S*;
-property : IDENT;
-value : [ any | block | ATKEYWORD S* ]+;
-any : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
- | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
- | DASHMATCH | FUNCTION S* any* ')'
- | '(' S* any* ')' | '[' S* any* ']' ] S*;
-
-Note: CDO, CDC will be stripped out by the scanner
-*/
-
-stylesheet ::= ws statement_list.
-
-ws ::= .
-ws ::= ws_1.
-
-ws_1 ::= S.
-ws_1 ::= ws_1 S.
-
-statement_list ::= .
-statement_list ::= statement_list statement.
-
-statement ::= ws_1.
-statement ::= ruleset.
-statement ::= at_rule.
-
-at_rule ::= ATKEYWORD ws any_list block.
-at_rule ::= ATKEYWORD(A) ws any_list(B) SEMI ws.
- { if ((A.length == 7) && (strncasecmp(A.text, "@import", 7) == 0)
- && B && !param->had_ruleset)
- css_atimport(param->stylesheet, B);
- css_free_node(B); }
-
-block ::= LBRACE ws block_body RBRACE ws.
-block_body ::= .
-block_body ::= block_body any ws.
-block_body ::= block_body block.
-block_body ::= block_body ATKEYWORD ws.
-block_body ::= block_body SEMI ws.
-
-ruleset ::= selector_list(A) LBRACE ws declaration_list(B) RBRACE ws.
- { if (A && B) {
- /*param->had_ruleset = true;*/
- css_add_ruleset(param->stylesheet, A, B);
- }
- else
- css_free_selector(A);
- css_free_node(B); }
-ruleset ::= LBRACE declaration_list(A) RBRACE.
- /* this form of ruleset not used in CSS2
- used to parse style attributes (ruleset_only = 1) */
- { if (param->ruleset_only) param->declaration = A;
- else css_free_node(A); }
-ruleset ::= any_list_1(A) LBRACE declaration_list(B) RBRACE.
- { css_free_node(A); css_free_node(B); } /* not CSS2 */
-
-selector_list(A) ::= selector(B) ws.
- { A = B; }
-selector_list(A) ::= selector_list(B) COMMA ws selector(C) ws.
- { if (B && C) {
- C->next = B;
- A = C;
- } else {
- css_free_selector(B);
- css_free_selector(C);
- A = 0;
- } }
-
-selector(A) ::= simple_selector(B).
- { A = B; }
-selector(A) ::= selector(B) css_combinator(C) simple_selector(D).
- { if (B && D) {
- D->combiner = B;
- D->comb = C;
- D->specificity += B->specificity;
- A = D;
- } else {
- css_free_selector(B);
- css_free_selector(D);
- A = 0;
- } }
-
-css_combinator(A) ::= ws PLUS ws.
- { A = CSS_COMB_PRECEDED; }
-css_combinator(A) ::= ws GT ws.
- { A = CSS_COMB_PARENT; }
-css_combinator(A) ::= ws_1.
- { A = CSS_COMB_ANCESTOR; }
-
-simple_selector(A) ::= element_name(B) detail_list(C).
- { if (C && (A = css_new_selector(CSS_SELECTOR_ELEMENT,
- B.text, B.length))) {
- A->detail = C;
- A->specificity = 1 + C->specificity;
- } else {
- param->memory_error = true;
- css_free_selector(C);
- A = 0;
- } }
-simple_selector(A) ::= element_name(B).
- { if ((A = css_new_selector(CSS_SELECTOR_ELEMENT,
- B.text, B.length)))
- A->specificity = CSS_SPECIFICITY_ELEMENT;
- else
- param->memory_error = true;
- }
-simple_selector(A) ::= detail_list(C).
- { if (C && (A = css_new_selector(CSS_SELECTOR_ELEMENT, 0, 0))) {
- A->detail = C;
- A->specificity = C->specificity;
- } else {
- param->memory_error = true;
- css_free_selector(C);
- A = 0;
- } }
-
-element_name(A) ::= IDENT(B).
- { A = B; }
-element_name(A) ::= ASTERISK.
- { A.text = 0; }
-
-detail_list(A) ::= detail(B).
- { A = B; }
-detail_list(A) ::= detail(B) detail_list(C).
- { if (B && C) {
- B->specificity += C->specificity;
- B->next = C;
- A = B;
- } else {
- css_free_selector(B);
- css_free_selector(C);
- A = 0;
- } }
-
-detail(A) ::= HASH(B).
- { A = css_new_selector(CSS_SELECTOR_ID, B.text+1, B.length-1);
- if (A) A->specificity = CSS_SPECIFICITY_ID;
- else param->memory_error = true; }
-detail(A) ::= DOT IDENT(B).
- { A = css_new_selector(CSS_SELECTOR_CLASS, B.text, B.length);
- if (A) A->specificity = CSS_SPECIFICITY_CLASS;
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB, B.text, B.length);
- if (A) A->specificity = CSS_SPECIFICITY_ATTR;
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws EQUALS ws IDENT(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_EQ, B.text, B.length);
- if (A) { A->data2 = C.text; A->data2_length = C.length;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws EQUALS ws STRING(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_EQ, B.text, B.length);
- if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws INCLUDES ws IDENT(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_INC, B.text, B.length);
- if (A) { A->data2 = C.text; A->data2_length = C.length;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws INCLUDES ws STRING(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_INC, B.text, B.length);
- if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws DASHMATCH ws IDENT(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_DM, B.text, B.length);
- if (A) { A->data2 = C.text; A->data2_length = C.length;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws DASHMATCH ws STRING(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_DM, B.text, B.length);
- if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws PREFIX ws IDENT(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_PRE, B.text, B.length);
- if (A) { A->data2 = C.text; A->data2_length = C.length;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws PREFIX ws STRING(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_PRE, B.text, B.length);
- if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws SUFFIX ws IDENT(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUF, B.text, B.length);
- if (A) { A->data2 = C.text; A->data2_length = C.length;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws SUFFIX ws STRING(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUF, B.text, B.length);
- if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws SUBSTR ws IDENT(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUB, B.text, B.length);
- if (A) { A->data2 = C.text; A->data2_length = C.length;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= LBRAC ws IDENT(B) ws SUBSTR ws STRING(C) ws RBRAC.
- { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUB, B.text, B.length);
- if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
- A->specificity = CSS_SPECIFICITY_ATTR; }
- else param->memory_error = true; }
-detail(A) ::= COLON IDENT(B).
- { if (B.length == 4 && strncasecmp(B.text, "link", 4) == 0) {
- A = css_new_selector(CSS_SELECTOR_ATTRIB, "href", 4);
- if (A) A->specificity = CSS_SPECIFICITY_ATTR;
- else param->memory_error = true;
- } else {
- A = css_new_selector(CSS_SELECTOR_PSEUDO, B.text, B.length);
- if (A) A->specificity = CSS_SPECIFICITY_ATTR;
- else param->memory_error = true;
- } }
-detail(A) ::= COLON FUNCTION(B) ws IDENT ws RPAREN.
- { A = css_new_selector(CSS_SELECTOR_PSEUDO, B.text, B.length);
- if (A) A->specificity = CSS_SPECIFICITY_ATTR;
- else param->memory_error = true; }
-detail(A) ::= COLON FUNCTION(B) ws RPAREN.
- { A = css_new_selector(CSS_SELECTOR_PSEUDO, B.text, B.length);
- if (A) A->specificity = CSS_SPECIFICITY_ATTR;
- else param->memory_error = true; }
-
-declaration_list(A) ::= .
- { A = 0; }
-declaration_list(A) ::= declaration(B).
- { A = B; }
-declaration_list(A) ::= declaration_list(B) SEMI.
- { A = B; }
-declaration_list(A) ::= declaration(B) SEMI ws declaration_list(C).
- { if (B) { B->next = C; A = B; } else { A = C; } }
-
-declaration ::= DELIM property ws COLON ws value ws.
- /* ignore this as it has no meaning in CSS2 */
-
-declaration(A) ::= property(B) ws COLON ws value(C) ws.
- { if (C && (A = css_new_node(param->stylesheet,
- CSS_NODE_DECLARATION,
- B.text, B.length))) {
- A->value = C;
- } else {
- param->memory_error = true;
- css_free_node(C);
- A = 0;
- } }
-declaration(A) ::= any_list_1(B). /* malformed declaration: ignore */
- { A = 0; css_free_node(B); }
-
-property(A) ::= IDENT(B).
- { A = B; }
-
-value(A) ::= any(B) ws.
- { A = B; }
-value(A) ::= any(B) ws value(C).
- { if (B && C) { B->next = C; A = B; }
- else { css_free_node(B); css_free_node(C); A = 0; } }
-value(A) ::= value(B) ws block.
- { A = B; }
-value(A) ::= value(B) ws ATKEYWORD ws.
- { A = B; }
-
-
-any_list(A) ::= .
- { A = 0; }
-any_list(A) ::= any(B) ws any_list(C).
- { if (B) { B->next = C; A = B; }
- else { css_free_node(B); css_free_node(C); A = 0; } }
-any_list_1(A) ::= any(B) ws any_list(C).
- { if (B) { B->next = C; A = B; }
- else { css_free_node(B); css_free_node(C); A = 0; } }
-any(A) ::= IDENT(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_IDENT,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= NUMBER(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_NUMBER,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= PERCENTAGE(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_PERCENTAGE,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= DIMENSION(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_DIMENSION,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= STRING(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_STRING,
- B.text + 1, B.length - 2);
- if (!A) param->memory_error = true; }
-any(A) ::= DELIM(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_DELIM,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= URI(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_URI,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= HASH(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_HASH,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= UNICODE_RANGE(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_UNICODE_RANGE,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-any(A) ::= INCLUDES.
- { A = css_new_node(param->stylesheet, CSS_NODE_INCLUDES,
- 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= FUNCTION(B) ws any_list(C) RPAREN.
- { if ((A = css_new_node(param->stylesheet, CSS_NODE_FUNCTION,
- B.text, B.length)))
- A->value = C;
- else {
- param->memory_error = true;
- css_free_node(C);
- A = 0;
- } }
-any(A) ::= DASHMATCH.
- { A = css_new_node(param->stylesheet, CSS_NODE_DASHMATCH,
- 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= PREFIX.
- { A = css_new_node(param->stylesheet, CSS_NODE_PREFIX,
- 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= SUFFIX.
- { A = css_new_node(param->stylesheet, CSS_NODE_SUFFIX,
- 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= SUBSTR.
- { A = css_new_node(param->stylesheet, CSS_NODE_SUBSTR,
- 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= COLON.
- { A = css_new_node(param->stylesheet, CSS_NODE_COLON, 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= COMMA.
- { A = css_new_node(param->stylesheet, CSS_NODE_COMMA, 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= DOT.
- { A = css_new_node(param->stylesheet, CSS_NODE_DOT, 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= PLUS.
- { A = css_new_node(param->stylesheet, CSS_NODE_PLUS, 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= GT.
- { A = css_new_node(param->stylesheet, CSS_NODE_GT, 0, 0);
- if (!A) param->memory_error = true; }
-any(A) ::= LPAREN ws any_list(B) RPAREN.
- { if ((A = css_new_node(param->stylesheet, CSS_NODE_PAREN,
- 0, 0)))
- A->value = B;
- else {
- param->memory_error = true;
- css_free_node(B);
- A = 0;
- } }
-any(A) ::= LBRAC ws any_list(B) RBRAC.
- { if ((A = css_new_node(param->stylesheet, CSS_NODE_BRAC,
- 0, 0)))
- A->value = B;
- else {
- param->memory_error = true;
- css_free_node(B);
- A = 0;
- } }
-any(A) ::= ASTERISK(B).
- { A = css_new_node(param->stylesheet, CSS_NODE_DELIM,
- B.text, B.length);
- if (!A) param->memory_error = true; }
-
-
-/* lemon directives */
-
-%extra_argument { struct css_parser_params *param }
-%include {
-#include <assert.h>
-#include <string.h>
-#include <strings.h>
-#define CSS_INTERNALS
-#include "css/css.h"
-#include "utils/utils.h" }
-%name css_parser_
-
-%token_type { struct css_parser_token }
-
-%type selector_list { struct css_selector * }
-%type selector { struct css_selector * }
-%type css_combinator { css_combinator }
-%type simple_selector { struct css_selector * }
-%type detail_list { struct css_selector * }
-%type detail { struct css_selector * }
-%type declaration_list { struct css_node * }
-%type declaration { struct css_node * }
-%type value { struct css_node * }
-%type any_list { struct css_node * }
-%type any_list_1 { struct css_node * }
-%type any { struct css_node * }
-
-%destructor selector_list { css_free_selector($$); }
-%destructor selector { css_free_selector($$); }
-%destructor simple_selector { css_free_selector($$); }
-%destructor detail_list { css_free_selector($$); }
-%destructor detail { css_free_selector($$); }
-%destructor declaration_list { css_free_node($$); }
-%destructor declaration { css_free_node($$); }
-%destructor value { css_free_node($$); }
-%destructor any_list { css_free_node($$); }
-%destructor any_list_1 { css_free_node($$); }
-%destructor any { css_free_node($$); }
-
-%left COLON COMMA GT HASH LBRAC PLUS.
-%left DOT.
-%left IDENT.
-%left LBRACE.
-
-%syntax_error { param->syntax_error = true; }
diff --git a/css/ruleset.c b/css/ruleset.c
deleted file mode 100644
index 46bc5e2a5..000000000
--- a/css/ruleset.c
+++ /dev/null
@@ -1,3152 +0,0 @@
-/*
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * CSS ruleset parsing.
- *
- * This file implements the last stage of CSS parsing. It converts trees of
- * struct css_node produced by the parser into struct style, and adds them to a
- * stylesheet.
- *
- * This code is complicated by the CSS error handling rules. According to
- * CSS 2.1 4.2 "Illegal values", the whole of a declaration must be legal for
- * any of it to be used.
- */
-
-#define _GNU_SOURCE /* for strndup */
-#include <assert.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <math.h>
-#define CSS_INTERNALS
-#include "css/css.h"
-#include "content/content.h"
-#include "desktop/options.h"
-#define NDEBUG
-#include "utils/log.h"
-#undef NDEBUG
-#include "utils/url.h"
-#include "utils/utils.h"
-
-static bool css_compare_selectors(const struct css_selector *n0,
- const struct css_selector *n1);
-static int parse_length(struct css_length * const length,
- const struct css_node * const v, bool non_negative);
-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);
-static void parse_background_color(struct css_style * const s, const struct css_node * const v);
-static void parse_background_image(struct css_style * const s,
- const struct css_node * const v);
-static bool css_background_image_parse(const struct css_node *v,
- css_background_image_type *type, char **uri);
-static struct css_background_entry *css_background_lookup(
- const struct css_node *v);
-static void parse_background_position(struct css_style * const s,
- const struct css_node * const v);
-static bool css_background_position_parse(const struct css_node **node,
- struct css_background_position *horz,
- struct css_background_position *vert);
-static void parse_background_repeat(struct css_style * const s, const struct css_node * const v);
-static void parse_border(struct css_style * const s, const struct css_node * v);
-static void parse_border_bottom(struct css_style * const s, const struct css_node * v);
-static void parse_border_bottom_color(struct css_style * const s, const struct css_node * v);
-static void parse_border_bottom_style(struct css_style * const s, const struct css_node * v);
-static void parse_border_bottom_width(struct css_style * const s, const struct css_node * v);
-static void parse_border_collapse(struct css_style * const s, const struct css_node * v);
-static void parse_border_color(struct css_style * const s, const struct css_node * v);
-static void parse_border_color_side(struct css_style * const s,
- const struct css_node * const v, unsigned int i);
-static void parse_border_left(struct css_style * const s, const struct css_node * v);
-static void parse_border_left_color(struct css_style * const s, const struct css_node * v);
-static void parse_border_left_style(struct css_style * const s, const struct css_node * v);
-static void parse_border_left_width(struct css_style * const s, const struct css_node * v);
-static void parse_border_right(struct css_style * const s, const struct css_node * v);
-static void parse_border_right_color(struct css_style * const s, const struct css_node * v);
-static void parse_border_right_style(struct css_style * const s, const struct css_node * v);
-static void parse_border_right_width(struct css_style * const s, const struct css_node * v);
-static void parse_border_side(struct css_style * const s,
- const struct css_node *v, unsigned int i);
-static void parse_border_spacing(struct css_style * const s, const struct css_node * v);
-static void parse_border_style(struct css_style * const s, const struct css_node * v);
-static void parse_border_style_side(struct css_style * const s,
- const struct css_node * const v, unsigned int i);
-static void parse_border_top(struct css_style * const s, const struct css_node * v);
-static void parse_border_top_color(struct css_style * const s, const struct css_node * v);
-static void parse_border_top_style(struct css_style * const s, const struct css_node * v);
-static void parse_border_top_width(struct css_style * const s, const struct css_node * v);
-static void parse_border_width(struct css_style * const s, const struct css_node * v);
-static void parse_border_width_side(struct css_style * const s,
- const struct css_node * const v, unsigned int i);
-static void parse_bottom(struct css_style * const s, const struct css_node * v);
-static void parse_caption_side(struct css_style * const s, const struct css_node * v);
-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);
-static void parse_empty_cells(struct css_style * const s, const struct css_node * v);
-static void parse_float(struct css_style * const s, const struct css_node * const v);
-static void parse_font(struct css_style * const s, const struct css_node * v);
-static void parse_font_family(struct css_style * const s, const struct css_node * v);
-static void parse_font_size(struct css_style * const s, const struct css_node * const v);
-static void parse_font_style(struct css_style * const s, const struct css_node * const v);
-static void parse_font_variant(struct css_style * const s, const struct css_node * const v);
-static void parse_font_weight(struct css_style * const s, const struct css_node * const v);
-static void parse_height(struct css_style * const s, const struct css_node * const v);
-static void parse_left(struct css_style * const s, const struct css_node * v);
-static void parse_letter_spacing(struct css_style * const s, const struct css_node * v);
-static void parse_line_height(struct css_style * const s, const struct css_node * const v);
-static void parse_list_style(struct css_style * const s, const struct css_node * v);
-static void parse_list_style_image(struct css_style * const s, const struct css_node * v);
-static bool css_list_style_image_parse(const struct css_node *v,
- css_list_style_image_type *type, char **uri);
-static void parse_list_style_position(struct css_style * const s, const struct css_node * v);
-static void parse_list_style_type(struct css_style * const s, const struct css_node * v);
-static void parse_margin(struct css_style * const s, const struct css_node * const v);
-static void parse_margin_bottom(struct css_style * const s, const struct css_node * const v);
-static void parse_margin_left(struct css_style * const s, const struct css_node * const v);
-static void parse_margin_right(struct css_style * const s, const struct css_node * const v);
-static void parse_margin_top(struct css_style * const s, const struct css_node * const v);
-static void parse_margin_side(struct css_style * const s, const struct css_node * const v,
- unsigned int i);
-static void parse_max_height(struct css_style *const s, const struct css_node * v);
-static void parse_max_width(struct css_style *const s, const struct css_node * v);
-static void parse_min_height(struct css_style *const s, const struct css_node * v);
-static void parse_min_width(struct css_style *const s, const struct css_node * v);
-static void parse_orphans(struct css_style * const s, const struct css_node * const v);
-static void parse_outline(struct css_style * const s, const struct css_node * v);
-static void parse_outline_color(struct css_style * const s, const struct css_node * const v);
-static void parse_outline_style(struct css_style * const s, const struct css_node * const v);
-static void parse_outline_width(struct css_style * const s, const struct css_node * const v);
-static bool css_outline_width_parse(const struct css_node * v, struct css_border_width * w);
-static void parse_overflow(struct css_style * const s, const struct css_node * const v);
-static void parse_padding(struct css_style * const s, const struct css_node * const v);
-static void parse_padding_bottom(struct css_style * const s, const struct css_node * const v);
-static void parse_padding_left(struct css_style * const s, const struct css_node * const v);
-static void parse_padding_right(struct css_style * const s, const struct css_node * const v);
-static void parse_padding_top(struct css_style * const s, const struct css_node * const v);
-static void parse_padding_side(struct css_style * const s, const struct css_node * const v,
- unsigned int i);
-static void parse_page_break_after(struct css_style * const s, const struct css_node * v);
-static void parse_page_break_before(struct css_style * const s, const struct css_node * v);
-static void parse_page_break_inside(struct css_style * const s, const struct css_node * v);
-static void parse_pos(struct css_style * const s, const struct css_node * v, unsigned int i);
-static void parse_position(struct css_style * const s, const struct css_node * v);
-static void parse_right(struct css_style * const s, const struct css_node * v);
-static void parse_table_layout(struct css_style * const s, const struct css_node * v);
-static void parse_text_align(struct css_style * const s, const struct css_node * const v);
-static void parse_text_decoration(struct css_style * const s, const struct css_node * const v);
-static void parse_text_indent(struct css_style * const s, const struct css_node * const v);
-static void parse_text_transform(struct css_style * const s, const struct css_node * const v);
-static void parse_top(struct css_style * const s, const struct css_node * v);
-static void parse_unicode_bidi(struct css_style * const s, const struct css_node * const v);
-static void parse_vertical_align(struct css_style * const s, const struct css_node * v);
-static void parse_visibility(struct css_style * const s, const struct css_node * const v);
-static void parse_widows(struct css_style * const s, const struct css_node * const v);
-static void parse_width(struct css_style * const s, const struct css_node * const v);
-static void parse_white_space(struct css_style * const s, const struct css_node * const v);
-static void parse_word_spacing(struct css_style * const s, const struct css_node * v);
-static void parse_z_index(struct css_style * const s, const struct css_node * const v);
-static css_text_decoration css_text_decoration_parse(const char * const s,
- int length);
-
-
-/** Invalid hex */
-#define IH 0xffffffff
-/** ASCII to hexadeximal conversion */
-static const unsigned int ascii_to_hex[] = {
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x00 - 0x0f */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x10 - 0x1f */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x20 - 0x2f */
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, IH, IH, IH, IH, IH, IH, /* 0x30 - 0x3f */
- IH, 10, 11, 12, 13, 14, 15, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x40 - 0x4f */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x50 - 0x5f */
- IH, 10, 11, 12, 13, 14, 15, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x60 - 0x6f */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x70 - 0x7f */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x80 - 0x8f */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0x90 - 0x9f */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0xa0 - 0xaf */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0xb0 - 0xbf */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0xc0 - 0xcf */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0xd0 - 0xdf */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, /* 0xe0 - 0xef */
- IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH, IH /* 0xf0 - 0xff */
-};
-
-
-/** An entry in css_property_table. */
-struct css_property_entry {
- const char name[25];
- void (*parse) (struct css_style * const s,
- const struct css_node * const v);
-};
-
-/** Table of property parsers. MUST be sorted by property name. */
-static const struct css_property_entry css_property_table[] = {
- { "background", parse_background },
- { "background-attachment", parse_background_attachment },
- { "background-color", parse_background_color },
- { "background-image", parse_background_image },
- { "background-position", parse_background_position },
- { "background-repeat", parse_background_repeat },
- { "border", parse_border },
- { "border-bottom", parse_border_bottom },
- { "border-bottom-color", parse_border_bottom_color },
- { "border-bottom-style", parse_border_bottom_style },
- { "border-bottom-width", parse_border_bottom_width },
- { "border-collapse", parse_border_collapse },
- { "border-color", parse_border_color },
- { "border-left", parse_border_left },
- { "border-left-color", parse_border_left_color },
- { "border-left-style", parse_border_left_style },
- { "border-left-width", parse_border_left_width },
- { "border-right", parse_border_right },
- { "border-right-color", parse_border_right_color },
- { "border-right-style", parse_border_right_style },
- { "border-right-width", parse_border_right_width },
- { "border-spacing", parse_border_spacing },
- { "border-style", parse_border_style },
- { "border-top", parse_border_top },
- { "border-top-color", parse_border_top_color },
- { "border-top-style", parse_border_top_style },
- { "border-top-width", parse_border_top_width },
- { "border-width", parse_border_width },
- { "bottom", parse_bottom },
- { "caption-side", parse_caption_side },
- { "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 },
- { "empty-cells", parse_empty_cells },
- { "float", parse_float },
- { "font", parse_font },
- { "font-family", parse_font_family },
- { "font-size", parse_font_size },
- { "font-style", parse_font_style },
- { "font-variant", parse_font_variant },
- { "font-weight", parse_font_weight },
- { "height", parse_height },
- { "left", parse_left },
- { "letter-spacing", parse_letter_spacing },
- { "line-height", parse_line_height },
- { "list-style", parse_list_style },
- { "list-style-image", parse_list_style_image },
- { "list-style-position", parse_list_style_position },
- { "list-style-type", parse_list_style_type },
- { "margin", parse_margin },
- { "margin-bottom", parse_margin_bottom },
- { "margin-left", parse_margin_left },
- { "margin-right", parse_margin_right },
- { "margin-top", parse_margin_top },
- { "max-height", parse_max_height },
- { "max-width", parse_max_width },
- { "min-height", parse_min_height },
- { "min-width", parse_min_width },
- { "orphans", parse_orphans },
- { "outline", parse_outline },
- { "outline-color", parse_outline_color },
- { "outline-style", parse_outline_style },
- { "outline-width", parse_outline_width },
- { "overflow", parse_overflow },
- { "padding", parse_padding },
- { "padding-bottom", parse_padding_bottom },
- { "padding-left", parse_padding_left },
- { "padding-right", parse_padding_right },
- { "padding-top", parse_padding_top },
- { "page-break-after", parse_page_break_after },
- { "page-break-before", parse_page_break_before },
- { "page-break-inside", parse_page_break_inside },
- { "position", parse_position },
- { "right", parse_right },
- { "table-layout", parse_table_layout },
- { "text-align", parse_text_align },
- { "text-decoration", parse_text_decoration },
- { "text-indent", parse_text_indent },
- { "text-transform", parse_text_transform },
- { "top", parse_top },
- { "unicode-bidi", parse_unicode_bidi },
- { "vertical-align", parse_vertical_align },
- { "visibility", parse_visibility },
- { "white-space", parse_white_space },
- { "widows", parse_widows },
- { "width", parse_width },
- { "word-spacing", parse_word_spacing },
- { "z-index", parse_z_index }
-};
-
-
-/** An entry in css_colour_table. */
-struct css_colour_entry {
- const char name[21];
- colour col;
-};
-
-/* Table of standard colour names. MUST be sorted by colour name.
- * Note: colour is 0xbbggrr. */
-static const struct css_colour_entry css_colour_table[] = {
- { "aliceblue", 0xfff8f0 },
- { "antiquewhite", 0xd7ebfa },
- { "aqua", 0xffff00 },
- { "aquamarine", 0xd4ff7f },
- { "azure", 0xfffff0 },
- { "beige", 0xdcf5f5 },
- { "bisque", 0xc4e4ff },
- { "black", 0x000000 },
- { "blanchedalmond", 0xcdebff },
- { "blue", 0xff0000 },
- { "blueviolet", 0xe22b8a },
- { "brown", 0x2a2aa5 },
- { "burlywood", 0x87b8de },
- { "cadetblue", 0xa09e5f },
- { "chartreuse", 0x00ff7f },
- { "chocolate", 0x1e69d2 },
- { "coral", 0x507fff },
- { "cornflowerblue", 0xed9564 },
- { "cornsilk", 0xdcf8ff },
- { "crimson", 0x3c14dc },
- { "cyan", 0xffff00 },
- { "darkblue", 0x8b0000 },
- { "darkcyan", 0x8b8b00 },
- { "darkgoldenrod", 0x0b86b8 },
- { "darkgray", 0xa9a9a9 },
- { "darkgreen", 0x006400 },
- { "darkgrey", 0xa9a9a9 },
- { "darkkhaki", 0x6bb7bd },
- { "darkmagenta", 0x8b008b },
- { "darkolivegreen", 0x2f6b55 },
- { "darkorange", 0x008cff },
- { "darkorchid", 0xcc3299 },
- { "darkred", 0x00008b },
- { "darksalmon", 0x7a96e9 },
- { "darkseagreen", 0x8fbc8f },
- { "darkslateblue", 0x8b3d48 },
- { "darkslategray", 0x4f4f2f },
- { "darkslategrey", 0x4f4f2f },
- { "darkturquoise", 0xd1ce00 },
- { "darkviolet", 0xd30094 },
- { "deeppink", 0x9314ff },
- { "deepskyblue", 0xffbf00 },
- { "dimgray", 0x696969 },
- { "dimgrey", 0x696969 },
- { "dodgerblue", 0xff901e },
- { "feldspar", 0x7592d1 }, /* not SVG-1.0 */
- { "firebrick", 0x2222b2 },
- { "floralwhite", 0xf0faff },
- { "forestgreen", 0x228b22 },
- { "fuchsia", 0xff00ff },
- { "gainsboro", 0xdcdcdc },
- { "ghostwhite", 0xfff8f8 },
- { "gold", 0x00d7ff },
- { "goldenrod", 0x20a5da },
- { "gray", 0x808080 },
- { "green", 0x008000 },
- { "greenyellow", 0x2fffad },
- { "grey", 0x808080 },
- { "honeydew", 0xf0fff0 },
- { "hotpink", 0xb469ff },
- { "indianred", 0x5c5ccd },
- { "indigo", 0x82004b },
- { "ivory", 0xf0ffff },
- { "khaki", 0x8ce6f0 },
- { "lavender", 0xfae6e6 },
- { "lavenderblush", 0xf5f0ff },
- { "lawngreen", 0x00fc7c },
- { "lemonchiffon", 0xcdfaff },
- { "lightblue", 0xe6d8ad },
- { "lightcoral", 0x8080f0 },
- { "lightcyan", 0xffffe0 },
- { "lightgoldenrodyellow", 0xd2fafa },
- { "lightgray", 0xd3d3d3 },
- { "lightgreen", 0x90ee90 },
- { "lightgrey", 0xd3d3d3 },
- { "lightpink", 0xc1b6ff },
- { "lightsalmon", 0x7aa0ff },
- { "lightseagreen", 0xaab220 },
- { "lightskyblue", 0xface87 },
- { "lightslateblue", 0xff7084 }, /* not SVG-1.0*/
- { "lightslategray", 0x998877 },
- { "lightslategrey", 0x998877 },
- { "lightsteelblue", 0xdec4b0 },
- { "lightyellow", 0xe0ffff },
- { "lime", 0x00ff00 },
- { "limegreen", 0x32cd32 },
- { "linen", 0xe6f0fa },
- { "magenta", 0xff00ff },
- { "maroon", 0x000080 },
- { "mediumaquamarine", 0xaacd66 },
- { "mediumblue", 0xcd0000 },
- { "mediumorchid", 0xd355ba },
- { "mediumpurple", 0xdb7093 },
- { "mediumseagreen", 0x71b33c },
- { "mediumslateblue", 0xee687b },
- { "mediumspringgreen", 0x9afa00 },
- { "mediumturquoise", 0xccd148 },
- { "mediumvioletred", 0x8515c7 },
- { "midnightblue", 0x701919 },
- { "mintcream", 0xfafff5 },
- { "mistyrose", 0xe1e4ff },
- { "moccasin", 0xb5e4ff },
- { "navajowhite", 0xaddeff },
- { "navy", 0x800000 },
- { "oldlace", 0xe6f5fd },
- { "olive", 0x008080 },
- { "olivedrab", 0x238e6b },
- { "orange", 0x00a5ff },
- { "orangered", 0x0045ff },
- { "orchid", 0xd670da },
- { "palegoldenrod", 0xaae8ee },
- { "palegreen", 0x98fb98 },
- { "paleturquoise", 0xeeeeaf },
- { "palevioletred", 0x9370db },
- { "papayawhip", 0xd5efff },
- { "peachpuff", 0xb9daff },
- { "peru", 0x3f85cd },
- { "pink", 0xcbc0ff },
- { "plum", 0xdda0dd },
- { "powderblue", 0xe6e0b0 },
- { "purple", 0x800080 },
- { "red", 0x0000ff },
- { "rosybrown", 0x8f8fbc },
- { "royalblue", 0xe16941 },
- { "saddlebrown", 0x13458b },
- { "salmon", 0x7280fa },
- { "sandybrown", 0x60a4f4 },
- { "seagreen", 0x578b2e },
- { "seashell", 0xeef5ff },
- { "sienna", 0x2d52a0 },
- { "silver", 0xc0c0c0 },
- { "skyblue", 0xebce87 },
- { "slateblue", 0xcd5a6a },
- { "slategray", 0x908070 },
- { "slategrey", 0x908070 },
- { "snow", 0xfafaff },
- { "springgreen", 0x7fff00 },
- { "steelblue", 0xb48246 },
- { "tan", 0x8cb4d2 },
- { "teal", 0x808000 },
- { "thistle", 0xd8bfd8 },
- { "tomato", 0x4763ff },
- { "transparent", NS_TRANSPARENT },
- { "turquoise", 0xd0e040 },
- { "violet", 0xee82ee },
- { "violetred", 0x9020d0 }, /* not SVG-1.0*/
- { "wheat", 0xb3def5 },
- { "white", 0xffffff },
- { "whitesmoke", 0xf5f5f5 },
- { "yellow", 0x00ffff },
- { "yellowgreen", 0x32cd9a },
-};
-
-
-/** An entry in css_font_size_table. */
-struct css_font_size_entry {
- const char name[10];
- float size;
-};
-
-/** Table of font sizes. MUST be sorted by name. */
-#define SIZE_FACTOR 1.2
-static const struct css_font_size_entry css_font_size_table[] = {
- { "large", 1.0 * SIZE_FACTOR },
- { "medium", 1.0 },
- { "small", 1.0 / SIZE_FACTOR },
- { "x-large", 1.0 * SIZE_FACTOR * SIZE_FACTOR },
- { "x-small", 1.0 / (SIZE_FACTOR * SIZE_FACTOR) },
- { "xx-large", 1.0 * SIZE_FACTOR * SIZE_FACTOR * SIZE_FACTOR },
- { "xx-small", 1.0 / (SIZE_FACTOR * SIZE_FACTOR * SIZE_FACTOR) },
-};
-
-
-/**
- * Add a ruleset to a stylesheet.
- */
-
-void css_add_ruleset(struct content *c,
- struct css_selector *selector,
- struct css_node *declaration)
-{
- bool found;
- struct css_stylesheet *stylesheet = c->data.css.css;
- struct css_selector *n, *sel, *next_sel, *prev;
- struct css_style *style;
- unsigned int hash;
-
- for (sel = selector; sel != 0; sel = next_sel) {
- next_sel = sel->next;
-
- /* check if this selector is already present */
- found = false;
- prev = 0;
- hash = css_hash(sel->data, sel->data_length);
- /* selectors are ordered by specificity in the hash chain */
- for (n = stylesheet->rule[hash];
- n && n->specificity < sel->specificity;
- n = n->next)
- prev = n;
- for ( ; n && n->specificity == sel->specificity;
- n = n->next) {
- prev = n;
- if (css_compare_selectors(sel, n)) {
- found = true;
- break;
- }
- }
- if (!found) {
- /* not present: construct a new struct css_style */
- LOG(("constructing new style"));
- style = css_duplicate_style(&css_empty_style);
- if (!style) {
- /** \todo report to user */
- css_free_selector(sel);
- return;
- }
- sel->style = style;
- sel->next = n;
- if (prev)
- prev->next = sel;
- else
- stylesheet->rule[hash] = sel;
- c->size += sizeof(*style);
- } else {
- /* already exists: augument existing style */
- LOG(("augumenting existing style"));
- style = n->style;
- sel->next = 0;
- css_free_selector(sel);
- }
-
- /* fill in the declarations */
- css_add_declarations(style, declaration);
- }
-}
-
-
-/**
- * Add declarations to a style.
- */
-
-void css_add_declarations(struct css_style *style, struct css_node *declaration)
-{
- char name[25]; /* this must be the same length as p->name */
- struct css_node *n;
- for (n = declaration; n != 0; n = n->next) {
- struct css_property_entry *p;
- assert(n->type == CSS_NODE_DECLARATION && n->data && n->value);
- if (24 < n->data_length)
- continue;
- strncpy(name, n->data, n->data_length);
- name[n->data_length] = 0;
- p = bsearch(name, css_property_table,
- sizeof css_property_table /
- sizeof css_property_table[0],
- sizeof css_property_table[0],
- (int (*)(const void *, const void *))
- strcasecmp);
- if (p == 0)
- continue;
- p->parse(style, n->value);
- }
-}
-
-
-/**
- * Compare two css_selectors.
- */
-
-bool css_compare_selectors(const struct css_selector *n0,
- const struct css_selector *n1)
-{
- struct css_selector *m0, *m1;
- unsigned int count0 = 0, count1 = 0;
-
- /* compare element name */
- if (!((n0->data == 0 && n1->data == 0) ||
- (n0->data != 0 && n1->data != 0 &&
- n0->data_length == n1->data_length &&
- strncmp(n0->data, n1->data, n0->data_length) == 0)))
- return false;
-
- if (n0->comb != n1->comb)
- return false;
-
- /* compare classes and ids */
- for (m0 = n0->detail; m0 != 0; m0 = m0->next)
- count0++;
- for (m1 = n1->detail; m1 != 0; m1 = m1->next)
- count1++;
- if (count0 != count1)
- return false;
- for (m0 = n0->detail; m0 != 0; m0 = m0->next) {
- bool found = false;
- for (m1 = n1->detail; m1 != 0; m1 = m1->next) {
- /* TODO: should this be case sensitive for IDs? */
- if (m0->type == m1->type &&
- m0->data_length == m1->data_length &&
- strncasecmp(m0->data, m1->data,
- m0->data_length) == 0 &&
- ((m0->data2 == 0 && m1->data2 == 0) ||
- (m0->data2_length == m1->data2_length &&
- strncasecmp(m0->data2, m1->data2,
- m0->data2_length) == 0))) {
- found = true;
- break;
- }
- }
- if (!found)
- return false;
- }
-
- /* compare ancestors */
- if (n0->comb == CSS_COMB_NONE)
- return true;
-
- return css_compare_selectors(n0->combiner, n1->combiner);
-}
-
-
-/*
- * Property parsers.
- */
-
-int parse_length(struct css_length * const length,
- const struct css_node * const v, bool non_negative)
-{
- css_unit u;
- float value;
- int num_length;
-
- if (v->type == CSS_NODE_NUMBER && fabs(atof(v->data)) < 0.0001) {
- length->unit = CSS_UNIT_PX;
- length->value = 0;
- return 0;
- }
-
- if (v->type != CSS_NODE_DIMENSION && v->type != CSS_NODE_NUMBER)
- return 1;
-
- num_length = strspn(v->data, "0123456789+-.");
-
- if (v->type == CSS_NODE_DIMENSION) {
- u = css_unit_parse(v->data + num_length,
- v->data_length - num_length);
- if (u == CSS_UNIT_UNKNOWN) {
- return 1;
- }
- } else {
- u = CSS_UNIT_PX;
- }
- value = atof(v->data);
- if (non_negative && value < 0)
- return 1;
- length->unit = u;
- length->value = value;
- return 0;
-}
-
-
-colour named_colour(const char *name)
-{
- struct css_colour_entry *col;
- int length;
-
- col = bsearch(name, css_colour_table,
- sizeof css_colour_table / sizeof css_colour_table[0],
- sizeof css_colour_table[0],
- (int (*)(const void *, const void *)) strcasecmp);
- if (col != 0)
- return col->col;
-
- /* A common error is the omission of the '#' from the
- * start of a colour specified in #rrggbb or #rgb format.
- * This attempts to detect and recover from this.
- */
- length = strlen(name);
- if ((length == 3) || (length == 6))
- return hex_colour(name, length);
- return CSS_COLOR_NONE;
-}
-
-
-colour parse_colour(const struct css_node * const v)
-{
- colour c = CSS_COLOR_NONE;
- struct css_colour_entry *col;
- char colour_name[21];
-
- switch (v->type) {
- case CSS_NODE_HASH:
- if ((v->data_length == 4) || (v->data_length == 7))
- c = hex_colour(v->data + 1, v->data_length - 1);
- break;
-
- case CSS_NODE_FUNCTION:
- if (v->data_length == 4 &&
- strncasecmp(v->data, "rgb", 3) == 0)
- c = css_parse_rgb(v->value);
- break;
-
- case CSS_NODE_IDENT:
- if (20 < v->data_length)
- break;
- strncpy(colour_name, v->data, v->data_length);
- colour_name[v->data_length] = 0;
- col = bsearch(colour_name, css_colour_table,
- sizeof css_colour_table /
- sizeof css_colour_table[0],
- sizeof css_colour_table[0],
- (int (*)(const void *, const void *))
- strcasecmp);
- if (col != 0)
- c = col->col;
- break;
-
- default:
- break;
- }
-
- /* Hex colour values without a preceding # are invalid but it is a
- * common omission that other browsers cater for. */
- if (c == CSS_COLOR_NONE && (v->type == CSS_NODE_DELIM ||
- v->type == CSS_NODE_IDENT || v->type == CSS_NODE_NUMBER ||
- v->type == CSS_NODE_DIMENSION)) {
- if ((v->data_length == 3) || (v->data_length == 6))
- return hex_colour(v->data, v->data_length);
- }
- return c;
-}
-
-
-/**
- * Parse an RGB value in hexadecimal notation.
- */
-colour hex_colour(const char *text, int length)
-{
- colour c;
-
- /* parse RGB */
- if (length == 3) {
- c = ascii_to_hex[(int)text[0]] | (ascii_to_hex[(int)text[1]] << 8) |
- (ascii_to_hex[(int)text[2]] << 16);
- if (c & (0xff << 24))
- return CSS_COLOR_NONE;
- return c | (c << 4);
- }
-
- /* parse RRGGBB */
- if (length == 6) {
- c = ascii_to_hex[(int)text[1]] | (ascii_to_hex[(int)text[0]] << 4) |
- (ascii_to_hex[(int)text[3]] << 8) | (ascii_to_hex[(int)text[2]] << 12) |
- (ascii_to_hex[(int)text[5]] << 16) | (ascii_to_hex[(int)text[4]] << 20);
- if (c & (0xff << 24))
- return CSS_COLOR_NONE;
- return c;
- }
- return CSS_COLOR_NONE;
-}
-
-
-/**
- * Parse an RGB value in functional notation.
- */
-
-colour css_parse_rgb(struct css_node *v)
-{
- unsigned int i;
- int c[3];
-
- /* we expect exactly the nodes
- * X COMMA X COMMA X
- * where X is NUMBER or PERCENTAGE
- */
-
- for (i = 0; i != 3; i++) {
- if (!v)
- return CSS_COLOR_NONE;
- if (v->type == CSS_NODE_NUMBER)
- c[i] = atoi(v->data);
- else if (v->type == CSS_NODE_PERCENTAGE)
- c[i] = atoi(v->data) * 255 / 100;
- else
- return CSS_COLOR_NONE;
- if (c[i] < 0)
- c[i] = 0;
- if (255 < c[i])
- c[i] = 255;
-
- v = v->next;
-
- if (i == 2) {
- if (v)
- return CSS_COLOR_NONE;
- } else {
- if (!v || v->type != CSS_NODE_COMMA)
- return CSS_COLOR_NONE;
-
- v = v->next;
- }
- }
-
- return (c[2] << 16) | (c[1] << 8) | c[0];
-}
-
-/**
- * Parse a uri
- *
- * \param v node to parse
- * \param uri updated to uri, if successful
- * \return true on success, false on failure
- */
-bool parse_uri(const struct css_node *v, char **uri)
-{
- bool string = false;
- const char *u;
- char *t, *url;
- url_func_result res;
-
- switch (v->type) {
- case CSS_NODE_URI:
- for (u = v->data + 4;
- *u == ' ' || *u == '\t' || *u == '\r' ||
- *u == '\n' || *u == '\f';
- u++)
- ;
- if (*u == '\'' || *u == '"') {
- string = true;
- u++;
- }
- url = strndup(u, v->data_length - (u - v->data));
- if (!url)
- return false;
- for (t = url + strlen(url) - 2;
- *t == ' ' || *t == '\t' || *t == '\r' ||
- *t == '\n' || *t == '\f';
- t--)
- ;
- if (string)
- *t = 0;
- else
- *(t + 1) = 0;
-
- /* for inline style attributes, the stylesheet
- * content is the parent HTML content
- */
- if (v->stylesheet->type == CONTENT_HTML)
- res = url_join(url, v->stylesheet->data.html.base_url, uri);
- else
- res = url_join(url, v->stylesheet->url, uri);
- free(url);
- if (res != URL_FUNC_OK)
- return false;
- break;
- case CSS_NODE_STRING:
- url = strndup(v->data, v->data_length);
- if (!url)
- return false;
-
- if (v->stylesheet->type == CONTENT_HTML)
- res = url_join(url, v->stylesheet->data.html.base_url, uri);
- else
- res = url_join(url, v->stylesheet->url, uri);
- free(url);
- if (res != URL_FUNC_OK)
- return false;
- break;
- default:
- return false;
- }
-
- return true;
-}
-
-/**
- * \name Individual property parsers.
- * \{
- */
-
-void parse_background(struct css_style * const s,
- const struct css_node * v)
-{
- colour c = NS_TRANSPARENT, c2;
- css_background_image_type bi = CSS_BACKGROUND_IMAGE_NONE, bi2;
- char *bi_uri = 0;
- css_background_repeat br = CSS_BACKGROUND_REPEAT_REPEAT, br2;
- css_background_attachment ba = CSS_BACKGROUND_ATTACHMENT_SCROLL, ba2;
- struct css_background_position horz =
- { CSS_BACKGROUND_POSITION_PERCENT, { 0 } };
- struct css_background_position vert =
- { CSS_BACKGROUND_POSITION_PERCENT, { 0 } };
- struct css_background_position horz2, vert2;
- bool had_colour = false, had_image = false, had_repeat = false,
- had_attachment = false, had_position = false;
-
- while (v) {
- switch (v->type) {
- case CSS_NODE_URI:
- case CSS_NODE_STRING:
- /* background-image */
- if (had_image)
- goto error;
- had_image = true;
- if (!css_background_image_parse(v, &bi2,
- &bi_uri))
- goto error;
- bi = bi2;
- v = v->next;
- break;
-
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- case CSS_NODE_PERCENTAGE:
- /* background-position */
- if (had_position)
- goto error;
- had_position = true;
- if (!css_background_position_parse(&v,
- &horz2, &vert2))
- goto error;
- horz = horz2;
- vert = vert2;
- break;
-
- case CSS_NODE_IDENT:
- /* could be background-image: none */
- if (v->data_length == 4 &&
- strncasecmp(v->data, "none",
- 4) == 0) {
- if (had_image)
- goto error;
- had_image = true;
- bi = CSS_BACKGROUND_IMAGE_NONE;
- v = v->next;
- break;
- }
-
- /* background-repeat */
- br2 = css_background_repeat_parse(v->data,
- v->data_length);
- if (br2 != CSS_BACKGROUND_REPEAT_UNKNOWN) {
- if (had_repeat)
- goto error;
- had_repeat = true;
- br = br2;
- v = v->next;
- break;
- }
-
- /* background-attachment */
- ba2 = css_background_attachment_parse(v->data,
- v->data_length);
- if (ba2 != CSS_BACKGROUND_ATTACHMENT_UNKNOWN) {
- if (had_attachment)
- goto error;
- had_attachment = true;
- ba = ba2;
- v = v->next;
- break;
- }
-
- /* background-position */
- if (css_background_position_parse(&v,
- &horz2, &vert2)) {
- if (had_position)
- goto error;
- had_position = true;
- horz = horz2;
- vert = vert2;
- break;
- }
-
- /* fall through */
- case CSS_NODE_HASH:
- case CSS_NODE_FUNCTION:
- /* background-color */
- if (had_colour)
- goto error;
- had_colour = true;
- c2 = parse_colour(v);
- if (c2 != CSS_COLOR_NONE) {
- c = c2;
- v = v->next;
- break;
- }
-
- /* fall through */
- default:
- /* parsing failed */
- goto error;
- }
- }
-
- s->background_color = c;
- s->background_image.type = bi;
- if (s->background_image.type == CSS_BACKGROUND_IMAGE_URI)
- free(s->background_image.uri);
- s->background_image.uri = bi_uri;
- s->background_repeat = br;
- s->background_attachment = ba;
- s->background_position.horz = horz;
- s->background_position.vert = vert;
-
- return;
-
-error:
- free(bi_uri);
-}
-
-
-void parse_background_attachment(struct css_style * const s,
- const struct css_node * const v)
-{
- css_background_attachment z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_background_attachment_parse(v->data, v->data_length);
- if (z != CSS_BACKGROUND_ATTACHMENT_UNKNOWN)
- s->background_attachment = z;
-}
-
-
-void parse_background_color(struct css_style * const s,
- const struct css_node * const v)
-{
- colour c;
- if (v->next)
- return;
- c = parse_colour(v);
- if (c != CSS_COLOR_NONE)
- s->background_color = c;
-}
-
-
-void parse_background_image(struct css_style * const s,
- const struct css_node * const v)
-{
- css_background_image_type type;
- char *uri = 0;
-
- if (v->next)
- return;
- if (!css_background_image_parse(v, &type, &uri))
- return;
-
- if (s->background_image.type == CSS_BACKGROUND_IMAGE_URI)
- free(s->background_image.uri);
- s->background_image.type = type;
- s->background_image.uri = uri;
-}
-
-
-
-/**
- * Parse a background-image property.
- *
- * \param node node to parse
- * \param type updated to background image type
- * \param uri updated to background image uri, if type is
- * CSS_BACKGROUND_IMAGE_URI
- * \return true on success, false on parse failure
- */
-
-bool css_background_image_parse(const struct css_node *v,
- css_background_image_type *type, char **uri)
-{
- switch (v->type) {
- case CSS_NODE_URI:
- case CSS_NODE_STRING:
- if (!parse_uri(v, uri))
- return false;
- *type = CSS_BACKGROUND_IMAGE_URI;
- break;
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- *type = CSS_BACKGROUND_IMAGE_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "none", 4) == 0)
- *type = CSS_BACKGROUND_IMAGE_NONE;
- break;
- default:
- return false;
- }
- return true;
-}
-
-
-/** An entry in css_background_table. */
-struct css_background_entry {
- const char *keyword;
- unsigned int length;
- float value;
- bool horizontal;
- bool vertical;
-};
-
-/** Lookup table for parsing background-postion. */
-struct css_background_entry css_background_table[] = {
- { "left", 4, 0, true, false },
- { "right", 5, 100, true, false },
- { "top", 3, 0, false, true },
- { "bottom", 6, 100, false, true },
- { "center", 6, 50, false, false } /* true, true would be more
- logical, but this actually simplifies the code */
-};
-
-#define CSS_BACKGROUND_TABLE_ENTRIES (sizeof css_background_table / \
- sizeof css_background_table[0])
-
-
-/**
- * Lookup a background-position keyword in css_background_table.
- */
-
-struct css_background_entry *css_background_lookup(
- const struct css_node *v)
-{
- unsigned int i;
- for (i = 0; i != CSS_BACKGROUND_TABLE_ENTRIES; i++)
- if (css_background_table[i].length == v->data_length &&
- strncasecmp(v->data,
- css_background_table[i].keyword,
- css_background_table[i].length) == 0)
- break;
- if (i == CSS_BACKGROUND_TABLE_ENTRIES)
- return NULL;
- return &css_background_table[i];
-}
-
-
-void parse_background_position(struct css_style * const s,
- const struct css_node * v)
-{
- const struct css_node *node = v;
- struct css_background_position horz, vert;
-
- if (v->next && v->next->next)
- /* more than two nodes */
- return;
-
- if (!css_background_position_parse(&node, &horz, &vert))
- return;
- if (node)
- /* didn't parse all the nodes */
- return;
-
- s->background_position.horz = horz;
- s->background_position.vert = vert;
-}
-
-
-/**
- * Parse a background-position property.
- *
- * \param node list of nodes, updated to first unused node
- * \param horz updated to horizontal background position
- * \param vert updated to vertical background position
- * \return true on success, false on parse failure
- */
-
-bool css_background_position_parse(const struct css_node **node,
- struct css_background_position *horz,
- struct css_background_position *vert)
-{
- const struct css_node *v = *node;
- const struct css_node *w = v->next;
- struct css_background_entry *bg = NULL, *bg2 = NULL;
- bool switched = false;
-
- if (v->type == CSS_NODE_IDENT)
- bg = css_background_lookup(v);
- if (w && w->type == CSS_NODE_IDENT)
- bg2 = css_background_lookup(w);
-
- if (!(w && ((w->type == CSS_NODE_IDENT && bg2) ||
- w->type == CSS_NODE_PERCENTAGE ||
- w->type == CSS_NODE_DIMENSION ||
- w->type == CSS_NODE_NUMBER))) {
- /* only one value specified */
- if (v->type == CSS_NODE_IDENT) {
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7)
- == 0) {
- horz->pos = vert->pos =
- CSS_BACKGROUND_POSITION_INHERIT;
- return false;
- }
-
- if (bg == NULL)
- return false;
- horz->pos = vert->pos = CSS_BACKGROUND_POSITION_PERCENT;
- horz->value.percent = bg->horizontal ? bg->value : 50;
- vert->value.percent = bg->vertical ? bg->value : 50;
- }
- else if (v->type == CSS_NODE_PERCENTAGE) {
- horz->pos = vert->pos = CSS_BACKGROUND_POSITION_PERCENT;
- horz->value.percent = atof(v->data);
- vert->value.percent = 50.0;
- }
- else if ((v->type == CSS_NODE_DIMENSION) ||
- (v->type == CSS_NODE_NUMBER)) {
- if (parse_length(&horz->value.
- length, v, false) == 0) {
- horz->pos = CSS_BACKGROUND_POSITION_LENGTH;
- vert->pos = CSS_BACKGROUND_POSITION_PERCENT;
- vert->value.percent = 50.0;
- }
- }
-
- *node = w;
- return true;
- }
-
- /* two values specified */
- if (v->type == CSS_NODE_IDENT && w->type == CSS_NODE_IDENT) {
- /* both keywords */
- if (bg == NULL || bg2 == NULL)
- return false;
- if ((bg->horizontal && bg2->horizontal) ||
- (bg->vertical && bg2->vertical))
- return false;
- horz->pos = vert->pos = CSS_BACKGROUND_POSITION_PERCENT;
- horz->value.percent = vert->value.percent = 50;
- if (bg->horizontal)
- horz->value.percent = bg->value;
- else if (bg2->horizontal)
- horz->value.percent = bg2->value;
- if (bg->vertical)
- vert->value.percent = bg->value;
- else if (bg2->vertical)
- vert->value.percent = bg2->value;
-
- *node = w->next;
- return true;
- }
-
- /* reverse specifiers such that idents are places in h, v order */
- if ((v->type == CSS_NODE_IDENT && bg && bg->vertical) ||
- (w->type == CSS_NODE_IDENT && bg2 && bg2->horizontal)) {
- const struct css_node *n_temp;
- struct css_background_entry *b_temp;
-
- n_temp = v;
- v = w;
- w = n_temp;
-
- b_temp = bg;
- bg = bg2;
- bg2 = b_temp;
-
- /* Flag this so we update *node with the right thing */
- switched = true;
- }
-
- if (v->type == CSS_NODE_IDENT) { /* horizontal value */
- if (bg == NULL || bg->vertical)
- return false;
- }
- if (w->type == CSS_NODE_IDENT) { /* vertical value */
- if (bg2 == NULL || bg2->horizontal)
- return false;
- }
-
- if (v->type == CSS_NODE_IDENT) { /* horizontal value */
- assert(bg != NULL);
- horz->pos = CSS_BACKGROUND_POSITION_PERCENT;
- horz->value.percent = bg->value;
- } else if (v->type == CSS_NODE_PERCENTAGE) {
- horz->pos = CSS_BACKGROUND_POSITION_PERCENT;
- horz->value.percent = atof(v->data);
- } else if ((v->type == CSS_NODE_DIMENSION) ||
- (v->type == CSS_NODE_NUMBER)) {
- if (parse_length(&horz->value.length,
- v, false) == 0)
- horz->pos = CSS_BACKGROUND_POSITION_LENGTH;
- }
-
- if (w->type == CSS_NODE_IDENT) { /* vertical value */
- assert(bg2 != NULL);
- vert->pos = CSS_BACKGROUND_POSITION_PERCENT;
- vert->value.percent = bg2->value;
- } else if (w->type == CSS_NODE_PERCENTAGE) {
- vert->pos = CSS_BACKGROUND_POSITION_PERCENT;
- vert->value.percent = atof(w->data);
- } else if ((w->type == CSS_NODE_DIMENSION) ||
- (w->type == CSS_NODE_NUMBER)) {
- if (parse_length(&vert->value.length,
- w, false) == 0)
- vert->pos = CSS_BACKGROUND_POSITION_LENGTH;
- }
-
- *node = switched ? v->next : w->next;
-
- return true;
-}
-
-
-void parse_background_repeat(struct css_style * const s,
- const struct css_node * const v)
-{
- css_background_repeat z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_background_repeat_parse(v->data, v->data_length);
- if (z != CSS_BACKGROUND_REPEAT_UNKNOWN)
- s->background_repeat = z;
-}
-
-
-void parse_border_width(struct css_style * const s,
- const struct css_node * const v)
-{
- unsigned int count = 0;
- const struct css_node *w;
-
- for (w = v; w; w = w->next, count++)
- if (!((w->type == CSS_NODE_IDENT && (
- (w->data_length == 7 &&
- strncasecmp(w->data, "inherit", 7) == 0) ||
- (w->data_length == 4 &&
- strncasecmp(w->data, "thin", 4) == 0) ||
- (w->data_length == 6 &&
- strncasecmp(w->data, "medium", 6) == 0) ||
- (w->data_length == 5 &&
- strncasecmp(w->data, "thick", 5) == 0))) ||
- (w->type == CSS_NODE_DIMENSION) ||
- (w->type == CSS_NODE_NUMBER)))
- return;
-
- w = v;
- switch (count) {
- case 1: /* one value: applies to all sides */
- parse_border_width_side(s, w, TOP);
- parse_border_width_side(s, w, RIGHT);
- parse_border_width_side(s, w, BOTTOM);
- parse_border_width_side(s, w, LEFT);
- break;
- case 2: /* (top and bottom), (left and right) */
- parse_border_width_side(s, w, TOP);
- parse_border_width_side(s, w, BOTTOM);
- w = w->next;
- parse_border_width_side(s, w, RIGHT);
- parse_border_width_side(s, w, LEFT);
- break;
- case 3: /* top, (left and right), bottom */
- parse_border_width_side(s, w, TOP);
- w = w->next;
- parse_border_width_side(s, w, RIGHT);
- parse_border_width_side(s, w, LEFT);
- w = w->next;
- parse_border_width_side(s, w, BOTTOM);
- break;
- case 4: /* top, right, bottom, left */
- parse_border_width_side(s, w, TOP);
- w = w->next;
- parse_border_width_side(s, w, RIGHT);
- w = w->next;
- parse_border_width_side(s, w, BOTTOM);
- w = w->next;
- parse_border_width_side(s, w, LEFT);
- break;
- }
-}
-
-#define PARSE_BORDER_WIDTH(side, z) \
-void parse_border_ ## side ## _width(struct css_style * const s, \
- const struct css_node * const v) \
-{ \
- if (v->next != 0) \
- return; \
- parse_border_width_side(s, v, z); \
-}
-
-PARSE_BORDER_WIDTH(top, TOP)
-PARSE_BORDER_WIDTH(right, RIGHT)
-PARSE_BORDER_WIDTH(bottom, BOTTOM)
-PARSE_BORDER_WIDTH(left, LEFT)
-
-void parse_border_width_side(struct css_style * const s,
- const struct css_node * const v, unsigned int i)
-{
- if (v->type == CSS_NODE_IDENT) {
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->border[i].width.width = CSS_BORDER_WIDTH_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "thin", 4) == 0) {
- s->border[i].width.width = CSS_BORDER_WIDTH_LENGTH;
- s->border[i].width.value.value = 1;
- s->border[i].width.value.unit = CSS_UNIT_PX;
- } else if (v->data_length == 6 &&
- strncasecmp(v->data, "medium", 6) == 0) {
- s->border[i].width.width = CSS_BORDER_WIDTH_LENGTH;
- s->border[i].width.value.value = 2;
- s->border[i].width.value.unit = CSS_UNIT_PX;
- } else if (v->data_length == 5 &&
- strncasecmp(v->data, "thick", 5) == 0) {
- s->border[i].width.width = CSS_BORDER_WIDTH_LENGTH;
- s->border[i].width.value.value = 4;
- s->border[i].width.value.unit = CSS_UNIT_PX;
- }
- } else if ((v->type == CSS_NODE_DIMENSION ||
- v->type == CSS_NODE_NUMBER) &&
- parse_length(&s->border[i].width.value, v, true) == 0)
- s->border[i].width.width = CSS_BORDER_WIDTH_LENGTH;
-}
-
-void parse_border_color(struct css_style * const s,
- const struct css_node * const v)
-{
- unsigned int count = 0;
- const struct css_node *w;
-
- for (w = v; w; w = w->next, count++)
- if (!(w->type == CSS_NODE_HASH ||
- w->type == CSS_NODE_FUNCTION ||
- w->type == CSS_NODE_IDENT))
- return;
-
- w = v;
- switch (count) {
- case 1: /* one value: applies to all sides */
- parse_border_color_side(s, w, TOP);
- parse_border_color_side(s, w, RIGHT);
- parse_border_color_side(s, w, BOTTOM);
- parse_border_color_side(s, w, LEFT);
- break;
- case 2: /* (top and bottom), (left and right) */
- parse_border_color_side(s, w, TOP);
- parse_border_color_side(s, w, BOTTOM);
- w = w->next;
- parse_border_color_side(s, w, RIGHT);
- parse_border_color_side(s, w, LEFT);
- break;
- case 3: /* top, (left and right), bottom */
- parse_border_color_side(s, w, TOP);
- w = w->next;
- parse_border_color_side(s, w, RIGHT);
- parse_border_color_side(s, w, LEFT);
- w = w->next;
- parse_border_color_side(s, w, BOTTOM);
- break;
- case 4: /* top, right, bottom, left */
- parse_border_color_side(s, w, TOP);
- w = w->next;
- parse_border_color_side(s, w, RIGHT);
- w = w->next;
- parse_border_color_side(s, w, BOTTOM);
- w = w->next;
- parse_border_color_side(s, w, LEFT);
- break;
- }
-}
-
-#define PARSE_BORDER_COLOR(side, z) \
-void parse_border_ ## side ## _color(struct css_style * const s, \
- const struct css_node * const v) \
-{ \
- if (v->next != 0) \
- return; \
- parse_border_color_side(s, v, z); \
-}
-
-PARSE_BORDER_COLOR(top, TOP)
-PARSE_BORDER_COLOR(right, RIGHT)
-PARSE_BORDER_COLOR(bottom, BOTTOM)
-PARSE_BORDER_COLOR(left, LEFT)
-
-void parse_border_color_side(struct css_style * const s,
- const struct css_node * const v, unsigned int i)
-{
- colour c = parse_colour(v);
- if (c != CSS_COLOR_NONE)
- s->border[i].color = c;
-}
-
-void parse_border_style(struct css_style * const s,
- const struct css_node * const v)
-{
- unsigned int count = 0;
- const struct css_node *w;
-
- for (w = v; w; w = w->next, count++)
- if (w->type != CSS_NODE_IDENT)
- return;
-
- w = v;
- switch (count) {
- case 1: /* one value: applies to all sides */
- parse_border_style_side(s, w, TOP);
- parse_border_style_side(s, w, RIGHT);
- parse_border_style_side(s, w, BOTTOM);
- parse_border_style_side(s, w, LEFT);
- break;
- case 2: /* (top and bottom), (left and right) */
- parse_border_style_side(s, w, TOP);
- parse_border_style_side(s, w, BOTTOM);
- w = w->next;
- parse_border_style_side(s, w, RIGHT);
- parse_border_style_side(s, w, LEFT);
- break;
- case 3: /* top, (left and right), bottom */
- parse_border_style_side(s, w, TOP);
- w = w->next;
- parse_border_style_side(s, w, RIGHT);
- parse_border_style_side(s, w, LEFT);
- w = w->next;
- parse_border_style_side(s, w, BOTTOM);
- break;
- case 4: /* top, right, bottom, left */
- parse_border_style_side(s, w, TOP);
- w = w->next;
- parse_border_style_side(s, w, RIGHT);
- w = w->next;
- parse_border_style_side(s, w, BOTTOM);
- w = w->next;
- parse_border_style_side(s, w, LEFT);
- break;
- }
-}
-
-#define PARSE_BORDER_STYLE(side, z) \
-void parse_border_ ## side ## _style(struct css_style * const s, \
- const struct css_node * const v) \
-{ \
- if (v->next != 0 || v->type != CSS_NODE_IDENT) \
- return; \
- parse_border_style_side(s, v, z); \
-}
-
-PARSE_BORDER_STYLE(top, TOP)
-PARSE_BORDER_STYLE(right, RIGHT)
-PARSE_BORDER_STYLE(bottom, BOTTOM)
-PARSE_BORDER_STYLE(left, LEFT)
-
-void parse_border_style_side(struct css_style * const s,
- const struct css_node * const v, unsigned int i)
-{
- css_border_style z = css_border_style_parse(v->data, v->data_length);
- if (z != CSS_BORDER_STYLE_UNKNOWN)
- s->border[i].style = z;
-}
-
-void parse_border(struct css_style * const s,
- const struct css_node * const v)
-{
- parse_border_side(s, v, TOP);
- parse_border_side(s, v, RIGHT);
- parse_border_side(s, v, BOTTOM);
- parse_border_side(s, v, LEFT);
-}
-
-#define PARSE_BORDER(side, z) \
-void parse_border_ ## side(struct css_style * const s, \
- const struct css_node * const v) \
-{ \
- parse_border_side(s, v, z); \
-}
-
-PARSE_BORDER(top, TOP)
-PARSE_BORDER(right, RIGHT)
-PARSE_BORDER(bottom, BOTTOM)
-PARSE_BORDER(left, LEFT)
-
-void parse_border_side(struct css_style * const s,
- const struct css_node *v, unsigned int i)
-{
- colour c;
- css_border_style z;
-
- if (!v->next && v->type == CSS_NODE_IDENT &&
- v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0) {
- s->border[i].color = CSS_COLOR_INHERIT;
- s->border[i].width.width = CSS_BORDER_WIDTH_INHERIT;
- s->border[i].style = CSS_BORDER_STYLE_INHERIT;
- return;
- }
-
- for (; v; v = v->next) {
- c = parse_colour(v);
- if (c != CSS_COLOR_NONE) {
- s->border[i].color = c;
- continue;
- }
-
- if (v->type == CSS_NODE_IDENT) {
- z = css_border_style_parse(v->data, v->data_length);
- if (z != CSS_BORDER_STYLE_UNKNOWN) {
- s->border[i].style = z;
- continue;
- }
- }
-
- parse_border_width_side(s, v, i);
- }
-}
-
-void parse_border_collapse(struct css_style * const s, const struct css_node * v)
-{
- css_border_collapse z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_border_collapse_parse(v->data, v->data_length);
- if (z != CSS_BORDER_COLLAPSE_UNKNOWN)
- s->border_collapse = z;
-}
-
-void parse_border_spacing(struct css_style * const s, const struct css_node * v)
-{
- if (v->next && v->next->next)
- /* more than two nodes */
- return;
-
- if (!v->next) {
- /* one node */
- if (v->type == CSS_NODE_IDENT && v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->border_spacing.border_spacing =
- CSS_BORDER_SPACING_INHERIT;
- else if (v->type == CSS_NODE_DIMENSION ||
- v->type == CSS_NODE_NUMBER) {
- if (parse_length(&s->border_spacing.horz,
- v, true) == 0 &&
- parse_length(&s->border_spacing.vert,
- v, true) == 0)
- s->border_spacing.border_spacing =
- CSS_BORDER_SPACING_LENGTH;
- }
- } else {
- /* two nodes */
- if ((v->type == CSS_NODE_DIMENSION ||
- v->type == CSS_NODE_NUMBER) &&
- (v->next->type == CSS_NODE_DIMENSION ||
- v->next->type == CSS_NODE_NUMBER)) {
- if (parse_length(&s->border_spacing.horz,
- v, true) == 0 &&
- parse_length(&s->border_spacing.vert,
- v->next, true) == 0)
- s->border_spacing.border_spacing =
- CSS_BORDER_SPACING_LENGTH;
- }
- }
-}
-
-void parse_caption_side(struct css_style * const s, const struct css_node * v)
-{
- css_caption_side z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_caption_side_parse(v->data, v->data_length);
- if (z != CSS_CAPTION_SIDE_UNKNOWN)
- s->caption_side = z;
-}
-
-void parse_clear(struct css_style * const s, const struct css_node * const v)
-{
- css_clear z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_clear_parse(v->data, v->data_length);
- if (z != CSS_CLEAR_UNKNOWN)
- s->clear = z;
-}
-
-void parse_clip(struct css_style * const s, const struct css_node * v)
-{
- int i;
- struct css_node *t;
-
- if (v->next != 0)
- return;
-
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->clip.clip = CSS_CLIP_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "auto", 4) == 0)
- s->clip.clip = CSS_CLIP_AUTO;
- break;
- case CSS_NODE_FUNCTION:
- /* must be rect(X,X,X,X) */
- if (v->data_length == 5 &&
- strncasecmp(v->data, "rect", 4) == 0) {
- struct {
- enum { CSS_CLIP_RECT_AUTO,
- CSS_CLIP_RECT_LENGTH } rect;
- struct css_length value;
- } rect[4];
-
- t = v->value;
- if (!t)
- return;
-
- for (i = 0; i != 4; i++) {
- switch (t->type) {
- case CSS_NODE_IDENT:
- if (t->data_length == 4 && strncasecmp(t->data, "auto", 4) == 0) {
- rect[i].rect = CSS_CLIP_RECT_AUTO;
- }
- else
- return;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (parse_length(&rect[i].value,
- t, false) != 0)
- return;
- rect[i].rect = CSS_CLIP_RECT_LENGTH;
- break;
- default:
- return;
- }
-
- /* move to comma or end */
- t = t->next;
-
- if (i == 3 && t)
- /* excess arguments - ignore rule */
- return;
- else {
- if (!t || t->type != CSS_NODE_COMMA)
- /* insufficient arguments or
- * no comma - ignore rule */
- return;
- }
-
- /* move to next argument */
- t = t->next;
- }
-
- /* If we reach here, rule is valid, so apply to s */
- for (i = 0; i != 4; i++) {
- s->clip.rect[i].rect = rect[i].rect;
- s->clip.rect[i].value.value =
- rect[i].value.value;
- s->clip.rect[i].value.unit =
- rect[i].value.unit;
- }
- s->clip.clip = CSS_CLIP_RECT;
- }
- break;
- default:
- break;
- }
-}
-
-void parse_color(struct css_style * const s, const struct css_node * const v)
-{
- colour c;
- if (v->next)
- return;
- c = parse_colour(v);
- if (c != CSS_COLOR_NONE)
- 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;
- for (; v; v = v->next) {
- switch (v->type) {
- case CSS_NODE_IDENT:
- z = css_cursor_parse(v->data, v->data_length);
- if (z != CSS_CURSOR_UNKNOWN) {
- s->cursor = z;
- return;
- }
- break;
- default:
- break;
- }
- }
-}
-
-void parse_direction(struct css_style * const s, const struct css_node * v)
-{
- css_direction z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_direction_parse(v->data, v->data_length);
- if (z != CSS_DIRECTION_UNKNOWN)
- s->direction = z;
-}
-
-void parse_display(struct css_style * const s, const struct css_node * const v)
-{
- css_display z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_display_parse(v->data, v->data_length);
- if (z != CSS_DISPLAY_UNKNOWN)
- s->display = z;
-}
-
-void parse_empty_cells(struct css_style * const s, const struct css_node * v)
-{
- css_empty_cells z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_empty_cells_parse(v->data, v->data_length);
- if (z != CSS_EMPTY_CELLS_UNKNOWN)
- s->empty_cells = z;
-}
-
-void parse_float(struct css_style * const s, const struct css_node * const v)
-{
- css_float z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_float_parse(v->data, v->data_length);
- if (z != CSS_FLOAT_UNKNOWN)
- s->float_ = z;
-}
-
-void parse_font(struct css_style * const s, const struct css_node * v)
-{
- css_font_family ff;
- css_font_style fs;
- css_font_variant fv;
- css_font_weight fw;
- s->font_family = CSS_FONT_FAMILY_SANS_SERIF;
- s->font_style = CSS_FONT_STYLE_NORMAL;
- s->font_weight = CSS_FONT_WEIGHT_NORMAL;
- s->line_height.size = CSS_LINE_HEIGHT_ABSOLUTE;
- s->line_height.value.absolute = 1.3;
- for (; v; v = v->next) {
- switch (v->type) {
- case CSS_NODE_IDENT:
- /* font-family */
- ff = css_font_family_parse(v->data,
- v->data_length);
- if (ff != CSS_FONT_FAMILY_UNKNOWN) {
- s->font_family = ff;
- break;
- }
- /* font-style, font-variant, or font-weight */
- fs = css_font_style_parse(v->data,
- v->data_length);
- if (fs != CSS_FONT_STYLE_UNKNOWN) {
- s->font_style = fs;
- break;
- }
- fv = css_font_variant_parse(v->data,
- v->data_length);
- if (fv != CSS_FONT_VARIANT_UNKNOWN) {
- s->font_variant = fv;
- break;
- }
- fw = css_font_weight_parse(v->data,
- v->data_length);
- if (fw != CSS_FONT_WEIGHT_UNKNOWN) {
- s->font_weight = fw;
- break;
- }
- case CSS_NODE_PERCENTAGE:
- case CSS_NODE_DIMENSION:
- parse_font_size(s, v);
- break;
- case CSS_NODE_DELIM:
- if (v->data[0] == '/' && v->data_length == 1 &&
- v->next) {
- v = v->next;
- parse_line_height(s, v);
- }
- break;
- default:
- break;
- }
- }
-}
-
-void parse_font_family(struct css_style * const s, const struct css_node * v)
-{
- css_font_family z;
- for (; v; v = v->next) {
- switch (v->type) {
- case CSS_NODE_IDENT:
- z = css_font_family_parse(v->data,
- v->data_length);
- if (z != CSS_FONT_FAMILY_UNKNOWN) {
- s->font_family = z;
- return;
- }
- break;
- default:
- break;
- }
- }
-}
-
-void parse_font_size(struct css_style * const s, const struct css_node * const v)
-{
- char font_size_name[10];
- struct css_font_size_entry *fs;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (9 < v->data_length)
- break;
- strncpy(font_size_name, v->data, v->data_length);
- font_size_name[v->data_length] = 0;
- fs = bsearch(font_size_name, css_font_size_table,
- sizeof css_font_size_table /
- sizeof css_font_size_table[0],
- sizeof css_font_size_table[0],
- (int (*)(const void *, const void *))
- strcasecmp);
- if (fs != 0) {
- s->font_size.size = CSS_FONT_SIZE_LENGTH;
- s->font_size.value.length.unit = CSS_UNIT_PT;
- s->font_size.value.length.value = fs->size *
- option_font_size / 10;
- } else if (v->data_length == 6 &&
- strncasecmp(v->data, "larger", 6) == 0) {
- s->font_size.size = CSS_FONT_SIZE_PERCENT;
- s->font_size.value.percent = SIZE_FACTOR * 100;
- } else if (v->data_length == 7 &&
- strncasecmp(v->data, "smaller", 7) == 0) {
- s->font_size.size = CSS_FONT_SIZE_PERCENT;
- s->font_size.value.percent = 1 / SIZE_FACTOR * 100;
- }
- break;
-
- case CSS_NODE_PERCENTAGE:
- s->font_size.size = CSS_FONT_SIZE_PERCENT;
- s->font_size.value.percent = atof(v->data);
- break;
-
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (parse_length(&s->font_size.value.length, v, true) == 0)
- s->font_size.size = CSS_FONT_SIZE_LENGTH;
- break;
-
- default:
- break;
- }
-}
-
-void parse_font_style(struct css_style * const s, const struct css_node * const v)
-{
- css_font_style z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_font_style_parse(v->data, v->data_length);
- if (z != CSS_FONT_STYLE_UNKNOWN)
- s->font_style = z;
-}
-
-void parse_font_variant(struct css_style * const s, const struct css_node * const v)
-{
- css_font_variant z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_font_variant_parse(v->data, v->data_length);
- if (z != CSS_FONT_VARIANT_UNKNOWN)
- s->font_variant = z;
-}
-
-void parse_font_weight(struct css_style * const s, const struct css_node * const v)
-{
- css_font_weight z;
- if ((v->type != CSS_NODE_IDENT && v->type != CSS_NODE_NUMBER) || v->next != 0)
- return;
- z = css_font_weight_parse(v->data, v->data_length);
- if (z != CSS_FONT_WEIGHT_UNKNOWN)
- s->font_weight = z;
-}
-
-void parse_height(struct css_style * const s, const struct css_node * const v)
-{
- if (v->type == CSS_NODE_IDENT && v->data_length == 4 &&
- strncasecmp(v->data, "auto", 4) == 0)
- s->height.height = CSS_HEIGHT_AUTO;
- else if (v->type == CSS_NODE_PERCENTAGE) {
- s->height.height = CSS_HEIGHT_PERCENT;
- s->height.value.percent = atof(v->data);
- } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) &&
- parse_length(&s->height.value.length, v, true) == 0)
- s->height.height = CSS_HEIGHT_LENGTH;
-}
-
-void parse_letter_spacing(struct css_style * const s, const struct css_node * v)
-{
- if (v->next != 0)
- return;
-
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->letter_spacing.letter_spacing = CSS_LETTER_SPACING_INHERIT;
- else if (v->data_length == 6 &&
- strncasecmp(v->data, "normal", 6) == 0)
- s->letter_spacing.letter_spacing = CSS_LETTER_SPACING_NORMAL;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (parse_length(&s->letter_spacing.length, v, false) == 0)
- s->letter_spacing.letter_spacing = CSS_LETTER_SPACING_LENGTH;
- break;
- default:
- break;
- }
-}
-
-void parse_line_height(struct css_style * const s, const struct css_node * const v)
-{
- if (v->type == CSS_NODE_IDENT && v->data_length == 6 &&
- strncasecmp(v->data, "normal", 6) == 0) {
- s->line_height.size = CSS_LINE_HEIGHT_ABSOLUTE;
- s->line_height.value.absolute = 1.3;
- } else if (v->type == CSS_NODE_PERCENTAGE) {
- s->line_height.size = CSS_LINE_HEIGHT_PERCENT;
- s->line_height.value.percent = atof(v->data);
- } else if (v->type == CSS_NODE_DIMENSION &&
- parse_length(&s->line_height.value.length, v, true) == 0) {
- s->line_height.size = CSS_LINE_HEIGHT_LENGTH;
- } else if (v->type == CSS_NODE_NUMBER) {
- s->line_height.size = CSS_LINE_HEIGHT_ABSOLUTE;
- s->line_height.value.absolute = atof(v->data);
- }
-}
-
-void parse_list_style(struct css_style * const s, const struct css_node * v)
-{
- css_list_style_type t = CSS_LIST_STYLE_TYPE_DISC, t2;
- css_list_style_position p = CSS_LIST_STYLE_POSITION_OUTSIDE, p2;
- css_list_style_image_type i = CSS_LIST_STYLE_IMAGE_NONE, i2;
- char *lsi_uri = 0;
-
- while (v) {
- switch (v->type) {
- case CSS_NODE_IDENT:
- t2 = css_list_style_type_parse(v->data, v->data_length);
- if (t2 != CSS_LIST_STYLE_TYPE_UNKNOWN) {
- t = t2;
- v = v->next;
- break;
- }
-
- p2 = css_list_style_position_parse(v->data, v->data_length);
- if (p2 != CSS_LIST_STYLE_POSITION_UNKNOWN) {
- p = p2;
- v = v->next;
- break;
- }
-
- /* drop through */
- case CSS_NODE_STRING:
- case CSS_NODE_URI:
- if (!css_list_style_image_parse(v, &i2, &lsi_uri))
- return;
- i = i2;
- v = v->next;
- break;
- default:
- return;
- }
- }
-
- s->list_style_type = t;
- s->list_style_position = p;
- s->list_style_image.type = i;
- s->list_style_image.uri = lsi_uri;
-}
-
-void parse_list_style_image(struct css_style * const s, const struct css_node * v)
-{
- css_list_style_image_type type;
- char *uri;
-
- if (v->next != 0)
- return;
- if (!css_list_style_image_parse(v, &type, &uri))
- return;
-
- if (s->list_style_image.type == CSS_LIST_STYLE_IMAGE_URI)
- free(s->list_style_image.uri);
- s->list_style_image.type = type;
- s->list_style_image.uri = uri;
-}
-
-/**
- * Parse a list-style-image property.
- *
- * \param node node to parse
- * \param type updated to list-style-image type
- * \param uri updated to image uri, if type is
- * CSS_LIST_STYLE_IMAGE_URI
- * \return true on success, false on parse failure
- */
-
-bool css_list_style_image_parse(const struct css_node *v,
- css_list_style_image_type *type, char **uri)
-{
- switch (v->type) {
- case CSS_NODE_URI:
- case CSS_NODE_STRING:
- if (!parse_uri(v, uri))
- return false;
- *type = CSS_LIST_STYLE_IMAGE_URI;
- break;
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- *type = CSS_LIST_STYLE_IMAGE_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "none", 4) == 0)
- *type = CSS_LIST_STYLE_IMAGE_NONE;
- break;
- default:
- return false;
- }
- return true;
-}
-
-void parse_list_style_position(struct css_style * const s, const struct css_node * v)
-{
- css_list_style_position z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_list_style_position_parse(v->data, v->data_length);
- if (z != CSS_LIST_STYLE_POSITION_UNKNOWN)
- s->list_style_position = z;
-}
-
-void parse_list_style_type(struct css_style * const s, const struct css_node * v)
-{
- css_list_style_type z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_list_style_type_parse(v->data, v->data_length);
- if (z != CSS_LIST_STYLE_TYPE_UNKNOWN)
- s->list_style_type = z;
-}
-
-void parse_margin(struct css_style * const s, const struct css_node * const v)
-{
- unsigned int count = 0;
- const struct css_node *w;
-
- for (w = v; w; w = w->next, count++)
- if (!((w->type == CSS_NODE_IDENT && (
- (w->data_length == 7 &&
- strncasecmp(w->data, "inherit", 7) == 0) ||
- (w->data_length == 4 &&
- strncasecmp(w->data, "auto", 4) == 0))) ||
- (w->type == CSS_NODE_PERCENTAGE) ||
- (w->type == CSS_NODE_DIMENSION) ||
- (w->type == CSS_NODE_NUMBER)))
- return;
-
- w = v;
- switch (count) {
- case 1: /* one value: applies to all sides */
- parse_margin_side(s, w, TOP);
- parse_margin_side(s, w, RIGHT);
- parse_margin_side(s, w, BOTTOM);
- parse_margin_side(s, w, LEFT);
- break;
- case 2: /* (top and bottom), (left and right) */
- parse_margin_side(s, w, TOP);
- parse_margin_side(s, w, BOTTOM);
- w = w->next;
- parse_margin_side(s, w, RIGHT);
- parse_margin_side(s, w, LEFT);
- break;
- case 3: /* top, (left and right), bottom */
- parse_margin_side(s, w, TOP);
- w = w->next;
- parse_margin_side(s, w, RIGHT);
- parse_margin_side(s, w, LEFT);
- w = w->next;
- parse_margin_side(s, w, BOTTOM);
- break;
- case 4: /* top, right, bottom, left */
- parse_margin_side(s, w, TOP);
- w = w->next;
- parse_margin_side(s, w, RIGHT);
- w = w->next;
- parse_margin_side(s, w, BOTTOM);
- w = w->next;
- parse_margin_side(s, w, LEFT);
- break;
- }
-}
-
-#define PARSE_MARGIN_(side, z) \
-void parse_margin_ ## side(struct css_style * const s, \
- const struct css_node * const v) \
-{ \
- if (v->next != 0) \
- return; \
- parse_margin_side(s, v, z); \
-}
-
-PARSE_MARGIN_(top, TOP)
-PARSE_MARGIN_(right, RIGHT)
-PARSE_MARGIN_(bottom, BOTTOM)
-PARSE_MARGIN_(left, LEFT)
-
-void parse_margin_side(struct css_style * const s, const struct css_node * const v,
- unsigned int i)
-{
- if (v->type == CSS_NODE_IDENT && v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->margin[i].margin = CSS_MARGIN_INHERIT;
- else if (v->type == CSS_NODE_IDENT && v->data_length == 4 &&
- strncasecmp(v->data, "auto", 4) == 0)
- s->margin[i].margin = CSS_MARGIN_AUTO;
- else if (v->type == CSS_NODE_PERCENTAGE) {
- s->margin[i].margin = CSS_MARGIN_PERCENT;
- s->margin[i].value.percent = atof(v->data);
- } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) &&
- parse_length(&s->margin[i].value.length, v, false) == 0) {
- s->margin[i].margin = CSS_MARGIN_LENGTH;
- }
-}
-
-void parse_max_height(struct css_style *const s, const struct css_node * v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->max_height.max_height = CSS_MAX_HEIGHT_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "none", 4) == 0)
- s->max_height.max_height = CSS_MAX_HEIGHT_NONE;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (!parse_length(&s->max_height.value.length, v, true))
- s->max_height.max_height = CSS_MAX_HEIGHT_LENGTH;
- break;
- case CSS_NODE_PERCENTAGE:
- s->max_height.value.percent = atof(v->data);
- s->max_height.max_height = CSS_MAX_HEIGHT_PERCENT;
- break;
- default:
- break;
- }
-}
-
-void parse_max_width(struct css_style *const s, const struct css_node * v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->max_width.max_width = CSS_MAX_WIDTH_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "none", 4) == 0)
- s->max_width.max_width = CSS_MAX_WIDTH_NONE;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (!parse_length(&s->max_width.value.length, v, true))
- s->max_width.max_width = CSS_MAX_WIDTH_LENGTH;
- break;
- case CSS_NODE_PERCENTAGE:
- s->max_width.value.percent = atof(v->data);
- s->max_width.max_width = CSS_MAX_WIDTH_PERCENT;
- break;
- default:
- break;
- }
-}
-
-void parse_min_height(struct css_style *const s, const struct css_node * v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->min_height.min_height = CSS_MIN_HEIGHT_INHERIT;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (!parse_length(&s->min_height.value.length, v, true))
- s->min_height.min_height = CSS_MIN_HEIGHT_LENGTH;
- break;
- case CSS_NODE_PERCENTAGE:
- s->min_height.value.percent = atof(v->data);
- s->min_height.min_height = CSS_MIN_HEIGHT_PERCENT;
- break;
- default:
- break;
- }
-}
-
-void parse_min_width(struct css_style *const s, const struct css_node * v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->min_width.min_width = CSS_MIN_WIDTH_INHERIT;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (!parse_length(&s->min_width.value.length, v, true))
- s->min_width.min_width = CSS_MIN_WIDTH_LENGTH;
- break;
- case CSS_NODE_PERCENTAGE:
- s->min_width.value.percent = atof(v->data);
- s->min_width.min_width = CSS_MIN_WIDTH_PERCENT;
- break;
- default:
- break;
- }
-}
-
-void parse_orphans(struct css_style * const s, const struct css_node * const v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->orphans.orphans = CSS_ORPHANS_INHERIT;
- break;
- case CSS_NODE_NUMBER:
- s->orphans.value = atoi(v->data);
- s->orphans.orphans = CSS_ORPHANS_INTEGER;
- break;
- default:
- break;
- }
-}
-
-void parse_outline(struct css_style * const s, const struct css_node * v)
-{
- css_outline_color_type c = CSS_OUTLINE_COLOR_INVERT;
- colour col = 0, col2;
- css_border_style b = CSS_BORDER_STYLE_NONE, b2;
- struct css_border_width w = { CSS_BORDER_WIDTH_LENGTH, { 2, CSS_UNIT_PX } };
- struct css_border_width w2;
-
- while (v) {
- switch (v->type) {
- case CSS_NODE_HASH:
- case CSS_NODE_FUNCTION:
- case CSS_NODE_IDENT:
- col2 = parse_colour(v);
- if (col2 != CSS_COLOR_NONE) {
- col = col2;
- c = CSS_OUTLINE_COLOR_COLOR;
- v = v->next;
- break;
- }
- if (v->type == CSS_NODE_HASH ||
- v->type == CSS_NODE_FUNCTION)
- return;
-
- /* could be inherit */
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0) {
- c = CSS_OUTLINE_COLOR_INHERIT;
- v = v->next;
- break;
- }
-
- b2 = css_border_style_parse(v->data, v->data_length);
- if (b2 != CSS_BORDER_STYLE_UNKNOWN) {
- b = b2;
- v = v->next;
- break;
- }
-
- /* fall through */
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (css_outline_width_parse(v, &w2)) {
- w = w2;
- v = v->next;
- break;
- }
-
- /* fall through */
- default:
- return;
- }
- }
-
- s->outline.color.color = c;
- s->outline.color.value = col;
- s->outline.width = w;
- s->outline.style = b;
-}
-
-void parse_outline_color(struct css_style * const s, const struct css_node * const v)
-{
- colour c;
-
- if (v->next != 0)
- return;
-
- c = parse_colour(v);
- if (c == CSS_COLOR_NONE && v->type == CSS_NODE_IDENT) {
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->outline.color.color = CSS_OUTLINE_COLOR_INHERIT;
- else if (v->data_length == 6 &&
- strncasecmp(v->data, "invert", 6) == 0)
- s->outline.color.color = CSS_OUTLINE_COLOR_INVERT;
- }
- else {
- s->outline.color.value = c;
- s->outline.color.color = CSS_OUTLINE_COLOR_COLOR;
- }
-}
-
-void parse_outline_style(struct css_style * const s, const struct css_node * const v)
-{
- css_border_style z;
-
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_border_style_parse(v->data, v->data_length);
- if (z != CSS_BORDER_STYLE_UNKNOWN)
- s->outline.style = z;
-}
-
-void parse_outline_width(struct css_style * const s, const struct css_node * const v)
-{
- struct css_border_width w;
- if (v->next != 0)
- return;
- if (!css_outline_width_parse(v, &w))
- return;
- s->outline.width = w;
-}
-
-
-bool css_outline_width_parse(const struct css_node * v, struct css_border_width * w)
-{
- if (v->type == CSS_NODE_IDENT) {
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0) {
- w->width = CSS_BORDER_WIDTH_INHERIT;
- return true;
- } else if (v->data_length == 4 &&
- strncasecmp(v->data, "thin", 4) == 0) {
- w->width = CSS_BORDER_WIDTH_LENGTH;
- w->value.value = 1;
- w->value.unit = CSS_UNIT_PX;
- return true;
- } else if (v->data_length == 6 &&
- strncasecmp(v->data, "medium", 6) == 0) {
- w->width = CSS_BORDER_WIDTH_LENGTH;
- w->value.value = 2;
- w->value.unit = CSS_UNIT_PX;
- return true;
- } else if (v->data_length == 5 &&
- strncasecmp(v->data, "thick", 5) == 0) {
- w->width = CSS_BORDER_WIDTH_LENGTH;
- w->value.value = 4;
- w->value.unit = CSS_UNIT_PX;
- return true;
- }
- } else if ((v->type == CSS_NODE_DIMENSION ||
- v->type == CSS_NODE_NUMBER) &&
- parse_length(&w->value, v, true) == 0) {
- w->width = CSS_BORDER_WIDTH_LENGTH;
- return true;
- }
-
- return false;
-}
-
-void parse_overflow(struct css_style * const s, const struct css_node * const v)
-{
- css_overflow z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_overflow_parse(v->data, v->data_length);
- if (z != CSS_OVERFLOW_UNKNOWN)
- s->overflow = z;
-}
-
-void parse_padding(struct css_style * const s, const struct css_node * const v)
-{
- unsigned int count = 0;
- const struct css_node *w;
-
- for (w = v; w; w = w->next, count++)
- if (!((w->type == CSS_NODE_IDENT && w->data_length == 7 &&
- strncasecmp(w->data, "inherit", 7) == 0) ||
- (w->type == CSS_NODE_PERCENTAGE) ||
- (w->type == CSS_NODE_DIMENSION) ||
- (w->type == CSS_NODE_NUMBER)))
- return;
-
- w = v;
- switch (count) {
- case 1: /* one value: applies to all sides */
- parse_padding_side(s, w, TOP);
- parse_padding_side(s, w, RIGHT);
- parse_padding_side(s, w, BOTTOM);
- parse_padding_side(s, w, LEFT);
- break;
- case 2: /* (top and bottom), (left and right) */
- parse_padding_side(s, w, TOP);
- parse_padding_side(s, w, BOTTOM);
- w = w->next;
- parse_padding_side(s, w, RIGHT);
- parse_padding_side(s, w, LEFT);
- break;
- case 3: /* top, (left and right), bottom */
- parse_padding_side(s, w, TOP);
- w = w->next;
- parse_padding_side(s, w, RIGHT);
- parse_padding_side(s, w, LEFT);
- w = w->next;
- parse_padding_side(s, w, BOTTOM);
- break;
- case 4: /* top, right, bottom, left */
- parse_padding_side(s, w, TOP);
- w = w->next;
- parse_padding_side(s, w, RIGHT);
- w = w->next;
- parse_padding_side(s, w, BOTTOM);
- w = w->next;
- parse_padding_side(s, w, LEFT);
- break;
- }
-}
-
-#define PARSE_PADDING_(side, z) \
-void parse_padding_ ## side(struct css_style * const s, \
- const struct css_node * const v) \
-{ \
- if (v->next != 0) \
- return; \
- parse_padding_side(s, v, z); \
-}
-
-PARSE_PADDING_(top, TOP)
-PARSE_PADDING_(right, RIGHT)
-PARSE_PADDING_(bottom, BOTTOM)
-PARSE_PADDING_(left, LEFT)
-
-void parse_padding_side(struct css_style * const s, const struct css_node * const v,
- unsigned int i)
-{
- if (v->type == CSS_NODE_IDENT && v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0) {
- s->padding[i].padding = CSS_PADDING_INHERIT;
- } else if (v->type == CSS_NODE_PERCENTAGE) {
- s->padding[i].padding = CSS_PADDING_PERCENT;
- s->padding[i].value.percent = atof(v->data);
- } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) &&
- parse_length(&s->padding[i].value.length, v, true) == 0) {
- s->padding[i].padding = CSS_PADDING_LENGTH;
- }
-}
-
-void parse_page_break_after(struct css_style * const s, const struct css_node * v)
-{
- css_page_break_after z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_page_break_after_parse(v->data, v->data_length);
- if (z != CSS_PAGE_BREAK_AFTER_UNKNOWN)
- s->page_break_after = z;
-}
-
-void parse_page_break_before(struct css_style * const s, const struct css_node * v)
-{
- css_page_break_before z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_page_break_before_parse(v->data, v->data_length);
- if (z != CSS_PAGE_BREAK_BEFORE_UNKNOWN)
- s->page_break_before = z;
-}
-
-void parse_page_break_inside(struct css_style * const s, const struct css_node * v)
-{
- css_page_break_inside z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_page_break_inside_parse(v->data, v->data_length);
- if (z != CSS_PAGE_BREAK_INSIDE_UNKNOWN)
- s->page_break_inside = z;
-}
-
-#define PARSE_POS(side, z) \
-void parse_ ## side(struct css_style * const s, \
- const struct css_node * const v) \
-{ \
- parse_pos(s, v, z); \
-}
-
-PARSE_POS(top, TOP)
-PARSE_POS(right, RIGHT)
-PARSE_POS(bottom, BOTTOM)
-PARSE_POS(left, LEFT)
-
-void parse_pos(struct css_style * const s, const struct css_node * v, unsigned int i)
-{
- if (v->next != 0)
- return;
-
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->pos[i].pos = CSS_POS_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "auto", 4) == 0)
- s->pos[i].pos = CSS_POS_AUTO;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (parse_length(&s->pos[i].value.length, v, false) == 0)
- s->pos[i].pos = CSS_POS_LENGTH;
- break;
- case CSS_NODE_PERCENTAGE:
- s->pos[i].pos = CSS_POS_PERCENT;
- s->pos[i].value.percent = atof(v->data);
- break;
- default:
- break;
- }
-}
-
-void parse_position(struct css_style * const s, const struct css_node * v)
-{
- css_position z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_position_parse(v->data, v->data_length);
- if (z != CSS_POSITION_UNKNOWN)
- s->position = z;
-}
-
-void parse_table_layout(struct css_style * const s, const struct css_node * v)
-{
- css_table_layout z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_table_layout_parse(v->data, v->data_length);
- if (z != CSS_TABLE_LAYOUT_UNKNOWN)
- s->table_layout = z;
-}
-
-void parse_text_align(struct css_style * const s, const struct css_node * const v)
-{
- css_text_align z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_text_align_parse(v->data, v->data_length);
- if (z != CSS_TEXT_ALIGN_UNKNOWN)
- s->text_align = z;
-}
-
-void parse_text_indent(struct css_style * const s, const struct css_node * const v)
-{
- if (v->type == CSS_NODE_IDENT) {
- return;
- } else if (v->type == CSS_NODE_PERCENTAGE) {
- s->text_indent.size = CSS_TEXT_INDENT_PERCENT;
- s->text_indent.value.percent = atof(v->data);
- } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) &&
- parse_length(&s->text_indent.value.length, v, false) == 0) {
- s->text_indent.size = CSS_TEXT_INDENT_LENGTH;
- }
-}
-
-void parse_text_decoration(struct css_style * const s, const struct css_node * const v)
-{
- struct css_node *temp;
- css_text_decoration z;
- if (v->type != CSS_NODE_IDENT)
- return;
- z = css_text_decoration_parse(v->data, v->data_length);
- if (z == CSS_TEXT_DECORATION_INHERIT || z == CSS_TEXT_DECORATION_NONE) {
- if (v->next != 0)
- return;
- s->text_decoration = z;
- }
- if (z != CSS_TEXT_DECORATION_UNKNOWN)
- s->text_decoration |= z;
- for (temp = v->next; temp; temp = temp->next) {
- z = css_text_decoration_parse(temp->data, temp->data_length);
- if (z != CSS_TEXT_DECORATION_UNKNOWN)
- s->text_decoration |= z;
- }
-}
-
-void parse_text_transform(struct css_style * const s, const struct css_node * const v)
-{
- css_text_transform z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_text_transform_parse(v->data, v->data_length);
- if (z != CSS_TEXT_TRANSFORM_UNKNOWN)
- s->text_transform = z;
-}
-
-void parse_unicode_bidi(struct css_style * const s, const struct css_node * const v)
-{
- css_unicode_bidi z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_unicode_bidi_parse(v->data, v->data_length);
- if (z != CSS_UNICODE_BIDI_UNKNOWN)
- s->unicode_bidi = z;
-}
-
-void parse_vertical_align(struct css_style * const s, const struct css_node * v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_INHERIT;
- else if (v->data_length == 8 &&
- strncasecmp(v->data, "baseline", 8) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_BASELINE;
- else if (v->data_length == 3 &&
- strncasecmp(v->data, "sub", 3) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_SUB;
- else if (v->data_length == 5 &&
- strncasecmp(v->data, "super", 5) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_SUPER;
- else if (v->data_length == 3 &&
- strncasecmp(v->data, "top", 3) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_TOP;
- else if (v->data_length == 8 &&
- strncasecmp(v->data, "text-top", 8) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_TEXT_TOP;
- else if (v->data_length == 6 &&
- strncasecmp(v->data, "middle", 6) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_MIDDLE;
- else if (v->data_length == 6 &&
- strncasecmp(v->data, "bottom", 6) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_BOTTOM;
- else if (v->data_length == 11 &&
- strncasecmp(v->data, "text-bottom", 11) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_TEXT_BOTTOM;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (parse_length(&s->vertical_align.value.length, v, false) == 0)
- s->vertical_align.type = CSS_VERTICAL_ALIGN_LENGTH;
- break;
- case CSS_NODE_PERCENTAGE:
- s->vertical_align.value.percent = atof(v->data);
- s->vertical_align.type = CSS_VERTICAL_ALIGN_PERCENT;
- break;
- default:
- break;
- }
-}
-
-void parse_visibility(struct css_style * const s, const struct css_node * const v)
-{
- css_visibility z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_visibility_parse(v->data, v->data_length);
- if (z != CSS_VISIBILITY_UNKNOWN)
- s->visibility = z;
-}
-
-void parse_widows(struct css_style * const s, const struct css_node * const v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->widows.widows = CSS_WIDOWS_INHERIT;
- break;
- case CSS_NODE_NUMBER:
- s->widows.value = atoi(v->data);
- s->widows.widows = CSS_WIDOWS_INTEGER;
- break;
- default:
- break;
- }
-}
-
-void parse_width(struct css_style * const s, const struct css_node * const v)
-{
- if (v->type == CSS_NODE_IDENT && v->data_length == 4 &&
- strncasecmp(v->data, "auto", 4) == 0)
- s->width.width = CSS_WIDTH_AUTO;
- else if (v->type == CSS_NODE_PERCENTAGE) {
- s->width.width = CSS_WIDTH_PERCENT;
- s->width.value.percent = atof(v->data);
- } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) &&
- parse_length(&s->width.value.length, v, true) == 0)
- s->width.width = CSS_WIDTH_LENGTH;
-}
-
-void parse_white_space(struct css_style * const s, const struct css_node * const v)
-{
- css_white_space z;
- if (v->type != CSS_NODE_IDENT || v->next != 0)
- return;
- z = css_white_space_parse(v->data, v->data_length);
- if (z != CSS_WHITE_SPACE_UNKNOWN)
- s->white_space = z;
-}
-
-void parse_word_spacing(struct css_style * const s, const struct css_node * v)
-{
- if (v->next != 0)
- return;
-
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->word_spacing.word_spacing = CSS_WORD_SPACING_INHERIT;
- else if (v->data_length == 6 &&
- strncasecmp(v->data, "normal", 6) == 0)
- s->word_spacing.word_spacing = CSS_WORD_SPACING_NORMAL;
- break;
- case CSS_NODE_DIMENSION:
- case CSS_NODE_NUMBER:
- if (parse_length(&s->word_spacing.length, v, false) == 0)
- s->word_spacing.word_spacing = CSS_WORD_SPACING_LENGTH;
- break;
- default:
- break;
- }
-}
-
-void parse_z_index(struct css_style * const s, const struct css_node * const v)
-{
- if (v->next != 0)
- return;
- switch (v->type) {
- case CSS_NODE_IDENT:
- if (v->data_length == 7 &&
- strncasecmp(v->data, "inherit", 7) == 0)
- s->z_index.z_index = CSS_Z_INDEX_INHERIT;
- else if (v->data_length == 4 &&
- strncasecmp(v->data, "auto", 4) == 0)
- s->z_index.z_index = CSS_Z_INDEX_AUTO;
- break;
- case CSS_NODE_NUMBER:
- s->z_index.value = atoi(v->data);
- s->z_index.z_index = CSS_Z_INDEX_INTEGER;
- break;
- default:
- break;
- }
-}
-
-css_text_decoration css_text_decoration_parse(const char * const s,
- int length)
-{
- if (length == 7 && strncasecmp(s, "inherit", 7) == 0)
- return CSS_TEXT_DECORATION_INHERIT;
- if (length == 4 && strncasecmp(s, "none", 4) == 0)
- return CSS_TEXT_DECORATION_NONE;
- if (length == 5 && strncasecmp(s, "blink", 5) == 0)
- return CSS_TEXT_DECORATION_BLINK;
- if (length == 12 && strncasecmp(s, "line-through", 12) == 0)
- return CSS_TEXT_DECORATION_LINE_THROUGH;
- if (length == 8 && strncasecmp(s, "overline", 8) == 0)
- return CSS_TEXT_DECORATION_OVERLINE;
- if (length == 9 && strncasecmp(s, "underline", 9) == 0)
- return CSS_TEXT_DECORATION_UNDERLINE;
- return CSS_TEXT_DECORATION_UNKNOWN;
-}
-
-/** \} */
diff --git a/css/scanner.l b/css/scanner.l
deleted file mode 100644
index 91574954e..000000000
--- a/css/scanner.l
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * This file is part of NetSurf, http://netsurf-browser.org/
- * Licensed under the GNU General Public License,
- * http://www.opensource.org/licenses/gpl-license
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- */
-
-/** \file
- * CSS tokeniser using re2c.
- *
- * see CSS2 Specification, chapter 4
- * http://www.w3.org/TR/REC-CSS2/syndata.html,
- * and errata
- * http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata
- */
-
-#include <stdbool.h>
-#define CSS_INTERNALS
-#include "css/css.h"
-#include "css/parser.h"
-
-#define YYCTYPE unsigned char
-#define YYCURSOR (*buffer)
-#define YYLIMIT end
-#define YYMARKER marker
-#define YYFILL(n) { return 0; }
-
-
-/**
- * Identify a CSS source token.
- *
- * \param buffer source to tokenise, updated to new position
- * \param end end of source
- * \param token_text updated to start of recognized token
- * \return token number
- */
-
-int css_tokenise(unsigned char **buffer, unsigned char *end,
- unsigned char **token_text)
-{
- unsigned char *marker;
-
-start:
- *token_text = YYCURSOR;
-
-/*!re2c
-nonascii = [\200-\377];
-unicode = "\\" [0-9a-f]+ ("\r\n" | [ \n\r\t\f])?;
-escape = unicode | "\\" [^\n\r\f0-9a-f];
-nmchar = [-a-zA-Z0-9_] | nonascii | escape;
-nmstart = [a-zA-Z_] | nonascii | escape;
-ident = [-]? nmstart nmchar*;
-name = nmchar+;
-num = [+-]? ([0-9]+ | [0-9]* "." [0-9]+);
-nl = "\n" | "\r\n" | "\r" | "\f";
-string1 = "\"" ([\t !#$%&(-~] | "\\" nl | "'" | nonascii | escape)* "\"";
-string2 = "'" ([\t !#$%&(-~] | "\\" nl | "\""| nonascii | escape)* "'";
-string = string1 | string2;
-s = [ \t\r\n\f];
-w = s*;
-any = [\000-\377];
-
-ident { return IDENT; }
-"@" ident { return ATKEYWORD; }
-string { return STRING; }
-"#" name { return HASH; }
-
-num { return NUMBER; }
-num "%" { return PERCENTAGE; }
-num ident { return DIMENSION; }
-
-"url(" w string w ")" | "url(" w ([!#$%&*-~]|nonascii|escape)* w ")"
- { return URI; }
-"U+" [0-9A-F?]+ ("-" [0-9A-F]+ )?
- { return UNICODE_RANGE; }
-
-"<!--" { goto start; /* ignore CDO */ }
-"-->" { goto start; /* ignore CDC */ }
-
-";" { return SEMI; }
-"{" { return LBRACE; }
-"}" { return RBRACE; }
-"(" { return LPAREN; }
-")" { return RPAREN; }
-"[" { return LBRAC; }
-"]" { return RBRAC; }
-
-s+ { return S; }
-
-"/*" (any\[*])* "*"+ ((any\[/*]) (any\[*])* "*"+)* "/"
- { goto start; /* ignore comments */ }
-
-ident "(" { return FUNCTION; }
-
-"~=" { return INCLUDES; }
-"|=" { return DASHMATCH; }
-"^=" { return PREFIX; }
-"$=" { return SUFFIX; }
-"*=" { return SUBSTR; }
-
-"=" { return EQUALS; }
-":" { return COLON; }
-"," { return COMMA; }
-"+" { return PLUS; }
-">" { return GT; }
-"." { return DOT; }
-"*" { return ASTERISK; }
-
-any { return DELIM; }
-*/
-
-}
diff --git a/css/select.c b/css/select.c
new file mode 100644
index 000000000..0f2f7327e
--- /dev/null
+++ b/css/select.c
@@ -0,0 +1,1981 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <strings.h>
+
+#include "content/content.h"
+#include "content/urldb.h"
+#include "css/internal.h"
+#include "css/select.h"
+#include "css/utils.h"
+#include "desktop/options.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+static css_error node_name(void *pw, void *node,
+ lwc_context *dict, lwc_string **name);
+static css_error named_ancestor_node(void *pw, void *node,
+ lwc_string *name, void **ancestor);
+static css_error named_parent_node(void *pw, void *node,
+ lwc_string *name, void **parent);
+static css_error named_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,
+ lwc_string *name, bool *match);
+static css_error node_has_class(void *pw, void *node,
+ lwc_string *name, bool *match);
+static css_error node_has_id(void *pw, void *node,
+ lwc_string *name, bool *match);
+static css_error node_has_attribute(void *pw, void *node,
+ lwc_string *name, bool *match);
+static css_error node_has_attribute_equal(void *pw, void *node,
+ lwc_string *name, lwc_string *value,
+ bool *match);
+static css_error node_has_attribute_dashmatch(void *pw, void *node,
+ lwc_string *name, lwc_string *value,
+ bool *match);
+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_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_lang(void *pw, void *node,
+ lwc_string *lang, bool *match);
+static css_error node_presentational_hint(void *pw, void *node,
+ uint32_t property, css_hint *hint);
+static css_error ua_default_for_property(void *pw, uint32_t property,
+ css_hint *hint);
+
+static int cmp_colour_name(const void *a, const void *b);
+static bool parse_named_colour(const char *data, css_color *result);
+static bool parse_dimension(const char *data, bool strict,
+ css_fixed *length, css_unit *unit);
+static bool parse_number(const char *data, bool non_negative, bool real,
+ css_fixed *value, size_t *consumed);
+
+static bool isWhitespace(char c);
+static bool isHex(char c);
+static uint8_t charToHex(char c);
+
+/**
+ * Selection callback table for libcss
+ */
+static css_select_handler selection_handler = {
+ node_name,
+ named_ancestor_node,
+ named_parent_node,
+ named_sibling_node,
+ parent_node,
+ sibling_node,
+ node_has_name,
+ node_has_class,
+ node_has_id,
+ node_has_attribute,
+ node_has_attribute_equal,
+ node_has_attribute_dashmatch,
+ node_has_attribute_includes,
+ node_is_first_child,
+ node_is_link,
+ node_is_visited,
+ node_is_hover,
+ node_is_active,
+ node_is_focus,
+ node_is_lang,
+ node_presentational_hint,
+ ua_default_for_property,
+ nscss_compute_font_size
+};
+
+/**
+ * Create an inline style
+ *
+ * \param data Source data
+ * \param len Length of data in bytes
+ * \param charset Charset of data, or NULL if unknown
+ * \param url URL of document containing data
+ * \param allow_quirks True to permit CSS parsing quirks
+ * \param dict String internment context
+ * \param alloc Memory allocation function
+ * \param pw Private word for allocator
+ * \return Pointer to stylesheet, or NULL on failure.
+ */
+css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
+ const char *charset, const char *url, bool allow_quirks,
+ lwc_context *dict, css_allocator_fn alloc, void *pw)
+{
+ css_stylesheet *sheet;
+ css_error error;
+
+ error = css_stylesheet_create(CSS_LEVEL_DEFAULT, charset, url, NULL,
+ CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL, allow_quirks, true,
+ dict, alloc, pw, nscss_resolve_url, NULL, &sheet);
+ if (error != CSS_OK)
+ return NULL;
+
+ error = css_stylesheet_append_data(sheet, data, len);
+ if (error != CSS_OK && error != CSS_NEEDDATA) {
+ css_stylesheet_destroy(sheet);
+ return NULL;
+ }
+
+ error = css_stylesheet_data_done(sheet);
+ if (error != CSS_OK) {
+ css_stylesheet_destroy(sheet);
+ return NULL;
+ }
+
+ return sheet;
+}
+
+/**
+ * Get a style for an element
+ *
+ * \param html HTML document
+ * \param n Element to select for
+ * \param pseudo_element Pseudo element to select for, instead
+ * \param media Permitted media types
+ * \param inline_style Inline style associated with element, or NULL
+ * \param alloc Memory allocation function
+ * \param pw Private word for allocator
+ * \return Pointer to partial computed style, or NULL on failure
+ */
+css_computed_style *nscss_get_style(struct content *html, xmlNode *n,
+ uint32_t pseudo_element, uint64_t media,
+ const css_stylesheet *inline_style,
+ css_allocator_fn alloc, void *pw)
+{
+ css_computed_style *style;
+ css_error error;
+
+ assert(html->type == CONTENT_HTML);
+
+ error = css_computed_style_create(alloc, pw, &style);
+ if (error != CSS_OK)
+ return NULL;
+
+ error = css_select_style(html->data.html.select_ctx, n,
+ pseudo_element, media, inline_style, style,
+ &selection_handler, html);
+ if (error != CSS_OK) {
+ css_computed_style_destroy(style);
+ return NULL;
+ }
+
+ return style;
+}
+
+/**
+ * Get an initial style
+ *
+ * \param html HTML document
+ * \param alloc Memory allocation function
+ * \param pw Private word for allocator
+ * \return Pointer to partial computed style, or NULL on failure
+ */
+css_computed_style *nscss_get_initial_style(struct content *html,
+ css_allocator_fn alloc, void *pw)
+{
+ css_computed_style *style;
+ css_error error;
+
+ assert(html->type == CONTENT_HTML);
+
+ error = css_computed_style_create(alloc, pw, &style);
+ if (error != CSS_OK)
+ return NULL;
+
+ error = css_computed_style_initialise(style, &selection_handler, html);
+ if (error != CSS_OK) {
+ css_computed_style_destroy(style);
+ return NULL;
+ }
+
+ return style;
+}
+
+/**
+ * Get a blank style
+ *
+ * \param html HTML document
+ * \param parent Parent style to cascade inherited properties from
+ * \param alloc Memory allocation function
+ * \param pw Private word for allocator
+ * \return Pointer to blank style, or NULL on failure
+ */
+css_computed_style *nscss_get_blank_style(struct content *html,
+ const css_computed_style *parent,
+ css_allocator_fn alloc, void *pw)
+{
+ css_computed_style *partial;
+ css_error error;
+
+ assert(html->type == CONTENT_HTML);
+
+ partial = nscss_get_initial_style(html, alloc, pw);
+ if (partial == NULL)
+ return NULL;
+
+ error = css_computed_style_compose(parent, partial,
+ nscss_compute_font_size, NULL, partial);
+ if (error != CSS_OK) {
+ css_computed_style_destroy(partial);
+ return NULL;
+ }
+
+ return partial;
+}
+
+/**
+ * Font size computation callback for libcss
+ *
+ * \param pw Computation context
+ * \param parent Parent font size (absolute)
+ * \param size Font size to compute
+ * \return CSS_OK on success
+ *
+ * \post \a size will be an absolute font size
+ */
+css_error nscss_compute_font_size(void *pw, const css_hint *parent,
+ css_hint *size)
+{
+ /**
+ * Table of font-size keyword scale factors
+ *
+ * These are multiplied by the configured default font size
+ * to produce an absolute size for the relevant keyword
+ */
+ static const css_fixed factors[] = {
+ FLTTOFIX(0.5625), /* xx-small */
+ FLTTOFIX(0.6250), /* x-small */
+ FLTTOFIX(0.8125), /* small */
+ FLTTOFIX(1.0000), /* medium */
+ FLTTOFIX(1.1250), /* large */
+ FLTTOFIX(1.5000), /* x-large */
+ FLTTOFIX(2.0000) /* xx-large */
+ };
+ css_hint_length parent_size;
+
+ /* Grab parent size, defaulting to medium if none */
+ if (parent == NULL) {
+ parent_size.value = FDIVI(
+ FMULI(factors[CSS_FONT_SIZE_MEDIUM - 1],
+ option_font_size), 10);
+ parent_size.unit = CSS_UNIT_PT;
+ } else {
+ assert(parent->status == CSS_FONT_SIZE_DIMENSION);
+ assert(parent->data.length.unit != CSS_UNIT_EM);
+ assert(parent->data.length.unit != CSS_UNIT_EX);
+ assert(parent->data.length.unit != CSS_UNIT_PCT);
+
+ parent_size = parent->data.length;
+ }
+
+ assert(size->status != CSS_FONT_SIZE_INHERIT);
+
+ if (size->status < CSS_FONT_SIZE_LARGER) {
+ /* Keyword -- simple */
+ size->data.length.value = FDIVI(
+ FMULI(factors[size->status - 1],
+ option_font_size), 10);
+ size->data.length.unit = CSS_UNIT_PT;
+ } else if (size->status == CSS_FONT_SIZE_LARGER) {
+ /** \todo Step within table, if appropriate */
+ size->data.length.value =
+ FMUL(parent_size.value, FLTTOFIX(1.2));
+ size->data.length.unit = parent_size.unit;
+ } else if (size->status == CSS_FONT_SIZE_SMALLER) {
+ /** \todo Step within table, if appropriate */
+ size->data.length.value =
+ FDIV(parent_size.value, FLTTOFIX(1.2));
+ size->data.length.unit = parent_size.unit;
+ } else if (size->data.length.unit == CSS_UNIT_EM ||
+ size->data.length.unit == CSS_UNIT_EX) {
+ size->data.length.value =
+ FMUL(size->data.length.value, parent_size.value);
+
+ if (size->data.length.unit == CSS_UNIT_EX) {
+ /* 1ex = 0.6em in NetSurf */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(0.6));
+ }
+
+ size->data.length.unit = parent_size.unit;
+ } else if (size->data.length.unit == CSS_UNIT_PCT) {
+ size->data.length.value = FDIV(FMUL(size->data.length.value,
+ parent_size.value), INTTOFIX(100));
+ size->data.length.unit = parent_size.unit;
+ }
+
+ size->status = CSS_FONT_SIZE_DIMENSION;
+
+ return CSS_OK;
+}
+
+/**
+ * Parser for colours specified in attribute values.
+ *
+ * \param data Data to parse (NUL-terminated)
+ * \param result Pointer to location to receive resulting css_color
+ * \return true on success, false on invalid input
+ */
+bool nscss_parse_colour(const char *data, css_color *result)
+{
+ size_t len = strlen(data);
+ uint8_t r, g, b;
+
+ /* 2 */
+ if (len == 0)
+ return false;
+
+ /* 3 */
+ if (len == SLEN("transparent") && strcasecmp(data, "transparent") == 0)
+ return false;
+
+ /* 4 */
+ if (parse_named_colour(data, result))
+ return true;
+
+ /** \todo Implement HTML5's utterly insane legacy colour parsing */
+
+ if (data[0] == '#') {
+ data++;
+ len--;
+ }
+
+ if (len == 3 && isHex(data[0]) && isHex(data[1]) && isHex(data[2])) {
+ r = charToHex(data[0]);
+ g = charToHex(data[1]);
+ b = charToHex(data[2]);
+
+ r |= (r << 4);
+ g |= (g << 4);
+ b |= (b << 4);
+
+ *result = (r << 24) | (g << 16) | (b << 8);
+
+ return true;
+ } else if (len == 6 && isHex(data[0]) && isHex(data[1]) &&
+ isHex(data[2]) && isHex(data[3]) && isHex(data[4]) &&
+ isHex(data[5])) {
+ r = (charToHex(data[0]) << 4) | charToHex(data[1]);
+ g = (charToHex(data[2]) << 4) | charToHex(data[3]);
+ b = (charToHex(data[4]) << 4) | charToHex(data[5]);
+
+ *result = (r << 24) | (g << 16) | (b << 8);
+
+ return true;
+ }
+
+ return false;
+}
+
+/******************************************************************************
+ * Style selection callbacks *
+ ******************************************************************************/
+
+/**
+ * Callback to retrieve a node's name.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param dict Dictionary to intern result in
+ * \param name Pointer to location to receive node name
+ * \return CSS_OK on success,
+ * CSS_NOMEM on memory exhaustion.
+ */
+css_error node_name(void *pw, void *node,
+ lwc_context *dict, lwc_string **name)
+{
+ xmlNode *n = node;
+ lwc_error lerror;
+
+ lerror = lwc_context_intern(dict, (const char *) n->name,
+ strlen((const char *) n->name), name);
+ switch (lerror) {
+ case lwc_error_oom:
+ return CSS_NOMEM;
+ case lwc_error_range:
+ assert(0);
+ default:
+ break;
+ }
+
+ return CSS_OK;
+
+}
+
+/**
+ * Callback to find a named ancestor node.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Node name to search for
+ * \param ancestor Pointer to location to receive ancestor
+ * \return CSS_OK.
+ *
+ * \post \a ancestor will contain the result, or NULL if there is no match
+ */
+css_error named_ancestor_node(void *pw, void *node,
+ lwc_string *name, void **ancestor)
+{
+ xmlNode *n = node;
+ size_t len = lwc_string_length(name);
+ const char *data = lwc_string_data(name);
+
+ *ancestor = NULL;
+
+ for (n = n->parent; n != NULL && n->type == XML_ELEMENT_NODE;
+ n = n->parent) {
+ bool match = strlen((const char *) n->name) == len &&
+ strncasecmp((const char *) n->name,
+ data, len) == 0;
+
+ if (match) {
+ *ancestor = (void *) n;
+ break;
+ }
+ }
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to find a named parent node
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Node name to search for
+ * \param parent Pointer to location to receive parent
+ * \return CSS_OK.
+ *
+ * \post \a parent will contain the result, or NULL if there is no match
+ */
+css_error named_parent_node(void *pw, void *node,
+ lwc_string *name, void **parent)
+{
+ xmlNode *n = node;
+ size_t len = lwc_string_length(name);
+ const char *data = lwc_string_data(name);
+
+ *parent = NULL;
+
+ if (n->parent != NULL && n->parent->type == XML_ELEMENT_NODE &&
+ strlen((const char *) n->parent->name) == len &&
+ strncasecmp((const char *) n->parent->name,
+ data, len) == 0)
+ *parent = (void *) n->parent;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to find a named sibling node.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Node name to search for
+ * \param sibling Pointer to location to receive sibling
+ * \return CSS_OK.
+ *
+ * \post \a sibling will contain the result, or NULL if there is no match
+ */
+css_error named_sibling_node(void *pw, void *node,
+ lwc_string *name, void **sibling)
+{
+ xmlNode *n = node;
+ size_t len = lwc_string_length(name);
+ const char *data = lwc_string_data(name);
+
+ *sibling = NULL;
+
+ while (n->prev != NULL && n->prev->type != XML_ELEMENT_NODE)
+ n = n->prev;
+
+ if (n->prev != NULL && strlen((const char *) n->prev->name) == len &&
+ strncasecmp((const char *) n->prev->name,
+ data, len) == 0)
+ *sibling = (void *) n->prev;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to retrieve the parent of a node.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param parent Pointer to location to receive parent
+ * \return CSS_OK.
+ *
+ * \post \a parent will contain the result, or NULL if there is no match
+ */
+css_error parent_node(void *pw, void *node, void **parent)
+{
+ xmlNode *n = node;
+
+ if (n->parent != NULL && n->parent->type == XML_ELEMENT_NODE)
+ *parent = (void *) n->parent;
+ else
+ *parent = NULL;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to retrieve the preceding sibling of a node.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param sibling Pointer to location to receive sibling
+ * \return CSS_OK.
+ *
+ * \post \a sibling will contain the result, or NULL if there is no match
+ */
+css_error sibling_node(void *pw, void *node, void **sibling)
+{
+ xmlNode *n = node;
+
+ while (n->prev != NULL && n->prev->type != XML_ELEMENT_NODE)
+ n = n->prev;
+
+ *sibling = (void *) n->prev;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has the given name.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Name to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_has_name(void *pw, void *node,
+ lwc_string *name, bool *match)
+{
+ xmlNode *n = node;
+ size_t len = lwc_string_length(name);
+ const char *data = lwc_string_data(name);
+
+ /* Element names are case insensitive in HTML */
+ *match = strlen((const char *) n->name) == len &&
+ strncasecmp((const char *) n->name, data, len) == 0;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has the given class.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Name to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_has_class(void *pw, void *node,
+ lwc_string *name, bool *match)
+{
+ struct content *html = pw;
+ xmlNode *n = node;
+ xmlAttr *class;
+ xmlChar *value = NULL;
+ const char *p;
+ const char *start;
+ const char *data;
+ size_t len;
+ int (*cmp)(const char *, const char *, size_t);
+
+ /* Class names are case insensitive in quirks mode */
+ if (html->data.html.quirks == BINDING_QUIRKS_MODE_FULL)
+ cmp = strncasecmp;
+ else
+ cmp = strncmp;
+
+ *match = false;
+
+ /* See if there is a class attribute on this node */
+ class = xmlHasProp(n, (const xmlChar *) "class");
+ if (class == NULL)
+ return CSS_OK;
+
+ /* We have a class attribute -- extract its value */
+ if (class->children != NULL && class->children->next == NULL &&
+ class->children->children == NULL) {
+ /* Simple case -- no XML entities */
+ start = (const char *) class->children->content;
+ } else {
+ /* Awkward case -- fall back to string copying */
+ value = xmlGetProp(n, (const xmlChar *) "class");
+ if (value == NULL)
+ return CSS_OK;
+
+ start = (const char *) value;
+ }
+
+ /* Extract expected class name data */
+ data = lwc_string_data(name);
+ len = lwc_string_length(name);
+
+ /* The class attribute is a space separated list of tokens.
+ * Search it for the one we're looking for.
+ */
+ do {
+ /* Find next space or end of string */
+ p = strchrnul(start, ' ');
+
+ /* Does it match? */
+ if ((size_t) (p - start) == len && cmp(start, data, len) == 0) {
+ *match = true;
+ break;
+ }
+
+ /* Move to start of next token in string */
+ start = p + 1;
+ } while (*p != '\0');
+
+ /* Clean up, if necessary */
+ if (value != NULL) {
+ xmlFree(value);
+ }
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has the given id.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Name to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_has_id(void *pw, void *node,
+ lwc_string *name, bool *match)
+{
+ xmlNode *n = node;
+ xmlAttr *id;
+ xmlChar *value = NULL;
+ const char *start;
+ const char *data;
+ size_t len;
+
+ *match = false;
+
+ /* See if there's an id attribute on this node */
+ id = xmlHasProp(n, (const xmlChar *) "id");
+ if (id == NULL)
+ return CSS_OK;
+
+ /* We have an id attribute -- extract its value */
+ if (id->children != NULL && id->children->next == NULL &&
+ id->children->children == NULL) {
+ /* Simple case -- no XML entities */
+ start = (const char *) id->children->content;
+ } else {
+ /* Awkward case -- fall back to string copying */
+ value = xmlGetProp(n, (const xmlChar *) "id");
+ if (value == NULL)
+ return CSS_OK;
+
+ start = (const char *) value;
+ }
+
+ /* Extract expected id data */
+ len = lwc_string_length(name);
+ data = lwc_string_data(name);
+
+ /* Compare */
+ *match = strlen(start) == len && strncmp(start, data, len) == 0;
+
+ /* Clean up if necessary */
+ if (value != NULL) {
+ xmlFree(value);
+ }
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has an attribute with the given name.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Name to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK on success,
+ * CSS_NOMEM on memory exhaustion.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_has_attribute(void *pw, void *node,
+ lwc_string *name, bool *match)
+{
+ xmlNode *n = node;
+ xmlAttr *attr;
+ char *buf;
+
+ buf = malloc(lwc_string_length(name) + 1);
+ if (buf == NULL)
+ return CSS_NOMEM;
+
+ memcpy(buf, lwc_string_data(name), lwc_string_length(name));
+ buf[lwc_string_length(name)] = '\0';
+
+ attr = xmlHasProp(n, (const xmlChar *) buf);
+ *match = attr != NULL;
+
+ free(buf);
+
+ return CSS_OK;
+
+}
+
+/**
+ * Callback to determine if a node has an attribute with given name and value.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Name to match
+ * \param value Value to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK on success,
+ * CSS_NOMEM on memory exhaustion.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_has_attribute_equal(void *pw, void *node,
+ lwc_string *name, lwc_string *value,
+ bool *match)
+{
+ xmlNode *n = node;
+ xmlChar *attr;
+ char *buf;
+
+ buf = malloc(lwc_string_length(name) + 1);
+ if (buf == NULL)
+ return CSS_NOMEM;
+
+ memcpy(buf, lwc_string_data(name), lwc_string_length(name));
+ buf[lwc_string_length(name)] = '\0';
+
+ *match = false;
+
+ attr = xmlGetProp(n, (const xmlChar *) buf);
+ if (attr != NULL) {
+ *match = strlen((const char *) attr) ==
+ lwc_string_length(value) &&
+ strncmp((const char *) attr,
+ lwc_string_data(value),
+ lwc_string_length(value)) == 0;
+ xmlFree(attr);
+ }
+
+ free(buf);
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has an attribute with the given name whose
+ * value dashmatches that given.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Name to match
+ * \param value Value to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK on success,
+ * CSS_NOMEM on memory exhaustion.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_has_attribute_dashmatch(void *pw, void *node,
+ lwc_string *name, lwc_string *value,
+ bool *match)
+{
+ xmlNode *n = node;
+ xmlChar *attr;
+ char *buf;
+ size_t vlen = lwc_string_length(value);
+
+ buf = malloc(lwc_string_length(name) + 1);
+ if (buf == NULL)
+ return CSS_NOMEM;
+
+ memcpy(buf, lwc_string_data(name), lwc_string_length(name));
+ buf[lwc_string_length(name)] = '\0';
+
+ *match = false;
+
+ attr = xmlGetProp(n, (const xmlChar *) buf);
+ if (attr != NULL) {
+ const char *p;
+ const char *start = (const char *) attr;
+ const char *end = start + strlen(start);
+
+ for (p = start; p <= end; p++) {
+ if (*p == '-' || *p == '\0') {
+ if ((size_t) (p - start) == vlen &&
+ strncasecmp(start,
+ lwc_string_data(value),
+ vlen) == 0) {
+ *match = true;
+ break;
+ }
+
+ start = p + 1;
+ }
+ }
+ }
+
+ free(buf);
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has an attribute with the given name whose
+ * value includes that given.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param name Name to match
+ * \param value Value to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK on success,
+ * CSS_NOMEM on memory exhaustion.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_has_attribute_includes(void *pw, void *node,
+ lwc_string *name, lwc_string *value,
+ bool *match)
+{
+ xmlNode *n = node;
+ xmlChar *attr;
+ char *buf;
+ size_t vlen = lwc_string_length(value);
+
+ buf = malloc(lwc_string_length(name) + 1);
+ if (buf == NULL)
+ return CSS_NOMEM;
+
+ memcpy(buf, lwc_string_data(name), lwc_string_length(name));
+ buf[lwc_string_length(name)] = '\0';
+
+ *match = false;
+
+ attr = xmlGetProp(n, (const xmlChar *) buf);
+ if (attr != NULL) {
+ const char *p;
+ const char *start = (const char *) attr;
+ const char *end = start + strlen(start);
+
+ for (p = start; p <= end; p++) {
+ if (*p == ' ' || *p == '\0') {
+ if ((size_t) (p - start) == vlen &&
+ strncasecmp(start,
+ lwc_string_data(value),
+ vlen) == 0) {
+ *match = true;
+ break;
+ }
+
+ start = p + 1;
+ }
+ }
+ }
+
+ free(buf);
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node is the first child of its parent.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_is_first_child(void *pw, void *node, bool *match)
+{
+ xmlNode *n = node;
+
+ *match = (n->parent != NULL && n->parent->children == n);
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node is a linking element.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_is_link(void *pw, void *node, bool *match)
+{
+ xmlNode *n = node;
+
+ *match = (strcasecmp((const char *) n->name, "a") == 0 &&
+ xmlHasProp(n, (const xmlChar *) "href") != NULL);
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node is a linking element whose target has been
+ * visited.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_is_visited(void *pw, void *node, bool *match)
+{
+ *match = false;
+
+ /** \todo Implement visted check in a more performant way */
+
+#ifdef SUPPORT_VISITED
+ struct content *html = pw;
+ xmlNode *n = node;
+
+ if (strcasecmp((const char *) n->name, "a") == 0) {
+ char *url, *nurl;
+ url_func_result res;
+ xmlChar *href = xmlGetProp(n, (const xmlChar *) "href");
+
+ if (href == NULL)
+ return CSS_OK;
+
+ /* Make href absolute */
+ res = url_join((const char *) href,
+ html->data.html.base_url, &url);
+
+ xmlFree(href);
+
+ if (res == URL_FUNC_NOMEM) {
+ return CSS_NOMEM;
+ } else if (res == URL_FUNC_OK) {
+ /* Normalize it */
+ res = url_normalize(url, &nurl);
+
+ free(url);
+
+ if (res == URL_FUNC_NOMEM) {
+ return CSS_NOMEM;
+ } else if (res == URL_FUNC_OK) {
+ const struct url_data *data;
+
+ data = urldb_get_url_data(nurl);
+
+ /* Visited if in the db and has
+ * non-zero visit count */
+ if (data != NULL && data->visits > 0)
+ *match = true;
+
+ free(nurl);
+ }
+ }
+ }
+#endif
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node is currently being hovered over.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_is_hover(void *pw, void *node, bool *match)
+{
+ /** \todo Support hovering */
+
+ *match = false;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node is currently activated.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_is_active(void *pw, void *node, bool *match)
+{
+ /** \todo Support active nodes */
+
+ *match = false;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has the input focus.
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_is_focus(void *pw, void *node, bool *match)
+{
+ /** \todo Support focussed nodes */
+
+ *match = false;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to determine if a node has the given language
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param lang Language specifier to match
+ * \param match Pointer to location to receive result
+ * \return CSS_OK.
+ *
+ * \post \a match will contain true if the node matches and false otherwise.
+ */
+css_error node_is_lang(void *pw, void *node,
+ lwc_string *lang, bool *match)
+{
+ /** \todo Support languages */
+
+ *match = false;
+
+ return CSS_OK;
+}
+
+/**
+ * Callback to retrieve presentational hints for a node
+ *
+ * \param pw HTML document
+ * \param node DOM node
+ * \param property CSS property to retrieve
+ * \param hint Pointer to hint object to populate
+ * \return CSS_OK on success,
+ * CSS_PROPERTY_NOT_SET if there is no hint for the requested property,
+ * CSS_NOMEM on memory exhaustion.
+ */
+css_error node_presentational_hint(void *pw, void *node,
+ uint32_t property, css_hint *hint)
+{
+ struct content *html = pw;
+ xmlNode *n = node;
+
+ if (property == CSS_PROP_BACKGROUND_IMAGE) {
+ char *url;
+ url_func_result res;
+ xmlChar *bg = xmlGetProp(n, (const xmlChar *) "background");
+
+ if (bg == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+
+ res = url_join((const char *) bg,
+ html->data.html.base_url, &url);
+
+ xmlFree(bg);
+
+ if (res == URL_FUNC_NOMEM) {
+ return CSS_NOMEM;
+ } else if (res == URL_FUNC_OK) {
+ lwc_string *iurl;
+ lwc_error lerror;
+
+ lerror = lwc_context_intern(
+ html->data.html.dict, url,
+ strlen(url), &iurl);
+
+ free(url);
+
+ if (lerror == lwc_error_oom) {
+ return CSS_NOMEM;
+ } else if (lerror == lwc_error_ok) {
+ hint->data.string = iurl;
+ hint->status = CSS_BACKGROUND_IMAGE_IMAGE;
+ return CSS_OK;
+ }
+ }
+ } else if (property == CSS_PROP_BACKGROUND_COLOR) {
+ xmlChar *bgcol = xmlGetProp(n, (const xmlChar *) "bgcolor");
+ if (bgcol == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (nscss_parse_colour((const char *) bgcol,
+ &hint->data.color)) {
+ hint->status = CSS_BACKGROUND_COLOR_COLOR;
+ } else {
+ xmlFree(bgcol);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(bgcol);
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_COLOR) {
+ xmlChar *col;
+ css_error error;
+ bool is_link, is_visited;
+
+ error = node_is_link(html, n, &is_link);
+ if (error != CSS_OK)
+ return error;
+
+ if (is_link) {
+ xmlNode *body;
+ for (body = n; body != NULL && body->parent != NULL &&
+ body->parent->parent != NULL;
+ body = body->parent) {
+ if (body->parent->parent->parent == NULL)
+ break;
+ }
+
+ error = node_is_visited(html, n, &is_visited);
+ if (error != CSS_OK)
+ return error;
+
+ if (is_visited)
+ col = xmlGetProp(body,
+ (const xmlChar *) "vlink");
+ else
+ col = xmlGetProp(body,
+ (const xmlChar *) "link");
+ } else if (strcmp((const char *) n->name, "body") == 0) {
+ col = xmlGetProp(n, (const xmlChar *) "text");
+ } else {
+ col = xmlGetProp(n, (const xmlChar *) "color");
+ }
+
+ if (col == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (nscss_parse_colour((const char *) col, &hint->data.color)) {
+ hint->status = CSS_COLOR_COLOR;
+ } else {
+ xmlFree(col);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(col);
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_HEIGHT) {
+ xmlChar *height;
+
+ if (strcmp((const char *) n->name, "iframe") == 0 ||
+ strcmp((const char *) n->name, "td") == 0 ||
+ strcmp((const char *) n->name, "th") == 0 ||
+ strcmp((const char *) n->name, "tr") == 0 ||
+ strcmp((const char *) n->name, "img") == 0 ||
+ strcmp((const char *) n->name, "object") == 0 ||
+ strcmp((const char *) n->name, "applet") == 0)
+ height = xmlGetProp(n, (const xmlChar *) "height");
+ else if (strcmp((const char *) n->name, "textarea") == 0)
+ height = xmlGetProp(n, (const xmlChar *) "rows");
+ else
+ height = NULL;
+
+ if (height == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (parse_dimension((const char *) height, false,
+ &hint->data.length.value,
+ &hint->data.length.unit)) {
+ hint->status = CSS_HEIGHT_SET;
+ } else {
+ xmlFree(height);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(height);
+
+ if (strcmp((const char *) n->name, "textarea") == 0)
+ hint->data.length.unit = CSS_UNIT_EM;
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_WIDTH) {
+ xmlChar *width;
+
+ if (strcmp((const char *) n->name, "hr") == 0 ||
+ strcmp((const char *) n->name, "iframe") == 0 ||
+ strcmp((const char *) n->name, "img") == 0 ||
+ strcmp((const char *) n->name, "object") == 0 ||
+ strcmp((const char *) n->name, "table") == 0 ||
+ strcmp((const char *) n->name, "td") == 0 ||
+ strcmp((const char *) n->name, "th") == 0 ||
+ strcmp((const char *) n->name, "applet") == 0)
+ width = xmlGetProp(n, (const xmlChar *) "width");
+ else if (strcmp((const char *) n->name, "textarea") == 0)
+ width = xmlGetProp(n, (const xmlChar *) "cols");
+ else if (strcmp((const char *) n->name, "input") == 0) {
+ width = xmlGetProp(n, (const xmlChar *) "size");
+ } else
+ width = NULL;
+
+ if (width == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (parse_dimension((const char *) width, false,
+ &hint->data.length.value,
+ &hint->data.length.unit)) {
+ hint->status = CSS_WIDTH_SET;
+ } else {
+ xmlFree(width);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(width);
+
+ if (strcmp((const char *) n->name, "textarea") == 0)
+ hint->data.length.unit = CSS_UNIT_EX;
+ else if (strcmp((const char *) n->name, "input") == 0) {
+ xmlChar *type = xmlGetProp(n, (const xmlChar *) "type");
+
+ if (type == NULL || strcasecmp((const char *) type,
+ "text") == 0 ||
+ strcasecmp((const char *) type,
+ "password") == 0)
+ hint->data.length.unit = CSS_UNIT_EX;
+
+ if (type != NULL)
+ xmlFree(type);
+ }
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_BORDER_SPACING) {
+ xmlChar *cellspacing;
+
+ if (strcmp((const char *) n->name, "table") != 0)
+ return CSS_PROPERTY_NOT_SET;
+
+ cellspacing = xmlGetProp(n, (const xmlChar *) "cellspacing");
+ if (cellspacing == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (parse_dimension((const char *) cellspacing, false,
+ &hint->data.position.h.value,
+ &hint->data.position.h.unit)) {
+ hint->data.position.v = hint->data.position.h;
+ hint->status = CSS_BORDER_SPACING_SET;
+ } else {
+ xmlFree(cellspacing);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(cellspacing);
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_BORDER_TOP_COLOR ||
+ property == CSS_PROP_BORDER_RIGHT_COLOR ||
+ property == CSS_PROP_BORDER_BOTTOM_COLOR ||
+ property == CSS_PROP_BORDER_LEFT_COLOR) {
+ xmlChar *col;
+
+ if (strcmp((const char *) n->name, "td") == 0 ||
+ strcmp((const char *) n->name, "th") == 0) {
+ /* Find table */
+ for (n = n->parent; n != NULL &&
+ n->type == XML_ELEMENT_NODE;
+ n = n->parent) {
+ if (strcmp((const char *) n->name, "table") ==
+ 0)
+ break;
+ }
+
+ if (n == NULL)
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ if (strcmp((const char *) n->name, "table") == 0)
+ col = xmlGetProp(n, (const xmlChar *) "bordercolor");
+ else
+ col = NULL;
+
+ if (col == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (nscss_parse_colour((const char *) col, &hint->data.color)) {
+ hint->status = CSS_BORDER_COLOR_COLOR;
+ } else {
+ xmlFree(col);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(col);
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_BORDER_TOP_STYLE ||
+ property == CSS_PROP_BORDER_RIGHT_STYLE ||
+ property == CSS_PROP_BORDER_BOTTOM_STYLE ||
+ property == CSS_PROP_BORDER_LEFT_STYLE) {
+ if (strcmp((const char *) n->name, "td") == 0 ||
+ strcmp((const char *) n->name, "th") == 0) {
+ /* Find table */
+ for (n = n->parent; n != NULL &&
+ n->type == XML_ELEMENT_NODE;
+ n = n->parent) {
+ if (strcmp((const char *) n->name, "table") ==
+ 0)
+ break;
+ }
+
+ if (n == NULL)
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ if (strcmp((const char *) n->name, "table") == 0 &&
+ xmlHasProp(n,
+ (const xmlChar *) "border") != NULL) {
+ hint->status = CSS_BORDER_STYLE_OUTSET;
+ return CSS_OK;
+ }
+ } else if (property == CSS_PROP_BORDER_TOP_WIDTH ||
+ property == CSS_PROP_BORDER_RIGHT_WIDTH ||
+ property == CSS_PROP_BORDER_BOTTOM_WIDTH ||
+ property == CSS_PROP_BORDER_LEFT_WIDTH) {
+ xmlChar *width;
+
+ if (strcmp((const char *) n->name, "td") == 0 ||
+ strcmp((const char *) n->name, "th") == 0) {
+ /* Find table */
+ for (n = n->parent; n != NULL &&
+ n->type == XML_ELEMENT_NODE;
+ n = n->parent) {
+ if (strcmp((const char *) n->name, "table") ==
+ 0)
+ break;
+ }
+
+ if (n == NULL)
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ if (strcmp((const char *) n->name, "table") == 0)
+ width = xmlGetProp(n, (const xmlChar *) "border");
+ else
+ width = NULL;
+
+ if (width == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (parse_dimension((const char *) width, false,
+ &hint->data.length.value,
+ &hint->data.length.unit)) {
+ hint->status = CSS_BORDER_WIDTH_WIDTH;
+ } else {
+ xmlFree(width);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(width);
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_MARGIN_TOP ||
+ property == CSS_PROP_MARGIN_BOTTOM) {
+ xmlChar *vspace;
+
+ if (strcmp((const char *) n->name, "img") == 0 ||
+ strcmp((const char *) n->name, "applet") == 0)
+ vspace = xmlGetProp(n, (const xmlChar *) "vspace");
+ else
+ vspace = NULL;
+
+ if (vspace == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (parse_dimension((const char *) vspace, false,
+ &hint->data.length.value,
+ &hint->data.length.unit)) {
+ hint->status = CSS_MARGIN_SET;
+ } else {
+ xmlFree(vspace);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(vspace);
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_MARGIN_RIGHT ||
+ property == CSS_PROP_MARGIN_LEFT) {
+ xmlChar *hspace;
+
+ if (strcmp((const char *) n->name, "img") == 0 ||
+ strcmp((const char *) n->name, "applet") == 0)
+ hspace = xmlGetProp(n, (const xmlChar *) "hspace");
+ else
+ hspace = NULL;
+
+ if (hspace == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (parse_dimension((const char *) hspace, false,
+ &hint->data.length.value,
+ &hint->data.length.unit)) {
+ hint->status = CSS_MARGIN_SET;
+ } else {
+ xmlFree(hspace);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(hspace);
+
+ return CSS_OK;
+ } else if (property == CSS_PROP_PADDING_TOP ||
+ property == CSS_PROP_PADDING_RIGHT ||
+ property == CSS_PROP_PADDING_BOTTOM ||
+ property == CSS_PROP_PADDING_LEFT) {
+ xmlChar *cellpadding = NULL;
+
+ if (strcmp((const char *) n->name, "td") == 0 ||
+ strcmp((const char *) n->name, "th") == 0) {
+ /* Find table */
+ for (n = n->parent; n != NULL &&
+ n->type == XML_ELEMENT_NODE;
+ n = n->parent) {
+ if (strcmp((const char *) n->name, "table") ==
+ 0)
+ break;
+ }
+
+ if (n != NULL)
+ cellpadding = xmlGetProp(n,
+ (const xmlChar *) "cellpadding");
+ }
+
+ if (cellpadding == NULL)
+ return CSS_PROPERTY_NOT_SET;
+
+ if (parse_dimension((const char *) cellpadding, false,
+ &hint->data.length.value,
+ &hint->data.length.unit)) {
+ hint->status = CSS_PADDING_SET;
+ } else {
+ xmlFree(cellpadding);
+ return CSS_PROPERTY_NOT_SET;
+ }
+
+ xmlFree(cellpadding);
+
+ return CSS_OK;
+ }
+
+ return CSS_PROPERTY_NOT_SET;
+}
+
+/**
+ * Callback to retrieve the User-Agent defaults for a CSS property.
+ *
+ * \param pw HTML document
+ * \param property Property to retrieve defaults for
+ * \param hint Pointer to hint object to populate
+ * \return CSS_OK on success,
+ * CSS_INVALID if the property should not have a user-agent default.
+ */
+css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint)
+{
+ if (property == CSS_PROP_COLOR) {
+ hint->data.color = 0x00000000;
+ hint->status = CSS_COLOR_COLOR;
+ } else if (property == CSS_PROP_FONT_FAMILY) {
+ hint->data.strings = NULL;
+ switch (option_font_default) {
+ case PLOT_FONT_FAMILY_SANS_SERIF:
+ hint->status = CSS_FONT_FAMILY_SANS_SERIF;
+ break;
+ case PLOT_FONT_FAMILY_SERIF:
+ hint->status = CSS_FONT_FAMILY_SERIF;
+ break;
+ case PLOT_FONT_FAMILY_MONOSPACE:
+ hint->status = CSS_FONT_FAMILY_MONOSPACE;
+ break;
+ case PLOT_FONT_FAMILY_CURSIVE:
+ hint->status = CSS_FONT_FAMILY_CURSIVE;
+ break;
+ case PLOT_FONT_FAMILY_FANTASY:
+ hint->status = CSS_FONT_FAMILY_FANTASY;
+ break;
+ }
+ } else if (property == CSS_PROP_QUOTES) {
+ /** \todo Not exactly useful :) */
+ hint->data.strings = NULL;
+ hint->status = CSS_QUOTES_NONE;
+ } else if (property == CSS_PROP_VOICE_FAMILY) {
+ /** \todo Fix this when we have voice-family done */
+ hint->data.strings = NULL;
+ hint->status = 0;
+ } else {
+ return CSS_INVALID;
+ }
+
+ return CSS_OK;
+}
+
+/**
+ * Mapping of colour name to CSS color
+ */
+struct colour_map {
+ const char *name;
+ css_color color;
+};
+
+/**
+ * Name comparator for named colour matching
+ *
+ * \param a Name to match
+ * \param b Colour map entry to consider
+ * \return 0 on match,
+ * < 0 if a < b,
+ * > 0 if b > a.
+ */
+int cmp_colour_name(const void *a, const void *b)
+{
+ const char *aa = a;
+ const struct colour_map *bb = b;
+
+ return strcasecmp(aa, bb->name);
+}
+
+/**
+ * Parse a named colour
+ *
+ * \param name Name to parse
+ * \param result Pointer to location to receive css_color
+ * \return true on success, false on invalid input
+ */
+bool parse_named_colour(const char *name, css_color *result)
+{
+ static const struct colour_map named_colours[] = {
+ { "aliceblue", 0xf0f8ff00 },
+ { "antiquewhite", 0xfaebd700 },
+ { "aqua", 0x00ffff00 },
+ { "aquamarine", 0x7fffd400 },
+ { "azure", 0xf0ffff00 },
+ { "beige", 0xf5f5dc00 },
+ { "bisque", 0xffe4c400 },
+ { "black", 0x00000000 },
+ { "blanchedalmond", 0xffebcd00 },
+ { "blue", 0x0000ff00 },
+ { "blueviolet", 0x8a2be200 },
+ { "brown", 0xa52a2a00 },
+ { "burlywood", 0xdeb88700 },
+ { "cadetblue", 0x5f9ea000 },
+ { "chartreuse", 0x7fff0000 },
+ { "chocolate", 0xd2691e00 },
+ { "coral", 0xff7f5000 },
+ { "cornflowerblue", 0x6495ed00 },
+ { "cornsilk", 0xfff8dc00 },
+ { "crimson", 0xdc143c00 },
+ { "cyan", 0x00ffff00 },
+ { "darkblue", 0x00008b00 },
+ { "darkcyan", 0x008b8b00 },
+ { "darkgoldenrod", 0xb8860b00 },
+ { "darkgray", 0xa9a9a900 },
+ { "darkgreen", 0x00640000 },
+ { "darkgrey", 0xa9a9a900 },
+ { "darkkhaki", 0xbdb76b00 },
+ { "darkmagenta", 0x8b008b00 },
+ { "darkolivegreen", 0x556b2f00 },
+ { "darkorange", 0xff8c0000 },
+ { "darkorchid", 0x9932cc00 },
+ { "darkred", 0x8b000000 },
+ { "darksalmon", 0xe9967a00 },
+ { "darkseagreen", 0x8fbc8f00 },
+ { "darkslateblue", 0x483d8b00 },
+ { "darkslategray", 0x2f4f4f00 },
+ { "darkslategrey", 0x2f4f4f00 },
+ { "darkturquoise", 0x00ced100 },
+ { "darkviolet", 0x9400d300 },
+ { "deeppink", 0xff149300 },
+ { "deepskyblue", 0x00bfff00 },
+ { "dimgray", 0x69696900 },
+ { "dimgrey", 0x69696900 },
+ { "dodgerblue", 0x1e90ff00 },
+ { "feldspar", 0xd1927500 },
+ { "firebrick", 0xb2222200 },
+ { "floralwhite", 0xfffaf000 },
+ { "forestgreen", 0x228b2200 },
+ { "fuchsia", 0xff00ff00 },
+ { "gainsboro", 0xdcdcdc00 },
+ { "ghostwhite", 0xf8f8ff00 },
+ { "gold", 0xffd70000 },
+ { "goldenrod", 0xdaa52000 },
+ { "gray", 0x80808000 },
+ { "green", 0x00800000 },
+ { "greenyellow", 0xadff2f00 },
+ { "grey", 0x80808000 },
+ { "honeydew", 0xf0fff000 },
+ { "hotpink", 0xff69b400 },
+ { "indianred", 0xcd5c5c00 },
+ { "indigo", 0x4b008200 },
+ { "ivory", 0xfffff000 },
+ { "khaki", 0xf0e68c00 },
+ { "lavender", 0xe6e6fa00 },
+ { "lavenderblush", 0xfff0f500 },
+ { "lawngreen", 0x7cfc0000 },
+ { "lemonchiffon", 0xfffacd00 },
+ { "lightblue", 0xadd8e600 },
+ { "lightcoral", 0xf0808000 },
+ { "lightcyan", 0xe0ffff00 },
+ { "lightgoldenrodyellow", 0xfafad200 },
+ { "lightgray", 0xd3d3d300 },
+ { "lightgreen", 0x90ee9000 },
+ { "lightgrey", 0xd3d3d300 },
+ { "lightpink", 0xffb6c100 },
+ { "lightsalmon", 0xffa07a00 },
+ { "lightseagreen", 0x20b2aa00 },
+ { "lightskyblue", 0x87cefa00 },
+ { "lightslateblue", 0x8470ff00 },
+ { "lightslategray", 0x77889900 },
+ { "lightslategrey", 0x77889900 },
+ { "lightsteelblue", 0xb0c4de00 },
+ { "lightyellow", 0xffffe000 },
+ { "lime", 0x00ff0000 },
+ { "limegreen", 0x32cd3200 },
+ { "linen", 0xfaf0e600 },
+ { "magenta", 0xff00ff00 },
+ { "maroon", 0x80000000 },
+ { "mediumaquamarine", 0x66cdaa00 },
+ { "mediumblue", 0x0000cd00 },
+ { "mediumorchid", 0xba55d300 },
+ { "mediumpurple", 0x9370db00 },
+ { "mediumseagreen", 0x3cb37100 },
+ { "mediumslateblue", 0x7b68ee00 },
+ { "mediumspringgreen", 0x00fa9a00 },
+ { "mediumturquoise", 0x48d1cc00 },
+ { "mediumvioletred", 0xc7158500 },
+ { "midnightblue", 0x19197000 },
+ { "mintcream", 0xf5fffa00 },
+ { "mistyrose", 0xffe4e100 },
+ { "moccasin", 0xffe4b500 },
+ { "navajowhite", 0xffdead00 },
+ { "navy", 0x00008000 },
+ { "oldlace", 0xfdf5e600 },
+ { "olive", 0x80800000 },
+ { "olivedrab", 0x6b8e2300 },
+ { "orange", 0xffa50000 },
+ { "orangered", 0xff450000 },
+ { "orchid", 0xda70d600 },
+ { "palegoldenrod", 0xeee8aa00 },
+ { "palegreen", 0x98fb9800 },
+ { "paleturquoise", 0xafeeee00 },
+ { "palevioletred", 0xdb709300 },
+ { "papayawhip", 0xffefd500 },
+ { "peachpuff", 0xffdab900 },
+ { "peru", 0xcd853f00 },
+ { "pink", 0xffc0cb00 },
+ { "plum", 0xdda0dd00 },
+ { "powderblue", 0xb0e0e600 },
+ { "purple", 0x80008000 },
+ { "red", 0xff000000 },
+ { "rosybrown", 0xbc8f8f00 },
+ { "royalblue", 0x4169e100 },
+ { "saddlebrown", 0x8b451300 },
+ { "salmon", 0xfa807200 },
+ { "sandybrown", 0xf4a46000 },
+ { "seagreen", 0x2e8b5700 },
+ { "seashell", 0xfff5ee00 },
+ { "sienna", 0xa0522d00 },
+ { "silver", 0xc0c0c000 },
+ { "skyblue", 0x87ceeb00 },
+ { "slateblue", 0x6a5acd00 },
+ { "slategray", 0x70809000 },
+ { "slategrey", 0x70809000 },
+ { "snow", 0xfffafa00 },
+ { "springgreen", 0x00ff7f00 },
+ { "steelblue", 0x4682b400 },
+ { "tan", 0xd2b48c00 },
+ { "teal", 0x00808000 },
+ { "thistle", 0xd8bfd800 },
+ { "tomato", 0xff634700 },
+ { "turquoise", 0x40e0d000 },
+ { "violet", 0xee82ee00 },
+ { "violetred", 0xd0209000 },
+ { "wheat", 0xf5deb300 },
+ { "white", 0xffffff00 },
+ { "whitesmoke", 0xf5f5f500 },
+ { "yellow", 0xffff0000 },
+ { "yellowgreen", 0x9acd3200 }
+ };
+ const struct colour_map *entry;
+
+ entry = bsearch(name, named_colours,
+ sizeof(named_colours) / sizeof(named_colours[0]),
+ sizeof(named_colours[0]),
+ cmp_colour_name);
+
+ if (entry != NULL)
+ *result = entry->color;
+
+ return entry != NULL;
+}
+
+/**
+ * Parse a dimension string
+ *
+ * \param data Data to parse (NUL-terminated)
+ * \param strict Whether to enforce strict parsing rules
+ * \param length Pointer to location to receive dimension's length
+ * \param unit Pointer to location to receive dimension's unit
+ * \return true on success, false on invalid input
+ */
+bool parse_dimension(const char *data, bool strict, css_fixed *length,
+ css_unit *unit)
+{
+ size_t len;
+ size_t read;
+ css_fixed value;
+
+ len = strlen(data);
+
+ if (parse_number(data, false, true, &value, &read) == false)
+ return false;
+
+ if (strict && value < INTTOFIX(1))
+ return false;
+
+ *length = value;
+
+ if (len > read && data[read] == '%')
+ *unit = CSS_UNIT_PCT;
+ else
+ *unit = CSS_UNIT_PX;
+
+ return true;
+}
+
+/**
+ * Parse a number string
+ *
+ * \param data Data to parse (NUL-terminated)
+ * \param maybe_negative Negative numbers permitted
+ * \param real Floating point numbers permitted
+ * \param value Pointer to location to receive numeric value
+ * \param consumed Pointer to location to receive number of input
+ * bytes consumed
+ * \return true on success, false on invalid input
+ */
+bool parse_number(const char *data, bool maybe_negative, bool real,
+ css_fixed *value, size_t *consumed)
+{
+ size_t len;
+ const uint8_t *ptr;
+ int32_t intpart = 0;
+ int32_t fracpart = 0;
+ int32_t pwr = 1;
+ int sign = 1;
+
+ *consumed = 0;
+
+ len = strlen(data);
+ ptr = (const uint8_t *) data;
+
+ if (len == 0)
+ return false;
+
+ /* Skip leading whitespace */
+ while (len > 0 && isWhitespace(ptr[0])) {
+ len--;
+ ptr++;
+ }
+
+ if (len == 0)
+ return false;
+
+ /* Extract sign, if any */
+ if (ptr[0] == '+') {
+ len--;
+ ptr++;
+ } else if (ptr[0] == '-' && maybe_negative) {
+ sign = -1;
+ len--;
+ ptr++;
+ }
+
+ if (len == 0)
+ return false;
+
+ /* Must have a digit [0,9] */
+ if ('0' > ptr[0] || ptr[0] > '9')
+ return false;
+
+ /* Now extract intpart, assuming base 10 */
+ while (len > 0) {
+ /* Stop on first non-digit */
+ if (ptr[0] < '0' || '9' < ptr[0])
+ break;
+
+ /* Prevent overflow of 'intpart'; proper clamping below */
+ if (intpart < (1 << 22)) {
+ intpart *= 10;
+ intpart += ptr[0] - '0';
+ }
+ ptr++;
+ len--;
+ }
+
+ /* And fracpart, again, assuming base 10 */
+ if (real && len > 1 && ptr[0] == '.' &&
+ ('0' <= ptr[1] && ptr[1] <= '9')) {
+ ptr++;
+ len--;
+
+ while (len > 0) {
+ if (ptr[0] < '0' || '9' < ptr[0])
+ break;
+
+ if (pwr < 1000000) {
+ pwr *= 10;
+ fracpart *= 10;
+ fracpart += ptr[0] - '0';
+ }
+ ptr++;
+ len--;
+ }
+
+ fracpart = ((1 << 10) * fracpart + pwr/2) / pwr;
+ if (fracpart >= (1 << 10)) {
+ intpart++;
+ fracpart &= (1 << 10) - 1;
+ }
+ }
+
+ if (sign > 0) {
+ /* If the result is larger than we can represent,
+ * then clamp to the maximum value we can store. */
+ if (intpart >= (1 << 21)) {
+ intpart = (1 << 21) - 1;
+ fracpart = (1 << 10) - 1;
+ }
+ } else {
+ /* If the negated result is smaller than we can represent
+ * then clamp to the minimum value we can store. */
+ if (intpart >= (1 << 21)) {
+ intpart = -(1 << 21);
+ fracpart = 0;
+ } else {
+ intpart = -intpart;
+ if (fracpart) {
+ fracpart = (1 << 10) - fracpart;
+ intpart--;
+ }
+ }
+ }
+
+ *value = (intpart << 10) | fracpart;
+
+ *consumed = ptr - (const uint8_t *) data;
+
+ return true;
+}
+
+/******************************************************************************
+ * Utility functions *
+ ******************************************************************************/
+
+/**
+ * Determine if a given character is whitespace
+ *
+ * \param c Character to consider
+ * \return true if character is whitespace, false otherwise
+ */
+bool isWhitespace(char c)
+{
+ return c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\n';
+}
+
+/**
+ * Determine if a given character is a valid hex digit
+ *
+ * \param c Character to consider
+ * \return true if character is a valid hex digit, false otherwise
+ */
+bool isHex(char c)
+{
+ return ('0' <= c && c <= '9') ||
+ ('A' <= (c & ~0x20) && (c & ~0x20) <= 'F');
+}
+
+/**
+ * Convert a character representing a hex digit to the corresponding hex value
+ *
+ * \param c Character to convert
+ * \return Hex value represented by character
+ *
+ * \note This function assumes an ASCII-compatible character set
+ */
+uint8_t charToHex(char c)
+{
+ /* 0-9 */
+ c -= '0';
+
+ /* A-F */
+ if (c > 9)
+ c -= 'A' - '9' - 1;
+
+ /* a-f */
+ if (c > 15)
+ c -= 'a' - 'A';
+
+ return c;
+}
+
diff --git a/css/select.h b/css/select.h
new file mode 100644
index 000000000..7b87b2783
--- /dev/null
+++ b/css/select.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_CSS_SELECT_H_
+#define NETSURF_CSS_SELECT_H_
+
+#include <stdint.h>
+
+#include <libxml/tree.h>
+
+#include "css/css.h"
+
+struct content;
+
+css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
+ const char *charset, const char *url, bool allow_quirks,
+ lwc_context *dict, css_allocator_fn alloc, void *pw);
+
+css_computed_style *nscss_get_style(struct content *html, xmlNode *n,
+ uint32_t pseudo_element, uint64_t media,
+ const css_stylesheet *inline_style,
+ css_allocator_fn alloc, void *pw);
+
+css_computed_style *nscss_get_initial_style(struct content *html,
+ css_allocator_fn, void *pw);
+
+css_computed_style *nscss_get_blank_style(struct content *html,
+ const css_computed_style *parent,
+ css_allocator_fn alloc, void *pw);
+
+css_error nscss_compute_font_size(void *pw, const css_hint *parent,
+ css_hint *size);
+
+bool nscss_parse_colour(const char *data, css_color *result);
+
+#endif
diff --git a/css/testcss.c b/css/testcss.c
deleted file mode 100644
index d21efa619..000000000
--- a/css/testcss.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "utils/config.h"
-#include "content/content.h"
-#include "css/css.h"
-#include "desktop/options.h"
-#include "utils/messages.h"
-#include "utils/talloc.h"
-#include "utils/utils.h"
-
-#define ITERATIONS (1)
-
-bool verbose_log = 0;
-int option_font_size = 10;
-int option_font_min_size = 10;
-
-void die(const char * const error)
-{
-}
-
-static bool css_process_data(struct content *c, const char *data,
- unsigned int size)
-{
- char *source_data;
- union content_msg_data msg_data;
- unsigned int extra_space;
-
- assert(c);
-
- if ((c->source_size + size) > c->source_allocated) {
- extra_space = (c->source_size + size) / 4;
- if (extra_space < 65536)
- extra_space = 65536;
- source_data = talloc_realloc(c, c->source_data, char,
- c->source_size + size + extra_space);
- if (!source_data) {
- c->status = CONTENT_STATUS_ERROR;
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
- }
- c->source_data = source_data;
- c->source_allocated = c->source_size + size + extra_space;
- }
- memcpy(c->source_data + c->source_size, data, size);
- c->source_size += size;
-
- return true;
-}
-
-void content_broadcast(struct content *c, content_msg msg,
- union content_msg_data data)
-{
-}
-
-void content_remove_user(struct content *c,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2)
-{
-}
-
-void content_add_error(struct content *c, const char *token,
- unsigned int line)
-{
-}
-
-void fetch_abort(struct fetch *f)
-{
-}
-
-void fetch_poll(void)
-{
-}
-
-struct content * fetchcache(const char *url,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2,
- int width, int height,
- bool no_error_pages,
- char *post_urlenc,
- struct form_successful_control *post_multipart,
- bool verifiable,
- bool download)
-{
- return NULL;
-}
-
-void fetchcache_go(struct content *content, const char *referer,
- void (*callback)(content_msg msg, struct content *c,
- intptr_t p1, intptr_t p2, union content_msg_data data),
- intptr_t p1, intptr_t p2,
- int width, int height,
- char *post_urlenc,
- struct form_successful_control *post_multipart,
- bool verifiable, const char *parent_url)
-{
-}
-
-void gui_multitask(void)
-{
-}
-
-int main(int argc, char **argv)
-{
-/* const char data[] = "h1 { blah: foo; display: block; }"
- "h1.c1 h2#id1 + h3, h4 h5.c2#id2 { size: 100mm; color: red }"
- "p { background-color: #123; clear: left; color: #ff0000; display: block;"
- "float: left; font-size: 150%; height: blah; line-height: 100;"
- "text-align: left right; width: 90%;}";
-*/
- struct content *c;
- FILE *fp;
-#define CHUNK_SIZE (4096)
- char data[CHUNK_SIZE];
- size_t len, origlen;
-
- if (argc != 2) {
- fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
- return 1;
- }
-
- printf("sizeof(struct css_style): %zu\n", sizeof(struct css_style));
-
- for (int i = 0; i < ITERATIONS; i++) {
- c = talloc_zero(0, struct content);
- if (c == NULL) {
- fprintf(stderr, "No memory for content\n");
- return 1;
- }
-
- c->url = talloc_strdup(c, "http://www.example.com/");
- if (c->url == NULL) {
- fprintf(stderr, "No memory for url\n");
- talloc_free(c);
- return 1;
- }
-
- c->type = CONTENT_CSS;
-
- fp = fopen(argv[1], "rb");
- if (fp == NULL) {
- fprintf(stderr, "Failed opening %s\n", argv[1]);
- talloc_free(c);
- return 1;
- }
-
- fseek(fp, 0, SEEK_END);
- origlen = len = ftell(fp);
- fseek(fp, 0, SEEK_SET);
-
- while (len >= CHUNK_SIZE) {
- fread(data, 1, CHUNK_SIZE, fp);
-
- css_process_data(c, data, CHUNK_SIZE);
-
- len -= CHUNK_SIZE;
- }
-
- if (len > 0) {
- fread(data, 1, len, fp);
-
- css_process_data(c, data, len);
-
- len = 0;
- }
-
- fclose(fp);
-
- css_convert(c, 100, 100);
-
- talloc_free(c);
- }
-
- return 0;
-}
diff --git a/css/utils.c b/css/utils.c
new file mode 100644
index 000000000..5ed569474
--- /dev/null
+++ b/css/utils.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2004 James Bursa <james@netsurf-browser.org>
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "css/utils.h"
+
+#include "desktop/options.h"
+#include "utils/log.h"
+
+/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
+css_fixed nscss_screen_dpi = INTTOFIX(90);
+
+/**
+ * Convert an absolute CSS length to points.
+ *
+ * \param length Length to convert
+ * \param unit Corresponding unit
+ * \return length in points
+ */
+css_fixed nscss_len2pt(css_fixed length, css_unit unit)
+{
+ /* Length must not be relative */
+ assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX);
+
+ switch (unit) {
+ /* We assume the screen and any other output has the same dpi */
+ /* 1in = DPIpx => 1px = (72/DPI)pt */
+ case CSS_UNIT_PX: return FDIV(FMULI(length, 72), nscss_screen_dpi);
+ /* 1in = 72pt */
+ case CSS_UNIT_IN: return FMULI(length, 72);
+ /* 1in = 2.54cm => 1cm = (72/2.54)pt */
+ case CSS_UNIT_CM: return FMUL(length,
+ FDIV(INTTOFIX(72), FLTTOFIX(2.54)));
+ /* 1in = 25.4mm => 1mm = (72/25.4)pt */
+ case CSS_UNIT_MM: return FMUL(length,
+ FDIV(INTTOFIX(72), FLTTOFIX(25.4)));
+ case CSS_UNIT_PT: return length;
+ /* 1pc = 12pt */
+ case CSS_UNIT_PC: return FMULI(length, 12);
+ default: break;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Convert a CSS length to pixels.
+ *
+ * \param length Length to convert
+ * \param unit Corresponding unit
+ * \param style Computed style applying to length. May be NULL if unit is
+ * neither em nor ex
+ * \return length in pixels
+ */
+css_fixed nscss_len2px(css_fixed length, css_unit unit,
+ const css_computed_style *style)
+{
+ /* We assume the screen and any other output has the same dpi */
+ const css_fixed lendpi = FMUL(length, nscss_screen_dpi);
+
+ assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX));
+
+ switch (unit) {
+ case CSS_UNIT_EM:
+ case CSS_UNIT_EX:
+ {
+ css_fixed font_size = 0;
+ css_unit font_unit = CSS_UNIT_PT;
+
+ css_computed_font_size(style, &font_size, &font_unit);
+
+ /* Convert to points */
+ font_size = nscss_len2pt(font_size, font_unit);
+
+ /* Clamp to configured minimum */
+ if (font_size < FDIVI(INTTOFIX(option_font_min_size), 10)) {
+ font_size = FDIVI(INTTOFIX(option_font_min_size), 10);
+ }
+
+ /* Expand relative length */
+ length = FMUL(length,
+ nscss_len2px(font_size, CSS_UNIT_PT, style));
+
+ /* Scale ex units: we use a fixed ratio of 1ex = 0.6em */
+ if (unit == CSS_UNIT_EX)
+ length = FMUL(length, FLTTOFIX(0.6));
+
+ return length;
+ }
+ case CSS_UNIT_PX: return length;
+ /* 1in = DPIpx */
+ case CSS_UNIT_IN: return lendpi;
+ /* 1in = 2.54cm => 1cm = (DPI/2.54)px */
+ case CSS_UNIT_CM: return FDIV(lendpi, FLTTOFIX(2.54));
+ /* 1in = 25.4mm => 1mm = (DPI/25.4)px */
+ case CSS_UNIT_MM: return FDIV(lendpi, FLTTOFIX(25.4));
+ /* 1in = 72pt => 1pt = (DPI/72)px */
+ case CSS_UNIT_PT: return FDIV(lendpi, INTTOFIX(72));
+ /* 1pc = 12pt => 1in = 6pc => 1pc = (DPI/6)px */
+ case CSS_UNIT_PC: return FDIV(lendpi, INTTOFIX(6));
+ default: break;
+ }
+
+ return 0;
+}
+
diff --git a/css/utils.h b/css/utils.h
new file mode 100644
index 000000000..71da8a41a
--- /dev/null
+++ b/css/utils.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_CSS_UTILS_H_
+#define NETSURF_CSS_UTILS_H_
+
+#include "css/css.h"
+#include "desktop/plot_style.h"
+
+/* DPI of the screen, in fixed point units */
+extern css_fixed nscss_screen_dpi;
+
+/**
+ * Convert a CSS color to a NetSurf colour primitive
+ *
+ * \param color The CSS color to convert
+ * \return Corresponding NetSurf colour primitive
+ */
+#define nscss_color_to_ns(color) \
+ (((color) & 0xff000000) >> 24) | \
+ (((color) & 0xff0000) >> 8) | \
+ (((color) & 0xff00) << 8) | \
+ (((color) & 0xff) << 24)
+
+css_fixed nscss_len2pt(css_fixed length, css_unit unit);
+css_fixed nscss_len2px(css_fixed length, css_unit unit,
+ const css_computed_style *style);
+
+#endif