[gs-commits] mupdf 1.16.1.69 Optimise CSS style usage in HTML.

[email protected] (Robin Watts) Thu, 3 Oct 2019 15:19:02 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
commit 9ec9f4ddda06790a773a9b7903157b955723ec2f
Author: Robin Watts <[email protected]>
Date:   Tue Oct 1 10:29:07 2019 +0100

    Optimise CSS style usage in HTML.

diff --git a/source/html/css-apply.c b/source/html/css-apply.c
index 7ff6e58..e54bd67 100644
--- a/source/html/css-apply.c
+++ b/source/html/css-apply.c
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <assert.h>
 
 static const char *inherit_list[] = {
 	"color",
@@ -1335,6 +1336,192 @@ fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, fz_css_style *style,
 	}
 }
 
+#ifdef DEBUG_CSS_SPLAY
+static void
+do_verify_splay(const fz_css_style_splay *x)
+{
+	printf("%x<", x);
+	if (x->lt)
+	{
+		assert(memcmp(&x->lt->style, &x->style, sizeof(x->style)) < 0);
+		assert(x->lt->up == x);
+		do_verify_splay(x->lt);
+	}
+	printf(",");
+	if (x->gt)
+	{
+		assert(memcmp(&x->gt->style, &x->style, sizeof(x->style)) > 0);
+		assert(x->gt->up == x);
+		do_verify_splay(x->gt);
+	}
+	printf(">\n");
+}
+
+static void
+verify_splay(const fz_css_style_splay *x)
+{
+	if (x == NULL)
+		return;
+	assert(x->up == NULL);
+	do_verify_splay(x);
+	printf("-----\n");
+}
+#endif
+
+/* Lookup style in the splay tree, returning a pointer to the found instance
+ * if there is one, creating and inserting (and moving to root) one if there
+ * is not. */
+const fz_css_style *
+fz_css_enlist(fz_context *ctx, const fz_css_style *style, fz_css_style_splay **tree, fz_pool *pool)
+{
+	fz_css_style_splay **current = tree;
+	fz_css_style_splay *x;
+	fz_css_style_splay *y = NULL;
+
+	/* Search for a match in the tree, if there is one, or for
+	 * the insertion point, if there is not. */
+	while (*current != NULL)
+	{
+		int cmp = memcmp(style, &(*current)->style, sizeof(*style));
+		if (cmp == 0)
+		{
+			/* We have a match - break out and do move to root. */
+			break;
+		}
+		y = (*current);
+		if (cmp < 0)
+			current = &y->lt;
+		else
+			current = &y->gt;
+	}
+	/* Create one if needed */
+	if (*current == NULL)
+	{
+		x = *current = fz_pool_alloc(ctx, pool, sizeof(*y));
+		x->style = *style;
+		x->up = y;
+		x->lt = NULL;
+		x->gt = NULL;
+	}
+	else
+		x = *current;
+	/* Now move to root */
+	/*
+	The splaying steps used:
+
+	Case 1:	|a)       z              x             b)     z                   x
+		|     y       D  =>  A       y            A       y           y       D
+		|   x   C                  B   z                B   x  =>  z     C
+		|  A B                        C D                  C D    A B
+
+	Case 2:	|a)       z              x             b)     z                   x
+		|     y       D  =>   y     z             A       y    =>     z       y
+		|   A   x            A B   C D                  x   D        A B     C D
+		|      B C                                     B C
+
+	Case 3:	|a)       y              x             b)     y                   x
+		|      x     C   =>   A     y              A     x      =>     y     C
+		|     A B                  B C                  B C           A B
+	*/
+#ifdef DEBUG_CSS_SPLAY
+	printf("BEFORE\n");
+	verify_splay(*tree);
+#endif
+	while ((y = x->up) != NULL ) /* While we're not at the root */
+	{
+		fz_css_style_splay *z = y->up;
+		y->up = x;
+		if (z == NULL)
+		{
+			if (y->lt == x)	/* Case 3a */
+			{
+				y->lt = x->gt;
+				if (y->lt)
+					y->lt->up = y;
+				x->gt = y;
+			}
+			else /* Case 3b */
+			{
+				y->gt = x->lt;
+				if (y->gt)
+					y->gt->up = y;
+				x->lt = y;
+			}
+			x->up = NULL;
+			break;
+		}
+		x->up = z->up;
+		if (z->up)
+		{
+			if (z->up->lt == z)
+				z->up->lt = x;
+			else
+				z->up->gt = x;
+		}
+		if (z->lt == y)
+		{
+			if (y->lt == x) /* Case 1a */
+			{
+				z->lt = y->gt;
+				if (z->lt)
+					z->lt->up = z;
+				y->lt = x->gt;
+				if (y->lt)
+					y->lt->up = y;
+				y->gt = z;
+				z->up = y;
+				x->gt = y;
+			}
+			else /* Case 2a */
+			{
+				y->gt = x->lt;
+				if (y->gt)
+					y->gt->up = y;
+				z->lt = x->gt;
+				if (z->lt)
+					z->lt->up = z;
+				x->lt = y;
+				x->gt = z;
+				z->up = x;
+			}
+		}
+		else
+		{
+			if (y->gt == x) /* Case 1b */
+			{
+				z->gt = y->lt;
+				if (z->gt)
+					z->gt->up = z;
+				y->gt = x->lt;
+				if (y->gt)
+					y->gt->up = y;
+				y->lt = z;
+				z->up = y;
+				x->lt = y;
+			}
+			else /* Case 2b */
+			{
+				z->gt = x->lt;
+				if (z->gt)
+					z->gt->up = z;
+				y->lt = x->gt;
+				if (y->lt)
+					y->lt->up = y;
+				x->gt = y;
+				x->lt = z;
+				z->up = x;
+			}
+		}
+	}
+
+	*tree = x;
+#ifdef DEBUG_CSS_SPLAY
+	printf("AFTER\n");
+	verify_splay(x);
+#endif
+
+	return &x->style;
+}
 /*
  * Pretty printing
  */
diff --git a/source/html/html-imp.h b/source/html/html-imp.h
index bd2f60f..08e2fd0 100644
--- a/source/html/html-imp.h
+++ b/source/html/html-imp.h
@@ -6,6 +6,7 @@ typedef struct fz_html_font_set_s fz_html_font_set;
 typedef struct fz_html_s fz_html;
 typedef struct fz_html_box_s fz_html_box;
 typedef struct fz_html_flow_s fz_html_flow;
+typedef struct fz_css_style_splay_s fz_css_style_splay;
 
 typedef struct fz_css_s fz_css;
 typedef struct fz_css_rule_s fz_css_rule;
@@ -181,6 +182,13 @@ struct fz_css_style_s
 	fz_font *font;
 };
 
+struct fz_css_style_splay_s {
+	fz_css_style style;
+	fz_css_style_splay *lt;
+	fz_css_style_splay *gt;
+	fz_css_style_splay *up;
+};
+
 enum
 {
 	BOX_BLOCK,	/* block-level: contains block, break, flow, and table boxes */
@@ -217,7 +225,7 @@ struct fz_html_box_s
 	fz_html_box *up, *down, *next;
 	fz_html_flow *flow_head, **flow_tail;
 	char *id, *href;
-	fz_css_style style;
+	const fz_css_style *style;
 	/* Only BOX_{BLOCK,TABLE,TABLE_ROW,TABLE_CELL} actually use the following */
 	float padding[4];
 	float margin[4];
@@ -282,6 +290,7 @@ void fz_match_css_at_page(fz_context *ctx, fz_css_match *match, fz_css *css);
 int fz_get_css_match_display(fz_css_match *node);
 void fz_default_css_style(fz_context *ctx, fz_css_style *style);
 void fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, fz_css_style *style, fz_css_match *match);
