summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--!NetSurf/Resources/Quirks,f7914
-rw-r--r--Makefile31
-rw-r--r--Makefile.sources34
-rwxr-xr-xamiga/context_menu.c2
-rw-r--r--amiga/font.c10
-rwxr-xr-xamiga/gui.c7
l---------amiga/resources/quirks.css1
-rwxr-xr-xamiga/save_complete.c11
-rw-r--r--beos/beos_font.cpp4
-rw-r--r--beos/beos_gui.cpp12
l---------beos/res/quirks.css1
-rw-r--r--content/content.c11
-rw-r--r--content/content.h3
-rw-r--r--content/fetchcache.c7
-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.h (renamed from render/loosen.h)19
-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
-rw-r--r--desktop/browser.c171
-rw-r--r--desktop/plot_style.c2
-rw-r--r--desktop/plot_style.h11
-rw-r--r--desktop/print.c64
-rw-r--r--desktop/print.h4
-rw-r--r--desktop/save_pdf/font_haru.c6
-rw-r--r--desktop/save_pdf/pdf_plotters.c19
-rw-r--r--desktop/save_text.c4
-rw-r--r--desktop/textarea.c16
-rw-r--r--desktop/textarea.h4
-rw-r--r--framebuffer/fbtk.c2
-rw-r--r--framebuffer/gui.c4
l---------framebuffer/res/quirks.css1
-rw-r--r--gtk/font_pango.c12
-rw-r--r--gtk/gtk_gui.c5
-rw-r--r--gtk/gtk_print.c6
-rw-r--r--gtk/gtk_scaffolding.c7
l---------gtk/res/quirks.css1
-rw-r--r--image/bmp.c3
-rw-r--r--image/bmp.h3
-rw-r--r--image/gif.c3
-rw-r--r--image/gif.h3
-rw-r--r--image/ico.c3
-rw-r--r--image/ico.h3
-rw-r--r--image/mng.c3
-rw-r--r--image/mng.h3
-rw-r--r--image/png.c3
-rw-r--r--image/png.h5
-rw-r--r--image/rsvg.c3
-rw-r--r--image/rsvg.h3
-rw-r--r--image/svg.c2
-rw-r--r--image/svg.h3
-rw-r--r--render/box.c39
-rw-r--r--render/box.h22
-rw-r--r--render/box_construct.c997
-rw-r--r--render/box_normalise.c637
-rw-r--r--render/directory.c5
-rw-r--r--render/directory.h3
-rw-r--r--render/font.c48
-rw-r--r--render/font.h2
-rw-r--r--render/html.c191
-rw-r--r--render/html.h18
-rw-r--r--render/html_redraw.c349
-rw-r--r--render/hubbub_binding.c21
-rw-r--r--render/layout.c1558
-rw-r--r--render/list.c49
-rw-r--r--render/list.h10
-rw-r--r--render/loosen.c501
-rw-r--r--render/parser_binding.h8
-rw-r--r--render/table.c892
-rw-r--r--render/table.h2
-rw-r--r--render/textplain.c9
-rw-r--r--render/textplain.h3
-rw-r--r--riscos/font.c19
-rw-r--r--riscos/gui.c9
-rw-r--r--riscos/image.h2
-rw-r--r--riscos/plugin.c3
-rw-r--r--riscos/plugin.h3
-rw-r--r--riscos/save.c6
-rw-r--r--riscos/save_complete.c11
-rw-r--r--riscos/textselection.c3
-rw-r--r--riscos/window.c4
-rw-r--r--utils/config.h15
-rw-r--r--utils/utils.c183
-rw-r--r--utils/utils.h4
96 files changed, 7673 insertions, 10758 deletions
diff --git a/!NetSurf/Resources/Quirks,f79 b/!NetSurf/Resources/Quirks,f79
new file mode 100644
index 000000000..2f0f9f369
--- /dev/null
+++ b/!NetSurf/Resources/Quirks,f79
@@ -0,0 +1,14 @@
+/* Quirks mode stylesheet for NetSurf */
+
+/**
+ * Netscape/IE 4 compatibility.
+ *
+ * See https://developer.mozilla.org/en/Fixing_Table_Inheritance_in_Quirks_Mode
+ */
+table {
+ /* Reset font properties (except family) */
+ font-size: medium;
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+}
diff --git a/Makefile b/Makefile
index 373ae05e8..3336e253b 100644
--- a/Makefile
+++ b/Makefile
@@ -254,9 +254,10 @@ CFLAGS += -DNETSURF_HOMEPAGE=\"$(NETSURF_HOMEPAGE)\"
ifeq ($(TARGET),riscos)
ifeq ($(HOST),riscos)
LDFLAGS += -Xlinker -symbols=$(OBJROOT)/sym -lxml2 -lz -lm -lcurl -lcares
- LDFLAGS += -lssl -lcrypto -lhubbub -lparserutils
+ LDFLAGS += -lssl -lcrypto -lhubbub -lcss -lparserutils -lwapcaplet
else
- LDFLAGS += $(shell $(PKG_CONFIG) --libs libxml-2.0 libcurl libhubbub openssl)
+ LDFLAGS += $(shell $(PKG_CONFIG) --libs libxml-2.0 libcurl openssl)
+ LDFLAGS += $(shell $(PKG_CONFIG) --libs libhubbub libcss)
endif
$(eval $(call feature_enabled,NSSVG,-DWITH_NS_SVG,-lsvgtiny,SVG rendering))
@@ -289,9 +290,7 @@ ifeq ($(TARGET),riscos)
CFLAGS += -I$(GCCSDK_INSTALL_ENV)/include \
-I$(GCCSDK_INSTALL_ENV)/include/libxml2 \
- -I$(GCCSDK_INSTALL_ENV)/include/libmng \
- -I$(GCCSDK_INSTALL_ENV)/include/hubbub0 \
- -I$(GCCSDK_INSTALL_ENV)/include/parserutils0
+ -I$(GCCSDK_INSTALL_ENV)/include/libmng
ifeq ($(HOST),riscos)
CFLAGS += -I<OSLib$$Dir> -mthrowback
endif
@@ -322,7 +321,7 @@ ifeq ($(TARGET),beos)
LDFLAGS += -L/boot/common/lib
# some people do *not* have libm...
LDFLAGS += -lxml2 -lcurl -liconv
- LDFLAGS += -lssl -lcrypto -lhubbub -lparserutils
+ LDFLAGS += -lssl -lcrypto -lhubbub -lcss -lparserutils -lwapcaplet
CFLAGS += -I. -O $(WARNFLAGS) -Dnsbeos \
-D_BSD_SOURCE -D_POSIX_C_SOURCE \
@@ -345,8 +344,9 @@ ifeq ($(TARGET),beos)
CFLAGS += -I/boot/home/config/include \
-I/boot/home/config/include/libxml2 \
-I/boot/home/config/include/libmng \
- -I/boot/home/config/include/hubbub0 \
- -I/boot/home/config/include/parserutils0
+ -I/boot/home/config/include/hubbub \
+ -I/boot/home/config/include/libcss \
+ -I/boot/home/config/include/parserutils
ifneq ($(wildcard /boot/develop/lib/*/libzeta.so),)
LDFLAGS += -lzeta
endif
@@ -355,8 +355,9 @@ ifeq ($(TARGET),beos)
CFLAGS += -I/boot/common/include \
-I/boot/common/include/libxml2 \
-I/boot/common/include/libmng \
- -I/boot/common/include/hubbub0 \
- -I/boot/common/include/parserutils0
+ -I/boot/common/include/hubbub \
+ -I/boot/common/include/libcss \
+ -I/boot/common/include/parserutils
NETLDFLAGS := -lnetwork
else
ifneq ($(wildcard /boot/develop/lib/*/libbind.so),)
@@ -377,16 +378,13 @@ ifeq ($(TARGET),beos)
ifeq ($(HOST),beos)
CFLAGS += -I$(PREFIX)/include
LDFLAGS += -L$(PREFIX)/lib
- $(eval $(call feature_enabled,HUBBUB,-DWITH_HUBBUB,-lhubbub-debug -lparserutils-debug,Hubbub HTML parser))
$(eval $(call feature_enabled,BMP,-DWITH_BMP,-lnsbmp,NetSurf BMP decoder))
$(eval $(call feature_enabled,GIF,-DWITH_GIF,-lnsgif,NetSurf GIF decoder))
$(eval $(call feature_enabled,PNG,-DWITH_PNG,-lpng,PNG support))
else
- NETSURF_FEATURE_HUBBUB_CFLAGS := -DWITH_HUBBUB
NETSURF_FEATURE_BMP_CFLAGS := -DWITH_BMP
NETSURF_FEATURE_GIF_CFLAGS := -DWITH_GIF
NETSURF_FEATURE_PNG_CFLAGS := -DWITH_PNG
- $(eval $(call pkg_config_find_and_add,HUBBUB,libhubbub,Hubbub HTML parser))
$(eval $(call pkg_config_find_and_add,BMP,libnsbmp,NetSurf BMP decoder))
$(eval $(call pkg_config_find_and_add,GIF,libnsgif,NetSurf GIF decoder))
$(eval $(call pkg_config_find_and_add,PNG,libpng,PNG support))
@@ -399,6 +397,7 @@ endif
ifeq ($(TARGET),gtk)
LDFLAGS += $(shell $(PKG_CONFIG) --libs libxml-2.0 libcurl libhubbub openssl)
+ LDFLAGS += $(shell $(PKG_CONFIG) --libs libcss)
# define additional CFLAGS and LDFLAGS requirements for pkg-configed libs here
NETSURF_FEATURE_RSVG_CFLAGS := -DWITH_RSVG
@@ -460,7 +459,7 @@ ifeq ($(TARGET),amiga)
CFLAGS += -D__USE_INLINE__ -std=c99 -I . -Dnsamiga
LDFLAGS += -lxml2 -lcurl -lpthread -lregex -lauto
- LDFLAGS += -lssl -lcrypto -lhubbub -lparserutils
+ LDFLAGS += -lssl -lcrypto -lhubbub -lcss -lparserutils -lwapcaplet
ifeq ($(NETSURF_AMIGA_USE_CAIRO),YES)
CFLAGS += -DNS_AMIGA_CAIRO -I SDK:local/common/include/cairo
@@ -503,10 +502,12 @@ ifeq ($(TARGET),framebuffer)
-D_POSIX_C_SOURCE=200112L \
$(shell $(PKG_CONFIG) --cflags libnsfb) \
$(shell $(PKG_CONFIG) --cflags libhubbub libcurl openssl) \
+ $(shell $(PKG_CONFIG) --cflags libcss) \
$(shell xml2-config --cflags)
LDFLAGS += -Wl,--whole-archive $(shell $(PKG_CONFIG) --libs libnsfb) -Wl,--no-whole-archive
LDFLAGS += $(shell $(PKG_CONFIG) --libs libxml-2.0 libcurl libhubbub openssl)
+ LDFLAGS += $(shell $(PKG_CONFIG) --libs libcss)
endif
@@ -634,7 +635,7 @@ DEPFILES :=
# 3 = obj filename, no prefix
define dependency_generate_c
DEPFILES += $(2)
-$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1) css/css_enum.h css/parser.h Makefile.config
+$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1) Makefile.config
endef
diff --git a/Makefile.sources b/Makefile.sources
index e3404739d..2ffe1e7f4 100644
--- a/Makefile.sources
+++ b/Makefile.sources
@@ -7,10 +7,10 @@
S_CONTENT := content.c fetch.c fetchcache.c urldb.c \
fetchers/fetch_curl.c fetchers/fetch_data.c
-S_CSS := css.c css_enum.c parser.c ruleset.c scanner.c
+S_CSS := css.c dump.c internal.c select.c utils.c
S_RENDER := box.c box_construct.c box_normalise.c directory.c \
font.c form.c html.c html_redraw.c hubbub_binding.c imagemap.c \
- layout.c list.c loosen.c table.c textplain.c
+ layout.c list.c table.c textplain.c
S_UTILS := base64.c filename.c hashtable.c locale.c messages.c talloc.c \
url.c utf8.c utils.c useragent.c
S_DESKTOP := knockout.c options.c print.c tree.c version.c textarea.c \
@@ -102,38 +102,14 @@ endif
S_FRAMEBUFFER := $(addprefix framebuffer/,$(S_FRAMEBUFFER))
-# Some extra rules for building the scanner etc.
-css/css_enum.c css/css_enum.h: css/css_enums css/makeenum
- $(VQ)echo "MAKEENUM: css"
- $(Q)$(PERL) css/makeenum css/css_enum < css/css_enums
+# Some extra rules for building the transliteration table.
ifeq ($(HOST),riscos)
-css/parser.c css/parser.h: css/parser.y
- $(VQ)echo " LEMON: css/parser.y"
- $(Q)dir css
- $(Q)-lemon parser.y
- $(Q)dir ^
- $(Q)touch css/parser.c css/parser.h
-css/scanner.c: css/scanner.l
- $(VQ)echo " RE2C: css/scanner.l"
- $(Q)dir css
- $(Q)re2c -s scanner.l > scanner.c
- $(Q)dir ^
utils/translit.c: transtab
$(VQ)echo "TRANSTAB: utils/translit.c"
$(Q)dir utils
$(Q)$(PERL) tt2code < transtab > translit.c
$(Q)dir ^
else
-css/parser.c css/parser.h: css/parser.y
- $(VQ)echo " LEMON: css/parser.y"
- $(Q)# If lemon really fails hard, we'll never know, sorry
- $(Q)cd css; lemon parser.y || true
- $(Q)# Unfortunately if the output hasn't changed, lemon doesn't
- $(Q)# alter the file and thus make gets confused.
- $(Q)touch css/parser.c css/parser.h
-css/scanner.c: css/scanner.l
- $(VQ)echo " RE2C: css/scanner.l"
- $(Q)cd css; re2c -s scanner.l > scanner.c
utils/translit.c: transtab
$(VQ)echo "TRANSTAB: utils/translit.c"
$(Q)cd utils; $(PERL) tt2code < transtab > translit.c
@@ -141,9 +117,7 @@ endif
clean-intermediates:
$(VQ)echo " CLEAN: intermediates"
- $(Q)$(RM) css/css_enum.c css/css_enum.h css/parser.c \
- css/parser.out css/parser.h
- $(Q)$(RM) css/scanner.c utils/translit.c
+ $(Q)$(RM) utils/translit.c
CLEANS += clean-intermediates
diff --git a/amiga/context_menu.c b/amiga/context_menu.c
index 7f60d4963..24dd90f2b 100755
--- a/amiga/context_menu.c
+++ b/amiga/context_menu.c
@@ -92,7 +92,7 @@ void ami_context_menu_show(struct gui_window_2 *gwin,int x,int y)
while(curbox = box_at_point(curbox,x,y,&box_x,&box_y,&cc))
{
- if (curbox->style && curbox->style->visibility == CSS_VISIBILITY_HIDDEN) continue;
+ if (curbox->style && css_computed_visibility(curbox->style) == CSS_VISIBILITY_HIDDEN) continue;
if(curbox->href)
{
diff --git a/amiga/font.c b/amiga/font.c
index cd7d834e2..5c694c199 100644
--- a/amiga/font.c
+++ b/amiga/font.c
@@ -237,7 +237,7 @@ struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle)
{
struct OutlineFont *ofont;
char *fontname;
- WORD ysize;
+ ULONG ysize;
int tstyle = 0;
if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE))
@@ -268,14 +268,12 @@ struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle)
break;
}
- ysize = fstyle->size;
-
- if(ysize < (option_font_min_size / 10) * FONT_SIZE_SCALE)
- ysize = (option_font_min_size / 10) * FONT_SIZE_SCALE;
+ /* Scale to 16.16 fixed point */
+ ysize = fstyle->size * ((1 << 16) / FONT_SIZE_SCALE);
if(ESetInfo(&ofont->olf_EEngine,
OT_DeviceDPI,(72<<16) | 72,
- OT_PointHeight,(ysize<<16)/FONT_SIZE_SCALE,
+ OT_PointHeight,ysize,
TAG_END) == OTERR_Success)
{
return ofont;
diff --git a/amiga/gui.c b/amiga/gui.c
index f36f4a5df..62e98afdf 100755
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -27,6 +27,7 @@
#include "amiga/schedule.h"
#include <proto/timer.h>
#include "content/urldb.h"
+#include "css/utils.h"
#include <libraries/keymap.h>
#include "desktop/history_core.h"
#include <proto/locale.h>
@@ -105,6 +106,7 @@
#include <reaction/reaction_macros.h>
char *default_stylesheet_url;
+char *quirks_stylesheet_url;
char *adblock_stylesheet_url;
struct MsgPort *appport;
@@ -324,6 +326,7 @@ void gui_init(int argc, char** argv)
messages_load(lang);
default_stylesheet_url = "file:///PROGDIR:Resources/amiga.css";
+ quirks_stylesheet_url = "file:///PROGDIR:Resources/quirks.css";
adblock_stylesheet_url = "file:///PROGDIR:Resources/adblock.css";
if(hubbub_initialise("PROGDIR:Resources/Aliases",myrealloc,NULL) != HUBBUB_OK)
@@ -331,7 +334,7 @@ void gui_init(int argc, char** argv)
die(messages_get("NoMemory"));
}
- css_screen_dpi = 72;
+ nscss_screen_dpi = INTTOFIX(72);
css_scrollbar_fg_colour = 0x00aaaaaa;
css_scrollbar_bg_colour = 0x00833c3c;
css_scrollbar_arrow_colour = 0x00d6d6d6;
@@ -1303,7 +1306,7 @@ void ami_handle_appmsg(void)
box = content->data.html.layout;
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content)))
{
- if (box->style && box->style->visibility == CSS_VISIBILITY_HIDDEN) continue;
+ if (box->style && css_computed_visibility(box->style) == CSS_VISIBILITY_HIDDEN) continue;
if (box->gadget)
{
diff --git a/amiga/resources/quirks.css b/amiga/resources/quirks.css
new file mode 120000
index 000000000..d9fb80334
--- /dev/null
+++ b/amiga/resources/quirks.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
diff --git a/amiga/save_complete.c b/amiga/save_complete.c
index 26b55adf5..2f5ebd584 100755
--- a/amiga/save_complete.c
+++ b/amiga/save_complete.c
@@ -120,17 +120,20 @@ bool save_complete_html(struct content *c, const char *path, bool index)
return true;
/* save stylesheets, ignoring the base and adblocking sheets */
- for (i = STYLESHEET_STYLE; i != c->data.html.stylesheet_count; i++) {
+ for (i = STYLESHEET_START; i != c->data.html.stylesheet_count; i++) {
struct content *css = c->data.html.stylesheet_content[i];
char *source;
int source_len;
+ bool is_style;
if (!css)
continue;
if (save_complete_list_check(css))
continue;
- if (i != STYLESHEET_STYLE) {
+ is_style = (strcmp(css->url, c->data.html.base_url) == 0);
+
+ if (is_style == false) {
if (!save_complete_list_add(css)) {
warn_user("NoMemory", 0);
return false;
@@ -140,7 +143,7 @@ bool save_complete_html(struct content *c, const char *path, bool index)
if (!save_imported_sheets(css, path))
return false;
- if (i == STYLESHEET_STYLE)
+ if (is_style)
continue; /* don't save <style> elements */
snprintf(spath, sizeof spath, "%s/%x", path,
@@ -317,7 +320,7 @@ bool save_imported_sheets(struct content *c, const char *path)
BPTR fh = 0;
for (j = 0; j != c->data.css.import_count; j++) {
- struct content *css = c->data.css.import_content[j];
+ struct content *css = c->data.css.imports[j];
if (!css)
continue;
diff --git a/beos/beos_font.cpp b/beos/beos_font.cpp
index 5549c51e6..f640859ca 100644
--- a/beos/beos_font.cpp
+++ b/beos/beos_font.cpp
@@ -366,10 +366,6 @@ void nsbeos_style_to_font(BFont &font, const plot_font_style_t *style)
//fprintf(stderr, "nsbeos_style_to_font: value %f unit %d\n", style->font_size.value.length.value, style->font_size.value.length.unit);
size = fstyle->size / FONT_SIZE_SCALE;
- //XXX: pango stuff ?
- if (size < abs(option_font_min_size / 10))
- size = option_font_min_size / 10;
-
//fprintf(stderr, "nsbeos_style_to_font: %f %d\n", size, style->font_size.value.length.unit);
font.SetSize(size);
diff --git a/beos/beos_gui.cpp b/beos/beos_gui.cpp
index 866c73023..0835a934c 100644
--- a/beos/beos_gui.cpp
+++ b/beos/beos_gui.cpp
@@ -96,6 +96,7 @@ bool gui_in_multitask = false;
bool replicated = false; /**< if we are running as a replicant */
char *default_stylesheet_url;
+char *quirks_stylesheet_url;
char *adblock_stylesheet_url;
char *options_file_location;
char *glade_file_location;
@@ -266,7 +267,7 @@ static char *generate_default_css()
return NULL;
const char *params[] = { 0 };
- if (!content_set_type(c, CONTENT_CSS, "text/css", params))
+ if (!content_set_type(c, CONTENT_CSS, "text/css", params, NULL))
return NULL;
if (!content_process_data(c, text.String(), text.Length()))
@@ -567,6 +568,14 @@ void gui_init(int argc, char** argv)
LOG(("Using '%s' as Default CSS URL", default_stylesheet_url));
#ifdef USE_RESOURCES
+ quirks_stylesheet_url = strdup("rsrc:/quirks.css,text/css");
+#else
+ find_resource(buf, "quirks.css", "./beos/res/quirks.css");
+ default_stylesheet_url = path_to_url(buf);
+#endif
+
+
+#ifdef USE_RESOURCES
adblock_stylesheet_url = strdup("rsrc:/adblock.css,text/css");
#else
find_resource(buf, "adblock.css", "./beos/res/adblock.css");
@@ -740,6 +749,7 @@ void gui_quit(void)
//options_save_tree(hotlist,option_hotlist_file,messages_get("TreeHotlist"));
free(default_stylesheet_url);
+ free(quirks_stylesheet_url);
free(adblock_stylesheet_url);
free(option_cookie_file);
free(option_cookie_jar);
diff --git a/beos/res/quirks.css b/beos/res/quirks.css
new file mode 120000
index 000000000..d9fb80334
--- /dev/null
+++ b/beos/res/quirks.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
diff --git a/content/content.c b/content/content.c
index bda652fad..2b4499a29 100644
--- a/content/content.c
+++ b/content/content.c
@@ -247,7 +247,8 @@ const char * const content_status_name[] = {
/** An entry in handler_map. */
struct handler_entry {
- bool (*create)(struct content *c, const char *params[]);
+ bool (*create)(struct content *c, struct content *parent,
+ const char *params[]);
bool (*process_data)(struct content *c, char *data, unsigned int size);
bool (*convert)(struct content *c, int width, int height);
void (*reformat)(struct content *c, int width, int height);
@@ -280,7 +281,8 @@ static const struct handler_entry handler_map[] = {
{textplain_create, textplain_process_data, textplain_convert,
textplain_reformat, textplain_destroy, 0, textplain_redraw, 0,
0, 0, true},
- {0, 0, css_convert, 0, css_destroy, 0, 0, 0, 0, 0, false},
+ {nscss_create, nscss_process_data, nscss_convert, 0, nscss_destroy,
+ 0, 0, 0, 0, 0, true},
#ifdef WITH_JPEG
{0, 0, nsjpeg_convert, 0, nsjpeg_destroy, 0,
nsjpeg_redraw, nsjpeg_redraw_tiled, 0, 0, false},
@@ -565,7 +567,8 @@ bool content_can_reformat(struct content *c)
*/
bool content_set_type(struct content *c, content_type type,
- const char *mime_type, const char *params[])
+ const char *mime_type, const char *params[],
+ struct content *parent)
{
union content_msg_data msg_data;
struct content *clone;
@@ -637,7 +640,7 @@ bool content_set_type(struct content *c, content_type type,
}
if (handler_map[type].create) {
- if (!handler_map[type].create(c, params)) {
+ if (!handler_map[type].create(c, parent, params)) {
c->type = CONTENT_UNKNOWN;
c->status = CONTENT_STATUS_ERROR;
return false;
diff --git a/content/content.h b/content/content.h
index 298e669ca..1db6122ee 100644
--- a/content/content.h
+++ b/content/content.h
@@ -283,7 +283,8 @@ struct content * content_get(const char *url);
struct content * content_get_ready(const char *url);
bool content_can_reformat(struct content *c);
bool content_set_type(struct content *c, content_type type,
- const char *mime_type, const char *params[]);
+ const char *mime_type, const char *params[],
+ struct content *parent);
void content_set_status(struct content *c, const char *status_message, ...);
bool content_process_data(struct content *c, const char *data,
unsigned int size);
diff --git a/content/fetchcache.c b/content/fetchcache.c
index cb5cc9132..71e39e4fa 100644
--- a/content/fetchcache.c
+++ b/content/fetchcache.c
@@ -409,6 +409,7 @@ void fetchcache_callback(fetch_msg msg, void *p, const void *data,
content_type type;
char *mime_type;
char **params;
+ struct content *parent;
unsigned int i;
union content_msg_data msg_data;
@@ -426,9 +427,11 @@ void fetchcache_callback(fetch_msg msg, void *p, const void *data,
return;
}
type = content_lookup(mime_type);
+ parent = fetch_get_parent(c->fetch);
res = content_set_type(c,
c->download ? CONTENT_OTHER : type,
- mime_type, (const char **) params);
+ mime_type, (const char **) params,
+ parent);
free(mime_type);
for (i = 0; params[i]; i++)
free(params[i]);
@@ -734,7 +737,7 @@ void fetchcache_error_page(struct content *c, const char *error)
if ((length = snprintf(error_page, sizeof(error_page),
messages_get("ErrorPage"), error)) < 0)
length = 0;
- if (!content_set_type(c, CONTENT_HTML, "text/html", params))
+ if (!content_set_type(c, CONTENT_HTML, "text/html", params, NULL))
return;
if (!content_process_data(c, error_page, length))
return;
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/render/loosen.h b/css/dump.h
index a5b3822bd..25d283e9e 100644
--- a/render/loosen.h
+++ b/css/dump.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -16,20 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
-\file
-General idea - a set of routines working themselves recursively through
-the box tree and trying to change the layout of the document as little
-as possible to acquire the desired width ( - to make it fit in a printed
-page ), where possible - also taking the dividing height into consideration,
-to prevent objects being cut by ends of pages.
-*/
+#ifndef NETSURF_CSS_DUMP_H_
+#define NETSURF_CSS_DUMP_H_
-#ifndef NETSURF_RENDER_LOOSEN_H
-#define NETSURF_RENDER_LOOSEN_H
-#include <stdbool.h>
+#include "css/css.h"
-bool loosen_document_layout(struct content *content, struct box *layout,
- int width, int height);
+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
diff --git a/desktop/browser.c b/desktop/browser.c
index b188316ea..d19281e9d 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -1421,10 +1421,12 @@ void browser_window_mouse_action_html(struct browser_window *bw,
while ((next_box = box_at_point(box, x, y, &box_x, &box_y, &content)) !=
NULL) {
+ enum css_overflow overflow = CSS_OVERFLOW_VISIBLE;
+
box = next_box;
- if (box->style &&
- box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
continue;
if (box->object)
@@ -1458,14 +1460,16 @@ void browser_window_mouse_action_html(struct browser_window *bw,
if (box->title)
title = box->title;
- if (box->style && box->style->cursor != CSS_CURSOR_UNKNOWN)
- pointer = get_pointer_shape(bw, box, false);
+ pointer = get_pointer_shape(bw, box, false);
+
+ if (box->style)
+ overflow = css_computed_overflow(box->style);
if (box->style && box->type != BOX_BR &&
box->type != BOX_INLINE &&
box->type != BOX_TEXT &&
- (box->style->overflow == CSS_OVERFLOW_SCROLL ||
- box->style->overflow == CSS_OVERFLOW_AUTO) &&
+ (overflow == CSS_OVERFLOW_SCROLL ||
+ overflow == CSS_OVERFLOW_AUTO) &&
((box_vscrollbar_present(box) &&
box_x + box->scroll_x + box->padding[LEFT] +
box->width < x) ||
@@ -2464,7 +2468,9 @@ gui_pointer_shape get_pointer_shape(struct browser_window *bw, struct box *box,
bool imagemap)
{
gui_pointer_shape pointer;
- struct css_style *style;
+ css_computed_style *style;
+ enum css_cursor cursor;
+ lwc_string **cursor_uris;
assert(bw);
@@ -2481,84 +2487,83 @@ gui_pointer_shape get_pointer_shape(struct browser_window *bw, struct box *box,
else
style = box->style;
- assert(style);
- switch (style->cursor) {
- case CSS_CURSOR_AUTO:
- if (box->href || (box->gadget &&
- (box->gadget->type == GADGET_IMAGE ||
- box->gadget->type == GADGET_SUBMIT)) ||
- imagemap) {
- /* link */
- pointer = GUI_POINTER_POINT;
- } else if (box->gadget &&
- (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_TEXTAREA)) {
- /* text input */
- pointer = GUI_POINTER_CARET;
- } else {
- /* anything else */
- if (loading)
- /* loading new content */
- pointer = GUI_POINTER_PROGRESS;
- else
- pointer = GUI_POINTER_DEFAULT;
- }
- break;
- case CSS_CURSOR_CROSSHAIR:
- pointer = GUI_POINTER_CROSS;
- break;
- case CSS_CURSOR_POINTER:
+ if (style == NULL)
+ return GUI_POINTER_DEFAULT;
+
+ cursor = css_computed_cursor(style, &cursor_uris);
+
+ switch (cursor) {
+ case CSS_CURSOR_AUTO:
+ if (box->href || (box->gadget &&
+ (box->gadget->type == GADGET_IMAGE ||
+ box->gadget->type == GADGET_SUBMIT)) ||
+ imagemap) {
+ /* link */
pointer = GUI_POINTER_POINT;
- break;
- case CSS_CURSOR_MOVE:
- pointer = GUI_POINTER_MOVE;
- break;
- case CSS_CURSOR_E_RESIZE:
- pointer = GUI_POINTER_RIGHT;
- break;
- case CSS_CURSOR_W_RESIZE:
- pointer = GUI_POINTER_LEFT;
- break;
- case CSS_CURSOR_N_RESIZE:
- pointer = GUI_POINTER_UP;
- break;
- case CSS_CURSOR_S_RESIZE:
- pointer = GUI_POINTER_DOWN;
- break;
- case CSS_CURSOR_NE_RESIZE:
- pointer = GUI_POINTER_RU;
- break;
- case CSS_CURSOR_SW_RESIZE:
- pointer = GUI_POINTER_LD;
- break;
- case CSS_CURSOR_SE_RESIZE:
- pointer = GUI_POINTER_RD;
- break;
- case CSS_CURSOR_NW_RESIZE:
- pointer = GUI_POINTER_LU;
- break;
- case CSS_CURSOR_TEXT:
+ } else if (box->gadget &&
+ (box->gadget->type == GADGET_TEXTBOX ||
+ box->gadget->type == GADGET_PASSWORD ||
+ box->gadget->type == GADGET_TEXTAREA)) {
+ /* text input */
pointer = GUI_POINTER_CARET;
- break;
- case CSS_CURSOR_WAIT:
- pointer = GUI_POINTER_WAIT;
- break;
- case CSS_CURSOR_PROGRESS:
- pointer = GUI_POINTER_PROGRESS;
- break;
- case CSS_CURSOR_NO_DROP:
- pointer = GUI_POINTER_NO_DROP;
- break;
- case CSS_CURSOR_NOT_ALLOWED:
- pointer = GUI_POINTER_NOT_ALLOWED;
- break;
- case CSS_CURSOR_HELP:
- pointer = GUI_POINTER_HELP;
- break;
- default:
- pointer = GUI_POINTER_DEFAULT;
- break;
+ } else {
+ /* anything else */
+ if (loading) {
+ /* loading new content */
+ pointer = GUI_POINTER_PROGRESS;
+ } else {
+ pointer = GUI_POINTER_DEFAULT;
+ }
+ }
+ break;
+ case CSS_CURSOR_CROSSHAIR:
+ pointer = GUI_POINTER_CROSS;
+ break;
+ case CSS_CURSOR_POINTER:
+ pointer = GUI_POINTER_POINT;
+ break;
+ case CSS_CURSOR_MOVE:
+ pointer = GUI_POINTER_MOVE;
+ break;
+ case CSS_CURSOR_E_RESIZE:
+ pointer = GUI_POINTER_RIGHT;
+ break;
+ case CSS_CURSOR_W_RESIZE:
+ pointer = GUI_POINTER_LEFT;
+ break;
+ case CSS_CURSOR_N_RESIZE:
+ pointer = GUI_POINTER_UP;
+ break;
+ case CSS_CURSOR_S_RESIZE:
+ pointer = GUI_POINTER_DOWN;
+ break;
+ case CSS_CURSOR_NE_RESIZE:
+ pointer = GUI_POINTER_RU;
+ break;
+ case CSS_CURSOR_SW_RESIZE:
+ pointer = GUI_POINTER_LD;
+ break;
+ case CSS_CURSOR_SE_RESIZE:
+ pointer = GUI_POINTER_RD;
+ break;
+ case CSS_CURSOR_NW_RESIZE:
+ pointer = GUI_POINTER_LU;
+ break;
+ case CSS_CURSOR_TEXT:
+ pointer = GUI_POINTER_CARET;
+ break;
+ case CSS_CURSOR_WAIT:
+ pointer = GUI_POINTER_WAIT;
+ break;
+ case CSS_CURSOR_PROGRESS:
+ pointer = GUI_POINTER_PROGRESS;
+ break;
+ case CSS_CURSOR_HELP:
+ pointer = GUI_POINTER_HELP;
+ break;
+ default:
+ pointer = GUI_POINTER_DEFAULT;
+ break;
}
return pointer;
diff --git a/desktop/plot_style.c b/desktop/plot_style.c
index 54dbd40ce..94e52ca00 100644
--- a/desktop/plot_style.c
+++ b/desktop/plot_style.c
@@ -140,7 +140,7 @@ plot_style_t *plot_style_stroke_history = &plot_style_stroke_history_static;
/* Generic font style */
static const plot_font_style_t plot_style_font_static = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 10,
+ .size = 10 * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
diff --git a/desktop/plot_style.h b/desktop/plot_style.h
index 088f0d275..a3b3f0103 100644
--- a/desktop/plot_style.h
+++ b/desktop/plot_style.h
@@ -23,6 +23,8 @@
#ifndef _NETSURF_DESKTOP_PLOT_STYLE_H_
#define _NETSURF_DESKTOP_PLOT_STYLE_H_
+#include <stdint.h>
+
/* html widget colours */
#define WIDGET_BASEC 0xd9d9d9
#define WIDGET_BLOBC 0x000000
@@ -63,6 +65,15 @@
((((c0 & 0xff) + (c1 & 0xff)) >> 1) << 0)
/**
+ * Colour type: XBGR
+ */
+typedef uint32_t colour;
+/**
+ * Magical transparent value
+ */
+#define NS_TRANSPARENT 0x01000000
+
+/**
* Type of plot operation
*/
typedef enum {
diff --git a/desktop/print.c b/desktop/print.c
index 1fdd5170d..4f86bbc22 100644
--- a/desktop/print.c
+++ b/desktop/print.c
@@ -26,10 +26,10 @@
#include <string.h>
#include "content/content.h"
+#include "css/utils.h"
#include "desktop/options.h"
#include "desktop/print.h"
#include "desktop/printer.h"
-#include "render/loosen.h"
#include "render/box.h"
#include "utils/log.h"
#include "utils/talloc.h"
@@ -197,8 +197,7 @@ struct content *print_init(struct content *content,
}
/**
- * The content is resized to fit page width. In case it is to wide, it is
- * loosened.
+ * The content is resized to fit page width.
*
* \param content The content to be printed
* \param settings The settings for printing to use
@@ -213,24 +212,18 @@ bool print_apply_settings(struct content *content,
/*Apply settings - adjust page size etc*/
page_content_width = (settings->page_width -
- settings->margins[MARGINLEFT] -
- settings->margins[MARGINRIGHT]) / settings->scale;
+ FIXTOFLT(FSUB(settings->margins[MARGINLEFT],
+ settings->margins[MARGINRIGHT]))) / settings->scale;
page_content_height = (settings->page_height -
- settings->margins[MARGINTOP] -
- settings->margins[MARGINBOTTOM]) / settings->scale;
+ FIXTOFLT(FSUB(settings->margins[MARGINTOP],
+ settings->margins[MARGINBOTTOM]))) / settings->scale;
content_reformat(content, page_content_width, 0);
LOG(("New layout applied.New height = %d ; New width = %d ",
content->height, content->width));
- /*check if loosening is necessary and requested*/
- if (option_enable_loosening && content->width > page_content_width)
- return loosen_document_layout(content,
- content->data.html.layout,
- page_content_width, page_content_height);
-
return true;
}
@@ -275,9 +268,8 @@ struct print_settings *print_make_settings(print_configuration configuration,
const char *filename, const struct font_functions *font_func)
{
struct print_settings *settings;
- struct css_length length;
-
- length.unit = CSS_UNIT_MM;
+ css_fixed length = 0;
+ css_unit unit = CSS_UNIT_MM;
switch (configuration){
case PRINT_DEFAULT:
@@ -292,14 +284,18 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = DEFAULT_EXPORT_SCALE;
- length.value = DEFAULT_MARGIN_LEFT_MM;
- settings->margins[MARGINLEFT] = css_len2px(&length, 0);
- length.value = DEFAULT_MARGIN_RIGHT_MM;
- settings->margins[MARGINRIGHT] = css_len2px(&length, 0);
- length.value = DEFAULT_MARGIN_TOP_MM;
- settings->margins[MARGINTOP] = css_len2px(&length, 0);
- length.value = DEFAULT_MARGIN_BOTTOM_MM;
- settings->margins[MARGINBOTTOM] = css_len2px(&length, 0);
+ length = INTTOFIX(DEFAULT_MARGIN_LEFT_MM);
+ settings->margins[MARGINLEFT] =
+ nscss_len2px(length, unit, NULL);
+ length = INTTOFIX(DEFAULT_MARGIN_RIGHT_MM);
+ settings->margins[MARGINRIGHT] =
+ nscss_len2px(length, unit, NULL);
+ length = INTTOFIX(DEFAULT_MARGIN_TOP_MM);
+ settings->margins[MARGINTOP] =
+ nscss_len2px(length, unit, NULL);
+ length = INTTOFIX(DEFAULT_MARGIN_BOTTOM_MM);
+ settings->margins[MARGINBOTTOM] =
+ nscss_len2px(length, unit, NULL);
break;
/* use settings from the Export options tab */
case PRINT_OPTIONS:
@@ -314,14 +310,18 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = (float)option_export_scale / 100;
- length.value = option_margin_left;
- settings->margins[MARGINLEFT] = css_len2px(&length, 0);
- length.value = option_margin_right;
- settings->margins[MARGINRIGHT] = css_len2px(&length, 0);
- length.value = option_margin_top;
- settings->margins[MARGINTOP] = css_len2px(&length, 0);
- length.value = option_margin_bottom;
- settings->margins[MARGINBOTTOM] = css_len2px(&length, 0);
+ length = INTTOFIX(option_margin_left);
+ settings->margins[MARGINLEFT] =
+ nscss_len2px(length, unit, NULL);
+ length = INTTOFIX(option_margin_right);
+ settings->margins[MARGINRIGHT] =
+ nscss_len2px(length, unit, NULL);
+ length = INTTOFIX(option_margin_top);
+ settings->margins[MARGINTOP] =
+ nscss_len2px(length, unit, NULL);
+ length = INTTOFIX(option_margin_bottom);
+ settings->margins[MARGINBOTTOM] =
+ nscss_len2px(length, unit, NULL);
break;
default:
return NULL;
diff --git a/desktop/print.h b/desktop/print.h
index bc07e377e..fece526be 100644
--- a/desktop/print.h
+++ b/desktop/print.h
@@ -34,6 +34,8 @@
#include <stdbool.h>
+#include "css/css.h"
+
struct content;
struct printer;
@@ -48,7 +50,7 @@ typedef enum { PRINT_DEFAULT, PRINT_OPTIONS } print_configuration;
struct print_settings{
/*Standard parameters*/
float page_width, page_height;
- int margins[4];
+ css_fixed margins[4];
float scale;
diff --git a/desktop/save_pdf/font_haru.c b/desktop/save_pdf/font_haru.c
index 0bf86c340..c90753121 100644
--- a/desktop/save_pdf/font_haru.c
+++ b/desktop/save_pdf/font_haru.c
@@ -37,6 +37,7 @@
#include <hpdf.h>
#include "css/css.h"
+#include "css/utils.h"
#include "desktop/options.h"
#include "desktop/save_pdf/font_haru.h"
@@ -216,8 +217,7 @@ bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle,
/**
* Find where to split a string to make it fit a width.
*
- * \param fstyle css_style for this text, with style->font_size.size ==
- * CSS_FONT_SIZE_LENGTH
+ * \param fstyle style for this text
* \param string string to measure (no UTF-8 currently)
* \param length length of string
* \param x width available
@@ -268,7 +268,7 @@ bool haru_nsfont_split(const plot_font_style_t *fstyle,
/**
* Apply font style to a Haru HPDF_Page
*
- * \param style plot style for this page
+ * \param fstyle plot style for this page
* \param doc document owning the page
* \param page the page to apply the style to
* \param font if this is non NULL it is updated to the font based
diff --git a/desktop/save_pdf/pdf_plotters.c b/desktop/save_pdf/pdf_plotters.c
index a29db2415..8dbe43971 100644
--- a/desktop/save_pdf/pdf_plotters.c
+++ b/desktop/save_pdf/pdf_plotters.c
@@ -146,7 +146,7 @@ bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *psty
{
DashPattern_e dash;
#ifdef PDF_DEBUG
- LOG(("%d %d %d %d %f %X", x0, y0, x1, y1, page_height - y0, style->fill_colour));
+ LOG(("%d %d %d %d %f %X", x0, y0, x1, y1, page_height - y0, pstyle->fill_colour));
#endif
if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
@@ -353,7 +353,7 @@ bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style)
bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
{
#ifdef PDF_DEBUG
- LOG(("%d %d %d %d %d %X", x, y, radius, angle1, angle2, c));
+ LOG(("%d %d %d %d %d %X", x, y, radius, angle1, angle2, style->stroke_colour));
#endif
/* FIXME: line width 1 is ok ? */
@@ -381,8 +381,8 @@ bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
HPDF_REAL max_width, max_height;
#ifdef PDF_DEBUG
- LOG(("%d %d %d %d %p 0x%x %p", x, y, width, height,
- bitmap, bg, content));
+ LOG(("%d %d %d %d %p 0x%x", x, y, width, height,
+ bitmap, bg));
#endif
if (width == 0 || height == 0)
return true;
@@ -662,10 +662,12 @@ bool pdf_begin(struct print_settings *print_settings)
settings = print_settings;
- page_width = settings->page_width - settings->margins[MARGINLEFT] -
- settings->margins[MARGINRIGHT];
+ page_width = settings->page_width -
+ FIXTOFLT(FSUB(settings->margins[MARGINLEFT],
+ settings->margins[MARGINRIGHT]));
- page_height = settings->page_height - settings->margins[MARGINTOP];
+ page_height = settings->page_height -
+ FIXTOFLT(settings->margins[MARGINTOP]);
#ifndef PDF_DEBUG
@@ -708,7 +710,8 @@ bool pdf_next_page(void)
HPDF_Page_SetWidth (pdf_page, settings->page_width);
HPDF_Page_SetHeight(pdf_page, settings->page_height);
- HPDF_Page_Concat(pdf_page, 1, 0, 0, 1, settings->margins[MARGINLEFT], 0);
+ HPDF_Page_Concat(pdf_page, 1, 0, 0, 1,
+ FIXTOFLT(settings->margins[MARGINLEFT]), 0);
pdfw_gs_save(pdf_page);
diff --git a/desktop/save_text.c b/desktop/save_text.c
index 535fec461..15f41702e 100644
--- a/desktop/save_text.c
+++ b/desktop/save_text.c
@@ -141,9 +141,9 @@ void save_text_solve_whitespace(struct box *box, bool *first,
(box->type != BOX_INLINE &&
(box->parent && box->parent->list_marker == box)) ||
(box->parent->style &&
- (box->parent->style->white_space ==
+ (css_computed_white_space(box->parent->style) ==
CSS_WHITE_SPACE_PRE ||
- box->parent->style->white_space ==
+ css_computed_white_space(box->parent->style) ==
CSS_WHITE_SPACE_PRE_WRAP) &&
box->type == BOX_INLINE_CONTAINER))) {
if (*before == WHITESPACE_ONE_NEW_LINE)
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 1b48d9d55..43ac85b0c 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <string.h>
#include "css/css.h"
+#include "css/utils.h"
#include "desktop/textarea.h"
#include "desktop/textinput.h"
#include "desktop/plotters.h"
@@ -135,14 +136,14 @@ static void textarea_normalise_text(struct text_area *ta,
* \param width width of the text area
* \param height width of the text area
* \param flags text area flags
- * \param style css style (font style properties are used only)
+ * \param style font style
* \param redraw_start_callback will be called when textarea wants to redraw
* \param redraw_end_callback will be called when textarea finisjes redrawing
* \param data user specified data which will be passed to redraw callbacks
* \return Opaque handle for textarea or 0 on error
*/
struct text_area *textarea_create(int x, int y, int width, int height,
- unsigned int flags, const struct css_style *style,
+ unsigned int flags, const plot_font_style_t *style,
textarea_start_redraw_callback redraw_start_callback,
textarea_end_redraw_callback redraw_end_callback, void *data)
{
@@ -183,9 +184,10 @@ struct text_area *textarea_create(int x, int y, int width, int height,
ret->text_len = 1;
ret->text_utf8_len = 0;
- font_plot_style_from_css(style, &ret->fstyle);
- ret->line_height = css_len2px(&(style->line_height.value.length),
- style);
+ ret->fstyle = *style;
+
+ ret->line_height = FIXTOINT(FDIVI(FMUL(
+ FLTTOFIX(1.2 * style->size), nscss_screen_dpi), 72));
ret->caret_pos.line = ret->caret_pos.char_off = 0;
ret->selection_start = -1;
@@ -427,7 +429,7 @@ bool textarea_set_caret(struct text_area *ta, int caret)
int index;
int x, y;
int x0, y0, x1, y1;
- int height;
+ int height = 0;
if (ta->flags & TEXTAREA_READONLY)
@@ -440,7 +442,7 @@ bool textarea_set_caret(struct text_area *ta, int caret)
if (caret != -1 && (unsigned)caret > c_len)
caret = c_len;
- height = ta->fstyle.size * css_screen_dpi / 72;
+ height = ta->fstyle.size * nscss_screen_dpi / 72;
/* Delete the old caret */
if (ta->caret_pos.char_off != -1) {
diff --git a/desktop/textarea.h b/desktop/textarea.h
index 14e93f5e8..ca02927b4 100644
--- a/desktop/textarea.h
+++ b/desktop/textarea.h
@@ -26,8 +26,8 @@
#include <stdint.h>
#include <stdbool.h>
-#include "css/css.h"
#include "desktop/browser.h"
+#include "desktop/plot_style.h"
/* Text area flags */
#define TEXTAREA_MULTILINE 0x01 /**< Text area is multiline */
@@ -39,7 +39,7 @@ typedef void(*textarea_start_redraw_callback)(void *data);
typedef void(*textarea_end_redraw_callback)(void *data);
struct text_area *textarea_create(int x, int y, int width, int height,
- unsigned int flags, const struct css_style *style,
+ unsigned int flags, const plot_font_style_t *style,
textarea_start_redraw_callback redraw_start_callback,
textarea_end_redraw_callback redraw_end_callback, void *data);
void textarea_set_position(struct text_area *ta, int x, int y);
diff --git a/framebuffer/fbtk.c b/framebuffer/fbtk.c
index c564a9117..d212fb4d5 100644
--- a/framebuffer/fbtk.c
+++ b/framebuffer/fbtk.c
@@ -41,7 +41,7 @@
static plot_font_style_t root_style = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 11,
+ .size = 11 * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
};
diff --git a/framebuffer/gui.c b/framebuffer/gui.c
index 65080db8a..fbed5bd86 100644
--- a/framebuffer/gui.c
+++ b/framebuffer/gui.c
@@ -56,6 +56,7 @@
#include "content/fetch.h"
char *default_stylesheet_url;
+char *quirks_stylesheet_url;
char *adblock_stylesheet_url;
char *options_file_location;
@@ -367,6 +368,9 @@ void gui_init(int argc, char** argv)
default_stylesheet_url = path_to_url(buf);
LOG(("Using '%s' as Default CSS URL", default_stylesheet_url));
+ fb_find_resource(buf, "quirks.css", "./framebuffer/res/quirks.css");
+ quirks_stylesheet_url = path_to_url(buf);
+
nsfb = framebuffer_initialise(argc, argv);
if (nsfb == NULL)
die("Unable to initialise framebuffer");
diff --git a/framebuffer/res/quirks.css b/framebuffer/res/quirks.css
new file mode 120000
index 000000000..d9fb80334
--- /dev/null
+++ b/framebuffer/res/quirks.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
diff --git a/gtk/font_pango.c b/gtk/font_pango.c
index c0d789344..e4944f0be 100644
--- a/gtk/font_pango.c
+++ b/gtk/font_pango.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <gtk/gtk.h>
#include "css/css.h"
+#include "css/utils.h"
#include "gtk/font_pango.h"
#include "gtk/gtk_plotters.h"
#include "render/font.h"
@@ -55,10 +56,6 @@ const struct font_functions nsfont = {
nsfont_split
};
-
-
-
-
/**
* Measure the width of a string.
*
@@ -302,12 +299,7 @@ PangoFontDescription *nsfont_style_to_description(
break;
}
- size = fstyle->size;
-
- if (size < (unsigned)abs(option_font_min_size / 10) * FONT_SIZE_SCALE)
- size = (option_font_min_size / 10) * FONT_SIZE_SCALE;
-
- size = (size * PANGO_SCALE) / FONT_SIZE_SCALE;
+ size = (fstyle->size * PANGO_SCALE) / FONT_SIZE_SCALE;
if (fstyle->flags & FONTF_ITALIC)
style = PANGO_STYLE_ITALIC;
diff --git a/gtk/gtk_gui.c b/gtk/gtk_gui.c
index b8217b7f1..58bc18ed6 100644
--- a/gtk/gtk_gui.c
+++ b/gtk/gtk_gui.c
@@ -65,6 +65,7 @@
bool gui_in_multitask = false;
char *default_stylesheet_url;
+char *quirks_stylesheet_url;
char *adblock_stylesheet_url;
char *options_file_location;
char *glade_file_location;
@@ -307,6 +308,9 @@ void gui_init(int argc, char** argv)
default_stylesheet_url = path_to_url(buf);
LOG(("Using '%s' as Default CSS URL", default_stylesheet_url));
+ find_resource(buf, "quirks.css", "./gtk/res/quirks.css");
+ quirks_stylesheet_url = path_to_url(buf);
+
find_resource(buf, "adblock.css", "./gtk/res/adblock.css");
adblock_stylesheet_url = path_to_url(buf);
LOG(("Using '%s' as AdBlock CSS URL", adblock_stylesheet_url));
@@ -417,6 +421,7 @@ void gui_quit(void)
urldb_save_cookies(option_cookie_jar);
urldb_save(option_url_file);
free(default_stylesheet_url);
+ free(quirks_stylesheet_url);
free(adblock_stylesheet_url);
free(option_cookie_file);
free(option_cookie_jar);
diff --git a/gtk/gtk_print.c b/gtk/gtk_print.c
index 8daa21df8..98b43cb89 100644
--- a/gtk/gtk_print.c
+++ b/gtk/gtk_print.c
@@ -449,7 +449,6 @@ static const struct plotter_table nsgtk_print_plotters = {
.option_knockout = false,
};
-
static bool gtk_print_begin(struct print_settings* settings)
{
return true;
@@ -504,8 +503,9 @@ void gtk_print_signal_begin_print (GtkPrintOperation *operation,
settings->page_width, settings->page_height, height_to_print));
height_on_page = settings->page_height;
- height_on_page = height_on_page - settings->margins[MARGINTOP]
- - settings->margins[MARGINBOTTOM];
+ height_on_page = height_on_page -
+ FIXTOFLT(FSUB(settings->margins[MARGINTOP],
+ settings->margins[MARGINBOTTOM]));
height_to_print *= settings->scale;
page_number = height_to_print / height_on_page;
diff --git a/gtk/gtk_scaffolding.c b/gtk/gtk_scaffolding.c
index d6c4f1e55..6905408fa 100644
--- a/gtk/gtk_scaffolding.c
+++ b/gtk/gtk_scaffolding.c
@@ -24,6 +24,7 @@
#include <gtk/gtk.h>
#include <libxml/debugXML.h>
#include "content/content.h"
+#include "css/utils.h"
#include "desktop/browser.h"
#include "desktop/history_core.h"
#include "desktop/gui.h"
@@ -1241,9 +1242,9 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
g->preferences_dialog = NULL;
- css_screen_dpi = gdk_screen_get_resolution(
- gtk_widget_get_screen(GTK_WIDGET(g->window)));
- LOG(("Set CSS DPI to %f", css_screen_dpi));
+ nscss_screen_dpi = FLTTOFIX(gdk_screen_get_resolution(
+ gtk_widget_get_screen(GTK_WIDGET(g->window))));
+ LOG(("Set CSS DPI to %f", FIXTOFLT(nscss_screen_dpi)));
/* set this window's size and position to what's in the options, or
* or some sensible default if they're not set yet.
diff --git a/gtk/res/quirks.css b/gtk/res/quirks.css
new file mode 120000
index 000000000..d9fb80334
--- /dev/null
+++ b/gtk/res/quirks.css
@@ -0,0 +1 @@
+../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
diff --git a/image/bmp.c b/image/bmp.c
index b7ca94b9c..4eaf5daa6 100644
--- a/image/bmp.c
+++ b/image/bmp.c
@@ -49,7 +49,8 @@ bmp_bitmap_callback_vt bmp_bitmap_callbacks = {
.bitmap_get_bpp = bitmap_get_bpp
};
-bool nsbmp_create(struct content *c, const char *params[])
+bool nsbmp_create(struct content *c, struct content *parent,
+ const char *params[])
{
union content_msg_data msg_data;
diff --git a/image/bmp.h b/image/bmp.h
index 905f9b40f..f7b974f03 100644
--- a/image/bmp.h
+++ b/image/bmp.h
@@ -40,7 +40,8 @@ struct content_bmp_data {
extern bmp_bitmap_callback_vt bmp_bitmap_callbacks; /** Only to be used by ICO code. */
-bool nsbmp_create(struct content *c, const char *params[]);
+bool nsbmp_create(struct content *c, struct content *parent,
+ const char *params[]);
bool nsbmp_convert(struct content *c, int width, int height);
void nsbmp_destroy(struct content *c);
bool nsbmp_redraw(struct content *c, int x, int y,
diff --git a/image/gif.c b/image/gif.c
index e16275448..62d73f0b0 100644
--- a/image/gif.c
+++ b/image/gif.c
@@ -64,7 +64,8 @@ gif_bitmap_callback_vt gif_bitmap_callbacks = {
};
-bool nsgif_create(struct content *c, const char *params[])
+bool nsgif_create(struct content *c, struct content *parent,
+ const char *params[])
{
union content_msg_data msg_data;
/* Initialise our data structure */
diff --git a/image/gif.h b/image/gif.h
index 571818ea2..0e3ef6605 100644
--- a/image/gif.h
+++ b/image/gif.h
@@ -37,7 +37,8 @@ struct content_gif_data {
int current_frame; /**< current frame to display [0...(max-1)] */
};
-bool nsgif_create(struct content *c, const char *params[]);
+bool nsgif_create(struct content *c, struct content *parent,
+ const char *params[]);
bool nsgif_convert(struct content *c, int width, int height);
void nsgif_destroy(struct content *c);
bool nsgif_redraw(struct content *c, int x, int y,
diff --git a/image/ico.c b/image/ico.c
index dc687a0e3..5416e612a 100644
--- a/image/ico.c
+++ b/image/ico.c
@@ -37,7 +37,8 @@
#include "utils/messages.h"
#include "utils/utils.h"
-bool nsico_create(struct content *c, const char *params[])
+bool nsico_create(struct content *c, struct content *parent,
+ const char *params[])
{
union content_msg_data msg_data;
c->data.ico.ico = calloc(sizeof(ico_collection), 1);
diff --git a/image/ico.h b/image/ico.h
index 435981470..cd7b0b432 100644
--- a/image/ico.h
+++ b/image/ico.h
@@ -35,7 +35,8 @@ struct content_ico_data {
struct ico_collection *ico; /** ICO collection data */
};
-bool nsico_create(struct content *c, const char *params[]);
+bool nsico_create(struct content *c, struct content *parent,
+ const char *params[]);
bool nsico_convert(struct content *c, int width, int height);
void nsico_destroy(struct content *c);
bool nsico_redraw(struct content *c, int x, int y,
diff --git a/image/mng.c b/image/mng.c
index 4f19d7202..d21d9e879 100644
--- a/image/mng.c
+++ b/image/mng.c
@@ -69,7 +69,8 @@ static void nsmng_free(mng_ptr p, mng_size_t n);
#endif
-bool nsmng_create(struct content *c, const char *params[])
+bool nsmng_create(struct content *c, struct content *parent,
+ const char *params[])
{
mng_retcode code;
union content_msg_data msg_data;
diff --git a/image/mng.h b/image/mng.h
index 1a3c8852d..2ea85409c 100644
--- a/image/mng.h
+++ b/image/mng.h
@@ -40,7 +40,8 @@ struct content_mng_data {
void *handle;
};
-bool nsmng_create(struct content *c, const char *params[]);
+bool nsmng_create(struct content *c, struct content *parent,
+ const char *params[]);
bool nsmng_process_data(struct content *c, char *data, unsigned int size);
bool nsmng_convert(struct content *c, int width, int height);
void nsmng_destroy(struct content *c);
diff --git a/image/png.c b/image/png.c
index 34c517d90..176b89423 100644
--- a/image/png.c
+++ b/image/png.c
@@ -51,7 +51,8 @@ static void row_callback(png_structp png, png_bytep new_row,
static void end_callback(png_structp png, png_infop info);
-bool nspng_create(struct content *c, const char *params[])
+bool nspng_create(struct content *c, struct content *parent,
+ const char *params[])
{
union content_msg_data msg_data;
diff --git a/image/png.h b/image/png.h
index 4c5b1bed3..ffabd73b9 100644
--- a/image/png.h
+++ b/image/png.h
@@ -24,7 +24,7 @@
#ifdef WITH_PNG
-#include "css/css.h"
+#include "desktop/plot_style.h"
#include <stdbool.h>
#include <png.h>
@@ -42,7 +42,8 @@ struct content_png_data {
size_t rowbytes; /**< Number of bytes per row */
};
-bool nspng_create(struct content *c, const char *params[]);
+bool nspng_create(struct content *c, struct content *parent,
+ const char *params[]);
bool nspng_process_data(struct content *c, char *data, unsigned int size);
bool nspng_convert(struct content *c, int width, int height);
void nspng_destroy(struct content *c);
diff --git a/image/rsvg.c b/image/rsvg.c
index b1d597052..86e1d5b66 100644
--- a/image/rsvg.c
+++ b/image/rsvg.c
@@ -49,7 +49,8 @@
static inline void rsvg_argb_to_abgr(uint32_t pixels[], int width, int height,
size_t rowstride);
-bool rsvg_create(struct content *c, const char *params[])
+bool rsvg_create(struct content *c, struct content *parent,
+ const char *params[])
{
struct content_rsvg_data *d = &c->data.rsvg;
union content_msg_data msg_data;
diff --git a/image/rsvg.h b/image/rsvg.h
index d627991cc..ac414d85c 100644
--- a/image/rsvg.h
+++ b/image/rsvg.h
@@ -41,7 +41,8 @@ struct content_rsvg_data {
struct bitmap *bitmap; /**< Created NetSurf bitmap */
};
-bool rsvg_create(struct content *c, const char *params[]);
+bool rsvg_create(struct content *c, struct content *parent,
+ const char *params[]);
bool rsvg_process_data(struct content *c, char *data, unsigned int size);
bool rsvg_convert(struct content *c, int width, int height);
void rsvg_destroy(struct content *c);
diff --git a/image/svg.c b/image/svg.c
index b87a8a67d..4321a9fc3 100644
--- a/image/svg.c
+++ b/image/svg.c
@@ -40,7 +40,7 @@
* Create a CONTENT_SVG.
*/
-bool svg_create(struct content *c, const char *params[])
+bool svg_create(struct content *c, struct content *parent, const char *params[])
{
union content_msg_data msg_data;
diff --git a/image/svg.h b/image/svg.h
index ec9c789c2..b191c4cd6 100644
--- a/image/svg.h
+++ b/image/svg.h
@@ -32,7 +32,8 @@ struct content_svg_data {
struct svgtiny_diagram *diagram;
};
-bool svg_create(struct content *c, const char *params[]);
+bool svg_create(struct content *c, struct content *parent,
+ const char *params[]);
bool svg_convert(struct content *c, int width, int height);
void svg_destroy(struct content *c);
bool svg_redraw(struct content *c, int x, int y,
diff --git a/render/box.c b/render/box.c
index 7dde0b759..b1ebfcbad 100644
--- a/render/box.c
+++ b/render/box.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "content/content.h"
#include "css/css.h"
+#include "css/dump.h"
#include "desktop/options.h"
#include "render/box.h"
#include "render/form.h"
@@ -58,7 +59,7 @@ static struct box_duplicate_llist *box_duplicate_last = NULL;
* \return allocated and initialised box, or 0 on memory exhaustion
*/
-struct box * box_create(struct css_style *style,
+struct box * box_create(css_computed_style *style,
char *href, const char *target, char *title, char *id,
void *context)
{
@@ -78,10 +79,11 @@ struct box * box_create(struct css_style *style,
box->descendant_x0 = box->descendant_y0 = 0;
box->descendant_x1 = box->descendant_y1 = 0;
for (i = 0; i != 4; i++)
- box->margin[i] = box->padding[i] = box->border[i] = 0;
+ box->margin[i] = box->padding[i] = box->border[i].width = 0;
box->scroll_x = box->scroll_y = 0;
box->min_width = 0;
box->max_width = UNKNOWN_MAX_WIDTH;
+ box->byte_offset = 0;
box->text = NULL;
box->length = 0;
box->space = 0;
@@ -444,34 +446,34 @@ siblings:
bool box_contains_point(struct box *box, int x, int y, bool *physically)
{
- if (box->x <= x + box->border[LEFT] &&
+ if (box->x <= x + box->border[LEFT].width &&
x < box->x + box->padding[LEFT] + box->width +
- box->border[RIGHT] + box->padding[RIGHT] &&
- box->y <= y + box->border[TOP] &&
+ box->border[RIGHT].width + box->padding[RIGHT] &&
+ box->y <= y + box->border[TOP].width &&
y < box->y + box->padding[TOP] + box->height +
- box->border[BOTTOM] + box->padding[BOTTOM]) {
+ box->border[BOTTOM].width + box->padding[BOTTOM]) {
*physically = true;
return true;
}
if (box->list_marker && box->list_marker->x <= x +
- box->list_marker->border[LEFT] &&
+ box->list_marker->border[LEFT].width &&
x < box->list_marker->x +
box->list_marker->padding[LEFT] +
box->list_marker->width +
- box->list_marker->border[RIGHT] +
+ box->list_marker->border[RIGHT].width +
box->list_marker->padding[RIGHT] &&
box->list_marker->y <= y +
- box->list_marker->border[TOP] &&
+ box->list_marker->border[TOP].width &&
y < box->list_marker->y +
box->list_marker->padding[TOP] +
box->list_marker->height +
- box->list_marker->border[BOTTOM] +
+ box->list_marker->border[BOTTOM].width +
box->list_marker->padding[BOTTOM]) {
*physically = true;
return true;
}
- if ((box->style && box->style->overflow == CSS_OVERFLOW_VISIBLE) ||
- !box->style) {
+ if ((box->style && css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->x + box->descendant_x0 <= x &&
x < box->x + box->descendant_x1 &&
box->y + box->descendant_y0 <= y &&
@@ -502,8 +504,8 @@ struct box *box_object_at_point(struct content *c, int x, int y)
assert(c->type == CONTENT_HTML);
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) {
- if (box->style &&
- box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
continue;
if (box->object)
@@ -532,8 +534,8 @@ struct box *box_href_at_point(struct content *c, int x, int y)
assert(c->type == CONTENT_HTML);
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) {
- if (box->style &&
- box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
continue;
if (box->href)
@@ -580,7 +582,8 @@ bool box_visible(struct box *box)
struct box *fallback;
/* visibility: hidden */
- if (box->style && box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
return false;
/* check if a fallback */
@@ -651,7 +654,7 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth)
if (box->gadget)
fprintf(stream, "(gadget) ");
if (box->style)
- css_dump_style(stream, box->style);
+ nscss_dump_computed_style(stream, box->style);
if (box->href)
fprintf(stream, " -> '%s'", box->href);
if (box->target)
diff --git a/render/box.h b/render/box.h
index 9a90c21a4..3134ea1a2 100644
--- a/render/box.h
+++ b/render/box.h
@@ -91,10 +91,10 @@
#include <stdio.h>
#include <libxml/HTMLparser.h>
+#include "css/css.h"
struct box;
struct column;
-struct css_style;
struct object_params;
struct object_param;
@@ -106,7 +106,7 @@ typedef enum {
BOX_TABLE_ROW_GROUP,
BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT,
BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT,
- BOX_INLINE_END
+ BOX_INLINE_END, BOX_NONE
} box_type;
struct rect {
@@ -114,6 +114,18 @@ struct rect {
int x1, y1;
};
+/* Sides of a box */
+enum box_side { TOP, RIGHT, BOTTOM, LEFT };
+
+/**
+ * Container for box border details
+ */
+struct box_border {
+ enum css_border_style style; /**< border-style */
+ enum css_border_color color; /**< border-color type */
+ css_color c; /**< border-color value */
+ int width; /**< border-width (pixels) */
+};
/** Node in box tree. All dimensions are in pixels. */
struct box {
@@ -121,7 +133,7 @@ struct box {
box_type type;
/** Style for this box. 0 for INLINE_CONTAINER and FLOAT_*. */
- struct css_style * style;
+ css_computed_style *style;
/** Coordinate of left padding edge relative to parent box, or relative
* to ancestor that contains this box in float_children for FLOAT_. */
@@ -153,7 +165,7 @@ struct box {
int margin[4]; /**< Margin: TOP, RIGHT, BOTTOM, LEFT. */
int padding[4]; /**< Padding: TOP, RIGHT, BOTTOM, LEFT. */
- int border[4]; /**< Border width: TOP, RIGHT, BOTTOM, LEFT. */
+ struct box_border border[4]; /**< Border: TOP, RIGHT, BOTTOM, LEFT. */
int scroll_x; /**< Horizontal scroll of descendants. */
int scroll_y; /**< Vertical scroll of descendants. */
@@ -282,7 +294,7 @@ extern const char *TARGET_BLANK;
#define UNKNOWN_MAX_WIDTH INT_MAX
-struct box * box_create(struct css_style *style,
+struct box * box_create(css_computed_style *style,
char *href, const char *target, char *title,
char *id, void *context);
void box_add_child(struct box *parent, struct box *child);
diff --git a/render/box_construct.c b/render/box_construct.c
index b8aa5e600..564a443c3 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -37,6 +37,8 @@
#include "utils/config.h"
#include "content/content.h"
#include "css/css.h"
+#include "css/utils.h"
+#include "css/select.h"
#include "desktop/browser.h"
#include "desktop/options.h"
#include "render/box.h"
@@ -82,59 +84,30 @@ static const content_type image_types[] = {
#endif
CONTENT_UNKNOWN };
-#define MAX_SPAN (100)
-
-
/* the strings are not important, since we just compare the pointers */
const char *TARGET_SELF = "_self";
const char *TARGET_PARENT = "_parent";
const char *TARGET_TOP = "_top";
const char *TARGET_BLANK = "_blank";
-/* keeps track of markup presentation */
-struct markup_track {
- enum {
- ALIGN_NONE,
- ALIGN_LEFT,
- ALIGN_CENTER,
- ALIGN_RIGHT
- } align;
- bool cell_border;
- colour border_color;
-
- bool cell_padding;
- long padding_width;
-
- bool table;
-};
-
static bool convert_xml_to_box(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author);
+ char *href, const char *target, char *title);
bool box_construct_element(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author);
+ char *href, const char *target, char *title);
bool box_construct_text(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
char *href, const char *target, char *title);
-static struct css_style * box_get_style(struct content *c,
- struct css_style *parent_style,
- xmlNode *n, struct markup_track *markup_track,
- struct css_importance *author);
-static void box_solve_display(struct css_style *style, bool root);
+static css_computed_style * box_get_style(struct content *c,
+ const css_computed_style *parent_style, xmlNode *n);
static void box_text_transform(char *s, unsigned int len,
- css_text_transform tt);
+ enum css_text_transform tt);
#define BOX_SPECIAL_PARAMS xmlNode *n, struct content *content, \
- struct box *box, bool *convert_children, \
- struct markup_track markup_track, \
- struct css_importance *author
+ struct box *box, bool *convert_children
static bool box_a(BOX_SPECIAL_PARAMS);
static bool box_body(BOX_SPECIAL_PARAMS);
static bool box_br(BOX_SPECIAL_PARAMS);
@@ -157,8 +130,10 @@ static bool box_get_attribute(xmlNode *n, const char *attribute,
void *context, char **value);
static struct frame_dimension *box_parse_multi_lengths(const char *s,
unsigned int *count);
-static void parse_inline_colour(char *text, colour *variable);
-
+static bool fetch_object_interned_url(struct content *c, lwc_string *url,
+ struct box *box, const content_type *permitted_types,
+ int available_width, int available_height,
+ bool background);
/* element_table must be sorted by name */
struct element_entry {
@@ -195,12 +170,7 @@ static const struct element_entry element_table[] = {
bool xml_to_box(xmlNode *n, struct content *c)
{
struct box root;
- struct box *inline_container = 0;
- struct css_importance author;
- struct markup_track markup_track;
- markup_track.cell_border = false;
- markup_track.cell_padding = false;
- markup_track.align = ALIGN_NONE;
+ struct box *inline_container = NULL;
assert(c->type == CONTENT_HTML);
@@ -214,20 +184,12 @@ bool xml_to_box(xmlNode *n, struct content *c)
root.float_children = NULL;
root.next_float = NULL;
- c->data.html.style = talloc_memdup(c, &css_base_style,
- sizeof css_base_style);
- if (!c->data.html.style)
- return false;
- c->data.html.style->font_size.value.length.value =
- option_font_size * 0.1;
- /* and get the default font family from the options */
- c->data.html.style->font_family = option_font_default;
-
c->data.html.object_count = 0;
c->data.html.object = 0;
- if (!convert_xml_to_box(n, c, c->data.html.style, &root,
- &inline_container, 0, 0, 0, markup_track, &author))
+ /* The root box's style */
+ if (!convert_xml_to_box(n, c, NULL, &root,
+ &inline_container, 0, 0, 0))
return false;
if (!box_normalise_block(&root, c))
@@ -241,7 +203,7 @@ bool xml_to_box(xmlNode *n, struct content *c)
/* mapping from CSS display to box type
- * this table must be in sync with css/css_enums */
+ * this table must be in sync with libcss' css_display enum */
static const box_type box_map[] = {
0, /*CSS_DISPLAY_INHERIT,*/
BOX_INLINE, /*CSS_DISPLAY_INLINE,*/
@@ -255,10 +217,11 @@ static const box_type box_map[] = {
BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_HEADER_GROUP,*/
BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_FOOTER_GROUP,*/
BOX_TABLE_ROW, /*CSS_DISPLAY_TABLE_ROW,*/
- BOX_INLINE, /*CSS_DISPLAY_TABLE_COLUMN_GROUP,*/
- BOX_INLINE, /*CSS_DISPLAY_TABLE_COLUMN,*/
+ BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN_GROUP,*/
+ BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN,*/
BOX_TABLE_CELL, /*CSS_DISPLAY_TABLE_CELL,*/
- BOX_INLINE /*CSS_DISPLAY_TABLE_CAPTION,*/
+ BOX_INLINE, /*CSS_DISPLAY_TABLE_CAPTION,*/
+ BOX_NONE /*CSS_DISPLAY_NONE*/
};
@@ -267,31 +230,25 @@ static const box_type box_map[] = {
*
* \param n fragment of xml tree
* \param content content of type CONTENT_HTML that is being processed
- * \param parent_style style at this point in xml tree
+ * \param parent_style style at this point in xml tree, or NULL for root box
* \param parent parent in box tree
* \param inline_container current inline container box, or 0, updated to
* new current inline container on exit
* \param href current link URL, or 0 if not in a link
* \param target current link target, or 0 if none
* \param title current title, or 0 if none
- * \param markup_track track presentation markup that affects descendents
- * \param author denotes whether current style has author level
- * importance for certain properties
* \return true on success, false on memory exhaustion
*/
bool convert_xml_to_box(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author)
+ char *href, const char *target, char *title)
{
switch (n->type) {
case XML_ELEMENT_NODE:
return box_construct_element(n, content, parent_style, parent,
- inline_container,
- href, target, title, markup_track, author);
+ inline_container, href, target, title);
case XML_TEXT_NODE:
return box_construct_text(n, content, parent_style, parent,
inline_container, href, target, title);
@@ -307,25 +264,20 @@ bool convert_xml_to_box(xmlNode *n, struct content *content,
*
* \param n XML node of type XML_ELEMENT_NODE
* \param content content of type CONTENT_HTML that is being processed
- * \param parent_style style at this point in xml tree
+ * \param parent_style style at this point in xml tree, or NULL for root node
* \param parent parent in box tree
* \param inline_container current inline container box, or 0, updated to
* new current inline container on exit
* \param href current link URL, or 0 if not in a link
* \param target current link target, or 0 if none
* \param title current title, or 0 if none
- * \param markup_track track presentation markup that affects descendents
- * \param author denotes whether current style has author level
- * importance for certain properties
* \return true on success, false on memory exhaustion
*/
bool box_construct_element(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author)
+ char *href, const char *target, char *title)
{
bool convert_children = true;
char *id = 0;
@@ -333,14 +285,14 @@ bool box_construct_element(xmlNode *n, struct content *content,
struct box *box = 0;
struct box *inline_container_c;
struct box *inline_end;
- struct css_style *style = 0;
+ css_computed_style *style = 0;
struct element_entry *element;
xmlChar *title0;
xmlNode *c;
+ lwc_string *bgimage_uri;
assert(n);
assert(n->type == XML_ELEMENT_NODE);
- assert(parent_style);
assert(parent);
assert(inline_container);
@@ -352,18 +304,23 @@ bool box_construct_element(xmlNode *n, struct content *content,
*/
parent->strip_leading_newline = 0;
- style = box_get_style(content, parent_style, n, &markup_track, author);
+ style = box_get_style(content, parent_style, n);
if (!style)
return false;
/* extract title attribute, if present */
if ((title0 = xmlGetProp(n, (const xmlChar *) "title"))) {
char *title1 = squash_whitespace((char *) title0);
+
xmlFree(title0);
+
if (!title1)
return false;
+
title = talloc_strdup(content, title1);
+
free(title1);
+
if (!title)
return false;
}
@@ -376,8 +333,25 @@ bool box_construct_element(xmlNode *n, struct content *content,
box = box_create(style, href, target, title, id, content);
if (!box)
return false;
- /* set box type from style */
- box->type = box_map[style->display];
+ /* set box type from computed display */
+ if ((css_computed_position(style) == CSS_POSITION_ABSOLUTE ||
+ css_computed_position(style) == CSS_POSITION_FIXED) &&
+ (css_computed_display_static(style) ==
+ CSS_DISPLAY_INLINE ||
+ css_computed_display_static(style) ==
+ CSS_DISPLAY_INLINE_BLOCK ||
+ css_computed_display_static(style) ==
+ CSS_DISPLAY_INLINE_TABLE)) {
+ /* Special case for absolute positioning: make absolute inlines
+ * into inline block so that the boxes are constructed in an
+ * inline container as if they were not absolutely positioned.
+ * Layout expects and handles this. */
+ box->type = box_map[CSS_DISPLAY_INLINE_BLOCK];
+ } else {
+ /* Normal mapping */
+ box->type = box_map[css_computed_display(style,
+ n->parent == NULL)];
+ }
/* special elements */
element = bsearch((const char *) n->name, element_table,
@@ -385,16 +359,17 @@ bool box_construct_element(xmlNode *n, struct content *content,
(int (*)(const void *, const void *)) strcmp);
if (element) {
/* a special convert function exists for this element */
- if (!element->convert(n, content, box, &convert_children,
- markup_track, author))
+ if (!element->convert(n, content, box, &convert_children))
return false;
+
href = box->href;
target = box->target;
}
- if (style->display == CSS_DISPLAY_NONE) {
+ if (box->type == BOX_NONE || css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE) {
/* Free style and invalidate box's style pointer */
- talloc_free(style);
+ css_computed_style_destroy(style);
box->style = NULL;
/* If this box has an associated gadget, invalidate the
@@ -416,60 +391,71 @@ bool box_construct_element(xmlNode *n, struct content *content,
(box->type == BOX_INLINE ||
box->type == BOX_BR ||
box->type == BOX_INLINE_BLOCK ||
- style->float_ == CSS_FLOAT_LEFT ||
- style->float_ == CSS_FLOAT_RIGHT)) {
+ css_computed_float(style) == CSS_FLOAT_LEFT ||
+ css_computed_float(style) == CSS_FLOAT_RIGHT)) {
/* this is the first inline in a block: make a container */
*inline_container = box_create(0, 0, 0, 0, 0, content);
if (!*inline_container)
return false;
+
(*inline_container)->type = BOX_INLINE_CONTAINER;
+
box_add_child(parent, *inline_container);
}
if (box->type == BOX_INLINE || box->type == BOX_BR) {
/* inline box: add to tree and recurse */
box_add_child(*inline_container, box);
+
if (convert_children && n->children) {
for (c = n->children; c; c = c->next)
if (!convert_xml_to_box(c, content, style,
parent, inline_container,
- href, target, title,
- markup_track, author))
+ href, target, title))
return false;
+
inline_end = box_create(style, href, target, title, id,
content);
if (!inline_end)
return false;
+
inline_end->type = BOX_INLINE_END;
+
if (*inline_container)
box_add_child(*inline_container, inline_end);
else
box_add_child(box->parent, inline_end);
+
box->inline_end = inline_end;
inline_end->inline_end = box;
}
} else if (box->type == BOX_INLINE_BLOCK) {
/* inline block box: add to tree and recurse */
box_add_child(*inline_container, box);
+
inline_container_c = 0;
+
for (c = n->children; convert_children && c; c = c->next)
if (!convert_xml_to_box(c, content, style, box,
&inline_container_c,
- href, target, title, markup_track,
- author))
+ href, target, title))
return false;
} else {
/* list item: compute marker, then treat as non-inline box */
- if (style->display == CSS_DISPLAY_LIST_ITEM) {
+ if (css_computed_display(style, n->parent == NULL) ==
+ CSS_DISPLAY_LIST_ITEM) {
+ lwc_string *image_uri;
struct box *marker;
+
marker = box_create(style, 0, 0, title, 0, content);
if (!marker)
return false;
+
marker->type = BOX_BLOCK;
+
/** \todo marker content (list-style-type) */
- switch (style->list_style_type) {
+ switch (css_computed_list_style_type(style)) {
case CSS_LIST_STYLE_TYPE_DISC:
- default:
/* 2022 BULLET */
marker->text = (char *) "\342\200\242";
marker->length = 3;
@@ -489,6 +475,7 @@ bool box_construct_element(xmlNode *n, struct content *content,
case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
+ default:
if (parent->last) {
struct box *last = parent->last;
@@ -515,9 +502,11 @@ bool box_construct_element(xmlNode *n, struct content *content,
list_marker->rows + 1;
}
}
+
marker->text = talloc_array(content, char, 20);
if (!marker->text)
return false;
+
snprintf(marker->text, 20, "%u.", marker->rows);
marker->length = strlen(marker->text);
break;
@@ -526,43 +515,50 @@ bool box_construct_element(xmlNode *n, struct content *content,
marker->length = 0;
break;
}
- if (style->list_style_image.type ==
- CSS_LIST_STYLE_IMAGE_URI) {
- if (!html_fetch_object(content,
- style->list_style_image.uri,
+
+ if (css_computed_list_style_image(style, &image_uri) ==
+ CSS_LIST_STYLE_IMAGE_URI &&
+ image_uri != NULL) {
+ if (!fetch_object_interned_url(content,
+ image_uri,
marker,
0, content->available_width,
1000, false))
return false;
}
+
box->list_marker = marker;
marker->parent = box;
}
/* float: insert a float box between the parent and
* current node. Note: new parent will be the float */
- if (style->float_ == CSS_FLOAT_LEFT ||
- style->float_ == CSS_FLOAT_RIGHT) {
+ if (css_computed_float(style) == CSS_FLOAT_LEFT ||
+ css_computed_float(style) == CSS_FLOAT_RIGHT) {
parent = box_create(0, href, target, title, 0, content);
if (!parent)
return false;
- if (style->float_ == CSS_FLOAT_LEFT)
+
+ if (css_computed_float(style) == CSS_FLOAT_LEFT)
parent->type = BOX_FLOAT_LEFT;
else
parent->type = BOX_FLOAT_RIGHT;
+
box_add_child(*inline_container, parent);
}
/* non-inline box: add to tree and recurse */
box_add_child(parent, box);
+
inline_container_c = 0;
+
for (c = n->children; convert_children && c; c = c->next)
if (!convert_xml_to_box(c, content, style, box,
&inline_container_c,
- href, target, title, markup_track,
- author))
+ href, target, title))
return false;
- if (style->float_ == CSS_FLOAT_NONE)
+
+ if (css_computed_float(style) == CSS_FLOAT_NONE)
/* new inline container unless this is a float */
*inline_container = 0;
}
@@ -571,23 +567,23 @@ bool box_construct_element(xmlNode *n, struct content *content,
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "colspan"))) {
if (isdigit(s[0])) {
box->columns = strtol(s, NULL, 10);
- if ((MAX_SPAN < box->columns) || (box->columns < 1))
- box->columns = 1;
}
xmlFree(s);
}
+
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rowspan"))) {
if (isdigit(s[0])) {
box->rows = strtol(s, NULL, 10);
- if ((MAX_SPAN < box->rows) || (box->rows < 1))
- box->rows = 1;
}
xmlFree(s);
}
/* fetch any background image for this box */
- if (style->background_image.type == CSS_BACKGROUND_IMAGE_URI) {
- if (!html_fetch_object(content, style->background_image.uri,
+ if (css_computed_background_image(style, &bgimage_uri) ==
+ CSS_BACKGROUND_IMAGE_IMAGE &&
+ bgimage_uri != NULL) {
+ if (!fetch_object_interned_url(content,
+ bgimage_uri,
box, image_types, content->available_width,
1000, true))
return false;
@@ -613,7 +609,7 @@ bool box_construct_element(xmlNode *n, struct content *content,
*/
bool box_construct_text(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
char *href, const char *target, char *title)
{
@@ -625,8 +621,9 @@ bool box_construct_text(xmlNode *n, struct content *content,
assert(parent);
assert(inline_container);
- if (parent_style->white_space == CSS_WHITE_SPACE_NORMAL ||
- parent_style->white_space == CSS_WHITE_SPACE_NOWRAP) {
+ if (css_computed_white_space(parent_style) == CSS_WHITE_SPACE_NORMAL ||
+ css_computed_white_space(parent_style) ==
+ CSS_WHITE_SPACE_NOWRAP) {
char *text = squash_whitespace((char *) n->content);
if (!text)
return false;
@@ -643,10 +640,14 @@ bool box_construct_text(xmlNode *n, struct content *content,
parent = parent->parent;
box_dump(stderr, parent, 0);
}
+
assert((*inline_container)->last != 0);
+
(*inline_container)->last->space = 1;
}
+
free(text);
+
return true;
}
@@ -657,34 +658,48 @@ bool box_construct_text(xmlNode *n, struct content *content,
free(text);
return false;
}
+
(*inline_container)->type = BOX_INLINE_CONTAINER;
+
box_add_child(parent, *inline_container);
}
- box = box_create(parent_style, href, target, title, 0, content);
+ /** \todo Dropping const here is not clever */
+ box = box_create((css_computed_style *) parent_style,
+ href, target, title, 0, content);
if (!box) {
free(text);
return false;
}
+
box->type = BOX_TEXT;
+
box->text = talloc_strdup(content, text);
free(text);
if (!box->text)
return false;
+
box->length = strlen(box->text);
+
/* strip ending space char off */
if (box->length > 1 && box->text[box->length - 1] == ' ') {
box->space = 1;
box->length--;
}
- if (parent_style->text_transform != CSS_TEXT_TRANSFORM_NONE)
+
+ if (css_computed_text_transform(parent_style) !=
+ CSS_TEXT_TRANSFORM_NONE)
box_text_transform(box->text, box->length,
- parent_style->text_transform);
- if (parent_style->white_space == CSS_WHITE_SPACE_NOWRAP) {
+ css_computed_text_transform(parent_style));
+
+ if (css_computed_white_space(parent_style) ==
+ CSS_WHITE_SPACE_NOWRAP) {
unsigned int i;
+
for (i = 0; i != box->length &&
box->text[i] != ' '; ++i)
; /* no body */
+
if (i != box->length) {
/* there is a space in text block and we
* want all spaces to be converted to NBSP
@@ -699,9 +714,12 @@ bool box_construct_text(xmlNode *n, struct content *content,
}
box_add_child(*inline_container, box);
+
if (box->text[0] == ' ') {
box->length--;
+
memmove(box->text, &box->text[1], box->length);
+
if (box->prev != NULL)
box->prev->space = 1;
}
@@ -710,17 +728,22 @@ bool box_construct_text(xmlNode *n, struct content *content,
/* white-space: pre */
char *text = cnv_space2nbsp((char *) n->content);
char *current;
+ enum css_white_space white_space =
+ css_computed_white_space(parent_style);
+
/* note: pre-wrap/pre-line are unimplemented */
- assert(parent_style->white_space == CSS_WHITE_SPACE_PRE ||
- parent_style->white_space ==
- CSS_WHITE_SPACE_PRE_LINE ||
- parent_style->white_space ==
- CSS_WHITE_SPACE_PRE_WRAP);
+ assert(white_space == CSS_WHITE_SPACE_PRE ||
+ white_space == CSS_WHITE_SPACE_PRE_LINE ||
+ white_space == CSS_WHITE_SPACE_PRE_WRAP);
+
if (!text)
return false;
- if (parent_style->text_transform != CSS_TEXT_TRANSFORM_NONE)
+
+ if (css_computed_text_transform(parent_style) !=
+ CSS_TEXT_TRANSFORM_NONE)
box_text_transform(text, strlen(text),
- parent_style->text_transform);
+ css_computed_text_transform(parent_style));
+
current = text;
/* swallow a single leading new line */
@@ -739,7 +762,9 @@ bool box_construct_text(xmlNode *n, struct content *content,
do {
size_t len = strcspn(current, "\r\n");
char old = current[len];
+
current[len] = 0;
+
if (!*inline_container) {
*inline_container = box_create(0, 0, 0, 0, 0,
content);
@@ -747,26 +772,37 @@ bool box_construct_text(xmlNode *n, struct content *content,
free(text);
return false;
}
+
(*inline_container)->type =
BOX_INLINE_CONTAINER;
+
box_add_child(parent, *inline_container);
}
- box = box_create(parent_style, href, target, title, 0,
- content);
+
+ /** \todo Dropping const isn't clever */
+ box = box_create((css_computed_style *) parent_style,
+ href, target, title, 0, content);
if (!box) {
free(text);
return false;
}
+
box->type = BOX_TEXT;
+
box->text = talloc_strdup(content, current);
if (!box->text) {
free(text);
return false;
}
+
box->length = strlen(box->text);
+
box_add_child(*inline_container, box);
+
current[len] = old;
+
current += len;
+
if (current[0] == '\r' && current[1] == '\n') {
current += 2;
*inline_container = 0;
@@ -775,6 +811,7 @@ bool box_construct_text(xmlNode *n, struct content *content,
*inline_container = 0;
}
} while (*current);
+
free(text);
}
@@ -782,524 +819,69 @@ bool box_construct_text(xmlNode *n, struct content *content,
}
+static void *myrealloc(void *ptr, size_t len, void *pw)
+{
+ return talloc_realloc_size(pw, ptr, len);
+}
+
/**
* Get the style for an element.
*
* \param c content of type CONTENT_HTML that is being processed
- * \param parent_style style at this point in xml tree
+ * \param parent_style style at this point in xml tree, or NULL for root
* \param n node in xml tree
- * \param markup_track track presentation markup that affects descendents
- * \param author denotes whether current style has author level
- * importance for certain properties
- * \return the new style, or 0 on memory exhaustion
- *
- * The style is collected from three sources:
- * 1. any styles for this element in the document stylesheet(s)
- * 2. the 'style' attribute
- * 3. non-CSS HTML attributes (subject to importance of CSS style properties)
+ * \return the new style, or NULL on memory exhaustion
*/
-
-struct css_style * box_get_style(struct content *c,
- struct css_style *parent_style,
- xmlNode *n, struct markup_track *markup_track,
- struct css_importance *author)
+css_computed_style *box_get_style(struct content *c,
+ const css_computed_style *parent_style,
+ xmlNode *n)
{
char *s;
- struct css_style *style;
- struct css_style *style_new;
- char *url;
- url_func_result res;
- colour border_color = 0x888888; /* mid-grey default for tables */
-
- /* if not in a table, switch off cellpadding and cell borders
- * and record that we're not in a table */
- if (strcmp((const char *) n->name, "thead") != 0 &&
- strcmp((const char *) n->name, "tbody") != 0 &&
- strcmp((const char *) n->name, "tfoot") != 0 &&
- strcmp((const char *) n->name, "tr") != 0 &&
- strcmp((const char *) n->name, "td") != 0 &&
- strcmp((const char *) n->name, "th") != 0 &&
- strcmp((const char *) n->name, "col") != 0 &&
- strcmp((const char *) n->name, "colgroup") != 0) {
- markup_track->cell_border = false;
- markup_track->cell_padding = false;
- markup_track->table = false;
- }
-
- style = talloc_memdup(c, parent_style, sizeof *style);
- if (!style)
- return 0;
-
- style_new = talloc_memdup(c, &css_blank_style, sizeof *style_new);
- if (!style_new)
- return 0;
- css_get_style(c->data.html.working_stylesheet, n, style_new, author);
- css_cascade(style, style_new, NULL);
+ css_stylesheet *inline_style = NULL;
+ css_computed_style *partial;
+ css_computed_style *style;
- /* style_new isn't needed past this point */
- talloc_free(style_new);
-
- /* Handle style attribute. (style attribute values have high enough
- * specificity to override existing style data.) */
+ /* Firstly, construct inline stylesheet, if any */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) {
- struct css_style *astyle;
- astyle = css_duplicate_style(&css_empty_style);
- if (!astyle) {
- xmlFree(s);
- return 0;
- }
- css_parse_property_list(c, astyle, s);
- css_cascade(style, astyle, author);
- css_free_style(astyle);
- xmlFree(s);
- }
-
- /* Apply presentational HTML attributes to style
- * (Only apply if style property does not have "author" level
- * importance or higher.)
- */
-
- /* This property only applies to the body element, if you believe
- * the spec. Many browsers seem to allow it on other elements too,
- * so let's be generic ;) */
- if (!author->background_image && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "background"))) {
- res = url_join(s, c->data.html.base_url, &url);
- xmlFree(s);
- if (res == URL_FUNC_NOMEM) {
- return 0;
- } else if (res == URL_FUNC_OK) {
- /* if url is equivalent to the parent's url,
- * we've got infinite inclusion: ignore */
- if (strcmp(url, c->data.html.base_url) == 0)
- free(url);
- else {
- style->background_image.type =
- CSS_BACKGROUND_IMAGE_URI;
- style->background_image.uri = talloc_strdup(
- c, url);
- free(url);
- if (!style->background_image.uri)
- return 0;
- }
- }
- }
-
- if (!author->background_color && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "bgcolor"))) {
- parse_inline_colour(s, &style->background_color);
- xmlFree(s);
- }
-
- if (!author->color && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "color"))) {
- parse_inline_colour(s, &style->color);
- xmlFree(s);
- }
-
- if (!author->height && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "height")) &&
- ((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))) {
- float value = isdigit(s[0]) ? atof(s) : -1;
- if (value <= 0 || strlen(s) == 0) {
- /* ignore negative values and height="" */
- } else if (strrchr(s, '%')) {
- style->height.height = CSS_HEIGHT_PERCENT;
- style->height.value.percent = value;
- } else {
- style->height.height = CSS_HEIGHT_LENGTH;
- style->height.value.length.unit = CSS_UNIT_PX;
- style->height.value.length.value = value;
- }
- xmlFree(s);
- }
-
- if (!author->width && strcmp((const char *) n->name, "input") == 0) {
- int size = -1;
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "size"))) {
- size = isdigit(s[0]) ? atoi(s): -1;
- if (0 < size) {
- char *type = (char *) xmlGetProp(n,
- (const xmlChar *) "type");
- style->width.width = CSS_WIDTH_LENGTH;
- if (!type || strcasecmp(type, "text") == 0 ||
- strcasecmp(type, "password") == 0)
- /* in characters for text, password */
- style->width.value.length.unit =
- CSS_UNIT_EX;
- else if (strcasecmp(type, "file") != 0)
- /* in pixels otherwise; ignore width
- * on file, because we do them
- * differently to most browsers */
- style->width.value.length.unit =
- CSS_UNIT_PX;
- style->width.value.length.value = size;
- if (type)
- xmlFree(type);
- }
- xmlFree(s);
- }
- /* If valid maxlength value is provided, the size attribute is
- * unset and maxlength is small, use it to reduce input width
- * to sensible size */
- if ((s = (char *) xmlGetProp(n, (const xmlChar *)
- "maxlength"))) {
- int maxlength = isdigit(s[0]) ? atoi(s): -1;
- if (0 < maxlength && size == -1 && maxlength < 10) {
- char *type;
- /* Bump up really small widths */
- maxlength = maxlength < 5 ? maxlength + 1 :
- maxlength;
- type = (char *) xmlGetProp(n,
- (const xmlChar *) "type");
- style->width.width = CSS_WIDTH_LENGTH;
- if (!type || strcasecmp(type, "text") == 0 ||
- strcasecmp(type, "password") == 0)
- /* in characters for text, password */
- style->width.value.length.unit =
- CSS_UNIT_EX;
- style->width.value.length.value = maxlength;
- if (type)
- xmlFree(type);
- }
- xmlFree(s);
- }
- }
+ inline_style = nscss_create_inline_style(
+ (uint8_t *) s, strlen(s),
+ c->data.html.encoding, c->url, false,
+ c->data.html.dict, myrealloc, c);
- if (!author->color && strcmp((const char *) n->name, "body") == 0) {
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "text"))) {
- parse_inline_colour(s, &style->color);
- xmlFree(s);
- }
- }
-
- if (!author->width && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "width")) &&
- ((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))) {
- float value = isdigit(s[0]) ? atof(s) : -1;
- if (value < 0 || strlen(s) == 0) {
- /* ignore negative values and width="" */
- } else if (strrchr(s, '%')) {
- style->width.width = CSS_WIDTH_PERCENT;
- style->width.value.percent = value;
- } else {
- style->width.width = CSS_WIDTH_LENGTH;
- style->width.value.length.unit = CSS_UNIT_PX;
- style->width.value.length.value = value;
- }
xmlFree(s);
- }
-
- if (strcmp((const char *) n->name, "textarea") == 0) {
- if (!author->height && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "rows"))) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 < value) {
- style->height.height = CSS_HEIGHT_LENGTH;
- style->height.value.length.unit = CSS_UNIT_EM;
- style->height.value.length.value = value;
- }
- xmlFree(s);
- }
- if (!author->width && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "cols"))) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 < value) {
- style->width.width = CSS_WIDTH_LENGTH;
- style->width.value.length.unit = CSS_UNIT_EX;
- style->width.value.length.value = value;
- }
- xmlFree(s);
- }
- }
-
- if (strcmp((const char *) n->name, "table") == 0) {
- if (!author->border_spacing && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "cellspacing"))) {
- /* percentage cellspacing not implemented */
- if (!strrchr(s, '%')) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 <= value) {
- style->border_spacing.border_spacing =
- CSS_BORDER_SPACING_LENGTH;
- style->border_spacing.horz.unit =
- style->border_spacing.vert.unit =
- CSS_UNIT_PX;
- style->border_spacing.horz.value =
- style->border_spacing.vert.value =
- value;
- }
- }
- xmlFree(s);
- }
-
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "bordercolor"))) {
- parse_inline_colour(s, &border_color);
- xmlFree(s);
- }
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "border"))) {
- int border_width = atoi(s);
- /* precentage border width not implemented */
- if (!strrchr(s, '%') && 0 < border_width) {
- unsigned int i;
- for (i = 0; i != 4; i++) {
- if (!author->border_color[i])
- style->border[i].color =
- border_color;
- if (!author->border_width[i]) {
- style->border[i].width.width =
- CSS_BORDER_WIDTH_LENGTH;
- style->border[i].width.value.
- value = border_width;
- style->border[i].width.value.
- unit = CSS_UNIT_PX;
- }
- if (!author->border_style[i])
- style->border[i].style =
- CSS_BORDER_STYLE_OUTSET;
- }
- }
- xmlFree(s);
- }
- }
- if (strcmp((const char *) n->name, "td") == 0 ||
- strcmp((const char *) n->name, "th") == 0) {
- /* set any cellborders stipulated by associated table */
- if (markup_track->cell_border) {
- unsigned int i;
- for (i = 0; i != 4; i++) {
- if (!author->border_color[i])
- style->border[i].color = markup_track->
- border_color;
- if (!author->border_width[i]) {
- style->border[i].width.width =
- CSS_BORDER_WIDTH_LENGTH;
- style->border[i].width.value.value = 1;
- style->border[i].width.value.unit =
- CSS_UNIT_PX;
- }
- if (!author->border_style[i])
- style->border[i].style =
- CSS_BORDER_STYLE_INSET;
- }
- }
- /* set any cellpadding stipulated by associated table */
- if (markup_track->cell_padding) {
- unsigned int i;
- for (i = 0; i != 4; i++) {
- if (!author->padding[i]) {
- style->padding[i].padding =
- CSS_PADDING_LENGTH;
- style->padding[i].value.length.value =
- markup_track->padding_width;
- style->padding[i].value.length.unit =
- CSS_UNIT_PX;
- }
- }
- }
+ if (inline_style == NULL)
+ return NULL;
}
- if ((strcmp((const char *) n->name, "img") == 0) ||
- (strcmp((const char *) n->name, "image") == 0) ||
- (strcmp((const char *) n->name, "applet") == 0)) {
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "hspace"))) {
- /* percentage hspace not implemented */
- if (!strrchr(s, '%')) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 <= value && !author->margin[LEFT]) {
- style->margin[LEFT].margin =
- CSS_MARGIN_LENGTH;
- style->margin[LEFT].value.length.value =
- value;
- style->margin[LEFT].value.length.unit =
- CSS_UNIT_PX;
- }
- if (0 <= value && !author->margin[RIGHT]) {
- style->margin[RIGHT].margin =
- CSS_MARGIN_LENGTH;
- style->margin[RIGHT].value.length.
- value = value;
- style->margin[RIGHT].value.length.unit =
- CSS_UNIT_PX;
- }
- }
- xmlFree(s);
- }
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "vspace"))) {
- /* percentage vspace not implemented */
- if (!strrchr(s, '%')) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 <= value && !author->margin[TOP]) {
- style->margin[TOP].margin =
- CSS_MARGIN_LENGTH;
- style->margin[TOP].value.length.value =
- value;
- style->margin[TOP].value.length.unit =
- CSS_UNIT_PX;
- }
- if (0 <= value && !author->margin[BOTTOM]) {
- style->margin[BOTTOM].margin =
- CSS_MARGIN_LENGTH;
- style->margin[BOTTOM].value.length.
- value = value;
- style->margin[BOTTOM].value.length.
- unit = CSS_UNIT_PX;
- }
- }
- xmlFree(s);
- }
- }
+ /* Select partial style for element */
+ partial = nscss_get_style(c, n, CSS_PSEUDO_ELEMENT_NONE,
+ CSS_MEDIA_SCREEN, inline_style, myrealloc, c);
- /* Handle markup-originating alignment of block level elements.
- * Adjust left and right margins. text-align property is handled in
- * the default CSS file.
- */
- if (markup_track->align != ALIGN_NONE &&
- (style->display == CSS_DISPLAY_BLOCK ||
- style->display == CSS_DISPLAY_TABLE) &&
- (strcmp((const char *) n->name, "blockquote") != 0)) {
- if (!author->margin[LEFT]) {
- if (markup_track->align == ALIGN_LEFT) {
- /* left */
- style->margin[LEFT].margin = CSS_MARGIN_LENGTH;
- style->margin[LEFT].value.length.value = 0;
- style->margin[LEFT].value.length.unit =
- CSS_UNIT_PX;
- } else
- /* center or right */
- style->margin[LEFT].margin = CSS_MARGIN_AUTO;
- }
-
- if (!author->margin[RIGHT]) {
- if (markup_track->align == ALIGN_RIGHT) {
- /* right */
- style->margin[RIGHT].margin = CSS_MARGIN_LENGTH;
- style->margin[RIGHT].value.length.value= 0;
- style->margin[RIGHT].value.length.unit =
- CSS_UNIT_PX;
- } else
- /* left or center */
- style->margin[RIGHT].margin = CSS_MARGIN_AUTO;
- }
- if (author->margin[LEFT] || author->margin[RIGHT]) {
- /* author stylesheet sets a margin so stop markup
- * alignment model propagation */
- markup_track->align = ALIGN_NONE;
- }
- }
- /* Centered tables are a special case. The align attribute only
- * affects the current element (table) and overrides any existing
- * HTML alignment rule. Tables aligned to left or right are floated
- * by the default CSS file. */
- if (!author->margin[LEFT] && !author->margin[RIGHT] &&
- strcmp((const char *) n->name, "table") == 0) {
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "align"))) {
- if (strcasecmp(s, "center") == 0) {
- style->margin[LEFT].margin = CSS_MARGIN_AUTO;
- style->margin[RIGHT].margin = CSS_MARGIN_AUTO;
- }
- xmlFree(s);
- }
- }
+ /* No longer need inline style */
+ if (inline_style != NULL)
+ css_stylesheet_destroy(inline_style);
- box_solve_display(style, !n->parent);
+ /* Failed selecting partial style -- bail out */
+ if (partial == NULL)
+ return NULL;
- /* Update markup_track with attributes which affect children of
- * current box. */
+ /* If there's a parent style, compose with partial to obtain
+ * complete computed style for element */
+ if (parent_style != NULL) {
+ css_error error;
- /* Handle html block level element alignment model.
- * Note that only margins of block level children are considered,
- * text-align for the current block can be handled in the default
- * CSS file.
- */
- if (strcmp((const char *) n->name, "center") == 0)
- markup_track->align = ALIGN_CENTER;
- else if (strcmp((const char *) n->name, "div") == 0 ||
- strcmp((const char *) n->name, "col") == 0 ||
- strcmp((const char *) n->name, "colgroup") == 0 ||
- strcmp((const char *) n->name, "tbody") == 0 ||
- strcmp((const char *) n->name, "td") == 0 ||
- strcmp((const char *) n->name, "tfoot") == 0 ||
- strcmp((const char *) n->name, "th") == 0 ||
- strcmp((const char *) n->name, "thead") == 0 ||
- strcmp((const char *) n->name, "tr") == 0) {
-
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "align"))) {
- if (strcasecmp(s, "center") == 0)
- markup_track->align = ALIGN_CENTER;
- else if (strcasecmp(s, "right") == 0)
- markup_track->align = ALIGN_RIGHT;
- else if (strcasecmp(s, "left") == 0)
- markup_track->align = ALIGN_LEFT;
- xmlFree(s);
- /* Need to remember if we're in a table, so that any
- * alignment rules set on the table's elements won't
- * get overridden by the default alignment of a cell
- * with no align attribute. At this point, we're in a
- * table if the element isn't a div */
- if (strcmp((const char *) n->name, "div") != 0)
- markup_track->table = true;
+ error = css_computed_style_compose(parent_style, partial,
+ nscss_compute_font_size, NULL, partial);
+ if (error != CSS_OK) {
+ css_computed_style_destroy(partial);
+ return NULL;
}
- }
- /* Table cells without an align value have a default implied
- * alignment. */
- if (strcmp((const char *) n->name, "td") == 0 && !markup_track->table) {
- if (!(s = (char *) xmlGetProp(n, (const xmlChar *) "align")))
- markup_track->align = ALIGN_LEFT;
- else
- xmlFree(s);
- }
- if (strcmp((const char *) n->name, "th") == 0 && !markup_track->table) {
- if (!(s = (char *) xmlGetProp(n, (const xmlChar *) "align")))
- markup_track->align = ALIGN_CENTER;
- else
- xmlFree(s);
- }
- /* Some of TABLE's attributes apply to the table cells contained
- * within the table. Those details are stored so they may be applied
- * to the cells when we get to them. */
- if (strcmp((const char *) n->name, "table") == 0) {
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "cellpadding"))) {
- char *endp;
- long value = strtol(s, &endp, 10);
- /* precentage padding width not implemented */
- if (*endp == 0 && 0 <= value && value < 1000) {
- markup_track->padding_width = value;
- markup_track->cell_padding = true;
- }
- xmlFree(s);
- }
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "border"))) {
- int border_width = atoi(s);
- markup_track->border_color = border_color;
- /* percentage border width not implemented */
- if (!strrchr(s, '%') && 0 < border_width) {
- markup_track->cell_border = true;
- }
- xmlFree(s);
- }
+ style = partial;
+ } else {
+ /* No parent style, so partial must be fully computed */
+ style = partial;
}
return style;
@@ -1307,52 +889,6 @@ struct css_style * box_get_style(struct content *c,
/**
- * Calculate 'display' based on 'display', 'position', and 'float', as given
- * by CSS 2.1 9.7.
- *
- * \param style style to update
- * \param root this is the root element
- */
-
-void box_solve_display(struct css_style *style, bool root)
-{
- if (style->display == CSS_DISPLAY_NONE) /* 1. */
- return;
- else if (style->position == CSS_POSITION_ABSOLUTE ||
- style->position == CSS_POSITION_FIXED) /* 2. */
- style->float_ = CSS_FLOAT_NONE;
- else if (style->float_ != CSS_FLOAT_NONE) /* 3. */
- ;
- else if (root) /* 4. */
- ;
- else /* 5. */
- return;
-
- /* Special case for absolute positioning: make absolute inlines into
- * inline block so that the boxes are constructed in an inline container
- * as if they were not absolutely positioned. Layout expects and
- * handles this. */
- if ((style->position == CSS_POSITION_ABSOLUTE ||
- style->position == CSS_POSITION_FIXED) &&
- (style->display == CSS_DISPLAY_INLINE ||
- style->display == CSS_DISPLAY_INLINE_BLOCK ||
- style->display == CSS_DISPLAY_INLINE_TABLE)) {
- style->display = CSS_DISPLAY_INLINE_BLOCK;
- return;
- }
-
- /* map specified value to computed value using table given in 9.7 */
- if (style->display == CSS_DISPLAY_INLINE_TABLE)
- style->display = CSS_DISPLAY_TABLE;
- else if (style->display == CSS_DISPLAY_LIST_ITEM ||
- style->display == CSS_DISPLAY_TABLE)
- ; /* same as specified */
- else
- style->display = CSS_DISPLAY_BLOCK;
-}
-
-
-/**
* Apply the CSS text-transform property to given text for its ASCII chars.
*
* \param s string to transform
@@ -1360,8 +896,7 @@ void box_solve_display(struct css_style *style, bool root)
* \param tt transform type
*/
-void box_text_transform(char *s, unsigned int len,
- css_text_transform tt)
+void box_text_transform(char *s, unsigned int len, enum css_text_transform tt)
{
unsigned int i;
if (len == 0)
@@ -1416,7 +951,15 @@ void box_text_transform(char *s, unsigned int len,
bool box_body(BOX_SPECIAL_PARAMS)
{
- content->data.html.background_colour = box->style->background_color;
+ enum css_background_color type;
+ css_color color;
+
+ type = css_computed_background_color(box->style, &color);
+ if (type == CSS_BACKGROUND_COLOR_TRANSPARENT)
+ content->data.html.background_colour = NS_TRANSPARENT;
+ else
+ content->data.html.background_colour = nscss_color_to_ns(color);
+
return true;
}
@@ -1507,7 +1050,8 @@ bool box_image(BOX_SPECIAL_PARAMS)
char *s, *url;
xmlChar *alt, *src;
- if (box->style && box->style->display == CSS_DISPLAY_NONE)
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE)
return true;
/* handle alt text */
@@ -1558,7 +1102,8 @@ bool box_object(BOX_SPECIAL_PARAMS)
xmlNode *c;
struct box *inline_container = 0;
- if (box->style && box->style->display == CSS_DISPLAY_NONE)
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE)
return true;
if (!box_get_attribute(n, "usemap", content, &box->usemap))
@@ -1685,8 +1230,7 @@ bool box_object(BOX_SPECIAL_PARAMS)
/* convert children and place into fallback */
for (c = n->children; c; c = c->next) {
if (!convert_xml_to_box(c, content, box->style, box,
- &inline_container, 0, 0, 0, markup_track,
- author))
+ &inline_container, 0, 0, 0))
return false;
}
box->fallback = box->children;
@@ -1849,7 +1393,7 @@ bool box_frameset(BOX_SPECIAL_PARAMS)
if (convert_children)
*convert_children = false;
/* And ignore this spurious frameset */
- box->style->display = CSS_DISPLAY_NONE;
+ box->type = BOX_NONE;
return true;
}
@@ -1860,7 +1404,7 @@ bool box_frameset(BOX_SPECIAL_PARAMS)
ok = box_create_frameset(content->data.html.frameset, n, content);
if (ok)
- box->style->display = CSS_DISPLAY_NONE;
+ box->type = BOX_NONE;
if (convert_children)
*convert_children = false;
@@ -1920,7 +1464,11 @@ bool box_create_frameset(struct content_html_frames *f, xmlNode *n,
/* common extension: bordercolor="#RRGGBB|<named colour>" to control
*all children */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bordercolor"))) {
- parse_inline_colour(s, &default_border_colour);
+ css_color color;
+
+ if (nscss_parse_colour((const char *) s, &color))
+ default_border_colour = nscss_color_to_ns(color);
+
xmlFree(s);
}
@@ -2030,7 +1578,13 @@ bool box_create_frameset(struct content_html_frames *f, xmlNode *n,
}
if ((s = (char *) xmlGetProp(c, (const xmlChar *)
"bordercolor"))) {
- parse_inline_colour(s, &frame->border_colour);
+ css_color color;
+
+ if (nscss_parse_colour((const char *) s,
+ &color))
+ frame->border_colour =
+ nscss_color_to_ns(color);
+
xmlFree(s);
}
@@ -2100,7 +1654,11 @@ bool box_iframe(BOX_SPECIAL_PARAMS)
xmlFree(s);
}
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bordercolor"))) {
- parse_inline_colour(s, &iframe->border_colour);
+ css_color color;
+
+ if (nscss_parse_colour(s, &color))
+ iframe->border_colour = nscss_color_to_ns(color);
+
xmlFree(s);
}
if ((s = (char *) xmlGetProp(n,
@@ -2155,31 +1713,36 @@ bool box_input(BOX_SPECIAL_PARAMS)
gadget->box = box;
if (type && strcasecmp(type, "password") == 0) {
- if (!box_input_text(n, content, box, 0, markup_track, author,
- true))
+ if (!box_input_text(n, content, box, 0, true))
goto no_memory;
} else if (type && strcasecmp(type, "file") == 0) {
box->type = BOX_INLINE_BLOCK;
} else if (type && strcasecmp(type, "hidden") == 0) {
/* no box for hidden inputs */
- box->style->display = CSS_DISPLAY_NONE;
+ box->type = BOX_NONE;
} else if (type && (strcasecmp(type, "checkbox") == 0 ||
strcasecmp(type, "radio") == 0)) {
} else if (type && (strcasecmp(type, "submit") == 0 ||
strcasecmp(type, "reset") == 0 ||
strcasecmp(type, "button") == 0)) {
struct box *inline_container, *inline_box;
- if (!box_button(n, content, box, 0, markup_track, author))
+
+ if (!box_button(n, content, box, 0))
goto no_memory;
+
inline_container = box_create(0, 0, 0, 0, 0, content);
if (!inline_container)
goto no_memory;
+
inline_container->type = BOX_INLINE_CONTAINER;
+
inline_box = box_create(box->style, 0, 0, box->title, 0,
content);
if (!inline_box)
goto no_memory;
+
inline_box->type = BOX_TEXT;
+
if (box->gadget->value != NULL)
inline_box->text = talloc_strdup(content,
box->gadget->value);
@@ -2191,15 +1754,20 @@ bool box_input(BOX_SPECIAL_PARAMS)
messages_get("Form_Reset"));
else
inline_box->text = talloc_strdup(content, "Button");
+
if (!inline_box->text)
goto no_memory;
+
inline_box->length = strlen(inline_box->text);
+
box_add_child(inline_container, inline_box);
+
box_add_child(box, inline_container);
} else if (type && strcasecmp(type, "image") == 0) {
gadget->type = GADGET_IMAGE;
- if (box->style && box->style->display != CSS_DISPLAY_NONE) {
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) != CSS_DISPLAY_NONE) {
if ((s = (char *) xmlGetProp(n,
(const xmlChar*) "src"))) {
res = url_join(s,
@@ -2227,8 +1795,7 @@ bool box_input(BOX_SPECIAL_PARAMS)
}
} else {
/* the default type is "text" */
- if (!box_input_text(n, content, box, 0, markup_track, author,
- false))
+ if (!box_input_text(n, content, box, 0, false))
goto no_memory;
}
@@ -2582,7 +2149,8 @@ bool box_embed(BOX_SPECIAL_PARAMS)
xmlChar *src;
xmlAttr *a;
- if (box->style && box->style->display == CSS_DISPLAY_NONE)
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE)
return true;
params = talloc(content, struct object_params);
@@ -2790,18 +2358,39 @@ struct frame_dimension *box_parse_multi_lengths(const char *s,
return length;
}
-
/**
- * Parse an inline colour string
+ * Fetch an object from an interned URL
+ *
+ * \param c Current content
+ * \param url URL to fetch
+ * \param box Box containing object
+ * \param permitted_types Array of permitted types terminated by
+ * CONTENT_UNKNOWN, or NULL for all types
+ * \param available_width Estimate of width of object
+ * \param available_height Estimate of height of object
+ * \param background This object forms the box background
+ * \return true on success, false on memory exhaustion
*/
-static void parse_inline_colour(char *s, colour *variable) {
- colour new_colour = CSS_COLOR_NONE;
- if (s[0] == '#') {
- if (strlen(s) == 7)
- new_colour = hex_colour(s + 1, 6);
- } else {
- new_colour = named_colour(s);
- }
- if (new_colour != CSS_COLOR_NONE)
- *variable = new_colour;
+bool fetch_object_interned_url(struct content *c, lwc_string *url,
+ struct box *box, const content_type *permitted_types,
+ int available_width, int available_height,
+ bool background)
+{
+ char *url_buf;
+ bool ret = true;
+
+ url_buf = malloc(lwc_string_length(url) + 1);
+ if (url_buf == NULL)
+ return false;
+
+ memcpy(url_buf, lwc_string_data(url), lwc_string_length(url));
+ url_buf[lwc_string_length(url)] = '\0';
+
+ ret = html_fetch_object(c, url_buf, box, permitted_types,
+ available_width, available_height, background);
+
+ free(url_buf);
+
+ return ret;
}
+
diff --git a/render/box_normalise.c b/render/box_normalise.c
index 865433e26..fc563e743 100644
--- a/render/box_normalise.c
+++ b/render/box_normalise.c
@@ -26,6 +26,7 @@
#include <assert.h>
#include <stdbool.h>
#include "css/css.h"
+#include "css/select.h"
#include "render/box.h"
#include "render/table.h"
#include "desktop/gui.h"
@@ -35,29 +36,34 @@
#include "utils/talloc.h"
+/**
+ * Row spanning information for a cell
+ */
struct span_info {
+ /** Number of rows this cell spans */
unsigned int row_span;
+ /** The cell in this column spans all rows until the end of the table */
bool auto_row;
- bool auto_column;
};
+/**
+ * Column record for a table
+ */
struct columns {
+ /** Current column index */
unsigned int current_column;
- bool extra;
- /* Number of columns in main part of table 1..max columns */
+ /** Number of columns in main part of table 1..max columns */
unsigned int num_columns;
- /* Information about columns in main table,
- array 0 to num_columns - 1 */
+ /** Information about columns in main table, array [0, num_columns) */
struct span_info *spans;
- /* Number of columns that have cells after a colspan 0 */
- unsigned int extra_columns;
- /* Number of rows in table */
+ /** Number of rows in table */
unsigned int num_rows;
};
static bool box_normalise_table(struct box *table, struct content *c);
-static void box_normalise_table_spans(struct box *table);
+static bool box_normalise_table_spans(struct box *table,
+ struct span_info *spans, struct content *c);
static bool box_normalise_table_row_group(struct box *row_group,
struct columns *col_info,
struct content *c);
@@ -69,6 +75,18 @@ static bool calculate_table_row(struct columns *col_info,
unsigned int *start_column);
static bool box_normalise_inline_container(struct box *cont, struct content *c);
+/**
+ * Allocator
+ *
+ * \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
+ */
+static void *myrealloc(void *ptr, size_t len, void *pw)
+{
+ return talloc_realloc_size(pw, ptr, len);
+}
/**
* Ensure the box tree is correctly nested by adding and removing nodes.
@@ -96,30 +114,34 @@ bool box_normalise_block(struct box *block, struct content *c)
struct box *child;
struct box *next_child;
struct box *table;
- struct css_style *style;
+ css_computed_style *style;
+
+ assert(block != NULL);
- assert(block != 0);
LOG(("block %p, block->type %u", block, block->type));
+
assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
block->type == BOX_TABLE_CELL);
+
gui_multitask();
- for (child = block->children; child != 0; child = next_child) {
+ for (child = block->children; child != NULL; child = next_child) {
LOG(("child %p, child->type = %d", child, child->type));
+
next_child = child->next; /* child may be destroyed */
+
switch (child->type) {
case BOX_BLOCK:
/* ok */
- if (!box_normalise_block(child, c))
+ if (box_normalise_block(child, c) == false)
return false;
break;
case BOX_INLINE_CONTAINER:
- if (!box_normalise_inline_container(child,
- c))
+ if (box_normalise_inline_container(child, c) == false)
return false;
break;
case BOX_TABLE:
- if (!box_normalise_table(child, c))
+ if (box_normalise_table(child, c) == false)
return false;
break;
case BOX_INLINE:
@@ -137,37 +159,48 @@ bool box_normalise_block(struct box *block, struct content *c)
case BOX_TABLE_ROW:
case BOX_TABLE_CELL:
/* insert implied table */
- style = talloc_memdup(c, block->style, sizeof *style);
- if (!style)
+ assert(block->style != NULL);
+
+ style = nscss_get_blank_style(c, block->style,
+ myrealloc, c);
+ if (style == NULL)
return false;
- css_cascade(style, &css_blank_style, NULL);
+
table = box_create(style, block->href, block->target,
- 0, 0, c);
- if (!table) {
- talloc_free(style);
+ NULL, NULL, c);
+ if (table == NULL) {
+ css_computed_style_destroy(style);
return false;
}
table->type = BOX_TABLE;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
block->children = table;
else
child->prev->next = table;
+
table->prev = child->prev;
- while (child != 0 && (
+
+ while (child != NULL && (
child->type == BOX_TABLE_ROW_GROUP ||
child->type == BOX_TABLE_ROW ||
child->type == BOX_TABLE_CELL)) {
box_add_child(table, child);
+
next_child = child->next;
- child->next = 0;
+ child->next = NULL;
child = next_child;
}
- table->last->next = 0;
+
+ table->last->next = NULL;
table->next = next_child = child;
- if (table->next)
+ if (table->next != NULL)
table->next->prev = table;
+ else
+ block->last = table;
table->parent = block;
- if (!box_normalise_table(table, c))
+
+ if (box_normalise_table(table, c) == false)
return false;
break;
default:
@@ -184,30 +217,32 @@ bool box_normalise_table(struct box *table, struct content * c)
struct box *child;
struct box *next_child;
struct box *row_group;
- struct css_style *style;
+ css_computed_style *style;
struct columns col_info;
- assert(table != 0);
+ assert(table != NULL);
assert(table->type == BOX_TABLE);
+
LOG(("table %p", table));
+
col_info.num_columns = 1;
col_info.current_column = 0;
col_info.spans = malloc(2 * sizeof *col_info.spans);
- if (!col_info.spans)
+ if (col_info.spans == NULL)
return false;
+
col_info.spans[0].row_span = col_info.spans[1].row_span = 0;
- col_info.spans[0].auto_row = col_info.spans[0].auto_column =
- col_info.spans[1].auto_row = col_info.spans[1].auto_column = false;
- col_info.num_rows = col_info.extra_columns = 0;
- col_info.extra = false;
+ col_info.spans[0].auto_row = false;
+ col_info.spans[1].auto_row = false;
+ col_info.num_rows = 0;
- for (child = table->children; child != 0; child = next_child) {
+ for (child = table->children; child != NULL; child = next_child) {
next_child = child->next;
switch (child->type) {
case BOX_TABLE_ROW_GROUP:
/* ok */
- if (!box_normalise_table_row_group(child,
- &col_info, c)) {
+ if (box_normalise_table_row_group(child,
+ &col_info, c) == false) {
free(col_info.spans);
return false;
}
@@ -219,46 +254,56 @@ bool box_normalise_table(struct box *table, struct content * c)
case BOX_TABLE_CELL:
/* insert implied table row group */
assert(table->style != NULL);
- style = talloc_memdup(c, table->style, sizeof *style);
- if (!style) {
+
+ style = nscss_get_blank_style(c, table->style,
+ myrealloc, c);
+ if (style == NULL) {
free(col_info.spans);
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row_group = box_create(style, table->href,
- table->target, 0, 0, c);
- if (!row_group) {
+ table->target, NULL, NULL, c);
+ if (row_group == NULL) {
+ css_computed_style_destroy(style);
free(col_info.spans);
- talloc_free(style);
return false;
}
+
row_group->type = BOX_TABLE_ROW_GROUP;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
table->children = row_group;
else
child->prev->next = row_group;
+
row_group->prev = child->prev;
- while (child != 0 && (
+
+ while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
child->type == BOX_TABLE_ROW ||
child->type == BOX_TABLE_CELL)) {
box_add_child(row_group, child);
+
next_child = child->next;
- child->next = 0;
+ child->next = NULL;
child = next_child;
}
+
assert(row_group->last != NULL);
- row_group->last->next = 0;
+
+ row_group->last->next = NULL;
row_group->next = next_child = child;
- if (row_group->next)
+ if (row_group->next != NULL)
row_group->next->prev = row_group;
else
table->last = row_group;
row_group->parent = table;
- if (!box_normalise_table_row_group(row_group,
- &col_info, c)) {
+
+ if (box_normalise_table_row_group(row_group,
+ &col_info, c) == false) {
free(col_info.spans);
return false;
}
@@ -282,38 +327,43 @@ bool box_normalise_table(struct box *table, struct content * c)
table->columns = col_info.num_columns;
table->rows = col_info.num_rows;
- free(col_info.spans);
- if (table->children == 0) {
+ if (table->children == NULL) {
struct box *row;
LOG(("table->children == 0, creating implied row"));
assert(table->style != NULL);
- style = talloc_memdup(c, table->style, sizeof *style);
- if (!style) {
+
+ style = nscss_get_blank_style(c, table->style, myrealloc, c);
+ if (style == NULL) {
+ free(col_info.spans);
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row_group = box_create(style, table->href,
- table->target, 0, 0, c);
- if (!row_group) {
- talloc_free(style);
+ table->target, NULL, NULL, c);
+ if (row_group == NULL) {
+ css_computed_style_destroy(style);
+ free(col_info.spans);
return false;
}
row_group->type = BOX_TABLE_ROW_GROUP;
- style = talloc_memdup(c, row_group->style, sizeof *style);
- if (!style) {
+ style = nscss_get_blank_style(c, row_group->style,
+ myrealloc, c);
+ if (style == NULL) {
box_free(row_group);
+ free(col_info.spans);
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row = box_create(style, row_group->href,
- row_group->target, 0, 0, c);
- if (!row) {
- talloc_free(style);
+ row_group->target, NULL, NULL, c);
+ if (row == NULL) {
+ css_computed_style_destroy(style);
box_free(row_group);
+ free(col_info.spans);
return false;
}
row->type = BOX_TABLE_ROW;
@@ -327,11 +377,15 @@ bool box_normalise_table(struct box *table, struct content * c)
table->rows = 1;
}
- box_normalise_table_spans(table);
- if (!table_calculate_column_types(table))
+ if (box_normalise_table_spans(table, col_info.spans, c) == false) {
+ free(col_info.spans);
+ return false;
+ }
+
+ free(col_info.spans);
+
+ if (table_calculate_column_types(table) == false)
return false;
- if (table->style->border_collapse == CSS_BORDER_COLLAPSE_COLLAPSE)
- table_collapse_borders(table);
LOG(("table %p done", table));
@@ -339,62 +393,141 @@ bool box_normalise_table(struct box *table, struct content * c)
}
-void box_normalise_table_spans(struct box *table)
+/**
+ * Normalise table cell column/row counts for colspan/rowspan = 0.
+ * Additionally, generate empty cells.
+ *
+ * \param table Table to process
+ * \param spans Array of length table->columns for use in empty cell detection
+ * \param c Content containing table
+ * \return True on success, false on memory exhaustion.
+ */
+
+bool box_normalise_table_spans(struct box *table, struct span_info *spans,
+ struct content *c)
{
struct box *table_row_group;
struct box *table_row;
struct box *table_cell;
- unsigned int last_column;
- unsigned int max_extra = 0;
- bool extra;
- bool force = false;
unsigned int rows_left = table->rows;
+ unsigned int col;
+
+ /* Clear span data */
+ memset(spans, 0, table->columns * sizeof(struct span_info));
- /* Scan table filling in table the width and height of table cells for
- cells with colspan = 0 or rowspan = 0. Ignore the colspan and
- rowspan of any cells that that follow an colspan = 0 */
+ /* Scan table, filling in width and height of table cells with
+ * colspan = 0 and rowspan = 0. Also generate empty cells */
for (table_row_group = table->children; table_row_group != NULL;
- table_row_group = table_row_group->next) {
- for (table_row = table_row_group->children; NULL != table_row;
+ table_row_group = table_row_group->next) {
+ for (table_row = table_row_group->children; table_row != NULL;
table_row = table_row->next){
- last_column = 0;
- extra = false;
- for (table_cell = table_row->children; NULL != table_cell;
+ for (table_cell = table_row->children;
+ table_cell != NULL;
table_cell = table_cell->next) {
- /* We hae reached the end of the row, and have passed
- a cell with colspan = 0 so ignore col and row spans */
- if (force || extra || (table_cell->start_column + 1 <=
- last_column)) {
- extra = true;
+ /* colspan = 0 -> colspan = 1 */
+ if (table_cell->columns == 0)
table_cell->columns = 1;
- table_cell->rows = 1;
- if (table_cell->start_column <= max_extra) {
- max_extra = table_cell->start_column + 1;
+
+ /* rowspan = 0 -> rowspan = rows_left */
+ if (table_cell->rows == 0)
+ table_cell->rows = rows_left;
+
+ /* Record span information */
+ for (col = table_cell->start_column;
+ col < table_cell->start_column +
+ table_cell->columns; col++) {
+ spans[col].row_span = table_cell->rows;
+ }
+ }
+
+ /* Reduce span count of each column */
+ for (col = 0; col < table->columns; col++) {
+ if (spans[col].row_span == 0) {
+ unsigned int start = col;
+ css_computed_style *style;
+ struct box *cell, *prev;
+
+ /* If it's already zero, then we need
+ * to generate an empty cell for the
+ * gap in the row that spans as many
+ * columns as remain blank.
+ */
+ assert(table_row->style != NULL);
+
+ /* Find width of gap */
+ while (col < table->columns &&
+ spans[col].row_span ==
+ 0) {
+ col++;
}
- table_cell->start_column += table->columns;
- } else {
- /* Fill out the number of columns or the number of rows
- if necessary */
- if (0 == table_cell->columns) {
- table_cell->columns = table->columns -
- table_cell->start_column;
- if ((0 == table_cell->start_column) &&
- (0 == table_cell->rows)) {
- force = true;
- }
+
+ style = nscss_get_blank_style(c,
+ table_row->style,
+ myrealloc, c);
+ if (style == NULL)
+ return false;
+
+ cell = box_create(style,
+ table_row->href,
+ table_row->target,
+ NULL, NULL, c);
+ if (cell == NULL) {
+ css_computed_style_destroy(
+ style);
+ return false;
}
- assert(0 != table_cell->columns);
- if (0 == table_cell->rows) {
- table_cell->rows = rows_left;
+ cell->type = BOX_TABLE_CELL;
+
+ cell->rows = 1;
+ cell->columns = col - start;
+ cell->start_column = start;
+
+ /* Find place to insert cell */
+ for (prev = table_row->children;
+ prev != NULL;
+ prev = prev->next) {
+ if (prev->start_column +
+ prev->columns ==
+ start)
+ break;
+ if (prev->next == NULL)
+ break;
}
- assert(0 != table_cell->rows);
- last_column = table_cell->start_column + 1;
+
+ /* Insert it */
+ if (prev == NULL) {
+ if (table_row->children != NULL)
+ table_row->children->
+ prev = cell;
+ else
+ table_row->last = cell;
+
+ cell->next =
+ table_row->children;
+ table_row->children = cell;
+ } else {
+ if (prev->next != NULL)
+ prev->next->prev = cell;
+ else
+ table_row->last = cell;
+
+ cell->next = prev->next;
+ prev->next = cell;
+ cell->prev = prev;
+ }
+ cell->parent = table_row;
+ } else {
+ spans[col].row_span--;
}
}
+
+ assert(rows_left > 0);
+
rows_left--;
}
}
- table->columns += max_extra;
+
+ return true;
}
@@ -405,19 +538,21 @@ bool box_normalise_table_row_group(struct box *row_group,
struct box *child;
struct box *next_child;
struct box *row;
- struct css_style *style;
+ css_computed_style *style;
assert(row_group != 0);
assert(row_group->type == BOX_TABLE_ROW_GROUP);
+
LOG(("row_group %p", row_group));
- for (child = row_group->children; child != 0; child = next_child) {
+ for (child = row_group->children; child != NULL; child = next_child) {
next_child = child->next;
+
switch (child->type) {
case BOX_TABLE_ROW:
/* ok */
- if (!box_normalise_table_row(child, col_info,
- c))
+ if (box_normalise_table_row(child, col_info,
+ c) == false)
return false;
break;
case BOX_BLOCK:
@@ -427,44 +562,52 @@ bool box_normalise_table_row_group(struct box *row_group,
case BOX_TABLE_CELL:
/* insert implied table row */
assert(row_group->style != NULL);
- style = talloc_memdup(c, row_group->style,
- sizeof *style);
- if (!style)
+
+ style = nscss_get_blank_style(c, row_group->style,
+ myrealloc, c);
+ if (style == NULL)
return false;
- css_cascade(style, &css_blank_style, NULL);
+
row = box_create(style, row_group->href,
- row_group->target, 0, 0, c);
- if (!row) {
- talloc_free(style);
+ row_group->target, NULL, NULL, c);
+ if (row == NULL) {
+ css_computed_style_destroy(style);
return false;
}
row->type = BOX_TABLE_ROW;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
row_group->children = row;
else
child->prev->next = row;
+
row->prev = child->prev;
- while (child != 0 && (
+
+ while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
child->type == BOX_TABLE_ROW_GROUP ||
child->type == BOX_TABLE_CELL)) {
box_add_child(row, child);
+
next_child = child->next;
- child->next = 0;
+ child->next = NULL;
child = next_child;
}
+
assert(row->last != NULL);
- row->last->next = 0;
+
+ row->last->next = NULL;
row->next = next_child = child;
- if (row->next)
+ if (row->next != NULL)
row->next->prev = row;
else
row_group->last = row;
row->parent = row_group;
- if (!box_normalise_table_row(row, col_info,
- c))
+
+ if (box_normalise_table_row(row, col_info,
+ c) == false)
return false;
break;
case BOX_INLINE:
@@ -483,24 +626,30 @@ bool box_normalise_table_row_group(struct box *row_group,
}
}
- if (row_group->children == 0) {
+ if (row_group->children == NULL) {
LOG(("row_group->children == 0, inserting implied row"));
+
assert(row_group->style != NULL);
- style = talloc_memdup(c, row_group->style, sizeof *style);
- if (!style) {
+
+ style = nscss_get_blank_style(c, row_group->style,
+ myrealloc, c);
+ if (style == NULL) {
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row = box_create(style, row_group->href,
- row_group->target, 0, 0, c);
- if (!row) {
- talloc_free(style);
+ row_group->target, NULL, NULL, c);
+ if (row == NULL) {
+ css_computed_style_destroy(style);
return false;
}
row->type = BOX_TABLE_ROW;
row->parent = row_group;
row_group->children = row_group->last = row;
+
+ /* Keep table's row count in sync */
+ col_info->num_rows++;
}
LOG(("row_group %p done", row_group));
@@ -516,19 +665,20 @@ bool box_normalise_table_row(struct box *row,
struct box *child;
struct box *next_child;
struct box *cell = NULL;
- struct css_style *style;
+ css_computed_style *style;
unsigned int i;
- assert(row != 0);
+ assert(row != NULL);
assert(row->type == BOX_TABLE_ROW);
LOG(("row %p", row));
- for (child = row->children; child != 0; child = next_child) {
+ for (child = row->children; child != NULL; child = next_child) {
next_child = child->next;
+
switch (child->type) {
case BOX_TABLE_CELL:
/* ok */
- if (!box_normalise_block(child, c))
+ if (box_normalise_block(child, c) == false)
return false;
cell = child;
break;
@@ -539,46 +689,51 @@ bool box_normalise_table_row(struct box *row,
case BOX_TABLE_ROW:
/* insert implied table cell */
assert(row->style != NULL);
- style = talloc_memdup(c, row->style, sizeof *style);
- if (!style)
+
+ style = nscss_get_blank_style(c, row->style,
+ myrealloc, c);
+ if (style == NULL)
return false;
- css_cascade(style, &css_blank_style, NULL);
- if (child->style && (child->style->position ==
- CSS_POSITION_ABSOLUTE ||
- child->style->position ==
- CSS_POSITION_FIXED)) {
- style->position = child->style->position;
- }
- cell = box_create(style, row->href, row->target, 0, 0,
- c);
- if (!cell) {
- talloc_free(style);
+
+ cell = box_create(style, row->href, row->target,
+ NULL, NULL, c);
+ if (cell == NULL) {
+ css_computed_style_destroy(style);
return false;
}
cell->type = BOX_TABLE_CELL;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
row->children = cell;
else
child->prev->next = cell;
+
cell->prev = child->prev;
- while (child != 0 && (
+
+ while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
child->type == BOX_TABLE_ROW_GROUP ||
child->type == BOX_TABLE_ROW)) {
box_add_child(cell, child);
+
next_child = child->next;
- child->next = 0;
+ child->next = NULL;
child = next_child;
}
+
assert(cell->last != NULL);
- cell->last->next = 0;
+
+ cell->last->next = NULL;
cell->next = next_child = child;
- if (cell->next)
+ if (cell->next != NULL)
cell->next->prev = cell;
+ else
+ row->last = cell;
cell->parent = row;
- if (!box_normalise_block(cell, c))
+
+ if (box_normalise_block(cell, c) == false)
return false;
break;
case BOX_INLINE:
@@ -596,42 +751,27 @@ bool box_normalise_table_row(struct box *row,
assert(0);
}
- if (!calculate_table_row(col_info, cell->columns, cell->rows,
- &cell->start_column))
+ if (calculate_table_row(col_info, cell->columns, cell->rows,
+ &cell->start_column) == false)
return false;
}
+
+ /* Update row spanning details for all columns */
for (i = 0; i < col_info->num_columns; i++) {
- if ((col_info->spans[i].row_span != 0) && (!col_info->spans[i].auto_row)) {
+ if (col_info->spans[i].row_span != 0 &&
+ col_info->spans[i].auto_row == false) {
+ /* This cell spans rows, and is not an auto row.
+ * Reduce number of rows left to span */
col_info->spans[i].row_span--;
- if ((col_info->spans[i].auto_column) && (0 == col_info->spans[i].row_span)) {
- col_info->spans[i].auto_column = false;
- }
}
}
+
+ /* Reset current column for next row */
col_info->current_column = 0;
- col_info->extra = false;
-
- /* Removing empty rows causes ill effects for HTML such as:
- *
- * <tr><td colspan="2">1</td></tr><tr></tr><tr><td>2</td></tr>
- *
- * as it breaks the colspan value. Additionally, both MSIE and FF
- * render in the same manner as NetSurf does with the empty row
- * culling commented out.
- */
-// if (row->children == 0) {
-// LOG(("row->children == 0, removing"));
-// if (row->prev == 0)
-// row->parent->children = row->next;
-// else
-// row->prev->next = row->next;
-// if (row->next != 0)
-// row->next->prev = row->prev;
-// box_free(row);
-// } else {
- col_info->num_rows++;
-// }
+
+ /* Increment row counter */
+ col_info->num_rows++;
LOG(("row %p done", row));
@@ -640,6 +780,13 @@ bool box_normalise_table_row(struct box *row,
/**
+ * Compute the column index at which the current cell begins.
+ * Additionally, update the column record to reflect row spanning.
+ *
+ * \param col_info Column record
+ * \param col_span Number of columns that current cell spans
+ * \param row_span Number of rows that current cell spans
+ * \param start_column Pointer to location to receive column index
* \return true on success, false on memory exhaustion
*/
@@ -647,70 +794,55 @@ bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
unsigned int *start_column)
{
- unsigned int cell_start_col;
+ unsigned int cell_start_col = col_info->current_column;
unsigned int cell_end_col;
unsigned int i;
struct span_info *spans;
- if (!col_info->extra) {
- /* skip columns with cells spanning from above */
- while ((col_info->spans[col_info->current_column].row_span != 0) &&
- (!col_info->spans[col_info->current_column].auto_column)) {
- col_info->current_column++;
- }
- if (col_info->spans[col_info->current_column].auto_column) {
- col_info->extra = true;
- col_info->current_column = 0;
- }
- }
+ /* Skip columns with cells spanning from above */
+ while (col_info->spans[cell_start_col].row_span != 0)
+ cell_start_col++;
+
+ /* Update current column with calculated start */
+ col_info->current_column = cell_start_col;
+
+ /* If this cell has a colspan of 0, then assume 1.
+ * No other browser supports colspan=0, anyway. */
+ if (col_span == 0)
+ col_span = 1;
+
+ cell_end_col = cell_start_col + col_span;
+
+ if (col_info->num_columns < cell_end_col) {
+ /* It appears that this row has more columns than
+ * the maximum recorded for the table so far.
+ * Allocate more span records. */
+ spans = realloc(col_info->spans,
+ sizeof *spans * (cell_end_col + 1));
+ if (spans == NULL)
+ return false;
- cell_start_col = col_info->current_column;
-
- /* If the current table cell follows a cell with colspan=0,
- ignore both colspan and rowspan just assume it is a standard
- size cell */
- if (col_info->extra) {
- col_info->current_column++;
- col_info->extra_columns = col_info->current_column;
- } else {
- /* If span to end of table, assume spaning single column
- at the moment */
- cell_end_col = cell_start_col + ((0 == col_span) ? 1 : col_span);
-
- if (col_info->num_columns < cell_end_col) {
- spans = realloc(col_info->spans,
- sizeof *spans * (cell_end_col + 1));
- if (!spans)
- return false;
- col_info->spans = spans;
- col_info->num_columns = cell_end_col;
-
- /* Mark new final column as sentinal */
- col_info->spans[cell_end_col].row_span = 0;
- col_info->spans[cell_end_col].auto_row =
- col_info->spans[cell_end_col].auto_column =
- false;
- }
+ col_info->spans = spans;
+ col_info->num_columns = cell_end_col;
- if (0 == col_span) {
- col_info->spans[cell_start_col].auto_column = true;
- col_info->spans[cell_start_col].row_span = row_span;
- col_info->spans[cell_start_col].auto_row = (0 == row_span);
- } else {
- for (i = cell_start_col; i < cell_end_col; i++) {
- col_info->spans[i].row_span = (0 == row_span) ?
- 1 : row_span;
- col_info->spans[i].auto_row = (0 == row_span);
- col_info->spans[i].auto_column = false;
- }
- }
- if (0 == col_span) {
- col_info->spans[cell_end_col].auto_column = true;
- }
- col_info->current_column = cell_end_col;
+ /* Mark new final column as sentinel */
+ col_info->spans[cell_end_col].row_span = 0;
+ col_info->spans[cell_end_col].auto_row = false;
+ }
+
+ /* This cell may span multiple columns. If it also wants to span
+ * multiple rows, temporarily assume it spans 1 row only. This will
+ * be fixed up in box_normalise_table_spans() */
+ for (i = cell_start_col; i < cell_end_col; i++) {
+ col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span;
+ col_info->spans[i].auto_row = (row_span == 0);
}
+ /* Update current column with calculated end. */
+ col_info->current_column = cell_end_col;
+
*start_column = cell_start_col;
+
return true;
}
@@ -720,11 +852,11 @@ bool box_normalise_inline_container(struct box *cont, struct content * c)
struct box *child;
struct box *next_child;
- assert(cont != 0);
+ assert(cont != NULL);
assert(cont->type == BOX_INLINE_CONTAINER);
LOG(("cont %p", cont));
- for (child = cont->children; child != 0; child = next_child) {
+ for (child = cont->children; child != NULL; child = next_child) {
next_child = child->next;
switch (child->type) {
case BOX_INLINE:
@@ -735,37 +867,40 @@ bool box_normalise_inline_container(struct box *cont, struct content * c)
break;
case BOX_INLINE_BLOCK:
/* ok */
- if (!box_normalise_block(child, c))
+ if (box_normalise_block(child, c) == false)
return false;
break;
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
/* ok */
- assert(child->children != 0);
+ assert(child->children != NULL);
+
switch (child->children->type) {
case BOX_BLOCK:
- if (!box_normalise_block(
- child->children,
- c))
+ if (box_normalise_block(child->children,
+ c) == false)
return false;
break;
case BOX_TABLE:
- if (!box_normalise_table(
- child->children,
- c))
+ if (box_normalise_table(child->children,
+ c) == false)
return false;
break;
default:
assert(0);
}
- if (child->children == 0) {
+
+ if (child->children == NULL) {
/* the child has destroyed itself: remove float */
- if (child->prev == 0)
+ if (child->prev == NULL)
child->parent->children = child->next;
else
child->prev->next = child->next;
- if (child->next != 0)
+ if (child->next != NULL)
child->next->prev = child->prev;
+ else
+ child->parent->last = child->prev;
+
box_free(child);
}
break;
diff --git a/render/directory.c b/render/directory.c
index 2c4a70dbd..82f24efa2 100644
--- a/render/directory.c
+++ b/render/directory.c
@@ -40,8 +40,9 @@ static const char header[] = "<html>\n<head>\n<title>\n";
static const char footer[] = "</pre>\n</body>\n</html>\n";
-bool directory_create(struct content *c, const char *params[]) {
- if (!html_create(c, params))
+bool directory_create(struct content *c, struct content *parent,
+ const char *params[]) {
+ if (!html_create(c, parent, params))
/* html_create() must have broadcast MSG_ERROR already, so we
* don't need to. */
return false;
diff --git a/render/directory.h b/render/directory.h
index 259f51b88..a54d516fb 100644
--- a/render/directory.h
+++ b/render/directory.h
@@ -29,7 +29,8 @@
#include "content/content_type.h"
-bool directory_create(struct content *c, const char *params[]);
+bool directory_create(struct content *c, struct content *parent,
+ const char *params[]);
bool directory_convert(struct content *c, int width, int height);
void directory_destroy(struct content *c);
diff --git a/render/font.c b/render/font.c
index 11135d959..4577ff373 100644
--- a/render/font.c
+++ b/render/font.c
@@ -17,13 +17,15 @@
*/
#include "css/css.h"
+#include "css/utils.h"
+#include "desktop/options.h"
#include "render/font.h"
static plot_font_generic_family_t plot_font_generic_family(
- css_font_family css);
-static int plot_font_weight(css_font_weight css);
-static plot_font_flags_t plot_font_flags(css_font_style style,
- css_font_variant variant);
+ enum css_font_family css);
+static int plot_font_weight(enum css_font_weight css);
+static plot_font_flags_t plot_font_flags(enum css_font_style style,
+ enum css_font_variant variant);
/**
* Populate a font style using data from a computed CSS style
@@ -31,15 +33,31 @@ static plot_font_flags_t plot_font_flags(css_font_style style,
* \param css Computed style to consider
* \param fstyle Font style to populate
*/
-void font_plot_style_from_css(const struct css_style *css,
+void font_plot_style_from_css(const css_computed_style *css,
plot_font_style_t *fstyle)
{
- fstyle->family = plot_font_generic_family(css->font_family);
- fstyle->size =
- css_len2pt(&css->font_size.value.length, css) * FONT_SIZE_SCALE;
- fstyle->weight = plot_font_weight(css->font_weight);
- fstyle->flags = plot_font_flags(css->font_style, css->font_variant);
- fstyle->foreground = css->color;
+ lwc_string **families;
+ css_fixed length = 0;
+ css_unit unit = CSS_UNIT_PX;
+ css_color col;
+
+ fstyle->family = plot_font_generic_family(
+ css_computed_font_family(css, &families));
+
+ css_computed_font_size(css, &length, &unit);
+ fstyle->size = FIXTOINT(FMULI(nscss_len2pt(length, unit),
+ FONT_SIZE_SCALE));
+
+ /* Clamp font size to configured minimum */
+ if (fstyle->size < (option_font_min_size * FONT_SIZE_SCALE) / 10)
+ fstyle->size = (option_font_min_size * FONT_SIZE_SCALE) / 10;
+
+ fstyle->weight = plot_font_weight(css_computed_font_weight(css));
+ fstyle->flags = plot_font_flags(css_computed_font_style(css),
+ css_computed_font_variant(css));
+
+ css_computed_color(css, &col);
+ fstyle->foreground = nscss_color_to_ns(col);
fstyle->background = 0;
}
@@ -54,7 +72,7 @@ void font_plot_style_from_css(const struct css_style *css,
* \return Plot font family
*/
plot_font_generic_family_t plot_font_generic_family(
- css_font_family css)
+ enum css_font_family css)
{
plot_font_generic_family_t plot;
@@ -86,7 +104,7 @@ plot_font_generic_family_t plot_font_generic_family(
* \param css CSS font weight
* \return Plot weight
*/
-int plot_font_weight(css_font_weight css)
+int plot_font_weight(enum css_font_weight css)
{
int weight;
@@ -133,8 +151,8 @@ int plot_font_weight(css_font_weight css)
* \param variant CSS font variant
* \return Computed plot flags
*/
-plot_font_flags_t plot_font_flags(css_font_style style,
- css_font_variant variant)
+plot_font_flags_t plot_font_flags(enum css_font_style style,
+ enum css_font_variant variant)
{
plot_font_flags_t flags = FONTF_NONE;
diff --git a/render/font.h b/render/font.h
index 9a80af329..3012abce0 100644
--- a/render/font.h
+++ b/render/font.h
@@ -53,7 +53,7 @@ struct font_functions
extern const struct font_functions nsfont;
-void font_plot_style_from_css(const struct css_style *css,
+void font_plot_style_from_css(const css_computed_style *css,
plot_font_style_t *fstyle);
#endif
diff --git a/render/html.c b/render/html.c
index 1905e8bc3..bad7ff2e2 100644
--- a/render/html.c
+++ b/render/html.c
@@ -61,7 +61,8 @@ static void html_convert_css_callback(content_msg msg, struct content *css,
static bool html_meta_refresh(struct content *c, xmlNode *head);
static bool html_head(struct content *c, xmlNode *head);
static bool html_find_stylesheets(struct content *c, xmlNode *html);
-static bool html_process_style_element(struct content *c, xmlNode *style);
+static bool html_process_style_element(struct content *c, unsigned int index,
+ xmlNode *style);
static void html_object_callback(content_msg msg, struct content *object,
intptr_t p1, intptr_t p2, union content_msg_data data);
static void html_object_done(struct box *box, struct content *object,
@@ -92,6 +93,18 @@ static const char empty_document[] =
"</body>"
"</html>";
+/**
+ * Allocator
+ *
+ * \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
+ */
+static void *myrealloc(void *ptr, size_t len, void *pw)
+{
+ return realloc(ptr, len);
+}
/**
* Create a CONTENT_HTML.
@@ -100,15 +113,19 @@ static const char empty_document[] =
* created.
*/
-bool html_create(struct content *c, const char *params[])
+bool html_create(struct content *c, struct content *parent,
+ const char *params[])
{
unsigned int i;
struct content_html_data *html = &c->data.html;
union content_msg_data msg_data;
binding_error error;
+ lwc_context *dict;
+ lwc_error lerror;
html->parser_binding = NULL;
html->document = 0;
+ html->quirks = BINDING_QUIRKS_MODE_NONE;
html->encoding = 0;
html->base_url = c->url;
html->base_target = NULL;
@@ -116,8 +133,7 @@ bool html_create(struct content *c, const char *params[])
html->background_colour = NS_TRANSPARENT;
html->stylesheet_count = 0;
html->stylesheet_content = 0;
- html->style = 0;
- html->working_stylesheet = 0;
+ html->select_ctx = NULL;
html->object_count = 0;
html->object = 0;
html->forms = 0;
@@ -130,6 +146,14 @@ bool html_create(struct content *c, const char *params[])
html->box = 0;
html->font_func = &nsfont;
+ lerror = lwc_create_context(myrealloc, c, &dict);
+ if (lerror != lwc_error_ok) {
+ error = BINDING_NOMEM;
+ goto error;
+ }
+
+ html->dict = lwc_context_ref(dict);
+
for (i = 0; params[i]; i += 2) {
if (strcasecmp(params[i], "charset") == 0) {
html->encoding = talloc_strdup(c, params[i + 1]);
@@ -343,7 +367,8 @@ bool html_convert(struct content *c, int width, int height)
}
c->data.html.document =
- binding_get_document(c->data.html.parser_binding);
+ binding_get_document(c->data.html.parser_binding,
+ &c->data.html.quirks);
/*xmlDebugDumpDocument(stderr, c->data.html.document);*/
if (!c->data.html.document) {
@@ -467,7 +492,7 @@ bool html_convert(struct content *c, int width, int height)
option_min_reflow_period : time_taken * 1.25));
LOG(("Scheduling relayout no sooner than %dcs",
c->reformat_time - wallclock()));
- /*box_dump(c->data.html.layout->children, 0);*/
+ /*box_dump(stderr, c->data.html.layout->children, 0);*/
/* Destroy the parser binding */
binding_destroy_tree(c->data.html.parser_binding);
@@ -778,16 +803,17 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
union content_msg_data msg_data;
url_func_result res;
struct content **stylesheet_content;
+ css_error error;
/* stylesheet 0 is the base style sheet,
- * stylesheet 1 is the adblocking stylesheet,
- * stylesheet 2 is any <style> elements */
+ * stylesheet 1 is the quirks mode style sheet,
+ * stylesheet 2 is the adblocking stylesheet */
c->data.html.stylesheet_content = talloc_array(c, struct content *,
STYLESHEET_START);
if (!c->data.html.stylesheet_content)
goto no_memory;
- c->data.html.stylesheet_content[STYLESHEET_ADBLOCK] = 0;
- c->data.html.stylesheet_content[STYLESHEET_STYLE] = 0;
+ c->data.html.stylesheet_content[STYLESHEET_QUIRKS] = NULL;
+ c->data.html.stylesheet_content[STYLESHEET_ADBLOCK] = NULL;
c->data.html.stylesheet_count = STYLESHEET_START;
c->active = 0;
@@ -805,6 +831,22 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
STYLESHEET_BASE, c->width, c->height,
0, 0, false, c);
+ if (c->data.html.quirks == BINDING_QUIRKS_MODE_FULL) {
+ c->data.html.stylesheet_content[STYLESHEET_QUIRKS] =
+ fetchcache(quirks_stylesheet_url,
+ html_convert_css_callback, (intptr_t) c,
+ STYLESHEET_QUIRKS, c->width, c->height,
+ true, 0, 0, false, false);
+ if (c->data.html.stylesheet_content[STYLESHEET_QUIRKS] == NULL)
+ goto no_memory;
+ c->active++;
+ fetchcache_go(c->data.html.
+ stylesheet_content[STYLESHEET_QUIRKS],
+ c->url, html_convert_css_callback,
+ (intptr_t) c, STYLESHEET_QUIRKS, c->width,
+ c->height, 0, 0, false, c);
+ }
+
if (option_block_ads) {
c->data.html.stylesheet_content[STYLESHEET_ADBLOCK] =
fetchcache(adblock_stylesheet_url,
@@ -931,31 +973,14 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
i++;
} else if (strcmp((const char *) node->name, "style") == 0) {
- if (!html_process_style_element(c, node))
+ if (!html_process_style_element(c, i, node))
return false;
+ i++;
}
}
c->data.html.stylesheet_count = i;
- if (c->data.html.stylesheet_content[STYLESHEET_STYLE] != 0) {
- if (css_convert(c->data.html.
- stylesheet_content[STYLESHEET_STYLE], c->width,
- c->height)) {
- if (!content_add_user(c->data.html.
- stylesheet_content[STYLESHEET_STYLE],
- html_convert_css_callback,
- (intptr_t) c, STYLESHEET_STYLE)) {
- /* no memory */
- c->data.html.stylesheet_content[STYLESHEET_STYLE] = 0;
- goto no_memory;
- }
- } else {
- /* conversion failed */
- c->data.html.stylesheet_content[STYLESHEET_STYLE] = 0;
- }
- }
-
/* complete the fetches */
while (c->active != 0) {
if (c->active != last_active) {
@@ -974,29 +999,23 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
return false;
}
- assert(c->data.html.stylesheet_content[STYLESHEET_BASE]);
- css_set_origin(c->data.html.stylesheet_content[STYLESHEET_BASE],
- CSS_ORIGIN_UA);
-
- /* any of our other stylesheet pointers could be NULL at this point if
- * the CSS file(s) failed to load/fetch */
- if (c->data.html.stylesheet_content[STYLESHEET_ADBLOCK])
- css_set_origin(c->data.html.stylesheet_content[
- STYLESHEET_ADBLOCK], CSS_ORIGIN_UA);
- if (c->data.html.stylesheet_content[STYLESHEET_STYLE])
- css_set_origin(c->data.html.stylesheet_content[
- STYLESHEET_STYLE], CSS_ORIGIN_AUTHOR);
- for (i = STYLESHEET_START; i != c->data.html.stylesheet_count; i++)
- if (c->data.html.stylesheet_content[i])
- css_set_origin(c->data.html.stylesheet_content[i],
- CSS_ORIGIN_AUTHOR);
-
- c->data.html.working_stylesheet = css_make_working_stylesheet(
- c->data.html.stylesheet_content,
- c->data.html.stylesheet_count);
- if (!c->data.html.working_stylesheet)
+ /* Create selection context */
+ error = css_select_ctx_create(myrealloc, c, &c->data.html.select_ctx);
+ if (error != CSS_OK)
goto no_memory;
+ /* Add sheets to it */
+ for (i = STYLESHEET_BASE; i != c->data.html.stylesheet_count; i++) {
+ if (c->data.html.stylesheet_content[i]) {
+ error = css_select_ctx_append_sheet(
+ c->data.html.select_ctx,
+ c->data.html.stylesheet_content[i]->
+ data.css.sheet);
+ if (error != CSS_OK)
+ goto no_memory;
+ }
+ }
+
return true;
no_memory:
@@ -1010,15 +1029,19 @@ no_memory:
* Process an inline stylesheet in the document.
*
* \param c content structure
+ * \param index Index of stylesheet in stylesheet_content array
* \param style xml node of style element
* \return true on success, false if an error occurred
*/
-bool html_process_style_element(struct content *c, xmlNode *style)
+bool html_process_style_element(struct content *c, unsigned int index,
+ xmlNode *style)
{
xmlNode *child;
char *type, *media, *data;
union content_msg_data msg_data;
+ struct content **stylesheet_content;
+ const char *params[] = { 0 };
/* type='text/css', or not present (invalid but common) */
if ((type = (char *) xmlGetProp(style, (const xmlChar *) "type"))) {
@@ -1039,20 +1062,24 @@ bool html_process_style_element(struct content *c, xmlNode *style)
xmlFree(media);
}
+ /* Extend array */
+ stylesheet_content = talloc_realloc(c, c->data.html.stylesheet_content,
+ struct content *, index + 1);
+ if (stylesheet_content == NULL)
+ goto no_memory;
+
+ c->data.html.stylesheet_content = stylesheet_content;
+
/* create stylesheet */
- if (c->data.html.stylesheet_content[STYLESHEET_STYLE] == 0) {
- const char *params[] = { 0 };
- c->data.html.stylesheet_content[STYLESHEET_STYLE] =
- content_create(c->data.html.base_url);
- if (!c->data.html.stylesheet_content[STYLESHEET_STYLE])
- goto no_memory;
- if (!content_set_type(c->data.html.
- stylesheet_content[STYLESHEET_STYLE],
- CONTENT_CSS, "text/css", params))
- /** \todo not necessarily caused by
- * memory exhaustion */
- goto no_memory;
- }
+ c->data.html.stylesheet_content[index] =
+ content_create(c->data.html.base_url);
+ if (c->data.html.stylesheet_content[index] == NULL)
+ goto no_memory;
+ if (!content_set_type(c->data.html.stylesheet_content[index],
+ CONTENT_CSS, "text/css", params, c))
+ /** \todo not necessarily caused by
+ * memory exhaustion */
+ goto no_memory;
/* can't just use xmlNodeGetContent(style), because that won't
* give the content of comments which may be used to 'hide'
@@ -1060,7 +1087,7 @@ bool html_process_style_element(struct content *c, xmlNode *style)
for (child = style->children; child != 0; child = child->next) {
data = (char *) xmlNodeGetContent(child);
if (!content_process_data(c->data.html.
- stylesheet_content[STYLESHEET_STYLE],
+ stylesheet_content[index],
data, strlen(data))) {
xmlFree(data);
/** \todo not necessarily caused by
@@ -1070,6 +1097,21 @@ bool html_process_style_element(struct content *c, xmlNode *style)
xmlFree(data);
}
+ /* Convert the content */
+ if (nscss_convert(c->data.html.stylesheet_content[index], c->width,
+ c->height)) {
+ if (!content_add_user(c->data.html.stylesheet_content[index],
+ html_convert_css_callback,
+ (intptr_t) c, index)) {
+ /* no memory */
+ c->data.html.stylesheet_content[index] = NULL;
+ goto no_memory;
+ }
+ } else {
+ /* conversion failed */
+ c->data.html.stylesheet_content[index] = NULL;
+ }
+
return true;
no_memory:
@@ -1181,7 +1223,7 @@ void html_convert_css_callback(content_msg msg, struct content *css,
* \return true on success, false on memory exhaustion
*/
-bool html_fetch_object(struct content *c, char *url, struct box *box,
+bool html_fetch_object(struct content *c, const char *url, struct box *box,
const content_type *permitted_types,
int available_width, int available_height,
bool background)
@@ -1693,10 +1735,10 @@ void html_reformat(struct content *c, int width, int height)
/* width and height are at least margin box of document */
c->width = layout->x + layout->padding[LEFT] + layout->width +
- layout->padding[RIGHT] + layout->border[RIGHT] +
+ layout->padding[RIGHT] + layout->border[RIGHT].width +
layout->margin[RIGHT];
c->height = layout->y + layout->padding[TOP] + layout->height +
- layout->padding[BOTTOM] + layout->border[BOTTOM] +
+ layout->padding[BOTTOM] + layout->border[BOTTOM].width +
layout->margin[BOTTOM];
/* if boxes overflow right or bottom edge, expand to contain it */
@@ -1757,6 +1799,12 @@ void html_destroy(struct content *c)
c->data.html.iframe = NULL;
}
+ /* Destroy selection context */
+ if (c->data.html.select_ctx) {
+ css_select_ctx_destroy(c->data.html.select_ctx);
+ c->data.html.select_ctx = NULL;
+ }
+
/* Free stylesheets */
if (c->data.html.stylesheet_count) {
for (i = 0; i != c->data.html.stylesheet_count; i++) {
@@ -1768,11 +1816,6 @@ void html_destroy(struct content *c)
}
}
- talloc_free(c->data.html.working_stylesheet);
-
- /*if (c->data.html.style)
- css_free_style(c->data.html.style);*/
-
/* Free objects */
for (i = 0; i != c->data.html.object_count; i++) {
LOG(("object %i %p", i, c->data.html.object[i].content));
@@ -1784,6 +1827,8 @@ void html_destroy(struct content *c)
c->data.html.object[i].content);
}
}
+
+ lwc_context_unref(c->data.html.dict);
}
void html_destroy_frameset(struct content_html_frames *frameset) {
diff --git a/render/html.h b/render/html.h
index e6c322e14..b41406659 100644
--- a/render/html.h
+++ b/render/html.h
@@ -42,12 +42,13 @@ struct plotters;
/* entries in stylesheet_content */
#define STYLESHEET_BASE 0 /* base style sheet */
-#define STYLESHEET_ADBLOCK 1 /* adblocking stylesheet */
-#define STYLESHEET_STYLE 2 /* <style> elements (not cached) */
+#define STYLESHEET_QUIRKS 1 /* quirks mode stylesheet */
+#define STYLESHEET_ADBLOCK 2 /* adblocking stylesheet */
#define STYLESHEET_START 3 /* start of document stylesheets */
extern char *default_stylesheet_url;
extern char *adblock_stylesheet_url;
+extern char *quirks_stylesheet_url;
struct frame_dimension {
float value;
@@ -117,6 +118,9 @@ struct content_html_iframe {
struct content_html_data {
void *parser_binding;
xmlDoc *document;
+ binding_quirks_mode quirks; /**< Quirkyness of document */
+
+ lwc_context *dict; /**< Internment context for this document */
char *encoding; /**< Encoding of source, 0 if unknown. */
binding_encoding_source encoding_source;
@@ -133,9 +137,8 @@ struct content_html_data {
unsigned int stylesheet_count;
/** Stylesheets. Each may be 0. */
struct content **stylesheet_content;
- struct css_style *style; /**< Base style. */
- /** Working stylesheet. */
- struct css_working_stylesheet *working_stylesheet;
+ /**< Style selection context */
+ css_select_ctx *select_ctx;
/** Number of entries in object. */
unsigned int object_count;
@@ -168,12 +171,13 @@ struct content_html_data {
extern bool html_redraw_debug;
-bool html_create(struct content *c, const char *params[]);
+bool html_create(struct content *c, struct content *parent,
+ const char *params[]);
bool html_process_data(struct content *c, char *data, unsigned int size);
bool html_convert(struct content *c, int width, int height);
void html_reformat(struct content *c, int width, int height);
void html_destroy(struct content *c);
-bool html_fetch_object(struct content *c, char *url, struct box *box,
+bool html_fetch_object(struct content *c, const char *url, struct box *box,
const content_type *permitted_types,
int available_width, int available_height,
bool background);
diff --git a/render/html_redraw.c b/render/html_redraw.c
index 309b81332..735c241a3 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -32,6 +32,7 @@
#include "utils/config.h"
#include "content/content.h"
#include "css/css.h"
+#include "css/utils.h"
#include "desktop/gui.h"
#include "desktop/plotters.h"
#include "desktop/knockout.h"
@@ -67,7 +68,7 @@ static bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
bool html_redraw_inline_borders(struct box *box, int x0, int y0, int x1, int y1,
float scale, bool first, bool last);
static bool html_redraw_border_plot(int i, int *p, colour c,
- css_border_style style, int thickness);
+ enum css_border_style style, int thickness);
static bool html_redraw_checkbox(int x, int y, int width, int height,
bool selected);
static bool html_redraw_radio(int x, int y, int width, int height,
@@ -193,6 +194,7 @@ bool html_redraw_box(struct box *box,
int x0, y0, x1, y1;
int x_scrolled, y_scrolled;
struct box *bg_box = NULL;
+ css_color bgcol = 0;
if (html_redraw_printing && box->printed)
return true;
@@ -208,10 +210,10 @@ bool html_redraw_box(struct box *box,
padding_width = padding_left + box->width + box->padding[RIGHT];
padding_height = padding_top + box->height +
box->padding[BOTTOM];
- border_left = box->border[LEFT];
- border_top = box->border[TOP];
- border_right = box->border[RIGHT];
- border_bottom = box->border[BOTTOM];
+ border_left = box->border[LEFT].width;
+ border_top = box->border[TOP].width;
+ border_right = box->border[RIGHT].width;
+ border_bottom = box->border[BOTTOM].width;
} else {
x = (x_parent + box->x) * scale;
y = (y_parent + box->y) * scale;
@@ -227,14 +229,15 @@ bool html_redraw_box(struct box *box,
box->padding[RIGHT]) * scale;
padding_height = (box->padding[TOP] + box->height +
box->padding[BOTTOM]) * scale;
- border_left = box->border[LEFT] * scale;
- border_top = box->border[TOP] * scale;
- border_right = box->border[RIGHT] * scale;
- border_bottom = box->border[BOTTOM] * scale;
+ border_left = box->border[LEFT].width * scale;
+ border_top = box->border[TOP].width * scale;
+ border_right = box->border[RIGHT].width * scale;
+ border_bottom = box->border[BOTTOM].width * scale;
}
/* calculate rectangle covering this box and descendants */
- if (box->style && box->style->overflow != CSS_OVERFLOW_VISIBLE) {
+ if (box->style && css_computed_overflow(box->style) !=
+ CSS_OVERFLOW_VISIBLE) {
x0 = x - border_left;
y0 = y - border_top;
x1 = x + padding_width + border_right;
@@ -296,7 +299,8 @@ bool html_redraw_box(struct box *box,
}
/* if visibility is hidden render children only */
- if (box->style && box->style->visibility == CSS_VISIBILITY_HIDDEN) {
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN) {
if ((plot.group_start) && (!plot.group_start("hidden box")))
return false;
if (!html_redraw_box_children(box, x_parent, y_parent,
@@ -346,20 +350,21 @@ bool html_redraw_box(struct box *box,
*/
if (!box->parent) {
/* Root box */
- if (box->style &&
- (box->style->background_color !=
- NS_TRANSPARENT ||
+ if (box->style && (css_computed_background_color(box->style,
+ &bgcol) != CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->background)) {
/* With its own background */
bg_box = box;
} else if (!box->style ||
- (box->style->background_color ==
- NS_TRANSPARENT &&
+ (css_computed_background_color(box->style,
+ &bgcol) == CSS_BACKGROUND_COLOR_TRANSPARENT &&
!box->background)) {
/* Without its own background */
if (box->children && box->children->style &&
- (box->children->style->
- background_color != NS_TRANSPARENT ||
+ (css_computed_background_color(
+ box->children->style,
+ &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->children->background)) {
/* But body has one, so use that */
bg_box = box->children;
@@ -367,14 +372,14 @@ bool html_redraw_box(struct box *box,
}
} else if (box->parent && !box->parent->parent) {
/* Body box */
- if (box->style &&
- (box->style->background_color !=
- NS_TRANSPARENT ||
+ if (box->style && (css_computed_background_color(box->style,
+ &bgcol) != CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->background)) {
/* With a background */
if (box->parent->style &&
- (box->parent->style->background_color !=
- NS_TRANSPARENT ||
+ (css_computed_background_color(
+ box->parent->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->parent->background)) {
/* Root has own background; process normally */
bg_box = box;
@@ -395,8 +400,9 @@ bool html_redraw_box(struct box *box,
bg_box->type != BOX_TEXT &&
bg_box->type != BOX_INLINE_END &&
(bg_box->type != BOX_INLINE || bg_box->object) &&
- ((bg_box->style->background_color != NS_TRANSPARENT) ||
- (bg_box->background))) {
+ (css_computed_background_color(bg_box->style,
+ &bgcol) != CSS_BACKGROUND_COLOR_TRANSPARENT ||
+ bg_box->background)) {
/* find intersection of clip box and border edge */
int px0, py0, px1, py1;
px0 = x - border_left < x0 ? x0 : x - border_left;
@@ -451,7 +457,8 @@ bool html_redraw_box(struct box *box,
/* backgrounds and borders for non-replaced inlines */
if (box->style && box->type == BOX_INLINE && box->inline_end &&
- (box->style->background_color != NS_TRANSPARENT ||
+ (css_computed_background_color(box->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->background || border_top || border_right ||
border_bottom || border_left)) {
/* inline backgrounds and borders span other boxes and may
@@ -482,15 +489,15 @@ bool html_redraw_box(struct box *box,
ib_y = y_parent + ib->y;
ib_p_width = ib->padding[LEFT] + ib->width +
ib->padding[RIGHT];
- ib_b_left = ib->border[LEFT];
- ib_b_right = ib->border[RIGHT];
+ ib_b_left = ib->border[LEFT].width;
+ ib_b_right = ib->border[RIGHT].width;
} else {
ib_x = (x_parent + ib->x) * scale;
ib_y = (y_parent + ib->y) * scale;
ib_p_width = (ib->padding[LEFT] + ib->width +
ib->padding[RIGHT]) * scale;
- ib_b_left = ib->border[LEFT] * scale;
- ib_b_right = ib->border[RIGHT] * scale;
+ ib_b_left = ib->border[LEFT].width * scale;
+ ib_b_right = ib->border[RIGHT].width * scale;
}
if (ib->inline_new_line && ib != box) {
@@ -587,7 +594,8 @@ bool html_redraw_box(struct box *box,
}
/* clip to the padding edge for boxes with overflow hidden or scroll */
- if (box->style && box->style->overflow != CSS_OVERFLOW_VISIBLE) {
+ if (box->style && css_computed_overflow(box->style) !=
+ CSS_OVERFLOW_VISIBLE) {
x0 = x;
y0 = y;
x1 = x + padding_width;
@@ -607,7 +615,7 @@ bool html_redraw_box(struct box *box,
/* text decoration */
if (box->type != BOX_TEXT && box->style &&
- box->style->text_decoration !=
+ css_computed_text_decoration(box->style) !=
CSS_TEXT_DECORATION_NONE)
if (!html_redraw_text_decoration(box, x_parent, y_parent,
scale, current_background_color))
@@ -665,8 +673,10 @@ bool html_redraw_box(struct box *box,
/* scrollbars */
if (box->style && box->type != BOX_BR && box->type != BOX_TABLE &&
box->type != BOX_INLINE &&
- (box->style->overflow == CSS_OVERFLOW_SCROLL ||
- box->style->overflow == CSS_OVERFLOW_AUTO))
+ (css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_SCROLL ||
+ css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_AUTO))
if (!html_redraw_scrollbars(box, scale, x, y,
padding_width, padding_height,
current_background_color))
@@ -984,10 +994,10 @@ bool html_redraw_caret(struct caret *c, colour current_background_color,
bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
int p_width, int p_height, float scale)
{
- int top = box->border[TOP];
- int right = box->border[RIGHT];
- int bottom = box->border[BOTTOM];
- int left = box->border[LEFT];
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
int x, y;
unsigned int i;
int p[20];
@@ -1017,12 +1027,19 @@ bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
p[18] = x - left; p[19] = y - top;
for (i = 0; i != 4; i++) {
- if (box->border[i] == 0)
+ colour col = 0;
+
+ if (box->border[i].width == 0)
continue;
- if (!html_redraw_border_plot(i, p,
- box->style->border[i].color,
- box->style->border[i].style,
- box->border[i] * scale))
+
+ if (box->border[i].color == CSS_BORDER_COLOR_TRANSPARENT) {
+ col = NS_TRANSPARENT;
+ } else {
+ col = nscss_color_to_ns(box->border[i].c);
+ }
+
+ if (!html_redraw_border_plot(i, p, col, box->border[i].style,
+ box->border[i].width * scale))
return false;
}
@@ -1047,10 +1064,11 @@ bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
bool html_redraw_inline_borders(struct box *box, int x0, int y0, int x1, int y1,
float scale, bool first, bool last)
{
- int top = box->border[TOP];
- int right = box->border[RIGHT];
- int bottom = box->border[BOTTOM];
- int left = box->border[LEFT];
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
+ colour col;
int p[20];
if (scale != 1.0) {
@@ -1074,26 +1092,54 @@ bool html_redraw_inline_borders(struct box *box, int x0, int y0, int x1, int y1,
assert(box->style);
- if (box->border[LEFT] && first)
- if (!html_redraw_border_plot(LEFT, p,
- box->style->border[LEFT].color,
- box->style->border[LEFT].style, left))
+ if (box->border[LEFT].width && first) {
+ if (box->border[LEFT].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[LEFT].c);
+
+ if (!html_redraw_border_plot(LEFT, p, col,
+ box->border[LEFT].style,
+ left))
return false;
- if (box->border[TOP])
- if (!html_redraw_border_plot(TOP, p,
- box->style->border[TOP].color,
- box->style->border[TOP].style, top))
+ }
+
+ if (box->border[TOP].width) {
+ if (box->border[TOP].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[TOP].c);
+
+ if (!html_redraw_border_plot(TOP, p, col,
+ box->border[TOP].style,
+ top))
return false;
- if (box->border[BOTTOM])
- if (!html_redraw_border_plot(BOTTOM, p,
- box->style->border[BOTTOM].color,
- box->style->border[BOTTOM].style, bottom))
+ }
+
+ if (box->border[BOTTOM].width) {
+ if (box->border[BOTTOM].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[BOTTOM].c);
+
+ if (!html_redraw_border_plot(BOTTOM, p, col,
+ box->border[BOTTOM].style,
+ bottom))
return false;
- if (box->border[RIGHT] && last)
- if (!html_redraw_border_plot(RIGHT, p,
- box->style->border[RIGHT].color,
- box->style->border[RIGHT].style, right))
+ }
+
+ if (box->border[RIGHT].width && last) {
+ if (box->border[RIGHT].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[RIGHT].c);
+
+ if (!html_redraw_border_plot(RIGHT, p, col,
+ box->border[RIGHT].style,
+ right))
return false;
+ }
+
return true;
}
@@ -1128,7 +1174,7 @@ static plot_style_t plot_style_fillbdr_dlight = {
*/
bool html_redraw_border_plot(int i, int *p, colour c,
- css_border_style style, int thickness)
+ enum css_border_style style, int thickness)
{
int z[8];
unsigned int light = i;
@@ -1449,7 +1495,10 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
int px0 = clip_x0, py0 = clip_y0, px1 = clip_x1, py1 = clip_y1;
int ox = x, oy = y;
int width, height;
+ css_fixed hpos = 0, vpos = 0;
+ css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
struct box *parent;
+ css_color bgcol;
plot_style_t pstyle_fill_bg = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
@@ -1479,7 +1528,7 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
box->padding[BOTTOM];
}
/* handle background-repeat */
- switch (background->style->background_repeat) {
+ switch (css_computed_background_repeat(background->style)) {
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
@@ -1501,50 +1550,39 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
}
/* handle background-position */
- switch (background->style->background_position.horz.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- x += (width - background->background->width) *
- scale *
- background->style->background_position.
- horz.value.percent / 100;
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- x += (int) (css_len2px(&background->style->
- background_position.horz.value.length,
- background->style) * scale);
- break;
- default:
- break;
+ css_computed_background_position(background->style,
+ &hpos, &hunit, &vpos, &vunit);
+ if (hunit == CSS_UNIT_PCT) {
+ x += (width - background->background->width) *
+ scale * FIXTOFLT(hpos) / 100.;
+ } else {
+ x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ background->style)) * scale);
}
- switch (background->style->background_position.vert.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- y += (height - background->background->height) *
- scale *
- background->style->background_position.
- vert.value.percent / 100;
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- y += (int) (css_len2px(&background->style->
- background_position.vert.value.length,
- background->style) * scale);
- break;
- default:
- break;
+ if (vunit == CSS_UNIT_PCT) {
+ y += (height - background->background->height) *
+ scale * FIXTOFLT(vpos) / 100.;
+ } else {
+ y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ background->style)) * scale);
}
}
/* special case for table rows as their background needs
* to be clipped to all the cells */
if (box->type == BOX_TABLE_ROW) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
+
for (parent = box->parent;
((parent) && (parent->type != BOX_TABLE));
parent = parent->parent);
assert(parent && (parent->style));
- clip_to_children =
- (parent->style->border_spacing.horz.value > 0) ||
- (parent->style->border_spacing.vert.value > 0);
+ css_computed_border_spacing(parent->style, &h, &hu, &v, &vu);
+
+ clip_to_children = (h > 0) || (v > 0);
if (clip_to_children)
clip_box = box->children;
@@ -1572,8 +1610,9 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
/* <td> attributes override <tr> */
if ((clip_x0 >= clip_x1) || (clip_y0 >= clip_y1) ||
- (clip_box->style->background_color !=
- NS_TRANSPARENT) ||
+ (css_computed_background_color(
+ clip_box->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT) ||
(clip_box->background &&
clip_box->background->bitmap &&
bitmap_get_opaque(
@@ -1582,11 +1621,10 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
}
/* plot the background colour */
- if (background->style->background_color != NS_TRANSPARENT) {
- *background_colour =
- background->style->background_color;
- pstyle_fill_bg.fill_colour =
- background->style->background_color;
+ if (css_computed_background_color(background->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT) {
+ *background_colour = nscss_color_to_ns(bgcol);
+ pstyle_fill_bg.fill_colour = *background_colour;
if (plot_colour)
if (!plot.rectangle(clip_x0, clip_y0,
clip_x1, clip_y1,
@@ -1670,6 +1708,9 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
bool repeat_y = false;
bool plot_colour = true;
bool plot_content;
+ css_fixed hpos = 0, vpos = 0;
+ css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
+ css_color bgcol;
plot_style_t pstyle_fill_bg = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
@@ -1682,7 +1723,7 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
if (plot_content) {
/* handle background-repeat */
- switch (box->style->background_repeat) {
+ switch (css_computed_background_repeat(box->style)) {
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
@@ -1704,57 +1745,35 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
}
/* handle background-position */
- switch (box->style->background_position.horz.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- x += (px1 - px0 -
- box->background->width * scale) *
- box->style->background_position.
- horz.value.percent / 100;
-
- if (!repeat_x &&
- ((box->style->
- background_position.
- horz.value.percent < 2 &&
- !first) ||
- (box->style->
- background_position.
- horz.value.percent > 98 &&
- !last))) {
- plot_content = false;
- }
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- x += (int) (css_len2px(&box->style->
- background_position.horz.value.length,
- box->style) * scale);
- break;
- default:
- break;
+ css_computed_background_position(box->style,
+ &hpos, &hunit, &vpos, &vunit);
+ if (hunit == CSS_UNIT_PCT) {
+ x += (px1 - px0 - box->background->width * scale) *
+ FIXTOFLT(hpos) / 100.;
+
+ if (!repeat_x && ((hpos < 2 && !first) ||
+ (hpos > 98 && !last))){
+ plot_content = false;
+ }
+ } else {
+ x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ box->style)) * scale);
}
- switch (box->style->background_position.vert.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- y += (py1 - py0 -
- box->background->height * scale) *
- box->style->background_position.
- vert.value.percent / 100;
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- y += (int) (css_len2px(&box->style->
- background_position.vert.value.length,
- box->style) * scale);
- break;
- default:
- break;
+ if (vunit == CSS_UNIT_PCT) {
+ y += (py1 - py0 - box->background->height * scale) *
+ FIXTOFLT(vpos) / 100.;
+ } else {
+ y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ box->style)) * scale);
}
}
/* plot the background colour */
- if (box->style->background_color != NS_TRANSPARENT) {
- *background_colour =
- box->style->background_color;
- pstyle_fill_bg.fill_colour =
- box->style->background_color;
+ if (css_computed_background_color(box->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT) {
+ *background_colour = nscss_color_to_ns(bgcol);
+ pstyle_fill_bg.fill_colour = *background_colour;
if (plot_colour)
if (!plot.rectangle(clip_x0, clip_y0,
@@ -1820,36 +1839,40 @@ bool html_redraw_text_decoration(struct box *box,
int x_parent, int y_parent, float scale,
colour background_colour)
{
- static const css_text_decoration decoration[] = {
+ static const enum css_text_decoration decoration[] = {
CSS_TEXT_DECORATION_UNDERLINE, CSS_TEXT_DECORATION_OVERLINE,
CSS_TEXT_DECORATION_LINE_THROUGH };
static const float line_ratio[] = { 0.9, 0.1, 0.5 };
- int colour;
+ colour fgcol;
unsigned int i;
+ css_color col;
+
+ css_computed_color(box->style, &col);
+ fgcol = nscss_color_to_ns(col);
/* antialias colour for under/overline */
- if (html_redraw_printing)
- colour = box->style->color;
- else
- colour = blend_colour(background_colour, box->style->color);
+ if (html_redraw_printing == false)
+ fgcol = blend_colour(background_colour, fgcol);
if (box->type == BOX_INLINE) {
if (!box->inline_end)
return true;
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (box->style->text_decoration & decoration[i])
+ if (css_computed_text_decoration(box->style) &
+ decoration[i])
if (!html_redraw_text_decoration_inline(box,
x_parent, y_parent, scale,
- colour, line_ratio[i]))
+ fgcol, line_ratio[i]))
return false;
} else {
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (box->style->text_decoration & decoration[i])
+ if (css_computed_text_decoration(box->style) &
+ decoration[i])
if (!html_redraw_text_decoration_block(box,
x_parent + box->x,
y_parent + box->y,
scale,
- colour, line_ratio[i]))
+ fgcol, line_ratio[i]))
return false;
}
@@ -2179,9 +2202,9 @@ bool html_redraw_scrollbars(struct box *box, float scale,
bool box_vscrollbar_present(const struct box * const box)
{
- return box->descendant_y0 < -box->border[TOP] ||
+ return box->descendant_y0 < -box->border[TOP].width ||
box->padding[TOP] + box->height + box->padding[BOTTOM] +
- box->border[BOTTOM] < box->descendant_y1;
+ box->border[BOTTOM].width < box->descendant_y1;
}
@@ -2194,9 +2217,9 @@ bool box_vscrollbar_present(const struct box * const box)
bool box_hscrollbar_present(const struct box * const box)
{
- return box->descendant_x0 < -box->border[LEFT] ||
+ return box->descendant_x0 < -box->border[LEFT].width ||
box->padding[LEFT] + box->width + box->padding[RIGHT] +
- box->border[RIGHT] < box->descendant_x1;
+ box->border[RIGHT].width < box->descendant_x1;
}
diff --git a/render/hubbub_binding.c b/render/hubbub_binding.c
index 279dd9933..1d8af25ca 100644
--- a/render/hubbub_binding.c
+++ b/render/hubbub_binding.c
@@ -41,6 +41,8 @@ typedef struct hubbub_ctx {
htmlDocPtr document;
bool owns_doc;
+ binding_quirks_mode quirks;
+
const char *encoding;
binding_encoding_source encoding_source;
@@ -147,6 +149,7 @@ binding_error binding_create_tree(void *arena, const char *charset, void **ctx)
: ENCODING_SOURCE_DETECTED;
c->document = NULL;
c->owns_doc = true;
+ c->quirks = BINDING_QUIRKS_MODE_NONE;
c->forms = NULL;
error = hubbub_parser_create(charset, true, myrealloc, arena,
@@ -239,13 +242,15 @@ const char *binding_get_encoding(void *ctx, binding_encoding_source *source)
return c->encoding != NULL ? c->encoding : "Windows-1252";
}
-xmlDocPtr binding_get_document(void *ctx)
+xmlDocPtr binding_get_document(void *ctx, binding_quirks_mode *quirks)
{
hubbub_ctx *c = (hubbub_ctx *) ctx;
xmlDocPtr doc = c->document;
c->owns_doc = false;
+ *quirks = c->quirks;
+
return doc;
}
@@ -744,6 +749,20 @@ hubbub_error add_attributes(void *ctx, void *node,
hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode)
{
+ hubbub_ctx *c = (hubbub_ctx *) ctx;
+
+ switch (mode) {
+ case HUBBUB_QUIRKS_MODE_NONE:
+ c->quirks = BINDING_QUIRKS_MODE_NONE;
+ break;
+ case HUBBUB_QUIRKS_MODE_LIMITED:
+ c->quirks = BINDING_QUIRKS_MODE_LIMITED;
+ break;
+ case HUBBUB_QUIRKS_MODE_FULL:
+ c->quirks = BINDING_QUIRKS_MODE_FULL;
+ break;
+ }
+
return HUBBUB_OK;
}
diff --git a/render/layout.c b/render/layout.c
index 4d9adc468..411d6755e 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -40,6 +40,7 @@
#include <string.h>
#include <math.h>
#include "css/css.h"
+#include "css/utils.h"
#include "content/content.h"
#include "desktop/gui.h"
#include "desktop/options.h"
@@ -47,6 +48,7 @@
#include "render/font.h"
#include "render/form.h"
#include "render/layout.h"
+#include "render/table.h"
#define NDEBUG
#include "utils/log.h"
#undef NDEBUG
@@ -69,36 +71,36 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container);
static void layout_block_add_scrollbar(struct box *box, int which);
static int layout_solve_width(int available_width, int width, int lm, int rm,
int max_width, int min_width,
- int margin[4], int padding[4], int border[4]);
+ int margin[4], int padding[4], struct box_border border[4]);
static void layout_float_find_dimensions(int available_width,
- struct css_style *style, struct box *box);
+ const css_computed_style *style, struct box *box);
static void layout_find_dimensions(int available_width, int viewport_height,
- struct box *box, struct css_style *style,
+ struct box *box, const css_computed_style *style,
int *width, int *height, int *max_width, int *min_width,
- int margin[4], int padding[4], int border[4]);
+ int margin[4], int padding[4], struct box_border border[4]);
static void layout_tweak_form_dimensions(struct box *box, bool percentage,
int available_width, bool setwidth, int *dimension);
-static int layout_clear(struct box *fl, css_clear clear);
+static int layout_clear(struct box *fl, enum css_clear clear);
static void find_sides(struct box *fl, int y0, int y1,
int *x0, int *x1, struct box **left, struct box **right);
static void layout_minmax_inline_container(struct box *inline_container,
const struct font_functions *font_func);
-static int line_height(struct css_style *style);
+static int line_height(const css_computed_style *style);
static bool layout_line(struct box *first, int *width, int *y,
int cx, int cy, struct box *cont, bool indent,
bool has_text_children,
struct content *content, struct box **next_box);
static struct box *layout_minmax_line(struct box *first, int *min, int *max,
const struct font_functions *font_func);
-static int layout_text_indent(struct css_style *style, int width);
+static int layout_text_indent(const css_computed_style *style, int width);
static bool layout_float(struct box *b, int width, struct content *content);
static void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont);
static bool layout_table(struct box *box, int available_width,
struct content *content);
static void layout_move_children(struct box *box, int x, int y);
-static void calculate_mbp_width(struct css_style *style, unsigned int side,
- bool margin, bool border, bool padding,
+static void calculate_mbp_width(const css_computed_style *style,
+ unsigned int side, bool margin, bool border, bool padding,
int *fixed, float *frac);
static void layout_lists(struct box *box,
const struct font_functions *font_func);
@@ -137,11 +139,11 @@ bool layout_document(struct content *content, int width, int height)
layout_minmax_block(doc, font_func);
layout_block_find_dimensions(width, height, 0, 0, doc);
- doc->x = doc->margin[LEFT] + doc->border[LEFT];
- doc->y = doc->margin[TOP] + doc->border[TOP];
- width -= doc->margin[LEFT] + doc->border[LEFT] + doc->padding[LEFT] +
- doc->padding[RIGHT] + doc->border[RIGHT] +
- doc->margin[RIGHT];
+ doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
+ doc->y = doc->margin[TOP] + doc->border[TOP].width;
+ width -= doc->margin[LEFT] + doc->border[LEFT].width +
+ doc->padding[LEFT] + doc->padding[RIGHT] +
+ doc->border[RIGHT].width + doc->margin[RIGHT];
if (width < 0)
width = 0;
doc->width = width;
@@ -150,18 +152,19 @@ bool layout_document(struct content *content, int width, int height)
/* make <html> and <body> fill available height */
if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
- doc->border[BOTTOM] + doc->margin[BOTTOM] <
+ doc->border[BOTTOM].width + doc->margin[BOTTOM] <
height) {
doc->height = height - (doc->y + doc->padding[TOP] +
- doc->padding[BOTTOM] + doc->border[BOTTOM] +
+ doc->padding[BOTTOM] +
+ doc->border[BOTTOM].width +
doc->margin[BOTTOM]);
if (doc->children)
doc->children->height = doc->height -
(doc->children->margin[TOP] +
- doc->children->border[TOP] +
+ doc->children->border[TOP].width +
doc->children->padding[TOP] +
doc->children->padding[BOTTOM] +
- doc->children->border[BOTTOM] +
+ doc->children->border[BOTTOM].width +
doc->children->margin[BOTTOM]);
}
@@ -197,7 +200,8 @@ bool layout_block_context(struct box *block, int viewport_height,
int y = 0;
int lm, rm;
struct box *margin_box;
- struct css_length gadget_size; /* Checkbox / radio buttons */
+ css_fixed gadget_size;
+ css_unit gadget_unit; /* Checkbox / radio buttons */
assert(block->type == BOX_BLOCK ||
block->type == BOX_INLINE_BLOCK ||
@@ -267,10 +271,11 @@ bool layout_block_context(struct box *block, int viewport_height,
block->gadget->type == GADGET_CHECKBOX)) {
/* form checkbox or radio button
* if width or height is AUTO, set it to 1em */
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
+ gadget_unit = CSS_UNIT_EM;
+ gadget_size = INTTOFIX(1);
if (block->height == AUTO)
- block->height = css_len2px(&gadget_size, block->style);
+ block->height = FIXTOINT(nscss_len2px(gadget_size,
+ gadget_unit, block->style));
}
box = margin_box = block->children;
@@ -317,8 +322,10 @@ bool layout_block_context(struct box *block, int viewport_height,
*/
if (box->style &&
- (box->style->position == CSS_POSITION_ABSOLUTE||
- box->style->position == CSS_POSITION_FIXED)) {
+ (css_computed_position(box->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(box->style) ==
+ CSS_POSITION_FIXED)) {
box->x = box->parent->padding[LEFT];
/* absolute positioned; this element will establish
* its own block context when it gets laid out later,
@@ -328,9 +335,10 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Clearance. */
y = 0;
- if (box->style && box->style->clear != CSS_CLEAR_NONE)
+ if (box->style && css_computed_clear(box->style) !=
+ CSS_CLEAR_NONE)
y = layout_clear(block->float_children,
- box->style->clear);
+ css_computed_clear(box->style));
/* Get top margin */
if (box->style) {
@@ -351,7 +359,7 @@ bool layout_block_context(struct box *block, int viewport_height,
if (box->type == BOX_BLOCK || box->object) {
if (!box->object && box->style &&
- box->style->overflow !=
+ css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
/* box establishes new block formatting context
* so available width may be diminished due to
@@ -381,7 +389,13 @@ bool layout_block_context(struct box *block, int viewport_height,
layout_block_add_scrollbar(box, BOTTOM);
}
} else if (box->type == BOX_TABLE) {
- if (box->style->width.width == CSS_WIDTH_AUTO) {
+ enum css_width wtype;
+ css_fixed width = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ wtype = css_computed_width(box->style, &width, &unit);
+
+ if (wtype == CSS_WIDTH_AUTO) {
/* max available width may be diminished due to
* floats. */
int x0, x1, top;
@@ -412,18 +426,18 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Position box: horizontal. */
box->x = box->parent->padding[LEFT] + box->margin[LEFT] +
- box->border[LEFT];
+ box->border[LEFT].width;
cx += box->x;
/* Position box: vertical. */
if (box->type != BOX_BLOCK || y ||
- box->border[TOP] || box->padding[TOP]) {
+ box->border[TOP].width || box->padding[TOP]) {
margin_box->y += max_pos_margin - max_neg_margin;
cy += max_pos_margin - max_neg_margin;
max_pos_margin = max_neg_margin = 0;
margin_box = 0;
- box->y += box->border[TOP];
- cy += box->border[TOP];
+ box->y += box->border[TOP].width;
+ cy += box->border[TOP].width;
if (cy < y) {
box->y += y - cy;
cy = y;
@@ -433,7 +447,8 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Unless the box has an overflow style of visible, the box
* establishes a new block context. */
if (box->type == BOX_BLOCK && box->style &&
- box->style->overflow != CSS_OVERFLOW_VISIBLE) {
+ css_computed_overflow(box->style) !=
+ CSS_OVERFLOW_VISIBLE) {
cy += max_pos_margin - max_neg_margin;
box->y += max_pos_margin - max_neg_margin;
@@ -449,7 +464,7 @@ bool layout_block_context(struct box *block, int viewport_height,
cx -= box->x;
cy += box->height + box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
max_pos_margin = max_neg_margin = 0;
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
@@ -457,7 +472,7 @@ bool layout_block_context(struct box *block, int viewport_height,
max_neg_margin = -box->margin[BOTTOM];
y = box->y + box->padding[TOP] + box->height +
box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
/* Skip children, because they are done in the new
* block context */
goto advance_to_next_box;
@@ -480,12 +495,19 @@ bool layout_block_context(struct box *block, int viewport_height,
struct box *left, *right;
y = cy;
while (1) {
+ enum css_width wtype;
+ css_fixed width = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ wtype = css_computed_width(box->style,
+ &width, &unit);
+
x0 = cx;
x1 = cx + box->parent->width;
find_sides(block->float_children, y,
y + box->height,
&x0, &x1, &left, &right);
- if (box->style->width.width == CSS_WIDTH_AUTO)
+ if (wtype == CSS_WIDTH_AUTO)
break;
if (box->width <= x1 - x0)
break;
@@ -527,7 +549,8 @@ bool layout_block_context(struct box *block, int viewport_height,
layout_block_add_scrollbar(box, BOTTOM);
}
- cy += box->height + box->padding[BOTTOM] + box->border[BOTTOM];
+ cy += box->height + box->padding[BOTTOM] +
+ box->border[BOTTOM].width;
max_pos_margin = max_neg_margin = 0;
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
@@ -535,7 +558,8 @@ bool layout_block_context(struct box *block, int viewport_height,
max_neg_margin = -box->margin[BOTTOM];
cx -= box->x;
y = box->y + box->padding[TOP] + box->height +
- box->padding[BOTTOM] + box->border[BOTTOM];
+ box->padding[BOTTOM] +
+ box->border[BOTTOM].width;
advance_to_next_box:
if (!box->next) {
/* No more siblings:
@@ -556,7 +580,8 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Apply any min-height and max-height to
* boxes in normal flow */
- if (box->style && box->style->position !=
+ if (box->style &&
+ css_computed_position(box->style) !=
CSS_POSITION_ABSOLUTE &&
layout_apply_minmax_height(box,
NULL)) {
@@ -567,7 +592,7 @@ bool layout_block_context(struct box *block, int viewport_height,
}
cy += box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
else if (max_neg_margin < -box->margin[BOTTOM])
@@ -575,7 +600,7 @@ bool layout_block_context(struct box *block, int viewport_height,
cx -= box->x;
y = box->y + box->padding[TOP] + box->height +
box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
} while (box != block && !box->next);
if (box == block)
break;
@@ -589,7 +614,7 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Increase height to contain any floats inside (CSS 2.1 10.6.7). */
for (box = block->float_children; box; box = box->next_float) {
y = box->y + box->height + box->padding[BOTTOM] +
- box->border[BOTTOM] + box->margin[BOTTOM];
+ box->border[BOTTOM].width + box->margin[BOTTOM];
if (cy < y)
cy = y;
}
@@ -600,7 +625,8 @@ bool layout_block_context(struct box *block, int viewport_height,
layout_block_add_scrollbar(block, BOTTOM);
}
- if (block->style && block->style->position != CSS_POSITION_ABSOLUTE) {
+ if (block->style && css_computed_position(block->style) !=
+ CSS_POSITION_ABSOLUTE) {
/* Block is in normal flow */
layout_apply_minmax_height(block, NULL);
}
@@ -624,12 +650,9 @@ void layout_minmax_block(struct box *block,
int min = 0, max = 0;
int extra_fixed = 0;
float extra_frac = 0;
- struct css_length size;
- struct css_length gadget_size; /* Checkbox / radio buttons */
- size.unit = CSS_UNIT_EM;
- size.value = 10;
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
+ enum css_width wtype;
+ css_fixed width = 0;
+ css_unit wunit = CSS_UNIT_PX;
assert(block->type == BOX_BLOCK ||
block->type == BOX_INLINE_BLOCK ||
@@ -639,22 +662,28 @@ void layout_minmax_block(struct box *block,
if (block->max_width != UNKNOWN_MAX_WIDTH)
return;
+ wtype = css_computed_width(block->style, &width, &wunit);
+
if (block->gadget && (block->gadget->type == GADGET_TEXTBOX ||
block->gadget->type == GADGET_PASSWORD ||
block->gadget->type == GADGET_FILE ||
block->gadget->type == GADGET_TEXTAREA) &&
- block->style &&
- block->style->width.width == CSS_WIDTH_AUTO) {
- min = max = css_len2px(&size, block->style);
+ block->style && wtype == CSS_WIDTH_AUTO) {
+ css_fixed size = INTTOFIX(10);
+ css_unit unit = CSS_UNIT_EM;
+
+ min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
}
if (block->gadget && (block->gadget->type == GADGET_RADIO ||
block->gadget->type == GADGET_CHECKBOX) &&
- block->style &&
- block->style->width.width == CSS_WIDTH_AUTO) {
+ block->style && wtype == CSS_WIDTH_AUTO) {
+ css_fixed size = INTTOFIX(1);
+ css_unit unit = CSS_UNIT_EM;
+
/* form checkbox or radio button
* if width is AUTO, set it to 1em */
- min = max = css_len2px(&gadget_size, block->style);
+ min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
}
if (block->object) {
@@ -686,9 +715,9 @@ void layout_minmax_block(struct box *block,
assert(child->max_width != UNKNOWN_MAX_WIDTH);
if (child->style &&
- (child->style->position ==
+ (css_computed_position(child->style) ==
CSS_POSITION_ABSOLUTE ||
- child->style->position ==
+ css_computed_position(child->style) ==
CSS_POSITION_FIXED)) {
/* This child is positioned out of normal flow,
* so it will have no affect on width */
@@ -708,18 +737,16 @@ void layout_minmax_block(struct box *block,
}
/* fixed width takes priority */
- if (block->type != BOX_TABLE_CELL &&
- block->style->width.width == CSS_WIDTH_LENGTH) {
- min = max = css_len2px(&block->style->width.value.length,
- block->style);
+ if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET &&
+ wunit != CSS_UNIT_PCT) {
+ min = max = FIXTOINT(nscss_len2px(width, wunit, block->style));
}
/* add margins, border, padding to min, max widths */
- if (block->gadget && (block->style->width.width == CSS_WIDTH_PERCENT ||
- (block->style->width.width == CSS_WIDTH_LENGTH &&
+ if (block->gadget && wtype == CSS_WIDTH_SET &&
(block->gadget->type == GADGET_SUBMIT ||
block->gadget->type == GADGET_RESET ||
- block->gadget->type == GADGET_BUTTON)))) {
+ block->gadget->type == GADGET_BUTTON)) {
/* some gadgets with specified width already include border and
* padding, so just get margin */
calculate_mbp_width(block->style, LEFT, true, false, false,
@@ -799,8 +826,8 @@ void layout_block_find_dimensions(int available_width, int viewport_height,
int height;
int *margin = box->margin;
int *padding = box->padding;
- int *border = box->border;
- struct css_style *style = box->style;
+ struct box_border *border = box->border;
+ const css_computed_style *style = box->style;
layout_find_dimensions(available_width, viewport_height, box, style,
&width, &height, &max_width, &min_width,
@@ -854,13 +881,13 @@ bool layout_apply_minmax_height(struct box *box, struct box *container)
bool updated = false;
/* Find containing block for percentage heights */
- if (box->style->position == CSS_POSITION_ABSOLUTE) {
+ if (css_computed_position(box->style) == CSS_POSITION_ABSOLUTE) {
/* Box is absolutely positioned */
assert(container);
containing_block = container;
} else if (box->float_container &&
- (box->style->float_ == CSS_FLOAT_LEFT ||
- box->style->float_ == CSS_FLOAT_RIGHT)) {
+ (css_computed_float(box->style) == CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
/* Box is a float */
assert(box->parent && box->parent->parent &&
box->parent->parent->parent);
@@ -875,72 +902,73 @@ bool layout_apply_minmax_height(struct box *box, struct box *container)
}
if (box->style) {
+ enum css_height htype = CSS_HEIGHT_AUTO;
+ css_fixed length = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ if (containing_block) {
+ htype = css_computed_height(containing_block->style,
+ &length, &unit);
+ }
+
/* max-height */
- switch (box->style->max_height.max_height) {
- case CSS_MAX_HEIGHT_LENGTH:
- h = css_len2px(&box->style->max_height.value.length,
- box->style);
- if (h < box->height) {
- box->height = h;
- updated = true;
- }
- break;
- case CSS_MAX_HEIGHT_PERCENT:
- if (containing_block &&
+ if (css_computed_max_height(box->style, &length, &unit) ==
+ CSS_MAX_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ if (containing_block &&
containing_block->height != AUTO &&
- (box->style->position ==
+ (css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.
- height == CSS_HEIGHT_LENGTH ||
- containing_block->style->height.
- height == CSS_HEIGHT_PERCENT))) {
- /* Box is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- h = box->style->max_height.value.percent *
+ htype == CSS_HEIGHT_SET)) {
+ /* Box is absolutely positioned or its
+ * containing block has a valid
+ * specified height. (CSS 2.1
+ * Section 10.5) */
+ h = FIXTOFLT(length) *
containing_block->height / 100;
+ if (h < box->height) {
+ box->height = h;
+ updated = true;
+ }
+ }
+ } else {
+ h = FIXTOINT(nscss_len2px(length, unit,
+ box->style));
if (h < box->height) {
box->height = h;
updated = true;
}
}
- break;
- default:
- break;
}
/* min-height */
- switch (box->style->min_height.min_height) {
- case CSS_MIN_HEIGHT_LENGTH:
- h = css_len2px(&box->style->min_height.value.length,
- box->style);
- if (h > box->height) {
- box->height = h;
- updated = true;
- }
- break;
- case CSS_MIN_HEIGHT_PERCENT:
- if (containing_block &&
+ if (css_computed_min_height(box->style, &length, &unit) ==
+ CSS_MIN_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ if (containing_block &&
containing_block->height != AUTO &&
- (box->style->position ==
+ (css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.
- height == CSS_HEIGHT_LENGTH ||
- containing_block->style->height.
- height == CSS_HEIGHT_PERCENT))) {
- /* Box is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- h = box->style->min_height.value.percent *
+ htype == CSS_HEIGHT_SET)) {
+ /* Box is absolutely positioned or its
+ * containing block has a valid
+ * specified height. (CSS 2.1
+ * Section 10.5) */
+ h = FIXTOFLT(length) *
containing_block->height / 100;
+ if (h > box->height) {
+ box->height = h;
+ updated = true;
+ }
+ }
+ } else {
+ h = FIXTOINT(nscss_len2px(length, unit,
+ box->style));
if (h > box->height) {
box->height = h;
updated = true;
}
}
- break;
- default:
- break;
}
}
return updated;
@@ -955,18 +983,24 @@ bool layout_apply_minmax_height(struct box *box, struct box *container)
void layout_block_add_scrollbar(struct box *box, int which)
{
+ enum css_overflow overflow;
+
assert(box->type == BOX_BLOCK && (which == RIGHT || which == BOTTOM));
- if (box->style && (box->style->overflow == CSS_OVERFLOW_SCROLL ||
- box->style->overflow == CSS_OVERFLOW_AUTO)) {
+ if (box->style == NULL)
+ return;
+
+ overflow = css_computed_overflow(box->style);
+
+ if (overflow == CSS_OVERFLOW_SCROLL || overflow == CSS_OVERFLOW_AUTO) {
/* make space for scrollbars, unless height/width are AUTO */
if (which == BOTTOM && box->height != AUTO &&
- (box->style->overflow == CSS_OVERFLOW_SCROLL ||
+ (overflow == CSS_OVERFLOW_SCROLL ||
box_hscrollbar_present(box))) {
box->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
if (which == RIGHT && box->width != AUTO &&
- (box->style->overflow == CSS_OVERFLOW_SCROLL ||
+ (overflow == CSS_OVERFLOW_SCROLL ||
box_vscrollbar_present(box))) {
box->width -= SCROLLBAR_WIDTH;
box->padding[RIGHT] += SCROLLBAR_WIDTH;
@@ -987,16 +1021,14 @@ void layout_block_add_scrollbar(struct box *box, int which)
* \param min_width Box min-width ( <=0 means no min-width to apply)
* \param margin[4] Current box margins. Updated with new box
* left / right margins
- * \param padding[4] Current box paddings. Updated with new box
- * left / right paddings
- * \param border[4] Current box border widths. Updated with new
- * box left / right border widths
+ * \param padding[4] Current box paddings.
+ * \param border[4] Current box border widths.
* \return New box width
*/
int layout_solve_width(int available_width, int width, int lm, int rm,
int max_width, int min_width,
- int margin[4], int padding[4], int border[4])
+ int margin[4], int padding[4], struct box_border border[4])
{
bool auto_width = false;
@@ -1013,8 +1045,9 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
if (margin[RIGHT] == AUTO) margin[RIGHT] = rm;
width = available_width -
- (margin[LEFT] + border[LEFT] + padding[LEFT] +
- padding[RIGHT] + border[RIGHT] + margin[RIGHT]);
+ (margin[LEFT] + border[LEFT].width +
+ padding[LEFT] + padding[RIGHT] +
+ border[RIGHT].width + margin[RIGHT]);
width = width < 0 ? 0 : width;
auto_width = true;
}
@@ -1032,8 +1065,8 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
if (!auto_width && margin[LEFT] == AUTO && margin[RIGHT] == AUTO) {
/* make the margins equal, centering the element */
margin[LEFT] = margin[RIGHT] = (available_width - lm - rm -
- (border[LEFT] + padding[LEFT] + width +
- padding[RIGHT] + border[RIGHT])) / 2;
+ (border[LEFT].width + padding[LEFT] + width +
+ padding[RIGHT] + border[RIGHT].width)) / 2;
if (margin[LEFT] < 0) {
margin[RIGHT] += margin[LEFT];
@@ -1044,14 +1077,16 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
} else if (!auto_width && margin[LEFT] == AUTO) {
margin[LEFT] = available_width - lm -
- (border[LEFT] + padding[LEFT] + width +
- padding[RIGHT] + border[RIGHT] + margin[RIGHT]);
+ (border[LEFT].width + padding[LEFT] + width +
+ padding[RIGHT] + border[RIGHT].width +
+ margin[RIGHT]);
margin[LEFT] = margin[LEFT] < lm ? lm : margin[LEFT];
} else if (!auto_width) {
/* margin-right auto or "over-constrained" */
margin[RIGHT] = available_width - rm -
- (margin[LEFT] + border[LEFT] + padding[LEFT] +
- width + padding[RIGHT] + border[RIGHT]);
+ (margin[LEFT] + border[LEFT].width +
+ padding[LEFT] + width + padding[RIGHT] +
+ border[RIGHT].width);
}
return width;
@@ -1070,14 +1105,15 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
*/
void layout_float_find_dimensions(int available_width,
- struct css_style *style, struct box *box)
+ const css_computed_style *style, struct box *box)
{
int width, height, max_width, min_width;
int *margin = box->margin;
int *padding = box->padding;
- int *border = box->border;
- int scrollbar_width = (style->overflow == CSS_OVERFLOW_SCROLL ||
- style->overflow == CSS_OVERFLOW_AUTO) ?
+ struct box_border *border = box->border;
+ int scrollbar_width =
+ (css_computed_overflow(style) == CSS_OVERFLOW_SCROLL ||
+ css_computed_overflow(style) == CSS_OVERFLOW_AUTO) ?
SCROLLBAR_WIDTH : 0;
layout_find_dimensions(available_width, -1, box, style, &width, &height,
@@ -1107,44 +1143,49 @@ void layout_float_find_dimensions(int available_width,
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_FILE ||
box->gadget->type == GADGET_TEXTAREA)) {
- struct css_length size;
+ css_fixed size = 0;
+ css_unit unit = CSS_UNIT_EM;
+
/* Give sensible dimensions to gadgets, with auto width/height,
* that don't shrink to fit contained text. */
assert(box->style);
- size.unit = CSS_UNIT_EM;
if (box->gadget->type == GADGET_TEXTBOX ||
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_FILE) {
if (width == AUTO) {
- size.value = 10;
- width = css_len2px(&size, box->style);
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
}
if (box->gadget->type == GADGET_FILE &&
height == AUTO) {
- size.value = 1.5;
- height = css_len2px(&size, box->style);
+ size = FLTTOFIX(1.5);
+ height = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
}
}
if (box->gadget->type == GADGET_TEXTAREA) {
if (width == AUTO) {
- size.value = 10;
- width = css_len2px(&size, box->style);
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
} else {
width -= scrollbar_width;
}
if (height == AUTO) {
- size.value = 4;
- height = css_len2px(&size, box->style);
+ size = INTTOFIX(4);
+ height = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
}
}
} else if (width == AUTO) {
/* CSS 2.1 section 10.3.5 */
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
@@ -1183,33 +1224,37 @@ void layout_float_find_dimensions(int available_width,
*/
void layout_find_dimensions(int available_width, int viewport_height,
- struct box *box, struct css_style *style,
+ struct box *box, const css_computed_style *style,
int *width, int *height, int *max_width, int *min_width,
- int margin[4], int padding[4], int border[4])
+ int margin[4], int padding[4], struct box_border border[4])
{
struct box *containing_block = NULL;
unsigned int i;
bool percentage;
if (width) {
- switch (style->width.width) {
- case CSS_WIDTH_LENGTH:
- *width = css_len2px(&style->width.value.length, style);
- break;
- case CSS_WIDTH_PERCENT:
- *width = (style->width.value.percent *
- available_width) / 100;
- break;
- case CSS_WIDTH_AUTO:
- default:
+ enum css_width wtype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ wtype = css_computed_width(style, &value, &unit);
+
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *width = (FIXTOFLT(value) * available_width)
+ / 100;
+ } else {
+ *width = FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ } else {
*width = AUTO;
- break;
}
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *width != AUTO) {
- percentage = style->width.width == CSS_WIDTH_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
layout_tweak_form_dimensions(box, percentage,
available_width, true, width);
@@ -1217,72 +1262,91 @@ void layout_find_dimensions(int available_width, int viewport_height,
}
if (height) {
- switch (style->height.height) {
- case CSS_HEIGHT_LENGTH:
- *height = css_len2px(&style->height.value.length,
- style);
- break;
- case CSS_HEIGHT_PERCENT:
- if (box->style->position == CSS_POSITION_ABSOLUTE) {
- /* Box is absolutely positioned */
- assert(box->float_container);
- containing_block = box->float_container;
- } else if (box->float_container &&
- box->style->position !=
- CSS_POSITION_ABSOLUTE &&
- (box->style->float_ ==
- CSS_FLOAT_LEFT ||
- box->style->float_ ==
- CSS_FLOAT_RIGHT)) {
- /* Box is a float */
- assert(box->parent && box->parent->parent &&
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ htype = css_computed_height(style, &value, &unit);
+
+ if (htype == CSS_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ enum css_height cbhtype;
+
+ if (css_computed_position(box->style) ==
+ CSS_POSITION_ABSOLUTE) {
+ /* Box is absolutely positioned */
+ assert(box->float_container);
+ containing_block = box->float_container;
+ } else if (box->float_container &&
+ css_computed_position(box->style) !=
+ CSS_POSITION_ABSOLUTE &&
+ (css_computed_float(box->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) ==
+ CSS_FLOAT_RIGHT)) {
+ /* Box is a float */
+ assert(box->parent &&
+ box->parent->parent &&
box->parent->parent->parent);
- containing_block = box->parent->parent->parent;
- } else if (box->parent && box->parent->type !=
- BOX_INLINE_CONTAINER) {
- /* Box is a block level element */
- containing_block = box->parent;
- } else if (box->parent && box->parent->type ==
- BOX_INLINE_CONTAINER) {
- /* Box is an inline block */
- assert(box->parent->parent);
- containing_block = box->parent->parent;
- }
- if (containing_block &&
+
+ containing_block =
+ box->parent->parent->parent;
+ } else if (box->parent && box->parent->type !=
+ BOX_INLINE_CONTAINER) {
+ /* Box is a block level element */
+ containing_block = box->parent;
+ } else if (box->parent && box->parent->type ==
+ BOX_INLINE_CONTAINER) {
+ /* Box is an inline block */
+ assert(box->parent->parent);
+ containing_block = box->parent->parent;
+ }
+
+ if (containing_block) {
+ css_fixed f = 0;
+ css_unit u = CSS_UNIT_PX;
+
+ cbhtype = css_computed_height(
+ containing_block->style,
+ &f, &u);
+ }
+
+ if (containing_block &&
containing_block->height != AUTO &&
- (box->style->position ==
+ (css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.
- height == CSS_HEIGHT_LENGTH ||
- containing_block->style->height.
- height == CSS_HEIGHT_PERCENT))) {
- /* Box is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- *height = style->height.value.percent *
- containing_block->height / 100;
- } else if ((!box->parent || !box->parent->parent) &&
- viewport_height >= 0) {
- /* If root element or it's child
- * (HTML or BODY) */
- *height = style->height.value.percent *
- viewport_height / 100;
+ cbhtype == CSS_HEIGHT_SET)) {
+ /* Box is absolutely positioned or its
+ * containing block has a valid
+ * specified height.
+ * (CSS 2.1 Section 10.5) */
+ *height = FIXTOFLT(value) *
+ containing_block->height /
+ 100;
+ } else if ((!box->parent ||
+ !box->parent->parent) &&
+ viewport_height >= 0) {
+ /* If root element or it's child
+ * (HTML or BODY) */
+ *height = FIXTOFLT(value) *
+ viewport_height / 100;
+ } else {
+ /* precentage height not permissible
+ * treat height as auto */
+ *height = AUTO;
+ }
} else {
- /* precentage height not permissible
- * treat height as auto */
- *height = AUTO;
+ *height = FIXTOINT(nscss_len2px(value, unit,
+ style));
}
- break;
- case CSS_HEIGHT_AUTO:
- default:
+ } else {
*height = AUTO;
- break;
}
/* specified gadget heights include borders and padding in
* some cases */
if (box->gadget && *height != AUTO) {
- percentage = style->height.height == CSS_HEIGHT_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
layout_tweak_form_dimensions(box, percentage,
available_width, false, height);
@@ -1290,53 +1354,60 @@ void layout_find_dimensions(int available_width, int viewport_height,
}
if (max_width) {
- switch (style->max_width.max_width) {
- case CSS_MAX_WIDTH_LENGTH:
- *max_width = css_len2px(&style->max_width.value.length,
- style);
- break;
- case CSS_MAX_WIDTH_PERCENT:
- *max_width = (style->max_width.value.percent *
- available_width) / 100;
- break;
- case CSS_MAX_WIDTH_NONE:
- default:
+ enum css_max_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ type = css_computed_max_width(style, &value, &unit);
+
+ if (type == CSS_MAX_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *max_width = (FIXTOFLT(value) *
+ available_width) / 100;
+ } else {
+ *max_width = FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ } else {
/* Inadmissible */
*max_width = -1;
- break;
}
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *max_width != -1) {
- percentage = style->max_width.max_width ==
- CSS_WIDTH_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
+
layout_tweak_form_dimensions(box, percentage,
available_width, true, max_width);
}
}
if (min_width) {
- switch (style->min_width.min_width) {
- case CSS_MIN_WIDTH_LENGTH:
- *min_width = css_len2px(&style->min_width.value.
- length, style);
- break;
- case CSS_MIN_WIDTH_PERCENT:
- *min_width = (style->min_width.value.percent *
+ enum css_min_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ type = css_computed_min_width(style, &value, &unit);
+
+ if (type == CSS_MIN_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *min_width = (FIXTOFLT(value) *
available_width) / 100;
- break;
- default:
+ } else {
+ *min_width = FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ } else {
/* Inadmissible */
*min_width = 0;
- break;
}
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *min_width != 0) {
- percentage = style->min_width.min_width ==
- CSS_WIDTH_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
+
layout_tweak_form_dimensions(box, percentage,
available_width, true, min_width);
}
@@ -1344,46 +1415,137 @@ void layout_find_dimensions(int available_width, int viewport_height,
for (i = 0; i != 4; i++) {
if (margin) {
- switch (style->margin[i].margin) {
- case CSS_MARGIN_LENGTH:
- margin[i] = css_len2px(&style->margin[i].
- value.length, style);
+ enum css_margin type = CSS_MARGIN_AUTO;;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ switch (i) {
+ case TOP:
+ type = css_computed_margin_top(style,
+ &value, &unit);
break;
- case CSS_MARGIN_PERCENT:
- margin[i] = available_width *
- style->margin[i].value.percent / 100;
+ case RIGHT:
+ type = css_computed_margin_right(style,
+ &value, &unit);
break;
- case CSS_MARGIN_AUTO:
- default:
- margin[i] = AUTO;
+ case BOTTOM:
+ type = css_computed_margin_bottom(style,
+ &value, &unit);
+ break;
+ case LEFT:
+ type = css_computed_margin_left(style,
+ &value, &unit);
break;
}
+
+ if (type == CSS_MARGIN_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ margin[i] = available_width *
+ FIXTOFLT(value) / 100;
+ } else {
+ margin[i] = FIXTOINT(nscss_len2px(value,
+ unit, style));
+ }
+ } else {
+ margin[i] = AUTO;
+ }
}
if (padding) {
- switch (style->padding[i].padding) {
- case CSS_PADDING_PERCENT:
- padding[i] = available_width *
- style->padding[i].value.
- percent / 100;
+ enum css_padding type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ switch (i) {
+ case TOP:
+ type = css_computed_padding_top(style,
+ &value, &unit);
break;
- case CSS_PADDING_LENGTH:
- default:
- padding[i] = css_len2px(&style->padding[i].
- value.length, style);
+ case RIGHT:
+ type = css_computed_padding_right(style,
+ &value, &unit);
+ break;
+ case BOTTOM:
+ type = css_computed_padding_bottom(style,
+ &value, &unit);
break;
+ case LEFT:
+ type = css_computed_padding_left(style,
+ &value, &unit);
+ break;
+ }
+
+ if (unit == CSS_UNIT_PCT) {
+ padding[i] = available_width *
+ FIXTOFLT(value) / 100;
+ } else {
+ padding[i] = FIXTOINT(nscss_len2px(value, unit,
+ style));
}
}
- if (border) {
- if (style->border[i].style == CSS_BORDER_STYLE_HIDDEN ||
- style->border[i].style ==
- CSS_BORDER_STYLE_NONE)
+ /* Table cell borders are populated in table.c */
+ if (border && box->type != BOX_TABLE_CELL) {
+ enum css_border_width wtype;
+ enum css_border_style bstyle = CSS_BORDER_STYLE_NONE;
+ enum css_border_color bcolor =
+ CSS_BORDER_COLOR_TRANSPARENT;
+ css_color color = 0;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ switch (i) {
+ case TOP:
+ wtype = css_computed_border_top_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_top_style(style);
+ bcolor = css_computed_border_top_color(style,
+ &color);
+ break;
+ case RIGHT:
+ wtype = css_computed_border_right_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_right_style(style);
+ bcolor = css_computed_border_right_color(style,
+ &color);
+ break;
+ case BOTTOM:
+ wtype = css_computed_border_bottom_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_bottom_style(
+ style);
+ bcolor = css_computed_border_bottom_color(style,
+ &color);
+ break;
+ case LEFT:
+ wtype = css_computed_border_left_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_left_style(style);
+ bcolor = css_computed_border_left_color(style,
+ &color);
+ break;
+ }
+
+ border[i].style = bstyle;
+ border[i].color = bcolor;
+ border[i].c = color;
+
+ if (bstyle == CSS_BORDER_STYLE_HIDDEN ||
+ bstyle == CSS_BORDER_STYLE_NONE)
/* spec unclear: following Mozilla */
- border[i] = 0;
+ border[i].width = 0;
else
- border[i] = css_len2px(&style->border[i].
- width.value, style);
+ border[i].width = FIXTOINT(nscss_len2px(value,
+ unit, style));
+
+ /* Special case for border-collapse: make all borders
+ * on table/table-row-group/table-row zero width. */
+ if (css_computed_border_collapse(style) ==
+ CSS_BORDER_COLLAPSE_COLLAPSE &&
+ (box->type == BOX_TABLE ||
+ box->type == BOX_TABLE_ROW_GROUP ||
+ box->type == BOX_TABLE_ROW))
+ border[i].width = 0;
}
}
}
@@ -1435,7 +1597,7 @@ void layout_tweak_form_dimensions(struct box *box, bool percentage,
* \return y coordinate relative to ancestor box for floats
*/
-int layout_clear(struct box *fl, css_clear clear)
+int layout_clear(struct box *fl, enum css_clear clear)
{
int y = 0;
for (; fl; fl = fl->next_float) {
@@ -1522,13 +1684,17 @@ bool layout_inline_container(struct box *inline_container, int width,
has_text_children = false;
for (c = inline_container->children; c; c = c->next) {
bool is_pre = false;
- if (c->style)
- is_pre = (c->style->white_space ==
- CSS_WHITE_SPACE_PRE ||
- c->style->white_space ==
- CSS_WHITE_SPACE_PRE_LINE ||
- c->style->white_space ==
- CSS_WHITE_SPACE_PRE_WRAP);
+
+ if (c->style) {
+ enum css_white_space whitespace;
+
+ whitespace = css_computed_white_space(c->style);
+
+ is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
+ whitespace == CSS_WHITE_SPACE_PRE_LINE ||
+ whitespace == CSS_WHITE_SPACE_PRE_WRAP);
+ }
+
if ((!c->object && c->text && (c->length || is_pre)) ||
c->type == BOX_BR)
has_text_children = true;
@@ -1600,31 +1766,50 @@ void layout_minmax_inline_container(struct box *inline_container,
* Calculate line height from a style.
*/
-int line_height(struct css_style *style)
+int line_height(const css_computed_style *style)
{
- float font_len;
+ enum css_line_height lhtype;
+ css_fixed lhvalue = 0;
+ css_unit lhunit = CSS_UNIT_PX;
+ css_fixed line_height;
assert(style);
- assert(style->line_height.size == CSS_LINE_HEIGHT_LENGTH ||
- style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE ||
- style->line_height.size == CSS_LINE_HEIGHT_PERCENT);
- /* take account of minimum font size option */
- if ((font_len = css_len2px(&style->font_size.value.length, 0)) <
- option_font_min_size * css_screen_dpi / 720.0)
- font_len = option_font_min_size * css_screen_dpi / 720.0;
+ lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
+ if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
+ /* Normal => use a constant of 1.3 * font-size */
+ lhvalue = FLTTOFIX(1.3);
+ lhtype = CSS_LINE_HEIGHT_NUMBER;
+ }
- switch (style->line_height.size) {
- case CSS_LINE_HEIGHT_LENGTH:
- return css_len2px(&style->line_height.value.length, style);
+ if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
+ lhunit == CSS_UNIT_PCT) {
+ css_fixed fs = 0, px_fs;
+ css_unit fs_unit = CSS_UNIT_PX;
- case CSS_LINE_HEIGHT_ABSOLUTE:
- return style->line_height.value.absolute * font_len;
+ css_computed_font_size(style, &fs, &fs_unit);
- case CSS_LINE_HEIGHT_PERCENT:
- default:
- return style->line_height.value.percent * font_len / 100.0;
+ /* Convert to points */
+ fs = nscss_len2pt(fs, fs_unit);
+ fs_unit = CSS_UNIT_PT;
+
+ /* Clamp to configured minimum */
+ if (fs < FDIVI(INTTOFIX(option_font_min_size), 10))
+ fs = FDIVI(INTTOFIX(option_font_min_size), 10);
+
+ px_fs = nscss_len2px(fs, fs_unit, style);
+
+ if (lhtype == CSS_LINE_HEIGHT_NUMBER)
+ line_height = FMUL(lhvalue, px_fs);
+ else
+ line_height = FDIVI(FMUL(lhvalue, px_fs), 100);
+ } else {
+ assert(lhunit != CSS_UNIT_PCT);
+
+ line_height = nscss_len2px(lhvalue, lhunit, style);
}
+
+ return FIXTOINT(line_height);
}
@@ -1666,13 +1851,9 @@ bool layout_line(struct box *first, int *width, int *y,
int space_before = 0, space_after = 0;
unsigned int inline_count = 0;
unsigned int i;
- struct css_length gadget_size; /* Checkbox / radio buttons */
const struct font_functions *font_func = content->data.html.font_func;
plot_font_style_t fstyle;
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
-
LOG(("first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
first, (int) first->length, first->text, *width,
*y, cx, cy));
@@ -1706,6 +1887,11 @@ bool layout_line(struct box *first, int *width, int *y,
* keep in sync with the loop in layout_minmax_line() */
LOG(("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0));
for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
+ enum css_width wtype;
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
b->type == BOX_FLOAT_LEFT ||
b->type == BOX_FLOAT_RIGHT ||
@@ -1719,8 +1905,10 @@ bool layout_line(struct box *first, int *width, int *y,
if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
continue;
if (b->type == BOX_INLINE_BLOCK &&
- (b->style->position == CSS_POSITION_ABSOLUTE ||
- b->style->position == CSS_POSITION_FIXED))
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED))
continue;
assert(b->style != NULL);
@@ -1732,13 +1920,15 @@ bool layout_line(struct box *first, int *width, int *y,
if (b->max_width != UNKNOWN_WIDTH)
if (!layout_float(b, *width, content))
return false;
- h = b->border[TOP] + b->padding[TOP] + b->height +
- b->padding[BOTTOM] + b->border[BOTTOM];
+ h = b->border[TOP].width + b->padding[TOP] + b->height +
+ b->padding[BOTTOM] +
+ b->border[BOTTOM].width;
if (height < h)
height = h;
- x += b->margin[LEFT] + b->border[LEFT] +
+ x += b->margin[LEFT] + b->border[LEFT].width +
b->padding[LEFT] + b->width +
- b->padding[RIGHT] + b->border[RIGHT] +
+ b->padding[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
space_after = 0;
continue;
@@ -1751,7 +1941,7 @@ bool layout_line(struct box *first, int *width, int *y,
for (i = 0; i != 4; i++)
if (b->margin[i] == AUTO)
b->margin[i] = 0;
- x += b->margin[LEFT] + b->border[LEFT] +
+ x += b->margin[LEFT] + b->border[LEFT].width +
b->padding[LEFT];
if (b->inline_end) {
b->inline_end->margin[RIGHT] = b->margin[RIGHT];
@@ -1760,7 +1950,8 @@ bool layout_line(struct box *first, int *width, int *y,
b->inline_end->border[RIGHT] =
b->border[RIGHT];
} else {
- x += b->padding[RIGHT] + b->border[RIGHT] +
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
}
} else if (b->type == BOX_INLINE_END) {
@@ -1772,7 +1963,7 @@ bool layout_line(struct box *first, int *width, int *y,
} else {
space_after = 0;
}
- x += b->padding[RIGHT] + b->border[RIGHT] +
+ x += b->padding[RIGHT] + b->border[RIGHT].width +
b->margin[RIGHT];
continue;
}
@@ -1838,32 +2029,27 @@ bool layout_line(struct box *first, int *width, int *y,
assert(b->style);
/* calculate box width */
- switch (b->style->width.width) {
- case CSS_WIDTH_LENGTH:
- b->width = css_len2px(&b->style->width.value.length,
- b->style);
- break;
- case CSS_WIDTH_PERCENT:
- b->width = *width * b->style->width.value.percent / 100;
- break;
- case CSS_WIDTH_AUTO:
- default:
+ wtype = css_computed_width(b->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ b->width = *width * FIXTOFLT(value) / 100;
+ } else {
+ b->width = FIXTOINT(nscss_len2px(value, unit,
+ b->style));
+ }
+ } else {
b->width = AUTO;
- break;
}
/* height */
- switch (b->style->height.height) {
- case CSS_HEIGHT_LENGTH:
- b->height = css_len2px(&b->style->height.value.length,
- b->style);
- break;
- case CSS_HEIGHT_AUTO:
- default:
+ htype = css_computed_height(b->style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET) {
+ b->height = FIXTOINT(nscss_len2px(value, unit,
+ b->style));
+ } else {
b->height = AUTO;
- break;
}
-
+
if (b->object) {
if (b->width == AUTO && b->height == AUTO) {
b->width = b->object->width;
@@ -1886,15 +2072,20 @@ bool layout_line(struct box *first, int *width, int *y,
} else {
/* form control with no object */
if (b->width == AUTO)
- b->width = css_len2px(&gadget_size, b->style);
+ b->width = FIXTOINT(nscss_len2px(INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
if (b->height == AUTO)
- b->height = css_len2px(&gadget_size, b->style);
+ b->height = FIXTOINT(nscss_len2px(INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
}
if (b->object && b->object->type == CONTENT_HTML &&
b->width != b->object->available_width) {
+ htype = css_computed_height(b->style, &value, &unit);
+
content_reformat(b->object, b->width, b->height);
- if (b->style->height.height == CSS_HEIGHT_AUTO)
+
+ if (htype == CSS_HEIGHT_AUTO)
b->height = b->object->height;
}
@@ -1925,8 +2116,10 @@ bool layout_line(struct box *first, int *width, int *y,
for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
LOG(("pass 2: b %p, x %i", b, x));
if (b->type == BOX_INLINE_BLOCK &&
- (b->style->position == CSS_POSITION_ABSOLUTE ||
- b->style->position == CSS_POSITION_FIXED)) {
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED)) {
b->x = x + space_after;
} else if (b->type == BOX_INLINE ||
@@ -1941,16 +2134,17 @@ bool layout_line(struct box *first, int *width, int *y,
if ((b->type == BOX_INLINE && !b->inline_end) ||
b->type == BOX_INLINE_BLOCK) {
- b->x += b->margin[LEFT] + b->border[LEFT];
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
x = b->x + b->padding[LEFT] + b->width +
b->padding[RIGHT] +
- b->border[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
} else if (b->type == BOX_INLINE) {
- b->x += b->margin[LEFT] + b->border[LEFT];
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
x = b->x + b->padding[LEFT] + b->width;
} else if (b->type == BOX_INLINE_END) {
- x += b->padding[RIGHT] + b->border[RIGHT] +
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
} else {
x += b->width;
@@ -1991,27 +2185,33 @@ bool layout_line(struct box *first, int *width, int *y,
if (!layout_float(d, *width, content))
return false;
- LOG(("%p : %d %d", d, d->margin[TOP], d->border[TOP]));
- d->x = d->margin[LEFT] + d->border[LEFT];
- d->y = d->margin[TOP] + d->border[TOP];
- b->width = d->margin[LEFT] + d->border[LEFT] +
+ LOG(("%p : %d %d", d, d->margin[TOP],
+ d->border[TOP].width));
+ d->x = d->margin[LEFT] + d->border[LEFT].width;
+ d->y = d->margin[TOP] + d->border[TOP].width;
+ b->width = d->margin[LEFT] + d->border[LEFT].width +
d->padding[LEFT] + d->width +
- d->padding[RIGHT] + d->border[RIGHT] +
+ d->padding[RIGHT] +
+ d->border[RIGHT].width +
d->margin[RIGHT];
- b->height = d->margin[TOP] + d->border[TOP] +
+ b->height = d->margin[TOP] + d->border[TOP].width +
d->padding[TOP] + d->height +
- d->padding[BOTTOM] + d->border[BOTTOM] +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
d->margin[BOTTOM];
if (b->width > (x1 - x0) - x)
place_below = true;
- if (d->style && (d->style->clear == CSS_CLEAR_NONE ||
- (d->style->clear == CSS_CLEAR_LEFT &&
- left == 0) ||
- (d->style->clear == CSS_CLEAR_RIGHT &&
- right == 0) ||
- (d->style->clear == CSS_CLEAR_BOTH &&
- left == 0 && right == 0)) &&
+ if (d->style && (css_computed_clear(d->style) ==
+ CSS_CLEAR_NONE ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_LEFT && left == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_RIGHT &&
+ right == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_BOTH &&
+ left == 0 && right == 0)) &&
(!place_below ||
(left == 0 && right == 0 && x == 0)) &&
cy >= cont->clear_level) {
@@ -2044,7 +2244,7 @@ bool layout_line(struct box *first, int *width, int *y,
place_float_below(b, *width,
cx, fy + height, cont);
- if (d->style && d->style->clear !=
+ if (d->style && css_computed_clear(d->style) !=
CSS_CLEAR_NONE) {
/* to be cleared below existing
* floats */
@@ -2054,7 +2254,7 @@ bool layout_line(struct box *first, int *width, int *y,
b->x = cx + *width - b->width;
fy = layout_clear(cont->float_children,
- d->style->clear);
+ css_computed_clear(d->style));
if (fy > cont->clear_level)
cont->clear_level = fy;
if (b->y < fy)
@@ -2221,7 +2421,7 @@ bool layout_line(struct box *first, int *width, int *y,
}
/* set positions */
- switch (first->parent->parent->style->text_align) {
+ switch (css_computed_text_align(first->parent->parent->style)) {
case CSS_TEXT_ALIGN_RIGHT:
x0 = x1 - x;
break;
@@ -2243,20 +2443,24 @@ bool layout_line(struct box *first, int *width, int *y,
}
if ((d->type == BOX_INLINE && (d->object || d->gadget)) ||
d->type == BOX_INLINE_BLOCK) {
- d->y = *y + d->border[TOP] + d->margin[TOP];
+ d->y = *y + d->border[TOP].width + d->margin[TOP];
}
if (d->type == BOX_INLINE_BLOCK) {
d->x += x0;
}
if (d->type == BOX_INLINE_BLOCK &&
- (d->style->position == CSS_POSITION_ABSOLUTE ||
- d->style->position == CSS_POSITION_FIXED))
+ (css_computed_position(d->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(d->style) ==
+ CSS_POSITION_FIXED))
continue;
if ((d->type == BOX_INLINE && (d->object || d->gadget)) ||
d->type == BOX_INLINE_BLOCK) {
- h = d->margin[TOP] + d->border[TOP] + d->padding[TOP] +
- d->height + d->padding[BOTTOM] +
- d->border[BOTTOM] + d->margin[BOTTOM];
+ h = d->margin[TOP] + d->border[TOP].width +
+ d->padding[TOP] + d->height +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
+ d->margin[BOTTOM];
if (used_height < h)
used_height = h;
}
@@ -2279,9 +2483,9 @@ bool layout_line(struct box *first, int *width, int *y,
}
/* handle clearance for br */
- if (br_box && br_box->style->clear != CSS_CLEAR_NONE) {
+ if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
int clear_y = layout_clear(cont->float_children,
- br_box->style->clear);
+ css_computed_clear(br_box->style));
if (used_height < clear_y - cy)
used_height = clear_y - cy;
}
@@ -2312,14 +2516,15 @@ struct box *layout_minmax_line(struct box *first,
float frac;
size_t i, j;
struct box *b;
- struct css_length gadget_size; /* Checkbox / radio buttons */
plot_font_style_t fstyle;
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
-
/* corresponds to the pass 1 loop in layout_line() */
for (b = first; b; b = b->next) {
+ enum css_width wtype;
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
b->type == BOX_FLOAT_LEFT ||
b->type == BOX_FLOAT_RIGHT ||
@@ -2444,34 +2649,28 @@ struct box *layout_minmax_line(struct box *first,
assert(b->style);
/* calculate box width */
- switch (b->style->width.width) {
- case CSS_WIDTH_LENGTH:
- width = css_len2px(&b->style->width.value.length,
- b->style);
- if (width < 0)
- width = 0;
- break;
- case CSS_WIDTH_PERCENT:
- /*
- b->width = width * b->style->width.value.percent / 100;
- break;
- */
- case CSS_WIDTH_AUTO:
- default:
+ wtype = css_computed_width(b->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ /*
+ b->width = width * FIXTOFLT(value) / 100
+ */
+ } else {
+ width = FIXTOINT(nscss_len2px(value, unit,
+ b->style));
+ if (width < 0)
+ width = 0;
+ }
+ } else {
width = AUTO;
- break;
}
/* height */
- switch (b->style->height.height) {
- case CSS_HEIGHT_LENGTH:
- height = css_len2px(&b->style->height.value.length,
- b->style);
- break;
- case CSS_HEIGHT_AUTO:
- default:
+ htype = css_computed_height(b->style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET) {
+ height = FIXTOINT(nscss_len2px(value, unit, b->style));
+ } else {
height = AUTO;
- break;
}
if (b->object) {
@@ -2494,7 +2693,8 @@ struct box *layout_minmax_line(struct box *first,
} else {
/* form control with no object */
if (width == AUTO)
- width = css_len2px(&gadget_size, b->style);
+ width = FIXTOINT(nscss_len2px(INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
}
if (min < width)
@@ -2522,15 +2722,17 @@ struct box *layout_minmax_line(struct box *first,
* \return length of indent
*/
-int layout_text_indent(struct css_style *style, int width)
+int layout_text_indent(const css_computed_style *style, int width)
{
- switch (style->text_indent.size) {
- case CSS_TEXT_INDENT_LENGTH:
- return css_len2px(&style->text_indent.value.length, style);
- case CSS_TEXT_INDENT_PERCENT:
- return width * style->text_indent.value.percent / 100;
- default:
- return 0;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ css_computed_text_indent(style, &value, &unit);
+
+ if (unit == CSS_UNIT_PCT) {
+ return width * FIXTOFLT(value) / 100;
+ } else {
+ return FIXTOINT(nscss_len2px(value, unit, style));
}
}
@@ -2644,7 +2846,11 @@ bool layout_table(struct box *table, int available_width,
struct box *row_group;
struct box **row_span_cell;
struct column *col;
- struct css_style *style = table->style;
+ const css_computed_style *style = table->style;
+ enum css_width wtype;
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
assert(table->type == BOX_TABLE);
assert(style);
@@ -2676,12 +2882,13 @@ bool layout_table(struct box *table, int available_width,
for (row = row_group->children; row; row = row->next) {
for (c = row->children; c; c = c->next) {
assert(c->style);
+ table_used_border_for_cell(c);
layout_find_dimensions(available_width, -1,
c, c->style, 0, 0, 0, 0, 0,
c->padding, c->border);
- if (c->style->overflow ==
+ if (css_computed_overflow(c->style) ==
CSS_OVERFLOW_SCROLL ||
- c->style->overflow ==
+ css_computed_overflow(c->style) ==
CSS_OVERFLOW_AUTO) {
c->padding[RIGHT] += SCROLLBAR_WIDTH;
c->padding[BOTTOM] += SCROLLBAR_WIDTH;
@@ -2691,92 +2898,104 @@ bool layout_table(struct box *table, int available_width,
}
/* border-spacing is used in the separated borders model */
- if (style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE) {
- border_spacing_h = css_len2px(&style->border_spacing.horz,
- style);
- border_spacing_v = css_len2px(&style->border_spacing.vert,
- style);
- }
+ if (css_computed_border_collapse(style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
- /* find specified table width, or available width if auto-width */
- switch (style->width.width) {
- case CSS_WIDTH_LENGTH:
- table_width = css_len2px(&style->width.value.length, style);
+ css_computed_border_spacing(style, &h, &hu, &v, &vu);
- /* specified width includes border */
- table_width -= table->border[LEFT] + table->border[RIGHT];
- table_width = table_width < 0 ? 0 : table_width;
+ border_spacing_h = FIXTOINT(nscss_len2px(h, hu, style));
+ border_spacing_v = FIXTOINT(nscss_len2px(v, vu, style));
+ }
- auto_width = table_width;
- break;
- case CSS_WIDTH_PERCENT:
- table_width = ceil(available_width *
- style->width.value.percent / 100);
+ /* find specified table width, or available width if auto-width */
+ wtype = css_computed_width(style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ table_width = ceil(available_width *
+ FIXTOFLT(value) / 100);
+ } else {
+ table_width =
+ FIXTOINT(nscss_len2px(value, unit, style));
+ }
/* specified width includes border */
- table_width -= table->border[LEFT] + table->border[RIGHT];
+ table_width -= table->border[LEFT].width +
+ table->border[RIGHT].width;
table_width = table_width < 0 ? 0 : table_width;
auto_width = table_width;
- break;
- case CSS_WIDTH_AUTO:
- default:
+ } else {
table_width = AUTO;
auto_width = available_width -
((table->margin[LEFT] == AUTO ? 0 :
table->margin[LEFT]) +
- table->border[LEFT] +
+ table->border[LEFT].width +
table->padding[LEFT] +
table->padding[RIGHT] +
- table->border[RIGHT] +
+ table->border[RIGHT].width +
(table->margin[RIGHT] == AUTO ? 0 :
table->margin[RIGHT]));
- break;
}
/* Find any table height specified within CSS/HTML */
- if (style->height.height == CSS_HEIGHT_LENGTH) {
- /* This is the minimum height for the table (see 17.5.3) */
- min_height = css_len2px(&style->height.value.length, style);
- } else if (style->height.height == CSS_HEIGHT_PERCENT) {
- /* This is the minimum height for the table (see 17.5.3) */
- if (table->style->position == CSS_POSITION_ABSOLUTE) {
- /* Table is absolutely positioned */
- assert(table->float_container);
- containing_block = table->float_container;
- } else if (table->float_container &&
- table->style->position !=
- CSS_POSITION_ABSOLUTE &&
- (table->style->float_ ==
- CSS_FLOAT_LEFT ||
- table->style->float_ ==
- CSS_FLOAT_RIGHT)) {
- /* Table is a float */
- assert(table->parent && table->parent->parent &&
- table->parent->parent->parent);
- containing_block = table->parent->parent->parent;
- } else if (table->parent && table->parent->type !=
- BOX_INLINE_CONTAINER) {
- /* Table is a block level element */
- containing_block = table->parent;
- } else if (table->parent && table->parent->type ==
- BOX_INLINE_CONTAINER) {
- /* Table is an inline block */
- assert(table->parent->parent);
- containing_block = table->parent->parent;
- }
- if (containing_block && containing_block->height != AUTO &&
- (table->style->position ==
- CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.height ==
- CSS_HEIGHT_LENGTH ||
- containing_block->style->height.height ==
- CSS_HEIGHT_PERCENT))) {
- /* Table is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- min_height = style->height.value.percent *
+ htype = css_computed_height(style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ /* This is the minimum height for the table
+ * (see 17.5.3) */
+ if (css_computed_position(table->style) ==
+ CSS_POSITION_ABSOLUTE) {
+ /* Table is absolutely positioned */
+ assert(table->float_container);
+ containing_block = table->float_container;
+ } else if (table->float_container &&
+ css_computed_position(table->style) !=
+ CSS_POSITION_ABSOLUTE &&
+ (css_computed_float(table->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(table->style) ==
+ CSS_FLOAT_RIGHT)) {
+ /* Table is a float */
+ assert(table->parent && table->parent->parent &&
+ table->parent->parent->parent);
+ containing_block =
+ table->parent->parent->parent;
+ } else if (table->parent && table->parent->type !=
+ BOX_INLINE_CONTAINER) {
+ /* Table is a block level element */
+ containing_block = table->parent;
+ } else if (table->parent && table->parent->type ==
+ BOX_INLINE_CONTAINER) {
+ /* Table is an inline block */
+ assert(table->parent->parent);
+ containing_block = table->parent->parent;
+ }
+
+ if (containing_block) {
+ css_fixed ignored = 0;
+
+ htype = css_computed_height(
+ containing_block->style,
+ &ignored, &unit);
+ }
+
+ if (containing_block &&
+ containing_block->height != AUTO &&
+ (css_computed_position(table->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ htype == CSS_HEIGHT_SET)) {
+ /* Table is absolutely positioned or its
+ * containing block has a valid specified
+ * height. (CSS 2.1 Section 10.5) */
+ min_height = FIXTOFLT(value) *
containing_block->height / 100;
+ }
+ } else {
+ /* This is the minimum height for the table
+ * (see 17.5.3) */
+ min_height = FIXTOINT(nscss_len2px(value, unit, style));
}
}
@@ -2950,20 +3169,21 @@ bool layout_table(struct box *table, int available_width,
int row_group_height = 0;
for (row = row_group->children; row; row = row->next) {
int row_height = 0;
- if (row->style->height.height == CSS_HEIGHT_LENGTH) {
- row_height = (int) css_len2px(&row->style->
- height.value.length,
- row->style);
+
+ htype = css_computed_height(row->style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) {
+ row_height = FIXTOINT(nscss_len2px(value, unit,
+ row->style));
}
for (c = row->children; c; c = c->next) {
assert(c->style);
c->width = xs[c->start_column + c->columns] -
xs[c->start_column] -
border_spacing_h -
- c->border[LEFT] -
+ c->border[LEFT].width -
c->padding[LEFT] -
c->padding[RIGHT] -
- c->border[RIGHT];
+ c->border[RIGHT].width;
c->float_children = 0;
c->height = AUTO;
@@ -2980,13 +3200,17 @@ bool layout_table(struct box *table, int available_width,
* until after vertical alignment is complete */
c->descendant_y0 = c->height;
c->descendant_y1 = c->padding[BOTTOM];
- if (c->style->height.height ==
- CSS_HEIGHT_LENGTH) {
+
+ htype = css_computed_height(c->style,
+ &value, &unit);
+
+ if (htype == CSS_HEIGHT_SET &&
+ unit != CSS_UNIT_PCT) {
/* some sites use height="1" or similar
* to attempt to make cells as small as
* possible, so treat it as a minimum */
- int h = (int) css_len2px(&c->style->
- height.value.length, c->style);
+ int h = FIXTOINT(nscss_len2px(value,
+ unit, c->style));
if (c->height < h)
c->height = h;
}
@@ -2994,24 +3218,25 @@ bool layout_table(struct box *table, int available_width,
*/
if (c->height < row_height)
c->height = row_height;
- c->x = xs[c->start_column] + c->border[LEFT];
- c->y = c->border[TOP];
+ c->x = xs[c->start_column] +
+ c->border[LEFT].width;
+ c->y = c->border[TOP].width;
for (i = 0; i != c->columns; i++) {
row_span[c->start_column + i] = c->rows;
excess_y[c->start_column + i] =
- c->border[TOP] +
+ c->border[TOP].width +
c->padding[TOP] +
c->height +
c->padding[BOTTOM] +
- c->border[BOTTOM];
+ c->border[BOTTOM].width;
row_span_cell[c->start_column + i] = 0;
}
row_span_cell[c->start_column] = c;
c->padding[BOTTOM] = -border_spacing_v -
- c->border[TOP] -
+ c->border[TOP].width -
c->padding[TOP] -
c->height -
- c->border[BOTTOM];
+ c->border[BOTTOM].width;
}
for (i = 0; i != columns; i++)
if (row_span[i] != 0)
@@ -3064,19 +3289,24 @@ bool layout_table(struct box *table, int available_width,
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
for (c = row->children; c; c = c->next) {
+ enum css_vertical_align vertical_align;
+
/* unextended bottom padding is in
* c->descendant_y1, and unextended
* cell height is in c->descendant_y0 */
spare_height = (c->padding[BOTTOM] -
c->descendant_y1) +
(c->height - c->descendant_y0);
- switch (c->style->vertical_align.type) {
+
+ vertical_align = css_computed_vertical_align(
+ c->style, &value, &unit);
+
+ switch (vertical_align) {
case CSS_VERTICAL_ALIGN_SUB:
case CSS_VERTICAL_ALIGN_SUPER:
case CSS_VERTICAL_ALIGN_TEXT_TOP:
case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
- case CSS_VERTICAL_ALIGN_LENGTH:
- case CSS_VERTICAL_ALIGN_PERCENT:
+ case CSS_VERTICAL_ALIGN_SET:
case CSS_VERTICAL_ALIGN_BASELINE:
/* todo: baseline alignment, for now
* just use ALIGN_TOP */
@@ -3094,7 +3324,6 @@ bool layout_table(struct box *table, int available_width,
layout_move_children(c, 0,
spare_height);
break;
- case CSS_VERTICAL_ALIGN_NOT_SET:
case CSS_VERTICAL_ALIGN_INHERIT:
assert(0);
break;
@@ -3134,6 +3363,9 @@ void layout_minmax_table(struct box *table,
float extra_frac = 0;
struct column *col = table->col;
struct box *row_group, *row, *cell;
+ enum css_width wtype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
/* check if the widths have already been calculated */
if (table->max_width != UNKNOWN_MAX_WIDTH)
@@ -3148,9 +3380,15 @@ void layout_minmax_table(struct box *table,
}
/* border-spacing is used in the separated borders model */
- if (table->style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE)
- border_spacing_h = css_len2px(&table->style->
- border_spacing.horz, table->style);
+ if (css_computed_border_collapse(table->style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
+
+ css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
+
+ border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style));
+ }
/* 1st pass: consider cells with colspan 1 only */
for (row_group = table->children; row_group; row_group =row_group->next)
@@ -3249,9 +3487,9 @@ void layout_minmax_table(struct box *table,
}
/* fixed width takes priority, unless it is too narrow */
- if (table->style->width.width == CSS_WIDTH_LENGTH) {
- int width = css_len2px(&table->style->width.value.length,
- table->style);
+ wtype = css_computed_width(table->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
+ int width = FIXTOINT(nscss_len2px(value, unit, table->style));
if (table_min < width)
table_min = width;
if (table_max < width)
@@ -3309,35 +3547,77 @@ void layout_move_children(struct box *box, int x, int y)
* \param frac increased by sum of fractional margin and padding
*/
-void calculate_mbp_width(struct css_style *style, unsigned int side,
+void calculate_mbp_width(const css_computed_style *style, unsigned int side,
bool margin, bool border, bool padding,
int *fixed, float *frac)
{
+ typedef uint8_t (*len_func)(const css_computed_style *style,
+ css_fixed *length, css_unit *unit);
+
+ static len_func margin_funcs[4] = {
+ css_computed_margin_top,
+ css_computed_margin_right,
+ css_computed_margin_bottom,
+ css_computed_margin_left
+ };
+ static len_func padding_funcs[4] = {
+ css_computed_padding_top,
+ css_computed_padding_right,
+ css_computed_padding_bottom,
+ css_computed_padding_left
+ };
+ static struct {
+ len_func width;
+ uint8_t (*style)(const css_computed_style *style);
+ } border_funcs[4] = {
+ { css_computed_border_top_width,
+ css_computed_border_top_style },
+ { css_computed_border_right_width,
+ css_computed_border_right_style },
+ { css_computed_border_bottom_width,
+ css_computed_border_bottom_style },
+ { css_computed_border_left_width,
+ css_computed_border_left_style }
+ };
+
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(style);
/* margin */
if (margin) {
- if (style->margin[side].margin == CSS_MARGIN_LENGTH)
- *fixed += css_len2px(&style->margin[side].value.length,
- style);
- else if (style->margin[side].margin == CSS_MARGIN_PERCENT)
- *frac += style->margin[side].value.percent * 0.01;
+ enum css_margin type;
+
+ type = margin_funcs[side](style, &value, &unit);
+ if (type == CSS_MARGIN_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *frac += FIXTOFLT(value) * 0.01;
+ } else {
+ *fixed += FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ }
}
/* border */
if (border) {
- if (style->border[side].style != CSS_BORDER_STYLE_NONE)
- *fixed += css_len2px(&style->border[side].width.value,
- style);
+ if (border_funcs[side].style(style) !=
+ CSS_BORDER_STYLE_NONE) {
+ border_funcs[side].width(style, &value, &unit);
+
+ *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ }
}
/* padding */
if (padding) {
- if (style->padding[side].padding == CSS_PADDING_LENGTH)
- *fixed += css_len2px(&style->padding[side].value.length,
- style);
- else if (style->padding[side].padding == CSS_PADDING_PERCENT)
- *frac += style->padding[side].value.percent * 0.01;
+ padding_funcs[side](style, &value, &unit);
+ if (unit == CSS_UNIT_PCT) {
+ *frac += FIXTOFLT(value) * 0.01;
+ } else {
+ *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ }
}
}
@@ -3424,7 +3704,8 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
continue;
/* If relatively positioned, get offsets */
- if (box->style && box->style->position == CSS_POSITION_RELATIVE)
+ if (box->style && css_computed_position(box->style) ==
+ CSS_POSITION_RELATIVE)
layout_compute_relative_offset(box, &x, &y);
else
x = y = 0;
@@ -3432,8 +3713,10 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
/* Adjust float coordinates.
* (note float x and y are relative to their block formatting
* context box and not their parent) */
- if (box->style && (box->style->float_ == CSS_FLOAT_LEFT ||
- box->style->float_ == CSS_FLOAT_RIGHT) &&
+ if (box->style && (css_computed_float(box->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) ==
+ CSS_FLOAT_RIGHT) &&
(fx != 0 || fy != 0)) {
/* box is a float and there is a float offset to
* apply */
@@ -3463,7 +3746,8 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
/* Ignore things we're not interested in. */
if (!box->style || (box->style &&
- box->style->position != CSS_POSITION_RELATIVE))
+ css_computed_position(box->style) !=
+ CSS_POSITION_RELATIVE))
continue;
box->x += x;
@@ -3498,10 +3782,12 @@ void layout_compute_relative_offset(struct box *box, int *x, int *y)
struct box *containing_block;
assert(box && box->parent && box->style &&
- box->style->position == CSS_POSITION_RELATIVE);
+ css_computed_position(box->style) ==
+ CSS_POSITION_RELATIVE);
- if (box->float_container && (box->style->float_ == CSS_FLOAT_LEFT ||
- box->style->float_ == CSS_FLOAT_RIGHT)) {
+ if (box->float_container && (css_computed_float(box->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
containing_block = box->float_container;
} else {
containing_block = box->parent;
@@ -3522,11 +3808,12 @@ void layout_compute_relative_offset(struct box *box, int *x, int *y)
/* over constrained => examine direction property
* of containing block */
if (containing_block->style) {
- if (box->parent->style->direction ==
+ if (css_computed_direction(containing_block->style) ==
CSS_DIRECTION_LTR)
/* left wins */
right = -left;
- else if (box->parent->style->direction ==
+ else if (css_computed_direction(
+ containing_block->style) ==
CSS_DIRECTION_RTL)
/* right wins */
left = -right;
@@ -3576,21 +3863,25 @@ bool layout_position_absolute(struct box *box,
for (c = box->children; c; c = c->next) {
if ((c->type == BOX_BLOCK || c->type == BOX_TABLE ||
c->type == BOX_INLINE_BLOCK) &&
- (c->style->position == CSS_POSITION_ABSOLUTE ||
- c->style->position == CSS_POSITION_FIXED)) {
+ (css_computed_position(c->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(c->style) ==
+ CSS_POSITION_FIXED)) {
if (!layout_absolute(c, containing_block,
cx, cy, content))
return false;
if (!layout_position_absolute(c, c, 0, 0, content))
return false;
- } else if (c->style &&
- c->style->position == CSS_POSITION_RELATIVE) {
+ } else if (c->style && css_computed_position(c->style) ==
+ CSS_POSITION_RELATIVE) {
if (!layout_position_absolute(c, c, 0, 0, content))
return false;
} else {
int px, py;
- if (c->style && (c->style->float_ == CSS_FLOAT_LEFT ||
- c->style->float_ == CSS_FLOAT_RIGHT)) {
+ if (c->style && (css_computed_float(c->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(c->style) ==
+ CSS_FLOAT_RIGHT)) {
/* Float x/y coords are relative to nearest
* ansestor with float_children, rather than
* relative to parent. Need to get x/y relative
@@ -3639,7 +3930,7 @@ bool layout_absolute(struct box *box, struct box *containing_block,
int width, height, max_width, min_width;
int *margin = box->margin;
int *padding = box->padding;
- int *border = box->border;
+ struct box_border *border = box->border;
int available_width = containing_block->width;
int space;
@@ -3680,8 +3971,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
/* 10.3.7 */
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- left, margin[LEFT], border[LEFT], padding[LEFT], width,
- padding[RIGHT], border[RIGHT], margin[RIGHT], right,
+ left, margin[LEFT], border[LEFT].width,
+ padding[LEFT], width, padding[RIGHT],
+ border[RIGHT].width, margin[RIGHT], right,
containing_block->width));
if (left == AUTO && width == AUTO && right == AUTO) {
if (margin[LEFT] == AUTO)
@@ -3692,19 +3984,19 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
right = containing_block->width -
- left -
- margin[LEFT] - border[LEFT] - padding[LEFT] -
- width -
- padding[RIGHT] - border[RIGHT] - margin[RIGHT];
+ left -
+ margin[LEFT] - border[LEFT].width - padding[LEFT] -
+ width -
+ padding[RIGHT] - border[RIGHT].width - margin[RIGHT];
} else if (left != AUTO && width != AUTO && right != AUTO) {
/* Adjust for {min|max}-width */
@@ -3713,9 +4005,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
if (margin[LEFT] == AUTO && margin[RIGHT] == AUTO) {
space = containing_block->width -
- left - border[LEFT] -
+ left - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - right;
+ border[RIGHT].width - right;
if (space < 0) {
margin[LEFT] = 0;
margin[RIGHT] = space;
@@ -3724,19 +4016,22 @@ bool layout_absolute(struct box *box, struct box *containing_block,
}
} else if (margin[LEFT] == AUTO) {
margin[LEFT] = containing_block->width -
- left - border[LEFT] -
+ left - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
} else if (margin[RIGHT] == AUTO) {
margin[RIGHT] = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - right;
+ border[RIGHT].width - right;
} else {
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
}
} else {
if (margin[LEFT] == AUTO)
@@ -3749,9 +4044,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
@@ -3760,9 +4055,10 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
left = containing_block->width -
- margin[LEFT] - border[LEFT] -
+ margin[LEFT] - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
} else if (left == AUTO && width != AUTO && right == AUTO) {
/* Adjust for {min|max}-width */
@@ -3773,17 +4069,18 @@ bool layout_absolute(struct box *box, struct box *containing_block,
left = static_left;
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
} else if (left != AUTO && width == AUTO && right == AUTO) {
available_width -= left;
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
@@ -3792,9 +4089,10 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
} else if (left == AUTO && width != AUTO && right != AUTO) {
/* Adjust for {min|max}-width */
@@ -3804,14 +4102,17 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
left = containing_block->width -
- margin[LEFT] - border[LEFT] -
+ margin[LEFT] - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
} else if (left != AUTO && width == AUTO && right != AUTO) {
width = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
@@ -3828,17 +4129,19 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
}
}
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- left, margin[LEFT], border[LEFT], padding[LEFT], width,
- padding[RIGHT], border[RIGHT], margin[RIGHT], right,
+ left, margin[LEFT], border[LEFT].width, padding[LEFT],
+ width, padding[RIGHT], border[RIGHT].width,
+ margin[RIGHT], right,
containing_block->width));
- box->x = left + margin[LEFT] + border[LEFT] - cx;
+ box->x = left + margin[LEFT] + border[LEFT].width - cx;
if (containing_block->type == BOX_BLOCK ||
containing_block->type == BOX_INLINE_BLOCK ||
containing_block->type == BOX_TABLE_CELL) {
@@ -3865,8 +4168,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
/* 10.6.4 */
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- top, margin[TOP], border[TOP], padding[TOP], height,
- padding[BOTTOM], border[BOTTOM], margin[BOTTOM], bottom,
+ top, margin[TOP], border[TOP].width, padding[TOP],
+ height, padding[BOTTOM], border[BOTTOM].width,
+ margin[BOTTOM], bottom,
containing_block->height));
if (top == AUTO && height == AUTO && bottom == AUTO) {
top = static_top;
@@ -3876,33 +4180,33 @@ bool layout_absolute(struct box *box, struct box *containing_block,
if (margin[BOTTOM] == AUTO)
margin[BOTTOM] = 0;
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height - padding[BOTTOM] -
- border[BOTTOM] - margin[BOTTOM];
+ border[BOTTOM].width - margin[BOTTOM];
} else if (top != AUTO && height != AUTO && bottom != AUTO) {
if (margin[TOP] == AUTO && margin[BOTTOM] == AUTO) {
space = containing_block->height -
- top - border[TOP] - padding[TOP] -
+ top - border[TOP].width - padding[TOP] -
height - padding[BOTTOM] -
- border[BOTTOM] - bottom;
+ border[BOTTOM].width - bottom;
margin[TOP] = margin[BOTTOM] = space / 2;
} else if (margin[TOP] == AUTO) {
margin[TOP] = containing_block->height -
- top - border[TOP] - padding[TOP] -
+ top - border[TOP].width - padding[TOP] -
height - padding[BOTTOM] -
- border[BOTTOM] - margin[BOTTOM] -
+ border[BOTTOM].width - margin[BOTTOM] -
bottom;
} else if (margin[BOTTOM] == AUTO) {
margin[BOTTOM] = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
bottom;
} else {
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
}
} else {
@@ -3913,50 +4217,51 @@ bool layout_absolute(struct box *box, struct box *containing_block,
if (top == AUTO && height == AUTO && bottom != AUTO) {
height = box->height;
top = containing_block->height -
- margin[TOP] - border[TOP] -
+ margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM] - bottom;
} else if (top == AUTO && height != AUTO && bottom == AUTO) {
top = static_top;
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
} else if (top != AUTO && height == AUTO && bottom == AUTO) {
height = box->height;
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
} else if (top == AUTO && height != AUTO && bottom != AUTO) {
top = containing_block->height -
- margin[TOP] - border[TOP] -
+ margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM] - bottom;
} else if (top != AUTO && height == AUTO && bottom != AUTO) {
height = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - padding[BOTTOM] -
- border[BOTTOM] - margin[BOTTOM] -
+ border[BOTTOM].width - margin[BOTTOM] -
bottom;
} else if (top != AUTO && height != AUTO && bottom == AUTO) {
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
}
}
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- top, margin[TOP], border[TOP], padding[TOP], height,
- padding[BOTTOM], border[BOTTOM], margin[BOTTOM], bottom,
+ top, margin[TOP], border[TOP].width, padding[TOP],
+ height, padding[BOTTOM], border[BOTTOM].width,
+ margin[BOTTOM], bottom,
containing_block->height));
- box->y = top + margin[TOP] + border[TOP] - cy;
+ box->y = top + margin[TOP] + border[TOP].width - cy;
if (containing_block->type == BOX_BLOCK ||
containing_block->type == BOX_INLINE_BLOCK ||
containing_block->type == BOX_TABLE_CELL) {
@@ -3991,49 +4296,67 @@ void layout_compute_offsets(struct box *box,
struct box *containing_block,
int *top, int *right, int *bottom, int *left)
{
+ uint32_t type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(containing_block->width != UNKNOWN_WIDTH &&
containing_block->width != AUTO &&
containing_block->height != AUTO);
/* left */
- if (box->style->pos[LEFT].pos == CSS_POS_PERCENT)
- *left = ((box->style->pos[LEFT].value.percent *
- containing_block->width) / 100);
- else if (box->style->pos[LEFT].pos == CSS_POS_LENGTH)
- *left = css_len2px(&box->style->pos[LEFT].value.length,
- box->style);
- else
+ type = css_computed_left(box->style, &value, &unit);
+ if (type == CSS_LEFT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *left = (FIXTOFLT(value) *
+ containing_block->width) / 100;
+ } else {
+ *left = FIXTOINT(nscss_len2px(value, unit, box->style));
+ }
+ } else {
*left = AUTO;
+ }
/* right */
- if (box->style->pos[RIGHT].pos == CSS_POS_PERCENT)
- *right = ((box->style->pos[RIGHT].value.percent *
- containing_block->width) / 100);
- else if (box->style->pos[RIGHT].pos == CSS_POS_LENGTH)
- *right = css_len2px(&box->style->pos[RIGHT].value.length,
- box->style);
- else
+ type = css_computed_right(box->style, &value, &unit);
+ if (type == CSS_RIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *right = (FIXTOFLT(value) *
+ containing_block->width) / 100;
+ } else {
+ *right = FIXTOINT(nscss_len2px(value, unit,
+ box->style));
+ }
+ } else {
*right = AUTO;
+ }
/* top */
- if (box->style->pos[TOP].pos == CSS_POS_PERCENT)
- *top = ((box->style->pos[TOP].value.percent *
- containing_block->height) / 100);
- else if (box->style->pos[TOP].pos == CSS_POS_LENGTH)
- *top = css_len2px(&box->style->pos[TOP].value.length,
- box->style);
- else
+ type = css_computed_top(box->style, &value, &unit);
+ if (type == CSS_TOP_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *top = (FIXTOFLT(value) *
+ containing_block->height) / 100;
+ } else {
+ *top = FIXTOINT(nscss_len2px(value, unit, box->style));
+ }
+ } else {
*top = AUTO;
+ }
/* bottom */
- if (box->style->pos[BOTTOM].pos == CSS_POS_PERCENT)
- *bottom = ((box->style->pos[BOTTOM].value.percent *
- containing_block->height) / 100);
- else if (box->style->pos[BOTTOM].pos == CSS_POS_LENGTH)
- *bottom = css_len2px(&box->style->pos[BOTTOM].value.length,
- box->style);
- else
+ type = css_computed_bottom(box->style, &value, &unit);
+ if (type == CSS_BOTTOM_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *bottom = (FIXTOFLT(value) *
+ containing_block->height) / 100;
+ } else {
+ *bottom = FIXTOINT(nscss_len2px(value, unit,
+ box->style));
+ }
+ } else {
*bottom = AUTO;
+ }
}
@@ -4056,12 +4379,12 @@ void layout_calculate_descendant_bboxes(struct box *box)
assert(0);
}
- box->descendant_x0 = -box->border[LEFT];
- box->descendant_y0 = -box->border[TOP];
+ box->descendant_x0 = -box->border[LEFT].width;
+ box->descendant_y0 = -box->border[TOP].width;
box->descendant_x1 = box->padding[LEFT] + box->width +
- box->padding[RIGHT] + box->border[RIGHT];
+ box->padding[RIGHT] + box->border[RIGHT].width;
box->descendant_y1 = box->padding[TOP] + box->height +
- box->padding[BOTTOM] + box->border[BOTTOM];
+ box->padding[BOTTOM] + box->border[BOTTOM].width;
if (box->type == BOX_INLINE || box->type == BOX_TEXT)
return;
@@ -4103,7 +4426,8 @@ void layout_calculate_descendant_bboxes(struct box *box)
layout_calculate_descendant_bboxes(child);
- if (box->style && box->style->overflow == CSS_OVERFLOW_HIDDEN)
+ if (box->style && css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_HIDDEN)
continue;
if (child->x + child->descendant_x0 < box->descendant_x0)
diff --git a/render/list.c b/render/list.c
index 84b5beffc..8f951a857 100644
--- a/render/list.c
+++ b/render/list.c
@@ -57,9 +57,9 @@ static const int list_counter_decimal[] = { 1, 4, 5, 9,
/ sizeof(list_counter_decimal[0]))
-static struct list_counter *render_list_find_counter(char *name);
+static struct list_counter *render_list_find_counter(const char *name);
static char *render_list_encode_counter(struct list_counter_state *state,
- css_list_style_type style);
+ enum css_list_style_type style);
static char *render_list_encode_roman(int value);
/*
@@ -72,7 +72,7 @@ static void render_list_counter_output(char *name);
* \param name the name of the counter to find
* \return the counter, or NULL if it couldn't be found/created.
*/
-static struct list_counter *render_list_find_counter(char *name) {
+static struct list_counter *render_list_find_counter(const char *name) {
struct list_counter *counter;
assert(name);
@@ -131,7 +131,7 @@ void render_list_destroy_counters(void) {
* \param value the value to reset the counter to
* \return true on success, false on failure.
*/
-bool render_list_counter_reset(char *name, int value) {
+bool render_list_counter_reset(const char *name, int value) {
struct list_counter *counter;
struct list_counter_state *state;
struct list_counter_state *link;
@@ -166,7 +166,7 @@ bool render_list_counter_reset(char *name, int value) {
* \param value the value to increment the counter by
* \return true on success, false on failure.
*/
-bool render_list_counter_increment(char *name, int value) {
+bool render_list_counter_increment(const char *name, int value) {
struct list_counter *counter;
assert(name);
@@ -196,7 +196,7 @@ bool render_list_counter_increment(char *name, int value) {
* \param name the name of the counter to end the scope for
* \return true on success, false on failure.
*/
-bool render_list_counter_end_scope(char *name) {
+bool render_list_counter_end_scope(const char *name) {
struct list_counter *counter;
assert(name);
@@ -216,28 +216,40 @@ bool render_list_counter_end_scope(char *name) {
* \param css_counter the counter to convert
* \return a textual representation of the counter, or NULL on failure
*/
-char *render_list_counter(struct css_counter *css_counter) {
+char *render_list_counter(const css_computed_content_item *css_counter) {
struct list_counter *counter;
struct list_counter_state *state;
char *compound = NULL;
char *merge, *extend;
+ lwc_string *name = NULL, *sep = NULL;
+ uint8_t style;
assert(css_counter);
- counter = render_list_find_counter(css_counter->name);
+
+ if (css_counter->type == CSS_COMPUTED_CONTENT_COUNTER) {
+ name = css_counter->data.counter.name;
+ style = css_counter->data.counter.style;
+ } else {
+ assert(css_counter->type == CSS_COMPUTED_CONTENT_COUNTERS);
+
+ name = css_counter->data.counters.name;
+ sep = css_counter->data.counters.sep;
+ style = css_counter->data.counters.style;
+ }
+
+ counter = render_list_find_counter(lwc_string_data(name));
if (!counter) {
LOG(("Failed to find/create counter for conversion"));
return NULL;
}
/* handle counter() first */
- if (!css_counter->separator)
- return render_list_encode_counter(counter->state,
- css_counter->style);
+ if (sep == NULL)
+ return render_list_encode_counter(counter->state, style);
/* loop through all states for counters() */
for (state = counter->first; state; state = state->next) {
- merge = render_list_encode_counter(state,
- css_counter->style);
+ merge = render_list_encode_counter(state, style);
if (!merge) {
free(compound);
return NULL;
@@ -258,14 +270,14 @@ char *render_list_counter(struct css_counter *css_counter) {
}
if (state->next) {
merge = realloc(compound, strlen(compound) +
- strlen(css_counter->separator) + 1);
+ lwc_string_length(sep) + 1);
if (!merge) {
LOG(("No memory for realloc()"));
free(compound);
return NULL;
}
compound = merge;
- strcat(compound, css_counter->separator);
+ strcat(compound, lwc_string_data(sep));
}
}
return compound;
@@ -280,7 +292,7 @@ char *render_list_counter(struct css_counter *css_counter) {
* \return a textual representation of the counter state, or NULL on failure
*/
static char *render_list_encode_counter(struct list_counter_state *state,
- css_list_style_type style) {
+ enum css_list_style_type style) {
char *result = NULL;
int i;
@@ -338,10 +350,7 @@ static char *render_list_encode_counter(struct list_counter_state *state,
return NULL;
result[0] = '\0';
break;
- case CSS_LIST_STYLE_TYPE_INHERIT:
- case CSS_LIST_STYLE_TYPE_UNKNOWN:
- case CSS_LIST_STYLE_TYPE_NOT_SET:
- assert(0);
+ default:
break;
}
diff --git a/render/list.h b/render/list.h
index 5206a3cc6..626eb5941 100644
--- a/render/list.h
+++ b/render/list.h
@@ -25,11 +25,13 @@
#include <stdbool.h>
+#include "css/css.h"
+
void render_list_destroy_counters(void);
-bool render_list_counter_reset(char *name, int value);
-bool render_list_counter_increment(char *name, int value);
-bool render_list_counter_end_scope(char *name);
-char *render_list_counter(struct css_counter *css_counter);
+bool render_list_counter_reset(const char *name, int value);
+bool render_list_counter_increment(const char *name, int value);
+bool render_list_counter_end_scope(const char *name);
+char *render_list_counter(const css_computed_content_item *css_counter);
void render_list_test(void);
diff --git a/render/loosen.c b/render/loosen.c
deleted file mode 100644
index 85136d89b..000000000
--- a/render/loosen.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
- *
- * 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 <stdbool.h>
-#include <assert.h>
-
-#include "content/content.h"
-
-#include "render/box.h"
-#include "render/font.h"
-
-#include "render/layout.h"
-#include "render/loosen.h"
-
-#include "utils/log.h"
-#include "utils/talloc.h"
-
-#define AUTO INT_MIN
-#define LOOSEN_MIN_TEXT_SIZE 10
-
-static bool loosen_text(struct box *text, int width, struct content *content);
-
-static bool loosen_table(struct box *box, int available_width,
- struct content *content);
-
-static bool loosen_position_static(struct box *box, int width, int cx,
- struct content *content);
-
-static bool loosen_shrink_object(struct box *box, int width);
-
-static bool loosen_all_first_pass(struct box *box, int width, int cx,
- struct content *content);
-static bool loosen_all_second_pass(struct box *box, int width, int cx,
- struct content *content);
-static bool loosen_all_margins_paddings(struct box *box, int width, int cx,
- struct content *content);
-
-static bool loosen_shrink_text(struct box *box);
-
-/**
- * Main loosing procedure
- * \param content Reformated content - talloc memory pool for new boxes
- * \param layout Root of the loosened box tree
- * \param width Width the content is intended to fit
- * \param height Height of a single page - to be taken into consideration for \
- * preventing elements for being cropped at top/bottom edges of pages.
- * \return true if successful, false otherwise (lack of memory)
-*/
-bool loosen_document_layout(struct content *content, struct box *layout,
- int width, int height)
-{
- /* Optional try - if the current layout is not more than xx% too wide,
- * maybe we scale the content to preserve the original layout?
- */
-
- if (!loosen_all_first_pass(layout, width, 0, content))
- return false;
- layout->min_width = 0;
- layout->max_width = UNKNOWN_MAX_WIDTH;
- content_reformat(content, width, 0);
-
- /*Check if pass 1 was enough - if re-layouting doesn't give
- *us the right width, go on to pass 2. And again - if pass 2 was not
- *enough - go on to pass 3
- */
-
- if (content->width > width) {
- if (!loosen_all_second_pass(layout, width, 0, content))
- return false;
- layout->min_width = 0;
- layout->max_width = UNKNOWN_MAX_WIDTH;
- content_reformat(content, width, 0);
- }
-
- if (content->width > width) {
- if (!loosen_all_margins_paddings(layout, width, 0, content))
- return false;
- layout->min_width = 0;
- layout->max_width = UNKNOWN_MAX_WIDTH;
- content_reformat(content, width, 0);
- }
-
- return true;
-}
-
-/** Primarily - break too wide words into pieces.
- * \param text - the box that contains text to be broken
- * \param width Width the content is intended to fit
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
-*/
-bool loosen_text(struct box *text, int width, struct content *content)
-{
- size_t offset;
- int actual_x;
-
- int *breaks;
- int break_count, i;
-
- unsigned int position;
- const struct font_functions *font_func;
-
- plot_font_style_t fstyle;
-
- font_plot_style_from_css(text->style, &fstyle);
-
- if (content->type == CONTENT_HTML)
- font_func = content->data.html.font_func;
- else
- return false;
-
- if (text->width <= width) {
- LOG(("loosen_text called unnecessary?"));
- /*Still - not an error for this function*/
- return true;
- }
-
- breaks = malloc( sizeof(int) * text->length);
- if (breaks == NULL)
- return false;
-
- break_count = 0;
- position = 0;
-
- while (position < text->length) {
- font_func->font_position_in_string(&fstyle,
- text->text + position,
- text->length - position,
- width, &offset, &actual_x);
-
- if (offset < text->length - position) {
- /*Another break*/
- LOG(("Current text broken at offset %zu",
- position + offset));
- breaks[break_count++] = position + offset-1;
- }
-
- position += offset;
- }
-
- text->text = talloc_realloc(content, text->text, char,
- text->length + break_count);
-
- i = text->length-1;
- text->length = text->length + break_count;
-
- for (; i>=0; i--) {
- text->text[i + break_count] = text->text[i];
- if (i == breaks[break_count - 1]) {
- break_count--;
- text->text[i + break_count] = ' ';
- }
- }
-
- free(breaks);
-
- return true;
-}
-
-/**
- * Changing table layout and structure to fit the contents width.
- * Firstly the borders are collapsed and the text is shrunken.
- * Secondly the text is loosened( this can be helpful for all data tables which
- * contain only text)
- * In the most extreme case - the table has no influence on the width
- * (each row is broken into one-cell rows).
- * \param table - the box that contains table to be broken
- * \param width Width the content is intended to fit
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_table(struct box *table, int width, struct content *content)
-{
- struct box *row_group, *row, *cell, *br, *prev, *inline_container;
-
- struct box *text, *child;
- const struct font_functions *font_func;
- float scale;
- int new_width;
-
- if (table->min_width <= width)
- return true;
-
- if (content->type == CONTENT_HTML)
- font_func = content->data.html.font_func;
- else
- return false;
-
- table->style->border_collapse = CSS_BORDER_COLLAPSE_COLLAPSE;
-
- if (!loosen_shrink_text(table))
- return false;
-
- if (!loosen_all_margins_paddings(table, width, 0, content))
- return false;
-
- scale = width;
- scale /= table->min_width;
-
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (cell = row->children; cell; cell = cell->next) {
- for (child = cell->children; child;
- child = child->next) {
- if (child->children)
- text = child->children;
- else
- continue;
-
- /*text in nested boxes won't be broken*/
- if (text->type != BOX_TEXT)
- continue;
-
-
- /*break the words propotionally to the
- current cell width*/
- new_width = (float)cell->width * scale * 0.9;
- loosen_text(text, new_width, content);
- }
- }
- }
- }
-
-
- /*check if the table is loosend enough...*/
- layout_minmax_table(table, font_func);
- if (table->min_width <= width)
- return true;
-
-
- /*...in case it's not continue with bigger changes,
- table cells are changed into inline containers*/
- inline_container = box_create(0, 0, 0, 0, 0, content);
- inline_container->type = BOX_INLINE_CONTAINER;
- inline_container->parent = table;
- inline_container->style = talloc_memdup(content, table->style,
- sizeof *table->style);
-
- prev = NULL;
-
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
-
- for (cell = row->children; cell; cell = cell->next) {
- cell->type = BOX_INLINE_BLOCK;
- cell->prev = prev;
- cell->parent = inline_container;
- cell->max_width = width;
- cell->min_width = 0;
-
- if (prev!=NULL)
- prev->next = cell;
- else
- inline_container->children = cell;
-
- prev = cell;
- }
-
- br = box_create(0, 0, 0, 0, 0, content);
- br->type = BOX_BR;
- br->parent = inline_container;
- br->prev = prev;
- br->style = talloc_memdup(content, table->style,
- sizeof *table->style);
- br->style->clear = CSS_CLEAR_BOTH;
-
- if (prev != NULL)
- prev->next = br;
- else
- inline_container->children = br;
-
- prev = br;
- }
- }
- inline_container->last = prev;
-
- table->type = BOX_BLOCK;
- table->children = table->last = inline_container;
- table->col = NULL;
-
- return true;
-}
-
-/**
-* Recursively step through the box tree applying LOOSEN_MIN_TEXT_SIZE wherever
-* text is found
-* \param box the box where the shrinking should be started
-* \return true if successful, false otherwise
-*/
-bool loosen_shrink_text(struct box *box)
-{
- struct box *child;
-
- box->max_width = UNKNOWN_MAX_WIDTH;
-
- if (box->type == BOX_TEXT) {
- box->style->font_size.size = CSS_FONT_SIZE_LENGTH;
- box->style->font_size.value.length.unit = CSS_UNIT_PX;
- box->style->font_size.value.length.value = LOOSEN_MIN_TEXT_SIZE;
- }
- else if (box->children)
- for(child = box->children; child; child = child->next)
- if (!loosen_shrink_text(child))
- return false;
-
- return true;
-}
-
-
-/**
- * Change absolute and relative positioned elements into block elements
- * in case they are positioned to far to the rigth
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_position_static(struct box *box, int width, int cx,
- struct content *content)
-{
- assert(box->style);
-
- if (box->style->position == CSS_POSITION_ABSOLUTE) {
- box->style->position = CSS_POSITION_NOT_SET;
- }
-
- return true;
-}
-
-/**
- * Shrink an object (esp. an image) to fit the page-width
- * \note Not sure wheter it won't be better for images to be cropped
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \return true if successful, false otherwise
-*/
-bool loosen_shrink_object(struct box *box, int width)
-{
- assert(box->object != NULL);
-
- box->height = AUTO;
- box->width = width;
-
- if (box->style) {
- box->style->width.width = CSS_WIDTH_PERCENT;
- box->style->width.value.percent = 100;
- box->style->height.height= CSS_HEIGHT_AUTO;
- }
-
- return true;
-}
-
-/**
- * Pass 1 of loosening - do such obvious changes as: breaking too long words,
- * moving absolute positioned objects into the visibile scope of width.
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
-*/
-bool loosen_all_first_pass(struct box *box, int width, int cx,
- struct content *content)
-{
- struct box* c;
- int x;
-
- for (c = box->children; c ; c = c->next) {
- x = cx + c->x;
- if (c->children != NULL)
- if (!loosen_all_first_pass(c, width, x, content))
- return false;
-
- if (c->style) {
- if (c->style->position == CSS_POSITION_RELATIVE ||
- c->style->position == CSS_POSITION_ABSOLUTE )
- if (!loosen_position_static(c, width, cx, content))
- return false;
- if ( c->style->width.width == CSS_WIDTH_LENGTH &&
- css_len2px(&c->style->width.value.length, c->style) > width)
- c->style->width.width = CSS_WIDTH_NOT_SET;
- }
-
- if (c->object && c->width > width)
- if (!loosen_shrink_object(c, width))
- return false;
-
- if (c->type == BOX_TEXT) {
- if (!loosen_text(c, width, content))
- return false;
- }
-
- c->min_width = 0;
- c->max_width = UNKNOWN_MAX_WIDTH;
-
- }
-
- return true;
-}
-
-/**
- * Pass 2 of loosening - break tables
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_all_second_pass(struct box *box, int width, int cx,
- struct content *content)
-{
- struct box *c;
- int x;
-
- for (c = box->children; c; c = c->next) {
- x = cx + c->x;
- if (c->children != NULL)
- if (!loosen_all_second_pass(c, width, x, content))
- return false;
-
- switch (c->type) {
- case BOX_TABLE:
- if (!loosen_table(c, width, content))
- return false;
- break;
- default:
- break;
- }
-
- c->min_width = 0;
- c->max_width = UNKNOWN_MAX_WIDTH;
- }
-
- return true;
-}
-
-
-/**
- * Pass 3 of loosening -zero all margins and paddings
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_all_margins_paddings(struct box *box, int width, int cx,
- struct content *content)
-{
- struct box *c;
- int x;
-
- for (c = box->children; c; c = c->next) {
- x = cx + c->x;
- if (c->children != NULL)
- if (!loosen_all_margins_paddings(c, width, x, content))
- return false;
-
- c->padding[LEFT] = c->padding[RIGHT] = 0;
- c->margin[LEFT] = c->margin[RIGHT] = 0;
-
- if (c->style) {
- c->style->margin[LEFT].margin = CSS_MARGIN_PERCENT;
- c->style->margin[LEFT].value.percent = 0;
-
- c->style->margin[RIGHT].margin = CSS_MARGIN_PERCENT;
- c->style->margin[RIGHT].value.percent = 0;
-
- c->style->padding[LEFT].padding = CSS_PADDING_PERCENT;
- c->style->padding[LEFT].value.percent = 0;
-
- c->style->padding[RIGHT].padding = CSS_PADDING_PERCENT;
- c->style->padding[RIGHT].value.percent = 0;
-
- }
-
- c->min_width = 0;
- c->max_width = UNKNOWN_MAX_WIDTH;
-
- }
-
- return true;
-}
-
diff --git a/render/parser_binding.h b/render/parser_binding.h
index d50b4e3b9..1641058bd 100644
--- a/render/parser_binding.h
+++ b/render/parser_binding.h
@@ -39,6 +39,12 @@ typedef enum binding_encoding_source {
ENCODING_SOURCE_META
} binding_encoding_source;
+typedef enum binding_quirks_mode {
+ BINDING_QUIRKS_MODE_NONE,
+ BINDING_QUIRKS_MODE_LIMITED,
+ BINDING_QUIRKS_MODE_FULL
+} binding_quirks_mode;
+
binding_error binding_create_tree(void *arena, const char *charset, void **ctx);
binding_error binding_destroy_tree(void *ctx);
@@ -46,7 +52,7 @@ binding_error binding_parse_chunk(void *ctx, const uint8_t *data, size_t len);
binding_error binding_parse_completed(void *ctx);
const char *binding_get_encoding(void *ctx, binding_encoding_source *source);
-xmlDocPtr binding_get_document(void *ctx);
+xmlDocPtr binding_get_document(void *ctx, binding_quirks_mode *quirks);
struct form *binding_get_forms(void *ctx);
struct form_control *binding_get_control_for_node(void *ctx, xmlNodePtr node);
diff --git a/render/table.c b/render/table.c
index d3134f687..aad3e38c2 100644
--- a/render/table.c
+++ b/render/table.c
@@ -23,6 +23,7 @@
#include <assert.h>
#include "css/css.h"
+#include "css/utils.h"
#include "render/box.h"
#include "render/table.h"
#define NDEBUG
@@ -30,15 +31,29 @@
#undef NDEBUG
#include "utils/talloc.h"
-
-static void table_collapse_borders_h(struct box *parent, struct box *child,
- bool *first);
-static void table_collapse_borders_v(struct box *row, struct box *cell,
- unsigned int columns);
-static void table_collapse_borders_cell(struct box *cell, struct box *right,
- struct box *bottom);
-static void table_remove_borders(struct css_style *style);
-struct box *table_find_cell(struct box *table, unsigned int x, unsigned int y);
+/**
+ * Container for border values during table border calculations
+ */
+struct border {
+ enum css_border_style style; /**< border-style */
+ enum css_border_color color; /**< border-color type */
+ css_color c; /**< border-color value */
+ css_fixed width; /**< border-width length */
+ css_unit unit; /**< border-width units */
+};
+
+static void table_used_left_border_for_cell(struct box *cell);
+static void table_used_top_border_for_cell(struct box *cell);
+static void table_used_right_border_for_cell(struct box *cell);
+static void table_used_bottom_border_for_cell(struct box *cell);
+static bool table_border_is_more_eyecatching(const struct border *a,
+ box_type a_src, const struct border *b, box_type b_src);
+static void table_cell_top_process_table(struct box *table, struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_group(struct box *cell, struct box *group,
+ struct border *a, box_type *a_src);
+static bool table_cell_top_process_row(struct box *cell, struct box *row,
+ struct border *a, box_type *a_src);
/**
@@ -75,6 +90,10 @@ bool table_calculate_column_types(struct box *table)
for (row_group = table->children; row_group; row_group =row_group->next)
for (row = row_group->children; row; row = row->next)
for (cell = row->children; cell; cell = cell->next) {
+ enum css_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(cell->type == BOX_TABLE_CELL);
assert(cell->style);
@@ -82,17 +101,21 @@ bool table_calculate_column_types(struct box *table)
continue;
i = cell->start_column;
- if (cell->style->position != CSS_POSITION_ABSOLUTE &&
- cell->style->position != CSS_POSITION_FIXED) {
+ if (css_computed_position(cell->style) !=
+ CSS_POSITION_ABSOLUTE &&
+ css_computed_position(cell->style) !=
+ CSS_POSITION_FIXED) {
col[i].positioned = false;
}
+ type = css_computed_width(cell->style, &value, &unit);
+
/* fixed width takes priority over any other width type */
if (col[i].type != COLUMN_WIDTH_FIXED &&
- cell->style->width.width == CSS_WIDTH_LENGTH) {
+ type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_FIXED;
- col[i].width = css_len2px(&cell->style->
- width.value.length, cell->style);
+ col[i].width = FIXTOINT(nscss_len2px(value, unit,
+ cell->style));
if (col[i].width < 0)
col[i].width = 0;
continue;
@@ -101,12 +124,12 @@ bool table_calculate_column_types(struct box *table)
if (col[i].type != COLUMN_WIDTH_UNKNOWN)
continue;
- if (cell->style->width.width == CSS_WIDTH_PERCENT) {
+ if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_PERCENT;
- col[i].width = cell->style->width.value.percent;
+ col[i].width = FIXTOINT(value);
if (col[i].width < 0)
col[i].width = 0;
- } else if (cell->style->width.width == CSS_WIDTH_AUTO) {
+ } else if (type == CSS_WIDTH_AUTO) {
col[i].type = COLUMN_WIDTH_AUTO;
}
}
@@ -118,6 +141,9 @@ bool table_calculate_column_types(struct box *table)
unsigned int fixed_columns = 0, percent_columns = 0,
auto_columns = 0, unknown_columns = 0;
int fixed_width = 0, percent_width = 0;
+ enum css_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
if (cell->columns == 1)
continue;
@@ -145,14 +171,16 @@ bool table_calculate_column_types(struct box *table)
if (!unknown_columns)
continue;
+ type = css_computed_width(cell->style, &value, &unit);
+
/* if cell is fixed width, and all spanned columns are fixed
* or unknown width, split extra width among unknown columns */
- if (cell->style->width.width == CSS_WIDTH_LENGTH &&
+ if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT &&
fixed_columns + unknown_columns ==
cell->columns) {
- int width = (css_len2px(&cell->style->
- width.value.length, cell->style) -
- fixed_width) / unknown_columns;
+ int width = (FIXTOFLT(nscss_len2px(value, unit,
+ cell->style)) - fixed_width) /
+ unknown_columns;
if (width < 0)
width = 0;
for (j = 0; j != cell->columns; j++) {
@@ -164,10 +192,10 @@ bool table_calculate_column_types(struct box *table)
}
/* as above for percentage width */
- if (cell->style->width.width == CSS_WIDTH_PERCENT &&
+ if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT &&
percent_columns + unknown_columns ==
cell->columns) {
- int width = (cell->style->width.value.percent -
+ int width = (FIXTOFLT(value) -
percent_width) / unknown_columns;
if (width < 0)
width = 0;
@@ -195,212 +223,734 @@ bool table_calculate_column_types(struct box *table)
return true;
}
-
/**
- * Handle collapsing border model.
+ * Calculate used values of border-{trbl}-{style,color,width} for table cells.
*
- * \param table box of type BOX_TABLE
+ * \param cell Table cell to consider
+ *
+ * \post \a cell's border array is populated
*/
+void table_used_border_for_cell(struct box *cell)
+{
+ int side;
+
+ assert(cell->type == BOX_TABLE_CELL);
+
+ if (css_computed_border_collapse(cell->style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed width = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ /* Left border */
+ cell->border[LEFT].style =
+ css_computed_border_left_style(cell->style);
+ cell->border[LEFT].color =
+ css_computed_border_left_color(cell->style,
+ &cell->border[LEFT].c);
+ css_computed_border_left_width(cell->style, &width, &unit);
+ cell->border[LEFT].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+
+ /* Top border */
+ cell->border[TOP].style =
+ css_computed_border_top_style(cell->style);
+ cell->border[TOP].color =
+ css_computed_border_top_color(cell->style,
+ &cell->border[TOP].c);
+ css_computed_border_top_width(cell->style, &width, &unit);
+ cell->border[TOP].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+
+ /* Right border */
+ cell->border[RIGHT].style =
+ css_computed_border_right_style(cell->style);
+ cell->border[RIGHT].color =
+ css_computed_border_right_color(cell->style,
+ &cell->border[RIGHT].c);
+ css_computed_border_right_width(cell->style, &width, &unit);
+ cell->border[RIGHT].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+
+ /* Bottom border */
+ cell->border[BOTTOM].style =
+ css_computed_border_bottom_style(cell->style);
+ cell->border[BOTTOM].color =
+ css_computed_border_bottom_color(cell->style,
+ &cell->border[BOTTOM].c);
+ css_computed_border_bottom_width(cell->style, &width, &unit);
+ cell->border[BOTTOM].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+ } else {
+ /* Left border */
+ table_used_left_border_for_cell(cell);
+
+ /* Top border */
+ table_used_top_border_for_cell(cell);
+
+ /* Right border */
+ table_used_right_border_for_cell(cell);
+
+ /* Bottom border */
+ table_used_bottom_border_for_cell(cell);
+ }
+
+ /* Finally, ensure that any borders configured as
+ * hidden or none have zero width. (c.f. layout_find_dimensions) */
+ for (side = 0; side != 4; side++) {
+ if (cell->border[side].style == CSS_BORDER_STYLE_HIDDEN ||
+ cell->border[side].style ==
+ CSS_BORDER_STYLE_NONE)
+ cell->border[side].width = 0;
+ }
+}
+
+/******************************************************************************
+ * Helpers for used border calculations *
+ ******************************************************************************/
-void table_collapse_borders(struct box *table)
+/**
+ * Calculate used values of border-left-{style,color,width}
+ *
+ * \param cell Table cell to consider
+ */
+void table_used_left_border_for_cell(struct box *cell)
{
- bool first;
- unsigned int i, j;
- struct box *row_group, *row, *cell;
+ struct border a, b;
+ box_type a_src, b_src;
+
+ /** \todo Need column and column_group, too */
+
+ /* Initialise to computed left border for cell */
+ a.style = css_computed_border_left_style(cell->style);
+ a.color = css_computed_border_left_color(cell->style, &a.c);
+ css_computed_border_left_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ if (cell->prev != NULL || cell->start_column != 0) {
+ /* Cell to the left -- consider its right border */
+ struct box *prev = NULL;
+
+ if (cell->prev == NULL) {
+ struct box *row;
+
+ /* Spanned from a previous row */
+ for (row = cell->parent; row != NULL; row = row->prev) {
+ for (prev = row->children; prev != NULL;
+ prev = prev->next) {
+ if (prev->start_column +
+ prev->columns ==
+ cell->start_column)
+ break;
+ }
- assert(table->type == BOX_TABLE);
-
- /* 1st stage: collapse all borders down to the cells */
- first = true;
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- assert(row_group->type == BOX_TABLE_ROW_GROUP);
- assert(row_group->style);
- table_collapse_borders_h(table, row_group, &first);
- first = row_group->children != NULL;
- for (row = row_group->children; row; row = row->next) {
- assert(row->type == BOX_TABLE_ROW);
- assert(row->style);
- table_collapse_borders_h(row_group, row, &first);
- for (cell = row->children; cell; cell = cell->next) {
- assert(cell->type == BOX_TABLE_CELL);
- assert(cell->style);
- table_collapse_borders_v(row, cell,
- table->columns);
+ if (prev != NULL)
+ break;
}
- table_remove_borders(row->style);
+
+ assert(prev != NULL);
+ } else {
+ prev = cell->prev;
+ }
+
+ b.style = css_computed_border_right_style(prev->style);
+ b.color = css_computed_border_right_color(prev->style, &b.c);
+ css_computed_border_right_width(prev->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_CELL;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+ } else {
+ /* First cell in row, so consider rows and row group */
+ struct box *row = cell->parent;
+ struct box *group = row->parent;
+ struct box *table = group->parent;
+ unsigned int rows = cell->rows;
+
+ while (rows-- > 0 && row != NULL) {
+ /* Spanned rows -- consider their left border */
+ b.style = css_computed_border_left_style(row->style);
+ b.color = css_computed_border_left_color(
+ row->style, &b.c);
+ css_computed_border_left_width(
+ row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src,
+ &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ row = row->next;
+ }
+
+ /** \todo can cells span row groups? */
+
+ /* Row group -- consider its left border */
+ b.style = css_computed_border_left_style(group->style);
+ b.color = css_computed_border_left_color(group->style, &b.c);
+ css_computed_border_left_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ /* The table itself -- consider its left border */
+ b.style = css_computed_border_left_style(table->style);
+ b.color = css_computed_border_left_color(table->style, &b.c);
+ css_computed_border_left_width(table->style, &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
}
- table_remove_borders(row_group->style);
}
- table_remove_borders(table->style);
-
- /* 2nd stage: rather than building a grid of cells, we slowly look up the
- * cell we want to collapse with */
- for (i = 0; i < table->columns; i++) {
- for (j = 0; j < table->rows; j++) {
- table_collapse_borders_cell(
- table_find_cell(table, i, j),
- table_find_cell(table, i + 1, j),
- table_find_cell(table, i, j + 1));
+
+ /* a now contains the used left border for the cell */
+ cell->border[LEFT].style = a.style;
+ cell->border[LEFT].color = a.color;
+ cell->border[LEFT].c = a.c;
+ cell->border[LEFT].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
+
+/**
+ * Calculate used values of border-top-{style,color,width}
+ *
+ * \param cell Table cell to consider
+ */
+void table_used_top_border_for_cell(struct box *cell)
+{
+ struct border a, b;
+ box_type a_src, b_src;
+ struct box *row = cell->parent;
+ bool process_group = false;
+
+ /* Initialise to computed top border for cell */
+ a.style = css_computed_border_top_style(cell->style);
+ a.color = css_computed_border_top_color(cell->style, &a.c);
+ css_computed_border_top_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ /* Top border of row */
+ b.style = css_computed_border_top_style(row->style);
+ b.color = css_computed_border_top_color(row->style, &b.c);
+ css_computed_border_top_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ if (row->prev != NULL) {
+ /* Consider row(s) above */
+ while (table_cell_top_process_row(cell, row->prev,
+ &a, &a_src) == false) {
+ if (row->prev->prev == NULL) {
+ /* Consider row group */
+ process_group = true;
+ break;
+ } else {
+ row = row->prev;
+ }
}
+ } else {
+ process_group = true;
}
- /* 3rd stage: remove redundant borders */
- first = true;
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (cell = row->children; cell; cell = cell->next) {
- if (!first) {
- cell->style->border[TOP].style =
- CSS_BORDER_STYLE_NONE;
- cell->style->border[TOP].width.value.value =
- 0;
- cell->style->border[TOP].width.value.unit =
- CSS_UNIT_PX;
- }
- if (cell->start_column > 0) {
- cell->style->border[LEFT].style =
- CSS_BORDER_STYLE_NONE;
- cell->style->border[LEFT].width.value.value =
- 0;
- cell->style->border[LEFT].width.value.unit =
- CSS_UNIT_PX;
+ if (process_group) {
+ struct box *group = row->parent;
+
+ /* Top border of row group */
+ b.style = css_computed_border_top_style(group->style);
+ b.color = css_computed_border_top_color(group->style, &b.c);
+ css_computed_border_top_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ if (group->prev == NULL) {
+ /* Top border of table */
+ table_cell_top_process_table(group->parent, &a, &a_src);
+ } else {
+ /* Process previous group(s) */
+ while (table_cell_top_process_group(cell, group->prev,
+ &a, &a_src) == false) {
+ if (group->prev->prev == NULL) {
+ /* Top border of table */
+ table_cell_top_process_table(
+ group->parent,
+ &a, &a_src);
+ break;
+ } else {
+ group = group->prev;
}
}
- first = false;
}
}
-}
+ /* a now contains the used top border for the cell */
+ cell->border[TOP].style = a.style;
+ cell->border[TOP].color = a.color;
+ cell->border[TOP].c = a.c;
+ cell->border[TOP].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
/**
- * Collapse the borders of two boxes together.
+ * Calculate used values of border-right-{style,color,width}
+ *
+ * \param cell Table cell to consider
*/
-
-void table_collapse_borders_v(struct box *row, struct box *cell, unsigned int columns)
+void table_used_right_border_for_cell(struct box *cell)
{
- struct css_border *border;
+ struct border a, b;
+ box_type a_src, b_src;
+
+ /** \todo Need column and column_group, too */
+
+ /* Initialise to computed right border for cell */
+ a.style = css_computed_border_right_style(cell->style);
+ a.color = css_computed_border_right_color(cell->style, &a.c);
+ css_computed_border_right_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ if (cell->next != NULL || cell->start_column + cell->columns !=
+ cell->parent->parent->parent->columns) {
+ /* Cell is not at right edge of table -- no right border */
+ a.style = CSS_BORDER_STYLE_NONE;
+ a.width = 0;
+ a.unit = CSS_UNIT_PX;
+ } else {
+ /* Last cell in row, so consider rows and row group */
+ struct box *row = cell->parent;
+ struct box *group = row->parent;
+ struct box *table = group->parent;
+ unsigned int rows = cell->rows;
+
+ while (rows-- > 0 && row != NULL) {
+ /* Spanned rows -- consider their right border */
+ b.style = css_computed_border_right_style(row->style);
+ b.color = css_computed_border_right_color(
+ row->style, &b.c);
+ css_computed_border_right_width(
+ row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src,
+ &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
- if (cell->start_column == 0) {
- border = css_eyecatching_border(&row->style->border[LEFT], row->style,
- &cell->style->border[LEFT], cell->style);
- cell->style->border[LEFT] = *border;
- }
- border = css_eyecatching_border(&row->style->border[TOP], row->style,
- &cell->style->border[TOP], cell->style);
- cell->style->border[TOP] = *border;
- border = css_eyecatching_border(&row->style->border[BOTTOM], row->style,
- &cell->style->border[BOTTOM], cell->style);
- cell->style->border[BOTTOM] = *border;
- if ((cell->start_column + cell->columns) == columns) {
- border = css_eyecatching_border(&row->style->border[RIGHT], row->style,
- &cell->style->border[RIGHT], cell->style);
- cell->style->border[RIGHT] = *border;
+ row = row->next;
+ }
+
+ /** \todo can cells span row groups? */
+
+ /* Row group -- consider its right border */
+ b.style = css_computed_border_right_style(group->style);
+ b.color = css_computed_border_right_color(group->style, &b.c);
+ css_computed_border_right_width(group->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ /* The table itself -- consider its right border */
+ b.style = css_computed_border_right_style(table->style);
+ b.color = css_computed_border_right_color(table->style, &b.c);
+ css_computed_border_right_width(table->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
}
-}
+ /* a now contains the used right border for the cell */
+ cell->border[RIGHT].style = a.style;
+ cell->border[RIGHT].color = a.color;
+ cell->border[RIGHT].c = a.c;
+ cell->border[RIGHT].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
/**
- * Collapse the borders of two boxes together.
+ * Calculate used values of border-bottom-{style,color,width}
+ *
+ * \param cell Table cell to consider
*/
-
-void table_collapse_borders_h(struct box *parent, struct box *child, bool *first)
+void table_used_bottom_border_for_cell(struct box *cell)
{
- struct css_border *border;
+ struct border a, b;
+ box_type a_src, b_src;
+ struct box *row = cell->parent;
+ unsigned int rows = cell->rows;
+
+ /* Initialise to computed bottom border for cell */
+ a.style = css_computed_border_bottom_style(cell->style);
+ a.color = css_computed_border_bottom_color(cell->style, &a.c);
+ css_computed_border_bottom_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ while (rows-- > 0 && row != NULL)
+ row = row->next;
+
+ /** \todo Can cells span row groups? */
+
+ if (row != NULL) {
+ /* Cell is not at bottom edge of table -- no bottom border */
+ a.style = CSS_BORDER_STYLE_NONE;
+ a.width = 0;
+ a.unit = CSS_UNIT_PX;
+ } else {
+ /* Cell at bottom of table, so consider row and row group */
+ struct box *row = cell->parent;
+ struct box *group = row->parent;
+ struct box *table = group->parent;
+
+ /* Bottom border of row */
+ b.style = css_computed_border_bottom_style(row->style);
+ b.color = css_computed_border_bottom_color(row->style, &b.c);
+ css_computed_border_bottom_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
- if (*first) {
- border = css_eyecatching_border(&parent->style->border[TOP], parent->style,
- &child->style->border[TOP], child->style);
- child->style->border[TOP] = *border;
- *first = false;
- }
- border = css_eyecatching_border(&parent->style->border[LEFT], parent->style,
- &child->style->border[LEFT], child->style);
- child->style->border[LEFT] = *border;
- border = css_eyecatching_border(&parent->style->border[RIGHT], parent->style,
- &child->style->border[RIGHT], child->style);
- child->style->border[RIGHT] = *border;
- if (!child->next) {
- border = css_eyecatching_border(&parent->style->border[BOTTOM], parent->style,
- &child->style->border[BOTTOM], child->style);
- child->style->border[BOTTOM] = *border;
+ /* Row group -- consider its bottom border */
+ b.style = css_computed_border_bottom_style(group->style);
+ b.color = css_computed_border_bottom_color(group->style, &b.c);
+ css_computed_border_bottom_width(group->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ /* The table itself -- consider its bottom border */
+ b.style = css_computed_border_bottom_style(table->style);
+ b.color = css_computed_border_bottom_color(table->style, &b.c);
+ css_computed_border_bottom_width(table->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
}
-}
+ /* a now contains the used bottom border for the cell */
+ cell->border[BOTTOM].style = a.style;
+ cell->border[BOTTOM].color = a.color;
+ cell->border[BOTTOM].c = a.c;
+ cell->border[BOTTOM].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
/**
- * Collapse the borders of two boxes together.
+ * Determine if a border style is more eyecatching than another
+ *
+ * \param a Reference border style
+ * \param a_src Source of \a a
+ * \param b Candidate border style
+ * \param b_src Source of \a b
+ * \return True if \a b is more eyecatching than \a a
*/
+bool table_border_is_more_eyecatching(const struct border *a,
+ box_type a_src, const struct border *b, box_type b_src)
+{
+ css_fixed awidth, bwidth;
+ int impact = 0;
-void table_collapse_borders_cell(struct box *cell, struct box *right,
- struct box *bottom) {
- struct css_border *border;
+ /* See CSS 2.1 $17.6.2.1 */
- if (!cell)
- return;
+ /* 1 + 2 -- hidden beats everything, none beats nothing */
+ if (a->style == CSS_BORDER_STYLE_HIDDEN ||
+ b->style == CSS_BORDER_STYLE_NONE)
+ return false;
+
+ if (b->style == CSS_BORDER_STYLE_HIDDEN ||
+ a->style == CSS_BORDER_STYLE_NONE)
+ return true;
+
+ /* 3a -- wider borders beat narrow ones */
+ /* The widths must be absolute, which will be the case
+ * if they've come from a computed style. */
+ assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX);
+ assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX);
+ awidth = nscss_len2px(a->width, a->unit, NULL);
+ bwidth = nscss_len2px(b->width, b->unit, NULL);
- if ((right) && (right != cell)) {
- border = css_eyecatching_border(&cell->style->border[RIGHT], cell->style,
- &right->style->border[LEFT], right->style);
- cell->style->border[RIGHT] = *border;
+ if (awidth < bwidth)
+ return true;
+ else if (bwidth < awidth)
+ return false;
+ /* 3b -- sort by style */
+ switch (a->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 ((bottom) && (bottom != cell)) {
- border = css_eyecatching_border(&cell->style->border[BOTTOM], cell->style,
- &bottom->style->border[TOP], bottom->style);
- cell->style->border[BOTTOM] = *border;
+
+ switch (b->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 true;
+ else if (impact > 0)
+ return false;
+
+ /* 4a -- sort by origin */
+ impact = 0;
+
+ switch (a_src) {
+ case BOX_TABLE_CELL: impact++;
+ case BOX_TABLE_ROW: impact++;
+ case BOX_TABLE_ROW_GROUP: impact++;
+ /** \todo COL/COL_GROUP */
+ case BOX_TABLE: impact++;
+ default:
+ break;
+ }
+
+ switch (b_src) {
+ case BOX_TABLE_CELL: impact--;
+ case BOX_TABLE_ROW: impact--;
+ case BOX_TABLE_ROW_GROUP: impact--;
+ /** \todo COL/COL_GROUP */
+ case BOX_TABLE: impact--;
+ default:
+ break;
+ }
+
+ if (impact < 0)
+ return true;
+ else if (impact > 0)
+ return false;
+
+ /* 4b -- furthest left (if direction: ltr) and towards top wins */
+ /** \todo Currently assumes b satisifies this */
+ return true;
}
+/******************************************************************************
+ * Helpers for top border collapsing *
+ ******************************************************************************/
/**
- * Removes all borders.
+ * Process a table
+ *
+ * \param table Table to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
+ *
+ * \post \a a will be updated with most eyecatching style
+ * \post \a a_src will be updated also
*/
+void table_cell_top_process_table(struct box *table, struct border *a,
+ box_type *a_src)
+{
+ struct border b;
+ box_type b_src;
+
+ /* Top border of table */
+ b.style = css_computed_border_top_style(table->style);
+ b.color = css_computed_border_top_color(table->style, &b.c);
+ css_computed_border_top_width(table->style, &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
+}
-void table_remove_borders(struct css_style *style)
+/**
+ * Process a group
+ *
+ * \param cell Cell being considered
+ * \param group Group to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
+ * \return true if group has non-empty rows, false otherwise
+ *
+ * \post \a a will be updated with most eyecatching style
+ * \post \a a_src will be updated also
+ */
+bool table_cell_top_process_group(struct box *cell, struct box *group,
+ struct border *a, box_type *a_src)
{
- int i;
+ struct border b;
+ box_type b_src;
+
+ /* Bottom border of group */
+ b.style = css_computed_border_bottom_style(group->style);
+ b.color = css_computed_border_bottom_color(group->style, &b.c);
+ css_computed_border_bottom_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
- for (i = 0; i < 4; i++) {
- style->border[i].style = CSS_BORDER_STYLE_NONE;
- style->border[i].width.value.value = 0;
- style->border[i].width.value.unit = CSS_UNIT_PX;
+ if (group->last != NULL) {
+ /* Process rows in group, starting with last */
+ struct box *row = group->last;
+
+ while (table_cell_top_process_row(cell, row,
+ a, a_src) == false) {
+ if (row->prev == NULL) {
+ return false;
+ } else {
+ row = row->prev;
+ }
+ }
+ } else {
+ /* Group is empty, so consider its top border */
+ b.style = css_computed_border_top_style(group->style);
+ b.color = css_computed_border_top_color(group->style, &b.c);
+ css_computed_border_top_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
+
+ return false;
}
-}
+ return true;
+}
/**
- * Find a cell occupying a particular position in a table grid.
+ * Process a row
+ *
+ * \param cell Cell being considered
+ * \param row Row to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
+ * \return true if row has cells, false otherwise
+ *
+ * \post \a a will be updated with most eyecatching style
+ * \post \a a_src will be updated also
*/
-
-struct box *table_find_cell(struct box *table, unsigned int x,
- unsigned int y)
+bool table_cell_top_process_row(struct box *cell, struct box *row,
+ struct border *a, box_type *a_src)
{
- struct box *row_group, *row, *cell;
- unsigned int row_num = 0;
-
- if (table->columns <= x || table->rows <= y)
- return 0;
+ struct border b;
+ box_type b_src;
+
+ /* Bottom border of row */
+ b.style = css_computed_border_bottom_style(row->style);
+ b.color = css_computed_border_bottom_color(row->style, &b.c);
+ css_computed_border_bottom_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
- row_group = table->children;
- row = row_group->children;
+ if (row->children == NULL) {
+ /* Row is empty, so consider its top border */
+ b.style = css_computed_border_top_style(row->style);
+ b.color = css_computed_border_top_color(row->style, &b.c);
+ css_computed_border_top_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
- while (row_num != y) {
- if (row->next) {
- row = row->next;
- } else {
- row_group = row_group->next;
- row = row_group->children;
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
}
- row_num++;
- }
+ return false;
+ } else {
+ /* Process cells that are directly above the cell being
+ * considered. They may not be in this row, but in one of the
+ * rows above it in the case where rowspan > 1. */
+ struct box *c;
+ bool processed = false;
+
+ while (processed == false) {
+ for (c = row->children; c != NULL; c = c->next) {
+ /* Ignore cells to the left */
+ if (c->start_column + c->columns <
+ cell->start_column)
+ continue;
+ /* Ignore cells to the right */
+ if (c->start_column >= cell->start_column +
+ cell->columns)
+ continue;
+
+ /* Flag that we've processed a cell */
+ processed = true;
+
+ /* Consider bottom border */
+ b.style = css_computed_border_bottom_style(
+ c->style);
+ b.color = css_computed_border_bottom_color(
+ c->style, &b.c);
+ css_computed_border_bottom_width(c->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE_CELL;
+
+ if (table_border_is_more_eyecatching(a, *a_src,
+ &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
+ }
- for (cell = row->children; cell; cell = cell->next)
- if (cell->start_column <= x &&
- x < cell->start_column + cell->columns)
- break;
+ if (processed == false) {
+ /* There must be a preceding row */
+ assert(row->prev != NULL);
+
+ row = row->prev;
+ }
+ }
+ }
- return cell;
+ return true;
}
+
diff --git a/render/table.h b/render/table.h
index 9a83d6394..ecd3043b5 100644
--- a/render/table.h
+++ b/render/table.h
@@ -29,6 +29,6 @@
struct box;
bool table_calculate_column_types(struct box *table);
-void table_collapse_borders(struct box *table);
+void table_used_border_for_cell(struct box *cell);
#endif
diff --git a/render/textplain.c b/render/textplain.c
index dd3d168f9..256d9b8db 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -30,6 +30,7 @@
#include <iconv.h>
#include "content/content.h"
#include "css/css.h"
+#include "css/utils.h"
#include "desktop/gui.h"
#include "desktop/plotters.h"
#include "desktop/selection.h"
@@ -51,7 +52,7 @@
static plot_font_style_t textplain_style = {
.family = PLOT_FONT_FAMILY_MONOSPACE,
- .size = 10,
+ .size = 10 * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
@@ -69,7 +70,8 @@ static float textplain_line_height(void);
* Create a CONTENT_TEXTPLAIN.
*/
-bool textplain_create(struct content *c, const char *params[])
+bool textplain_create(struct content *c, struct content *parent,
+ const char *params[])
{
unsigned int i;
char *utf8_data;
@@ -733,6 +735,7 @@ float textplain_line_height(void)
/* Size is in points, so convert to pixels.
* Then use a constant line height of 1.2 x font size.
*/
- return (textplain_style.size * css_screen_dpi / 72) * 1.2;
+ return FIXTOFLT(FDIVI((FMUL(FLTTOFIX(1.2),
+ FMULI(nscss_screen_dpi, textplain_style.size))), 72));
}
diff --git a/render/textplain.h b/render/textplain.h
index 972405fe6..10609a71b 100644
--- a/render/textplain.h
+++ b/render/textplain.h
@@ -46,7 +46,8 @@ struct content_textplain_data {
int formatted_width;
};
-bool textplain_create(struct content *c, const char *params[]);
+bool textplain_create(struct content *c, struct content *parent,
+ const char *params[]);
bool textplain_process_data(struct content *c, char *data, unsigned int size);
bool textplain_convert(struct content *c, int width, int height);
void textplain_reformat(struct content *c, int width, int height);
diff --git a/riscos/font.c b/riscos/font.c
index eef02690f..a2cf561fb 100644
--- a/riscos/font.c
+++ b/riscos/font.c
@@ -28,6 +28,7 @@
#include "oslib/wimpreadsysinfo.h"
#include "rufl.h"
#include "css/css.h"
+#include "css/utils.h"
#include "render/font.h"
#include "riscos/gui.h"
#include "riscos/options.h"
@@ -235,6 +236,10 @@ bool nsfont_width(const plot_font_style_t *fstyle,
rufl_code code;
nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0) {
+ *width = 0;
+ return true;
+ }
code = rufl_width(font_family, font_style, font_size,
string, length,
@@ -277,6 +282,11 @@ bool nsfont_position_in_string(const plot_font_style_t *fstyle,
rufl_code code;
nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0) {
+ *char_offset = 0;
+ *actual_x = 0;
+ return true;
+ }
code = rufl_x_to_offset(font_family, font_style, font_size,
string, length,
@@ -324,6 +334,11 @@ bool nsfont_split(const plot_font_style_t *fstyle,
rufl_code code;
nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0) {
+ *char_offset = 0;
+ *actual_x = 0;
+ return true;
+ }
code = rufl_split(font_family, font_style, font_size,
string, length,
@@ -383,6 +398,8 @@ bool nsfont_paint(const plot_font_style_t *fstyle, const char *string,
rufl_code code;
nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+ if (font_size == 0)
+ return true;
code = rufl_paint(font_family, font_style, font_size * scale,
string, length, x, y,
@@ -426,8 +443,6 @@ void nsfont_read_style(const plot_font_style_t *fstyle,
};
*font_size = (fstyle->size * 16) / FONT_SIZE_SCALE;
- if (*font_size < option_font_min_size * 1.6)
- *font_size = option_font_min_size * 1.6;
if (1600 < *font_size)
*font_size = 1600;
diff --git a/riscos/gui.c b/riscos/gui.c
index 5d70a0d8f..594488341 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -154,6 +154,7 @@ extern int __dynamic_num;
const char * NETSURF_DIR;
char *default_stylesheet_url;
+char *quirks_stylesheet_url;
char *adblock_stylesheet_url;
static const char *task_name = "NetSurf";
@@ -409,8 +410,10 @@ void gui_init(int argc, char** argv)
/* Initialise stylesheet URLs */
default_stylesheet_url = strdup("file:///NetSurf:/Resources/CSS");
+ quirks_stylesheet_url = strdup("file:///NetSurf:/Resources/Quirks");
adblock_stylesheet_url = strdup("file:///NetSurf:/Resources/AdBlock");
- if (!default_stylesheet_url || !adblock_stylesheet_url)
+ if (!default_stylesheet_url || !quirks_stylesheet_url ||
+ !adblock_stylesheet_url)
die("Failed initialising string constants.");
/* Initialise filename allocator */
@@ -771,6 +774,7 @@ void gui_quit(void)
free(gui_sprites);
xwimp_close_down(task_handle);
free(default_stylesheet_url);
+ free(quirks_stylesheet_url);
free(adblock_stylesheet_url);
/* We don't care if this fails */
hubbub_finalise(myrealloc, NULL);
@@ -2283,9 +2287,6 @@ void ro_gui_dump_content(struct content *content)
case CONTENT_HTML:
box_dump(stream, content->data.html.layout, 0);
break;
- case CONTENT_CSS:
- css_dump_stylesheet(content->data.css.css);
- break;
default:
break;
}
diff --git a/riscos/image.h b/riscos/image.h
index f0bf2fdf9..a11388c13 100644
--- a/riscos/image.h
+++ b/riscos/image.h
@@ -20,7 +20,7 @@
#define _NETSURF_RISCOS_IMAGE_H_
#include <stdbool.h>
-#include "css/css.h"
+#include "desktop/plot_style.h"
#include "oslib/osspriteop.h"
struct osspriteop_area;
diff --git a/riscos/plugin.c b/riscos/plugin.c
index 742a099b7..5778e531b 100644
--- a/riscos/plugin.c
+++ b/riscos/plugin.c
@@ -183,7 +183,8 @@ static void plugin_fetch_callback(fetch_msg msg, void *p, const void *data,
* \param params Parameters associated with the content
* \return true on success, false otherwise
*/
-bool plugin_create(struct content *c, const char *params[])
+bool plugin_create(struct content *c, struct content *parent,
+ const char *params[])
{
LOG(("plugin_create"));
c->data.plugin.bw = 0;
diff --git a/riscos/plugin.h b/riscos/plugin.h
index 39c2d1b3d..6f288235a 100644
--- a/riscos/plugin.h
+++ b/riscos/plugin.h
@@ -52,7 +52,8 @@ struct content_plugin_data {
/* function definitions */
bool plugin_handleable(const char *mime_type);
void plugin_msg_parse(wimp_message *message, int ack);
-bool plugin_create(struct content *c, const char *params[]);
+bool plugin_create(struct content *c, struct content *parent,
+ const char *params[]);
bool plugin_convert(struct content *c, int width, int height);
void plugin_reformat(struct content *c, int width, int height);
void plugin_destroy(struct content *c);
diff --git a/riscos/save.c b/riscos/save.c
index e49ce319d..292c46194 100644
--- a/riscos/save.c
+++ b/riscos/save.c
@@ -626,8 +626,10 @@ void ro_gui_save_drag_end(wimp_dragged *drag)
while (!dest_ok && (box = box_at_point(box, pos.x, pos.y,
&box_x, &box_y, &content))) {
- if (box->style &&
- box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style &&
+ css_computed_visibility(
+ box->style) ==
+ CSS_VISIBILITY_HIDDEN)
continue;
if (box->gadget) {
diff --git a/riscos/save_complete.c b/riscos/save_complete.c
index 0e9e3845d..7342a7c20 100644
--- a/riscos/save_complete.c
+++ b/riscos/save_complete.c
@@ -120,17 +120,20 @@ bool save_complete_html(struct content *c, const char *path, bool index)
return true;
/* save stylesheets, ignoring the base and adblocking sheets */
- for (i = STYLESHEET_STYLE; i != c->data.html.stylesheet_count; i++) {
+ for (i = STYLESHEET_START; i != c->data.html.stylesheet_count; i++) {
struct content *css = c->data.html.stylesheet_content[i];
char *source;
int source_len;
+ bool is_style;
if (!css)
continue;
if (save_complete_list_check(css))
continue;
- if (i != STYLESHEET_STYLE) {
+ is_style = (strcmp(css->url, c->data.html.base_url) == 0);
+
+ if (is_style == false) {
if (!save_complete_list_add(css)) {
warn_user("NoMemory", 0);
return false;
@@ -140,7 +143,7 @@ bool save_complete_html(struct content *c, const char *path, bool index)
if (!save_imported_sheets(css, path))
return false;
- if (i == STYLESHEET_STYLE)
+ if (is_style)
continue; /* don't save <style> elements */
snprintf(spath, sizeof spath, "%s.%x", path,
@@ -262,7 +265,7 @@ bool save_imported_sheets(struct content *c, const char *path)
os_error *error;
for (j = 0; j != c->data.css.import_count; j++) {
- struct content *css = c->data.css.import_content[j];
+ struct content *css = c->data.css.imports[j];
if (!css)
continue;
diff --git a/riscos/textselection.c b/riscos/textselection.c
index 8da2d4e79..7b4578ad9 100644
--- a/riscos/textselection.c
+++ b/riscos/textselection.c
@@ -556,7 +556,8 @@ void ro_gui_selection_dragging(wimp_message *message)
while ((box = box_at_point(box, pos.x, pos.y,
&box_x, &box_y, &content))) {
- if (box->style && box->style->visibility ==
+ if (box->style &&
+ css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
continue;
diff --git a/riscos/window.c b/riscos/window.c
index d8637661b..764a014ed 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -2824,8 +2824,8 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message)
box_y = box->margin[TOP];
while ((box = box_at_point(box, pos.x, pos.y, &box_x, &box_y, &content))) {
- if (box->style &&
- box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
continue;
if (box->gadget) {
diff --git a/utils/config.h b/utils/config.h
index f46423ad7..e184c6964 100644
--- a/utils/config.h
+++ b/utils/config.h
@@ -34,6 +34,21 @@
char *strndup(const char *s, size_t n);
#endif
+#define HAVE_STRCASESTR
+#if !(defined(_GNU_SOURCE) || defined(__NetBSD__) || defined(__OpenBSD__)) \
+ || defined(riscos) || defined(__APPLE__)
+#undef HAVE_STRCASESTR
+char *strcasestr(const char *haystack, const char *needle);
+#endif
+
+#define HAVE_STRCHRNUL
+/* For some reason, UnixLib defines this unconditionally.
+ * Assume we're using UnixLib if building for RISC OS. */
+#if !(defined(_GNU_SOURCE) || defined(riscos))
+#undef HAVE_STRCHRNUL
+char *strchrnul(const char *s, int c);
+#endif
+
/* This section toggles build options on and off.
* Simply undefine a symbol to turn the relevant feature off.
*
diff --git a/utils/utils.c b/utils/utils.c
index ad76c5e30..ae58222b9 100644
--- a/utils/utils.c
+++ b/utils/utils.c
@@ -230,6 +230,26 @@ const char *rfc1123_date(time_t t)
}
/**
+ * Returns a number of centiseconds, that increases in real time, for the
+ * purposes of measuring how long something takes in wall-clock terms. It uses
+ * gettimeofday() for this. Should the call to gettimeofday() fail, it returns
+ * zero.
+ *
+ * \return number of centiseconds that increases monotonically
+ */
+unsigned int wallclock(void)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL) == -1)
+ return 0;
+
+ return ((tv.tv_sec * 100) + (tv.tv_usec / 10000));
+}
+
+#ifndef HAVE_STRCASESTR
+
+/**
* Case insensitive strstr implementation
*
* \param haystack String to search in
@@ -250,24 +270,7 @@ char *strcasestr(const char *haystack, const char *needle)
return NULL;
}
-/**
- * Returns a number of centiseconds, that increases in real time, for the
- * purposes of measuring how long something takes in wall-clock terms. It uses
- * gettimeofday() for this. Should the call to gettimeofday() fail, it returns
- * zero.
- *
- * \return number of centiseconds that increases monotonically
- */
-unsigned int wallclock(void)
-{
- struct timeval tv;
-
- if (gettimeofday(&tv, NULL) == -1)
- return 0;
-
- return ((tv.tv_sec * 100) + (tv.tv_usec / 10000));
-}
-
+#endif
#ifndef HAVE_STRNDUP
@@ -293,3 +296,147 @@ char *strndup(const char *s, size_t n)
}
#endif
+
+#ifndef HAVE_STRCHRNUL
+
+/**
+ * Find the first occurrence of C in S or the final NUL byte.
+ *
+ * \note This implementation came from glibc 2.2.5
+ */
+char *strchrnul (const char *s, int c_in)
+{
+ const unsigned char *char_ptr;
+ const unsigned long int *longword_ptr;
+ unsigned long int longword, magic_bits, charmask;
+ unsigned char c;
+
+ c = (unsigned char) c_in;
+
+ /* Handle the first few characters by reading one character at a time.
+ Do this until CHAR_PTR is aligned on a longword boundary. */
+ for (char_ptr = (const unsigned char *)s; ((unsigned long int) char_ptr
+ & (sizeof (longword) - 1)) != 0;
+ ++char_ptr)
+ if (*char_ptr == c || *char_ptr == '\0')
+ return (void *) char_ptr;
+
+ /* All these elucidatory comments refer to 4-byte longwords,
+ but the theory applies equally well to 8-byte longwords. */
+
+ longword_ptr = (unsigned long int *) char_ptr;
+
+ /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
+ the "holes." Note that there is a hole just to the left of
+ each byte, with an extra at the end:
+
+ bits: 01111110 11111110 11111110 11111111
+ bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
+
+ The 1-bits make sure that carries propagate to the next 0-bit.
+ The 0-bits provide holes for carries to fall into. */
+ switch (sizeof (longword))
+ {
+ case 4: magic_bits = 0x7efefeffL; break;
+ case 8: magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL; break;
+ default:
+ abort ();
+ }
+
+ /* Set up a longword, each of whose bytes is C. */
+ charmask = c | (c << 8);
+ charmask |= charmask << 16;
+ if (sizeof (longword) > 4)
+ /* Do the shift in two steps to avoid a warning if long has 32 bits. */
+ charmask |= (charmask << 16) << 16;
+ if (sizeof (longword) > 8)
+ abort ();
+
+ /* Instead of the traditional loop which tests each character,
+ we will test a longword at a time. The tricky part is testing
+ if *any of the four* bytes in the longword in question are zero. */
+ for (;;)
+ {
+ /* We tentatively exit the loop if adding MAGIC_BITS to
+ LONGWORD fails to change any of the hole bits of LONGWORD.
+
+ 1) Is this safe? Will it catch all the zero bytes?
+ Suppose there is a byte with all zeros. Any carry bits
+ propagating from its left will fall into the hole at its
+ least significant bit and stop. Since there will be no
+ carry from its most significant bit, the LSB of the
+ byte to the left will be unchanged, and the zero will be
+ detected.
+
+ 2) Is this worthwhile? Will it ignore everything except
+ zero bytes? Suppose every byte of LONGWORD has a bit set
+ somewhere. There will be a carry into bit 8. If bit 8
+ is set, this will carry into bit 16. If bit 8 is clear,
+ one of bits 9-15 must be set, so there will be a carry
+ into bit 16. Similarly, there will be a carry into bit
+ 24. If one of bits 24-30 is set, there will be a carry
+ into bit 31, so all of the hole bits will be changed.
+
+ The one misfire occurs when bits 24-30 are clear and bit
+ 31 is set; in this case, the hole at bit 31 is not
+ changed. If we had access to the processor carry flag,
+ we could close this loophole by putting the fourth hole
+ at bit 32!
+
+ So it ignores everything except 128's, when they're aligned
+ properly.
+
+ 3) But wait! Aren't we looking for C as well as zero?
+ Good point. So what we do is XOR LONGWORD with a longword,
+ each of whose bytes is C. This turns each byte that is C
+ into a zero. */
+
+ longword = *longword_ptr++;
+
+ /* Add MAGIC_BITS to LONGWORD. */
+ if ((((longword + magic_bits)
+
+ /* Set those bits that were unchanged by the addition. */
+ ^ ~longword)
+
+ /* Look at only the hole bits. If any of the hole bits
+ are unchanged, most likely one of the bytes was a
+ zero. */
+ & ~magic_bits) != 0 ||
+
+ /* That caught zeroes. Now test for C. */
+ ((((longword ^ charmask) + magic_bits) ^ ~(longword ^ charmask))
+ & ~magic_bits) != 0)
+ {
+ /* Which of the bytes was C or zero?
+ If none of them were, it was a misfire; continue the search. */
+
+ const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);
+
+ if (*cp == c || *cp == '\0')
+ return (char *) cp;
+ if (*++cp == c || *cp == '\0')
+ return (char *) cp;
+ if (*++cp == c || *cp == '\0')
+ return (char *) cp;
+ if (*++cp == c || *cp == '\0')
+ return (char *) cp;
+ if (sizeof (longword) > 4)
+ {
+ if (*++cp == c || *cp == '\0')
+ return (char *) cp;
+ if (*++cp == c || *cp == '\0')
+ return (char *) cp;
+ if (*++cp == c || *cp == '\0')
+ return (char *) cp;
+ if (*++cp == c || *cp == '\0')
+ return (char *) cp;
+ }
+ }
+ }
+
+ /* This should never happen. */
+ return NULL;
+}
+
+#endif
diff --git a/utils/utils.h b/utils/utils.h
index f2cd2e0dd..279bd73c8 100644
--- a/utils/utils.h
+++ b/utils/utils.h
@@ -82,10 +82,6 @@ void regcomp_wrapper(regex_t *preg, const char *regex, int cflags);
void unicode_transliterate(unsigned int c, char **r);
char *human_friendly_bytesize(unsigned long bytesize);
const char *rfc1123_date(time_t t);
-#if !(defined(_GNU_SOURCE) || defined(__NetBSD__) || defined(__OpenBSD__)) \
- || defined(riscos) || defined(__APPLE__)
-char *strcasestr(const char *haystack, const char *needle);
-#endif
unsigned int wallclock(void);
/**