diff options
author | Robin Watts <robin.watts@artifex.com> | 2012-03-14 19:11:02 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2012-03-14 21:16:27 +0000 |
commit | 77eed8154c782a4d3b0e38a49986c18c240ab2f2 (patch) | |
tree | 4349aa1ce473250ba9186ed11498af96aeb4d40e | |
parent | ebd905bf410d0093bf68ff1af2621fc4303ed2bd (diff) | |
download | mupdf-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.c | 18 | ||||
-rw-r--r-- | fitz/fitz-internal.h | 8 | ||||
-rw-r--r-- | fitz/res_path.c | 97 | ||||
-rw-r--r-- | pdf/pdf_interpret.c | 91 | ||||
-rw-r--r-- | xps/xps_path.c | 92 |
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); |