+const fz_css_style *fz_css_enlist(fz_context *ctx, const fz_css_style *style, fz_css_style_splay **tree, fz_pool *pool);
 
 float fz_from_css_number(fz_css_number number, float em, float percent_value, float auto_value);
 float fz_from_css_number_scale(fz_css_number number, float scale);
diff --git a/source/html/html-layout.c b/source/html/html-layout.c
index a74cdc6..b65ecbd 100644
--- a/source/html/html-layout.c
+++ b/source/html/html-layout.c
@@ -244,10 +244,10 @@ static void measure_string(fz_context *ctx, fz_html_flow *node, hb_buffer_t *hb_
 	node->x = 0;
 	node->y = 0;
 	node->w = 0;
-	node->h = fz_from_css_number_scale(node->box->style.line_height, em);
+	node->h = fz_from_css_number_scale(node->box->style->line_height, em);
 
 	s = get_node_text(ctx, node);
-	init_string_walker(ctx, &walker, hb_buf, node->bidi_level & 1, node->box->style.font, node->script, node->markup_lang, node->box->style.small_caps, s);
+	init_string_walker(ctx, &walker, hb_buf, node->bidi_level & 1, node->box->style->font, node->script, node->markup_lang, node->box->style->small_caps, s);
 	while (walk_string(&walker))
 	{
 		int x = 0;
@@ -382,7 +382,7 @@ static void layout_line(fz_context *ctx, float indent, float page_w, float line_
 		node->x = x;
 		x += w;
 
-		switch (node->box->style.vertical_align)
+		switch (node->box->style->vertical_align)
 		{
 		default:
 		case VA_BASELINE:
@@ -450,7 +450,7 @@ static void layout_flow_inline(fz_context *ctx, fz_html_box *box, fz_html_box *t
 	while (box)
 	{
 		box->y = top->y;
-		box->em = fz_from_css_number(box->style.font_size, top->em, top->em, top->em);
+		box->em = fz_from_css_number(box->style->font_size, top->em, top->em, top->em);
 		if (box->down)
 			layout_flow_inline(ctx, box->down, box);
 		box = box->next;
@@ -463,9 +463,9 @@ static void layout_flow(fz_context *ctx, fz_html_box *box, fz_html_box *top, flo
 	float line_w, candidate_w, indent, break_w, nonbreak_w;
 	int line_align, align;
 
-	float em = box->em = fz_from_css_number(box->style.font_size, top->em, top->em, top->em);
-	indent = box->is_first_flow ? fz_from_css_number(top->style.text_indent, em, top->w, 0) : 0;
-	align = top->style.text_align;
+	float em = box->em = fz_from_css_number(box->style->font_size, top->em, top->em, top->em);
+	indent = box->is_first_flow ? fz_from_css_number(top->style->text_indent, em, top->w, 0) : 0;
+	align = top->style->text_align;
 
 	if (box->markup_dir == FZ_BIDI_RTL)
 	{
@@ -503,8 +503,8 @@ static void layout_flow(fz_context *ctx, fz_html_box *box, fz_html_box *top, flo
 			node->w = node->content.image->w * 72 / 96;
 			node->h = node->content.image->h * 72 / 96;
 
-			node->w = fz_from_css_number(node->box->style.width, top->em, top->w - margin_w, node->w);
-			node->h = fz_from_css_number(node->box->style.height, top->em, page_h - margin_h, node->h);
+			node->w = fz_from_css_number(node->box->style->width, top->em, top->w - margin_w, node->w);
+			node->h = fz_from_css_number(node->box->style->height, top->em, page_h - margin_h, node->h);
 
 			/* Shrink image to fit on one page if needed */
 			if (max_w > 0 && node->w > max_w)
@@ -627,9 +627,9 @@ static void layout_table(fz_context *ctx, fz_html_box *box, fz_html_box *top, fl
 	fz_html_box *row, *cell, *child;
 	int col, ncol = 0;
 
-	box->em = fz_from_css_number(box->style.font_size, top->em, top->em, top->em);
+	box->em = fz_from_css_number(box->style->font_size, top->em, top->em, top->em);
 	box->x = top->x;
-	box->w = fz_from_css_number(box->style.width, box->em, top->w, top->w);
+	box->w = fz_from_css_number(box->style->width, box->em, top->w, top->w);
 	box->y = box->b = top->b;
 
 	for (row = box->down; row; row = row->next)
@@ -645,7 +645,7 @@ static void layout_table(fz_context *ctx, fz_html_box *box, fz_html_box *top, fl
 	{
 		col = 0;
 
-		row->em = fz_from_css_number(row->style.font_size, box->em, box->em, box->em);
+		row->em = fz_from_css_number(row->style->font_size, box->em, box->em, box->em);
 		row->x = box->x;
 		row->w = box->w;
 		row->y = row->b = box->b;
@@ -654,7 +654,7 @@ static void layout_table(fz_context *ctx, fz_html_box *box, fz_html_box *top, fl
 		{
 			float colw = row->w / ncol; // TODO: proper calculation
 
-			cell->em = fz_from_css_number(cell->style.font_size, row->em, row->em, row->em);
+			cell->em = fz_from_css_number(cell->style->font_size, row->em, row->em, row->em);
 			cell->y = cell->b = row->y;
 			cell->x = row->x + col * colw;
 			cell->w = colw;
@@ -685,7 +685,7 @@ static float layout_block(fz_context *ctx, fz_html_box *box, float em, float top
 	float auto_width;
 	int first;
 
-	fz_css_style *style = &box->style;
+	const fz_css_style *style = box->style;
 	float *margin = box->margin;
 	float *border = box->border;
 	float *padding = box->padding;
@@ -811,10 +811,10 @@ fz_layout_html(fz_context *ctx, fz_html *html, float w, float h, float em)
 	fz_var(hb_buf);
 	fz_var(unlocked);
 
-	html->page_margin[T] = fz_from_css_number(html->root->style.margin[T], em, em, 0);
-	html->page_margin[B] = fz_from_css_number(html->root->style.margin[B], em, em, 0);
-	html->page_margin[L] = fz_from_css_number(html->root->style.margin[L], em, em, 0);
-	html->page_margin[R] = fz_from_css_number(html->root->style.margin[R], em, em, 0);
+	html->page_margin[T] = fz_from_css_number(html->root->style->margin[T], em, em, 0);
+	html->page_margin[B] = fz_from_css_number(html->root->style->margin[B], em, em, 0);
+	html->page_margin[L] = fz_from_css_number(html->root->style->margin[L], em, em, 0);
+	html->page_margin[R] = fz_from_css_number(html->root->style->margin[R], em, em, 0);
 
 	html->page_w = w - html->page_margin[L] - html->page_margin[R];
 	if (html->page_w <= 72)
@@ -889,7 +889,7 @@ static void draw_flow_box(fz_context *ctx, fz_html_box *box, float page_top, flo
 
 	for (node = box->flow_head; node; node = node->next)
 	{
-		fz_css_style *style = &node->box->style;
+		const fz_css_style *style = node->box->style;
 
 		if (node->type == FLOW_IMAGE)
 		{
@@ -1169,7 +1169,7 @@ static void draw_list_mark(fz_context *ctx, fz_html_box *box, float page_top, fl
 	}
 	else
 	{
-		float h = fz_from_css_number_scale(box->style.line_height, box->em);
+		float h = fz_from_css_number_scale(box->style->line_height, box->em);
 		float a = box->em * 0.8f;
 		float d = box->em * 0.2f;
 		if (a + d > h)
@@ -1180,14 +1180,14 @@ static void draw_list_mark(fz_context *ctx, fz_html_box *box, float page_top, fl
 	if (y > page_bot || y < page_top)
 		return;
 
-	format_list_number(ctx, box->style.list_style_type, n, buf, sizeof buf);
+	format_list_number(ctx, box->style->list_style_type, n, buf, sizeof buf);
 
 	s = buf;
 	w = 0;
 	while (*s)
 	{
 		s += fz_chartorune(&c, s);
-		g = fz_encode_character_with_fallback(ctx, box->style.font, c, UCDN_SCRIPT_LATIN, FZ_LANG_UNSET, &font);
+		g = fz_encode_character_with_fallback(ctx, box->style->font, c, UCDN_SCRIPT_LATIN, FZ_LANG_UNSET, &font);
 		w += fz_advance_glyph(ctx, font, g, 0) * box->em;
 	}
 
@@ -1201,14 +1201,14 @@ static void draw_list_mark(fz_context *ctx, fz_html_box *box, float page_top, fl
 		while (*s)
 		{
 			s += fz_chartorune(&c, s);
-			g = fz_encode_character_with_fallback(ctx, box->style.font, c, UCDN_SCRIPT_LATIN, FZ_LANG_UNSET, &font);
+			g = fz_encode_character_with_fallback(ctx, box->style->font, c, UCDN_SCRIPT_LATIN, FZ_LANG_UNSET, &font);
 			fz_show_glyph(ctx, text, font, trm, g, c, 0, 0, FZ_BIDI_NEUTRAL, FZ_LANG_UNSET);
 			trm.e += fz_advance_glyph(ctx, font, g, 0) * box->em;
 		}
 
-		color[0] = box->style.color.r / 255.0f;
-		color[1] = box->style.color.g / 255.0f;
-		color[2] = box->style.color.b / 255.0f;
+		color[0] = box->style->color.r / 255.0f;
+		color[1] = box->style->color.g / 255.0f;
+		color[2] = box->style->color.b / 255.0f;
 
 		fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1, fz_default_color_params);
 	}
@@ -1234,18 +1234,18 @@ static void draw_block_box(fz_context *ctx, fz_html_box *box, float page_top, fl
 	if (y0 > page_bot || y1 < page_top)
 		return;
 
-	if (box->style.visibility == V_VISIBLE)
+	if (box->style->visibility == V_VISIBLE)
 	{
-		draw_rect(ctx, dev, ctm, page_top, box->style.background_color, x0, y0, x1, y1);
+		draw_rect(ctx, dev, ctm, page_top, box->style->background_color, x0, y0, x1, y1);
 
 		if (border[T] > 0)
-			draw_rect(ctx, dev, ctm, page_top, box->style.border_color[T], x0 - border[L], y0 - border[T], x1 + border[R], y0);
+			draw_rect(ctx, dev, ctm, page_top, box->style->border_color[T], x0 - border[L], y0 - border[T], x1 + border[R], y0);
 		if (border[B] > 0)
-			draw_rect(ctx, dev, ctm, page_top, box->style.border_color[B], x0 - border[L], y1, x1 + border[R], y1 + border[B]);
+			draw_rect(ctx, dev, ctm, page_top, box->style->border_color[B], x0 - border[L], y1, x1 + border[R], y1 + border[B]);
 		if (border[L] > 0)
-			draw_rect(ctx, dev, ctm, page_top, box->style.border_color[L], x0 - border[L], y0 - border[T], x0, y1 + border[B]);
+			draw_rect(ctx, dev, ctm, page_top, box->style->border_color[L], x0 - border[L], y0 - border[T], x0, y1 + border[B]);
 		if (border[R] > 0)
-			draw_rect(ctx, dev, ctm, page_top, box->style.border_color[R], x1, y0 - border[T], x1 + border[R], y1 + border[B]);
+			draw_rect(ctx, dev, ctm, page_top, box->style->border_color[R], x1, y0 - border[T], x1 + border[R], y1 + border[B]);
 
 		if (box->list_item)
 			draw_list_mark(ctx, box, page_top, page_bot, dev, ctm, box->list_item);
@@ -1276,7 +1276,7 @@ fz_draw_html(fz_context *ctx, fz_device *dev, fz_matrix ctm, fz_html *html, int
 	fz_var(hb_buf);
 	fz_var(unlocked);
 
-	draw_rect(ctx, dev, ctm, 0, html->root->style.background_color,
+	draw_rect(ctx, dev, ctm, 0, html->root->style->background_color,
 			0, 0,
 			html->page_w + html->page_margin[L] + html->page_margin[R],
 			html->page_h + html->page_margin[T] + html->page_margin[B]);
diff --git a/source/html/html-parse.c b/source/html/html-parse.c
index 686992e..5adbd85 100644
--- a/source/html/html-parse.c
+++ b/source/html/html-parse.c
@@ -109,6 +109,7 @@ struct genstate
 	int at_bol;
 	int emit_white;
 	int last_brk_cls;
+	fz_css_style_splay *styles;
 };
 
 static int iswhite(int c)
@@ -226,7 +227,7 @@ static fz_html_flow *split_flow(fz_context *ctx, fz_pool *pool, fz_html_flow *fl
 static void flush_space(fz_context *ctx, fz_html_box *flow, fz_html_box *inline_box, int lang, struct genstate *g)
 {
 	static const char *space = " ";
-	int bsp = inline_box->style.white_space & WS_ALLOW_BREAK_SPACE;
+	int bsp = inline_box->style->white_space & WS_ALLOW_BREAK_SPACE;
 	fz_pool *pool = g->pool;
 	if (g->emit_white)
 	{
@@ -281,9 +282,9 @@ static void generate_text(fz_context *ctx, fz_html_box *box, const char *text, i
 {
 	fz_html_box *flow;
 	fz_pool *pool = g->pool;
-	int collapse = box->style.white_space & WS_COLLAPSE;
-	int bsp = box->style.white_space & WS_ALLOW_BREAK_SPACE;
-	int bnl = box->style.white_space & WS_FORCE_BREAK_NEWLINE;
+	int collapse = box->style->white_space & WS_COLLAPSE;
+	int bsp = box->style->white_space & WS_ALLOW_BREAK_SPACE;
+	int bnl = box->style->white_space & WS_FORCE_BREAK_NEWLINE;
 
 	static const char *space = " ";
 
@@ -483,8 +484,7 @@ static void init_box(fz_context *ctx, fz_html_box *box, fz_bidi_direction markup
 	box->flow_head = NULL;
 	box->flow_tail = &box->flow_head;
 	box->markup_dir = markup_dir;
-
-	fz_default_css_style(ctx, &box->style);
+	box->style = NULL;
 }
 
 static void fz_drop_html_box(fz_context *ctx, fz_html_box *box)
@@ -641,8 +641,11 @@ static void insert_inline_box(fz_context *ctx, fz_html_box *box, fz_html_box *to
 		}
 		else
 		{
+			fz_css_style style;
 			fz_html_box *flow = new_short_box(ctx, g->pool, markup_dir);
 			flow->is_first_flow = !top->next;
+			fz_default_css_style(ctx, &style);
+			flow->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 			insert_box(ctx, flow, BOX_FLOW, top);
 			insert_box(ctx, box, BOX_INLINE, flow);
 			g->at_bol = 1;
@@ -665,6 +668,7 @@ generate_boxes(fz_context *ctx,
 	fz_html_box *box, *last_top;
 	const char *tag;
 	int display;
+	fz_css_style style;
 
 	while (node)
 	{
@@ -690,7 +694,8 @@ generate_boxes(fz_context *ctx,
 				else
 				{
 					box = new_short_box(ctx, g->pool, markup_dir);
-					fz_apply_css_style(ctx, g->set, &box->style, &match);
+					fz_apply_css_style(ctx, g->set, &style, &match);
+					box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 					top = insert_break_box(ctx, box, top);
 				}
 				g->at_bol = 1;
@@ -705,17 +710,18 @@ generate_boxes(fz_context *ctx,
 					const char *w_att = fz_xml_att(node, "width");
 					const char *h_att = fz_xml_att(node, "height");
 					box = new_short_box(ctx, g->pool, markup_dir);
-					fz_apply_css_style(ctx, g->set, &box->style, &match);
+					fz_apply_css_style(ctx, g->set, &style, &match);
 					if (w_att && (w = fz_atoi(w_att)) > 0)
 					{
-						box->style.width.value = w;
-						box->style.width.unit = strchr(w_att, '%') ? N_PERCENT : N_LENGTH;
+						style.width.value = w;
+						style.width.unit = strchr(w_att, '%') ? N_PERCENT : N_LENGTH;
 					}
 					if (h_att && (h = fz_atoi(h_att)) > 0)
 					{
-						box->style.height.value = h;
-						box->style.height.unit = strchr(h_att, '%') ? N_PERCENT : N_LENGTH;
+						style.height.value = h;
+						style.height.unit = strchr(h_att, '%') ? N_PERCENT : N_LENGTH;
 					}
+					box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 					insert_inline_box(ctx, box, top, markup_dir, g);
 					generate_image(ctx, box, load_html_image(ctx, g->zip, g->base_uri, src), g);
 				}
@@ -724,7 +730,8 @@ generate_boxes(fz_context *ctx,
 			else if (tag[0]=='s' && tag[1]=='v' && tag[2]=='g' && tag[3]==0)
 			{
 				box = new_short_box(ctx, g->pool, markup_dir);
-				fz_apply_css_style(ctx, g->set, &box->style, &match);
+				fz_apply_css_style(ctx, g->set, &style, &match);
+				box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 				insert_inline_box(ctx, box, top, markup_dir, g);
 				generate_image(ctx, box, load_svg_image(ctx, g->zip, g->base_uri, node), g);
 			}
@@ -741,17 +748,21 @@ generate_boxes(fz_context *ctx,
 					{
 						fz_html_box *imgbox;
 						box = new_box(ctx, g->pool, markup_dir);
-						fz_apply_css_style(ctx, g->set, &box->style, &match);
+						fz_default_css_style(ctx, &style);
+						fz_apply_css_style(ctx, g->set, &style, &match);
+						box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 						top = insert_block_box(ctx, box, top);
 						imgbox = new_short_box(ctx, g->pool, markup_dir);
-						fz_apply_css_style(ctx, g->set, &imgbox->style, &match);
+						fz_apply_css_style(ctx, g->set, &style, &match);
+						imgbox->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 						insert_inline_box(ctx, imgbox, box, markup_dir, g);
 						generate_image(ctx, imgbox, fz_keep_image(ctx, img), g);
 					}
 					else if (display == DIS_INLINE)
 					{
 						box = new_short_box(ctx, g->pool, markup_dir);
-						fz_apply_css_style(ctx, g->set, &box->style, &match);
+						fz_apply_css_style(ctx, g->set, &style, &match);
+						box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 						insert_inline_box(ctx, box, top, markup_dir, g);
 						generate_image(ctx, box, fz_keep_image(ctx, img), g);
 					}
@@ -785,7 +796,9 @@ generate_boxes(fz_context *ctx,
 					box = new_short_box(ctx, g->pool, child_dir);
 				else
 					box = new_box(ctx, g->pool, child_dir);
-				fz_apply_css_style(ctx, g->set, &box->style, &match);
+				fz_default_css_style(ctx, &style);
+				fz_apply_css_style(ctx, g->set, &style, &match);
+				box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 
 				id = fz_xml_att(node, "id");
 				if (id)
@@ -872,7 +885,7 @@ generate_boxes(fz_context *ctx,
 		else
 		{
 			const char *text = fz_xml_text(node);
-			int collapse = top->style.white_space & WS_COLLAPSE;
+			int collapse = top->style->white_space & WS_COLLAPSE;
 			if (collapse && is_all_white(text))
 			{
 				g->emit_white = 1;
@@ -882,12 +895,16 @@ generate_boxes(fz_context *ctx,
 				if (top->type != BOX_INLINE)
 				{
 					/* Create anonymous inline box, with the same style as the top block box. */
+					fz_css_style style;
 					box = new_short_box(ctx, g->pool, markup_dir);
+					fz_default_css_style(ctx, &style);
+					box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 					insert_inline_box(ctx, box, top, markup_dir, g);
-					box->style = top->style;
+					style = *top->style;
 					/* Make sure not to recursively multiply font sizes. */
-					box->style.font_size.value = 1;
-					box->style.font_size.unit = N_SCALE;
+					style.font_size.value = 1;
+					style.font_size.unit = N_SCALE;
+					box->style = fz_css_enlist(ctx, &style, &g->styles, g->pool);
 					generate_text(ctx, box, text, markup_lang, g);
 				}
 				else
@@ -1253,6 +1270,7 @@ fz_parse_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const cha
 	g.at_bol = 0;
 	g.emit_white = 0;
 	g.last_brk_cls = UCDN_LINEBREAK_CLASS_OP;
+	g.styles = NULL;
 
 	xml = fz_parse_xml(ctx, buf, 1);
 	root = fz_xml_root(xml);
@@ -1308,15 +1326,19 @@ fz_parse_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const cha
 
 	fz_try(ctx)
 	{
+		fz_css_style style;
+
 		g.pool = fz_new_pool(ctx);
 		html = fz_pool_alloc(ctx, g.pool, sizeof *html);
 		html->pool = g.pool;
 		html->root = new_box(ctx, g.pool, DEFAULT_DIR);
+		fz_default_css_style(ctx, &style);
 
 		match.up = NULL;
 		match.count = 0;
 		fz_match_css_at_page(ctx, &match, g.css);
-		fz_apply_css_style(ctx, g.set, &html->root->style, &match);
+		fz_apply_css_style(ctx, g.set, &style, &match);
+		html->root->style = fz_css_enlist(ctx, &style, &g.styles, g.pool);
 		// TODO: transfer page margins out of this hacky box
 
 		generate_boxes(ctx, root, html->root, &match, 0, 0, DEFAULT_DIR, FZ_LANG_UNSET, &g);
@@ -1378,18 +1400,18 @@ fz_debug_html_flow(fz_context *ctx, fz_html_flow *flow, int level)
 			}
 			sbox = flow->box;
 			indent(level);
-			printf("span em=%g font='%s'", sbox->em, fz_font_name(ctx, sbox->style.font));
-			if (fz_font_is_serif(ctx, sbox->style.font))
+			printf("span em=%g font='%s'", sbox->em, fz_font_name(ctx, sbox->style->font));
+			if (fz_font_is_serif(ctx, sbox->style->font))
 				printf(" serif");
 			else
 				printf(" sans");
-			if (fz_font_is_monospaced(ctx, sbox->style.font))
+			if (fz_font_is_monospaced(ctx, sbox->style->font))
 				printf(" monospaced");
-			if (fz_font_is_bold(ctx, sbox->style.font))
+			if (fz_font_is_bold(ctx, sbox->style->font))
 				printf(" bold");
-			if (fz_font_is_italic(ctx, sbox->style.font))
+			if (fz_font_is_italic(ctx, sbox->style->font))
 				printf(" italic");
-			if (sbox->style.small_caps)
+			if (sbox->style->small_caps)
 				printf(" small-caps");
 			printf("\n");
 			indent(level);

http://git.ghostscript.com/?p=mupdf.git;a=commit;h=9ec9f4ddda06790a773a9b7903157b955723ec2f

--
MuPDF library
Artifex Software, Inc.