[wip] show_image(): Introduce struct screen_image with complete but abstract on-scree...
[elinks/images.git] / src / document / dom / renderer.c
blob97b2854ef0e738cbbe18ce2749796b4178cdd5ab
1 /* DOM document renderer */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <string.h>
9 #include "elinks.h"
11 #include "cache/cache.h"
12 #include "document/document.h"
13 #include "document/dom/renderer.h"
14 #include "document/dom/rss.h"
15 #include "document/dom/source.h"
16 #include "document/dom/util.h"
17 #include "document/renderer.h"
18 #include "dom/configuration.h"
19 #include "dom/scanner.h"
20 #include "dom/sgml/parser.h"
21 #include "dom/sgml/html/html.h"
22 #include "dom/sgml/rss/rss.h"
23 #include "dom/node.h"
24 #include "dom/stack.h"
25 #include "intl/charsets.h"
26 #include "protocol/uri.h"
27 #include "util/error.h"
28 #include "util/memory.h"
29 #include "util/string.h"
32 static inline void
33 init_dom_renderer(struct dom_renderer *renderer, struct document *document,
34 struct string *buffer, struct conv_table *convert_table)
36 memset(renderer, 0, sizeof(*renderer));
38 renderer->document = document;
39 renderer->convert_table = convert_table;
40 renderer->convert_mode = document->options.plain ? CSM_NONE : CSM_DEFAULT;
41 renderer->source = buffer->source;
42 renderer->end = buffer->source + buffer->length;
43 renderer->position = renderer->source;
44 renderer->base_uri = get_uri_reference(document->uri);
47 static inline void
48 done_dom_renderer(struct dom_renderer *renderer)
50 done_uri(renderer->base_uri);
54 static void
55 get_doctype(struct dom_renderer *renderer, struct cache_entry *cached)
57 if (!c_strcasecmp("application/rss+xml", cached->content_type)) {
58 renderer->doctype = SGML_DOCTYPE_RSS;
60 } else if (!c_strcasecmp("application/docbook+xml",
61 cached->content_type)) {
62 renderer->doctype = SGML_DOCTYPE_DOCBOOK;
64 } else if (!c_strcasecmp("application/xbel+xml", cached->content_type)
65 || !c_strcasecmp("application/x-xbel", cached->content_type)
66 || !c_strcasecmp("application/xbel", cached->content_type)) {
67 renderer->doctype = SGML_DOCTYPE_XBEL;
69 } else {
70 assertm(!c_strcasecmp("text/html", cached->content_type)
71 || !c_strcasecmp("application/xhtml+xml",
72 cached->content_type),
73 "Couldn't resolve doctype '%s'", cached->content_type);
75 renderer->doctype = SGML_DOCTYPE_HTML;
79 /* Shared multiplexor between renderers */
80 void
81 render_dom_document(struct cache_entry *cached, struct document *document,
82 struct string *buffer)
84 unsigned char *head = empty_string_or_(cached->head);
85 struct dom_renderer renderer;
86 struct dom_config config;
87 struct conv_table *convert_table;
88 struct sgml_parser *parser;
89 enum sgml_parser_type parser_type;
90 unsigned char *string = struri(cached->uri);
91 size_t length = strlen(string);
92 struct dom_string uri = INIT_DOM_STRING(string, length);
94 convert_table = get_convert_table(head, document->options.cp,
95 document->options.assume_cp,
96 &document->cp,
97 &document->cp_status,
98 document->options.hard_assume);
100 init_dom_renderer(&renderer, document, buffer, convert_table);
102 document->color.background = document->options.default_style.color.background;
103 #ifdef CONFIG_UTF8
104 document->options.utf8 = is_cp_utf8(document->options.cp);
105 #endif /* CONFIG_UTF8 */
107 if (document->options.plain)
108 parser_type = SGML_PARSER_STREAM;
109 else
110 parser_type = SGML_PARSER_TREE;
112 get_doctype(&renderer, cached);
114 parser = init_sgml_parser(parser_type, renderer.doctype, &uri, 0);
115 if (!parser) return;
117 if (document->options.plain) {
118 add_dom_stack_context(&parser->stack, &renderer,
119 &dom_source_renderer_context_info);
121 } else if (renderer.doctype == SGML_DOCTYPE_RSS) {
122 add_dom_stack_context(&parser->stack, &renderer,
123 &dom_rss_renderer_context_info);
124 add_dom_config_normalizer(&parser->stack, &config, RSS_CONFIG_FLAGS);
127 /* FIXME: When rendering this way we don't really care about the code.
128 * However, it will be useful when we will be able to also
129 * incrementally parse new data. This will require the parser to live
130 * during the fetching of data. */
131 parse_sgml(parser, buffer->source, buffer->length, 1);
132 if (parser->root) {
133 assert(parser->stack.depth == 1);
135 get_dom_stack_top(&parser->stack)->immutable = 0;
136 /* For SGML_PARSER_STREAM this will free the DOM
137 * root node. */
138 pop_dom_node(&parser->stack);
141 done_dom_renderer(&renderer);
142 done_sgml_parser(parser);