📄 renderer.c
字号:
/* HTML renderer *//* $Id: renderer.c,v 1.140.2.3 2005/04/05 21:08:41 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <ctype.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include "elinks.h"#include "cache/cache.h"#include "config/options.h"#include "document/document.h"#include "document/dom/renderer.h"#include "document/html/frames.h"#include "document/html/renderer.h"#include "document/plain/renderer.h"#include "document/renderer.h"#include "document/view.h"#include "ecmascript/ecmascript.h"#include "intl/charsets.h"#include "main.h"#include "protocol/header.h"#include "protocol/protocol.h"#include "protocol/uri.h"#include "sched/session.h"#include "terminal/terminal.h"#include "terminal/window.h"#include "util/error.h"#include "util/memory.h"#include "util/object.h"#include "util/string.h"#include "viewer/text/view.h"#include "viewer/text/vs.h"static void sort_links(struct document *document);#ifdef CONFIG_ECMASCRIPT/* XXX: This function is de facto obsolete, since we do not need to copy * snippets around anymore (we process them in one go after the document is * loaded; gradual processing was practically impossible because the snippets * could reorder randomly during the loading - consider i.e. * <body onLoad><script></body>: first just <body> is loaded, but then the * rest of the document is loaded and <script> gets before <body>; do not even * imagine the trouble with rewritten (through scripting hooks) documents; * besides, implementing document.write() will be much simpler). * But I want to take no risk by reworking that now. --pasky */static voidadd_snippets(struct ecmascript_interpreter *interpreter, struct list_head *doc_snippets, struct list_head *queued_snippets){ struct string_list_item *doc_current = doc_snippets->next;#ifdef CONFIG_LEDS if (list_empty(*queued_snippets) && interpreter->vs->doc_view->session) interpreter->vs->doc_view->session->status.ecmascript_led->value = '-';#endif if (list_empty(*doc_snippets) || !get_opt_bool("ecmascript.enable")) return; /* We do this all only once per view_state now. */ if (!list_empty(*queued_snippets)) { /* So if we already did it, we shouldn't need to do it again. * This is the case of moving around in history - we have all * what happenned recorded in the view_state and needn't bother * again. */#ifdef CONFIG_DEBUG /* Hopefully. */ struct string_list_item *iterator = queued_snippets->next; while (iterator != (struct string_list_item *) queued_snippets) { if (doc_current == (struct string_list_item *) doc_snippets) { INTERNAL("add_snippets(): doc_snippets shorter than queued_snippets!"); return; }#if 0 DBG("Comparing snippets\n%.*s\n###### vs #####\n%.*s\n #####", iterator->string.length, iterator->string.source, doc_current->string.length, doc_current->string.source);#endif assert(!strlcmp(iterator->string.source, iterator->string.length, doc_current->string.source, doc_current->string.length)); doc_current = doc_current->next; iterator = iterator->next; }#endif return; } assert(doc_current); for (; doc_current != (struct string_list_item *) doc_snippets; doc_current = doc_current->next) { add_to_string_list(queued_snippets, doc_current->string.source, doc_current->string.length);#if 0 DBG("Adding snippet\n%.*s\n #####", doc_current->string.length, doc_current->string.source);#endif }}static voidprocess_snippets(struct ecmascript_interpreter *interpreter, struct list_head *snippets, struct string_list_item **current){ if (!*current) *current = snippets->next; for (; *current != (struct string_list_item *) snippets; (*current) = (*current)->next) { struct string *string = &(*current)->string; unsigned char *uristring; struct uri *uri; struct cache_entry *cached; struct fragment *fragment; if (string->length == 0) continue; if (*string->source != '^') { /* Evaluate <script>code</script> snippet */ ecmascript_eval(interpreter, string); continue; } /* Eval external <script src="reference"></script> snippet */ uristring = string->source + 1; if (!*uristring) continue; uri = get_uri(uristring, URI_BASE); if (!uri) continue; cached = get_redirected_cache_entry(uri); done_uri(uri); if (!cached) { /* At this time (!gradual_rerendering), we should've * already retrieved this though. So it must've been * that it went away because unused and the cache was * already too full. */#if 0 /* Disabled because gradual rerendering can be triggered * by numerous events other than a ecmascript reference * completing like the original document and CSS. Problem * is that we should never continue this loop but rather * break out if that is the case. Somehow we need to * be able to derive URI loading problems at this point * or maybe remove reference snippets if they fail to load. * * This FIFO queue handling should be used for also CSS * imports so it would be cool if it could be general * enough for that. Using it for frames with the FIFOing * disabled probably wouldn't hurt either. * * To top this thing off it would be nice if it also * handled dependency tracking between references so that * CSS documents will not disappear from the cache * before all referencing HTML documents has been deleted * from it. * * Reported as bug 533. */ /* Pasky's explanation: If we get the doc in a single * shot, before calling draw_formatted() we didn't have * anything additional queued for loading and the cache * entry was already loaded, so we didn't get * gradual_loading set. But then while parsing the * document we got some external references and trying * to process them right now. Boom. * * The obvious solution would be to always call * draw_formatted() with gradual_loading in * doc_loading_callback() and if we are sure the * loading is really over, call it one more time * without gradual_loading set. I'm not sure about * the implications though so I won't do it before * 0.10.0. --pasky */ ERROR("The script of %s was lost in too full a cache!", uristring);#endif continue; } fragment = get_cache_fragment(cached); if (fragment) { struct string code = INIT_STRING(fragment->data, fragment->length); ecmascript_eval(interpreter, &code); } }}#endifstatic voidrender_encoded_document(struct cache_entry *cached, struct document *document){ struct uri *uri = cached->uri; enum stream_encoding encoding = ENCODING_NONE; unsigned char *extension; struct fragment *fragment = get_cache_fragment(cached); struct string buffer = INIT_STRING("", 0); /* Even empty documents have to be rendered so that info in the protocol * header, such as refresh info, get processed. (bug 625) */ if (fragment) { buffer.source = fragment->data; buffer.length = fragment->length; } extension = get_extension_from_uri(uri); if (extension) { encoding = guess_encoding(extension); mem_free(extension); } if (encoding != ENCODING_NONE) { int length = 0; unsigned char *source; source = decode_encoded_buffer(encoding, buffer.source, buffer.length, &length); if (source) { buffer.source = source; buffer.length = length; } else { encoding = ENCODING_NONE; } } if (document->options.plain) {#ifdef CONFIG_DOM if (cached->content_type && !strlcasecmp("text/html", 9, cached->content_type, -1)) render_dom_document(cached, document, &buffer); else#endif render_plain_document(cached, document, &buffer); } else { render_html_document(cached, document, &buffer); } if (encoding != ENCODING_NONE) { done_string(&buffer); }}voidrender_document(struct view_state *vs, struct document_view *doc_view, struct document_options *options){ unsigned char *name; struct document *document; struct cache_entry *cached; assert(vs && doc_view && options); if_assert_failed return;#if 0 DBG("(Re%d)Rendering %s on doc_view %p [%s] while attaching it to %p", options->gradual_rerendering, struri(vs->uri), doc_view, doc_view->name, vs);#endif name = doc_view->name; doc_view->name = NULL; detach_formatted(doc_view); doc_view->name = name; doc_view->vs = vs; doc_view->last_x = doc_view->last_y = -1;#if 0 /* This is a nice idea, but doesn't always work: in particular when * there's a frame name conflict. You loaded something to the vs' * frame, but later something tried to get loaded to a frame with * the same name and we got back this frame again, so we are now * overriding the original document with a cuckoo. This assert()ion * should be re-enabled when we start to get this right (which is * very complex, but someone should rewrite the frames support * anyway). --pasky */ assert(!vs->doc_view);#else if (vs->doc_view) { /* It will be still detached, no worries - hopefully it still * resides in ses->scrn_frames. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -