From 144bd772403983ff1ea0baf8d37e339b89912394 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Tue, 28 Aug 2007 17:12:23 +0200 Subject: [PATCH] document/dom: Split rendering utilities to util.* These are functions that are commonly used by the individual renderers to put stuff on the canvas etc. --- src/document/dom/Makefile | 2 +- src/document/dom/renderer.c | 285 +----------------------------------- src/document/dom/util.c | 273 ++++++++++++++++++++++++++++++++++ src/document/dom/util.h | 64 ++++++++ 4 files changed, 339 insertions(+), 285 deletions(-) create mode 100644 src/document/dom/util.c create mode 100644 src/document/dom/util.h diff --git a/src/document/dom/Makefile b/src/document/dom/Makefile index 21f56d72c..38599dcc2 100644 --- a/src/document/dom/Makefile +++ b/src/document/dom/Makefile @@ -1,6 +1,6 @@ top_builddir=../../.. include $(top_builddir)/Makefile.config -OBJS = renderer.o +OBJS = renderer.o util.o include $(top_srcdir)/Makefile.lib diff --git a/src/document/dom/renderer.c b/src/document/dom/renderer.c index 6391ff82b..c66ce41fd 100644 --- a/src/document/dom/renderer.c +++ b/src/document/dom/renderer.c @@ -12,15 +12,14 @@ #include "elinks.h" -#include "bookmarks/bookmarks.h" /* get_bookmark() */ #include "cache/cache.h" #include "document/css/css.h" #include "document/css/parser.h" #include "document/css/property.h" #include "document/css/stylesheet.h" -#include "document/docdata.h" #include "document/document.h" #include "document/dom/renderer.h" +#include "document/dom/util.h" #include "document/renderer.h" #include "dom/configuration.h" #include "dom/scanner.h" @@ -30,60 +29,17 @@ #include "dom/node.h" #include "dom/stack.h" #include "intl/charsets.h" -#include "globhist/globhist.h" /* get_global_history_item() */ #include "protocol/uri.h" #include "terminal/draw.h" -#include "util/box.h" #include "util/error.h" #include "util/memory.h" #include "util/snprintf.h" #include "util/string.h" -struct dom_renderer { - enum sgml_document_type doctype; - struct document *document; - - struct conv_table *convert_table; - enum convert_string_mode convert_mode; - - struct uri *base_uri; - - unsigned char *source; - unsigned char *end; - - unsigned char *position; - int canvas_x, canvas_y; - -#ifdef HAVE_REGEX_H - regex_t url_regex; - unsigned int find_url:1; -#endif - struct screen_char styles[DOM_NODES]; - - /* RSS renderer variables */ - struct dom_node *channel; - struct dom_node_list *items; - struct dom_node *item; - struct dom_node *node; - struct dom_string text; -}; - #define URL_REGEX "(file://|((f|ht|nt)tp(s)?|smb)://[[:alnum:]]+([-@:.]?[[:alnum:]])*\\.[[:alpha:]]{2,4}(:[[:digit:]]+)?)(/(%[[:xdigit:]]{2}|[-_~&=;?.a-z0-9])*)*" #define URL_REGFLAGS (REG_ICASE | REG_EXTENDED) -static void -init_template(struct screen_char *template, struct document_options *options, - color_T background, color_T foreground, enum screen_char_attr attr) -{ - struct color_pair colors = INIT_COLOR_PAIR(background, foreground); - - template->attr = attr; - template->data = ' '; - set_term_color(template, &colors, - options->color_flags, options->color_mode); -} - /* Checks the user CSS for properties for each DOM node type name */ static inline void @@ -200,245 +156,6 @@ done_dom_renderer(struct dom_renderer *renderer) } -/* Document maintainance */ - -static struct screen_char * -realloc_line(struct document *document, int x, int y) -{ - struct line *line = realloc_lines(document, y); - - if (!line) return NULL; - - if (x > line->length) { - if (!ALIGN_LINE(&line->chars, line->length, x)) - return NULL; - - for (; line->length < x; line->length++) { - line->chars[line->length].data = ' '; - } - - if (x > document->width) document->width = x; - } - - return line->chars; -} - -static struct node * -add_search_node(struct dom_renderer *renderer, int width) -{ - struct node *node = mem_alloc(sizeof(*node)); - - if (node) { - set_box(&node->box, renderer->canvas_x, renderer->canvas_y, - width, 1); - add_to_list(renderer->document->nodes, node); - } - - return node; -} - -#define X(renderer) ((renderer)->canvas_x) -#define Y(renderer) ((renderer)->canvas_y) -#define POS(renderer) (&(renderer)->document->data[Y(renderer)].chars[X(renderer)]) -#define WIDTH(renderer, add) ((renderer)->canvas_x + (add)) - -static void -render_dom_line(struct dom_renderer *renderer, struct screen_char *template, - unsigned char *string, int length) -{ - struct document *document = renderer->document; - struct conv_table *convert = renderer->convert_table; - enum convert_string_mode mode = renderer->convert_mode; - int x, charlen; -#ifdef CONFIG_UTF8 - int utf8 = document->options.utf8; - unsigned char *end; -#endif /* CONFIG_UTF8 */ - - - assert(renderer && template && string && length); - - string = convert_string(convert, string, length, document->options.cp, - mode, &length, NULL, NULL); - if (!string) return; - - if (!realloc_line(document, WIDTH(renderer, length), Y(renderer))) { - mem_free(string); - return; - } - - add_search_node(renderer, length); - -#ifdef CONFIG_UTF8 - end = string + length; -#endif /* CONFIG_UTF8 */ - for (x = 0, charlen = 1; x < length;x += charlen, renderer->canvas_x++) { - unsigned char *text = &string[x]; - - /* This is mostly to be able to break out so the indentation - * level won't get to high. */ - switch (*text) { - case ASCII_TAB: - { - int tab_width = 7 - (X(renderer) & 7); - int width = WIDTH(renderer, length - x + tab_width); - - template->data = ' '; - - if (!realloc_line(document, width, Y(renderer))) - break; - - /* Only loop over the expanded tab chars and let the - * ``main loop'' add the actual tab char. */ - for (; tab_width-- > 0; renderer->canvas_x++) - copy_screen_chars(POS(renderer), template, 1); - charlen = 1; - break; - } - default: -#ifdef CONFIG_UTF8 - if (utf8) { - unicode_val_T data; - charlen = utf8charlen(text); - data = utf8_to_unicode(&text, end); - - template->data = (unicode_val_T)data; - - if (unicode_to_cell(data) == 2) { - copy_screen_chars(POS(renderer), - template, 1); - - X(renderer)++; - template->data = UCS_NO_CHAR; - } - - } else -#endif /* CONFIG_UTF8 */ - template->data = isscreensafe(*text) ? *text:'.'; - } - - copy_screen_chars(POS(renderer), template, 1); - } - mem_free(string); -} - -static inline unsigned char * -split_dom_line(unsigned char *line, int length, int *linelen) -{ - unsigned char *end = line + length; - unsigned char *pos; - - /* End of line detection. - * We handle \r, \r\n and \n types here. */ - for (pos = line; pos < end; pos++) { - int step = 0; - - if (pos[step] == ASCII_CR) - step++; - - if (pos[step] == ASCII_LF) - step++; - - if (step) { - *linelen = pos - line; - return pos + step; - } - } - - *linelen = length; - return NULL; -} - -static void -render_dom_text(struct dom_renderer *renderer, struct screen_char *template, - unsigned char *string, int length) -{ - int linelen; - - for (; length > 0; string += linelen, length -= linelen) { - unsigned char *newline = split_dom_line(string, length, &linelen); - - if (linelen) - render_dom_line(renderer, template, string, linelen); - - if (newline) { - renderer->canvas_y++; - renderer->canvas_x = 0; - linelen = newline - string; - } - } -} - -#define realloc_document_links(doc, size) \ - ALIGN_LINK(&(doc)->links, (doc)->nlinks, size) - -static inline struct link * -add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length, - unsigned char *uristring, int urilength) -{ - struct document *document = renderer->document; - int x = renderer->canvas_x; - int y = renderer->canvas_y; - unsigned char *where; - struct link *link; - struct point *point; - struct screen_char template; - color_T fgcolor; - - if (!realloc_document_links(document, document->nlinks + 1)) - return NULL; - - link = &document->links[document->nlinks]; - - if (!realloc_points(link, length)) - return NULL; - - uristring = convert_string(renderer->convert_table, - uristring, urilength, document->options.cp, - CSM_DEFAULT, NULL, NULL, NULL); - if (!uristring) return NULL; - - where = join_urls(renderer->base_uri, uristring); - - mem_free(uristring); - - if (!where) - return NULL; -#ifdef CONFIG_GLOBHIST - else if (get_global_history_item(where)) - fgcolor = document->options.default_vlink; -#endif -#ifdef CONFIG_BOOKMARKS - else if (get_bookmark(where)) - fgcolor = document->options.default_bookmark_link; -#endif - else - fgcolor = document->options.default_link; - - link->npoints = length; - link->type = LINK_HYPERTEXT; - link->where = where; - link->color.background = document->options.default_bg; - link->color.foreground = fgcolor; - link->number = document->nlinks; - - init_template(&template, &document->options, - link->color.background, link->color.foreground, 0); - - render_dom_text(renderer, &template, string, length); - - for (point = link->points; length > 0; length--, point++, x++) { - point->x = x; - point->y = y; - } - - document->nlinks++; - document->links_sorted = 0; - - return link; -} - - /* DOM Source Renderer */ #define check_dom_node_source(renderer, str, len) \ diff --git a/src/document/dom/util.c b/src/document/dom/util.c new file mode 100644 index 000000000..65062a20e --- /dev/null +++ b/src/document/dom/util.c @@ -0,0 +1,273 @@ +/* Utilities for rendering document bits */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* FreeBSD needs this before regex.h */ +#ifdef HAVE_REGEX_H +#include +#endif +#include + +#include "elinks.h" + +#include "bookmarks/bookmarks.h" /* get_bookmark() */ +#include "document/docdata.h" +#include "document/document.h" +#include "document/dom/util.h" +#include "intl/charsets.h" +#include "globhist/globhist.h" /* get_global_history_item() */ +#include "protocol/uri.h" +#include "terminal/draw.h" +#include "util/error.h" +#include "util/memory.h" +#include "util/box.h" + + +inline void +init_template(struct screen_char *template, struct document_options *options, + color_T background, color_T foreground, enum screen_char_attr attr) +{ + struct color_pair colors = INIT_COLOR_PAIR(background, foreground); + + template->attr = attr; + template->data = ' '; + set_term_color(template, &colors, + options->color_flags, options->color_mode); +} + + +static struct screen_char * +realloc_line(struct document *document, int x, int y) +{ + struct line *line = realloc_lines(document, y); + + if (!line) return NULL; + + if (x > line->length) { + if (!ALIGN_LINE(&line->chars, line->length, x)) + return NULL; + + for (; line->length < x; line->length++) { + line->chars[line->length].data = ' '; + } + + if (x > document->width) document->width = x; + } + + return line->chars; +} + +static struct node * +add_search_node(struct dom_renderer *renderer, int width) +{ + struct node *node = mem_alloc(sizeof(*node)); + + if (node) { + set_box(&node->box, renderer->canvas_x, renderer->canvas_y, + width, 1); + add_to_list(renderer->document->nodes, node); + } + + return node; +} + +#define POS(renderer) (&(renderer)->document->data[Y(renderer)].chars[X(renderer)]) +#define WIDTH(renderer, add) ((renderer)->canvas_x + (add)) + +static void +render_dom_line(struct dom_renderer *renderer, struct screen_char *template, + unsigned char *string, int length) +{ + struct document *document = renderer->document; + struct conv_table *convert = renderer->convert_table; + enum convert_string_mode mode = renderer->convert_mode; + int x, charlen; +#ifdef CONFIG_UTF8 + int utf8 = document->options.utf8; + unsigned char *end; +#endif /* CONFIG_UTF8 */ + + + assert(renderer && template && string && length); + + string = convert_string(convert, string, length, document->options.cp, + mode, &length, NULL, NULL); + if (!string) return; + + if (!realloc_line(document, WIDTH(renderer, length), Y(renderer))) { + mem_free(string); + return; + } + + add_search_node(renderer, length); + +#ifdef CONFIG_UTF8 + end = string + length; +#endif /* CONFIG_UTF8 */ + for (x = 0, charlen = 1; x < length;x += charlen, renderer->canvas_x++) { + unsigned char *text = &string[x]; + + /* This is mostly to be able to break out so the indentation + * level won't get to high. */ + switch (*text) { + case ASCII_TAB: + { + int tab_width = 7 - (X(renderer) & 7); + int width = WIDTH(renderer, length - x + tab_width); + + template->data = ' '; + + if (!realloc_line(document, width, Y(renderer))) + break; + + /* Only loop over the expanded tab chars and let the + * ``main loop'' add the actual tab char. */ + for (; tab_width-- > 0; renderer->canvas_x++) + copy_screen_chars(POS(renderer), template, 1); + charlen = 1; + break; + } + default: +#ifdef CONFIG_UTF8 + if (utf8) { + unicode_val_T data; + charlen = utf8charlen(text); + data = utf8_to_unicode(&text, end); + + template->data = (unicode_val_T)data; + + if (unicode_to_cell(data) == 2) { + copy_screen_chars(POS(renderer), + template, 1); + + X(renderer)++; + template->data = UCS_NO_CHAR; + } + + } else +#endif /* CONFIG_UTF8 */ + template->data = isscreensafe(*text) ? *text:'.'; + } + + copy_screen_chars(POS(renderer), template, 1); + } + mem_free(string); +} + +static inline unsigned char * +split_dom_line(unsigned char *line, int length, int *linelen) +{ + unsigned char *end = line + length; + unsigned char *pos; + + /* End of line detection. + * We handle \r, \r\n and \n types here. */ + for (pos = line; pos < end; pos++) { + int step = 0; + + if (pos[step] == ASCII_CR) + step++; + + if (pos[step] == ASCII_LF) + step++; + + if (step) { + *linelen = pos - line; + return pos + step; + } + } + + *linelen = length; + return NULL; +} + +void +render_dom_text(struct dom_renderer *renderer, struct screen_char *template, + unsigned char *string, int length) +{ + int linelen; + + for (; length > 0; string += linelen, length -= linelen) { + unsigned char *newline = split_dom_line(string, length, &linelen); + + if (linelen) + render_dom_line(renderer, template, string, linelen); + + if (newline) { + renderer->canvas_y++; + renderer->canvas_x = 0; + linelen = newline - string; + } + } +} + +#define realloc_document_links(doc, size) \ + ALIGN_LINK(&(doc)->links, (doc)->nlinks, size) + +inline struct link * +add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length, + unsigned char *uristring, int urilength) +{ + struct document *document = renderer->document; + int x = renderer->canvas_x; + int y = renderer->canvas_y; + unsigned char *where; + struct link *link; + struct point *point; + struct screen_char template; + color_T fgcolor; + + if (!realloc_document_links(document, document->nlinks + 1)) + return NULL; + + link = &document->links[document->nlinks]; + + if (!realloc_points(link, length)) + return NULL; + + uristring = convert_string(renderer->convert_table, + uristring, urilength, document->options.cp, + CSM_DEFAULT, NULL, NULL, NULL); + if (!uristring) return NULL; + + where = join_urls(renderer->base_uri, uristring); + + mem_free(uristring); + + if (!where) + return NULL; +#ifdef CONFIG_GLOBHIST + else if (get_global_history_item(where)) + fgcolor = document->options.default_vlink; +#endif +#ifdef CONFIG_BOOKMARKS + else if (get_bookmark(where)) + fgcolor = document->options.default_bookmark_link; +#endif + else + fgcolor = document->options.default_link; + + link->npoints = length; + link->type = LINK_HYPERTEXT; + link->where = where; + link->color.background = document->options.default_bg; + link->color.foreground = fgcolor; + link->number = document->nlinks; + + init_template(&template, &document->options, + link->color.background, link->color.foreground, 0); + + render_dom_text(renderer, &template, string, length); + + for (point = link->points; length > 0; length--, point++, x++) { + point->x = x; + point->y = y; + } + + document->nlinks++; + document->links_sorted = 0; + + return link; +} diff --git a/src/document/dom/util.h b/src/document/dom/util.h new file mode 100644 index 000000000..de8fef8e0 --- /dev/null +++ b/src/document/dom/util.h @@ -0,0 +1,64 @@ +#ifndef EL__DOCUMENT_DOM_UTIL_H +#define EL__DOCUMENT_DOM_UTIL_H + +/* This header is meant to be used only amongst the DOM renderers. */ + +#include /* FreeBSD needs this before regex.h */ +#ifdef HAVE_REGEX_H +#include +#endif + +#include "dom/sgml/sgml.h" +#include "intl/charsets.h" +#include "terminal/draw.h" + + +struct document; +struct uri; +struct dom_node; +struct dom_node_list; +struct dom_string; + +struct dom_renderer { + enum sgml_document_type doctype; + struct document *document; + + struct conv_table *convert_table; + enum convert_string_mode convert_mode; + + struct uri *base_uri; + + unsigned char *source; + unsigned char *end; + + unsigned char *position; + int canvas_x, canvas_y; + +#ifdef HAVE_REGEX_H + regex_t url_regex; + unsigned int find_url:1; +#endif + struct screen_char styles[DOM_NODES]; + + /* RSS renderer variables */ + struct dom_node *channel; + struct dom_node_list *items; + struct dom_node *item; + struct dom_node *node; + struct dom_string text; +}; + +#define X(renderer) ((renderer)->canvas_x) +#define Y(renderer) ((renderer)->canvas_y) + + +void init_template(struct screen_char *template, + struct document_options *options, + color_T background, color_T foreground, + enum screen_char_attr attr); +void render_dom_text(struct dom_renderer *renderer, struct screen_char *template, + unsigned char *string, int length); +struct link *add_dom_link(struct dom_renderer *renderer, unsigned char *string, + int length, unsigned char *uristring, int urilength); + +#endif