Exemplo n.º 1
0
static void
html_render_tag(struct render_context *ctx, const struct array tag)
{
	if (tag.size > 0) {
		ctx->closing = html_tag_is_closing(&tag);
		html_output_tag(ctx->output, tag);
		if (HTML_TAG_PRE == parse_tag(tag)) {
			ctx->preformatted = !ctx->closing;
		}
	}
}
Exemplo n.º 2
0
static void
html_output_tag(struct html_output *output, const struct array *tag)
#if GTK_CHECK_VERSION(2,0,0)
{
	static struct {
		gboolean initialized;
		short_string_t centre_line, nbsp, bullet, soft_hyphen, em_dash;
		short_string_t list_item_prefix;
	} special;
	struct html_context *ctx;
	const gchar *style, *text, *attr;
	enum html_tag id;
	gboolean closing;
	GtkTextBuffer *buffer;

	if (!special.initialized) {

		special.initialized = TRUE;
		special.bullet = utf8_char(0x2022);
		special.centre_line = utf8_char(0xFE4E);
		special.soft_hyphen = utf8_char(0x00AD);
		special.nbsp = utf8_char(0x00A0);
		special.em_dash = utf8_char(0x2014);
		concat_strings(special.list_item_prefix.str,
			sizeof special.list_item_prefix.str,
			" ", special.bullet.str, " ", (void *) 0);
	}
	
	style = NULL;
	text = NULL;
	attr = NULL;
	closing = html_tag_is_closing(tag);
	ctx = html_output_get_udata(output);
	id = html_parse_tag(tag);
	buffer = gtk_text_view_get_buffer(ctx->html_view->widget);

	switch (id) {
	case HTML_TAG_BODY:
		style = STYLE_TAG_WORD_WRAP;
		break;
	case HTML_TAG_A:
		if (closing) {
			if (ctx->start[id] && ctx->href) {
				GtkTextIter start, end;
				GtkTextTag *anchor;

				anchor = gtk_text_buffer_create_tag(buffer, NULL, (void *) 0);
				g_object_set_data(G_OBJECT(anchor), "href",
					deconstify_gchar(ctx->href));
				gtk_text_buffer_get_iter_at_mark(buffer,
					&start, ctx->start[id]);
				gtk_text_buffer_get_end_iter(buffer, &end);
				gtk_text_buffer_apply_tag(buffer, anchor, &start, &end);
				style = get_style_for_href(ctx->href);
				ctx->href = NULL;
			}
		} else {
			struct array value;

			value = html_get_attribute(tag, HTML_ATTR_HREF);
			if (value.data && value.size > 0) {
				GtkTextIter iter;

				ctx->href = g_strndup(value.data, value.size);
				ctx->html_view->to_free = g_slist_prepend(
						ctx->html_view->to_free, deconstify_gchar(ctx->href));
				gtk_text_buffer_get_end_iter(buffer, &iter);
				ctx->start[id] = gtk_text_buffer_create_mark(buffer,
										NULL, &iter, TRUE);
				g_object_set_data(G_OBJECT(ctx->start[id]), "href",
					deconstify_gchar(ctx->href));
			}
			value = html_get_attribute(tag, HTML_ATTR_NAME);
			if (value.data && value.size > 0) {
				GtkTextTagTable *table;
				gchar name[256];
				size_t n;

				n = sizeof name - 2;
				n = MIN(value.size, n);
				name[0] = '#';
				memcpy(&name[1], value.data, n);
				name[n + 1] = '\0';
				
				table = gtk_text_buffer_get_tag_table(buffer);
				if (NULL == gtk_text_tag_table_lookup(table, name)) {
					GtkTextIter iter;

					gtk_text_buffer_get_end_iter(buffer, &iter);
					gtk_text_buffer_create_mark(buffer, name, &iter, TRUE);
				}
			}
		}
		break;
	case HTML_TAG_B:
	case HTML_TAG_STRONG:
	case HTML_TAG_THEAD:
		style = STYLE_TAG_BOLD;
		break;
	case HTML_TAG_TH:
		if (closing)
			text = "\t";
		break;
	case HTML_TAG_EM:
		style = STYLE_TAG_UNDERLINE;
		break;
	case HTML_TAG_I:
	case HTML_TAG_Q:
		style = STYLE_TAG_ITALIC;
		break;
	case HTML_TAG_IMG:
		if (!closing) {
			struct array value;
			static gchar alt[1024];
			
			value = html_get_attribute(tag, HTML_ATTR_ALT);
			if (value.data) {
				gm_snprintf(alt, sizeof alt, "\n[image alt=\"%.*s\"]\n",
					(int)value.size, value.data);
				text = alt;
			}
			value = html_get_attribute(tag, HTML_ATTR_SRC);
			if (value.data) {
				GdkPixbuf *pixbuf;
				gchar *filename;
				GtkTextIter iter;

				filename = h_strndup(value.data, value.size);
				pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
				if (pixbuf) {
					gtk_text_buffer_get_end_iter(buffer, &iter);
					gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf);
				} else {
					static gchar msg[1024];
					gm_snprintf(msg, sizeof msg,
						"\n[Image not found (\"%s\")]\n", filename);
					text = msg;
				}
				HFREE_NULL(filename);
			}
			if (!text) {
				text = "\n[image]\n";
			}
		}
		attr = STYLE_TAG_BOLD;
		break;
	case HTML_TAG_TD:
		if (closing)
			text = "\t";
		break;
	case HTML_TAG_P:
	case HTML_TAG_DIV:
		text = closing ? "\n\n" : special.soft_hyphen.str;
		break;
	case HTML_TAG_DL:
	case HTML_TAG_TABLE:
	case HTML_TAG_TR:
	case HTML_TAG_UL:
	case HTML_TAG_OL:
	case HTML_TAG_BR:
		text = "\n";
		break;
	case HTML_TAG_DT:
	case HTML_TAG_LI:
		if (closing) {
			GtkTextIter start, end;
			GtkTextTag *margin;
			PangoLayout *pl;
			gint width;

			pl = pango_layout_new(gtk_widget_get_pango_context(
						GTK_WIDGET(ctx->html_view->widget)));
			pango_layout_set_text(pl, special.list_item_prefix.str, -1);
			pango_layout_get_pixel_size(pl, &width, NULL);
			g_object_unref(G_OBJECT(pl));

			margin = gtk_text_buffer_create_tag(buffer, NULL,
						"left-margin",		width * 2,
						"left-margin-set",	TRUE,
						(void *) 0);

			gtk_text_buffer_get_iter_at_mark(buffer, &start, ctx->start[id]);
			gtk_text_buffer_get_end_iter(buffer, &end);
			gtk_text_buffer_apply_tag(buffer, margin, &start, &end);
		} else {
			GtkTextIter iter;
		
			gtk_text_buffer_get_end_iter(buffer, &iter);
			gtk_text_buffer_insert(buffer, &iter, "\n", (-1));

			gtk_text_buffer_get_end_iter(buffer, &iter);
			gtk_text_buffer_insert_with_tags_by_name(buffer, &iter,
					special.list_item_prefix.str, (-1),
					STYLE_TAG_BOLD, (void *) 0);
			gtk_text_buffer_get_end_iter(buffer, &iter);
			ctx->start[id] = gtk_text_buffer_create_mark(buffer, NULL,
					&iter, TRUE);
		}
		break;
	case HTML_TAG_CODE:
	case HTML_TAG_KBD:
	case HTML_TAG_PRE:
	case HTML_TAG_TT:
		style = STYLE_TAG_MONOSPACE;
		break;
	case HTML_TAG_H1:
		style = STYLE_TAG_HEADING_1;
		text = closing ? "\n\n" : "\n";
		break;
	case HTML_TAG_H2:
		style = STYLE_TAG_HEADING_2;
		text = closing ? "\n\n" : "\n";
		break;
	case HTML_TAG_H3:
		style = STYLE_TAG_HEADING_3;
		text = closing ? "\n\n" : "\n";
		break;
	case HTML_TAG_H4:
	case HTML_TAG_H5:
	case HTML_TAG_H6:
		style = STYLE_TAG_HEADING_4;
		text = closing ? "\n\n" : "\n";
		break;
	case HTML_TAG_TITLE:
		if (closing) {
			if (ctx->title) {
				GtkWidget *window;

				window = gtk_widget_get_toplevel(
							GTK_WIDGET(ctx->html_view->widget));
				gtk_window_set_title(GTK_WINDOW(window), str_2c(ctx->title));
				str_destroy_null(&ctx->title);
			}
		} else {
			ctx->title = str_new(0);
		}
		break;
	case HTML_TAG_HR:
		{
			GtkTextIter iter;

			gtk_text_buffer_get_end_iter(buffer, &iter);
			gtk_text_buffer_insert_with_tags_by_name(buffer, &iter,
					"\n    \n", (-1),
					STYLE_TAG_CENTER, STYLE_TAG_UNDERLINE, (void *) 0);
		}
		text = "\n";
		break;
	case HTML_TAG_COMMENT:
#if 0 
		{
			GtkTextIter iter;

			/* Comments can be made visible this way */
			ctx->start[id] = gtk_text_buffer_create_mark(buffer, NULL,
					&iter, TRUE);
			gtk_text_buffer_get_end_iter(buffer, &iter);
			gtk_text_buffer_insert_with_tags_by_name(buffer, &iter,
					tag->data, tag->size, STYLE_TAG_ITALIC, (void *) 0);
		}
		closing = TRUE;
		text = "\n";
#endif
		break;
	case HTML_TAG_HTML:
		if (closing) {
		   	if (ctx->lang && ctx->start[id]) {
				GtkTextIter start, end;
				GtkTextTag *lang;

				lang = gtk_text_buffer_create_tag(buffer, NULL,
						"language",		ctx->lang,
						"language-set",	TRUE,
						(void *) 0);
				gtk_text_buffer_get_iter_at_mark(buffer,
					&start, ctx->start[id]);
				gtk_text_buffer_get_end_iter(buffer, &end);
				gtk_text_buffer_apply_tag(buffer, lang, &start, &end);
				ctx->lang = NULL;
			}
		} else {
			struct array value;

			value = html_get_attribute(tag, HTML_ATTR_LANG);
			if (value.data && value.size > 0) {
				GtkTextIter iter;

				ctx->lang = g_strndup(value.data, value.size);
				ctx->html_view->to_free = g_slist_prepend(
						ctx->html_view->to_free, deconstify_gchar(ctx->lang));
				gtk_text_buffer_get_end_iter(buffer, &iter);
				ctx->start[id] = gtk_text_buffer_create_mark(buffer,
										NULL, &iter, TRUE);
			}
		}
	case HTML_TAG_HEAD:
	case HTML_TAG_META:
	case HTML_TAG_SPAN:
	case HTML_TAG_COL:
	case HTML_TAG_DD:
	case HTML_TAG_TBODY:
	case HTML_TAG_DOCTYPE:
	case HTML_TAG_UNKNOWN:
		break;
	case NUM_HTML_TAG:
		g_assert_not_reached();
	}

	if (style) {
		if (closing) {
			if (ctx->start[id]) {
				GtkTextIter start, end;
		
				gtk_text_buffer_get_iter_at_mark(buffer,
						&start, ctx->start[id]);
				gtk_text_buffer_get_end_iter(buffer, &end);
				gtk_text_buffer_apply_tag_by_name(buffer, style, &start, &end);
				ctx->start[id] = NULL;
			}
		} else {
			GtkTextIter iter;
			gtk_text_buffer_get_end_iter(buffer, &iter);
			ctx->start[id] = gtk_text_buffer_create_mark(buffer,
										NULL, &iter, TRUE);
		}
	}
	if (text) {
		GtkTextIter iter;

		gtk_text_buffer_get_end_iter(buffer, &iter);
		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter,
			text, (-1), attr, (void *) 0);
	}
}