2005-09-15 09:58:31 -04:00
|
|
|
/* DOM document renderer */
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "cache/cache.h"
|
|
|
|
#include "document/document.h"
|
|
|
|
#include "document/dom/renderer.h"
|
2007-08-28 11:31:43 -04:00
|
|
|
#include "document/dom/rss.h"
|
2007-08-28 11:41:55 -04:00
|
|
|
#include "document/dom/source.h"
|
|
|
|
#include "document/dom/util.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "document/renderer.h"
|
2006-01-15 23:12:34 -05:00
|
|
|
#include "dom/configuration.h"
|
2005-12-28 08:05:14 -05:00
|
|
|
#include "dom/scanner.h"
|
|
|
|
#include "dom/sgml/parser.h"
|
2006-01-25 17:16:30 -05:00
|
|
|
#include "dom/sgml/html/html.h"
|
2006-01-07 21:44:23 -05:00
|
|
|
#include "dom/sgml/rss/rss.h"
|
2005-12-28 08:05:14 -05:00
|
|
|
#include "dom/node.h"
|
|
|
|
#include "dom/stack.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "intl/charsets.h"
|
|
|
|
#include "protocol/uri.h"
|
|
|
|
#include "util/error.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
#include "util/string.h"
|
|
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
init_dom_renderer(struct dom_renderer *renderer, struct document *document,
|
2019-02-17 14:46:16 -05:00
|
|
|
struct string_ *buffer, struct conv_table *convert_table)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
memset(renderer, 0, sizeof(*renderer));
|
|
|
|
|
|
|
|
renderer->document = document;
|
|
|
|
renderer->convert_table = convert_table;
|
|
|
|
renderer->convert_mode = document->options.plain ? CSM_NONE : CSM_DEFAULT;
|
|
|
|
renderer->source = buffer->source;
|
|
|
|
renderer->end = buffer->source + buffer->length;
|
|
|
|
renderer->position = renderer->source;
|
2006-01-25 17:16:30 -05:00
|
|
|
renderer->base_uri = get_uri_reference(document->uri);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2006-05-05 20:43:44 -04:00
|
|
|
static inline void
|
|
|
|
done_dom_renderer(struct dom_renderer *renderer)
|
|
|
|
{
|
|
|
|
done_uri(renderer->base_uri);
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-05-06 01:03:39 -04:00
|
|
|
static void
|
|
|
|
get_doctype(struct dom_renderer *renderer, struct cache_entry *cached)
|
|
|
|
{
|
2008-10-18 21:25:00 -04:00
|
|
|
if (!c_strcasecmp("application/rss+xml", cached->content_type)) {
|
2006-05-06 01:03:39 -04:00
|
|
|
renderer->doctype = SGML_DOCTYPE_RSS;
|
|
|
|
|
2008-10-18 21:25:00 -04:00
|
|
|
} else if (!c_strcasecmp("application/docbook+xml",
|
|
|
|
cached->content_type)) {
|
2006-05-06 01:03:39 -04:00
|
|
|
renderer->doctype = SGML_DOCTYPE_DOCBOOK;
|
|
|
|
|
2008-10-18 21:25:00 -04:00
|
|
|
} else if (!c_strcasecmp("application/xbel+xml", cached->content_type)
|
|
|
|
|| !c_strcasecmp("application/x-xbel", cached->content_type)
|
|
|
|
|| !c_strcasecmp("application/xbel", cached->content_type)) {
|
2006-05-06 01:03:39 -04:00
|
|
|
renderer->doctype = SGML_DOCTYPE_XBEL;
|
|
|
|
|
|
|
|
} else {
|
2008-10-18 21:25:00 -04:00
|
|
|
assertm(!c_strcasecmp("text/html", cached->content_type)
|
|
|
|
|| !c_strcasecmp("application/xhtml+xml",
|
|
|
|
cached->content_type),
|
2006-05-06 01:03:39 -04:00
|
|
|
"Couldn't resolve doctype '%s'", cached->content_type);
|
|
|
|
|
|
|
|
renderer->doctype = SGML_DOCTYPE_HTML;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
/* Shared multiplexor between renderers */
|
|
|
|
void
|
|
|
|
render_dom_document(struct cache_entry *cached, struct document *document,
|
2019-02-17 14:46:16 -05:00
|
|
|
struct string_ *buffer)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
unsigned char *head = empty_string_or_(cached->head);
|
|
|
|
struct dom_renderer renderer;
|
2008-06-20 18:19:15 -04:00
|
|
|
struct dom_config config;
|
2005-09-15 09:58:31 -04:00
|
|
|
struct conv_table *convert_table;
|
2005-11-27 03:18:40 -05:00
|
|
|
struct sgml_parser *parser;
|
2006-01-07 21:44:23 -05:00
|
|
|
enum sgml_parser_type parser_type;
|
2005-12-28 09:19:10 -05:00
|
|
|
unsigned char *string = struri(cached->uri);
|
|
|
|
size_t length = strlen(string);
|
|
|
|
struct dom_string uri = INIT_DOM_STRING(string, length);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
convert_table = get_convert_table(head, document->options.cp,
|
|
|
|
document->options.assume_cp,
|
|
|
|
&document->cp,
|
|
|
|
&document->cp_status,
|
|
|
|
document->options.hard_assume);
|
|
|
|
|
2005-11-15 06:11:48 -05:00
|
|
|
init_dom_renderer(&renderer, document, buffer, convert_table);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-10-12 10:50:47 -04:00
|
|
|
document->color.background = document->options.default_style.color.background;
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-07-18 11:51:03 -04:00
|
|
|
document->options.utf8 = is_cp_utf8(document->options.cp);
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-01-07 21:44:23 -05:00
|
|
|
if (document->options.plain)
|
|
|
|
parser_type = SGML_PARSER_STREAM;
|
|
|
|
else
|
|
|
|
parser_type = SGML_PARSER_TREE;
|
|
|
|
|
2006-05-06 01:03:39 -04:00
|
|
|
get_doctype(&renderer, cached);
|
2005-12-19 21:08:13 -05:00
|
|
|
|
2006-01-25 17:16:30 -05:00
|
|
|
parser = init_sgml_parser(parser_type, renderer.doctype, &uri, 0);
|
2006-05-06 01:03:39 -04:00
|
|
|
if (!parser) return;
|
2006-01-12 18:11:39 -05:00
|
|
|
|
2006-01-07 21:44:23 -05:00
|
|
|
if (document->options.plain) {
|
|
|
|
add_dom_stack_context(&parser->stack, &renderer,
|
|
|
|
&dom_source_renderer_context_info);
|
2005-12-05 13:20:48 -05:00
|
|
|
|
2006-01-25 17:16:30 -05:00
|
|
|
} else if (renderer.doctype == SGML_DOCTYPE_RSS) {
|
2006-01-07 21:44:23 -05:00
|
|
|
add_dom_stack_context(&parser->stack, &renderer,
|
|
|
|
&dom_rss_renderer_context_info);
|
2008-06-20 18:19:15 -04:00
|
|
|
add_dom_config_normalizer(&parser->stack, &config, RSS_CONFIG_FLAGS);
|
2006-01-07 21:44:23 -05:00
|
|
|
}
|
2005-12-21 08:41:28 -05:00
|
|
|
|
2006-01-02 11:40:42 -05:00
|
|
|
/* FIXME: When rendering this way we don't really care about the code.
|
|
|
|
* However, it will be useful when we will be able to also
|
|
|
|
* incrementally parse new data. This will require the parser to live
|
|
|
|
* during the fetching of data. */
|
2011-09-23 20:25:51 -04:00
|
|
|
parse_sgml(parser, buffer->source, buffer->length, 1);
|
2006-01-02 11:40:42 -05:00
|
|
|
if (parser->root) {
|
2005-12-22 06:33:27 -05:00
|
|
|
assert(parser->stack.depth == 1);
|
2005-12-05 13:20:48 -05:00
|
|
|
|
2005-12-22 06:33:27 -05:00
|
|
|
get_dom_stack_top(&parser->stack)->immutable = 0;
|
|
|
|
/* For SGML_PARSER_STREAM this will free the DOM
|
|
|
|
* root node. */
|
|
|
|
pop_dom_node(&parser->stack);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2006-05-05 20:43:44 -04:00
|
|
|
done_dom_renderer(&renderer);
|
2005-12-22 06:33:27 -05:00
|
|
|
done_sgml_parser(parser);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|