From d2423464852664218310ae7c5610fb0b6da4218b Mon Sep 17 00:00:00 2001 From: Ken Sharp Date: Fri, 7 Mar 2014 13:41:01 +0000 Subject: [PATCH] PS interpreter, vector devices and pdfwrite - remove setdash limit of 11 Bug #693916 "setdash does not accept more than 11 elements in the array argument" The PostScript interpreter was already capable of this, it simply required the limit check to be removed. The vector device needed to allocate and free an array of floats, rather than maintain a fixed size array. pdfwrite was teh most complex as it maintains a stack of gstates, and these also needed to be modified to allocate and free the dash array. However the gstate stack wasn't already a garbage collecting structure. Rather than going to the effort of turning it into one I've opted to allocate the dash pattern from non-gc memory. A few PCL files show differences with pdfwrite, because previously pdfwrite would throw an error (more than 11 elements in the dash array) and the stroked lines would degenerate into filled rectangles, whereas now they are drawn as stroked lines with a correct dash pattern. This is much more efficient. The clist remains unmodified, Ray assures me that it will be handled there without problems. --- Resource/Init/gs_init.ps | 1 - base/gdevpdf.c | 6 ++++++ base/gdevpdfg.c | 32 +++++++++++++++++++++++++++----- base/gdevpdfx.h | 3 ++- base/gdevvec.c | 14 ++++++++++---- base/gdevvec.h | 13 ++++++------- 6 files changed, 51 insertions(+), 18 deletions(-) diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps index 0083fa3..b4a6c48 100644 --- a/Resource/Init/gs_init.ps +++ b/Resource/Init/gs_init.ps @@ -518,7 +518,6 @@ userdict /.echo.mode //true put 0 .argindex type dup /integertype eq exch /realtype eq or not { /setdash .systemvar /typecheck signalerror } if - 1 .argindex length 11 gt { /setdash .systemvar /limitcheck signalerror } if //setdash } odef /setdevice diff --git a/base/gdevpdf.c b/base/gdevpdf.c index 8416b51..d740cc1 100644 --- a/base/gdevpdf.c +++ b/base/gdevpdf.c @@ -2873,6 +2873,12 @@ pdf_close(gx_device * dev) gs_free_object(mem, pdev->Pages, "Free Pages dict"); pdev->Pages = 0; + { + int i; + for (i=0;i < pdev->vgstack_depth;i++) + gs_free_object(pdev->memory->non_gc_memory, pdev->vgstack[i].dash_pattern, "pdfwrite final free stored dash in gstate"); + } + cos_release((cos_object_t *)pdev->NI_stack, "Release Name Index stack"); gs_free_object(mem, pdev->NI_stack, "Free Name Index stack"); pdev->NI_stack = 0; diff --git a/base/gdevpdfg.c b/base/gdevpdfg.c index 2d4e040..56b24f7 100644 --- a/base/gdevpdfg.c +++ b/base/gdevpdfg.c @@ -71,8 +71,19 @@ pdf_save_viewer_state(gx_device_pdf *pdev, stream *s) pdev->vgstack[i].saved_stroke_color = pdev->saved_stroke_color; pdev->vgstack[i].line_params = pdev->state.line_params; pdev->vgstack[i].line_params.dash.pattern = 0; /* Use pdev->dash_pattern instead. */ - memcpy(pdev->vgstack[i].dash_pattern, pdev->dash_pattern, - sizeof(pdev->vgstack[i].dash_pattern)); + if (pdev->dash_pattern) { + if (pdev->vgstack[i].dash_pattern) + gs_free_object(pdev->memory->non_gc_memory, pdev->vgstack[i].dash_pattern, "free gstate copy dash"); + pdev->vgstack[i].dash_pattern = (float *)gs_alloc_bytes(pdev->memory->non_gc_memory, pdev->dash_pattern_size * sizeof(float), "gstate copy dash"); + memcpy(pdev->vgstack[i].dash_pattern, pdev->dash_pattern, pdev->dash_pattern_size * sizeof(float)); + pdev->vgstack[i].dash_pattern_size = pdev->dash_pattern_size; + } else { + if (pdev->vgstack[i].dash_pattern) { + gs_free_object(pdev->memory->non_gc_memory, pdev->vgstack[i].dash_pattern, "free gstate copy dash"); + pdev->vgstack[i].dash_pattern = 0; + pdev->vgstack[i].dash_pattern_size = 0; + } + } pdev->vgstack_depth++; if (s) stream_puts(s, "q\n"); @@ -106,8 +117,18 @@ pdf_load_viewer_state(gx_device_pdf *pdev, pdf_viewer_state *s) pdev->saved_fill_color = s->saved_fill_color; pdev->saved_stroke_color = s->saved_stroke_color; pdev->state.line_params = s->line_params; - memcpy(pdev->dash_pattern, s->dash_pattern, - sizeof(s->dash_pattern)); + if (s->dash_pattern) { + if (pdev->dash_pattern) + gs_free_object(pdev->memory->stable_memory, pdev->dash_pattern, "vector free dash pattern"); + pdev->dash_pattern = (float *)gs_alloc_bytes(pdev->memory->stable_memory, s->dash_pattern_size * sizeof(float), "vector allocate dash pattern"); + pdev->dash_pattern_size = s->dash_pattern_size; + } else { + if (pdev->dash_pattern) { + gs_free_object(pdev->memory->stable_memory, pdev->dash_pattern, "vector free dash pattern"); + pdev->dash_pattern = 0; + pdev->dash_pattern_size = 0; + } + } } /* Restore the viewer's graphic state. */ @@ -178,7 +199,8 @@ pdf_viewer_state_from_imager_state_aux(pdf_viewer_state *pvs, const gs_imager_st pvs->line_params.dot_length_absolute = pis->line_params.dot_length_absolute; pvs->line_params.dot_orientation = pis->line_params.dot_orientation; memset(&pvs->line_params.dash, 0 , sizeof(pvs->line_params.dash)); - memset(pvs->dash_pattern, 0, sizeof(pvs->dash_pattern)); + pvs->dash_pattern = 0; + pvs->dash_pattern_size = 0; } /* Copy viewer state from images state. */ diff --git a/base/gdevpdfx.h b/base/gdevpdfx.h index bc0545d..69a8257 100644 --- a/base/gdevpdfx.h +++ b/base/gdevpdfx.h @@ -500,7 +500,8 @@ typedef struct pdf_viewer_state_s { gx_hl_saved_color saved_fill_color; gx_hl_saved_color saved_stroke_color; gx_line_params line_params; - float dash_pattern[max_dash]; + float *dash_pattern; + uint dash_pattern_size; gs_id soft_mask_id; } pdf_viewer_state; diff --git a/base/gdevvec.c b/base/gdevvec.c index ddf787e..ac006f5 100644 --- a/base/gdevvec.c +++ b/base/gdevvec.c @@ -457,24 +457,26 @@ gdev_vector_prepare_stroke(gx_device_vector * vdev, float dash_offset = pis->line_params.dash.offset * scale; float half_width = pis->line_params.half_width * scale; - if (pattern_size > max_dash) - return_error(gs_error_limitcheck); if (dash_offset != vdev->state.line_params.dash.offset || pattern_size != vdev->state.line_params.dash.pattern_size || (pattern_size != 0 && !dash_pattern_eq(vdev->dash_pattern, &pis->line_params.dash, scale)) ) { - float pattern[max_dash]; + float *pattern; int i, code; + pattern = gs_alloc_bytes(vdev->memory->stable_memory, pattern_size * sizeof(float), "vector allocate dash pattern"); for (i = 0; i < pattern_size; ++i) pattern[i] = pis->line_params.dash.pattern[i] * scale; code = (*vdev_proc(vdev, setdash)) (vdev, pattern, pattern_size, dash_offset); if (code < 0) return code; - memcpy(vdev->dash_pattern, pattern, pattern_size * sizeof(float)); + if (vdev->dash_pattern) + gs_free_object(vdev->memory->stable_memory, vdev->dash_pattern, "vector free old dash pattern"); + vdev->dash_pattern = pattern; + vdev->dash_pattern_size = pattern_size; vdev->state.line_params.dash.pattern_size = pattern_size; vdev->state.line_params.dash.offset = dash_offset; @@ -816,6 +818,10 @@ gdev_vector_close_file(gx_device_vector * vdev) FILE *f = vdev->file; int err; + if (vdev->dash_pattern) { + gs_free_object(vdev->memory->stable_memory, vdev->dash_pattern, "vector free dash pattern"); + vdev->dash_pattern = 0; + } if (vdev->bbox_device) { rc_decrement(vdev->bbox_device->icc_struct, "vector_close(bbox_device->icc_struct"); vdev->bbox_device->icc_struct = NULL; diff --git a/base/gdevvec.h b/base/gdevvec.h index 1a3eece..385e126 100644 --- a/base/gdevvec.h +++ b/base/gdevvec.h @@ -66,9 +66,6 @@ typedef struct gx_device_vector_s gx_device_vector; /* Define the maximum size of the output file name. */ #define fname_size (gp_file_name_sizeof - 1) -/* Define the longest dash pattern we can remember. */ -#define max_dash 11 - /* * Define procedures for writing common output elements. Not all devices * will support all of these elements. Note that these procedures normally @@ -168,7 +165,8 @@ int gdev_vector_dorect(gx_device_vector * vdev, fixed x0, fixed y0, int open_options; /* see below */\ /* Graphics state */\ gs_imager_state state;\ - float dash_pattern[max_dash];\ + float *dash_pattern;\ + uint dash_pattern_size;\ bool fill_used_process_color;\ bool stroke_used_process_color;\ gx_hl_saved_color saved_fill_color;\ @@ -194,7 +192,8 @@ int gdev_vector_dorect(gx_device_vector * vdev, fixed x0, fixed y0, 0, /* strmbuf_size */\ 0, /* open_options */\ { 0 }, /* state */\ - { 0 }, /* dash_pattern */\ + 0, /* dash_pattern */\ + 0, /* dash pattern size */\ true, /* fill_used_process_color */\ true, /* stroke_used_process_color */\ { 0 }, /* fill_color ****** WRONG ****** */\ @@ -216,10 +215,10 @@ struct gx_device_vector_s { /* extern its descriptor for the sake of subclasses. */ extern_st(st_device_vector); #define public_st_device_vector() /* in gdevvec.c */\ - gs_public_st_suffix_add3_final(st_device_vector, gx_device_vector,\ + gs_public_st_suffix_add4_final(st_device_vector, gx_device_vector,\ "gx_device_vector", device_vector_enum_ptrs,\ device_vector_reloc_ptrs, gx_device_finalize, st_device, strm, strmbuf,\ - bbox_device) + dash_pattern, bbox_device) #define st_device_vector_max_ptrs (st_device_max_ptrs + 3) /* ================ Utility procedures ================ */ -- 2.14.3