summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-03-14 19:11:02 +0000
committerRobin Watts <robin.watts@artifex.com>2012-03-14 21:16:27 +0000
commit77eed8154c782a4d3b0e38a49986c18c240ab2f2 (patch)
tree4349aa1ce473250ba9186ed11498af96aeb4d40e
parentebd905bf410d0093bf68ff1af2621fc4303ed2bd (diff)
downloadmupdf-77eed8154c782a4d3b0e38a49986c18c240ab2f2.tar.xz
Bug 692917: Move to dynamic stroke_states.
Move fz_stroke_state from being a simple structure whose contents are copied repeatedly to being a dynamically allocated reference counted object so we can cope with large numbers of entries in the dash array.
-rw-r--r--fitz/dev_list.c18
-rw-r--r--fitz/fitz-internal.h8
-rw-r--r--fitz/res_path.c97
-rw-r--r--pdf/pdf_interpret.c91
-rw-r--r--xps/xps_path.c92
5 files changed, 217 insertions, 89 deletions
diff --git a/fitz/dev_list.c b/fitz/dev_list.c
index d0dfabc5..f0cfdeb5 100644
--- a/fitz/dev_list.c
+++ b/fitz/dev_list.c
@@ -96,14 +96,6 @@ fz_new_display_node(fz_context *ctx, fz_display_command cmd, fz_matrix ctm,
return node;
}
-static fz_stroke_state *
-fz_clone_stroke_state(fz_context *ctx, fz_stroke_state *stroke)
-{
- fz_stroke_state *newstroke = fz_malloc_struct(ctx, fz_stroke_state);
- *newstroke = *stroke;
- return newstroke;
-}
-
static void
fz_append_display_node(fz_display_list *list, fz_display_node *node)
{
@@ -219,7 +211,7 @@ fz_free_display_node(fz_context *ctx, fz_display_node *node)
break;
}
if (node->stroke)
- fz_free(ctx, node->stroke);
+ fz_drop_stroke_state(ctx, node->stroke);
if (node->colorspace)
fz_drop_colorspace(ctx, node->colorspace);
fz_free(ctx, node);
@@ -257,7 +249,7 @@ fz_list_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_m
{
node->rect = fz_bound_path(dev->ctx, path, stroke, ctm);
node->item.path = fz_clone_path(dev->ctx, path);
- node->stroke = fz_clone_stroke_state(dev->ctx, stroke);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
}
fz_catch(ctx)
{
@@ -301,7 +293,7 @@ fz_list_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke
if (rect)
node->rect = fz_intersect_rect(node->rect, *rect);
node->item.path = fz_clone_path(dev->ctx, path);
- node->stroke = fz_clone_stroke_state(dev->ctx, stroke);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
}
fz_catch(ctx)
{
@@ -343,7 +335,7 @@ fz_list_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_m
{
node->rect = fz_bound_text(dev->ctx, text, ctm);
node->item.text = fz_clone_text(dev->ctx, text);
- node->stroke = fz_clone_stroke_state(dev->ctx, stroke);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
}
fz_catch(ctx)
{
@@ -386,7 +378,7 @@ fz_list_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke,
{
node->rect = fz_bound_text(dev->ctx, text, ctm);
node->item.text = fz_clone_text(dev->ctx, text);
- node->stroke = fz_clone_stroke_state(dev->ctx, stroke);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
}
fz_catch(ctx)
{
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h
index 0a639b1c..eda9736a 100644
--- a/fitz/fitz-internal.h
+++ b/fitz/fitz-internal.h
@@ -791,6 +791,7 @@ struct fz_path_s
struct fz_stroke_state_s
{
+ int refs;
fz_linecap start_cap, dash_cap, end_cap;
fz_linejoin linejoin;
float linewidth;
@@ -816,6 +817,13 @@ fz_path *fz_clone_path(fz_context *ctx, fz_path *old);
fz_rect fz_bound_path(fz_context *ctx, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm);
void fz_print_path(fz_context *ctx, FILE *out, fz_path *, int indent);
+fz_stroke_state *fz_new_stroke_state(fz_context *ctx);
+fz_stroke_state *fz_new_stroke_state_with_len(fz_context *ctx, int len);
+fz_stroke_state *fz_keep_stroke_state(fz_context *ctx, fz_stroke_state *stroke);
+void fz_drop_stroke_state(fz_context *ctx, fz_stroke_state *stroke);
+fz_stroke_state *fz_unshare_stroke_state(fz_context *ctx, fz_stroke_state *shared);
+fz_stroke_state *fz_unshare_stroke_state_with_len(fz_context *ctx, fz_stroke_state *shared, int len);
+
/*
* Glyph cache
*/
diff --git a/fitz/res_path.c b/fitz/res_path.c
index fed1504a..13705969 100644
--- a/fitz/res_path.c
+++ b/fitz/res_path.c
@@ -365,3 +365,100 @@ fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent)
}
}
}
+
+fz_stroke_state *
+fz_keep_stroke_state(fz_context *ctx, fz_stroke_state *stroke)
+{
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+
+ if (!stroke)
+ return NULL;
+
+ if (stroke->refs > 0)
+ stroke->refs++;
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ return stroke;
+}
+
+void
+fz_drop_stroke_state(fz_context *ctx, fz_stroke_state *stroke)
+{
+ int drop;
+
+ if (!stroke)
+ return;
+
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+ drop = (stroke->refs > 0 ? --stroke->refs == 0 : 0);
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ if (drop)
+ fz_free(ctx, stroke);
+}
+
+fz_stroke_state *
+fz_new_stroke_state_with_len(fz_context *ctx, int len)
+{
+ fz_stroke_state *state;
+
+ len -= nelem(state->dash_list);
+ if (len < 0)
+ len = 0;
+
+ state = Memento_label(fz_malloc(ctx, sizeof(*state) + sizeof(state->dash_list[0]) * len), "fz_stroke_state");
+ state->refs = 1;
+ state->start_cap = FZ_LINECAP_BUTT;
+ state->dash_cap = FZ_LINECAP_BUTT;
+ state->end_cap = FZ_LINECAP_BUTT;
+ state->linejoin = FZ_LINEJOIN_MITER;
+ state->linewidth = 1;
+ state->miterlimit = 10;
+ state->dash_phase = 0;
+ state->dash_len = 0;
+ memset(state->dash_list, 0, sizeof(state->dash_list[0]) * (len + nelem(state->dash_list)));
+
+ return state;
+}
+
+fz_stroke_state *
+fz_new_stroke_state(fz_context *ctx)
+{
+ return fz_new_stroke_state_with_len(ctx, 0);
+}
+
+
+fz_stroke_state *
+fz_unshare_stroke_state_with_len(fz_context *ctx, fz_stroke_state *shared, int len)
+{
+ int single, unsize, shsize, shlen, drop;
+ fz_stroke_state *unshared;
+
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+ single = (shared->refs == 1);
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+
+ shlen = shared->dash_len - nelem(shared->dash_list);
+ if (shlen < 0)
+ shlen = 0;
+ shsize = sizeof(*shared) + sizeof(shared->dash_list[0]) * shlen;
+ len -= nelem(shared->dash_list);
+ if (len < 0)
+ len = 0;
+ if (single && shlen >= len)
+ return shared;
+ unsize = sizeof(*unshared) + sizeof(unshared->dash_list[0]) * len;
+ unshared = Memento_label(fz_malloc(ctx, unsize), "fz_stroke_state");
+ memcpy(unshared, shared, (shsize > unsize ? unsize : shsize));
+ unshared->refs = 1;
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+ drop = (shared->refs > 0 ? --shared->refs == 0 : 0);
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ if (drop)
+ fz_free(ctx, shared);
+ return unshared;
+}
+
+fz_stroke_state *
+fz_unshare_stroke_state(fz_context *ctx, fz_stroke_state *shared)
+{
+ return fz_unshare_stroke_state_with_len(ctx, shared, shared->dash_len);
+}
diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c
index 3888b35f..5b2f75a1 100644
--- a/pdf/pdf_interpret.c
+++ b/pdf/pdf_interpret.c
@@ -37,7 +37,7 @@ struct pdf_gstate_s
int clip_depth;
/* path stroking */
- fz_stroke_state stroke_state;
+ fz_stroke_state *stroke_state;
/* materials */
pdf_material stroke;
@@ -442,9 +442,9 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
if (dostroke) {
if (csi->dev->flags & (FZ_DEVFLAG_STROKECOLOR_UNDEFINED | FZ_DEVFLAG_LINEJOIN_UNDEFINED | FZ_DEVFLAG_LINEWIDTH_UNDEFINED))
csi->dev->flags |= FZ_DEVFLAG_UNCACHEABLE;
- else if (gstate->stroke_state.dash_len != 0 && csi->dev->flags & (FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED))
+ else if (gstate->stroke_state->dash_len != 0 && csi->dev->flags & (FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED))
csi->dev->flags |= FZ_DEVFLAG_UNCACHEABLE;
- else if (gstate->stroke_state.linejoin == FZ_LINEJOIN_MITER && (csi->dev->flags & FZ_DEVFLAG_MITERLIMIT_UNDEFINED))
+ else if (gstate->stroke_state->linejoin == FZ_LINEJOIN_MITER && (csi->dev->flags & FZ_DEVFLAG_MITERLIMIT_UNDEFINED))
csi->dev->flags |= FZ_DEVFLAG_UNCACHEABLE;
}
if (dofill) {
@@ -461,7 +461,7 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
fz_closepath(ctx, path);
if (dostroke)
- bbox = fz_bound_path(ctx, path, &gstate->stroke_state, gstate->ctm);
+ bbox = fz_bound_path(ctx, path, gstate->stroke_state, gstate->ctm);
else
bbox = fz_bound_path(ctx, path, NULL, gstate->ctm);
@@ -514,13 +514,13 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
case PDF_MAT_NONE:
break;
case PDF_MAT_COLOR:
- fz_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm,
+ fz_stroke_path(csi->dev, path, gstate->stroke_state, gstate->ctm,
gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
break;
case PDF_MAT_PATTERN:
if (gstate->stroke.pattern)
{
- fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm);
+ fz_clip_stroke_path(csi->dev, path, &bbox, gstate->stroke_state, gstate->ctm);
pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_STROKE);
fz_pop_clip(csi->dev);
}
@@ -528,7 +528,7 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
case PDF_MAT_SHADE:
if (gstate->stroke.shade)
{
- fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm);
+ fz_clip_stroke_path(csi->dev, path, &bbox, gstate->stroke_state, gstate->ctm);
fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
fz_pop_clip(csi->dev);
}
@@ -634,13 +634,13 @@ pdf_flush_text(pdf_csi *csi)
case PDF_MAT_NONE:
break;
case PDF_MAT_COLOR:
- fz_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm,
+ fz_stroke_text(csi->dev, text, gstate->stroke_state, gstate->ctm,
gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
break;
case PDF_MAT_PATTERN:
if (gstate->stroke.pattern)
{
- fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
+ fz_clip_stroke_text(csi->dev, text, gstate->stroke_state, gstate->ctm);
pdf_show_pattern(csi, gstate->stroke.pattern, csi->text_bbox, PDF_STROKE);
fz_pop_clip(csi->dev);
}
@@ -648,7 +648,7 @@ pdf_flush_text(pdf_csi *csi)
case PDF_MAT_SHADE:
if (gstate->stroke.shade)
{
- fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
+ fz_clip_stroke_text(csi->dev, text, gstate->stroke_state, gstate->ctm);
fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
fz_pop_clip(csi->dev);
}
@@ -859,20 +859,12 @@ pdf_show_text(pdf_csi *csi, pdf_obj *text)
*/
static void
-pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm)
+pdf_init_gstate(fz_context *ctx, pdf_gstate *gs, fz_matrix ctm)
{
gs->ctm = ctm;
gs->clip_depth = 0;
- gs->stroke_state.start_cap = FZ_LINECAP_BUTT;
- gs->stroke_state.dash_cap = FZ_LINECAP_BUTT;
- gs->stroke_state.end_cap = FZ_LINECAP_BUTT;
- gs->stroke_state.linejoin = FZ_LINEJOIN_MITER;
- gs->stroke_state.linewidth = 1;
- gs->stroke_state.miterlimit = 10;
- gs->stroke_state.dash_phase = 0;
- gs->stroke_state.dash_len = 0;
- memset(gs->stroke_state.dash_list, 0, sizeof(gs->stroke_state.dash_list));
+ gs->stroke_state = fz_new_stroke_state(ctx);
gs->stroke.kind = PDF_MAT_COLOR;
gs->stroke.colorspace = fz_device_gray; /* No fz_keep_colorspace as static */
@@ -934,6 +926,7 @@ copy_state(fz_context *ctx, pdf_gstate *gs, pdf_gstate *old)
gs->fill = old->fill;
gs->font = old->font;
gs->softmask = old->softmask;
+ gs->stroke_state = fz_keep_stroke_state(ctx, old->stroke_state);
pdf_keep_material(ctx, &gs->stroke);
pdf_keep_material(ctx, &gs->fill);
@@ -981,7 +974,7 @@ pdf_new_csi(pdf_document *xref, fz_device *dev, fz_matrix ctm, char *event, fz_c
csi->gstate = fz_malloc_array(ctx, csi->gcap, sizeof(pdf_gstate));
csi->top_ctm = ctm;
- pdf_init_gstate(&csi->gstate[0], ctm);
+ pdf_init_gstate(ctx, &csi->gstate[0], ctm);
if (gstate)
copy_state(ctx, &csi->gstate[0], gstate);
csi->gtop = 0;
@@ -1037,6 +1030,7 @@ pdf_gsave(pdf_csi *csi)
pdf_keep_font(ctx, gs->font);
if (gs->softmask)
pdf_keep_xobject(ctx, gs->softmask);
+ fz_keep_stroke_state(ctx, gs->stroke_state);
}
static void
@@ -1058,6 +1052,7 @@ pdf_grestore(pdf_csi *csi)
pdf_drop_font(ctx, gs->font);
if (gs->softmask)
pdf_drop_xobject(ctx, gs->softmask);
+ fz_drop_stroke_state(ctx, gs->stroke_state);
csi->gtop --;
@@ -1090,6 +1085,7 @@ pdf_free_csi(pdf_csi *csi)
pdf_drop_font(ctx, csi->gstate[0].font);
if (csi->gstate[0].softmask)
pdf_drop_xobject(ctx, csi->gstate[0].softmask);
+ fz_drop_stroke_state(ctx, csi->gstate[0].stroke_state);
while (csi->gstate[0].clip_depth--)
fz_pop_clip(csi->dev);
@@ -1483,24 +1479,28 @@ pdf_run_extgstate(pdf_csi *csi, pdf_obj *rdb, pdf_obj *extgstate)
else if (!strcmp(s, "LC"))
{
csi->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED);
- gstate->stroke_state.start_cap = pdf_to_int(val);
- gstate->stroke_state.dash_cap = pdf_to_int(val);
- gstate->stroke_state.end_cap = pdf_to_int(val);
+ gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
+ gstate->stroke_state->start_cap = pdf_to_int(val);
+ gstate->stroke_state->dash_cap = pdf_to_int(val);
+ gstate->stroke_state->end_cap = pdf_to_int(val);
}
else if (!strcmp(s, "LW"))
{
csi->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED;
- gstate->stroke_state.linewidth = pdf_to_real(val);
+ gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
+ gstate->stroke_state->linewidth = pdf_to_real(val);
}
else if (!strcmp(s, "LJ"))
{
csi->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED;
- gstate->stroke_state.linejoin = pdf_to_int(val);
+ gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
+ gstate->stroke_state->linejoin = pdf_to_int(val);
}
else if (!strcmp(s, "ML"))
{
csi->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED;
- gstate->stroke_state.miterlimit = pdf_to_real(val);
+ gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
+ gstate->stroke_state->miterlimit = pdf_to_real(val);
}
else if (!strcmp(s, "D"))
@@ -1508,10 +1508,12 @@ pdf_run_extgstate(pdf_csi *csi, pdf_obj *rdb, pdf_obj *extgstate)
if (pdf_is_array(val) && pdf_array_len(val) == 2)
{
pdf_obj *dashes = pdf_array_get(val, 0);
- gstate->stroke_state.dash_len = MAX(pdf_array_len(dashes), 32);
- for (k = 0; k < gstate->stroke_state.dash_len; k++)
- gstate->stroke_state.dash_list[k] = pdf_to_real(pdf_array_get(dashes, k));
- gstate->stroke_state.dash_phase = pdf_to_real(pdf_array_get(val, 1));
+ int len = pdf_array_len(dashes);
+ gstate->stroke_state = fz_unshare_stroke_state_with_len(ctx, gstate->stroke_state, len);
+ gstate->stroke_state->dash_len = len;
+ for (k = 0; k < len; k++)
+ gstate->stroke_state->dash_list[k] = pdf_to_real(pdf_array_get(dashes, k));
+ gstate->stroke_state->dash_phase = pdf_to_real(pdf_array_get(val, 1));
}
else
fz_throw(ctx, "malformed /D");
@@ -1859,9 +1861,10 @@ static void pdf_run_J(pdf_csi *csi)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
csi->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED);
- gstate->stroke_state.start_cap = csi->stack[0];
- gstate->stroke_state.dash_cap = csi->stack[0];
- gstate->stroke_state.end_cap = csi->stack[0];
+ gstate->stroke_state = fz_unshare_stroke_state(csi->dev->ctx, gstate->stroke_state);
+ gstate->stroke_state->start_cap = csi->stack[0];
+ gstate->stroke_state->dash_cap = csi->stack[0];
+ gstate->stroke_state->end_cap = csi->stack[0];
}
static void pdf_run_K(pdf_csi *csi)
@@ -1875,7 +1878,8 @@ static void pdf_run_M(pdf_csi *csi)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
csi->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED;
- gstate->stroke_state.miterlimit = csi->stack[0];
+ gstate->stroke_state = fz_unshare_stroke_state(csi->dev->ctx, gstate->stroke_state);
+ gstate->stroke_state->miterlimit = csi->stack[0];
}
static void pdf_run_MP(pdf_csi *csi)
@@ -2143,12 +2147,15 @@ static void pdf_run_d(pdf_csi *csi)
pdf_gstate *gstate = csi->gstate + csi->gtop;
pdf_obj *array;
int i;
+ int len;
array = csi->obj;
- gstate->stroke_state.dash_len = MIN(pdf_array_len(array), nelem(gstate->stroke_state.dash_list));
- for (i = 0; i < gstate->stroke_state.dash_len; i++)
- gstate->stroke_state.dash_list[i] = pdf_to_real(pdf_array_get(array, i));
- gstate->stroke_state.dash_phase = csi->stack[0];
+ len = pdf_array_len(array);
+ gstate->stroke_state = fz_unshare_stroke_state_with_len(csi->dev->ctx, gstate->stroke_state, len);
+ gstate->stroke_state->dash_len = len;
+ for (i = 0; i < len; i++)
+ gstate->stroke_state->dash_list[i] = pdf_to_real(pdf_array_get(array, i));
+ gstate->stroke_state->dash_phase = csi->stack[0];
}
static void pdf_run_d0(pdf_csi *csi)
@@ -2217,7 +2224,8 @@ static void pdf_run_j(pdf_csi *csi)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
csi->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED;
- gstate->stroke_state.linejoin = csi->stack[0];
+ gstate->stroke_state = fz_unshare_stroke_state(csi->dev->ctx, gstate->stroke_state);
+ gstate->stroke_state->linejoin = csi->stack[0];
}
static void pdf_run_k(pdf_csi *csi)
@@ -2333,7 +2341,8 @@ static void pdf_run_w(pdf_csi *csi)
pdf_gstate *gstate = csi->gstate + csi->gtop;
pdf_flush_text(csi); /* linewidth affects stroked text rendering mode */
csi->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED;
- gstate->stroke_state.linewidth = csi->stack[0];
+ gstate->stroke_state = fz_unshare_stroke_state(csi->dev->ctx, gstate->stroke_state);
+ gstate->stroke_state->linewidth = csi->stack[0];
}
static void pdf_run_y(pdf_csi *csi)
diff --git a/xps/xps_path.c b/xps/xps_path.c
index e368776d..6720390d 100644
--- a/xps/xps_path.c
+++ b/xps/xps_path.c
@@ -857,7 +857,7 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
char *stroke_thickness_att;
char *navigate_uri_att;
- fz_stroke_state stroke;
+ fz_stroke_state *stroke = NULL;
fz_matrix transform;
float samples[32];
fz_colorspace *colorspace;
@@ -865,6 +865,7 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
fz_path *stroke_path = NULL;
fz_rect area;
int fill_rule;
+ int dash_len = 0;
/*
* Extract attributes and extended attributes.
@@ -936,43 +937,63 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
stroke_tag = NULL;
}
- stroke.start_cap = xps_parse_line_cap(stroke_start_line_cap_att);
- stroke.dash_cap = xps_parse_line_cap(stroke_dash_cap_att);
- stroke.end_cap = xps_parse_line_cap(stroke_end_line_cap_att);
-
- stroke.linejoin = FZ_LINEJOIN_MITER_XPS;
- if (stroke_line_join_att)
- {
- if (!strcmp(stroke_line_join_att, "Miter")) stroke.linejoin = FZ_LINEJOIN_MITER_XPS;
- if (!strcmp(stroke_line_join_att, "Round")) stroke.linejoin = FZ_LINEJOIN_ROUND;
- if (!strcmp(stroke_line_join_att, "Bevel")) stroke.linejoin = FZ_LINEJOIN_BEVEL;
- }
+ if (stroke_att || stroke_tag)
+ {
+ if (stroke_dash_array_att)
+ {
+ char *s = stroke_dash_array_att;
- stroke.miterlimit = 10;
- if (stroke_miter_limit_att)
- stroke.miterlimit = fz_atof(stroke_miter_limit_att);
+ while (*s)
+ {
+ while (*s == ' ')
+ s++;
+ if (*s) /* needed in case of a space before the last quote */
+ dash_len++;
+
+ while (*s && *s != ' ')
+ s++;
+ }
+ }
+ stroke = fz_new_stroke_state_with_len(doc->ctx, dash_len);
+ stroke->start_cap = xps_parse_line_cap(stroke_start_line_cap_att);
+ stroke->dash_cap = xps_parse_line_cap(stroke_dash_cap_att);
+ stroke->end_cap = xps_parse_line_cap(stroke_end_line_cap_att);
- stroke.linewidth = 1;
- if (stroke_thickness_att)
- stroke.linewidth = fz_atof(stroke_thickness_att);
+ stroke->linejoin = FZ_LINEJOIN_MITER_XPS;
+ if (stroke_line_join_att)
+ {
+ if (!strcmp(stroke_line_join_att, "Miter")) stroke->linejoin = FZ_LINEJOIN_MITER_XPS;
+ if (!strcmp(stroke_line_join_att, "Round")) stroke->linejoin = FZ_LINEJOIN_ROUND;
+ if (!strcmp(stroke_line_join_att, "Bevel")) stroke->linejoin = FZ_LINEJOIN_BEVEL;
+ }
- stroke.dash_phase = 0;
- stroke.dash_len = 0;
- if (stroke_dash_array_att)
- {
- char *s = stroke_dash_array_att;
+ stroke->miterlimit = 10;
+ if (stroke_miter_limit_att)
+ stroke->miterlimit = fz_atof(stroke_miter_limit_att);
- if (stroke_dash_offset_att)
- stroke.dash_phase = fz_atof(stroke_dash_offset_att) * stroke.linewidth;
+ stroke->linewidth = 1;
+ if (stroke_thickness_att)
+ stroke->linewidth = fz_atof(stroke_thickness_att);
- while (*s && stroke.dash_len < nelem(stroke.dash_list))
+ stroke->dash_phase = 0;
+ stroke->dash_len = 0;
+ if (stroke_dash_array_att)
{
- while (*s == ' ')
- s++;
- if (*s) /* needed in case of a space before the last quote */
- stroke.dash_list[stroke.dash_len++] = fz_atof(s) * stroke.linewidth;
- while (*s && *s != ' ')
- s++;
+ char *s = stroke_dash_array_att;
+
+ if (stroke_dash_offset_att)
+ stroke->dash_phase = fz_atof(stroke_dash_offset_att) * stroke->linewidth;
+
+ while (*s)
+ {
+ while (*s == ' ')
+ s++;
+ if (*s) /* needed in case of a space before the last quote */
+ stroke->dash_list[stroke->dash_len++] = fz_atof(s) * stroke->linewidth;
+ while (*s && *s != ' ')
+ s++;
+ }
+ stroke->dash_len = dash_len;
}
}
@@ -1000,7 +1021,7 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
if (stroke_att || stroke_tag)
{
- area = fz_bound_path(doc->ctx, stroke_path, &stroke, ctm);
+ area = fz_bound_path(doc->ctx, stroke_path, stroke, ctm);
if (stroke_path != path && (fill_att || fill_tag))
area = fz_union_rect(area, fz_bound_path(doc->ctx, path, NULL, ctm));
}
@@ -1037,13 +1058,13 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
samples[0] *= fz_atof(stroke_opacity_att);
xps_set_color(doc, colorspace, samples);
- fz_stroke_path(doc->dev, stroke_path, &stroke, ctm,
+ fz_stroke_path(doc->dev, stroke_path, stroke, ctm,
doc->colorspace, doc->color, doc->alpha);
}
if (stroke_tag)
{
- fz_clip_stroke_path(doc->dev, stroke_path, NULL, &stroke, ctm);
+ fz_clip_stroke_path(doc->dev, stroke_path, NULL, stroke, ctm);
xps_parse_brush(doc, ctm, area, stroke_uri, dict, stroke_tag);
fz_pop_clip(doc->dev);
}
@@ -1054,6 +1075,7 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
fz_free_path(doc->ctx, stroke_path);
fz_free_path(doc->ctx, path);
path = NULL;
+ fz_drop_stroke_state(doc->ctx, stroke);
if (clip_att || clip_tag)
fz_pop_clip(doc->dev);