📄 renderer.c
字号:
}/* DOM Source Renderer */#define check_dom_node_source(renderer, str, len) \ ((renderer)->source <= (str) && (str) + (len) <= (renderer)->end)#define assert_source(renderer, str, len) \ assertm(check_dom_node_source(renderer, str, len), "renderer[%p : %p] str[%p : %p]", \ (renderer)->source, (renderer)->end, (str), (str) + (len))static inline voidrender_dom_flush(struct dom_renderer *renderer, unsigned char *string){ struct screen_char *template = &renderer->styles[DOM_NODE_TEXT]; int length = string - renderer->position; assert_source(renderer, renderer->position, 0); assert_source(renderer, string, 0); if (length <= 0) return; render_dom_text(renderer, template, renderer->position, length); renderer->position = string; assert_source(renderer, renderer->position, 0);}static inline voidrender_dom_node_text(struct dom_renderer *renderer, struct screen_char *template, struct dom_node *node){ unsigned char *string = node->string.string; int length = node->string.length; if (node->type == DOM_NODE_ENTITY_REFERENCE) { string -= 1; length += 2; } if (check_dom_node_source(renderer, string, length)) { render_dom_flush(renderer, string); renderer->position = string + length; assert_source(renderer, renderer->position, 0); } render_dom_text(renderer, template, string, length);}#ifdef HAVE_REGEX_Hstatic inline voidrender_dom_node_enhanced_text(struct dom_renderer *renderer, struct dom_node *node){ regex_t *regex = &renderer->url_regex; regmatch_t regmatch; unsigned char *string = node->string.string; int length = node->string.length; struct screen_char *template = &renderer->styles[node->type]; unsigned char *alloc_string; if (check_dom_node_source(renderer, string, length)) { render_dom_flush(renderer, string); renderer->position = string + length; assert_source(renderer, renderer->position, 0); } alloc_string = memacpy(string, length); if (alloc_string) string = alloc_string; while (length > 0 && !regexec(regex, string, 1, ®match, 0)) { int matchlen = regmatch.rm_eo - regmatch.rm_so; int offset = regmatch.rm_so; if (!matchlen || offset < 0 || regmatch.rm_eo > length) break; if (offset > 0) render_dom_text(renderer, template, string, offset); string += offset; length -= offset; add_dom_link(renderer, string, matchlen); length -= matchlen; string += matchlen; } if (length > 0) render_dom_text(renderer, template, string, length); mem_free_if(alloc_string);}#endifstatic voidrender_dom_node_source(struct dom_stack *stack, struct dom_node *node, void *data){ struct dom_renderer *renderer = stack->current->data; assert(node && renderer && renderer->document);#ifdef HAVE_REGEX_H if (renderer->find_url && (node->type == DOM_NODE_TEXT || node->type == DOM_NODE_CDATA_SECTION || node->type == DOM_NODE_COMMENT)) { render_dom_node_enhanced_text(renderer, node); return; }#endif render_dom_node_text(renderer, &renderer->styles[node->type], node);}/* This callback is also used for rendering processing instruction nodes. */static voidrender_dom_element_source(struct dom_stack *stack, struct dom_node *node, void *data){ struct dom_renderer *renderer = stack->current->data; assert(node && renderer && renderer->document); render_dom_node_text(renderer, &renderer->styles[node->type], node);}static voidrender_dom_element_end_source(struct dom_stack *stack, struct dom_node *node, void *data){ struct dom_renderer *renderer = stack->current->data; struct dom_stack_state *state = get_dom_stack_top(stack); struct sgml_parser_state *pstate = get_dom_stack_state_data(stack->contexts[0], state); struct dom_scanner_token *token = &pstate->end_token; unsigned char *string = token->string.string; int length = token->string.length; assert(node && renderer && renderer->document); if (!string || !length) return; if (check_dom_node_source(renderer, string, length)) { render_dom_flush(renderer, string); renderer->position = string + length; assert_source(renderer, renderer->position, 0); } render_dom_text(renderer, &renderer->styles[node->type], string, length);}static voidset_base_uri(struct dom_renderer *renderer, unsigned char *value, size_t valuelen){ unsigned char *href = memacpy(value, valuelen); unsigned char *uristring; struct uri *uri; if (!href) return; uristring = join_urls(renderer->base_uri, href); mem_free(href); if (!uristring) return; uri = get_uri(uristring, 0); mem_free(uristring); if (!uri) return; done_uri(renderer->base_uri); renderer->base_uri = uri;}static voidrender_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void *data){ struct dom_renderer *renderer = stack->current->data; struct screen_char *template = &renderer->styles[node->type]; assert(node && renderer->document); render_dom_node_text(renderer, template, node); if (is_dom_string_set(&node->data.attribute.value)) { int quoted = node->data.attribute.quoted == 1; unsigned char *value = node->data.attribute.value.string - quoted; int valuelen = node->data.attribute.value.length + quoted * 2; if (check_dom_node_source(renderer, value, 0)) { render_dom_flush(renderer, value); renderer->position = value + valuelen; assert_source(renderer, renderer->position, 0); } if (node->data.attribute.reference && valuelen - quoted * 2 > 0) { int skips; /* Need to flush the first quoting delimiter and any * leading whitespace so that the renderers x position * is at the start of the value string. */ for (skips = 0; skips < valuelen; skips++) { if ((quoted && skips == 0) || isspace(value[skips]) || value[skips] < ' ') continue; break; } if (skips > 0) { render_dom_text(renderer, template, value, skips); value += skips; valuelen -= skips; } /* Figure out what should be skipped after the actual * link text. */ for (skips = 0; skips < valuelen; skips++) { if ((quoted && skips == 0) || isspace(value[valuelen - skips - 1]) || value[valuelen - skips - 1] < ' ') continue; break; } if (renderer->doctype == SGML_DOCTYPE_HTML && node->data.attribute.type == HTML_ATTRIBUTE_HREF && node->parent->data.element.type == HTML_ELEMENT_BASE) { set_base_uri(renderer, value, valuelen - skips); } add_dom_link(renderer, value, valuelen - skips); if (skips > 0) { value += valuelen - skips; render_dom_text(renderer, template, value, skips); } } else { render_dom_text(renderer, template, value, valuelen); } }}static voidrender_dom_cdata_source(struct dom_stack *stack, struct dom_node *node, void *data){ struct dom_renderer *renderer = stack->current->data; unsigned char *string = node->string.string; assert(node && renderer && renderer->document); /* Highlight the 'CDATA' part of <![CDATA[ if it is there. */ if (check_dom_node_source(renderer, string - 6, 6)) { render_dom_flush(renderer, string - 6); render_dom_text(renderer, &renderer->styles[DOM_NODE_ATTRIBUTE], string - 6, 5); renderer->position = string - 1; assert_source(renderer, renderer->position, 0); } render_dom_node_text(renderer, &renderer->styles[node->type], node);}static voidrender_dom_document_end(struct dom_stack *stack, struct dom_node *node, void *data){ struct dom_renderer *renderer = stack->current->data; /* If there are no non-element nodes after the last element node make * sure that we flush to the end of the cache entry source including * the '>' of the last element tag if it has one. (bug 519) */ if (check_dom_node_source(renderer, renderer->position, 0)) { render_dom_flush(renderer, renderer->end); }}static struct dom_stack_context_info dom_source_renderer_context_info = { /* Object size: */ 0, /* Push: */ { /* */ NULL, /* DOM_NODE_ELEMENT */ render_dom_element_source, /* DOM_NODE_ATTRIBUTE */ render_dom_attribute_source, /* DOM_NODE_TEXT */ render_dom_node_source, /* DOM_NODE_CDATA_SECTION */ render_dom_cdata_source, /* DOM_NODE_ENTITY_REFERENCE */ render_dom_node_source, /* DOM_NODE_ENTITY */ render_dom_node_source, /* DOM_NODE_PROC_INSTRUCTION */ render_dom_element_source, /* DOM_NODE_COMMENT */ render_dom_node_source, /* DOM_NODE_DOCUMENT */ NULL, /* DOM_NODE_DOCUMENT_TYPE */ render_dom_node_source, /* DOM_NODE_DOCUMENT_FRAGMENT */ render_dom_node_source, /* DOM_NODE_NOTATION */ render_dom_node_source, }, /* Pop: */ { /* */ NULL, /* DOM_NODE_ELEMENT */ render_dom_element_end_source, /* DOM_NODE_ATTRIBUTE */ NULL, /* DOM_NODE_TEXT */ NULL, /* DOM_NODE_CDATA_SECTION */ NULL, /* DOM_NODE_ENTITY_REFERENCE */ NULL, /* DOM_NODE_ENTITY */ NULL, /* DOM_NODE_PROC_INSTRUCTION */ NULL, /* DOM_NODE_COMMENT */ NULL, /* DOM_NODE_DOCUMENT */ render_dom_document_end, /* DOM_NODE_DOCUMENT_TYPE */ NULL, /* DOM_NODE_DOCUMENT_FRAGMENT */ NULL, /* DOM_NODE_NOTATION */ NULL, }};/* Shared multiplexor between renderers */voidrender_dom_document(struct cache_entry *cached, struct document *document, struct string *buffer){ unsigned char *head = empty_string_or_(cached->head); struct dom_node *root; struct dom_renderer renderer; struct conv_table *convert_table; struct sgml_parser *parser; unsigned char *string = struri(cached->uri); size_t length = strlen(string); struct dom_string uri = INIT_DOM_STRING(string, length); struct dom_string source = INIT_DOM_STRING(buffer->source, buffer->length); assert(document->options.plain); convert_table = get_convert_table(head, document->options.cp, document->options.assume_cp, &document->cp, &document->cp_status, document->options.hard_assume); init_dom_renderer(&renderer, document, buffer, convert_table); document->bgcolor = document->options.default_bg; if (!strcasecmp("application/rss+xml", cached->content_type)) { renderer.doctype = SGML_DOCTYPE_RSS; } else if (!strcasecmp("application/xbel+xml", cached->content_type) || !strcasecmp("application/x-xbel", cached->content_type) || !strcasecmp("application/xbel", cached->content_type)) { renderer.doctype = SGML_DOCTYPE_XBEL; } else { assertm(!strcasecmp("text/html", cached->content_type) || !strcasecmp("application/xhtml+xml", cached->content_type), "Couldn't resolve doctype '%s'", cached->content_type); renderer.doctype = SGML_DOCTYPE_HTML; } parser = init_sgml_parser(SGML_PARSER_STREAM, renderer.doctype, &uri); if (!parser) return; add_dom_stack_context(&parser->stack, &renderer, &dom_source_renderer_context_info); root = parse_sgml(parser, &source); if (root) { assert(parser->stack.depth == 1); get_dom_stack_top(&parser->stack)->immutable = 0; /* For SGML_PARSER_STREAM this will free the DOM * root node. */ pop_dom_node(&parser->stack); }#ifdef HAVE_REGEX_H if (renderer.find_url) regfree(&renderer.url_regex);#endif done_uri(renderer.base_uri); done_sgml_parser(parser);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -