From 77eed8154c782a4d3b0e38a49986c18c240ab2f2 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Wed, 14 Mar 2012 19:11:02 +0000 Subject: 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. --- fitz/dev_list.c | 18 +++------- fitz/fitz-internal.h | 8 +++++ fitz/res_path.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 13 deletions(-) (limited to 'fitz') 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); +} -- cgit v1.2.3