renderer.c

来自「elinks下lynx是最重要的二个文本浏览器, 在linux下非常实用, el」· C语言 代码 · 共 2,052 行 · 第 1/4 页

C
2,052
字号
			} else {				int to_move = link->npoints - (i + 1);				assert(to_move >= 0);				if (to_move > 0) {					memmove(&link->points[i],						&link->points[i + 1],						to_move *						sizeof(*link->points));					i--;				}				link->npoints--;			}		}		if (!matched) {			renderer_context.last_link_to_move = nlink;		}	}	/* Don't move tags when removing links. */	if (yt < 0) return;	matched = 0;	tag = renderer_context.last_tag_to_move;	while (list_has_next(part->document->tags, tag)) {		tag = tag->next;		if (tag->y == Y(yf)) {			matched = 1;			if (tag->x >= X(xf)) {				tag->y = Y(yt);				tag->x += -xf + xt;			}		} else if (!matched && tag->y > Y(yf)) {			/* Fix for bug 479 (part two) */			matched = 1;		}		if (!matched) renderer_context.last_tag_to_move = tag;	}}static inline voidcopy_chars(struct html_context *html_context, int x, int y, int width, struct screen_char *d){	struct part *part;	assert(html_context);	if_assert_failed return;	part = html_context->part;	assert(width > 0 && part && part->document && part->document->data);	if_assert_failed return;	if (realloc_line(html_context, part->document, Y(y), X(x) + width - 1))		return;	copy_screen_chars(&POS(x, y), d, width);}static inline voidmove_chars(struct html_context *html_context, int x, int y, int nx, int ny){	struct part *part;	assert(html_context);	if_assert_failed return;	part = html_context->part;	assert(part && part->document && part->document->data);	if_assert_failed return;	if (LEN(y) - x <= 0) return;	copy_chars(html_context, nx, ny, LEN(y) - x, &POS(x, y));	LINE(y).length = X(x);	move_links(html_context, x, y, nx, ny);}static inline voidshift_chars(struct html_context *html_context, int y, int shift){	struct part *part;	struct screen_char *a;	int len;	assert(html_context);	if_assert_failed return;	part = html_context->part;	assert(part && part->document && part->document->data);	if_assert_failed return;	len = LEN(y);	a = fmem_alloc(len * sizeof(*a));	if (!a) return;	copy_screen_chars(a, &POS(0, y), len);	clear_hchars(html_context, 0, y, shift);	copy_chars(html_context, shift, y, len, a);	fmem_free(a);	move_links(html_context, 0, y, shift, y);}static inline voiddel_chars(struct html_context *html_context, int x, int y){	struct part *part;	assert(html_context);	if_assert_failed return;	part = html_context->part;	assert(part && part->document && part->document->data);	if_assert_failed return;	LINE(y).length = X(x);	move_links(html_context, x, y, -1, -1);}#define overlap(x) int_max((x).width - (x).rightmargin, 0)static int inlinesplit_line_at(struct html_context *html_context, int width){	struct part *part;	int tmp;	int new_width = width + par_format.rightmargin;	assert(html_context);	if_assert_failed return 0;	part = html_context->part;	assert(part);	if_assert_failed return 0;	/* Make sure that we count the right margin to the total	 * actual box width. */	int_lower_bound(&part->box.width, new_width);	if (part->document) {		assert(part->document->data);		if_assert_failed return 0;		assertm(POS(width, part->cy).data == ' ',			"bad split: %c", POS(width, part->cy).data);		move_chars(html_context, width + 1, part->cy, par_format.leftmargin, part->cy + 1);		del_chars(html_context, width, part->cy);	}	width++; /* Since we were using (x + 1) only later... */	tmp = part->spaces_len - width;	if (tmp > 0) {		/* 0 is possible and I'm paranoid ... --Zas */		memmove(part->spaces, part->spaces + width, tmp);	}	assert(tmp >= 0);	if_assert_failed tmp = 0;	memset(part->spaces + tmp, 0, width);	if (par_format.leftmargin > 0) {		tmp = part->spaces_len - par_format.leftmargin;		assertm(tmp > 0, "part->spaces_len - par_format.leftmargin == %d", tmp);		/* So tmp is zero, memmove() should survive that. Don't recover. */		memmove(part->spaces + par_format.leftmargin, part->spaces, tmp);	}	part->cy++;	if (part->cx == width) {		part->cx = -1;		int_lower_bound(&part->box.height, part->cy);		return 2;	} else {		part->cx -= width - par_format.leftmargin;		int_lower_bound(&part->box.height, part->cy + 1);		return 1;	}}/* Here, we scan the line for a possible place where we could split it into two * (breaking it, because it is too long), if it is overlapping from the maximal * box width. *//* Returns 0 if there was found no spot suitable for breaking the line. *         1 if the line was split into two. *         2 if the (second) splitted line is blank (that is useful to determine *           ie. if the next line_break() should really break the line; we don't *           want to see any blank lines to pop up, do we?). */static intsplit_line(struct html_context *html_context){	struct part *part;	int x;	assert(html_context);	if_assert_failed return 0;	part = html_context->part;	assert(part);	if_assert_failed return 0;	for (x = overlap(par_format); x >= par_format.leftmargin; x--)		if (x < part->spaces_len && part->spaces[x])			return split_line_at(html_context, x);	for (x = par_format.leftmargin; x < part->cx ; x++)		if (x < part->spaces_len && part->spaces[x])			return split_line_at(html_context, x);	/* Make sure that we count the right margin to the total	 * actual box width. */	int_lower_bound(&part->box.width, part->cx + par_format.rightmargin);	return 0;}/* Insert @new_spaces spaces before the coordinates @x and @y, * adding those spaces to whatever link is at those coordinates. *//* TODO: Integrate with move_links. */static voidinsert_spaces_in_link(struct part *part, int x, int y, int new_spaces){	int i = part->document->nlinks;	x = X(x);	y = Y(y);	while (i--) {		struct link *link = &part->document->links[i];		int j = link->npoints;		while (j-- > 1) {			struct point *point = &link->points[j];			if (point->x != x || point->y != y)				continue;			if (!realloc_points(link, link->npoints + new_spaces))				return;			link->npoints += new_spaces;			point = &link->points[link->npoints - 1];			while (new_spaces--) {				point->x = --x;				point->y = y;				point--;			}			return;		}	}}/* This function is very rare exemplary of clean and beautyful code here. * Please handle with care. --pasky */static voidjustify_line(struct html_context *html_context, int y){	struct part *part;	struct screen_char *line; /* we save original line here */	int len;	int pos;	int *space_list;	int spaces;	int diff;	assert(html_context);	if_assert_failed return;	part = html_context->part;	assert(part && part->document && part->document->data);	if_assert_failed return;	len = LEN(y);	assert(len > 0);	if_assert_failed return;	line = fmem_alloc(len * sizeof(*line));	if (!line) return;	/* It may sometimes happen that the line is only one char long and that	 * char is space - then we're going to write to both [0] and [1], but	 * we allocated only one field. Thus, we've to do (len + 1). --pasky */	space_list = fmem_alloc((len + 1) * sizeof(*space_list));	if (!space_list) {		fmem_free(line);		return;	}	copy_screen_chars(line, &POS(0, y), len);	/* Skip leading spaces */	spaces = 0;	pos = 0;	while (line[pos].data == ' ')		pos++;	/* Yes, this can be negative, we know. But we add one to it always	 * anyway, so it's ok. */	space_list[spaces++] = pos - 1;	/* Count spaces */	for (; pos < len; pos++)		if (line[pos].data == ' ')			space_list[spaces++] = pos;	space_list[spaces] = len;	/* Realign line */	/* Diff is the difference between the width of the paragraph	 * and the current length of the line. */	diff = overlap(par_format) - len;	/* We check diff > 0 because diff can be negative (i.e., we have	 * an unbroken line of length > overlap(par_format))	 * even when spaces > 1 if the line has only non-breaking spaces. */	if (spaces > 1 && diff > 0) {		int prev_end = 0;		int word;		clear_hchars(html_context, 0, y, overlap(par_format));		for (word = 0; word < spaces; word++) {			/* We have to increase line length by 'diff' num. of			 * characters, so we move 'word'th word 'word_shift'			 * characters right. */			int word_start = space_list[word] + 1;			int word_len = space_list[word + 1] - word_start;			int word_shift;			int new_start;			int new_spaces;			assert(word_len >= 0);			if_assert_failed continue;			if (!word_len) continue;			word_shift = (word * diff) / (spaces - 1);			new_start = word_start + word_shift;			copy_chars(html_context, new_start, y, word_len,				   &line[word_start]);			new_spaces = new_start - prev_end - 1;			if (word && new_spaces) {				move_links(html_context, prev_end + 1, y, new_start, y);				insert_spaces_in_link(part,						      new_start, y, new_spaces);			}			prev_end = new_start + word_len;		}	}	fmem_free(space_list);	fmem_free(line);}static voidalign_line(struct html_context *html_context, int y, int last){	struct part *part;	int shift;	int len;	assert(html_context);	if_assert_failed return;	part = html_context->part;	assert(part && part->document && part->document->data);	if_assert_failed return;	len = LEN(y);	if (!len || par_format.align == ALIGN_LEFT)		return;	if (par_format.align == ALIGN_JUSTIFY) {		if (!last)			justify_line(html_context, y);		return;	}	shift = overlap(par_format) - len;	if (par_format.align == ALIGN_CENTER)		shift /= 2;	if (shift > 0)		shift_chars(html_context, y, shift);}static inline voidinit_link_event_hooks(struct html_context *html_context, struct link *link){	link->event_hooks = mem_calloc(1, sizeof(*link->event_hooks));	if (!link->event_hooks) return;#define add_evhook(list_, type_, src_)						\	do {									\		struct script_event_hook *evhook;				\										\		if (!src_) break;						\										\		evhook = mem_calloc(1, sizeof(*evhook));			\		if (!evhook) break;						\										\		evhook->type = type_;						\		evhook->src  = stracpy(src_);					\		add_to_list(*(list_), evhook);					\	} while (0)	init_list(*link->event_hooks);	add_evhook(link->event_hooks, SEVHOOK_ONCLICK, format.onclick);	add_evhook(link->event_hooks, SEVHOOK_ONDBLCLICK, format.ondblclick);	add_evhook(link->event_hooks, SEVHOOK_ONMOUSEOVER, format.onmouseover);	add_evhook(link->event_hooks, SEVHOOK_ONHOVER, format.onhover);	add_evhook(link->event_hooks, SEVHOOK_ONFOCUS, format.onfocus);	add_evhook(link->event_hooks, SEVHOOK_ONMOUSEOUT, format.onmouseout);	add_evhook(link->event_hooks, SEVHOOK_ONBLUR, format.onblur);#undef add_evhook}static struct link *new_link(struct html_context *html_context, unsigned char *name, int namelen){	struct document *document;	struct part *part;	int link_number;	struct link *link;	assert(html_context);	if_assert_failed return NULL;	part = html_context->part;	assert(part);	if_assert_failed return NULL;	document = part->document;	assert(document);	if_assert_failed return NULL;	link_number = part->link_num;	if (!ALIGN_LINK(&document->links, document->nlinks, document->nlinks + 1))		return NULL;	link = &document->links[document->nlinks++];	link->number = link_number - 1;	if (document->options.use_tabindex) link->number += format.tabindex;	link->accesskey = format.accesskey;	link->title = null_or_stracpy(format.title);	link->where_img = null_or_stracpy(format.image);	if (!format.form) {		link->target = null_or_stracpy(format.target);		link->data.name = memacpy(name, namelen);		/* if (strlen(url) > 4 && !strncasecmp(url, "MAP@", 4)) { */		if (format.link		    && ((format.link[0]|32) == 'm')		    && ((format.link[1]|32) == 'a')		    && ((format.link[2]|32) == 'p')		    && 	(format.link[3]     == '@')		    &&   format.link[4]) {			link->type = LINK_MAP;			link->where = stracpy(format.link + 4);		} else {			link->type = LINK_HYPERTEXT;			link->where = null_or_stracpy(format.link);		}	} else {		struct form_control *fc = format.form;		struct form *form;		switch (fc->type) {		case FC_TEXT:		case FC_PASSWORD:		case FC_FILE:			link->type = LINK_FIELD;			break;		case FC_TEXTAREA:			link->type = LINK_AREA;			break;		case FC_CHECKBOX:		case FC_RADIO:			link->type = LINK_CHECKBOX;			break;		case FC_SELECT:			link->type = LINK_SELECT;			break;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?