mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Merge branch 'master' of ssh://pasky.or.cz/srv/git/elinks
Conflicts: src/document/options.c
This commit is contained in:
commit
0e0bacf0d3
@ -184,10 +184,6 @@ MAKE_COLOR = @MAKE_COLOR@
|
||||
|
||||
LIB_O_NAME = lib.o
|
||||
|
||||
# Reverse a CONFIG_* string
|
||||
# Usage $(call not,$(CONFIG_FOO))
|
||||
not = $(if $(findstring yes,$(1)),no,yes)
|
||||
|
||||
### This is here because Makefile.config is usually the first thing
|
||||
### we get and sometimes the all rule can be implicit, yet we want
|
||||
### it always as the default one. So this should make sure it always
|
||||
|
13
Makefile.lib
13
Makefile.lib
@ -74,11 +74,11 @@ quiet_cmd_uninstall = " [$(UNINSTALL_COLOR)UNINSTALL$(END_COLOR)] $(3)/$(n
|
||||
#############################################################################
|
||||
# Special handling of conditional variables
|
||||
|
||||
SUBDIRS += $(SUBDIRS-yes)
|
||||
OBJS += $(OBJS-yes)
|
||||
SUBDIRS += $(SUBDIRS-yes) $(SUBDIRS-unlessno) $(SUBDIRS-unless)
|
||||
OBJS += $(OBJS-yes) $(OBJS-unlessno) $(OBJS-unless)
|
||||
|
||||
ALTDIRS = $(SUBDIRS-no) $(SUBDIRS-)
|
||||
ALTOBJS = $(OBJS-no) $(OBJS-)
|
||||
ALTDIRS = $(SUBDIRS-no) $(SUBDIRS-) $(SUBDIRS-unlessyes)
|
||||
ALTOBJS = $(OBJS-no) $(OBJS-) $(OBJS-unlessyes)
|
||||
|
||||
ifneq ($(findstring cleanall,$(MAKECMDGOALS)),)
|
||||
INCLUDE_ALL=1
|
||||
@ -191,8 +191,7 @@ test-default:
|
||||
|
||||
ifdef TEST_PROGS
|
||||
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o
|
||||
TESTDEPS-$(call not,$(CONFIG_SMALL)) += \
|
||||
$(top_builddir)/src/util/fastfind.o \
|
||||
TESTDEPS-unless$(CONFIG_SMALL) += $(top_builddir)/src/util/fastfind.o
|
||||
|
||||
# Add most of the basic utility library to the test dependencies.
|
||||
TESTDEPS += \
|
||||
@ -206,7 +205,7 @@ TESTDEPS += \
|
||||
$(top_builddir)/src/util/string.o \
|
||||
$(top_builddir)/src/util/time.o
|
||||
|
||||
TESTDEPS += $(TESTDEPS-yes)
|
||||
TESTDEPS += $(TESTDEPS-yes) $(TESTDEPS-unlessno)
|
||||
|
||||
TEST_LIB=$(top_srcdir)/test/libtest.sh
|
||||
export TEST_LIB
|
||||
|
@ -6,6 +6,6 @@ SUBDIRS-$(CONFIG_DOM) += dom
|
||||
|
||||
SUBDIRS = html plain
|
||||
|
||||
OBJS = docdata.o document.o forms.o options.o refresh.o renderer.o
|
||||
OBJS = docdata.o document.o format.o forms.o options.o refresh.o renderer.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "document/css/property.h"
|
||||
#include "document/css/scanner.h"
|
||||
#include "document/css/stylesheet.h"
|
||||
#include "document/format.h"
|
||||
#include "document/html/parser/parse.h"
|
||||
#include "document/options.h"
|
||||
#include "util/align.h"
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "document/css/scanner.h"
|
||||
#include "document/css/stylesheet.h"
|
||||
#include "document/css/value.h"
|
||||
#include "document/html/parser.h"
|
||||
#include "util/color.h"
|
||||
#include "util/lists.h"
|
||||
#include "util/error.h"
|
||||
|
@ -2,7 +2,8 @@
|
||||
#ifndef EL__DOCUMENT_CSS_PROPERTY_H
|
||||
#define EL__DOCUMENT_CSS_PROPERTY_H
|
||||
|
||||
#include "document/html/parser.h"
|
||||
#include "document/format.h"
|
||||
#include "util/align.h"
|
||||
#include "util/color.h"
|
||||
#include "util/lists.h"
|
||||
|
||||
@ -48,7 +49,7 @@ struct css_property {
|
||||
CSS_DISP_BLOCK,
|
||||
} display;
|
||||
struct {
|
||||
enum format_attr add, rem;
|
||||
enum text_style_format add, rem;
|
||||
} font_attribute;
|
||||
enum format_align text_align;
|
||||
/* TODO:
|
||||
|
@ -2,6 +2,7 @@
|
||||
#ifndef EL__DOCUMENT_CSS_STYLESHEET_H
|
||||
#define EL__DOCUMENT_CSS_STYLESHEET_H
|
||||
|
||||
#include "protocol/uri.h"
|
||||
#include "util/lists.h"
|
||||
|
||||
/* #define DEBUG_CSS */
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "document/css/property.h"
|
||||
#include "document/css/scanner.h"
|
||||
#include "document/css/value.h"
|
||||
#include "document/html/parser.h"
|
||||
#include "util/color.h"
|
||||
#include "util/error.h"
|
||||
#include "util/memory.h"
|
||||
|
@ -1,6 +1,6 @@
|
||||
top_builddir=../../..
|
||||
include $(top_builddir)/Makefile.config
|
||||
|
||||
OBJS = renderer.o
|
||||
OBJS = renderer.o rss.o source.o util.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
2
src/document/dom/README
Normal file
2
src/document/dom/README
Normal file
@ -0,0 +1,2 @@
|
||||
This is DOM document renderer. The DOM "engine" itself (parsers, selectors,
|
||||
...) lives directly in src/dom/.
|
@ -4,23 +4,16 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* FreeBSD needs this before regex.h */
|
||||
#ifdef HAVE_REGEX_H
|
||||
#include <regex.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/renderer.h"
|
||||
#include "document/dom/rss.h"
|
||||
#include "document/dom/source.h"
|
||||
#include "document/dom/util.h"
|
||||
#include "document/renderer.h"
|
||||
#include "dom/configuration.h"
|
||||
#include "dom/scanner.h"
|
||||
@ -30,69 +23,16 @@
|
||||
#include "dom/node.h"
|
||||
#include "dom/stack.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 {
|
||||
enum sgml_document_type doctype;
|
||||
struct document *document;
|
||||
|
||||
struct conv_table *convert_table;
|
||||
enum convert_string_mode convert_mode;
|
||||
|
||||
struct uri *base_uri;
|
||||
|
||||
unsigned char *source;
|
||||
unsigned char *end;
|
||||
|
||||
unsigned char *position;
|
||||
int canvas_x, canvas_y;
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
regex_t url_regex;
|
||||
unsigned int find_url:1;
|
||||
#endif
|
||||
struct screen_char styles[DOM_NODES];
|
||||
|
||||
/* RSS renderer variables */
|
||||
struct dom_node *channel;
|
||||
struct dom_node_list *items;
|
||||
struct dom_node *item;
|
||||
struct dom_node *node;
|
||||
struct dom_string text;
|
||||
};
|
||||
|
||||
#define URL_REGEX "(file://|((f|ht|nt)tp(s)?|smb)://[[:alnum:]]+([-@:.]?[[:alnum:]])*\\.[[:alpha:]]{2,4}(:[[:digit:]]+)?)(/(%[[:xdigit:]]{2}|[-_~&=;?.a-z0-9])*)*"
|
||||
#define URL_REGFLAGS (REG_ICASE | REG_EXTENDED)
|
||||
|
||||
static void
|
||||
init_template(struct screen_char *template, struct document_options *options,
|
||||
color_T background, color_T foreground, enum screen_char_attr attr)
|
||||
{
|
||||
struct color_pair colors = INIT_COLOR_PAIR(background, foreground);
|
||||
|
||||
template->attr = attr;
|
||||
template->data = ' ';
|
||||
set_term_color(template, &colors,
|
||||
options->color_flags, options->color_mode);
|
||||
}
|
||||
|
||||
|
||||
/* Checks the user CSS for properties for each DOM node type name */
|
||||
static inline void
|
||||
init_dom_renderer(struct dom_renderer *renderer, struct document *document,
|
||||
struct string *buffer, struct conv_table *convert_table)
|
||||
{
|
||||
enum dom_node_type type;
|
||||
struct css_stylesheet *css = &default_stylesheet;
|
||||
|
||||
memset(renderer, 0, sizeof(*renderer));
|
||||
|
||||
renderer->document = document;
|
||||
@ -102,894 +42,15 @@ init_dom_renderer(struct dom_renderer *renderer, struct document *document,
|
||||
renderer->end = buffer->source + buffer->length;
|
||||
renderer->position = renderer->source;
|
||||
renderer->base_uri = get_uri_reference(document->uri);
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
if (renderer->document->options.plain_display_links) {
|
||||
if (regcomp(&renderer->url_regex, URL_REGEX, URL_REGFLAGS)) {
|
||||
regfree(&renderer->url_regex);
|
||||
} else {
|
||||
renderer->find_url = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (type = 0; type < DOM_NODES; type++) {
|
||||
struct screen_char *template = &renderer->styles[type];
|
||||
color_T background = document->options.default_bg;
|
||||
color_T foreground = document->options.default_fg;
|
||||
enum screen_char_attr attr = 0;
|
||||
static int i_want_struct_module_for_dom;
|
||||
|
||||
struct dom_string *name = get_dom_node_type_name(type);
|
||||
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 } "
|
||||
"cdata-section { color: orange2 } ";
|
||||
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));
|
||||
}
|
||||
|
||||
if (name)
|
||||
if (is_dom_string_set(name))
|
||||
selector = find_css_selector(&css->selectors,
|
||||
CST_ELEMENT, CSR_ROOT,
|
||||
name->string, name->length);
|
||||
|
||||
if (selector) {
|
||||
struct css_property *property;
|
||||
|
||||
foreach (property, selector->properties) {
|
||||
switch (property->type) {
|
||||
case CSS_PT_BACKGROUND_COLOR:
|
||||
case CSS_PT_BACKGROUND:
|
||||
if (property->value_type == CSS_VT_COLOR)
|
||||
background = property->value.color;
|
||||
break;
|
||||
case CSS_PT_COLOR:
|
||||
foreground = property->value.color;
|
||||
break;
|
||||
case CSS_PT_FONT_WEIGHT:
|
||||
if (property->value.font_attribute.add & AT_BOLD)
|
||||
attr |= SCREEN_ATTR_BOLD;
|
||||
break;
|
||||
case CSS_PT_FONT_STYLE:
|
||||
if (property->value.font_attribute.add & AT_UNDERLINE)
|
||||
attr |= SCREEN_ATTR_UNDERLINE;
|
||||
|
||||
if (property->value.font_attribute.add & AT_ITALIC)
|
||||
attr |= SCREEN_ATTR_ITALIC;
|
||||
break;
|
||||
case CSS_PT_TEXT_DECORATION:
|
||||
if (property->value.font_attribute.add & AT_UNDERLINE)
|
||||
attr |= SCREEN_ATTR_UNDERLINE;
|
||||
break;
|
||||
case CSS_PT_DISPLAY:
|
||||
case CSS_PT_NONE:
|
||||
case CSS_PT_TEXT_ALIGN:
|
||||
case CSS_PT_WHITE_SPACE:
|
||||
case CSS_PT_LAST:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init_template(template, &document->options, background, foreground, attr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
done_dom_renderer(struct dom_renderer *renderer)
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
if (renderer->find_url)
|
||||
regfree(&renderer->url_regex);
|
||||
#endif
|
||||
done_uri(renderer->base_uri);
|
||||
}
|
||||
|
||||
|
||||
/* 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 void
|
||||
render_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, charlen;
|
||||
#ifdef CONFIG_UTF8
|
||||
int utf8 = document->options.utf8;
|
||||
unsigned char *end;
|
||||
#endif /* CONFIG_UTF8 */
|
||||
|
||||
|
||||
assert(renderer && template && string && length);
|
||||
|
||||
string = convert_string(convert, string, length, document->options.cp,
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_UTF8
|
||||
end = string + length;
|
||||
#endif /* CONFIG_UTF8 */
|
||||
for (x = 0, charlen = 1; x < length;x += charlen, renderer->canvas_x++) {
|
||||
unsigned char *text = &string[x];
|
||||
|
||||
/* This is mostly to be able to break out so the indentation
|
||||
* level won't get to high. */
|
||||
switch (*text) {
|
||||
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);
|
||||
charlen = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
#ifdef CONFIG_UTF8
|
||||
if (utf8) {
|
||||
unicode_val_T data;
|
||||
charlen = utf8charlen(text);
|
||||
data = utf8_to_unicode(&text, end);
|
||||
|
||||
template->data = (unicode_val_T)data;
|
||||
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
copy_screen_chars(POS(renderer),
|
||||
template, 1);
|
||||
|
||||
X(renderer)++;
|
||||
template->data = UCS_NO_CHAR;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif /* CONFIG_UTF8 */
|
||||
template->data = isscreensafe(*text) ? *text:'.';
|
||||
}
|
||||
|
||||
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 void
|
||||
render_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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,
|
||||
unsigned char *uristring, int urilength)
|
||||
{
|
||||
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;
|
||||
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,
|
||||
uristring, urilength, document->options.cp,
|
||||
CSM_DEFAULT, NULL, NULL, NULL);
|
||||
if (!uristring) return NULL;
|
||||
|
||||
where = join_urls(renderer->base_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;
|
||||
link->type = LINK_HYPERTEXT;
|
||||
link->where = where;
|
||||
link->color.background = document->options.default_bg;
|
||||
link->color.foreground = fgcolor;
|
||||
link->number = document->nlinks;
|
||||
|
||||
init_template(&template, &document->options,
|
||||
link->color.background, link->color.foreground, 0);
|
||||
|
||||
render_dom_text(renderer, &template, string, length);
|
||||
|
||||
for (point = link->points; length > 0; length--, point++, x++) {
|
||||
point->x = x;
|
||||
point->y = y;
|
||||
}
|
||||
|
||||
document->nlinks++;
|
||||
document->links_sorted = 0;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
/* 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 void
|
||||
render_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 void
|
||||
render_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_H
|
||||
static inline void
|
||||
render_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, string, matchlen);
|
||||
|
||||
length -= matchlen;
|
||||
string += matchlen;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
render_dom_text(renderer, template, string, length);
|
||||
|
||||
mem_free_if(alloc_string);
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum dom_code
|
||||
render_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);
|
||||
} else
|
||||
#endif
|
||||
render_dom_node_text(renderer, &renderer->styles[node->type], node);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
/* This callback is also used for rendering processing instruction nodes. */
|
||||
static enum dom_code
|
||||
render_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);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
enum dom_code
|
||||
render_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 DOM_CODE_OK;
|
||||
|
||||
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);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
set_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;
|
||||
}
|
||||
|
||||
enum dom_code
|
||||
render_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,
|
||||
value, valuelen - skips);
|
||||
|
||||
if (skips > 0) {
|
||||
value += valuelen - skips;
|
||||
render_dom_text(renderer, template, value, skips);
|
||||
}
|
||||
} else {
|
||||
render_dom_text(renderer, template, value, valuelen);
|
||||
}
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
enum dom_code
|
||||
render_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);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
enum dom_code
|
||||
render_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);
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* DOM RSS Renderer */
|
||||
|
||||
#define RSS_CONFIG_FLAGS \
|
||||
(DOM_CONFIG_NORMALIZE_WHITESPACE | DOM_CONFIG_NORMALIZE_CHARACTERS)
|
||||
|
||||
enum dom_code
|
||||
dom_rss_push_element(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
|
||||
assert(node && renderer && renderer->document);
|
||||
|
||||
switch (node->data.element.type) {
|
||||
case RSS_ELEMENT_CHANNEL:
|
||||
/* The stack should have: #document * channel */
|
||||
if (stack->depth != 3)
|
||||
break;
|
||||
|
||||
if (!renderer->channel) {
|
||||
renderer->channel = node;
|
||||
}
|
||||
break;
|
||||
|
||||
case RSS_ELEMENT_ITEM:
|
||||
/* The stack should have: #document * channel item */
|
||||
#if 0
|
||||
/* Don't be so strict ... */
|
||||
if (stack->depth != 4)
|
||||
break;
|
||||
#endif
|
||||
/* ... but be exclusive. */
|
||||
if (renderer->item)
|
||||
break;
|
||||
add_to_dom_node_list(&renderer->items, node, -1);
|
||||
renderer->item = node;
|
||||
break;
|
||||
|
||||
case RSS_ELEMENT_LINK:
|
||||
case RSS_ELEMENT_DESCRIPTION:
|
||||
case RSS_ELEMENT_TITLE:
|
||||
case RSS_ELEMENT_AUTHOR:
|
||||
case RSS_ELEMENT_PUBDATE:
|
||||
if (!node->parent || renderer->node != node->parent)
|
||||
break;
|
||||
|
||||
renderer->node = node;
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
enum dom_code
|
||||
dom_rss_pop_element(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct dom_node_list **list;
|
||||
|
||||
assert(node && renderer && renderer->document);
|
||||
|
||||
switch (node->data.element.type) {
|
||||
case RSS_ELEMENT_ITEM:
|
||||
if (is_dom_string_set(&renderer->text))
|
||||
done_dom_string(&renderer->text);
|
||||
renderer->item = NULL;
|
||||
break;
|
||||
|
||||
case RSS_ELEMENT_LINK:
|
||||
case RSS_ELEMENT_DESCRIPTION:
|
||||
case RSS_ELEMENT_TITLE:
|
||||
case RSS_ELEMENT_AUTHOR:
|
||||
case RSS_ELEMENT_PUBDATE:
|
||||
if (!is_dom_string_set(&renderer->text)
|
||||
|| !node->parent
|
||||
|| renderer->item != node->parent
|
||||
|| renderer->node != node)
|
||||
break;
|
||||
|
||||
/* Replace any child nodes with the normalized text node. */
|
||||
list = get_dom_node_list(node->parent, node);
|
||||
done_dom_node_list(*list);
|
||||
if (is_dom_string_set(&renderer->text)) {
|
||||
if (!add_dom_node(node, DOM_NODE_TEXT, &renderer->text))
|
||||
done_dom_string(&renderer->text);
|
||||
}
|
||||
renderer->node = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
|
||||
static struct dom_string *
|
||||
get_rss_text(struct dom_node *node, enum rss_element_type type)
|
||||
{
|
||||
node = get_dom_node_child(node, DOM_NODE_ELEMENT, type);
|
||||
|
||||
if (!node) return NULL;
|
||||
|
||||
node = get_dom_node_child(node, DOM_NODE_TEXT, 0);
|
||||
|
||||
return node ? &node->string: NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
render_rss_item(struct dom_renderer *renderer, struct dom_node *item)
|
||||
{
|
||||
struct dom_string *title = get_rss_text(item, RSS_ELEMENT_TITLE);
|
||||
struct dom_string *link = get_rss_text(item, RSS_ELEMENT_LINK);
|
||||
struct dom_string *author = get_rss_text(item, RSS_ELEMENT_AUTHOR);
|
||||
struct dom_string *date = get_rss_text(item, RSS_ELEMENT_PUBDATE);
|
||||
|
||||
if (title && is_dom_string_set(title)) {
|
||||
if (item == renderer->channel) {
|
||||
unsigned char *str;
|
||||
|
||||
str = convert_string(renderer->convert_table,
|
||||
title->string, title->length,
|
||||
renderer->document->options.cp,
|
||||
CSM_DEFAULT, NULL, NULL, NULL);
|
||||
if (str)
|
||||
renderer->document->title = str;
|
||||
}
|
||||
render_dom_text(renderer, &renderer->styles[DOM_NODE_ELEMENT],
|
||||
title->string, title->length);
|
||||
}
|
||||
|
||||
if (link && is_dom_string_set(link)) {
|
||||
X(renderer)++;
|
||||
add_dom_link(renderer, "[link]", 6, link->string, link->length);
|
||||
}
|
||||
|
||||
/* New line, and indent */
|
||||
Y(renderer)++;
|
||||
X(renderer) = 0;
|
||||
|
||||
if (author && is_dom_string_set(author)) {
|
||||
render_dom_text(renderer, &renderer->styles[DOM_NODE_COMMENT],
|
||||
author->string, author->length);
|
||||
}
|
||||
|
||||
if (date && is_dom_string_set(date)) {
|
||||
if (author && is_dom_string_set(author)) {
|
||||
render_dom_text(renderer, &renderer->styles[DOM_NODE_COMMENT],
|
||||
" - ", 3);
|
||||
}
|
||||
|
||||
render_dom_text(renderer, &renderer->styles[DOM_NODE_COMMENT],
|
||||
date->string, date->length);
|
||||
}
|
||||
|
||||
if ((author && is_dom_string_set(author))
|
||||
|| (date && is_dom_string_set(date))) {
|
||||
/* New line, and indent */
|
||||
Y(renderer)++;
|
||||
X(renderer) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
enum dom_code
|
||||
dom_rss_pop_document(struct dom_stack *stack, struct dom_node *root, void *data)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
|
||||
if (!renderer->channel)
|
||||
return DOM_CODE_OK;
|
||||
|
||||
render_rss_item(renderer, renderer->channel);
|
||||
|
||||
if (renderer->items) {
|
||||
struct dom_node *node;
|
||||
int index;
|
||||
|
||||
foreach_dom_node (renderer->items, node, index) {
|
||||
Y(renderer)++;
|
||||
X(renderer) = 0;
|
||||
render_rss_item(renderer, node);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dom_string_set(&renderer->text))
|
||||
done_dom_string(&renderer->text);
|
||||
mem_free_if(renderer->items);
|
||||
|
||||
done_dom_node(root);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
|
||||
static struct dom_stack_context_info dom_rss_renderer_context_info = {
|
||||
/* Object size: */ 0,
|
||||
/* Push: */
|
||||
{
|
||||
/* */ NULL,
|
||||
/* DOM_NODE_ELEMENT */ dom_rss_push_element,
|
||||
/* 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 */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
|
||||
/* DOM_NODE_NOTATION */ NULL,
|
||||
},
|
||||
/* Pop: */
|
||||
{
|
||||
/* */ NULL,
|
||||
/* DOM_NODE_ELEMENT */ dom_rss_pop_element,
|
||||
/* 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 */ dom_rss_pop_document,
|
||||
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
|
||||
/* DOM_NODE_NOTATION */ NULL,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
get_doctype(struct dom_renderer *renderer, struct cache_entry *cached)
|
||||
{
|
||||
@ -1038,7 +99,7 @@ render_dom_document(struct cache_entry *cached, struct document *document,
|
||||
|
||||
init_dom_renderer(&renderer, document, buffer, convert_table);
|
||||
|
||||
document->bgcolor = document->options.default_bg;
|
||||
document->bgcolor = document->options.default_style.bg;
|
||||
#ifdef CONFIG_UTF8
|
||||
document->options.utf8 = is_cp_utf8(document->options.cp);
|
||||
#endif /* CONFIG_UTF8 */
|
||||
|
262
src/document/dom/rss.c
Normal file
262
src/document/dom/rss.c
Normal file
@ -0,0 +1,262 @@
|
||||
/* DOM-based RSS renderer */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "document/css/css.h"
|
||||
#include "document/css/parser.h"
|
||||
#include "document/css/stylesheet.h"
|
||||
#include "document/document.h"
|
||||
#include "document/dom/util.h"
|
||||
#include "document/dom/rss.h"
|
||||
#include "dom/sgml/rss/rss.h"
|
||||
#include "dom/node.h"
|
||||
#include "dom/stack.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "util/error.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
|
||||
enum rss_style {
|
||||
RSS_STYLE_TITLE,
|
||||
RSS_STYLE_AUTHOR,
|
||||
RSS_STYLE_AUTHOR_DATE_SEP,
|
||||
RSS_STYLE_DATE,
|
||||
RSS_STYLES,
|
||||
};
|
||||
|
||||
struct rss_renderer {
|
||||
/* The current item being processed; can be either a channel or
|
||||
* item element. */
|
||||
struct dom_node *item;
|
||||
|
||||
/* One style per node type. */
|
||||
struct screen_char styles[RSS_STYLES];
|
||||
};
|
||||
|
||||
|
||||
static struct dom_string *
|
||||
get_rss_text(struct dom_node *node, enum rss_element_type type)
|
||||
{
|
||||
node = get_dom_node_child(node, DOM_NODE_ELEMENT, type);
|
||||
|
||||
if (!node) return NULL;
|
||||
|
||||
node = get_dom_node_child(node, DOM_NODE_TEXT, 0);
|
||||
|
||||
return node ? &node->string: NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
render_rss_item(struct dom_renderer *renderer, struct dom_node *item)
|
||||
{
|
||||
struct rss_renderer *rss = renderer->data;
|
||||
struct dom_string *title = get_rss_text(item, RSS_ELEMENT_TITLE);
|
||||
struct dom_string *link = get_rss_text(item, RSS_ELEMENT_LINK);
|
||||
struct dom_string *author = get_rss_text(item, RSS_ELEMENT_AUTHOR);
|
||||
struct dom_string *date = get_rss_text(item, RSS_ELEMENT_PUBDATE);
|
||||
|
||||
if (item->data.element.type == RSS_ELEMENT_ITEM) {
|
||||
Y(renderer)++;
|
||||
X(renderer) = 0;
|
||||
}
|
||||
|
||||
if (title && is_dom_string_set(title)) {
|
||||
if (item->data.element.type == RSS_ELEMENT_CHANNEL) {
|
||||
unsigned char *str;
|
||||
|
||||
str = convert_string(renderer->convert_table,
|
||||
title->string, title->length,
|
||||
renderer->document->options.cp,
|
||||
CSM_DEFAULT, NULL, NULL, NULL);
|
||||
if (str)
|
||||
renderer->document->title = str;
|
||||
}
|
||||
render_dom_text(renderer, &rss->styles[RSS_STYLE_TITLE],
|
||||
title->string, title->length);
|
||||
}
|
||||
|
||||
if (link && is_dom_string_set(link)) {
|
||||
X(renderer)++;
|
||||
add_dom_link(renderer, "[link]", 6, link->string, link->length);
|
||||
}
|
||||
|
||||
/* New line, and indent */
|
||||
Y(renderer)++;
|
||||
X(renderer) = 0;
|
||||
|
||||
if (author && is_dom_string_set(author)) {
|
||||
render_dom_text(renderer, &rss->styles[RSS_STYLE_AUTHOR],
|
||||
author->string, author->length);
|
||||
}
|
||||
|
||||
if (date && is_dom_string_set(date)) {
|
||||
if (author && is_dom_string_set(author)) {
|
||||
render_dom_text(renderer, &rss->styles[RSS_STYLE_AUTHOR_DATE_SEP],
|
||||
" - ", 3);
|
||||
}
|
||||
|
||||
render_dom_text(renderer, &rss->styles[RSS_STYLE_DATE],
|
||||
date->string, date->length);
|
||||
}
|
||||
|
||||
if ((author && is_dom_string_set(author))
|
||||
|| (date && is_dom_string_set(date))) {
|
||||
/* New line, and indent */
|
||||
Y(renderer)++;
|
||||
X(renderer) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
flush_rss_item(struct dom_renderer *renderer, struct rss_renderer *rss)
|
||||
{
|
||||
if (rss->item) {
|
||||
render_rss_item(renderer, rss->item);
|
||||
rss->item = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static enum dom_code
|
||||
dom_rss_push_element(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct rss_renderer *rss = renderer->data;
|
||||
|
||||
assert(node && node->parent && renderer && renderer->document);
|
||||
|
||||
switch (node->data.element.type) {
|
||||
case RSS_ELEMENT_CHANNEL:
|
||||
/* The stack should have: #document * channel */
|
||||
if (stack->depth == 3)
|
||||
rss->item = node;
|
||||
break;
|
||||
|
||||
case RSS_ELEMENT_ITEM:
|
||||
flush_rss_item(renderer, rss);
|
||||
rss->item = node;
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_code
|
||||
dom_rss_pop_element(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct rss_renderer *rss = renderer->data;
|
||||
|
||||
assert(node && node->parent && renderer && renderer->document);
|
||||
|
||||
switch (node->data.element.type) {
|
||||
case RSS_ELEMENT_CHANNEL:
|
||||
flush_rss_item(renderer, rss);
|
||||
break;
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
|
||||
static enum dom_code
|
||||
dom_rss_push_document(struct dom_stack *stack, struct dom_node *root, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct document *document = renderer->document;
|
||||
struct rss_renderer *rss;
|
||||
enum rss_style type;
|
||||
|
||||
struct css_stylesheet *css = &default_stylesheet;
|
||||
{
|
||||
static int i_want_struct_module_for_dom;
|
||||
|
||||
if (!i_want_struct_module_for_dom) {
|
||||
static const unsigned char default_colors[] =
|
||||
"title { color: lightgreen } "
|
||||
"author { color: aqua }"
|
||||
"author-date-sep{ color: aqua }"
|
||||
"date { 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));
|
||||
}
|
||||
}
|
||||
|
||||
rss = renderer->data = mem_calloc(1, sizeof(*rss));
|
||||
if (rss)
|
||||
return DOM_CODE_ALLOC_ERR;
|
||||
|
||||
/* Initialize styles. */
|
||||
|
||||
for (type = 0; type < RSS_STYLES; type++) {
|
||||
struct screen_char *template = &rss->styles[type];
|
||||
static const unsigned char *names[RSS_STYLES] =
|
||||
{ "title", "author", "author-date-sep", "date" };
|
||||
struct css_selector *selector = NULL;
|
||||
|
||||
selector = find_css_selector(&css->selectors,
|
||||
CST_ELEMENT, CSR_ROOT,
|
||||
names[type], strlen(names[type]));
|
||||
init_template_by_style(template, &document->options,
|
||||
selector ? &selector->properties : NULL);
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_code
|
||||
dom_rss_pop_document(struct dom_stack *stack, struct dom_node *root, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct rss_renderer *rss = renderer->data;
|
||||
|
||||
done_dom_node(root);
|
||||
mem_free(rss);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
|
||||
struct dom_stack_context_info dom_rss_renderer_context_info = {
|
||||
/* Object size: */ 0,
|
||||
/* Push: */
|
||||
{
|
||||
/* */ NULL,
|
||||
/* DOM_NODE_ELEMENT */ dom_rss_push_element,
|
||||
/* 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 */ dom_rss_push_document,
|
||||
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
|
||||
/* DOM_NODE_NOTATION */ NULL,
|
||||
},
|
||||
/* Pop: */
|
||||
{
|
||||
/* */ NULL,
|
||||
/* DOM_NODE_ELEMENT */ dom_rss_pop_element,
|
||||
/* 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 */ dom_rss_pop_document,
|
||||
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
|
||||
/* DOM_NODE_NOTATION */ NULL,
|
||||
}
|
||||
};
|
13
src/document/dom/rss.h
Normal file
13
src/document/dom/rss.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef EL__DOCUMENT_DOM_RSS_H
|
||||
#define EL__DOCUMENT_DOM_RSS_H
|
||||
|
||||
#include "dom/stack.h"
|
||||
|
||||
|
||||
#define RSS_CONFIG_FLAGS \
|
||||
(DOM_CONFIG_NORMALIZE_WHITESPACE | DOM_CONFIG_NORMALIZE_CHARACTERS)
|
||||
|
||||
extern struct dom_stack_context_info dom_rss_renderer_context_info;
|
||||
|
||||
#endif
|
450
src/document/dom/source.c
Normal file
450
src/document/dom/source.c
Normal file
@ -0,0 +1,450 @@
|
||||
/* DOM-based SGML (HTML) source view renderer (just syntax highlighting :-) */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* FreeBSD needs this before regex.h */
|
||||
#ifdef HAVE_REGEX_H
|
||||
#include <regex.h>
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#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/document.h"
|
||||
#include "document/dom/renderer.h"
|
||||
#include "document/dom/util.h"
|
||||
#include "document/dom/rss.h"
|
||||
#include "document/renderer.h"
|
||||
#include "dom/configuration.h"
|
||||
#include "dom/scanner.h"
|
||||
#include "dom/sgml/parser.h"
|
||||
#include "dom/sgml/html/html.h"
|
||||
#include "dom/sgml/rss/rss.h"
|
||||
#include "dom/node.h"
|
||||
#include "dom/stack.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "terminal/draw.h"
|
||||
#include "util/error.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
|
||||
|
||||
#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))
|
||||
|
||||
|
||||
#define URL_REGEX "(file://|((f|ht|nt)tp(s)?|smb)://[[:alnum:]]+([-@:.]?[[:alnum:]])*\\.[[:alpha:]]{2,4}(:[[:digit:]]+)?)(/(%[[:xdigit:]]{2}|[-_~&=;?.a-z0-9])*)*"
|
||||
#define URL_REGFLAGS (REG_ICASE | REG_EXTENDED)
|
||||
|
||||
|
||||
struct source_renderer {
|
||||
#ifdef HAVE_REGEX_H
|
||||
regex_t url_regex;
|
||||
unsigned int find_url:1;
|
||||
#endif
|
||||
|
||||
/* One style per node type. */
|
||||
struct screen_char styles[DOM_NODES];
|
||||
};
|
||||
|
||||
|
||||
static inline void
|
||||
render_dom_flush(struct dom_renderer *renderer, unsigned char *string)
|
||||
{
|
||||
struct source_renderer *data = renderer->data;
|
||||
struct screen_char *template = &data->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 void
|
||||
render_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_H
|
||||
static inline void
|
||||
render_dom_node_enhanced_text(struct dom_renderer *renderer, struct dom_node *node)
|
||||
{
|
||||
struct source_renderer *data = renderer->data;
|
||||
regex_t *regex = &data->url_regex;
|
||||
regmatch_t regmatch;
|
||||
unsigned char *string = node->string.string;
|
||||
int length = node->string.length;
|
||||
struct screen_char *template = &data->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, string, matchlen);
|
||||
|
||||
length -= matchlen;
|
||||
string += matchlen;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
render_dom_text(renderer, template, string, length);
|
||||
|
||||
mem_free_if(alloc_string);
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum dom_code
|
||||
render_dom_node_source(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct source_renderer *data = renderer->data;
|
||||
|
||||
assert(node && renderer && renderer->document);
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
if (data->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);
|
||||
} else
|
||||
#endif
|
||||
render_dom_node_text(renderer, &data->styles[node->type], node);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
/* This callback is also used for rendering processing instruction nodes. */
|
||||
static enum dom_code
|
||||
render_dom_element_source(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct source_renderer *data = renderer->data;
|
||||
|
||||
assert(node && renderer && renderer->document);
|
||||
|
||||
render_dom_node_text(renderer, &data->styles[node->type], node);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_code
|
||||
render_dom_element_end_source(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct source_renderer *data = renderer->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 DOM_CODE_OK;
|
||||
|
||||
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, &data->styles[node->type], string, length);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
set_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 enum dom_code
|
||||
render_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct source_renderer *data = renderer->data;
|
||||
struct screen_char *template = &data->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,
|
||||
value, valuelen - skips);
|
||||
|
||||
if (skips > 0) {
|
||||
value += valuelen - skips;
|
||||
render_dom_text(renderer, template, value, skips);
|
||||
}
|
||||
} else {
|
||||
render_dom_text(renderer, template, value, valuelen);
|
||||
}
|
||||
}
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_code
|
||||
render_dom_cdata_source(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct source_renderer *data = renderer->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, &data->styles[DOM_NODE_ATTRIBUTE], string - 6, 5);
|
||||
renderer->position = string - 1;
|
||||
assert_source(renderer, renderer->position, 0);
|
||||
}
|
||||
|
||||
render_dom_node_text(renderer, &data->styles[node->type], node);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
|
||||
static enum dom_code
|
||||
render_dom_document_start(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct document *document = renderer->document;
|
||||
struct source_renderer *data;
|
||||
enum dom_node_type type;
|
||||
|
||||
struct css_stylesheet *css = &default_stylesheet;
|
||||
{
|
||||
static int i_want_struct_module_for_dom;
|
||||
|
||||
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 } "
|
||||
"cdata-section { color: orange2 } ";
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
data = renderer->data = mem_calloc(1, sizeof(*data));
|
||||
|
||||
/* Initialize styles for all the DOM node types. */
|
||||
|
||||
for (type = 0; type < DOM_NODES; type++) {
|
||||
struct screen_char *template = &data->styles[type];
|
||||
struct dom_string *name = get_dom_node_type_name(type);
|
||||
struct css_selector *selector = NULL;
|
||||
|
||||
if (name && is_dom_string_set(name))
|
||||
selector = find_css_selector(&css->selectors,
|
||||
CST_ELEMENT, CSR_ROOT,
|
||||
name->string, name->length);
|
||||
init_template_by_style(template, &document->options,
|
||||
selector ? &selector->properties : NULL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
if (document->options.plain_display_links) {
|
||||
if (regcomp(&data->url_regex, URL_REGEX, URL_REGFLAGS)) {
|
||||
regfree(&data->url_regex);
|
||||
} else {
|
||||
data->find_url = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_code
|
||||
render_dom_document_end(struct dom_stack *stack, struct dom_node *node, void *xxx)
|
||||
{
|
||||
struct dom_renderer *renderer = stack->current->data;
|
||||
struct source_renderer *data = renderer->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);
|
||||
}
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
if (data->find_url)
|
||||
regfree(&data->url_regex);
|
||||
#endif
|
||||
|
||||
mem_free(data);
|
||||
|
||||
return DOM_CODE_OK;
|
||||
}
|
||||
|
||||
|
||||
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 */ render_dom_document_start,
|
||||
/* 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,
|
||||
}
|
||||
};
|
||||
|
10
src/document/dom/source.h
Normal file
10
src/document/dom/source.h
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef EL__DOCUMENT_DOM_SOURCE_H
|
||||
#define EL__DOCUMENT_DOM_SOURCE_H
|
||||
|
||||
#include "dom/stack.h"
|
||||
|
||||
|
||||
extern struct dom_stack_context_info dom_source_renderer_context_info;
|
||||
|
||||
#endif
|
313
src/document/dom/util.c
Normal file
313
src/document/dom/util.c
Normal file
@ -0,0 +1,313 @@
|
||||
/* Utilities for rendering document bits */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* FreeBSD needs this before regex.h */
|
||||
#ifdef HAVE_REGEX_H
|
||||
#include <regex.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "bookmarks/bookmarks.h" /* get_bookmark() */
|
||||
#include "document/css/property.h"
|
||||
#include "document/docdata.h"
|
||||
#include "document/document.h"
|
||||
#include "document/dom/util.h"
|
||||
#include "document/format.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "globhist/globhist.h" /* get_global_history_item() */
|
||||
#include "protocol/uri.h"
|
||||
#include "terminal/draw.h"
|
||||
#include "util/error.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/box.h"
|
||||
|
||||
|
||||
static inline void
|
||||
init_template(struct screen_char *template, struct document_options *options,
|
||||
enum screen_char_attr attr, color_T foreground, color_T background)
|
||||
{
|
||||
struct text_style style = { attr, foreground, background };
|
||||
|
||||
get_screen_char_template(template, options, style);
|
||||
}
|
||||
|
||||
void
|
||||
init_template_by_style(struct screen_char *template, struct document_options *options,
|
||||
LIST_OF(struct css_property) *properties)
|
||||
{
|
||||
struct text_style style = options->default_style;
|
||||
struct css_property *property;
|
||||
|
||||
if (properties) {
|
||||
/* TODO: Use the CSS appliers. */
|
||||
foreach (property, *properties) {
|
||||
switch (property->type) {
|
||||
case CSS_PT_BACKGROUND_COLOR:
|
||||
case CSS_PT_BACKGROUND:
|
||||
if (property->value_type == CSS_VT_COLOR)
|
||||
style.bg = property->value.color;
|
||||
break;
|
||||
case CSS_PT_COLOR:
|
||||
style.fg = property->value.color;
|
||||
break;
|
||||
case CSS_PT_FONT_WEIGHT:
|
||||
style.attr |= property->value.font_attribute.add;
|
||||
break;
|
||||
case CSS_PT_FONT_STYLE:
|
||||
style.attr |= property->value.font_attribute.add;
|
||||
break;
|
||||
case CSS_PT_TEXT_DECORATION:
|
||||
style.attr |= property->value.font_attribute.add;
|
||||
break;
|
||||
case CSS_PT_DISPLAY:
|
||||
case CSS_PT_NONE:
|
||||
case CSS_PT_TEXT_ALIGN:
|
||||
case CSS_PT_WHITE_SPACE:
|
||||
case CSS_PT_LAST:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get_screen_char_template(template, options, style);
|
||||
}
|
||||
|
||||
|
||||
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 POS(renderer) (&(renderer)->document->data[Y(renderer)].chars[X(renderer)])
|
||||
#define WIDTH(renderer, add) ((renderer)->canvas_x + (add))
|
||||
|
||||
static void
|
||||
render_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, charlen;
|
||||
#ifdef CONFIG_UTF8
|
||||
int utf8 = document->options.utf8;
|
||||
unsigned char *end;
|
||||
#endif /* CONFIG_UTF8 */
|
||||
|
||||
|
||||
assert(renderer && template && string && length);
|
||||
|
||||
string = convert_string(convert, string, length, document->options.cp,
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_UTF8
|
||||
end = string + length;
|
||||
#endif /* CONFIG_UTF8 */
|
||||
for (x = 0, charlen = 1; x < length;x += charlen, renderer->canvas_x++) {
|
||||
unsigned char *text = &string[x];
|
||||
|
||||
/* This is mostly to be able to break out so the indentation
|
||||
* level won't get to high. */
|
||||
switch (*text) {
|
||||
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);
|
||||
charlen = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
#ifdef CONFIG_UTF8
|
||||
if (utf8) {
|
||||
unicode_val_T data;
|
||||
charlen = utf8charlen(text);
|
||||
data = utf8_to_unicode(&text, end);
|
||||
|
||||
template->data = (unicode_val_T)data;
|
||||
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
copy_screen_chars(POS(renderer),
|
||||
template, 1);
|
||||
|
||||
X(renderer)++;
|
||||
template->data = UCS_NO_CHAR;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif /* CONFIG_UTF8 */
|
||||
template->data = isscreensafe(*text) ? *text:'.';
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
render_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define realloc_document_links(doc, size) \
|
||||
ALIGN_LINK(&(doc)->links, (doc)->nlinks, size)
|
||||
|
||||
inline struct link *
|
||||
add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length,
|
||||
unsigned char *uristring, int urilength)
|
||||
{
|
||||
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;
|
||||
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,
|
||||
uristring, urilength, document->options.cp,
|
||||
CSM_DEFAULT, NULL, NULL, NULL);
|
||||
if (!uristring) return NULL;
|
||||
|
||||
where = join_urls(renderer->base_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;
|
||||
link->type = LINK_HYPERTEXT;
|
||||
link->where = where;
|
||||
link->color.background = document->options.default_style.bg;
|
||||
link->color.foreground = fgcolor;
|
||||
link->number = document->nlinks;
|
||||
|
||||
init_template(&template, &document->options,
|
||||
0, link->color.foreground, link->color.background);
|
||||
|
||||
render_dom_text(renderer, &template, string, length);
|
||||
|
||||
for (point = link->points; length > 0; length--, point++, x++) {
|
||||
point->x = x;
|
||||
point->y = y;
|
||||
}
|
||||
|
||||
document->nlinks++;
|
||||
document->links_sorted = 0;
|
||||
|
||||
return link;
|
||||
}
|
54
src/document/dom/util.h
Normal file
54
src/document/dom/util.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef EL__DOCUMENT_DOM_UTIL_H
|
||||
#define EL__DOCUMENT_DOM_UTIL_H
|
||||
|
||||
/* This header is meant to be used only amongst the DOM renderers. */
|
||||
|
||||
#include <sys/types.h> /* FreeBSD needs this before regex.h */
|
||||
#ifdef HAVE_REGEX_H
|
||||
#include <regex.h>
|
||||
#endif
|
||||
|
||||
#include "dom/sgml/sgml.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "terminal/draw.h"
|
||||
|
||||
|
||||
struct document;
|
||||
struct uri;
|
||||
struct dom_node;
|
||||
struct dom_node_list;
|
||||
struct dom_string;
|
||||
|
||||
struct dom_renderer {
|
||||
enum sgml_document_type doctype;
|
||||
struct document *document;
|
||||
|
||||
struct conv_table *convert_table;
|
||||
enum convert_string_mode convert_mode;
|
||||
|
||||
struct uri *base_uri;
|
||||
|
||||
unsigned char *source;
|
||||
unsigned char *end;
|
||||
|
||||
unsigned char *position;
|
||||
int canvas_x, canvas_y;
|
||||
|
||||
/* Renderer-specific data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define X(renderer) ((renderer)->canvas_x)
|
||||
#define Y(renderer) ((renderer)->canvas_y)
|
||||
|
||||
|
||||
void init_template_by_style(struct screen_char *template,
|
||||
struct document_options *options,
|
||||
LIST_OF(struct css_property) *properties);
|
||||
|
||||
void render_dom_text(struct dom_renderer *renderer, struct screen_char *template,
|
||||
unsigned char *string, int length);
|
||||
struct link *add_dom_link(struct dom_renderer *renderer, unsigned char *string,
|
||||
int length, unsigned char *uristring, int urilength);
|
||||
|
||||
#endif
|
46
src/document/format.c
Normal file
46
src/document/format.c
Normal file
@ -0,0 +1,46 @@
|
||||
/** Format attributes utilities
|
||||
* @file */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "document/format.h"
|
||||
#include "document/options.h"
|
||||
#include "terminal/draw.h"
|
||||
#include "util/color.h"
|
||||
|
||||
|
||||
void
|
||||
get_screen_char_template(struct screen_char *template,
|
||||
struct document_options *options,
|
||||
struct text_style style)
|
||||
{
|
||||
template->attr = 0;
|
||||
template->data = ' ';
|
||||
|
||||
if (style.attr) {
|
||||
if (style.attr & AT_UNDERLINE) {
|
||||
template->attr |= SCREEN_ATTR_UNDERLINE;
|
||||
}
|
||||
|
||||
if (style.attr & AT_BOLD) {
|
||||
template->attr |= SCREEN_ATTR_BOLD;
|
||||
}
|
||||
|
||||
if (style.attr & AT_ITALIC) {
|
||||
template->attr |= SCREEN_ATTR_ITALIC;
|
||||
}
|
||||
|
||||
if (style.attr & AT_GRAPHICS) {
|
||||
template->attr |= SCREEN_ATTR_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct color_pair colors = INIT_COLOR_PAIR(style.bg, style.fg);
|
||||
set_term_color(template, &colors, options->color_flags, options->color_mode);
|
||||
}
|
||||
}
|
28
src/document/format.h
Normal file
28
src/document/format.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef EL__DOCUMENT_FORMAT_H
|
||||
#define EL__DOCUMENT_FORMAT_H
|
||||
|
||||
#include "util/color.h"
|
||||
|
||||
struct document_options;
|
||||
struct screen_char;
|
||||
|
||||
|
||||
enum text_style_format {
|
||||
AT_BOLD = 1,
|
||||
AT_ITALIC = 2,
|
||||
AT_UNDERLINE = 4,
|
||||
AT_FIXED = 8,
|
||||
AT_GRAPHICS = 16,
|
||||
AT_PREFORMATTED = 32,
|
||||
};
|
||||
|
||||
struct text_style {
|
||||
enum text_style_format attr;
|
||||
color_T fg;
|
||||
color_T bg;
|
||||
};
|
||||
|
||||
void get_screen_char_template(struct screen_char *template, struct document_options *options, struct text_style style);
|
||||
|
||||
#endif
|
||||
|
@ -702,7 +702,7 @@ get_image_map(unsigned char *head, unsigned char *pos, unsigned char *eof,
|
||||
|
||||
|
||||
|
||||
struct html_element *
|
||||
void *
|
||||
init_html_parser_state(struct html_context *html_context,
|
||||
enum html_element_mortality_type type,
|
||||
int align, int margin, int width)
|
||||
@ -728,8 +728,10 @@ init_html_parser_state(struct html_context *html_context,
|
||||
|
||||
void
|
||||
done_html_parser_state(struct html_context *html_context,
|
||||
struct html_element *element)
|
||||
void *state)
|
||||
{
|
||||
struct html_element *element = state;
|
||||
|
||||
html_context->line_breax = 1;
|
||||
|
||||
while (html_top != element) {
|
||||
@ -801,8 +803,7 @@ init_html_parser(struct uri *uri, struct document_options *options,
|
||||
format.form = NULL;
|
||||
format.title = NULL;
|
||||
|
||||
format.style.fg = options->default_fg;
|
||||
format.style.bg = options->default_bg;
|
||||
format.style = options->default_style;
|
||||
format.clink = options->default_link;
|
||||
format.vlink = options->default_vlink;
|
||||
#ifdef CONFIG_BOOKMARKS
|
||||
@ -819,7 +820,7 @@ init_html_parser(struct uri *uri, struct document_options *options,
|
||||
par_format.dd_margin = options->margin;
|
||||
par_format.flags = P_NONE;
|
||||
|
||||
par_format.bgcolor = options->default_bg;
|
||||
par_format.bgcolor = options->default_style.bg;
|
||||
|
||||
html_top->invisible = 0;
|
||||
html_top->name = NULL;
|
||||
|
@ -2,6 +2,7 @@
|
||||
#ifndef EL__DOCUMENT_HTML_PARSER_H
|
||||
#define EL__DOCUMENT_HTML_PARSER_H
|
||||
|
||||
#include "document/format.h"
|
||||
#include "intl/charsets.h" /* unicode_val_T */
|
||||
#include "util/align.h"
|
||||
#include "util/color.h"
|
||||
@ -16,28 +17,14 @@ struct menu_item;
|
||||
struct part;
|
||||
struct string;
|
||||
struct uri;
|
||||
enum html_special_type;
|
||||
|
||||
/* XXX: This is just terible - this interface is from 75% only for other HTML
|
||||
* files - there's lack of any well defined interface and it's all randomly
|
||||
* mixed up :/. */
|
||||
|
||||
enum format_attr {
|
||||
AT_BOLD = 1,
|
||||
AT_ITALIC = 2,
|
||||
AT_UNDERLINE = 4,
|
||||
AT_FIXED = 8,
|
||||
AT_GRAPHICS = 16,
|
||||
AT_PREFORMATTED = 32,
|
||||
};
|
||||
|
||||
struct text_attrib_style {
|
||||
enum format_attr attr;
|
||||
color_T fg;
|
||||
color_T bg;
|
||||
};
|
||||
|
||||
struct text_attrib {
|
||||
struct text_attrib_style style;
|
||||
struct text_style style;
|
||||
|
||||
int fontsize;
|
||||
unsigned char *link;
|
||||
@ -150,23 +137,6 @@ struct html_element {
|
||||
#define is_inline_element(e) (e->linebreak == 0)
|
||||
#define is_block_element(e) (e->linebreak > 0)
|
||||
|
||||
enum html_special_type {
|
||||
SP_TAG,
|
||||
SP_FORM,
|
||||
SP_CONTROL,
|
||||
SP_TABLE,
|
||||
SP_USED,
|
||||
SP_FRAMESET,
|
||||
SP_FRAME,
|
||||
SP_NOWRAP,
|
||||
SP_CACHE_CONTROL,
|
||||
SP_CACHE_EXPIRES,
|
||||
SP_REFRESH,
|
||||
SP_STYLESHEET,
|
||||
SP_COLOR_LINK_LINES,
|
||||
SP_SCRIPT,
|
||||
};
|
||||
|
||||
/* Interface for the renderer */
|
||||
|
||||
struct html_context *
|
||||
@ -177,11 +147,10 @@ init_html_parser(struct uri *uri, struct document_options *options,
|
||||
void (*line_break)(struct html_context *),
|
||||
void *(*special)(struct html_context *, enum html_special_type,
|
||||
...));
|
||||
|
||||
void done_html_parser(struct html_context *html_context);
|
||||
struct html_element *init_html_parser_state(struct html_context *html_context, enum html_element_mortality_type type, int align, int margin, int width);
|
||||
void done_html_parser_state(struct html_context *html_context,
|
||||
struct html_element *element);
|
||||
|
||||
void *init_html_parser_state(struct html_context *html_context, enum html_element_mortality_type type, int align, int margin, int width);
|
||||
void done_html_parser_state(struct html_context *html_context, void *state);
|
||||
|
||||
/* Interface for the table handling */
|
||||
|
||||
|
@ -197,7 +197,7 @@ html_apply_canvas_bgcolor(struct html_context *html_context)
|
||||
}
|
||||
|
||||
if (html_context->has_link_lines
|
||||
&& par_format.bgcolor != html_context->options->default_bg
|
||||
&& par_format.bgcolor != html_context->options->default_style.bg
|
||||
&& !search_html_stack(html_context, "BODY")) {
|
||||
html_context->special_f(html_context, SP_COLOR_LINK_LINES);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "document/html/parser/parse.h"
|
||||
#include "document/html/parser/stack.h"
|
||||
#include "document/html/parser.h"
|
||||
#include "document/html/renderer.h"
|
||||
#include "document/options.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "util/conv.h"
|
||||
|
@ -340,39 +340,19 @@ static inline struct screen_char *
|
||||
get_format_screen_char(struct html_context *html_context,
|
||||
enum link_state link_state)
|
||||
{
|
||||
static struct text_attrib_style ta_cache = { -1, 0x0, 0x0 };
|
||||
static struct text_style ta_cache = { -1, 0x0, 0x0 };
|
||||
static struct screen_char schar_cache;
|
||||
|
||||
if (memcmp(&ta_cache, &format.style, sizeof(ta_cache))) {
|
||||
copy_struct(&ta_cache, &format.style);
|
||||
|
||||
schar_cache.attr = 0;
|
||||
if (format.style.attr) {
|
||||
if (format.style.attr & AT_UNDERLINE) {
|
||||
schar_cache.attr |= SCREEN_ATTR_UNDERLINE;
|
||||
}
|
||||
|
||||
if (format.style.attr & AT_BOLD) {
|
||||
schar_cache.attr |= SCREEN_ATTR_BOLD;
|
||||
}
|
||||
|
||||
if (format.style.attr & AT_ITALIC) {
|
||||
schar_cache.attr |= SCREEN_ATTR_ITALIC;
|
||||
}
|
||||
|
||||
if (format.style.attr & AT_GRAPHICS) {
|
||||
schar_cache.attr |= SCREEN_ATTR_FRAME;
|
||||
}
|
||||
}
|
||||
struct text_style final_style = format.style;
|
||||
|
||||
if (link_state != LINK_STATE_NONE
|
||||
&& html_context->options->underline_links) {
|
||||
schar_cache.attr |= SCREEN_ATTR_UNDERLINE;
|
||||
final_style.attr |= AT_UNDERLINE;
|
||||
}
|
||||
|
||||
set_screen_char_color(&schar_cache, format.style.bg, format.style.fg,
|
||||
html_context->options->color_flags,
|
||||
html_context->options->color_mode);
|
||||
get_screen_char_template(&schar_cache, html_context->options, final_style);
|
||||
}
|
||||
|
||||
if (!!(schar_cache.attr & SCREEN_ATTR_UNSEARCHABLE)
|
||||
@ -2094,7 +2074,7 @@ format_html_part(struct html_context *html_context,
|
||||
int link_num)
|
||||
{
|
||||
struct part *part;
|
||||
struct html_element *html_state;
|
||||
void *html_state;
|
||||
int llm = renderer_context.last_link_to_move;
|
||||
struct tag *ltm = renderer_context.last_tag_to_move;
|
||||
int ef = renderer_context.empty_format;
|
||||
|
@ -12,6 +12,27 @@ struct string;
|
||||
|
||||
void render_html_document(struct cache_entry *cached, struct document *document, struct string *buffer);
|
||||
|
||||
|
||||
/* Interface with parser.c */
|
||||
|
||||
enum html_special_type {
|
||||
SP_TAG,
|
||||
SP_FORM,
|
||||
SP_CONTROL,
|
||||
SP_TABLE,
|
||||
SP_USED,
|
||||
SP_FRAMESET,
|
||||
SP_FRAME,
|
||||
SP_NOWRAP,
|
||||
SP_CACHE_CONTROL,
|
||||
SP_CACHE_EXPIRES,
|
||||
SP_REFRESH,
|
||||
SP_STYLESHEET,
|
||||
SP_COLOR_LINK_LINES,
|
||||
SP_SCRIPT,
|
||||
};
|
||||
|
||||
|
||||
/* Interface with tables.c */
|
||||
|
||||
/* This holds some context about what we're currently rendering. We only need
|
||||
|
@ -37,8 +37,8 @@ init_document_options(struct session *ses, struct document_options *doo)
|
||||
doo->default_form_input_size = get_opt_int("document.browse.forms.input_size", ses);
|
||||
|
||||
/* Color options. */
|
||||
doo->default_fg = get_opt_color("document.colors.text", ses);
|
||||
doo->default_bg = get_opt_color("document.colors.background", ses);
|
||||
doo->default_style.fg = get_opt_color("document.colors.text", ses);
|
||||
doo->default_style.bg = get_opt_color("document.colors.background", ses);
|
||||
doo->default_link = get_opt_color("document.colors.link", ses);
|
||||
doo->default_vlink = get_opt_color("document.colors.vlink", ses);
|
||||
#ifdef CONFIG_BOOKMARKS
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef EL__DOCUMENT_OPTIONS_H
|
||||
#define EL__DOCUMENT_OPTIONS_H
|
||||
|
||||
#include "document/format.h"
|
||||
#include "terminal/color.h"
|
||||
#include "util/color.h"
|
||||
#include "util/box.h"
|
||||
@ -34,8 +35,7 @@ struct document_options {
|
||||
|
||||
/** @name The default (fallback) colors.
|
||||
* @{ */
|
||||
color_T default_fg;
|
||||
color_T default_bg;
|
||||
struct text_style default_style;
|
||||
color_T default_link;
|
||||
color_T default_vlink;
|
||||
#ifdef CONFIG_BOOKMARKS
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "config/options.h"
|
||||
#include "document/docdata.h"
|
||||
#include "document/document.h"
|
||||
#include "document/format.h"
|
||||
#include "document/options.h"
|
||||
#include "document/plain/renderer.h"
|
||||
#include "document/renderer.h"
|
||||
@ -92,7 +93,7 @@ add_document_link(struct document *document, unsigned char *uri, int length,
|
||||
link->npoints = length;
|
||||
link->type = LINK_HYPERTEXT;
|
||||
link->where = uri;
|
||||
link->color.background = document->options.default_bg;
|
||||
link->color.background = document->options.default_style.bg;
|
||||
link->color.foreground = document->options.default_link;
|
||||
link->number = document->nlinks;
|
||||
|
||||
@ -213,7 +214,7 @@ print_document_link(struct plain_renderer *renderer, int lineno,
|
||||
|
||||
line[link_end] = saved_char;
|
||||
|
||||
new_link->color.background = doc_opts->default_bg;
|
||||
new_link->color.background = doc_opts->default_style.bg;
|
||||
|
||||
set_term_color(&template, &new_link->color,
|
||||
doc_opts->color_flags, doc_opts->color_mode);
|
||||
@ -478,14 +479,7 @@ next:
|
||||
static void
|
||||
init_template(struct screen_char *template, struct document_options *options)
|
||||
{
|
||||
color_T background = options->default_bg;
|
||||
color_T foreground = options->default_fg;
|
||||
struct color_pair colors = INIT_COLOR_PAIR(background, foreground);
|
||||
|
||||
template->attr = 0;
|
||||
template->data = ' ';
|
||||
set_term_color(template, &colors,
|
||||
options->color_flags, options->color_mode);
|
||||
get_screen_char_template(template, options, options->default_style);
|
||||
}
|
||||
|
||||
static struct node *
|
||||
@ -643,7 +637,7 @@ render_plain_document(struct cache_entry *cached, struct document *document,
|
||||
renderer.max_width = document->options.wrap ? document->options.box.width
|
||||
: INT_MAX;
|
||||
|
||||
document->bgcolor = document->options.default_bg;
|
||||
document->bgcolor = document->options.default_style.bg;
|
||||
document->width = 0;
|
||||
#ifdef CONFIG_UTF8
|
||||
document->options.utf8 = is_cp_utf8(document->options.cp);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/** HTML renderer
|
||||
/** Generic renderer multiplexer
|
||||
* @file */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -8,6 +8,7 @@ struct document_options;
|
||||
struct document_view;
|
||||
struct session;
|
||||
struct view_state;
|
||||
struct screen_char;
|
||||
|
||||
void render_document(struct view_state *, struct document_view *, struct document_options *);
|
||||
void render_document_frames(struct session *ses, int no_cache);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "dialogs/menu.h"
|
||||
#include "dialogs/status.h"
|
||||
#include "document/html/frames.h"
|
||||
#include "document/html/parser.h"
|
||||
#include "document/html/renderer.h"
|
||||
#include "document/refresh.h"
|
||||
#include "document/view.h"
|
||||
|
@ -3,7 +3,7 @@ include $(top_builddir)/Makefile.config
|
||||
|
||||
INCLUDES += $(GNUTLS_CFLAGS) $(OPENSSL_CFLAGS)
|
||||
|
||||
OBJS-$(call not,$(CONFIG_SMALL)) += fastfind.o
|
||||
OBJS-unless$(CONFIG_SMALL) += fastfind.o
|
||||
OBJS-$(CONFIG_CSS) += scanner.o
|
||||
OBJS-$(CONFIG_DEBUG) += memdebug.o
|
||||
OBJS-$(CONFIG_DOM) += scanner.o
|
||||
@ -12,14 +12,14 @@ OBJS-$(CONFIG_DOM) += scanner.o
|
||||
# (either the real thing or GNUTLS compat wrappers).
|
||||
OBJS-$(CONFIG_OWN_LIBC) += md5.o
|
||||
ifeq ($(CONFIG_GNUTLS_OPENSSL_COMPAT),no)
|
||||
OBJS-$(call not,$(CONFIG_OPENSSL)) += md5.o
|
||||
OBJS-unless$(CONFIG_OPENSSL) += md5.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BITTORRENT),yes)
|
||||
# BitTorrent is the only user. Compile in SHA1 if testing libc or
|
||||
# there is no OpenSSL. The GNUTLS OpenSSL wrappers doesn't have it.
|
||||
OBJS-$(CONFIG_OWN_LIBC) += sha1.o
|
||||
OBJS-$(call not,$(CONFIG_OPENSSL)) += sha1.o
|
||||
OBJS-unless$(CONFIG_OPENSSL) += sha1.o
|
||||
endif
|
||||
|
||||
OBJS = \
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "dialogs/menu.h"
|
||||
#include "document/document.h"
|
||||
#include "document/forms.h"
|
||||
#include "document/html/parser.h"
|
||||
#include "document/view.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "formhist/formhist.h"
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "dialogs/status.h"
|
||||
#include "document/document.h"
|
||||
#include "document/forms.h"
|
||||
#include "document/html/parser.h"
|
||||
#include "document/html/renderer.h"
|
||||
#include "document/options.h"
|
||||
#include "document/view.h"
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "bfu/dialog.h"
|
||||
#include "document/document.h"
|
||||
#include "document/forms.h"
|
||||
#include "document/html/parser.h"
|
||||
#include "document/html/renderer.h"
|
||||
#include "document/view.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
|
Loading…
Reference in New Issue
Block a user