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

📄 dw_page.c

📁 微型浏览器
💻 C
📖 第 1 页 / 共 3 页
字号:
 *  * + do request_repaint for added stuff. But what level of * granularity? reinstate the update_begin/update_end cycle? Do at * line granularity when making a new line (but risk paint * inconsistency)? Do at word granularity but take on region overhead * on every word (optimize away if outside visible rectangle)? *  * + better formatting, including justification & floats *  *//* * Returns the x offset (the indentation plus any offset needed for * centering or right justification) for the line. The offset returned * is relative to the page (i.e. add allocation.x0 to get the dw * toplevel coordinate. */static gint Dw_page_line_x_offset(DwPage * page, DwPageLine * line){	gint x;	if (line->first)		x = page->words[line->first_word].style->left_indent_first;	else		x = page->words[line->first_word].style->left_indent_rest;	return x;}/* * ? */static void Dw_page_add_line(DwPage * page){	gint num_lines;	DwPageLine *line;	num_lines = page->num_lines;	a_List_add(page->lines, num_lines, sizeof(*page->lines), page->num_lines_max);	line = &page->lines[num_lines];	line->first_word = page->current_word;	line->last_word = page->current_word;	if (num_lines == 0) {		line->y_top = 0;	} else {		line->y_top = page->lines[num_lines - 1].y_top + page->lines[num_lines - 1].y_ascent + page->lines[num_lines - 1].y_descent + page->lines[num_lines - 1].y_space;	}	line->x_size = 0;	line->y_ascent = 6;	line->y_descent = 3;	line->y_space = 0;	line->hard = FALSE;	line->first = (num_lines == 0 || (page->lines[num_lines - 1].hard && page->lines[num_lines - 1].y_space > 0));	page->num_lines++;}/* * Allocate a new word in a page structure. This routine is where word * wrapping happens. The newly allocated word has the x_size, x_space, * y_ascent, and y_descent fields filled in, but no others. */static DwPageWord *Dw_page_new_word(DwPage * page, gint x_size, gint y_ascent, gint y_descent, DwStyle * style){	DwPageLine *line;	DwPageWord *word;	DwStyle *style2;	gboolean existing;	gboolean new_line;	gint width, set_width, nw, nl;	line = NULL;	word = NULL;	new_line = FALSE;	existing = FALSE;	/* Is it an existing word? */	if (x_size == -1)		existing = TRUE;	if (existing) {		word = &page->words[page->current_word];		style2 = word->style;		x_size = word->x_size;		y_ascent = word->y_ascent;		y_descent = word->y_descent;	} else {		style2 = style;	}	nl = page->num_lines;	if (nl == 0) {		new_line = TRUE;	} else {		line = &page->lines[nl - 1];		if (line->hard) {			new_line = TRUE;		} else {			/* Calculate width of new line and see if it exceeds page width. */			nw = line->last_word;			if (nw > line->first_word) {				set_width = page->avail_width - style2->right_indent;				if (line->first)					set_width -= style2->left_indent_first;				else					set_width -= style2->left_indent_rest;				width = line->x_size + page->words[nw - 1].x_space + x_size;				if (width > set_width)					new_line = TRUE;			}		}		if (new_line)			page->real_width = MAX(page->real_width, line->x_size + Dw_page_line_x_offset(page, line));	}	if (new_line) {		Dw_page_add_line(page);		line = &page->lines[nl];	}	nw = line->last_word;	/* Add a new word */	if (!existing) {		a_List_add(page->words, nw, sizeof(*page->words), page->num_words_max);		word = &page->words[nw];		word->x_size = x_size;		word->x_space = 0;		word->y_ascent = y_ascent;		word->y_descent = y_descent;		/* Just in case the page only has one word */		if (page->num_words == 0)			page->real_width = x_size;		page->num_words++;	}	/* Apply the attributes to the line */	if (nw - line->first_word)		line->x_size += page->words[nw - 1].x_space;	line->x_size += x_size;	line->y_ascent = MAX(line->y_ascent, y_ascent);	line->y_descent = MAX(line->y_descent, y_descent);	/* update the width requisitions */	if (nw == line->first_word && line->first)		page->last_line_max_width = style2->left_indent_first;	else if (nw == line->first_word)		page->last_line_max_width += page->words[line->first_word].x_space;	else		page->last_line_max_width += page->words[nw - 1].x_space;	page->last_line_max_width += x_size;	page->current_word++;	line->last_word++;	return word;}/* Performance is not as good as it could be - it could only rewrap if * it needs to (should be a cheap test: the line is ok if it fits * within the page->width and either it's hard or the width plus the * width of the first word on the next line (plus the spacing of the * last word) exceed the page->width). This would save on memory * allocation too. *  * But hey, it works! */static void Dw_page_calc_widget_size(DwPage * page, DwPageWord * word){	DwRequisition requisition;	gint req_height, alloc_height;	a_Dw_widget_size_request(word->content.widget.widget, &requisition);	if (word->content.widget.rel_width == -1)		word->x_size = requisition.width;	else		word->x_size = word->content.widget.rel_width * page->avail_width;	if (word->content.widget.rel_height == -1) {		word->y_ascent = requisition.ascent;		word->y_descent = requisition.descent;	} else {		/* todo: re-think about it */		req_height = requisition.ascent + requisition.descent;		if (req_height) {			alloc_height = word->content.widget.rel_height * (page->avail_ascent + page->avail_descent);			word->y_ascent = requisition.ascent * alloc_height / req_height;			word->y_descent = requisition.descent * alloc_height / req_height;		} else {			word->y_ascent = 0;			word->y_descent = 0;		}	}}/* * Rewrap the page. * There are basically two times we'll want to do this: * either when the viewport is resized, or when the size changes on one * of the child widgets. */static void Dw_page_rewrap(DwPage * page){	DwPageLine *old_lines;	DwWidget *widget;	gint old_num_lines;	gint line_index, word_index;	gint nl;	DwPageLine *old_line;	DwPageWord *word;	widget = DW_WIDGET(page);	old_lines = page->lines;	old_num_lines = page->num_lines;	//g_print(">>>       Dw_page_rewrap (%d x %d x %d)\n",	//page->avail_width, page->avail_ascent, page->avail_descent);	/* Initialize the lines structure of the page. */	page->num_lines = 0;	page->num_lines_max = 16;	page->lines = g_new(DwPageLine, page->num_lines_max);	page->current_word = 0;	page->real_width = 0;	/* Iterate over the old lines, adding the words to the page structure. */	for (line_index = 0; line_index < old_num_lines; line_index++) {		old_line = &(old_lines[line_index]);		/* Here, we're actually relying on the invariant that a soft line		 * is never followed by an empty hard line. */		if (old_line->last_word == old_line->first_word && old_line->hard) {			Dw_page_add_line(page);		}		for (word_index = old_line->first_word; word_index < old_line->last_word; word_index++) {			word = &page->words[word_index];			if (word->content_type == DW_PAGE_CONTENT_WIDGET)				Dw_page_calc_widget_size(page, word);			Dw_page_new_word(page, -1, -1, -1, NULL);			if (word->content_type == DW_PAGE_CONTENT_ANCHOR) {				Dw_widget_set_anchor(widget, word->content.anchor, page->lines[page->num_lines - 1].y_top);			}		}		if (old_line->hard) {			a_Dw_page_linebreak(page);			page->lines[page->num_lines - 1].y_space = old_line->y_space;		}	}	g_free(old_lines);	/* The last line hasn't been compared to real_width yet */	nl = page->num_lines;	if (nl > 0)		page->real_width = MAX(page->real_width, page->lines[nl - 1].x_size + Dw_page_line_x_offset(page, &(page->lines[nl - 1])));}/* * Paint a line * - x and y are toplevel dw coordinates (Question: what Dw? Changed. Test!) * - area is used always (ev. set it to event->area) * - event is only used when is_expose */static void Dw_page_draw_line(DwPage * page, DwPageLine * line, DwRectangle * area, GdkEventExpose * event){	DwWidget *widget;	DwPageWord *word;	gint word_index;	gint x_cursor, y_cursor;	gint diff;	GdkColormap *colormap;	gint uline_width;	DwWidget *child;	DwRectangle child_area;	GdkWindow *window;	/* Here's an idea on how to optimize this routine to minimize the number	 * of calls to gdk_draw_string:	 * 	 * Copy the text from the words into a buffer, adding a new word	 * only if: the attributes match, and the spacing is either zero or	 * equal to the width of ' '. In the latter case, copy a " " into	 * the buffer. Then draw the buffer. */	widget = DW_WIDGET(page);	window = widget->window;	colormap = gtk_widget_get_colormap(widget->viewport);	x_cursor = Dw_widget_x_world_to_viewport(widget, widget->allocation.x + Dw_page_line_x_offset(page, line));	y_cursor = Dw_widget_y_world_to_viewport(widget, widget->allocation.y + line->y_top + line->y_ascent);	for (word_index = line->first_word; word_index < line->last_word; word_index++) {		word = &page->words[word_index];		diff = 0;		switch (word->content_type) {		case DW_PAGE_CONTENT_TEXT:			/* Adjust the text baseline if the word is <SUP>-ed or <SUB>-ed */			if (word->style->SubSup == TEXT_SUB)				diff = word->y_ascent / 2;			else if (word->style->SubSup == TEXT_SUP)				diff -= word->y_ascent / 3;			gdk_draw_string(window, word->style->font->font, word->style->color->gc, x_cursor, y_cursor + diff, word->content.text);			if (word->style->uline >= 0) {				uline_width = word->x_size;				if (word_index + 1 < line->last_word && word->style->uline == page->words[word_index + 1].style->uline)					uline_width += word->x_space;				gdk_draw_line(window, word->style->color->gc, x_cursor, y_cursor + 1 + diff, x_cursor + uline_width - 1, y_cursor + 1 + diff);			}			if (word->style->strike >= 0) {				uline_width = word->x_size;				if (word_index + 1 < line->last_word && word->style->strike == page->words[word_index + 1].style->strike)					uline_width += word->x_space;				gdk_draw_line(window, word->style->color->gc, x_cursor, y_cursor - word->y_ascent / 2 + diff, x_cursor + uline_width - 1, y_cursor - word->y_ascent / 2 + diff);			}			break;		case DW_PAGE_CONTENT_WIDGET:			child = word->content.widget.widget;			if (Dw_widget_intersect(child, area, &child_area)) {				//g_print ("Drawing widget %p\n", child);				a_Dw_widget_draw(child, &child_area, event);			}			break;		case DW_PAGE_CONTENT_ANCHOR:			/* nothing - an anchor isn't seen */			/* BUG: sometimes anchors have x_space; 			 * we subtract that just in case --EG */			x_cursor -= word->x_size + word->x_space;			break;		}		x_cursor += word->x_size + word->x_space;	}}/* * Find the first line index that includes y, relative to top of widget. */static gint Dw_page_find_line_index(DwPage * page, gint y){	gint max_index = page->num_lines - 1;	gint step, index, low = 0;	step = (page->num_lines + 1) >> 1;	while (step > 1) {		index = low + step;		if (index <= max_index && page->lines[index].y_top < y)			low = index;		step = (step + 1) >> 1;	}	if (low < max_index && page->lines[low + 1].y_top < y)		low++;	/* This new routine returns the line number between	 * (y_top) and (y_top + y_ascent + y_descent + y_space) : 	 * the space _below_ the line is considered part of the line.	 * Old routine returned line number between	 * (y_top - previous_line->y_space) and (y_top + y_ascent + y_descent) :	 * the space _above_ the line was considered part of the line.	 * This is important for Dw_page_find_link()  --EG	 */	return low;}/* * Draw the actual lines, starting at (x, y) in toplevel Dw coords. * (former Dw_page_expose_lines) */static void Dw_page_draw(DwWidget * widget, DwRectangle * area, GdkEventExpose * event){	DwPage *page;	gint line_index;	DwPageLine *line;	//gint x1;	page = DW_PAGE(widget);	line_index = Dw_page_find_line_index(page, area->y);	for (; line_index < page->num_lines; line_index++) {		line = &(page->lines[line_index]);		if (line->y_top >= area->y + area->height)			break;		Dw_page_draw_line(page, line, area, event);	}}/* * Find a link given a coordinate location relative to the window */static gint Dw_page_find_link(DwPage * page, gint x, gint y){	gint line_index, word_index;	gint x_cursor, last_x_cursor;	gint x1, y1;		/* coordinates relative to page */	gint x0, y0;		/* coordinates relative to word */	DwPageLine *line;	DwPageWord *word;	DwPageShape *shape;	int dx, dy;	int num_shape;	guint map;	/* x1 = x - DW_WIDGET(page)->allocation.x;	 * y1 = y - DW_WIDGET(page)->allocation.y; */	x1 = x;	y1 = y;	if ((line_index = Dw_page_find_line_index(page, y1)) >= page->num_lines)		return -1;	line = &page->lines[line_index];	if (line->y_top + line->y_ascent + line->y_descent <= y1)		return -1;	x0 = x1;	y0 = y1 - line->y_top;	page->x_click = -1;	x_cursor = Dw_page_line_x_offset(page, line);	for (word_index = line->first_word; word_index < line->last_word; word_index++) {		word = &page->words[word_index];		last_x_cursor = x_cursor;		x_cursor += word->x_size + word->x_space;		if (last_x_cursor <= x1 && x_cursor > x1) {			if (word->style->link >= 0) {				/* todo: DW_STYLE_HAS_MAP will move elsewhere */				if (word->style->flags & DW_STYLE_HAS_MAP) {					page->x_click = x0;					page->y_click = y0;				} else					page->x_click = -1;				return word->style->link;			} else if (word->style->flags & DW_STYLE_HAS_MAP) {				map = word->style->map;				for (num_shape = 0; num_shape < page->num_shapes; num_shape++) {					shape = &(page->shapes[num_shape]);					if (shape->map == map) {						if (shape->type == DW_PAGE_SHAPE_CIRCLE) {							dx = shape->data.circle.x - x0;							dy = shape->data.circle.y - y0;							if (shape->data.circle.r2 >= (dx * dx + dy * dy))								return shape->link;						} else if (shape->type == DW_PAGE_SHAPE_RECT) {							if (x0 > shape->data.rect.left && x0 < shape->data.rect.right && y0 > shape->data.rect.top && y0 < shape->data.rect.bottom)								return shape->link;						} else if (shape->type == DW_PAGE_SHAPE_POLY) {							if (gdk_region_point_in(shape->data.poly, x0, y0))

⌨️ 快捷键说明

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