Blob Blame History Raw
From d2423464852664218310ae7c5610fb0b6da4218b Mon Sep 17 00:00:00 2001
From: Ken Sharp <ken.sharp@artifex.com>
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