📄 renderer.c
字号:
/* DOM document renderer *//* $Id: renderer.c,v 1.17.2.4 2005/05/01 21:09:35 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>#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/navigator.h"#include "document/dom/node.h"#include "document/dom/renderer.h"#include "document/renderer.h"#include "document/sgml/parser.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 { struct document *document; struct conv_table *convert_table; enum convert_string_mode convert_mode; struct dom_node *root; unsigned char *source; unsigned char *end; unsigned char *position; int canvas_x, canvas_y; struct screen_char styles[DOM_NODES];};static voidinit_template(struct screen_char *template, color_t background, color_t foreground){ struct color_pair colors = INIT_COLOR_PAIR(background, foreground); template->attr = 0; template->data = ' '; set_term_color(template, &colors, global_doc_opts->color_flags, global_doc_opts->color_mode);}static inline struct css_property *get_css_property(struct list_head *list, enum css_property_type type){ struct css_property *property; foreach (property, *list) if (property->type == type) return property; return NULL;}/* Checks the user CSS for properties for each DOM node type name */static inline voidinit_dom_renderer(struct dom_renderer *renderer, struct document *document, struct string *buffer, struct dom_node *root, struct conv_table *convert_table){ enum dom_node_type type; struct css_stylesheet *css = &default_stylesheet; memset(renderer, 0, sizeof(*renderer)); renderer->document = document; renderer->convert_table = convert_table; renderer->convert_mode = document->options.plain ? CSM_NONE : CSM_DEFAULT; renderer->root = root; renderer->source = buffer->source; renderer->end = buffer->source + buffer->length; renderer->position = renderer->source; for (type = 0; type < DOM_NODES; type++) { struct screen_char *template = &renderer->styles[type]; color_t background = global_doc_opts->default_bg; color_t foreground = global_doc_opts->default_fg; static int i_want_struct_module_for_dom; unsigned char *name = get_dom_node_type_name(type); int namelen = name ? strlen(name) : 0; struct css_selector *selector = NULL; if (!i_want_struct_module_for_dom) { static const unsigned char default_colors[] = "document { color: yellow } " "element { color: lightgreen } " "entity-reference { color: red } " "proc-instruction { color: red } " "attribute { color: magenta } " "comment { color: aqua } "; unsigned char *styles = (unsigned char *) default_colors; i_want_struct_module_for_dom = 1; /* When someone will get here earlier than at 4am, * this will be done in some init function, perhaps * not overriding the user's default stylesheet. */ css_parse_stylesheet(css, NULL, styles, styles + sizeof(default_colors) + 1); } if (name) selector = find_css_selector(&css->selectors, CST_ELEMENT, CSR_ROOT, name, namelen); if (selector) { struct list_head *properties = &selector->properties; struct css_property *property; property = get_css_property(properties, CSS_PT_BACKGROUND_COLOR); if (!property) property = get_css_property(properties, CSS_PT_BACKGROUND); if (property && property->value_type == CSS_VT_COLOR) background = property->value.color; property = get_css_property(properties, CSS_PT_COLOR); if (property) foreground = property->value.color; } init_template(template, background, foreground); }}/* 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 voidrender_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; assert(renderer && template && string && length); string = convert_string(convert, string, length, 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); for (x = 0; x < length; x++, renderer->canvas_x++) { unsigned char data = string[x]; /* This is mostly to be able to break out so the indentation * level won't get to high. */ switch (data) { 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); break; } default: template->data = isscreensafe(data) ? data : '.'; } 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 voidrender_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; } }}#ifdef DOM_TREE_RENDERERstatic voidrender_dom_printf(struct dom_renderer *renderer, struct screen_char *template, unsigned char *format, ...){ unsigned char *text; int textlen; va_list ap, ap2; va_start(ap, format); VA_COPY(ap2, ap); textlen = vsnprintf(NULL, 0, format, ap2); text = mem_alloc(textlen + 1); if (!text) goto free_va_args; if (vsnprintf((char *) text, textlen + 1, format, ap) == textlen) render_dom_text(renderer, template, text, textlen); mem_free(text);free_va_args: va_end(ap);}#endif /* DOM_TREE_RENDERER */#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){ 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; unsigned char *uristring; 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, string, length, CSM_DEFAULT, NULL, NULL, NULL); if (!uristring) return NULL; where = join_urls(document->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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -