⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 frames.c

📁 一个很有名的浏览器
💻 C
字号:
/* HTML frames parser *//* $Id: frames.c,v 1.90.6.2 2005/04/05 21:08:41 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "elinks.h"#include "cache/cache.h"#include "document/document.h"#include "document/html/frames.h"#include "document/options.h"#include "document/renderer.h"#include "document/view.h"#include "protocol/uri.h"#include "sched/session.h"#include "terminal/draw.h"#include "util/color.h"#include "util/string.h"#include "util/ttime.h"voidadd_frameset_entry(struct frameset_desc *frameset_desc,		   struct frameset_desc *subframe,		   unsigned char *name, unsigned char *url){	struct frame_desc *frame_desc;	int offset;	assert(frameset_desc);	if_assert_failed return;	/* FIXME: The following is triggered by	 * http://www.thegoodlookingorganisation.co.uk/main.htm.	 * There may exist a true fix for this... --Zas */	/* May the one truly fixing this notify'n'close bug 237 in the	 * Bugzilla... --pasky */	if (frameset_desc->box.y >= frameset_desc-> box.height)		return;	offset = frameset_desc->box.x		 + frameset_desc->box.y * frameset_desc->box.width;	frame_desc = &frameset_desc->frame_desc[offset];	frame_desc->subframe = subframe;	frame_desc->name = null_or_stracpy(name);	frame_desc->uri = url && *url ? get_uri(url, 0) : NULL;	if (!frame_desc->uri)		frame_desc->uri = get_uri("about:blank", 0);	frameset_desc->box.x++;	if (frameset_desc->box.x >= frameset_desc->box.width) {		frameset_desc->box.x = 0;		frameset_desc->box.y++;		/* FIXME: check y here ? --Zas */	}}struct frameset_desc *create_frameset(struct frameset_param *fp){	struct frameset_desc *fd;	unsigned int size;	assert(fp);	if_assert_failed return NULL;	assertm(fp->x > 0 && fp->y > 0,		"Bad size of frameset: x=%d y=%d", fp->x, fp->y);	if_assert_failed {		if (fp->x <= 0) fp->x = 1;		if (fp->y <= 0) fp->y = 1;	}	size = fp->x * fp->y;	/* size - 1 since one struct frame_desc is already reserved	 * in struct frameset_desc. */	fd = mem_calloc(1, sizeof(*fd)			   + (size - 1) * sizeof(fd->frame_desc[0]));	if (!fd) return NULL;	{		int i;		for (i = 0; i < size; i++) {			fd->frame_desc[i].width = fp->width[i % fp->x];			fd->frame_desc[i].height = fp->height[i / fp->x];		}	}	fd->n = size;	fd->box.width = fp->x;	fd->box.height = fp->y;	if (fp->parent)		add_frameset_entry(fp->parent, fd, NULL, NULL);	return fd;}static voidadd_frame_to_list(struct session *ses, struct document_view *doc_view){	struct document_view *ses_doc_view;	assert(ses && doc_view);	if_assert_failed return;	foreach (ses_doc_view, ses->scrn_frames) {		int sx = ses_doc_view->box.x;		int sy = ses_doc_view->box.y;		int x = doc_view->box.x;		int y = doc_view->box.y;		if (sy > y || (sy == y && sx > x)) {			add_at_pos(ses_doc_view->prev, doc_view);			return;		}	}	add_to_list_end(ses->scrn_frames, doc_view);}static struct document_view *find_fd(struct session *ses, unsigned char *name,	int depth, int x, int y){	struct document_view *doc_view;	assert(ses && name);	if_assert_failed return NULL;	foreachback (doc_view, ses->scrn_frames) {		if (doc_view->used) continue;		if (strcasecmp(doc_view->name, name)) continue;		doc_view->used = 1;		doc_view->depth = depth;		return doc_view;	}	doc_view = mem_calloc(1, sizeof(*doc_view));	if (!doc_view) return NULL;	doc_view->used = 1;	doc_view->name = stracpy(name);	if (!doc_view->name) {		mem_free(doc_view);		return NULL;	}	doc_view->depth = depth;	doc_view->session = ses;	doc_view->search_word = &ses->search_word;	set_box(&doc_view->box, x, y, 0, 0);	add_frame_to_list(ses, doc_view);	return doc_view;}static struct document_view *format_frame(struct session *ses, struct frame_desc *frame_desc,	     struct document_options *o, int depth){	struct cache_entry *cached;	struct view_state *vs;	struct document_view *doc_view;	struct frame *frame;	int plain;	assert(ses && frame_desc && o);	if_assert_failed return NULL;repeat:	frame = ses_find_frame(ses, frame_desc->name);	if (!frame) return NULL;	vs = &frame->vs;	cached = find_in_cache(vs->uri);	if (!cached) return NULL;	plain = o->plain;	if (vs->plain != -1) o->plain = vs->plain;	if (cached->redirect && frame->redirect_cnt < MAX_REDIRECTS) {		frame->redirect_cnt++;		done_uri(vs->uri);		vs->uri = get_uri_reference(cached->redirect);#ifdef CONFIG_ECMASCRIPT		vs->ecmascript_fragile = 1;#endif		o->plain = plain;		goto repeat;	}	doc_view = find_fd(ses, frame_desc->name, depth, o->box.x, o->box.y);	if (doc_view) {		render_document(vs, doc_view, o);		assert(doc_view->document);		doc_view->document->frame = frame_desc;	}	o->plain = plain;	return doc_view;}voidformat_frames(struct session *ses, struct frameset_desc *fsd,	      struct document_options *op, int depth){	struct document_options o;	int j, n;	assert(ses && fsd && op);	if_assert_failed return;	if (depth > HTML_MAX_FRAME_DEPTH) {		return;	}	copy_struct(&o, op);	o.margin = !!o.margin;	n = 0;	for (j = 0; j < fsd->box.height; j++) {		int i;		o.box.x = op->box.x;		for (i = 0; i < fsd->box.width; i++) {			struct frame_desc *frame_desc = &fsd->frame_desc[n];			o.box.width = frame_desc->width;			o.box.height = frame_desc->height;			o.framename = frame_desc->name;			if (frame_desc->subframe) {				format_frames(ses, frame_desc->subframe, &o, depth + 1);			} else if (frame_desc->name) {				struct document_view *doc_view;				doc_view = format_frame(ses, frame_desc, &o, depth);#ifdef CONFIG_DEBUG				do_not_optimize_here(&doc_view);#endif				if (doc_view && document_has_frames(doc_view->document)) {					struct document *document = doc_view->document;					/* Make sure the frameset does not					 * disappear during processing further					 * frames - this can happen when we					 * kick the same-frame-ids bug and					 * replace view_state of an existing					 * frame - if that frame is *this* one,					 * it gets detached, losing the					 * document and if we aren't lucky the					 * document gets burned in					 * shrink_format_cache(). Also note					 * that the same bug replacing					 * view_state also causes doc_view					 * recyclation so we end up with a					 * *different* document attached to it					 * after the call, so we need to cache					 * it. It's all fun to debug, really.					 * --pasky */					object_lock(document);					format_frames(ses, document->frame_desc,						      &o, depth + 1);					object_unlock(document);				}			}			o.box.x += o.box.width + 1;			n++;#ifdef CONFIG_DEBUG			/* This makes this ugly loop actually at least remotely			 * debuggable by gdb, otherwise the compiler happily			 * randomly trashes or just blasts away *all* of these			 * variables. */			do_not_optimize_here(&n);			do_not_optimize_here(&i);			do_not_optimize_here(&j);			do_not_optimize_here(&fsd);			do_not_optimize_here(&frame_desc);#endif		}		o.box.y += o.box.height + 1;	}}/* Frame width computation tools *//* Returns 0 on error. */static intdistribute_rows_or_cols(int *val_, int max_value, int *values, int values_count){	int i;	int divisor = 0;	int tmp_val;	int val = *val_;	for (i = 0; i < values_count; i++)		if (values[i] < 1)			values[i] = 1;	val -= max_value;	for (i = 0; i < values_count; i++)		divisor += values[i];	assert(divisor);	tmp_val = val;	for (i = 0; i < values_count; i++) {		int tmp;		/* SIGH! gcc 2.7.2.* has an optimizer bug! */		do_not_optimize_here_gcc_2_7(&divisor);		tmp = values[i] * (divisor - tmp_val) / divisor;		val -= values[i] - tmp;		values[i] = tmp;	}	while (val) {		int flag = 0;		for (i = 0; i < values_count; i++) {			if (val < 0) values[i]++, val++, flag = 1;			if (val > 0 && values[i] > 1) values[i]--, val--, flag = 1;			if (!val) break;		}		if (!flag) break;	}	*val_ = val;	return 1;}/* Returns 0 on error. */static intdistribute_rows_or_cols_that_left(int *val_, int max_value, int *values, int values_count){	int i;	int val = *val_;	int *tmp_values;	int divisor = 0;	int tmp_val;	tmp_values = fmem_alloc(values_count * sizeof(*tmp_values));	if (!tmp_values) return 0;	memcpy(tmp_values, values, values_count * sizeof(*tmp_values));	for (i = 0; i < values_count; i++)		if (values[i] < 1)			values[i] = 1;	val = max_value - val;	for (i = 0; i < values_count; i++)		if (tmp_values[i] < 0)			divisor += -tmp_values[i];	assert(divisor);	tmp_val = val;	for (i = 0; i < values_count; i++)		if (tmp_values[i] < 0) {			int tmp = (-tmp_values[i] * tmp_val / divisor);			values[i] += tmp;			val -= tmp;		}	assertm(val >= 0, "distribute_rows_or_cols_that_left: val < 0");	if_assert_failed val = 0;	for (i = 0; i < values_count; i++)		if (tmp_values[i] < 0 && val)			values[i]++, val--;	assertm(val <= 0, "distribute_rows_or_cols_that_left: val > 0");	if_assert_failed val = 0;	fmem_free(tmp_values);	*val_ = val;	return 1;}/* Returns 0 on error. */static intextract_rows_or_cols_values(unsigned char *str, int max_value, int pixels_per_char,			    int **new_values, int *new_values_count){	unsigned char *tmp_str;	int *values = NULL;	int values_count = 0;	while (1) {		unsigned char *end = str;		int *tmp_values;		unsigned long number;		int val = -1;	/* Wildcard */		skip_space(str);		/* Some platforms (FreeBSD) set errno when the first char is		 * not a digit others (GNU/Linux) don't so ignore errno. */		/* Extract number. */		number = strtoul(str, (char **) &end, 10);		if (end == str) {			number = 0;		} else {			str = end;		}		/* @number is an ulong, but @val is int,		 * so check if @number is in a reasonable		 * range to prevent bad things. */		if (number <= 0xffff) {			if (*str == '%')	/* Percentage */				val = int_min((int) number, 100) * max_value / 100;			else if (*str != '*')	/* Pixels */				val = (number + (pixels_per_char - 1) / 2) / pixels_per_char;			else if (number)	/* Fraction, marked by negative value. */				val = -number;		}		/* Save value. */		tmp_values = mem_realloc(values, (values_count + 1) * sizeof(*tmp_values));		if (!tmp_values) return 0;		values = tmp_values;		values[values_count++] = val;		/* Check for next field if any. */		tmp_str = strchr(str, ',');		if (!tmp_str) break;	/* It was the last field. */		str = tmp_str + 1;	}	*new_values = values;	*new_values_count = values_count;	return 1;}/* Parse rows and cols attribute values and calculate appropriated values for display. * It handles things like: * <frameset cols="140,260,160">			values in pixels * <frameset cols="1*,2*,3*"> 				values in fractions * <frameset cols="320,*">				wildcard * <frameset cols="33%,33%,33%" rows="33%,33%,33%"> 	values in percentage * */voidparse_frame_widths(unsigned char *str, int max_value, int pixels_per_char,		   int **new_values, int *new_values_count){	int val, ret;	int *values;	int values_count;	int i;	*new_values_count = 0;	ret = extract_rows_or_cols_values(str, max_value, pixels_per_char,					  &values, &values_count);	if (!ret) return;	/* Here begins distribution between rows or cols. */	val = 2 * values_count - 1;	for (i = 0; i < values_count; i++)		if (values[i] > 0)			val += values[i] - 1;	if (val >= max_value) {		ret = distribute_rows_or_cols(&val, max_value, values, values_count);	} else {		int neg = 0;		for (i = 0; i < values_count; i++)			if (values[i] < 0)				neg = 1;		if (neg)			ret = distribute_rows_or_cols_that_left(&val, max_value, values, values_count);		else			ret = distribute_rows_or_cols(&val, max_value, values, values_count);	}	if (!ret) return;	for (i = 0; i < values_count; i++)		if (!values[i]) {			int j;			int maxval = 0;			int maxpos = 0;			for (j = 0; j < values_count; j++)				if (values[j] > maxval)					maxval = values[j], maxpos = j;			if (maxval)				values[i] = 1, values[maxpos]--;		}	*new_values = values;	*new_values_count = values_count;}

⌨️ 快捷键说明

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