diff -Nru ghostscript-9.25~dfsg+1/base/gdebug.h ghostscript-9.26~dfsg+0/base/gdebug.h --- ghostscript-9.25~dfsg+1/base/gdebug.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdebug.h 2018-11-20 09:59:43.000000000 +0000 @@ -119,6 +119,34 @@ BEGIN if (gs_debug_c(c)) dlprintf11(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); END # define if_debug12(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)\ BEGIN if (gs_debug_c(c)) dlprintf12(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); END + +# define dbgprintf(s)\ + BEGIN dlprintf(s); END +# define dbgprintf1(s,a1)\ + BEGIN dlprintf1(s,a1); END +# define dbgprintf2(s,a1,a2)\ + BEGIN dlprintf2(s,a1,a2); END +# define dbgprintf3(s,a1,a2,a3)\ + BEGIN dlprintf3(s,a1,a2,a3); END +# define dbgprintf4(s,a1,a2,a3,a4)\ + BEGIN dlprintf4(s,a1,a2,a3,a4); END +# define dbgprintf5(s,a1,a2,a3,a4,a5)\ + BEGIN dlprintf5(s,a1,a2,a3,a4,a5); END +# define dbgprintf6(s,a1,a2,a3,a4,a5,a6)\ + BEGIN dlprintf6(s,a1,a2,a3,a4,a5,a6); END +# define dbgprintf7(s,a1,a2,a3,a4,a5,a6,a7)\ + BEGIN dlprintf7(s,a1,a2,a3,a4,a5,a6,a7); END +# define dbgprintf8(s,a1,a2,a3,a4,a5,a6,a7,a8)\ + BEGIN dlprintf8(s,a1,a2,a3,a4,a5,a6,a7,a8); END +# define dbgprintf9(s,a1,a2,a3,a4,a5,a6,a7,a8,a9)\ + BEGIN dlprintf9(s,a1,a2,a3,a4,a5,a6,a7,a8,a9); END +# define dbgprintf10(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)\ + BEGIN dlprintf10(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); END +# define dbgprintf11(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)\ + BEGIN dlprintf11(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); END +# define dbgprintf12(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)\ + BEGIN dlprintf12(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); END + #else # define if_debug0(c,s) DO_NOTHING # define if_debug1(c,s,a1) DO_NOTHING @@ -133,6 +161,20 @@ # define if_debug10(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) DO_NOTHING # define if_debug11(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) DO_NOTHING # define if_debug12(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) DO_NOTHING + +# define dbgprintf(s) DO_NOTHING +# define dbgprintf1(s,a1) DO_NOTHING +# define dbgprintf2(s,a1,a2) DO_NOTHING +# define dbgprintf3(s,a1,a2,a3) DO_NOTHING +# define dbgprintf4(s,a1,a2,a3,a4) DO_NOTHING +# define dbgprintf5(s,a1,a2,a3,a4,a5) DO_NOTHING +# define dbgprintf6(s,a1,a2,a3,a4,a5,a6) DO_NOTHING +# define dbgprintf7(s,a1,a2,a3,a4,a5,a6,a7) DO_NOTHING +# define dbgprintf8(s,a1,a2,a3,a4,a5,a6,a7,a8) DO_NOTHING +# define dbgprintf9(s,a1,a2,a3,a4,a5,a6,a7,a8,a9) DO_NOTHING +# define dbgprintf10(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) DO_NOTHING +# define dbgprintf11(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) DO_NOTHING +# define dbgprintf12(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) DO_NOTHING #endif #ifdef DEBUG @@ -162,6 +204,34 @@ BEGIN if (gs_debug_c(c)) dmlprintf11(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); END # define if_debug12m(c,m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)\ BEGIN if (gs_debug_c(c)) dmlprintf12(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); END + +# define dbgmprintf(m,s)\ + BEGIN dmlprintf(m,s); END +# define dbgmprintf1(m,s,a1)\ + BEGIN dmlprintf1(m,s,a1); END +# define dbgmprintf2(m,s,a1,a2)\ + BEGIN dmlprintf2(m,s,a1,a2); END +# define dbgmprintf3(m,s,a1,a2,a3)\ + BEGIN dmlprintf3(m,s,a1,a2,a3); END +# define dbgmprintf4(m,s,a1,a2,a3,a4)\ + BEGIN dmlprintf4(m,s,a1,a2,a3,a4); END +# define dbgmprintf5(m,s,a1,a2,a3,a4,a5)\ + BEGIN dmlprintf5(m,s,a1,a2,a3,a4,a5); END +# define dbgmprintf6(m,s,a1,a2,a3,a4,a5,a6)\ + BEGIN dmlprintf6(m,s,a1,a2,a3,a4,a5,a6); END +# define dbgmprintf7(m,s,a1,a2,a3,a4,a5,a6,a7)\ + BEGIN dmlprintf7(m,s,a1,a2,a3,a4,a5,a6,a7); END +# define dbgmprintf8(m,s,a1,a2,a3,a4,a5,a6,a7,a8)\ + BEGIN dmlprintf8(m,s,a1,a2,a3,a4,a5,a6,a7,a8); END +# define dbgmprintf9(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9)\ + BEGIN dmlprintf9(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9); END +# define dbgmprintf10(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)\ + BEGIN dmlprintf10(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); END +# define dbgmprintf11(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)\ + BEGIN dmlprintf11(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); END +# define dbgmprintf12(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)\ + BEGIN dmlprintf12(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); END + #else # define if_debug0m(c,m,s) DO_NOTHING # define if_debug1m(c,m,s,a1) DO_NOTHING @@ -176,6 +246,20 @@ # define if_debug10m(c,m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) DO_NOTHING # define if_debug11m(c,m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) DO_NOTHING # define if_debug12m(c,m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) DO_NOTHING + +# define dbgmprintf(m,s) DO_NOTHING +# define dbgmprintf1(m,s,a1) DO_NOTHING +# define dbgmprintf2(m,s,a1,a2) DO_NOTHING +# define dbgmprintf3(m,s,a1,a2,a3) DO_NOTHING +# define dbgmprintf4(m,s,a1,a2,a3,a4) DO_NOTHING +# define dbgmprintf5(m,s,a1,a2,a3,a4,a5) DO_NOTHING +# define dbgmprintf6(m,s,a1,a2,a3,a4,a5,a6) DO_NOTHING +# define dbgmprintf7(m,s,a1,a2,a3,a4,a5,a6,a7) DO_NOTHING +# define dbgmprintf8(m,s,a1,a2,a3,a4,a5,a6,a7,a8) DO_NOTHING +# define dbgmprintf9(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9) DO_NOTHING +# define dbgmprintf10(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) DO_NOTHING +# define dbgmprintf11(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) DO_NOTHING +# define dbgmprintf12(m,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) DO_NOTHING #endif /* Debugging support procedures in gsmisc.c */ diff -Nru ghostscript-9.25~dfsg+1/base/gdevdflt.c ghostscript-9.26~dfsg+0/base/gdevdflt.c --- ghostscript-9.25~dfsg+1/base/gdevdflt.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevdflt.c 2018-11-20 09:59:43.000000000 +0000 @@ -764,6 +764,7 @@ fill_dev_proc(dev, dev_spec_op, gx_default_dev_spec_op); fill_dev_proc(dev, copy_planes, gx_default_copy_planes); fill_dev_proc(dev, process_page, gx_default_process_page); + fill_dev_proc(dev, transform_pixel_region, gx_default_transform_pixel_region); } @@ -1044,6 +1045,13 @@ dev_param_req_t *request = (dev_param_req_t *)data; return gx_default_get_param(pdev, request->Param, request->list); } + case gxdso_current_output_device: + { + *(gx_device **)data = pdev; + return 0; + } + case gxdso_copy_color_is_fast: + return (dev_proc(pdev, copy_color) != gx_default_copy_color); } return_error(gs_error_undefined); } @@ -1166,7 +1174,7 @@ } int -gx_default_put_image(gx_device *dev, const byte **buffers, int num_chan, int x, int y, int width, int height, int row_stride, int alpha_plane_index, int tag_plane_index) +gx_default_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y, int width, int height, int row_stride, int alpha_plane_index, int tag_plane_index) { return_error(gs_error_undefined); } @@ -1296,6 +1304,7 @@ set_dev_proc(dest, strip_copy_rop2, dev_proc(prototype, strip_copy_rop2)); set_dev_proc(dest, strip_tile_rect_devn, dev_proc(prototype, strip_tile_rect_devn)); set_dev_proc(dest, process_page, dev_proc(prototype, process_page)); + set_dev_proc(dest, transform_pixel_region, dev_proc(prototype, transform_pixel_region)); /* * We absolutely must set the 'set_graphics_type_tag' to the default subclass one @@ -1673,3 +1682,549 @@ set_dev_proc(dev, create_compositor, gx_subclass_create_compositor); return code; } + +typedef enum +{ + transform_pixel_region_portrait, + transform_pixel_region_landscape, + transform_pixel_region_skew +} transform_pixel_region_posture; + +typedef struct gx_default_transform_pixel_region_state_s gx_default_transform_pixel_region_state_t; + +typedef int (gx_default_transform_pixel_region_render_fn)(gx_device *dev, gx_default_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs); + +struct gx_default_transform_pixel_region_state_s +{ + gs_memory_t *mem; + gx_dda_fixed_point pixels; + gx_dda_fixed_point rows; + gs_int_rect clip; + int w; + int h; + int spp; + transform_pixel_region_posture posture; + gs_logical_operation_t lop; + byte *line; + gx_default_transform_pixel_region_render_fn *render; +}; + +static void +get_portrait_y_extent(gx_default_transform_pixel_region_state_t *state, int *iy, int *ih) +{ + fixed y0, y1; + gx_dda_fixed row = state->rows.y; + + y0 = dda_current(row); + dda_next(row); + y1 = dda_current(row); + + if (y1 < y0) { + fixed t = y1; y1 = y0; y0 = t; + } + + *iy = fixed2int_pixround_perfect(y0); + *ih = fixed2int_pixround_perfect(y1) - *iy; +} + +static void +get_landscape_x_extent(gx_default_transform_pixel_region_state_t *state, int *ix, int *iw) +{ + fixed x0, x1; + gx_dda_fixed row = state->rows.x; + + x0 = dda_current(row); + dda_next(row); + x1 = dda_current(row); + + if (x1 < x0) { + fixed t = x1; x1 = x0; x0 = t; + } + + *ix = fixed2int_pixround_perfect(x0); + *iw = fixed2int_pixround_perfect(x1) - *ix; +} + +static void +get_skew_extents(gx_default_transform_pixel_region_state_t *state, fixed *w, fixed *h) +{ + fixed x0, x1, y0, y1; + gx_dda_fixed_point row = state->rows; + + x0 = dda_current(row.x); + y0 = dda_current(row.y); + dda_next(row.x); + dda_next(row.y); + x1 = dda_current(row.x); + y1 = dda_current(row.y); + + *w = x1-x0; + *h = y1-y0; +} + +static int +transform_pixel_region_render_portrait(gx_device *dev, gx_default_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + gs_logical_operation_t lop = state->lop; + gx_dda_fixed_point pnext; + int vci, vdi; + int irun; /* int x/rrun */ + int w = state->w; + int h = state->h; + int spp = state->spp; + const byte *data = buffer[0] + data_x * spp; + const byte *bufend = NULL; + int code = 0; + const byte *run; + int k; + gx_color_value *conc = &cmapper->conc[0]; + int to_rects; + gx_cmapper_fn *mapper = cmapper->set_color; + int minx, maxx; + + if (h == 0) + return 0; + + /* Clip on Y */ + get_portrait_y_extent(state, &vci, &vdi); + if (vci < state->clip.p.y) + vdi += vci - state->clip.p.y, vci = state->clip.p.y; + if (vci+vdi > state->clip.q.y) + vdi = state->clip.q.y - vci; + if (vdi <= 0) + return 0; + + pnext = state->pixels; + dda_translate(pnext.x, (-fixed_epsilon)); + irun = fixed2int_var_rounded(dda_current(pnext.x)); + if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", + vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y))); + to_rects = (dev->color_info.depth != spp*8); + if (to_rects == 0) { + if (dev_proc(dev, dev_spec_op)(dev, gxdso_copy_color_is_fast, NULL, 0) <= 0) + to_rects = 1; + } + + minx = state->clip.p.x; + maxx = state->clip.q.x; + bufend = data + w * spp; + if (to_rects) { + while (data < bufend) { + /* Find the length of the next run. It will either end when we hit + * the end of the source data, or when the pixel data differs. */ + run = data + spp; + while (1) { + dda_next(pnext.x); + if (run >= bufend) + break; + if (memcmp(run, data, spp)) + break; + run += spp; + } + /* So we have a run of pixels from data to run that are all the same. */ + /* This needs to be sped up */ + for (k = 0; k < spp; k++) { + conc[k] = gx_color_value_from_byte(data[k]); + } + mapper(cmapper); + /* Fill the region between irun and fixed2int_var_rounded(pnext.x) */ + { + int xi = irun; + int wi = (irun = fixed2int_var_rounded(dda_current(pnext.x))) - xi; + + if (wi < 0) + xi += wi, wi = -wi; + if (xi < minx) + wi += xi - minx, xi = minx; + if (xi + wi > maxx) + wi = maxx - xi; + if (wi > 0) + code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi, + &cmapper->devc, dev, lop); + } + if (code < 0) + goto err; + data = run; + } + } else { + int pending_left = irun; + int pending_right; + byte *out; + int depth = spp; + if (state->line == NULL) { + state->line = gs_alloc_bytes(state->mem, dev->width * depth, + "image line"); + if (state->line == NULL) + return gs_error_VMerror; + } + out = state->line; + + if (pending_left < minx) + pending_left = minx; + else if (pending_left > maxx) + pending_left = maxx; + pending_right = pending_left; + + while (data < bufend) { + /* Find the length of the next run. It will either end when we hit + * the end of the source data, or when the pixel data differs. */ + run = data + spp; + while (1) { + dda_next(pnext.x); + if (run >= bufend) + break; + if (memcmp(run, data, spp)) + break; + run += spp; + } + /* So we have a run of pixels from data to run that are all the same. */ + /* This needs to be sped up */ + for (k = 0; k < spp; k++) { + conc[k] = gx_color_value_from_byte(data[k]); + } + mapper(cmapper); + /* Fill the region between irun and fixed2int_var_rounded(pnext.x) */ + { + int xi = irun; + int wi = (irun = fixed2int_var_rounded(dda_current(pnext.x))) - xi; + + if (wi < 0) + xi += wi, wi = -wi; + + if (xi < minx) + wi += xi - minx, xi = minx; + if (xi + wi > maxx) + wi = maxx - xi; + + if (wi > 0) { + if (color_is_pure(&cmapper->devc)) { + gx_color_index color = cmapper->devc.colors.pure; + int xii = xi * spp; + + if (pending_left > xi) + pending_left = xi; + else + pending_right = xi + wi; + do { + /* Excuse the double shifts below, that's to stop the + * C compiler complaining if the color index type is + * 32 bits. */ + switch(depth) + { + case 8: out[xii++] = ((color>>28)>>28) & 0xff; + case 7: out[xii++] = ((color>>24)>>24) & 0xff; + case 6: out[xii++] = ((color>>24)>>16) & 0xff; + case 5: out[xii++] = ((color>>24)>>8) & 0xff; + case 4: out[xii++] = (color>>24) & 0xff; + case 3: out[xii++] = (color>>16) & 0xff; + case 2: out[xii++] = (color>>8) & 0xff; + case 1: out[xii++] = color & 0xff; + } + } while (--wi != 0); + } else { + if (pending_left != pending_right) { + code = dev_proc(dev, copy_color)(dev, out, pending_left, 0, 0, pending_left, vci, pending_right - pending_left, vdi); + if (code < 0) + goto err; + } + pending_left = pending_right = xi + (pending_left > xi ? 0 : wi); + code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi, + &cmapper->devc, dev, lop); + } + } + if (code < 0) + goto err; + } + data = run; + } + if (pending_left != pending_right) { + code = dev_proc(dev, copy_color)(dev, out, pending_left, 0, 0, pending_left, vci, pending_right - pending_left, vdi); + if (code < 0) + goto err; + } + } + return (code < 0 ? code : 1); + /* Save position if error, in case we resume. */ +err: + buffer[0] = run; + return code; +} + +static int +transform_pixel_region_render_landscape(gx_device *dev, gx_default_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + gs_logical_operation_t lop = state->lop; + gx_dda_fixed_point pnext; + int vci, vdi; + int irun; /* int x/rrun */ + int w = state->w; + int h = state->h; + int spp = state->spp; + const byte *data = buffer[0] + data_x * spp; + const byte *bufend = NULL; + int code = 0; + const byte *run; + int k; + gx_color_value *conc = &cmapper->conc[0]; + int to_rects; + gx_cmapper_fn *mapper = cmapper->set_color; + int miny, maxy; + + if (h == 0) + return 0; + + /* Clip on X */ + get_landscape_x_extent(state, &vci, &vdi); + if (vci < state->clip.p.x) + vdi += vci - state->clip.p.x, vci = state->clip.p.x; + if (vci+vdi > state->clip.q.x) + vdi = state->clip.q.x - vci; + if (vdi <= 0) + return 0; + + pnext = state->pixels; + dda_translate(pnext.x, (-fixed_epsilon)); + irun = fixed2int_var_rounded(dda_current(pnext.y)); + if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", + vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y))); + to_rects = (dev->color_info.depth != spp*8); + if (to_rects == 0) { + if (dev_proc(dev, dev_spec_op)(dev, gxdso_copy_color_is_fast, NULL, 0) <= 0) + to_rects = 1; + } + + miny = state->clip.p.y; + maxy = state->clip.q.y; + bufend = data + w * spp; + while (data < bufend) { + /* Find the length of the next run. It will either end when we hit + * the end of the source data, or when the pixel data differs. */ + run = data + spp; + while (1) { + dda_next(pnext.y); + if (run >= bufend) + break; + if (memcmp(run, data, spp)) + break; + run += spp; + } + /* So we have a run of pixels from data to run that are all the same. */ + /* This needs to be sped up */ + for (k = 0; k < spp; k++) { + conc[k] = gx_color_value_from_byte(data[k]); + } + mapper(cmapper); + /* Fill the region between irun and fixed2int_var_rounded(pnext.y) */ + { /* 90 degree rotated rectangle */ + int yi = irun; + int hi = (irun = fixed2int_var_rounded(dda_current(pnext.y))) - yi; + + if (hi < 0) + yi += hi, hi = -hi; + if (yi < miny) + hi += yi - miny, yi = miny; + if (yi + hi > maxy) + hi = maxy - yi; + if (hi > 0) + code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi, + &cmapper->devc, dev, lop); + } + if (code < 0) + goto err; + data = run; + } + return (code < 0 ? code : 1); + /* Save position if error, in case we resume. */ +err: + buffer[0] = run; + return code; +} + +static int +transform_pixel_region_render_skew(gx_device *dev, gx_default_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + gs_logical_operation_t lop = state->lop; + gx_dda_fixed_point pnext; + fixed xprev, yprev; + fixed pdyx, pdyy; /* edge of parallelogram */ + int w = state->w; + int h = state->h; + int spp = state->spp; + const byte *data = buffer[0] + data_x * spp; + fixed xpos; /* x ditto */ + fixed ypos; /* y ditto */ + const byte *bufend = data + w * spp; + int code = 0; + int k; + byte initial_run[GX_DEVICE_COLOR_MAX_COMPONENTS] = { 0 }; + const byte *prev = &initial_run[0]; + gx_cmapper_fn *mapper = cmapper->set_color; + gx_color_value *conc = &cmapper->conc[0]; + + if (h == 0) + return 0; + pnext = state->pixels; + get_skew_extents(state, &pdyx, &pdyy); + dda_translate(pnext.x, (-fixed_epsilon)); + xprev = dda_current(pnext.x); + yprev = dda_current(pnext.y); + if_debug4m('b', dev->memory, "[b]y=? data_x=%d w=%d xt=%f yt=%f\n", + data_x, w, fixed2float(xprev), fixed2float(yprev)); + initial_run[0] = ~data[0]; /* Force intial setting */ + while (data < bufend) { + dda_next(pnext.x); + dda_next(pnext.y); + xpos = dda_current(pnext.x); + ypos = dda_current(pnext.y); + + if (memcmp(prev, data, spp) != 0) + { + /* This needs to be sped up */ + for (k = 0; k < spp; k++) { + conc[k] = gx_color_value_from_byte(data[k]); + } + mapper(cmapper); + } + /* Fill the region between */ + /* xprev/yprev and xpos/ypos */ + /* Parallelogram */ + code = (*dev_proc(dev, fill_parallelogram)) + (dev, xprev, yprev, xpos - xprev, ypos - yprev, pdyx, pdyy, + &cmapper->devc, lop); + xprev = xpos; + yprev = ypos; + if (code < 0) + goto err; + prev = data; + data += spp; + } + return (code < 0 ? code : 1); + /* Save position if error, in case we resume. */ +err: + buffer[0] = prev; + return code; +} + +static int +gx_default_transform_pixel_region_begin(gx_device *dev, int w, int h, int spp, + const gx_dda_fixed_point *pixels, const gx_dda_fixed_point *rows, + const gs_int_rect *clip, gs_logical_operation_t lop, + gx_default_transform_pixel_region_state_t **statep) +{ + gx_default_transform_pixel_region_state_t *state; + gs_memory_t *mem = dev->memory->non_gc_memory; + + *statep = state = (gx_default_transform_pixel_region_state_t *)gs_alloc_bytes(mem, sizeof(gx_default_transform_pixel_region_state_t), "gx_default_transform_pixel_region_state_t"); + if (state == NULL) + return gs_error_VMerror; + state->mem = mem; + state->rows = *rows; + state->pixels = *pixels; + state->clip = *clip; + state->w = w; + state->h = h; + state->spp = spp; + state->lop = lop; + state->line = NULL; + + /* FIXME: Consider sheers here too. Probably happens rarely enough not to be worth it. */ + if (rows->x.step.dQ == 0 && rows->x.step.dR == 0 && pixels->y.step.dQ == 0 && pixels->y.step.dR == 0) + state->posture = transform_pixel_region_portrait; + else if (rows->y.step.dQ == 0 && rows->y.step.dR == 0 && pixels->x.step.dQ == 0 && pixels->x.step.dR == 0) + state->posture = transform_pixel_region_landscape; + else + state->posture = transform_pixel_region_skew; + + if (state->posture == transform_pixel_region_portrait) + state->render = transform_pixel_region_render_portrait; + else if (state->posture == transform_pixel_region_landscape) + state->render = transform_pixel_region_render_landscape; + else + state->render = transform_pixel_region_render_skew; + + return 0; +} + +static void +step_to_next_line(gx_default_transform_pixel_region_state_t *state) +{ + fixed x = dda_current(state->rows.x); + fixed y = dda_current(state->rows.y); + + dda_next(state->rows.x); + dda_next(state->rows.y); + x = dda_current(state->rows.x) - x; + y = dda_current(state->rows.y) - y; + dda_translate(state->pixels.x, x); + dda_translate(state->pixels.y, y); +} + +static int +gx_default_transform_pixel_region_data_needed(gx_device *dev, gx_default_transform_pixel_region_state_t *state) +{ + if (state->posture == transform_pixel_region_portrait) { + int iy, ih; + + get_portrait_y_extent(state, &iy, &ih); + + if (iy + ih < state->clip.p.y || iy >= state->clip.q.y) { + /* Skip this line. */ + step_to_next_line(state); + return 0; + } + } else if (state->posture == transform_pixel_region_landscape) { + int ix, iw; + + get_landscape_x_extent(state, &ix, &iw); + + if (ix + iw < state->clip.p.x || ix >= state->clip.q.x) { + /* Skip this line. */ + step_to_next_line(state); + return 0; + } + } + + return 1; +} + +static int +gx_default_transform_pixel_region_process_data(gx_device *dev, gx_default_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + int ret = state->render(dev, state, buffer, data_x, cmapper, pgs); + + step_to_next_line(state); + return ret; +} + +static int +gx_default_transform_pixel_region_end(gx_device *dev, gx_default_transform_pixel_region_state_t *state) +{ + if (state) { + gs_free_object(state->mem, state->line, "image line"); + gs_free_object(state->mem, state, "gx_default_transform_pixel_region_state_t"); + } + return 0; +} + +int +gx_default_transform_pixel_region(gx_device *dev, + transform_pixel_region_reason reason, + transform_pixel_region_data *data) +{ + gx_default_transform_pixel_region_state_t *state = (gx_default_transform_pixel_region_state_t *)data->state; + + switch (reason) + { + case transform_pixel_region_begin: + return gx_default_transform_pixel_region_begin(dev, data->u.init.w, data->u.init.h, data->u.init.spp, data->u.init.pixels, data->u.init.rows, data->u.init.clip, data->u.init.lop, (gx_default_transform_pixel_region_state_t **)&data->state); + case transform_pixel_region_data_needed: + return gx_default_transform_pixel_region_data_needed(dev, state); + case transform_pixel_region_process_data: + return gx_default_transform_pixel_region_process_data(dev, state, data->u.process_data.buffer, data->u.process_data.data_x, data->u.process_data.cmapper, data->u.process_data.pgs); + case transform_pixel_region_end: + data->state = NULL; + return gx_default_transform_pixel_region_end(dev, state); + default: + return gs_error_unknownerror; + } +} diff -Nru ghostscript-9.25~dfsg+1/base/gdevdrop.c ghostscript-9.26~dfsg+0/base/gdevdrop.c --- ghostscript-9.25~dfsg+1/base/gdevdrop.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevdrop.c 2018-11-20 09:59:43.000000000 +0000 @@ -1013,3 +1013,599 @@ #undef MPo return (rop & mask) | (rop3_D & ~mask); } + +typedef enum { + transform_pixel_region_portrait, + transform_pixel_region_landscape, + transform_pixel_region_skew +} transform_pixel_region_posture; + +typedef struct mem_transform_pixel_region_state_s mem_transform_pixel_region_state_t; + +typedef int (mem_transform_pixel_region_render_fn)(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs); + +struct mem_transform_pixel_region_state_s +{ + gs_memory_t *mem; + gx_dda_fixed_point pixels; + gx_dda_fixed_point rows; + gs_int_rect clip; + int w; + int h; + int spp; + transform_pixel_region_posture posture; + mem_transform_pixel_region_render_fn *render; + void *passthru; +}; + +static void +get_portrait_y_extent(mem_transform_pixel_region_state_t *state, int *iy, int *ih) +{ + fixed y0, y1; + gx_dda_fixed row = state->rows.y; + + y0 = dda_current(row); + dda_next(row); + y1 = dda_current(row); + + if (y1 < y0) { + fixed t = y1; y1 = y0; y0 = t; + } + + *iy = fixed2int_pixround_perfect(y0); + *ih = fixed2int_pixround_perfect(y1) - *iy; +} + +static void +get_landscape_x_extent(mem_transform_pixel_region_state_t *state, int *ix, int *iw) +{ + fixed x0, x1; + gx_dda_fixed row = state->rows.x; + + x0 = dda_current(row); + dda_next(row); + x1 = dda_current(row); + + if (x1 < x0) { + fixed t = x1; x1 = x0; x0 = t; + } + + *ix = fixed2int_pixround_perfect(x0); + *iw = fixed2int_pixround_perfect(x1) - *ix; +} + +static inline int +template_mem_transform_pixel_region_render_portrait(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs, int spp) +{ + gx_device_memory *mdev = (gx_device_memory *)dev; + gx_dda_fixed_point pnext; + int vci, vdi; + int irun; /* int x/rrun */ + int w = state->w; + int h = state->h; + const byte *data = buffer[0] + data_x * spp; + const byte *bufend = NULL; + const byte *run; + int k; + gx_color_value *conc = &cmapper->conc[0]; + gx_cmapper_fn *mapper = cmapper->set_color; + byte *out; + byte *out_row; + int minx, maxx; + + if (h == 0) + return 0; + + /* Clip on y */ + get_portrait_y_extent(state, &vci, &vdi); + if (vci < state->clip.p.y) + vdi += vci - state->clip.p.y, vci = state->clip.p.y; + if (vci+vdi > state->clip.q.y) + vdi = state->clip.q.y - vci; + if (vdi <= 0) + return 0; + + pnext = state->pixels; + dda_translate(pnext.x, (-fixed_epsilon)); + irun = fixed2int_var_rounded(dda_current(pnext.x)); + if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", + vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y))); + + minx = state->clip.p.x; + maxx = state->clip.q.x; + out_row = mdev->base + mdev->raster * vci; + bufend = data + w * spp; + while (data < bufend) { + /* Find the length of the next run. It will either end when we hit + * the end of the source data, or when the pixel data differs. */ + run = data + spp; + while (1) { + dda_next(pnext.x); + if (run >= bufend) + break; + if (memcmp(run, data, spp)) + break; + run += spp; + } + /* So we have a run of pixels from data to run that are all the same. */ + /* This needs to be sped up */ + for (k = 0; k < spp; k++) { + conc[k] = gx_color_value_from_byte(data[k]); + } + mapper(cmapper); + /* Fill the region between irun and fixed2int_var_rounded(pnext.x) */ + { + int xi = irun; + int wi = (irun = fixed2int_var_rounded(dda_current(pnext.x))) - xi; + + if (wi < 0) + xi += wi, wi = -wi; + + if (xi < minx) + wi += xi - minx, xi = minx; + if (xi+wi > maxx) + wi = maxx - xi; + if (wi > 0) { + /* assert(color_is_pure(&cmapper->devc)); */ + out = out_row; + for (h = vdi; h > 0; h--, out += mdev->raster) { + gx_color_index color = cmapper->devc.colors.pure; + int xii = xi * spp; + int wii = wi; + do { + /* Excuse the double shifts below, that's to stop the + * C compiler complaining if the color index type is + * 32 bits. */ + switch(spp) + { + case 8: out[xii++] = ((color>>28)>>28) & 0xff; + case 7: out[xii++] = ((color>>24)>>24) & 0xff; + case 6: out[xii++] = ((color>>24)>>16) & 0xff; + case 5: out[xii++] = ((color>>24)>>8) & 0xff; + case 4: out[xii++] = (color>>24) & 0xff; + case 3: out[xii++] = (color>>16) & 0xff; + case 2: out[xii++] = (color>>8) & 0xff; + case 1: out[xii++] = color & 0xff; + } + } while (--wii != 0); + } + } + } + data = run; + } + return 0; +} + +static int +mem_transform_pixel_region_render_portrait_1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs, 1); +} + +static int +mem_transform_pixel_region_render_portrait_3(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs, 3); +} + +static int +mem_transform_pixel_region_render_portrait_4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs, 4); +} + +static int +mem_transform_pixel_region_render_portrait_n(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs, state->spp); +} + +static int +mem_transform_pixel_region_render_portrait(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + switch(state->spp) { + case 1: + return mem_transform_pixel_region_render_portrait_1(dev, state, buffer, data_x, cmapper, pgs); + case 3: + return mem_transform_pixel_region_render_portrait_3(dev, state, buffer, data_x, cmapper, pgs); + case 4: + return mem_transform_pixel_region_render_portrait_4(dev, state, buffer, data_x, cmapper, pgs); + default: + return mem_transform_pixel_region_render_portrait_n(dev, state, buffer, data_x, cmapper, pgs); + } +} + +static inline int +template_mem_transform_pixel_region_render_portrait_1to1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs, int spp) +{ + gx_device_memory *mdev = (gx_device_memory *)dev; + gx_dda_fixed_point pnext; + int vci, vdi; + int w = state->w; + int h = state->h; + int left, right, oleft; + + if (h == 0) + return 0; + + /* Clip on y */ + get_portrait_y_extent(state, &vci, &vdi); + if (vci < state->clip.p.y) + vdi += vci - state->clip.p.y, vci = state->clip.p.y; + if (vci+vdi > state->clip.q.y) + vdi = state->clip.q.y - vci; + if (vdi <= 0) + return 0; + + pnext = state->pixels; + dda_translate(pnext.x, (-fixed_epsilon)); + left = fixed2int_var_rounded(dda_current(pnext.x)); + if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", + vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y))); + right = fixed2int_var_rounded(dda_current(pnext.x)) + w; + + if (left > right) { + int tmp = left; left = right; right = tmp; + } + oleft = left; + if (left < state->clip.p.x) + left = state->clip.p.x; + if (right > state->clip.q.x) + right = state->clip.q.x; + if (left < right) { + byte *out = mdev->base + mdev->raster * vci + left * spp; + const byte *data = buffer[0] + (data_x + left - oleft) * spp; + right = (right-left)*spp; + do { + memcpy(out, data, right); + out += mdev->raster; + } while (--vdi); + } + + return 0; +} + +static int +mem_transform_pixel_region_render_portrait_1to1_1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait_1to1(dev, state, buffer, data_x, cmapper, pgs, 1); +} + +static int +mem_transform_pixel_region_render_portrait_1to1_3(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait_1to1(dev, state, buffer, data_x, cmapper, pgs, 3); +} + +static int +mem_transform_pixel_region_render_portrait_1to1_4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait_1to1(dev, state, buffer, data_x, cmapper, pgs, 4); +} + +static int +mem_transform_pixel_region_render_portrait_1to1_n(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_portrait_1to1(dev, state, buffer, data_x, cmapper, pgs, state->spp); +} + +static int +mem_transform_pixel_region_render_portrait_1to1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + if (!cmapper->direct) + return mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs); + switch(state->spp) { + case 1: + return mem_transform_pixel_region_render_portrait_1to1_1(dev, state, buffer, data_x, cmapper, pgs); + case 3: + return mem_transform_pixel_region_render_portrait_1to1_3(dev, state, buffer, data_x, cmapper, pgs); + case 4: + return mem_transform_pixel_region_render_portrait_1to1_4(dev, state, buffer, data_x, cmapper, pgs); + default: + return mem_transform_pixel_region_render_portrait_1to1_n(dev, state, buffer, data_x, cmapper, pgs); + } +} + +static inline int +template_mem_transform_pixel_region_render_landscape(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs, int spp) +{ + gx_device_memory *mdev = (gx_device_memory *)dev; + gx_dda_fixed_point pnext; + int vci, vdi; + int irun; /* int x/rrun */ + int w = state->w; + int h = state->h; + const byte *data = buffer[0] + data_x * spp; + const byte *bufend = NULL; + int code = 0; + const byte *run; + int k; + gx_color_value *conc = &cmapper->conc[0]; + gx_cmapper_fn *mapper = cmapper->set_color; + byte *out; + byte *out_row; + int miny, maxy; + + if (h == 0) + return 0; + + /* Clip on x */ + get_landscape_x_extent(state, &vci, &vdi); + if (vci < state->clip.p.x) + vdi += vci - state->clip.p.x, vci = state->clip.p.x; + if (vci+vdi > state->clip.q.x) + vdi = state->clip.q.x - vci; + if (vdi <= 0) + return 0; + + pnext = state->pixels; + dda_translate(pnext.x, (-fixed_epsilon)); + irun = fixed2int_var_rounded(dda_current(pnext.y)); + if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", + vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y))); + + miny = state->clip.p.y; + maxy = state->clip.q.y; + out_row = mdev->base + vci * spp; + bufend = data + w * spp; + while (data < bufend) { + /* Find the length of the next run. It will either end when we hit + * the end of the source data, or when the pixel data differs. */ + run = data + spp; + while (1) { + dda_next(pnext.y); + if (run >= bufend) + break; + if (memcmp(run, data, spp)) + break; + run += spp; + } + /* So we have a run of pixels from data to run that are all the same. */ + /* This needs to be sped up */ + for (k = 0; k < spp; k++) { + conc[k] = gx_color_value_from_byte(data[k]); + } + mapper(cmapper); + /* Fill the region between irun and fixed2int_var_rounded(pnext.y) */ + { /* 90 degree rotated rectangle */ + int yi = irun; + int hi = (irun = fixed2int_var_rounded(dda_current(pnext.y))) - yi; + + if (hi < 0) + yi += hi, hi = -hi; + + if (yi < miny) + hi += yi - miny, yi = miny; + if (yi+hi > maxy) + hi = maxy - yi; + if (hi > 0) { + /* assert(color_is_pure(&cmapper->devc)); */ + out = out_row + mdev->raster * yi; + for (h = hi; h > 0; h--, out += mdev->raster) { + gx_color_index color = cmapper->devc.colors.pure; + int xii = 0; + int wii = vdi; + do { + /* Excuse the double shifts below, that's to stop the + * C compiler complaining if the color index type is + * 32 bits. */ + switch(spp) + { + case 8: out[xii++] = ((color>>28)>>28) & 0xff; + case 7: out[xii++] = ((color>>24)>>24) & 0xff; + case 6: out[xii++] = ((color>>24)>>16) & 0xff; + case 5: out[xii++] = ((color>>24)>>8) & 0xff; + case 4: out[xii++] = (color>>24) & 0xff; + case 3: out[xii++] = (color>>16) & 0xff; + case 2: out[xii++] = (color>>8) & 0xff; + case 1: out[xii++] = color & 0xff; + } + } while (--wii != 0); + } + } + } + if (code < 0) + goto err; + data = run; + } + return (code < 0 ? code : 1); + /* Save position if error, in case we resume. */ +err: + buffer[0] = run; + return code; +} + +static int +mem_transform_pixel_region_render_landscape_1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_landscape(dev, state, buffer, data_x, cmapper, pgs, 1); +} + +static int +mem_transform_pixel_region_render_landscape_3(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_landscape(dev, state, buffer, data_x, cmapper, pgs, 3); +} + +static int +mem_transform_pixel_region_render_landscape_4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_landscape(dev, state, buffer, data_x, cmapper, pgs, 4); +} + +static int +mem_transform_pixel_region_render_landscape_n(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + return template_mem_transform_pixel_region_render_landscape(dev, state, buffer, data_x, cmapper, pgs, state->spp); +} + +static int +mem_transform_pixel_region_render_landscape(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + switch (state->spp) { + case 1: + return mem_transform_pixel_region_render_landscape_1(dev, state, buffer, data_x, cmapper, pgs); + case 3: + return mem_transform_pixel_region_render_landscape_3(dev, state, buffer, data_x, cmapper, pgs); + case 4: + return mem_transform_pixel_region_render_landscape_4(dev, state, buffer, data_x, cmapper, pgs); + default: + return mem_transform_pixel_region_render_landscape_n(dev, state, buffer, data_x, cmapper, pgs); + } +} + +static int +mem_transform_pixel_region_begin(gx_device *dev, int w, int h, int spp, + const gx_dda_fixed_point *pixels, const gx_dda_fixed_point *rows, + const gs_int_rect *clip, transform_pixel_region_posture posture, + mem_transform_pixel_region_state_t **statep) +{ + mem_transform_pixel_region_state_t *state; + gs_memory_t *mem = dev->memory->non_gc_memory; + *statep = state = (mem_transform_pixel_region_state_t *)gs_alloc_bytes(mem, sizeof(mem_transform_pixel_region_state_t), "mem_transform_pixel_region_state_t"); + if (state == NULL) + return gs_error_VMerror; + state->mem = mem; + state->rows = *rows; + state->pixels = *pixels; + state->clip = *clip; + if (state->clip.p.x < 0) + state->clip.p.x = 0; + if (state->clip.q.x > dev->width) + state->clip.q.x = dev->width; + if (state->clip.p.y < 0) + state->clip.p.y = 0; + if (state->clip.q.y > dev->height) + state->clip.q.y = dev->height; + state->w = w; + state->h = h; + state->spp = spp; + state->posture = posture; + + if (state->posture == transform_pixel_region_portrait) { + if (pixels->x.step.dQ == fixed_1 && pixels->x.step.dR == 0) + state->render = mem_transform_pixel_region_render_portrait_1to1; + else + state->render = mem_transform_pixel_region_render_portrait; + } else + state->render = mem_transform_pixel_region_render_landscape; + + return 0; +} + +static void +step_to_next_line(mem_transform_pixel_region_state_t *state) +{ + fixed x = dda_current(state->rows.x); + fixed y = dda_current(state->rows.y); + dda_next(state->rows.x); + dda_next(state->rows.y); + x = dda_current(state->rows.x) - x; + y = dda_current(state->rows.y) - y; + dda_translate(state->pixels.x, x); + dda_translate(state->pixels.y, y); +} + +static int +mem_transform_pixel_region_data_needed(gx_device *dev, mem_transform_pixel_region_state_t *state) +{ + if (state->posture == transform_pixel_region_portrait) { + int iy, ih; + + get_portrait_y_extent(state, &iy, &ih); + + if (iy + ih < state->clip.p.y || iy >= state->clip.q.y) { + /* Skip this line. */ + step_to_next_line(state); + return 0; + } + } else if (state->posture == transform_pixel_region_landscape) { + int ix, iw; + + get_landscape_x_extent(state, &ix, &iw); + + if (ix + iw < state->clip.p.x || ix >= state->clip.q.x) { + /* Skip this line. */ + step_to_next_line(state); + return 0; + } + } + + return 1; +} + +static int +mem_transform_pixel_region_process_data(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs) +{ + int ret = state->render(dev, state, buffer, data_x, cmapper, pgs); + + step_to_next_line(state); + + return ret; +} + +static int +mem_transform_pixel_region_end(gx_device *dev, mem_transform_pixel_region_state_t *state) +{ + if (state) + gs_free_object(state->mem->non_gc_memory, state, "mem_transform_pixel_region_state_t"); + return 0; +} + +int mem_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) +{ + mem_transform_pixel_region_state_t *state = (mem_transform_pixel_region_state_t *)data->state; + transform_pixel_region_posture posture; + + /* Pass through */ + if (reason == transform_pixel_region_begin) { + const gx_dda_fixed_point *rows = data->u.init.rows; + const gx_dda_fixed_point *pixels = data->u.init.pixels; + if (rows->x.step.dQ == 0 && rows->x.step.dR == 0 && pixels->y.step.dQ == 0 && pixels->y.step.dR == 0) + posture = transform_pixel_region_portrait; + else if (rows->y.step.dQ == 0 && rows->y.step.dR == 0 && pixels->x.step.dQ == 0 && pixels->x.step.dR == 0) + posture = transform_pixel_region_landscape; + else + posture = transform_pixel_region_skew; + + if (posture == transform_pixel_region_skew || dev->color_info.depth != data->u.init.spp*8 || data->u.init.lop != 0xf0) { + mem_transform_pixel_region_state_t *state = (mem_transform_pixel_region_state_t *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(mem_transform_pixel_region_state_t), "mem_transform_pixel_region_state_t"); + if (state == NULL) + return gs_error_VMerror; + state->render = NULL; + if (gx_default_transform_pixel_region(dev, transform_pixel_region_begin, data) < 0) { + gs_free_object(dev->memory->non_gc_memory, state, "mem_transform_pixel_region_state_t"); + return gs_error_VMerror; + } + state->passthru = data->state; + data->state = state; + return 0; + } + } else if (state->render == NULL) { + int ret; + data->state = state->passthru; + ret = gx_default_transform_pixel_region(dev, reason, data); + data->state = state; + if (reason == transform_pixel_region_end) { + gs_free_object(dev->memory->non_gc_memory, state, "mem_transform_pixel_region_state_t"); + data->state = NULL; + } + return ret; + } + + /* We can handle this case natively */ + switch(reason) + { + case transform_pixel_region_begin: + return mem_transform_pixel_region_begin(dev, data->u.init.w, data->u.init.h, data->u.init.spp, data->u.init.pixels, data->u.init.rows, data->u.init.clip, posture, (mem_transform_pixel_region_state_t **)&data->state); + case transform_pixel_region_data_needed: + return mem_transform_pixel_region_data_needed(dev, state); + case transform_pixel_region_process_data: + return mem_transform_pixel_region_process_data(dev, state, data->u.process_data.buffer, data->u.process_data.data_x, data->u.process_data.cmapper, data->u.process_data.pgs); + case transform_pixel_region_end: + data->state = NULL; + return mem_transform_pixel_region_end(dev, state); + default: + return gs_error_unknownerror; + } +} diff -Nru ghostscript-9.25~dfsg+1/base/gdevepo.c ghostscript-9.26~dfsg+0/base/gdevepo.c --- ghostscript-9.25~dfsg+1/base/gdevepo.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevepo.c 2018-11-20 09:59:43.000000000 +0000 @@ -80,6 +80,7 @@ static dev_proc_copy_planes(epo_copy_planes); static dev_proc_copy_alpha_hl_color(epo_copy_alpha_hl_color); static dev_proc_process_page(epo_process_page); +static dev_proc_transform_pixel_region(epo_transform_pixel_region); /* The device prototype */ #define MAX_COORD (max_int_in_fixed - 1000) @@ -182,7 +183,8 @@ epo_strip_copy_rop2, default_subclass_strip_tile_rect_devn, epo_copy_alpha_hl_color, - epo_process_page + epo_process_page, + epo_transform_pixel_region } }; @@ -208,7 +210,7 @@ static bool device_wants_optimization(gx_device *dev) { - return (dev_proc(dev, fillpage) == gx_default_fillpage); + return (!gs_is_null_device(dev) && dev_proc(dev, fillpage) == gx_default_fillpage); } /* Use this when debugging to enable/disable epo @@ -466,7 +468,7 @@ return dev_proc(dev, fill_linear_color_triangle)(dev, fa, p0, p1, p2, c0, c1, c2); } -int epo_put_image(gx_device *dev, const byte **buffers, int num_chan, int x, int y, +int epo_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y, int width, int height, int row_stride, int alpha_plane_index, int tag_plane_index) { @@ -474,7 +476,7 @@ if (code != 0) return code; - return dev_proc(dev, put_image)(dev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); + return dev_proc(dev, put_image)(dev, mdev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); } int epo_create_compositor(gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte, @@ -676,3 +678,12 @@ return code; return dev_proc(dev, process_page)(dev, options); } + +int epo_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) +{ + int code = epo_handle_erase_page(dev); + + if (code != 0) + return code; + return dev_proc(dev, transform_pixel_region)(dev, reason, data); +} diff -Nru ghostscript-9.25~dfsg+1/base/gdevflp.c ghostscript-9.26~dfsg+0/base/gdevflp.c --- ghostscript-9.25~dfsg+1/base/gdevflp.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevflp.c 2018-11-20 09:59:43.000000000 +0000 @@ -105,6 +105,7 @@ static dev_proc_strip_tile_rect_devn(flp_strip_tile_rect_devn); static dev_proc_copy_alpha_hl_color(flp_copy_alpha_hl_color); static dev_proc_process_page(flp_process_page); +static dev_proc_transform_pixel_region(flp_transform_pixel_region); /* The device prototype */ #define MAX_COORD (max_int_in_fixed - 1000) @@ -1132,7 +1133,7 @@ return 0; } -int flp_put_image(gx_device *dev, const byte **buffers, int num_chan, int x, int y, +int flp_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y, int width, int height, int row_stride, int alpha_plane_index, int tag_plane_index) { @@ -1141,7 +1142,7 @@ if (code < 0) return code; if (!code) - return default_subclass_put_image(dev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); + return default_subclass_put_image(dev, mdev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); return 0; } @@ -1211,3 +1212,15 @@ return 0; } + +int flp_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) +{ + int code = SkipPage(dev); + + if (code < 0) + return code; + if (!code) + return default_subclass_transform_pixel_region(dev, reason, data); + + return 0; +} diff -Nru ghostscript-9.25~dfsg+1/base/gdevmem.c ghostscript-9.26~dfsg+0/base/gdevmem.c --- ghostscript-9.25~dfsg+1/base/gdevmem.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevmem.c 2018-11-20 09:59:43.000000000 +0000 @@ -179,8 +179,8 @@ dev->color_info.separable_and_linear = target->color_info.separable_and_linear; dev->cached_colors = target->cached_colors; dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */ - /* Do a copy of put_image since it needs the source buffer */ - set_dev_proc(dev, put_image, target->procs.put_image); + + set_dev_proc(dev, put_image, gx_forward_put_image); set_dev_proc(dev, dev_spec_op, gx_default_dev_spec_op); } if (dev->color_info.depth == 1) { diff -Nru ghostscript-9.25~dfsg+1/base/gdevmem.h ghostscript-9.26~dfsg+0/base/gdevmem.h --- ghostscript-9.25~dfsg+1/base/gdevmem.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevmem.h 2018-11-20 09:59:43.000000000 +0000 @@ -102,6 +102,7 @@ /* Default implementations */ dev_proc_strip_copy_rop(mem_default_strip_copy_rop); dev_proc_strip_copy_rop2(mem_default_strip_copy_rop2); +dev_proc_transform_pixel_region(mem_transform_pixel_region); /* * Macro for generating the device descriptor. @@ -182,7 +183,26 @@ NULL, /* encode_color */\ NULL, /* decode_color */\ NULL, /* pattern_manage */\ - fill_rectangle_hl_color /* fill_rectangle_hl_color */\ + fill_rectangle_hl_color, /* fill_rectangle_hl_color */\ + NULL, /* include_color_space */\ + NULL, /* fill_linear_color_scanline */\ + NULL, /* fill_linear_color_trapezoid */\ + NULL, /* fill_linear_color_triangle */\ + NULL, /* update_spot_equivalent_colors */\ + NULL, /* ret_devn_params */\ + NULL, /* fillpage */\ + NULL, /* push_transparency_state */\ + NULL, /* pop_transparency_state */\ + NULL, /* put_image */\ + NULL, /* dev_spec_op */\ + NULL, /* copy_planes */\ + NULL, /* get_profile */\ + NULL, /* set_graphics_type_tag */\ + NULL, /* strip_copy_rop2 */\ + NULL, /* strip_tile_rect_devn */\ + NULL, /* copy_alpha_hl_color */\ + NULL, /* process_page */\ + mem_transform_pixel_region\ },\ 0, /* target */\ mem_device_init_private /* see gxdevmem.h */\ diff -Nru ghostscript-9.25~dfsg+1/base/gdevmpla.c ghostscript-9.26~dfsg+0/base/gdevmpla.c --- ghostscript-9.25~dfsg+1/base/gdevmpla.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevmpla.c 2018-11-20 09:59:43.000000000 +0000 @@ -254,11 +254,11 @@ /* Put image command for copying the planar image buffers with or without alpha directly to the device buffer */ static int -mem_planar_put_image(gx_device *pdev, const byte **buffers, int num_chan, int xstart, +mem_planar_put_image(gx_device *pdev, gx_device *pmdev, const byte **buffers, int num_chan, int xstart, int ystart, int width, int height, int row_stride, int alpha_plane_index, int tag_plane_index) { - gx_device_memory * const mdev = (gx_device_memory *)pdev; + gx_device_memory * const mdev = (gx_device_memory *)pmdev; /* We don't want alpha, return 0 to ask for the pdf14 device to do the alpha composition. We also do not want chunky data coming in or to deal diff -Nru ghostscript-9.25~dfsg+1/base/gdevmplt.c ghostscript-9.26~dfsg+0/base/gdevmplt.c --- ghostscript-9.25~dfsg+1/base/gdevmplt.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevmplt.c 2018-11-20 09:59:43.000000000 +0000 @@ -151,7 +151,8 @@ default_subclass_strip_copy_rop2, default_subclass_strip_tile_rect_devn, default_subclass_copy_alpha_hl_color, - default_subclass_process_page + default_subclass_process_page, + default_subclass_transform_pixel_region } }; diff -Nru ghostscript-9.25~dfsg+1/base/gdevnfwd.c ghostscript-9.26~dfsg+0/base/gdevnfwd.c --- ghostscript-9.25~dfsg+1/base/gdevnfwd.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevnfwd.c 2018-11-20 09:59:43.000000000 +0000 @@ -112,10 +112,12 @@ fill_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors); fill_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params); fill_dev_proc(dev, fillpage, gx_forward_fillpage); + fill_dev_proc(dev, put_image, gx_forward_put_image); fill_dev_proc(dev, get_profile, gx_forward_get_profile); fill_dev_proc(dev, set_graphics_type_tag, gx_forward_set_graphics_type_tag); fill_dev_proc(dev, strip_copy_rop2, gx_forward_strip_copy_rop2); - fill_dev_proc(dev, strip_tile_rect_devn, gx_forward_strip_tile_rect_devn); + fill_dev_proc(dev, strip_tile_rect_devn, gx_forward_strip_tile_rect_devn); + fill_dev_proc(dev, transform_pixel_region, gx_forward_transform_pixel_region); gx_device_fill_in_procs((gx_device *) dev); } @@ -610,17 +612,17 @@ int gx_forward_strip_tile_rect_devn(gx_device * dev, const gx_strip_bitmap * tiles, - int x, int y, int w, int h, const gx_drawing_color * pdcolor0, + int x, int y, int w, int h, const gx_drawing_color * pdcolor0, const gx_drawing_color * pdcolor1, int px, int py) { gx_device_forward * const fdev = (gx_device_forward *)dev; gx_device *tdev = fdev->target; if (tdev == 0) - return gx_default_strip_tile_rect_devn(dev, tiles, x, y, w, h, pdcolor0, + return gx_default_strip_tile_rect_devn(dev, tiles, x, y, w, h, pdcolor0, pdcolor1, px, py); else - return dev_proc(tdev, strip_tile_rect_devn)(tdev, tiles, x, y, w, h, + return dev_proc(tdev, strip_tile_rect_devn)(tdev, tiles, x, y, w, h, pdcolor0, pdcolor1, px, py); } @@ -1013,7 +1015,33 @@ dev->graphics_type_tag = (dev->graphics_type_tag & GS_DEVICE_ENCODES_TAGS) | graphics_type_tag; } -/* ---------------- The null device(s) ---------------- */ +int +gx_forward_put_image(gx_device *pdev, gx_device *mdev, const byte **buffers, int num_chan, int xstart, + int ystart, int width, int height, int row_stride, + int alpha_plane_index, int tag_plane_index) +{ + gx_device_forward * const fdev = (gx_device_forward *)pdev; + gx_device *tdev = fdev->target; + + if (tdev != 0) + return dev_proc(tdev, put_image)(tdev, mdev, buffers, num_chan, xstart, ystart, width, height, row_stride, alpha_plane_index, tag_plane_index); + else + return gx_default_put_image(tdev, mdev, buffers, num_chan, xstart, ystart, width, height, row_stride, alpha_plane_index, tag_plane_index); +} + +int +gx_forward_transform_pixel_region(gx_device *pdev, transform_pixel_region_reason reason, transform_pixel_region_data *data) +{ + gx_device_forward * const fdev = (gx_device_forward *)pdev; + gx_device *tdev = fdev->target; + + if (tdev != 0) + return dev_proc(tdev, transform_pixel_region)(tdev, reason, data); + else + return gx_default_transform_pixel_region(pdev, reason, data); +} + +/* ---------------- The null device(s) ---------_plane_index------- */ static dev_proc_get_initial_matrix(gx_forward_upright_get_initial_matrix); static dev_proc_fill_rectangle(null_fill_rectangle); @@ -1276,7 +1304,7 @@ static int null_strip_tile_rect_devn(gx_device * dev, const gx_strip_bitmap * tiles, - int x, int y, int w, int h, const gx_drawing_color * pdcolor0, + int x, int y, int w, int h, const gx_drawing_color * pdcolor0, const gx_drawing_color * pdcolor1, int px, int py) { return 0; diff -Nru ghostscript-9.25~dfsg+1/base/gdevoflt.c ghostscript-9.26~dfsg+0/base/gdevoflt.c --- ghostscript-9.25~dfsg+1/base/gdevoflt.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevoflt.c 2018-11-20 09:59:43.000000000 +0000 @@ -173,7 +173,8 @@ obj_filter_strip_copy_rop2, obj_filter_strip_tile_rect_devn, default_subclass_copy_alpha_hl_color, - default_subclass_process_page + default_subclass_process_page, + default_subclass_transform_pixel_region } }; @@ -530,12 +531,12 @@ return 0; } -int obj_filter_put_image(gx_device *dev, const byte **buffers, int num_chan, int x, int y, +int obj_filter_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y, int width, int height, int row_stride, int alpha_plane_index, int tag_plane_index) { if ((dev->ObjectFilter & FILTERIMAGE) == 0) - return default_subclass_put_image(dev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); + return default_subclass_put_image(dev, mdev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); return 0; } diff -Nru ghostscript-9.25~dfsg+1/base/gdevp14.c ghostscript-9.26~dfsg+0/base/gdevp14.c --- ghostscript-9.25~dfsg+1/base/gdevp14.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevp14.c 2018-11-20 09:59:43.000000000 +0000 @@ -1883,11 +1883,10 @@ if (dev_target_profile == NULL) return gs_throw_code(gs_error_Fatal); - /* See if the target device has a put_image command. If yes then see if it - can handle the image data directly. If it cannot, then we will need to + /* See if the target device can handle the image data directly. If it cannot, then we will need to use the begin_typed_image interface, which cannot pass along tag nor alpha data to the target device. */ - if (dev_proc(target, put_image) != gx_default_put_image) { + { pdf14_buf *cm_result = NULL; int alpha_offset, tag_offset; const byte *buf_ptrs[GS_CLIENT_COLOR_MAX_COMPONENTS]; @@ -1946,7 +1945,7 @@ /* See if the target device can handle the data with alpha component */ for (i = 0; i < buf->n_planes; i++) buf_ptrs[i] = buf_ptr + i * buf->planestride; - code = dev_proc(target, put_image) (target, buf_ptrs, num_comp, + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, rect.p.x, rect.p.y, width, height, buf->rowstride, alpha_offset, tag_offset); @@ -1973,7 +1972,7 @@ /* Try again now with just the tags */ alpha_offset = 0; - code = dev_proc(target, put_image) (target, buf_ptrs, num_comp, + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, rect.p.x, rect.p.y, width, height, buf->rowstride, alpha_offset, tag_offset); @@ -1982,7 +1981,7 @@ /* We processed some or all of the rows. Continue until we are done */ num_rows_left = height - code; while (num_rows_left > 0) { - code = dev_proc(target, put_image) (target, buf_ptrs, num_comp, + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, rect.p.x, rect.p.y + code, width, num_rows_left, buf->rowstride, alpha_offset, tag_offset); @@ -5618,7 +5617,8 @@ return 0; } } - if (dev_spec_op == gxdso_get_dev_param || dev_spec_op == gxdso_restrict_bbox) { + if (dev_spec_op == gxdso_get_dev_param || dev_spec_op == gxdso_restrict_bbox + || dev_spec_op == gxdso_current_output_device) { return dev_proc(p14dev->target, dev_spec_op)(p14dev->target, dev_spec_op, data, size); } diff -Nru ghostscript-9.25~dfsg+1/base/gdevprn.c ghostscript-9.26~dfsg+0/base/gdevprn.c --- ghostscript-9.25~dfsg+1/base/gdevprn.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevprn.c 2018-11-20 09:59:43.000000000 +0000 @@ -210,6 +210,11 @@ return code; } +#ifdef DEBUG + if (dev_spec_op == gxdso_debug_printer_check) + return 1; +#endif + return gx_default_dev_spec_op(pdev, dev_spec_op, data, size); } @@ -1466,17 +1471,22 @@ mdev = (gx_device_memory *)*pbdev; } if (target == (gx_device *)mdev) { + dev_t_proc_dev_spec_op((*orig_dso), gx_device) = dev_proc(mdev, dev_spec_op); /* The following is a special hack for setting up printer devices. */ assign_dev_procs(mdev, mdproto); + /* Do not override the dev_spec_op! */ + dev_proc(mdev, dev_spec_op) = orig_dso; check_device_separable((gx_device *)mdev); /* In order for saved-pages to work, we need to hook the dev_spec_op */ - if (mdev->procs.dev_spec_op == NULL) + if (mdev->procs.dev_spec_op == NULL || mdev->procs.dev_spec_op == gx_default_dev_spec_op) set_dev_proc(mdev, dev_spec_op, gdev_prn_dev_spec_op); #ifdef DEBUG /* scanning sources didn't show anything, but if a device gets changed or added */ /* that has its own dev_spec_op, it should call the gdev_prn_spec_op as well */ - else - errprintf(mdev->memory, "Warning: printer device has private dev_spec_op\n"); + else { + if (dev_proc(mdev, dev_spec_op)((gx_device *)mdev, gxdso_debug_printer_check, NULL, 0) < 0) + errprintf(mdev->memory, "Warning: printer device has private dev_spec_op\n"); + } #endif gx_device_fill_in_procs((gx_device *)mdev); } else { diff -Nru ghostscript-9.25~dfsg+1/base/gdevsclass.c ghostscript-9.26~dfsg+0/base/gdevsclass.c --- ghostscript-9.25~dfsg+1/base/gdevsclass.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevsclass.c 2018-11-20 09:59:43.000000000 +0000 @@ -99,13 +99,21 @@ */ int default_subclass_open_device(gx_device *dev) { - if (dev->child) { - dev_proc(dev->child, open_device)(dev->child); - dev->child->is_open = true; - gx_update_from_subclass(dev); - } + int code = 0; - return 0; + /* observed with Bug 699794, don't set is_open = true if the open_device failed */ + /* and make sure to propagate the return code from the child device to caller. */ + /* Only open the child if it was closed and if child open is OK, return 1. */ + /* (see gs_opendevice) */ + if (dev->child && dev->child->is_open == 0) { + code = dev_proc(dev->child, open_device)(dev->child); + if (code >= 0) { + dev->child->is_open = true; + code = 1; /* device had been closed, but now is open */ + } + gx_update_from_subclass(dev); /* this is probably safe to do even if the open failed */ + } + return code; } void default_subclass_get_initial_matrix(gx_device *dev, gs_matrix *pmat) @@ -784,12 +792,12 @@ return 0; } -int default_subclass_put_image(gx_device *dev, const byte **buffers, int num_chan, int x, int y, +int default_subclass_put_image(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y, int width, int height, int row_stride, int alpha_plane_index, int tag_plane_index) { if (dev->child) - return dev_proc(dev->child, put_image)(dev->child, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); + return dev_proc(dev->child, put_image)(dev->child, mdev, buffers, num_chan, x, y, width, height, row_stride, alpha_plane_index, tag_plane_index); return 0; } @@ -887,12 +895,25 @@ return 0; } +int default_subclass_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) +{ + if (dev->child) + return dev_proc(dev->child, transform_pixel_region)(dev->child, reason, data); + + return gs_error_unknownerror; +} + void default_subclass_finalize(const gs_memory_t *cmem, void *vptr) { gx_device * const dev = (gx_device *)vptr; generic_subclass_data *psubclass_data = (generic_subclass_data *)dev->subclass_data; (void)cmem; /* unused */ + discard(gs_closedevice(dev)); + + if (dev->finalize) + dev->finalize(dev); + if (psubclass_data) { gs_free_object(dev->memory->non_gc_memory, psubclass_data, "gx_epo_finalize(suclass data)"); dev->subclass_data = NULL; @@ -900,6 +921,9 @@ if (dev->child) { gs_free_object(dev->memory->stable_memory, dev->child, "free child device memory for subclassing device"); } + if (dev->stype_is_dynamic) + gs_free_const_object(dev->memory->non_gc_memory, dev->stype, + "default_subclass_finalize"); if (dev->parent) dev->parent->child = dev->child; if (dev->child) diff -Nru ghostscript-9.25~dfsg+1/base/gdevsclass.h ghostscript-9.26~dfsg+0/base/gdevsclass.h --- ghostscript-9.25~dfsg+1/base/gdevsclass.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gdevsclass.h 2018-11-20 09:59:43.000000000 +0000 @@ -101,6 +101,8 @@ dev_proc_strip_tile_rect_devn(default_subclass_strip_tile_rect_devn); dev_proc_copy_alpha_hl_color(default_subclass_copy_alpha_hl_color); dev_proc_process_page(default_subclass_process_page); +dev_proc_transform_pixel_region(default_subclass_transform_pixel_region); + void default_subclass_finalize(const gs_memory_t *cmem, void *vptr); #endif /* gdev_obj_filter_INCLUDED */ diff -Nru ghostscript-9.25~dfsg+1/base/gen_ordered.c ghostscript-9.26~dfsg+0/base/gen_ordered.c --- ghostscript-9.25~dfsg+1/base/gen_ordered.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gen_ordered.c 2018-11-20 09:59:43.000000000 +0000 @@ -105,8 +105,8 @@ int *locations; } htsc_dither_pos_t; -static void htsc_determine_cell_shape(double *x, double *y, double *v, double *u, - double *N, htsc_param_t params, void *mem); +static void htsc_determine_cell_shape(int *x, int *y, int *v, int *u, + int *N, htsc_param_t params, void *mem); static double htsc_spot_value(spottype_t spot_type, double x, double y); static int htsc_getpoint(htsc_dig_grid_t *dig_grid, int x, int y); static void htsc_setpoint(htsc_dig_grid_t *dig_grid, int x, int y, int value); @@ -171,8 +171,8 @@ int htsc_gen_ordered(htsc_param_t params, int *S, htsc_dig_grid_t *final_mask) { - double num_levels; - double x=0.0, y=0.0, v=0.0, u=0.0, N=0.0; + int num_levels; + int x=0, y=0, v=0, u=0, N=0; htsc_vertices_t vertices; htsc_vector_t bin_center; htsc_point_t one_index = { 0., 0. }; @@ -195,7 +195,7 @@ /* Figure out how many levels to dither across. */ if (params.targ_quant_spec) { - num_levels = ROUND((double) params.targ_quant / N); + num_levels = ROUND((double) params.targ_quant / (double)N); } else { num_levels = 1; } @@ -267,13 +267,13 @@ /* Make a warning about large requested quantization levels with no -s set */ if (params.targ_size == 1 && num_levels > 1) { - min_size = (int)ceil((double)params.targ_quant / N); + min_size = (int)ceil((double)params.targ_quant / (double)N); EPRINTF1(final_mask->memory, "To achieve %d quantization levels with the desired lpi,\n", params.targ_quant); EPRINTF1(final_mask->memory, "it is necessary to specify a SuperCellSize (-s) of at least %d.\n", min_size); EPRINTF(final_mask->memory, "Note that an even larger size may be needed to reduce pattern artifacts.\n"); EPRINTF(final_mask->memory, "Because no SuperCellSize was specified, the minimum possible size\n"); EPRINTF(final_mask->memory, "that can approximate the requested angle and lpi will be created\n"); - EPRINTF1(final_mask->memory, "with %d quantization levels.\n", (int) N); + EPRINTF1(final_mask->memory, "with %d quantization levels.\n", N); } /* Go ahead and fill up the super cell grid with our growth dot values */ @@ -292,10 +292,10 @@ /* Dont allow nonsense settings */ if (num_levels * N > super_cell.height * super_cell.width) { EPRINTF3(final_mask->memory, - "Notice, %3.0lf quantization levels not possible with super cell of %d by %d\n", + "Notice, %d quantization levels not possible with super cell of %d by %d\n", num_levels, super_cell.height, super_cell.width); - num_levels = ROUND((super_cell.height * super_cell.width) / N); - EPRINTF1(final_mask->memory, "Reducing dithering quantization to %3.0lf\n", + num_levels = ROUND((super_cell.height * super_cell.width) / (double)N); + EPRINTF1(final_mask->memory, "Reducing dithering quantization to %d\n", num_levels); EPRINTF1(final_mask->memory, "For an effective quantization of %d\n", super_cell.height * super_cell.width); @@ -326,12 +326,13 @@ double cost = val_a->value - val_b->value; /* If same value, use distance to center for decision */ - if (cost == 0) { - /* Don't think these should ever be the same due to tiling effect */ - return val_a->dist_to_center - val_b->dist_to_center; - } else { - return cost; - } + if (cost == 0) + cost = val_a->dist_to_center - val_b->dist_to_center; + if (cost == 0) + return 0; + if (cost < 0) + return -1; + return 1; } static int @@ -402,8 +403,8 @@ } static void -htsc_determine_cell_shape(double *x_out, double *y_out, double *v_out, - double *u_out, double *N_out, htsc_param_t params, void *mem) +htsc_determine_cell_shape(int *x_out, int *y_out, int *v_out, + int *u_out, int *N_out, htsc_param_t params, void *mem) { double x = 0., y = 0., v = 0., u = 0., N = 0.; double frac, scaled_x; @@ -660,11 +661,11 @@ x = x_use; } } - *x_out = x; - *y_out = y; - *v_out = v; - *u_out = u; - *N_out = N; + *x_out = (int)x; + *y_out = (int)y; + *v_out = (int)v; + *u_out = (int)u; + *N_out = (int)N; } static void @@ -1041,8 +1042,8 @@ min_vert_number = *H; } - a = ceil((float) target_size / (float) lcm_value); - b = ceil((float) target_size / (float) min_vert_number); + a = (int)ceil((float) target_size / (float) lcm_value); + b = (int)ceil((float) target_size / (float) min_vert_number); /* super_cell Size is b*min_vert_number by a*lcm_value create the large cell */ @@ -1267,7 +1268,7 @@ filter = (float*) ALLOC(mem, sizeof(float) * sizefilty * sizefiltx); if (filter == NULL) return -1; - create_2d_gauss_filter(filter, sizefiltx, sizefilty, sizefiltx, sizefilty); + create_2d_gauss_filter(filter, sizefiltx, sizefilty, (float)sizefiltx, (float)sizefilty); screen_blur = (float*)ALLOC(mem, sizeof(float) * num_cols * num_rows); if (screen_blur == NULL) { FREE(mem, filter); @@ -1284,8 +1285,8 @@ white_pos = 0; dist = (num_cols) * (num_cols) + (num_rows) * (num_rows); for (k = 0; k < num_dots; k++) { - curr_dist = (pos_y[k] - min_pos.y) * (pos_y[k] - min_pos.y) + - (pos_x[k] - min_pos.x) * (pos_x[k] - min_pos.x); + curr_dist = (pos_y[k] - (int)min_pos.y) * (pos_y[k] - (int)min_pos.y) + + (pos_x[k] - (int)min_pos.x) * (pos_x[k] - (int)min_pos.x); if (curr_dist < dist && screen_matrix[pos_x[k] + num_cols * pos_y[k]] == 0) { white_pos = k; @@ -1338,7 +1339,7 @@ filter = (float*) ALLOC(mem, sizeof(float) * sizefilty * sizefiltx); if (filter == NULL) return -1; - create_2d_gauss_filter(filter, sizefiltx, sizefilty, sizefiltx, sizefilty); + create_2d_gauss_filter(filter, sizefiltx, sizefilty, (float)sizefiltx, (float)sizefilty); screen_blur = (float*) ALLOC(mem, sizeof(float) * num_cols * num_rows); if (screen_blur == NULL) { FREE(mem, filter); @@ -1354,11 +1355,11 @@ #endif /* Find the closest on dot to the max position */ black_pos = 0; - dist = (pos_y[0] - max_pos.y) * (pos_y[0] - max_pos.y) + - (pos_x[0] - max_pos.x) * (pos_x[0] - max_pos.x); + dist = (pos_y[0] - (int)max_pos.y) * (pos_y[0] - (int)max_pos.y) + + (pos_x[0] - (int)max_pos.x) * (pos_x[0] - (int)max_pos.x); for ( k = 1; k < num_dots; k++) { - curr_dist = (pos_y[k] - max_pos.y) * (pos_y[k] - max_pos.y) + - (pos_x[k] - max_pos.x) * (pos_x[k] - max_pos.x); + curr_dist = (pos_y[k] - (int)max_pos.y) * (pos_y[k] - (int)max_pos.y) + + (pos_x[k] - (int)max_pos.x) * (pos_x[k] - (int)max_pos.x); if (curr_dist < dist && screen_matrix[pos_x[k] + num_cols * pos_y[k]] == 1) { black_pos = k; @@ -1372,11 +1373,11 @@ sizefilty, screen_blur, &max_val, &max_pos, &min_val, &min_pos); /* Find the closest OFF dot to the min position. */ white_pos = 0; - dist = (pos_y[0] - min_pos.y) * (pos_y[0] - min_pos.y) + - (pos_x[0] - min_pos.x) * (pos_x[0] - min_pos.x); + dist = (pos_y[0] - (int)min_pos.y) * (pos_y[0] - (int)min_pos.y) + + (pos_x[0] - (int)min_pos.x) * (pos_x[0] - (int)min_pos.x); for ( k = 1; k < num_dots; k++) { - curr_dist = (pos_y[k] - min_pos.y) * (pos_y[k] - min_pos.y) + - (pos_x[k] - min_pos.x) * (pos_x[k] - min_pos.x); + curr_dist = (pos_y[k] - (int)min_pos.y) * (pos_y[k] - (int)min_pos.y) + + (pos_x[k] - (int)min_pos.x) * (pos_x[k] - (int)min_pos.x); if (curr_dist < dist && screen_matrix[pos_x[k] + num_cols * pos_y[k]] == 0) { white_pos = k; @@ -1615,7 +1616,7 @@ goto out; } for (k = 0; k < N; k++) { - thresholds[N-1-k] = (k + 1) * step_size - (step_size / 2); + thresholds[N-1-k] = (int)((k + 1) * step_size - (step_size / 2)); } mag_offset = (double) (thresholds[0]-thresholds[1]) / (double) (num_levels+1); @@ -1688,9 +1689,9 @@ /* In case we have modulo of a negative number */ if (k_index < 0) k_index = k_index + width_supercell; - threshold_value = thresholds[val-1] + - mag_offset * dot_level_sort[h]; - if (threshold_value > MAXVAL) threshold_value = MAXVAL; + threshold_value = (int)(thresholds[val-1] + + mag_offset * dot_level_sort[h]); + if (threshold_value > MAXVAL) threshold_value = (int)MAXVAL; if (threshold_value < 0) threshold_value = 0; htsc_setpoint(final_mask,k_index,j_index,threshold_value); } diff -Nru ghostscript-9.25~dfsg+1/base/gp_mswin.c ghostscript-9.26~dfsg+0/base/gp_mswin.c --- ghostscript-9.25~dfsg+1/base/gp_mswin.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gp_mswin.c 2018-11-20 09:59:43.000000000 +0000 @@ -735,7 +735,7 @@ return file; } -int gp_stat(const char *path, struct _stat *buf) +int gp_stat(const char *path, struct _stat64 *buf) { int len = utf8_to_wchar(NULL, path); wchar_t *uni; @@ -747,7 +747,7 @@ if (uni == NULL) return -1; utf8_to_wchar(uni, path); - ret = _wstat(uni, buf); + ret = _wstat64(uni, buf); free(uni); return ret; } diff -Nru ghostscript-9.25~dfsg+1/base/gsdevice.c ghostscript-9.26~dfsg+0/base/gsdevice.c --- ghostscript-9.25~dfsg+1/base/gsdevice.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsdevice.c 2018-11-20 09:59:43.000000000 +0000 @@ -51,11 +51,11 @@ gx_device * const dev = (gx_device *)vptr; (void)cmem; /* unused */ + discard(gs_closedevice(dev)); + if (dev->icc_struct != NULL) { rc_decrement(dev->icc_struct, "gx_device_finalize(icc_profile)"); } - if (dev->finalize) - dev->finalize(dev); /* Deal with subclassed devices. Ordinarily these should not be a problem, we * will never see them, but if ths is a end of job restore we can end up @@ -71,7 +71,9 @@ dev->PageList = 0; } - discard(gs_closedevice(dev)); + if (dev->finalize) + dev->finalize(dev); + if (dev->stype_is_dynamic) gs_free_const_object(dev->memory->non_gc_memory, dev->stype, "gx_device_finalize"); @@ -498,7 +500,9 @@ if (libctx->io_device_table != NULL) { cmm_dev_profile_t *dev_profile; if (pgs->icc_manager->lab_profile == NULL) { /* pick one not set externally */ - gsicc_init_iccmanager(pgs); + code = gsicc_init_iccmanager(pgs); + if (code < 0) + return(code); } /* Also, if the device profile is not yet set then take care of that before we start filling pages, if we can */ @@ -691,8 +695,9 @@ gs_nulldevice(gs_gstate * pgs) { int code = 0; + gs_gstate *spgs; bool saveLockSafety = false; - if (pgs->device == 0 || !gx_device_is_null(pgs->device)) { + if (pgs->device == NULL || !gx_device_is_null(pgs->device)) { gx_device *ndev; code = gs_copydevice(&ndev, (const gx_device *)&gs_null_device, pgs->memory); @@ -718,9 +723,20 @@ set_dev_proc(ndev, get_profile, gx_default_get_profile); } - if ((code = gs_setdevice_no_erase(pgs, ndev)) < 0) + if (gs_setdevice_no_erase(pgs, ndev) < 0) { gs_free_object(pgs->memory, ndev, "gs_copydevice(device)"); - gs_currentdevice_inline(pgs)->LockSafetyParams = saveLockSafety; + /* We are out of options: find the device we installed in + the initial graphics state, and put that in place. + We just need something so we can end this job cleanly. + */ + spgs = pgs->saved; + while (spgs->saved) spgs = spgs->saved; + gs_currentdevice_inline(pgs) = gs_currentdevice_inline(spgs); + rc_increment(gs_currentdevice_inline(pgs)); + code = gs_note_error(gs_error_Fatal); + } + if (gs_currentdevice_inline(pgs) != NULL) + gs_currentdevice_inline(pgs)->LockSafetyParams = saveLockSafety; } return code; } diff -Nru ghostscript-9.25~dfsg+1/base/gsfcid2.c ghostscript-9.26~dfsg+0/base/gsfcid2.c --- ghostscript-9.25~dfsg+1/base/gsfcid2.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsfcid2.c 2018-11-20 09:59:43.000000000 +0000 @@ -84,7 +84,7 @@ uint segCount2; ulong endCount, startCount, idDelta, idRangeOffset, glyphIdArray; } gs_cmap_tt_16bit_format4_t; -gs_private_st_suffix_add1(st_cmap_tt_16bit_format4, gs_cmap_tt_16bit_format4_t, +gs_public_st_suffix_add1(st_cmap_tt_16bit_format4, gs_cmap_tt_16bit_format4_t, "gs_cmap_tt_16bit_format4_t", cmap_tt_16bit_format4_enum_ptrs, cmap_tt_16bit_format4_reloc_ptrs, st_cmap, font); diff -Nru ghostscript-9.25~dfsg+1/base/gsfcmap.c ghostscript-9.26~dfsg+0/base/gsfcmap.c --- ghostscript-9.25~dfsg+1/base/gsfcmap.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsfcmap.c 2018-11-20 09:59:43.000000000 +0000 @@ -32,7 +32,7 @@ /* GC descriptors */ public_st_cmap(); -gs_private_st_suffix_add0_local(st_cmap_identity, gs_cmap_identity_t, +gs_public_st_suffix_add0_local(st_cmap_identity, gs_cmap_identity_t, "gs_cmap_identity_t", cmap_ptrs, cmap_data, st_cmap); @@ -425,7 +425,7 @@ static const int gs_cmap_ToUnicode_code_bytes = 2; -gs_private_st_suffix_add0(st_cmap_ToUnicode, gs_cmap_ToUnicode_t, +gs_public_st_suffix_add0(st_cmap_ToUnicode, gs_cmap_ToUnicode_t, "gs_cmap_ToUnicode_t", cmap_ToUnicode_enum_ptrs, cmap_ToUnicode_reloc_ptrs, st_cmap); diff -Nru ghostscript-9.25~dfsg+1/base/gsfont.c ghostscript-9.26~dfsg+0/base/gsfont.c --- ghostscript-9.25~dfsg+1/base/gsfont.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsfont.c 2018-11-20 09:59:43.000000000 +0000 @@ -288,6 +288,10 @@ cmem->gs_lib_ctx->font_dir = NULL; } + /* free character cache machinery */ + gs_free_object(pdir->memory, pdir->fmcache.mdata, "gs_font_dir_finalize"); + gs_free_object(pdir->memory, pdir->ccache.table, "gs_font_dir_finalize"); + /* free the circular list of memory chunks */ while (chunk) { if (start_chunk == chunk->next) { @@ -304,7 +308,6 @@ pdir->ccache.chunks = NULL; } - /* Allocate and minimally initialize a font. */ gs_font * gs_font_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype, diff -Nru ghostscript-9.25~dfsg+1/base/gsfont.h ghostscript-9.26~dfsg+0/base/gsfont.h --- ghostscript-9.25~dfsg+1/base/gsfont.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsfont.h 2018-11-20 09:59:43.000000000 +0000 @@ -41,6 +41,8 @@ /* Initialization */ /* These procedures return 0 if they fail. */ +/* The returned gs_font_dir can be cleanly deallocated by + * simply calling gs_free_object on it. */ gs_font_dir *gs_font_dir_alloc2(gs_memory_t * struct_mem, gs_memory_t * bits_mem); gs_font_dir *gs_font_dir_alloc2_limits(gs_memory_t * struct_mem, diff -Nru ghostscript-9.25~dfsg+1/base/gsicc_cache.c ghostscript-9.26~dfsg+0/base/gsicc_cache.c --- ghostscript-9.25~dfsg+1/base/gsicc_cache.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsicc_cache.c 2018-11-20 09:59:43.000000000 +0000 @@ -644,6 +644,7 @@ { (*profile) = NULL; (*render_cond).rendering_intent = gsPERCEPTUAL; + (*render_cond).cmm = gsCMM_DEFAULT; switch (graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS) { case GS_UNKNOWN_TAG: case GS_UNTOUCHED_TAG: diff -Nru ghostscript-9.25~dfsg+1/base/gsicc_lcms2mt.c ghostscript-9.26~dfsg+0/base/gsicc_lcms2mt.c --- ghostscript-9.25~dfsg+1/base/gsicc_lcms2mt.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsicc_lcms2mt.c 2018-11-20 09:59:43.000000000 +0000 @@ -313,8 +313,8 @@ { cmsContext ctx = gs_lib_ctx_get_cms_context(mem); - cmsSetLogErrorHandlerTHR(ctx, gscms_error); - return cmsOpenProfileFromMemTHR(ctx,buffer,input_size); + cmsSetLogErrorHandler(ctx, gscms_error); + return cmsOpenProfileFromMem(ctx,buffer,input_size); } /* Get ICC Profile handle from file ptr */ @@ -323,7 +323,7 @@ { cmsContext ctx = gs_lib_ctx_get_cms_context(mem); - return cmsOpenProfileFromFileTHR(ctx, filename, "r"); + return cmsOpenProfileFromFile(ctx, filename, "r"); } /* Transform an entire buffer */ @@ -735,7 +735,7 @@ "gscms_transform_color_buffer"); if (link_handle == NULL) return NULL; - link_handle->hTransform = cmsCreateTransformTHR(ctx, lcms_srchandle, src_data_type, + link_handle->hTransform = cmsCreateTransform(ctx, lcms_srchandle, src_data_type, lcms_deshandle, des_data_type, rendering_params->rendering_intent, flag | cmm_flags); @@ -853,7 +853,7 @@ } /* Use relative colorimetric here */ - link_handle->hTransform = cmsCreateMultiprofileTransformTHR(ctx, + link_handle->hTransform = cmsCreateMultiprofileTransform(ctx, hProfiles, nProfiles, src_data_type, des_data_type, gsRELATIVECOLORIMETRIC, flag); cmsCloseProfile(ctx, src_to_proof); @@ -912,7 +912,7 @@ || rendering_params->black_point_comp == gsBLACKPTCOMP_ON_OR) { flag = (flag | cmsFLAGS_BLACKPOINTCOMPENSATION); } - link_handle->hTransform = cmsCreateMultiprofileTransformTHR(ctx, + link_handle->hTransform = cmsCreateMultiprofileTransform(ctx, hProfiles, nProfiles, src_data_type, des_data_type, rendering_params->rendering_intent, flag); } @@ -935,10 +935,10 @@ return_error(gs_error_VMerror); #ifdef USE_LCMS2_LOCKING - cmsPluginTHR(ctx, (void *)&gs_cms_mutexhandler); + cmsPlugin(ctx, (void *)&gs_cms_mutexhandler); #endif - cmsSetLogErrorHandlerTHR(ctx, gscms_error); + cmsSetLogErrorHandler(ctx, gscms_error); gs_lib_ctx_set_cms_context(memory, ctx); return 0; } @@ -1058,7 +1058,7 @@ /* Create the transform */ /* ToDo: Adjust rendering intent */ - hTransform = cmsCreateProofingTransformTHR(ctx, + hTransform = cmsCreateProofingTransform(ctx, lcms_srchandle, TYPE_NAMED_COLOR_INDEX, lcms_deshandle, TYPE_CMYK_8, lcms_proofhandle,INTENT_PERCEPTUAL, diff -Nru ghostscript-9.25~dfsg+1/base/gsicc_manage.c ghostscript-9.26~dfsg+0/base/gsicc_manage.c --- ghostscript-9.25~dfsg+1/base/gsicc_manage.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsicc_manage.c 2018-11-20 09:59:43.000000000 +0000 @@ -3010,7 +3010,7 @@ pval->persistent = true; } else { pval->data = (byte *)pgs->icc_manager->srcgtag_profile->name; - pval->size = strlen((const char *)pval->data); + pval->size = pgs->icc_manager->srcgtag_profile->name_length; pval->persistent = false; } } diff -Nru ghostscript-9.25~dfsg+1/base/gsptype1.c ghostscript-9.26~dfsg+0/base/gsptype1.c --- ghostscript-9.25~dfsg+1/base/gsptype1.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsptype1.c 2018-11-20 09:59:43.000000000 +0000 @@ -50,7 +50,7 @@ /* GC descriptors */ private_st_pattern1_template(); -private_st_pattern1_instance(); +public_st_pattern1_instance(); /* GC procedures */ static ENUM_PTRS_BEGIN(pattern1_instance_enum_ptrs) { diff -Nru ghostscript-9.25~dfsg+1/base/gsptype2.c ghostscript-9.26~dfsg+0/base/gsptype2.c --- ghostscript-9.25~dfsg+1/base/gsptype2.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsptype2.c 2018-11-20 09:59:43.000000000 +0000 @@ -33,7 +33,7 @@ /* GC descriptors */ private_st_pattern2_template(); -private_st_pattern2_instance(); +public_st_pattern2_instance(); /* GC procedures */ static ENUM_PTRS_BEGIN(pattern2_instance_enum_ptrs) { @@ -206,10 +206,10 @@ pinst->saved->overprint_mode = pgs->overprint_mode; pinst->saved->overprint = pgs->overprint; - + num_comps = pgs->device->color_info.num_components; for (k = 0; k < num_comps; k++) { - pgs->color_component_map.color_map[k] = + pgs->color_component_map.color_map[k] = pinst->saved->color_component_map.color_map[k]; } code = pcs->type->set_overprint(pcs, pgs); diff -Nru ghostscript-9.25~dfsg+1/base/gsptype2.h ghostscript-9.26~dfsg+0/base/gsptype2.h --- ghostscript-9.25~dfsg+1/base/gsptype2.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gsptype2.h 2018-11-20 09:59:43.000000000 +0000 @@ -57,8 +57,8 @@ bool shfill; } gs_pattern2_instance_t; -#define private_st_pattern2_instance() /* in gsptype2.c */\ - gs_private_st_composite(st_pattern2_instance, gs_pattern2_instance_t,\ +#define public_st_pattern2_instance() /* in gsptype2.c */\ + gs_public_st_composite(st_pattern2_instance, gs_pattern2_instance_t,\ "gs_pattern2_instance_t", pattern2_instance_enum_ptrs,\ pattern2_instance_reloc_ptrs) diff -Nru ghostscript-9.25~dfsg+1/base/gxblend1.c ghostscript-9.26~dfsg+0/base/gxblend1.c --- ghostscript-9.25~dfsg+1/base/gxblend1.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxblend1.c 2018-11-20 09:59:43.000000000 +0000 @@ -722,9 +722,8 @@ input_map[num_known_comp++] = comp_num + 4; } } - /* See if the target device has a put_image command. If - yes then see if it can handle the image data directly. */ - if (target->procs.put_image != gx_default_put_image) { + + { /* See if the target device can handle the data in its current form with the alpha component */ int alpha_offset = num_comp; @@ -733,7 +732,7 @@ int i; for (i = 0; i < num_comp; i++) buf_ptrs[i] = buf_ptr + i * planestride; - code = dev_proc(target, put_image) (target, buf_ptrs, num_comp, + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, rect.p.x, rect.p.y, width, height, rowstride, num_comp,tag_offset); @@ -758,7 +757,7 @@ #endif /* Try again now */ alpha_offset = 0; - code = dev_proc(target, put_image) (target, buf_ptrs, num_comp, + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, rect.p.x, rect.p.y, width, height, rowstride, alpha_offset, tag_offset); @@ -767,7 +766,7 @@ /* We processed some or all of the rows. Continue until we are done */ num_rows_left = height - code; while (num_rows_left > 0) { - code = dev_proc(target, put_image) (target, buf_ptrs, num_comp, + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, rect.p.x, rect.p.y+code, width, num_rows_left, rowstride, alpha_offset, tag_offset); diff -Nru ghostscript-9.25~dfsg+1/base/gxclip.c ghostscript-9.26~dfsg+0/base/gxclip.c --- ghostscript-9.25~dfsg+1/base/gxclip.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxclip.c 2018-11-20 09:59:43.000000000 +0000 @@ -46,6 +46,7 @@ static dev_proc_get_clipping_box(clip_get_clipping_box); static dev_proc_get_bits_rectangle(clip_get_bits_rectangle); static dev_proc_fill_path(clip_fill_path); +static dev_proc_transform_pixel_region(clip_transform_pixel_region); /* The device descriptor. */ static const gx_device_clip gs_clip_device = @@ -122,7 +123,9 @@ gx_forward_set_graphics_type_tag, clip_strip_copy_rop2, clip_strip_tile_rect_devn, - clip_copy_alpha_hl_color + clip_copy_alpha_hl_color, + NULL, + clip_transform_pixel_region } }; @@ -1541,3 +1544,68 @@ fixed2int(box.q.y - box.p.y), clip_call_fill_path, &ccdata); } + +typedef struct { + int use_default; + void *child_state; +} clip_transform_pixel_region_data; + +static int +clip_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) +{ + clip_transform_pixel_region_data *state = (clip_transform_pixel_region_data *)data->state; + gx_device_clip *cdev = (gx_device_clip *)dev; + transform_pixel_region_data local_data; + gs_int_rect local_clip; + int ret; + + if (reason == transform_pixel_region_begin) { + int skewed = 1; + if (data->u.init.pixels->y.step.dQ == 0 && data->u.init.pixels->y.step.dR == 0 && + data->u.init.rows->x.step.dQ == 0 && data->u.init.rows->x.step.dR == 0) + skewed = 0; + else if (data->u.init.pixels->x.step.dQ == 0 && data->u.init.pixels->x.step.dR == 0 && + data->u.init.rows->y.step.dQ == 0 && data->u.init.rows->y.step.dR == 0) + skewed = 0; + state = (clip_transform_pixel_region_data *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(*state), "clip_transform_pixel_region_data"); + if (state == NULL) + return gs_error_VMerror; + local_data = *data; + if (cdev->list.count == 1 && skewed == 0) { + /* Single unskewed rectangle - we can use the underlying device direct */ + local_data.u.init.clip = &local_clip; + local_clip = *data->u.init.clip; + if (local_clip.p.x < cdev->current->xmin) + local_clip.p.x = cdev->current->xmin; + if (local_clip.q.x > cdev->current->xmax) + local_clip.q.x = cdev->current->xmax; + if (local_clip.p.y < cdev->current->ymin) + local_clip.p.y = cdev->current->ymin; + if (local_clip.q.y > cdev->current->ymax) + local_clip.q.y = cdev->current->ymax; + state->use_default = 0; + ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, &local_data); + } else { + /* Multiple rectangles - we need to use the default */ + state->use_default = 1; + ret = gx_default_transform_pixel_region(dev, reason, &local_data); + } + state->child_state = local_data.state; + data->state = state; + return ret; + } + + data->state = state->child_state; + if (state->use_default) + ret = gx_default_transform_pixel_region(dev, reason, data); + else + ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, data); + + if (reason == transform_pixel_region_end) { + gs_free_object(dev->memory->non_gc_memory, state, "clip_transform_pixel_region_data"); + state = NULL; + } + data->state = state; + + return ret; +} diff -Nru ghostscript-9.25~dfsg+1/base/gxclipm.c ghostscript-9.26~dfsg+0/base/gxclipm.c --- ghostscript-9.25~dfsg+1/base/gxclipm.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxclipm.c 2018-11-20 09:59:43.000000000 +0000 @@ -111,7 +111,9 @@ gx_forward_set_graphics_type_tag, mask_clip_strip_copy_rop2, mask_clip_strip_tile_rect_devn, - mask_clip_copy_alpha_hl_color + mask_clip_copy_alpha_hl_color, + NULL, + gx_default_transform_pixel_region } }; diff -Nru ghostscript-9.25~dfsg+1/base/gxclist.c ghostscript-9.26~dfsg+0/base/gxclist.c --- ghostscript-9.25~dfsg+1/base/gxclist.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxclist.c 2018-11-20 09:59:43.000000000 +0000 @@ -203,6 +203,7 @@ clist_strip_tile_rect_devn, clist_copy_alpha_hl_color, clist_process_page, + gx_default_transform_pixel_region }; /*------------------- Choose the implementation ----------------------- diff -Nru ghostscript-9.25~dfsg+1/base/gxclrast.c ghostscript-9.26~dfsg+0/base/gxclrast.c --- ghostscript-9.25~dfsg+1/base/gxclrast.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxclrast.c 2018-11-20 09:59:43.000000000 +0000 @@ -2434,7 +2434,7 @@ cmd_getw(index, cbp); cmd_getw(offset, cbp); - if_debug2m('L', mem, " index=%d offset=%lu\n", pcls->tile_index, offset); + if_debug2m('L', mem, " index=%d offset=%lu\n", index, offset); pcls->tile_index = index; cdev->tile_table[pcls->tile_index].offset = offset; slot = (tile_slot *)(cdev->cache_chunk->data + offset); diff -Nru ghostscript-9.25~dfsg+1/base/gxcmap.c ghostscript-9.26~dfsg+0/base/gxcmap.c --- ghostscript-9.25~dfsg+1/base/gxcmap.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxcmap.c 2018-11-20 09:59:43.000000000 +0000 @@ -1136,8 +1136,6 @@ } /* if output device supports devn, we need to make sure we send it the proper color type */ - /* if output device supports devn, we need to make sure we send it the - proper color type */ if (dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0)) { for (i = 0; i < ncomps; i++) pdc->colors.devn.values[i] = frac2cv(cm_comps[i]); @@ -1998,7 +1996,7 @@ } static void -cmapper_transfer_halftone_add(gx_cmapper_data *data) +cmapper_transfer_halftone_add(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; const gs_gstate * pgs = data->pgs; @@ -2021,7 +2019,7 @@ } static void -cmapper_transfer_halftone_op(gx_cmapper_data *data) +cmapper_transfer_halftone_op(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; const gs_gstate * pgs = data->pgs; @@ -2050,7 +2048,7 @@ } static void -cmapper_transfer_halftone_sub(gx_cmapper_data *data) +cmapper_transfer_halftone_sub(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; const gs_gstate * pgs = data->pgs; @@ -2074,7 +2072,7 @@ } static void -cmapper_transfer_add(gx_cmapper_data *data) +cmapper_transfer_add(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; const gs_gstate * pgs = data->pgs; @@ -2099,7 +2097,7 @@ } static void -cmapper_transfer_op(gx_cmapper_data *data) +cmapper_transfer_op(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; const gs_gstate * pgs = data->pgs; @@ -2121,7 +2119,7 @@ } static void -cmapper_transfer_sub(gx_cmapper_data *data) +cmapper_transfer_sub(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; const gs_gstate * pgs = data->pgs; @@ -2150,7 +2148,7 @@ during an ICC color flow. In this case, the color is already in the device color space but in 16bpp color values. */ static void -cmapper_halftone(gx_cmapper_data *data) +cmapper_halftone(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; const gs_gstate * pgs = data->pgs; @@ -2174,7 +2172,7 @@ during an ICC color flow. In this case, the color is already in the device color space but in 16bpp color values. */ static void -cmapper_vanilla(gx_cmapper_data *data) +cmapper_vanilla(gx_cmapper_t *data) { gx_color_value *pconc = &data->conc[0]; gx_device * dev = data->dev; @@ -2186,8 +2184,8 @@ color_set_pure(&data->devc, color); } -gx_cmapper_fn * -gx_get_cmapper(gx_cmapper_data *data, const gs_gstate *pgs, +void +gx_get_cmapper(gx_cmapper_t *data, const gs_gstate *pgs, gx_device *dev, bool has_transfer, bool has_halftone, gs_color_select_t select) { @@ -2196,6 +2194,7 @@ data->dev = dev; data->select = select; data->devc.type = gx_dc_type_none; + data->direct = 0; if (has_transfer && dev->color_info.opmode == GX_CINFO_OPMODE_UNKNOWN) check_cmyk_color_model_comps(dev); if (pgs->effective_transfer_non_identity_count == 0) @@ -2220,10 +2219,11 @@ } else { if (has_halftone) data->set_color = cmapper_halftone; - else + else { data->set_color = cmapper_vanilla; + data->direct = 1; + } } - return data->set_color; } /* This is used by image color render to handle the cases where we need to diff -Nru ghostscript-9.25~dfsg+1/base/gxcmap.h ghostscript-9.26~dfsg+0/base/gxcmap.h --- ghostscript-9.25~dfsg+1/base/gxcmap.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxcmap.h 2018-11-20 09:59:43.000000000 +0000 @@ -281,21 +281,22 @@ void cmap_transfer_plane(gx_color_value *pconc, const gs_gstate *pgs, gx_device *dev, int plane); -typedef struct gx_cmapper_data_s gx_cmapper_data; +typedef struct gx_cmapper_s gx_cmapper_t; -typedef void (gx_cmapper_fn)(gx_cmapper_data *data); +typedef void (gx_cmapper_fn)(gx_cmapper_t *cmapper); -struct gx_cmapper_data_s { +struct gx_cmapper_s { gx_color_value conc[GX_DEVICE_COLOR_MAX_COMPONENTS]; const gs_gstate *pgs; gx_device *dev; gs_color_select_t select; gx_device_color devc; gx_cmapper_fn *set_color; + int direct; }; -gx_cmapper_fn *gx_get_cmapper(gx_cmapper_data *data, const gs_gstate *pgs, - gx_device *dev, bool has_transfer, bool has_halftone, - gs_color_select_t select); +void gx_get_cmapper(gx_cmapper_t *cmapper, const gs_gstate *pgs, + gx_device *dev, bool has_transfer, bool has_halftone, + gs_color_select_t select); #endif /* gxcmap_INCLUDED */ diff -Nru ghostscript-9.25~dfsg+1/base/gxcolor2.h ghostscript-9.26~dfsg+0/base/gxcolor2.h --- ghostscript-9.25~dfsg+1/base/gxcolor2.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxcolor2.h 2018-11-20 09:59:43.000000000 +0000 @@ -92,8 +92,8 @@ gx_bitmap_id id; /* key for cached bitmap (= id of mask) */ }; -#define private_st_pattern1_instance() /* in gsptype1.c */\ - gs_private_st_composite(st_pattern1_instance, gs_pattern1_instance_t,\ +#define public_st_pattern1_instance() /* in gsptype1.c */\ + gs_public_st_composite(st_pattern1_instance, gs_pattern1_instance_t,\ "gs_pattern1_instance_t", pattern1_instance_enum_ptrs,\ pattern1_instance_reloc_ptrs) diff -Nru ghostscript-9.25~dfsg+1/base/gxdevcli.h ghostscript-9.26~dfsg+0/base/gxdevcli.h --- ghostscript-9.25~dfsg+1/base/gxdevcli.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxdevcli.h 2018-11-20 09:59:43.000000000 +0000 @@ -40,6 +40,7 @@ #include "gp.h" #include "gscms.h" #include "gxrplane.h" +#include "gxdda.h" /* See Drivers.htm for documentation of the driver interface. */ @@ -1514,7 +1515,7 @@ dev_t_proc_pop_transparency_state(proc, gx_device) #define dev_t_proc_put_image(proc, dev_t)\ - int proc(gx_device *dev, const byte **buffers, int num_chan, int x, int y,\ + int proc(gx_device *dev, gx_device *mdev, const byte **buffers, int num_chan, int x, int y,\ int width, int height, int row_stride,\ int alpha_plane_index, int tag_plane_index) #define dev_proc_put_image(proc)\ @@ -1589,6 +1590,40 @@ #define dev_proc_process_page(proc)\ dev_t_proc_process_page(proc, gx_device) +typedef enum { + transform_pixel_region_begin = 0, + transform_pixel_region_data_needed = 1, + transform_pixel_region_process_data = 2, + transform_pixel_region_end = 3 +} transform_pixel_region_reason; + +typedef struct { + void *state; + union { + struct { + const gs_int_rect *clip; + int w; /* source width */ + int h; /* source height */ + int spp; + const gx_dda_fixed_point *pixels; /* DDA to enumerate the destination positions of pixels across a row */ + const gx_dda_fixed_point *rows; /* DDA to enumerate the starting position of each row */ + gs_logical_operation_t lop; + } init; + struct { + const unsigned char *buffer[GX_DEVICE_COLOR_MAX_COMPONENTS]; + int data_x; + gx_cmapper_t *cmapper; + const gs_gstate *pgs; + } process_data; + } u; +} transform_pixel_region_data; + +#define dev_t_proc_transform_pixel_region(proc, dev_t)\ + int proc(dev_t *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) +#define dev_proc_transform_pixel_region(proc)\ + dev_t_proc_transform_pixel_region(proc, gx_device) + + /* Define the device procedure vector template proper. */ #define gx_device_proc_struct(dev_t)\ @@ -1665,6 +1700,7 @@ dev_t_proc_strip_tile_rect_devn((*strip_tile_rect_devn), dev_t);\ dev_t_proc_copy_alpha_hl_color((*copy_alpha_hl_color), dev_t);\ dev_t_proc_process_page((*process_page), dev_t);\ + dev_t_proc_transform_pixel_region((*transform_pixel_region), dev_t);\ } /* diff -Nru ghostscript-9.25~dfsg+1/base/gxdevice.h ghostscript-9.26~dfsg+0/base/gxdevice.h --- ghostscript-9.25~dfsg+1/base/gxdevice.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxdevice.h 2018-11-20 09:59:43.000000000 +0000 @@ -313,6 +313,7 @@ dev_proc_strip_tile_rect_devn(gx_default_strip_tile_rect_devn); dev_proc_copy_alpha_hl_color(gx_default_copy_alpha_hl_color); dev_proc_process_page(gx_default_process_page); +dev_proc_transform_pixel_region(gx_default_transform_pixel_region); dev_proc_begin_transparency_group(gx_default_begin_transparency_group); dev_proc_end_transparency_group(gx_default_end_transparency_group); dev_proc_begin_transparency_mask(gx_default_begin_transparency_mask); @@ -408,6 +409,7 @@ dev_proc_update_spot_equivalent_colors(gx_forward_update_spot_equivalent_colors); dev_proc_ret_devn_params(gx_forward_ret_devn_params); dev_proc_fillpage(gx_forward_fillpage); +dev_proc_put_image(gx_forward_put_image); dev_proc_copy_planes(gx_forward_copy_planes); dev_proc_create_compositor(gx_forward_create_compositor); dev_proc_get_profile(gx_forward_get_profile); @@ -415,6 +417,7 @@ dev_proc_strip_copy_rop2(gx_forward_strip_copy_rop2); dev_proc_strip_tile_rect_devn(gx_forward_strip_tile_rect_devn); dev_proc_copy_alpha_hl_color(gx_forward_copy_alpha_hl_color); +dev_proc_transform_pixel_region(gx_forward_transform_pixel_region); /* ---------------- Implementation utilities ---------------- */ int gx_default_get_param(gx_device *dev, char *Param, void *list); diff -Nru ghostscript-9.25~dfsg+1/base/gxdevsop.h ghostscript-9.26~dfsg+0/base/gxdevsop.h --- ghostscript-9.25~dfsg+1/base/gxdevsop.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxdevsop.h 2018-11-20 09:59:43.000000000 +0000 @@ -327,6 +327,18 @@ gxdso_JPEG_passthrough_data, gxdso_JPEG_passthrough_end, gxdso_supports_iccpostrender, + /* Retrieve the last device in a device chain + (either forwarding or subclass devices). + */ + gxdso_current_output_device, + /* Should we call copy_color rather than resolving images to fill_rectangles? */ + gxdso_copy_color_is_fast, + + /* Debug only dsos follow here */ +#ifdef DEBUG + /* Private dso used to check that a printer device properly forwards to the default */ + gxdso_debug_printer_check, +#endif /* Add new gxdso_ keys above this. */ gxdso_pattern__LAST }; diff -Nru ghostscript-9.25~dfsg+1/base/gxdownscale.c ghostscript-9.26~dfsg+0/base/gxdownscale.c --- ghostscript-9.25~dfsg+1/base/gxdownscale.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxdownscale.c 2018-11-20 09:59:43.000000000 +0000 @@ -1682,18 +1682,6 @@ static int check_trapping(gs_memory_t *memory, int trap_w, int trap_h, int num_comps, const int *comp_order) { -#ifndef ENABLE_TRAPPING - if (trap_w > 0 || trap_h > 0) - { - dmprintf(memory, - "Trapping is disabled in this build. To enable trapping,\n" - "follow the instructions in the documentation. Please note\n" - "that if you do this, you are responsible for ensuring that\n" - "you have any and all patent licenses that may be required.\n"); - return_error(gs_error_rangecheck); - } -#endif - if (trap_w < 0 || trap_h < 0) { dmprintf(memory, "Trapping range must be >= 0"); diff -Nru ghostscript-9.25~dfsg+1/base/gxgstate.h ghostscript-9.26~dfsg+0/base/gxgstate.h --- ghostscript-9.25~dfsg+1/base/gxgstate.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxgstate.h 2018-11-20 09:59:43.000000000 +0000 @@ -502,9 +502,9 @@ /* Also make sure the tag is set in the device so the two remain in sync. */ static inline void ensure_tag_is_set(gs_gstate *pgs, gx_device *dev, gs_graphics_type_tag_t tag) { + if ((dev->graphics_type_tag & tag) == 0) + dev_proc(dev, set_graphics_type_tag)(dev, tag); if (device_encodes_tags(dev)) { - if ((dev->graphics_type_tag & tag) == 0) - dev_proc(dev, set_graphics_type_tag)(dev, tag); if ((pgs->color[0].dev_color->tag & tag) == 0) { gx_unset_dev_color(pgs); /* current dev_color needs update to new tag */ pgs->color[0].dev_color->tag = tag; /* after unset, now set it */ diff -Nru ghostscript-9.25~dfsg+1/base/gxi12bit.c ghostscript-9.26~dfsg+0/base/gxi12bit.c --- ghostscript-9.25~dfsg+1/base/gxi12bit.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxi12bit.c 2018-11-20 09:59:43.000000000 +0000 @@ -602,8 +602,8 @@ bool has_transfer = penum->icc_setup.has_transfer; int num_des_comps; cmm_dev_profile_t *dev_profile; - gx_cmapper_data data; - gx_cmapper_fn *mapper = gx_get_cmapper(&data, pgs, dev, has_transfer, must_halftone, gs_color_select_source); + gx_cmapper_t data; + gx_cmapper_fn *mapper; gx_color_value *conc = &data.conc[0]; if (h == 0) @@ -612,6 +612,8 @@ if (penum->icc_link == NULL) { return gs_rethrow(-1, "ICC Link not created during image render icc16"); } + gx_get_cmapper(&data, pgs, dev, has_transfer, must_halftone, gs_color_select_source); + mapper = data.set_color; /* Needed for device N */ code = dev_proc(dev, get_profile)(dev, &dev_profile); num_des_comps = gsicc_get_device_profile_comps(dev_profile); diff -Nru ghostscript-9.25~dfsg+1/base/gxicolor.c ghostscript-9.26~dfsg+0/base/gxicolor.c --- ghostscript-9.25~dfsg+1/base/gxicolor.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxicolor.c 2018-11-20 09:59:43.000000000 +0000 @@ -58,11 +58,11 @@ iclass_proc(gs_image_class_4_color); static irender_proc(image_render_color_DeviceN); -static irender_proc(image_render_color_icc_portrait); -static irender_proc(image_render_color_icc_landscape); -static irender_proc(image_render_color_icc_skew); +static irender_proc(image_render_color_icc_tpr); static irender_proc(image_render_color_thresh); +static int image_skip_color_icc_tpr(gx_image_enum *penum, gx_device *dev); + irender_proc_t gs_image_class_4_color(gx_image_enum * penum) { @@ -73,6 +73,12 @@ #else bool use_fast_thresh = false; #endif + const gs_color_space *pcs; + gsicc_rendering_param_t rendering_params; + int k; + int src_num_comp = cs_num_components(penum->pcs); + int des_num_comp, bpc; + cmm_dev_profile_t *dev_profile; if (penum->use_mask_color) { /* @@ -114,95 +120,110 @@ penum->pcs->cmm_icc_profile_data == NULL) || penum->use_mask_color || !std_cmap_procs) { return &image_render_color_DeviceN; - } else { - /* Set up the link now */ - const gs_color_space *pcs; - gsicc_rendering_param_t rendering_params; - int k; - int src_num_comp = cs_num_components(penum->pcs); - int des_num_comp, bpc; - cmm_dev_profile_t *dev_profile; - - code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile); - if (code < 0) - return NULL; /* This function does not return errors, best we can do is say 'we can't handle this' */ + } - des_num_comp = gsicc_get_device_profile_comps(dev_profile); - bpc = penum->dev->color_info.depth / des_num_comp; /* bits per component */ + /* Set up the link now */ + code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile); + if (code < 0) + return NULL; /* This function does not return errors, best we can do is say 'we can't handle this' */ + + des_num_comp = gsicc_get_device_profile_comps(dev_profile); + bpc = penum->dev->color_info.depth / des_num_comp; /* bits per component */ + penum->icc_setup.need_decode = false; + /* Check if we need to do any decoding. If yes, then that will slow us down */ + for (k = 0; k < src_num_comp; k++) { + if ( penum->map[k].decoding != sd_none ) { + penum->icc_setup.need_decode = true; + break; + } + } + /* Define the rendering intents */ + rendering_params.black_point_comp = penum->pgs->blackptcomp; + rendering_params.graphics_type_tag = GS_IMAGE_TAG; + rendering_params.override_icc = false; + rendering_params.preserve_black = gsBKPRESNOTSPECIFIED; + rendering_params.rendering_intent = penum->pgs->renderingintent; + rendering_params.cmm = gsCMM_DEFAULT; + if (gs_color_space_is_PSCIE(penum->pcs) && penum->pcs->icc_equivalent != NULL) { + pcs = penum->pcs->icc_equivalent; + } else { + pcs = penum->pcs; + } + penum->icc_setup.is_lab = pcs->cmm_icc_profile_data->islab; + penum->icc_setup.must_halftone = gx_device_must_halftone(penum->dev); + penum->icc_setup.has_transfer = gx_has_transfer(penum->pgs, des_num_comp); + if (penum->icc_setup.is_lab) penum->icc_setup.need_decode = false; - /* Check if we need to do any decoding. If yes, then that will slow us down */ - for (k = 0; k < src_num_comp; k++) { - if ( penum->map[k].decoding != sd_none ) { - penum->icc_setup.need_decode = true; + if (penum->icc_link == NULL) { + penum->icc_link = gsicc_get_link(penum->pgs, penum->dev, pcs, NULL, + &rendering_params, penum->memory); + } + /* PS CIE color spaces may have addition decoding that needs to + be performed to ensure that the range of 0 to 1 is provided + to the CMM since ICC profiles are restricted to that range + but the PS color spaces are not. */ + penum->use_cie_range = false; + if (gs_color_space_is_PSCIE(penum->pcs) && + penum->pcs->icc_equivalent != NULL) { + /* We have a PS CIE space. Check the range */ + if ( !check_cie_range(penum->pcs) ) { + /* It is not 0 to 1. We will be doing decode + plus an additional linear adjustment */ + penum->use_cie_range = (get_cie_range(penum->pcs) != NULL); + } + } + if (gx_device_must_halftone(penum->dev) && use_fast_thresh && + (penum->posture == image_portrait || penum->posture == image_landscape) + && penum->image_parent_type == gs_image_type1) { + bool transfer_is_monotonic = true; + + for (k=0; kpgs, k)) { + transfer_is_monotonic = false; break; } } - /* Define the rendering intents */ - rendering_params.black_point_comp = penum->pgs->blackptcomp; - rendering_params.graphics_type_tag = GS_IMAGE_TAG; - rendering_params.override_icc = false; - rendering_params.preserve_black = gsBKPRESNOTSPECIFIED; - rendering_params.rendering_intent = penum->pgs->renderingintent; - rendering_params.cmm = gsCMM_DEFAULT; - if (gs_color_space_is_PSCIE(penum->pcs) && penum->pcs->icc_equivalent != NULL) { - pcs = penum->pcs->icc_equivalent; - } else { - pcs = penum->pcs; - } - penum->icc_setup.is_lab = pcs->cmm_icc_profile_data->islab; - penum->icc_setup.must_halftone = gx_device_must_halftone(penum->dev); - penum->icc_setup.has_transfer = gx_has_transfer(penum->pgs, des_num_comp); - if (penum->icc_setup.is_lab) - penum->icc_setup.need_decode = false; - if (penum->icc_link == NULL) { - penum->icc_link = gsicc_get_link(penum->pgs, penum->dev, pcs, NULL, - &rendering_params, penum->memory); - } - /* PS CIE color spaces may have addition decoding that needs to - be performed to ensure that the range of 0 to 1 is provided - to the CMM since ICC profiles are restricted to that range - but the PS color spaces are not. */ - penum->use_cie_range = false; - if (gs_color_space_is_PSCIE(penum->pcs) && - penum->pcs->icc_equivalent != NULL) { - /* We have a PS CIE space. Check the range */ - if ( !check_cie_range(penum->pcs) ) { - /* It is not 0 to 1. We will be doing decode - plus an additional linear adjustment */ - penum->use_cie_range = (get_cie_range(penum->pcs) != NULL); + /* If num components is 1 or if we are going to CMYK planar device + then we will may use the thresholding if it is a halftone + device IFF we have one bit per component */ + if ((bpc == 1) && transfer_is_monotonic && + (penum->dev->color_info.num_components == 1 || penum->dev->is_planar) && + penum->bps == 8) { + code = gxht_thresh_image_init(penum); + if (code == 0) { + /* NB: transfer function is pickled into the threshold arrray */ + penum->icc_setup.has_transfer = false; + return &image_render_color_thresh; } } - if (gx_device_must_halftone(penum->dev) && use_fast_thresh && - (penum->posture == image_portrait || penum->posture == image_landscape) - && penum->image_parent_type == gs_image_type1) { - bool transfer_is_monotonic = true; - - for (k=0; kpgs, k)) { - transfer_is_monotonic = false; - break; - } - } - /* If num components is 1 or if we are going to CMYK planar device - then we will may use the thresholding if it is a halftone - device IFF we have one bit per component */ - if ((bpc == 1) && transfer_is_monotonic && - (penum->dev->color_info.num_components == 1 || penum->dev->is_planar) && - penum->bps == 8) { - code = gxht_thresh_image_init(penum); - if (code == 0) { - /* NB: transfer function is pickled into the threshold arrray */ - penum->icc_setup.has_transfer = false; - return &image_render_color_thresh; - } - } + } + { + gs_int_rect rect; + transform_pixel_region_data data; + data.u.init.clip = ▭ + data.u.init.w = penum->rect.w; + data.u.init.h = penum->rect.h; + data.u.init.pixels = &penum->dda.pixel0; + data.u.init.rows = &penum->dda.row; + data.u.init.lop = penum->log_op; + rect.p.x = fixed2int(penum->clip_outer.p.x); + rect.p.y = fixed2int(penum->clip_outer.p.y); + rect.q.x = fixed2int_ceiling(penum->clip_outer.q.x); + rect.q.y = fixed2int_ceiling(penum->clip_outer.q.y); + + if (penum->icc_link == NULL || (penum->icc_link->is_identity && !penum->icc_setup.need_decode)) + data.u.init.spp = penum->spp; + else + data.u.init.spp = des_num_comp; + + code = dev_proc(penum->dev, transform_pixel_region)(penum->dev, transform_pixel_region_begin, &data); + if (code >= 0) { + penum->tpr_state = data.state; + penum->skip_next_line = image_skip_color_icc_tpr; + return &image_render_color_icc_tpr; } - if (penum->posture == image_portrait) - return &image_render_color_icc_portrait; - if (penum->posture == image_landscape) - return &image_render_color_icc_landscape; - return &image_render_color_icc_skew; } + return NULL; } /* ------ Rendering procedures ------ */ @@ -870,115 +891,31 @@ } /* Render a color image with 8 or fewer bits per sample using ICC profile. */ -static int -image_render_color_icc_portrait(gx_image_enum *penum_orig, const byte *buffer, int data_x, - uint w, int h, gx_device * dev) +static int +image_skip_color_icc_tpr(gx_image_enum *penum, gx_device *dev) { - const gx_image_enum *const penum = penum_orig; /* const within proc */ - const gs_gstate *pgs = penum->pgs; - gs_logical_operation_t lop = penum->log_op; - gx_dda_fixed_point pnext; - int vci, vdi; - int spp = penum->spp; - const byte *psrc = buffer + data_x * spp; - int irun; /* int x/rrun */ - byte *bufend = NULL; - int code = 0; - byte *psrc_cm = NULL, *psrc_cm_start = NULL; - byte *psrc_cm_initial; - byte *run; - int k; - int spp_cm = 0; - bool must_halftone = penum->icc_setup.must_halftone; - bool has_transfer = penum->icc_setup.has_transfer; - gx_cmapper_data data; - gx_cmapper_fn *mapper = gx_get_cmapper(&data, pgs, dev, has_transfer, must_halftone, gs_color_select_source); - gx_color_value *conc = &data.conc[0]; - - if (h == 0) - return 0; - code = image_color_icc_prep(penum_orig, psrc, w, dev, &spp_cm, &psrc_cm, - &psrc_cm_start, &bufend, false); - if (code < 0) return code; - psrc_cm_initial = psrc_cm; - /* Needed for device N */ - pnext = penum->dda.pixel0; - dda_translate(pnext.x, (-fixed_epsilon)); - irun = fixed2int_var_rounded(dda_current(pnext.x)); - vci = penum->yci, vdi = penum->hci; - if_debug5m('b', penum->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", - penum->y, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y))); - while (psrc_cm < bufend) { - /* Find the length of the next run. It will either end when we hit - * the end of the source data, or when the pixel data differs. */ - run = psrc_cm + spp_cm; - while (1) - { - dda_next(pnext.x); - if (run >= bufend) - break; - if (memcmp(run, psrc_cm, spp_cm)) - break; - run += spp_cm; - } - /* So we have a run of pixels from psrc_cm to run that are all the same. */ - /* This needs to be sped up */ - for (k = 0; k < spp_cm; k++) { - conc[k] = gx_color_value_from_byte(psrc_cm[k]); - } - mapper(&data); - /* Fill the region between irun and fixed2int_var_rounded(pnext.x) */ - { - int xi = irun; - int wi = (irun = fixed2int_var_rounded(dda_current(pnext.x))) - xi; - - if (wi < 0) - xi += wi, wi = -wi; - if (wi > 0) - code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi, - &data.devc, dev, lop); - } - if (code < 0) - goto err; - psrc_cm = run; - } - /* Free cm buffer, if it was used */ - if (psrc_cm_start != NULL) { - gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_color_icc"); - } - return (code < 0 ? code : 1); - /* Save position if error, in case we resume. */ -err: - gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_color_icc"); - penum_orig->used.x = (run - psrc_cm_initial) / spp_cm; - penum_orig->used.y = 0; - return code; + transform_pixel_region_data data; + data.state = penum->tpr_state; + return dev_proc(dev, transform_pixel_region)(dev, transform_pixel_region_data_needed, &data) == 0; } static int -image_render_color_icc_landscape(gx_image_enum *penum_orig, const byte *buffer, int data_x, - uint w, int h, gx_device * dev) +image_render_color_icc_tpr(gx_image_enum *penum_orig, const byte *buffer, int data_x, + uint w, int h, gx_device * dev) { const gx_image_enum *const penum = penum_orig; /* const within proc */ const gs_gstate *pgs = penum->pgs; - gs_logical_operation_t lop = penum->log_op; - gx_dda_fixed_point pnext; - int vci, vdi; int spp = penum->spp; const byte *psrc = buffer + data_x * spp; - int irun; /* int x/rrun */ - byte *bufend = NULL; - int code = 0; + int code; byte *psrc_cm = NULL, *psrc_cm_start = NULL; byte *psrc_cm_initial; - byte *run; - int k; + byte *bufend = NULL; int spp_cm = 0; bool must_halftone = penum->icc_setup.must_halftone; bool has_transfer = penum->icc_setup.has_transfer; - gx_cmapper_data data; - gx_cmapper_fn *mapper = gx_get_cmapper(&data, pgs, dev, has_transfer, must_halftone, gs_color_select_source); - gx_color_value *conc = &data.conc[0]; + gx_cmapper_t cmapper; + transform_pixel_region_data data; if (h == 0) return 0; @@ -986,141 +923,20 @@ &psrc_cm_start, &bufend, false); if (code < 0) return code; psrc_cm_initial = psrc_cm; - /* Needed for device N */ - pnext = penum->dda.pixel0; - dda_translate(pnext.x, (-fixed_epsilon)); - irun = fixed2int_var_rounded(dda_current(pnext.y)); - vci = penum->xci, vdi = penum->wci; - if_debug5m('b', penum->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", - penum->y, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y))); - while (psrc_cm < bufend) { - /* Find the length of the next run. It will either end when we hit - * the end of the source data, or when the pixel data differs. */ - run = psrc_cm + spp_cm; - while (1) - { - dda_next(pnext.y); - if (run >= bufend) - break; - if (memcmp(run, psrc_cm, spp_cm)) - break; - run += spp_cm; - } - /* So we have a run of pixels from psrc_cm to run that are all the same. */ - /* This needs to be sped up */ - for (k = 0; k < spp_cm; k++) { - conc[k] = gx_color_value_from_byte(psrc_cm[k]); - } - mapper(&data); - /* Fill the region between irun and fixed2int_var_rounded(pnext.y) */ - { /* 90 degree rotated rectangle */ - int yi = irun; - int hi = (irun = fixed2int_var_rounded(dda_current(pnext.y))) - yi; - - if (hi < 0) - yi += hi, hi = -hi; - if (hi > 0) - code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi, - &data.devc, dev, lop); - } - if (code < 0) - goto err; - psrc_cm = run; - } - /* Free cm buffer, if it was used */ - if (psrc_cm_start != NULL) { - gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_color_icc"); - } - return (code < 0 ? code : 1); - /* Save position if error, in case we resume. */ -err: - gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_color_icc"); - penum_orig->used.x = (run - psrc_cm_initial) / spp_cm; - penum_orig->used.y = 0; - return code; -} + gx_get_cmapper(&cmapper, pgs, dev, has_transfer, must_halftone, gs_color_select_source); -static int -image_render_color_icc_skew(gx_image_enum *penum_orig, const byte *buffer, int data_x, - uint w, int h, gx_device * dev) -{ - const gx_image_enum *const penum = penum_orig; /* const within proc */ - const gs_gstate *pgs = penum->pgs; - gs_logical_operation_t lop = penum->log_op; - gx_dda_fixed_point pnext; - fixed xprev, yprev; - fixed pdyx, pdyy; /* edge of parallelogram */ - int spp = penum->spp; - const byte *psrc = buffer + data_x * spp; - fixed xpos; /* x ditto */ - fixed ypos; /* y ditto */ - byte *bufend = NULL; - int code = 0; - byte *psrc_cm = NULL, *psrc_cm_start = NULL; - byte *psrc_cm_initial; - int k; - int spp_cm = 0; - bool must_halftone = penum->icc_setup.must_halftone; - bool has_transfer = penum->icc_setup.has_transfer; - byte initial_run[GX_DEVICE_COLOR_MAX_COMPONENTS] = { 0 }; - byte *prev_cm = &initial_run[0]; - gx_cmapper_data data; - gx_cmapper_fn *mapper = gx_get_cmapper(&data, pgs, dev, has_transfer, must_halftone, gs_color_select_source); - gx_color_value *conc = &data.conc[0]; + data.state = penum->tpr_state; + data.u.process_data.buffer[0] = psrc_cm; + data.u.process_data.data_x = 0; + data.u.process_data.cmapper = &cmapper; + code = dev_proc(dev, transform_pixel_region)(dev, transform_pixel_region_process_data, &data); + gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_color_icc"); - if (h == 0) - return 0; - code = image_color_icc_prep(penum_orig, psrc, w, dev, &spp_cm, &psrc_cm, - &psrc_cm_start, &bufend, false); - if (code < 0) return code; - psrc_cm_initial = psrc_cm; - /* Needed for device N */ - pnext = penum->dda.pixel0; - dda_translate(pnext.x, (-fixed_epsilon)); - xprev = dda_current(pnext.x); - yprev = dda_current(pnext.y); - pdyx = dda_current(penum->dda.row.x) - penum->cur.x; - pdyy = dda_current(penum->dda.row.y) - penum->cur.y; - if_debug5m('b', penum->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n", - penum->y, data_x, w, fixed2float(xprev), fixed2float(yprev)); - prev_cm[0] = ~psrc_cm[0]; /* Force intial setting */ - while (psrc_cm < bufend) { - dda_next(pnext.x); - dda_next(pnext.y); - xpos = dda_current(pnext.x); - ypos = dda_current(pnext.y); - - if (memcmp(prev_cm, psrc_cm, spp_cm) != 0) - { - /* This needs to be sped up */ - for (k = 0; k < spp_cm; k++) { - conc[k] = gx_color_value_from_byte(psrc_cm[k]); - } - mapper(&data); - } - /* Fill the region between */ - /* xprev/yprev and xpos/ypos */ - /* Parallelogram */ - code = (*dev_proc(dev, fill_parallelogram)) - (dev, xprev, yprev, xpos - xprev, ypos - yprev, pdyx, pdyy, - &data.devc, lop); - xprev = xpos; - yprev = ypos; - if (code < 0) - goto err; - prev_cm = psrc_cm; - psrc_cm += spp_cm; - } - /* Free cm buffer, if it was used */ - if (psrc_cm_start != NULL) { - gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_color_icc"); + if (code < 0) { + /* Save position if error, in case we resume. */ + penum_orig->used.x = (data.u.process_data.buffer[0] - psrc_cm_initial) / spp_cm; + penum_orig->used.y = 0; } - return (code < 0 ? code : 1); - /* Save position if error, in case we resume. */ -err: - gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_color_icc"); - penum_orig->used.x = (psrc_cm - psrc_cm_initial) / spp_cm; - penum_orig->used.y = 0; return code; } diff -Nru ghostscript-9.25~dfsg+1/base/gxidata.c ghostscript-9.26~dfsg+0/base/gxidata.c --- ghostscript-9.25~dfsg+1/base/gxidata.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxidata.c 2018-11-20 09:59:43.000000000 +0000 @@ -474,7 +474,17 @@ return code; } - /* release the reference to the target */ + if (penum->tpr_state != NULL) { + transform_pixel_region_data data; + gx_device *dev = penum->dev; + if (penum->clip_dev) + dev = (gx_device *)penum->clip_dev; + if (penum->rop_dev) + dev = (gx_device *)penum->rop_dev; + data.state = penum->tpr_state; + dev_proc(dev, transform_pixel_region)(dev, transform_pixel_region_end, &data); + } + /* release the reference to the target */ if ( penum->rop_dev ) gx_device_set_target((gx_device_forward *)penum->rop_dev, NULL); if ( penum->clip_dev ) diff -Nru ghostscript-9.25~dfsg+1/base/gxifast.c ghostscript-9.26~dfsg+0/base/gxifast.c --- ghostscript-9.25~dfsg+1/base/gxifast.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxifast.c 2018-11-20 09:59:43.000000000 +0000 @@ -110,9 +110,6 @@ penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { - gx_default_end_image(penum->dev, - (gx_image_enum_common_t *) penum, - false); return 0; } #ifdef PACIFY_VALGRIND diff -Nru ghostscript-9.25~dfsg+1/base/gximage.h ghostscript-9.26~dfsg+0/base/gximage.h --- ghostscript-9.25~dfsg+1/base/gximage.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gximage.h 2018-11-20 09:59:43.000000000 +0000 @@ -305,6 +305,7 @@ ht_landscape_info_t ht_landscape; gx_image_icc_setup_t icc_setup; bool use_cie_range; /* Needed potentially if CS was PS CIE based */ + void *tpr_state; }; /* Enumerate the pointers in an image enumerator. */ diff -Nru ghostscript-9.25~dfsg+1/base/gxpath.h ghostscript-9.26~dfsg+0/base/gxpath.h --- ghostscript-9.25~dfsg+1/base/gxpath.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxpath.h 2018-11-20 09:59:43.000000000 +0000 @@ -287,6 +287,8 @@ void gx_point_scale_exp2(gs_fixed_point *, int, int), gx_rect_scale_exp2(gs_fixed_rect *, int, int); +int gx_path_elide_1d(gx_path *ppath); + /* Path enumerator */ /* This interface does not make a copy of the path. */ diff -Nru ghostscript-9.25~dfsg+1/base/gxpcmap.c ghostscript-9.26~dfsg+0/base/gxpcmap.c --- ghostscript-9.25~dfsg+1/base/gxpcmap.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxpcmap.c 2018-11-20 09:59:43.000000000 +0000 @@ -177,7 +177,10 @@ NULL, /* get_profile */ NULL, /* set_graphics_type_tag */ gx_default_strip_copy_rop2, - gx_default_strip_tile_rect_devn + gx_default_strip_tile_rect_devn, + NULL, /* alpha_hl_color */ + NULL, /* process_page */ + gx_default_transform_pixel_region /* NOT the default forwarding one */ }, 0, /* target */ 0, 0, 0, 0 /* bitmap_memory, bits, mask, instance */ @@ -307,7 +310,7 @@ gx_device_clist_writer *cwdev; const int data_size = 1024*128; gx_band_params_t band_params = { 0 }; - byte *data = gs_alloc_bytes(storage_memory->non_gc_memory, data_size, cname); + byte *data = gs_alloc_bytes(tdev->memory->non_gc_memory, data_size, cname); if (data == NULL) return 0; @@ -321,7 +324,7 @@ &buf_procs, &band_params, true, /* use_memory_clist */ pinst->templat.uses_transparency, pinst); if (cdev == 0) { - gs_free_object(storage_memory->non_gc_memory, data, cname); + gs_free_object(tdev->memory->non_gc_memory, data, cname); return 0; } cwdev = (gx_device_clist_writer *)cdev; diff -Nru ghostscript-9.25~dfsg+1/base/gxpcopy.c ghostscript-9.26~dfsg+0/base/gxpcopy.c --- ghostscript-9.25~dfsg+1/base/gxpcopy.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxpcopy.c 2018-11-20 09:59:43.000000000 +0000 @@ -851,3 +851,196 @@ } return 0; } + +static int +is_colinear(gs_fixed_rect *rect, fixed x, fixed y) +{ + fixed x0 = rect->p.x; + fixed y0 = rect->p.y; + fixed x1 = rect->q.x; + fixed y1 = rect->q.y; + + if (x0 == x1) { + if (y0 == y1) { + /* Initial case */ + /* Still counts as colinear */ + } else if (x == x0) { + /* OK! */ + } else { + return 0; /* Not colinear */ + } + } else if (rect->p.y == rect->q.y) { + if (y == rect->p.y) { + /* OK */ + } else { + return 0; /* Not colinear */ + } + } else { + /* Need to do hairy maths */ + /* The distance of a point (x,y) from the line passing through + * (x0,y0) and (x1,y1) is: + * d = |(y1-y0)x - (x1-x0)y + x1y0 - y1x0| / SQR((y1-y0)^2 + (x1-x0)^2) + * + * We want d <= epsilon to count as colinear. + * + * d = |(y1-y0)x - (x1-x0)y + x1y0 - y1x0| / SQR((y1-y0)^2 + (x1-x0)^2) <= epsilon + * + * |(y1-y0)x - (x1-x0)y + x1y0 - y1x0| <= epsilon * SQR((y1-y0)^2 + (x1-x0)^2) + * + * ((y1-y0)x - (x1-x0)y + x1y0 - y1x0)^2 <= epsilon^2 * ((y1-y0)^2 + (x1-x0)^2) + */ + int64_t ix1 = ((int64_t)x1); + int64_t iy1 = ((int64_t)y1); + int64_t dx = ix1 - x0; + int64_t dy = iy1 - y0; + int64_t num = dy*x - dx*y + ix1*y0 - iy1*x0; + int64_t den = dx*dx + dy*dy; + int epsilon_squared = 2; + + if (num < 0) + num = -num; + while (num > (1<<30)) { + num >>= 2; + den >>= 1; + if (den == 0) + return 0; /* Not colinear */ + } + num *= num; + if (num > epsilon_squared * den) + return 0; + } + /* rect is not really a rect. It's just a pair of points. We guarantee that x0 <= x1. */ + if (x == x0) { + if (y < y0) + rect->p.y = y; + else if (y > y1) + rect->q.y = y; + } else if (x < x0) { + rect->p.x = x; + rect->p.y = y; + } else { + rect->q.x = x; + rect->q.y = y; + } + + return 1; +} + +static int +gx_path_copy_eliding_1d(const gx_path *ppath_old, gx_path *ppath) +{ + const segment *pseg; + /* + * Since we're going to be adding to the path, unshare it + * before we start. + */ + int code = gx_path_unshare(ppath); + + if (code < 0) + return code; +#ifdef DEBUG + if (gs_debug_c('P')) + gx_dump_path(ppath_old, "before eliding_1d"); +#endif + + pseg = (const segment *)(ppath_old->first_subpath); + while (pseg != NULL) { + const segment *look = pseg; + gs_fixed_rect rect; + + rect.p.x = rect.q.x = look->pt.x; + rect.p.y = rect.q.y = look->pt.y; + + if (look->type != s_start) { + dlprintf("Unlikely?"); + } + + look = look->next; + while (look != NULL && look->type != s_start) { + if (look->type == s_curve) { + const curve_segment *pc = (const curve_segment *)look; + if (!is_colinear(&rect, pc->p1.x, pc->p1.y) || + !is_colinear(&rect, pc->p2.x, pc->p2.y) || + !is_colinear(&rect, pc->pt.x, pc->pt.y)) + goto not_colinear; + } else if (!is_colinear(&rect, look->pt.x, look->pt.y)) { + goto not_colinear; + } + look = look->next; + } + pseg = look; + if (0) + { +not_colinear: + /* Not colinear. We want to keep this section. */ + while (look != NULL && look->type != s_start) + look = look->next; + while (pseg != look && code >= 0) { + /* Copy */ + switch (pseg->type) { + case s_start: + code = gx_path_add_point(ppath, + pseg->pt.x, pseg->pt.y); + break; + case s_curve: + { + const curve_segment *pc = (const curve_segment *)pseg; + + code = gx_path_add_curve_notes(ppath, + pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y, + pc->pt.x, pc->pt.y, pseg->notes); + break; + } + case s_line: + code = gx_path_add_line_notes(ppath, + pseg->pt.x, pseg->pt.y, pseg->notes); + break; + case s_gap: + code = gx_path_add_gap_notes(ppath, + pseg->pt.x, pseg->pt.y, pseg->notes); + break; + case s_dash: + { + const dash_segment *pd = (const dash_segment *)pseg; + + code = gx_path_add_dash_notes(ppath, + pd->pt.x, pd->pt.y, pd->tangent.x, pd->tangent.y, pseg->notes); + break; + } + case s_line_close: + code = gx_path_close_subpath(ppath); + break; + default: /* can't happen */ + code = gs_note_error(gs_error_unregistered); + } + pseg = pseg->next; + } + if (code < 0) { + gx_path_new(ppath); + return code; + } + } + } + ppath->bbox_set = false; +#ifdef DEBUG + if (gs_debug_c('P')) + gx_dump_path(ppath, "after eliding_1d"); +#endif + return 0; +} + +int +gx_path_elide_1d(gx_path *ppath) +{ + int code; + gx_path path; + + gx_path_init_local(&path, ppath->memory); + code = gx_path_copy_eliding_1d(ppath, &path); + if (code < 0) + return code; + gx_path_assign_free(ppath, &path); + gx_path_free(&path, "gx_path_elide_1d"); + + return 0; +} diff -Nru ghostscript-9.25~dfsg+1/base/gxscanc.c ghostscript-9.26~dfsg+0/base/gxscanc.c --- ghostscript-9.25~dfsg+1/base/gxscanc.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/gxscanc.c 2018-11-20 09:59:43.000000000 +0000 @@ -195,6 +195,127 @@ } #endif +typedef void (zero_filler_fn)(int *, const fixed *); + +static void mark_line_zero(fixed sx, fixed ex, fixed *zf) +{ + if (sx < zf[0]) + zf[0] = sx; + if (ex < zf[0]) + zf[0] = ex; + if (sx > zf[1]) + zf[1] = sx; + if (ex > zf[1]) + zf[1] = ex; +} + +static void mark_curve_zero(fixed sx, fixed c1x, fixed c2x, fixed ex, int depth, fixed *zf) +{ + fixed ax = (sx + c1x)>>1; + fixed bx = (c1x + c2x)>>1; + fixed cx = (c2x + ex)>>1; + fixed dx = (ax + bx)>>1; + fixed fx = (bx + cx)>>1; + fixed gx = (dx + fx)>>1; + + assert(depth >= 0); + if (depth == 0) + mark_line_zero(sx, ex, zf); + else { + depth--; + mark_curve_zero(sx, ax, dx, gx, depth, zf); + mark_curve_zero(gx, fx, cx, ex, depth, zf); + } +} + +static void mark_curve_big_zero(fixed64 sx, fixed64 c1x, fixed64 c2x, fixed64 ex, int depth, fixed *zf) +{ + fixed64 ax = (sx + c1x)>>1; + fixed64 bx = (c1x + c2x)>>1; + fixed64 cx = (c2x + ex)>>1; + fixed64 dx = (ax + bx)>>1; + fixed64 fx = (bx + cx)>>1; + fixed64 gx = (dx + fx)>>1; + + assert(depth >= 0); + if (depth == 0) + mark_line_zero((fixed)sx, (fixed)ex, zf); + else { + depth--; + mark_curve_big_zero(sx, ax, dx, gx, depth, zf); + mark_curve_big_zero(gx, fx, cx, ex, depth, zf); + } +} + +static void mark_curve_top_zero(fixed sx, fixed c1x, fixed c2x, fixed ex, int depth, fixed *zf) +{ + fixed test = (sx^(sx<<1))|(c1x^(c1x<<1))|(c2x^(c2x<<1))|(ex^(ex<<1)); + + if (test < 0) + mark_curve_big_zero(sx, c1x, c2x, ex, depth, zf); + else + mark_curve_zero(sx, c1x, c2x, ex, depth, zf); +} + +static int +zero_case(gx_device * gs_restrict pdev, + gx_path * gs_restrict path, + gs_fixed_rect * gs_restrict ibox, + int * gs_restrict index, + int * gs_restrict table, + fixed fixed_flat, + zero_filler_fn * fill) +{ + const subpath *psub; + fixed zf[2]; + + /* Step 2 continued: Now we run through the path, filling in the real + * values. */ + for (psub = path->first_subpath; psub != 0;) { + const segment *pseg = (const segment *)psub; + fixed ex = pseg->pt.x; + fixed sy = pseg->pt.y; + fixed ix = ex; + int iy = fixed2int(pseg->pt.y); + + zf[0] = ex; + zf[1] = ex; + + while ((pseg = pseg->next) != 0 && + pseg->type != s_start + ) { + fixed sx = ex; + ex = pseg->pt.x; + + switch (pseg->type) { + default: + case s_start: /* Should never happen */ + case s_dash: /* We should never be seeing a dash here */ + assert("This should never happen" == NULL); + break; + case s_curve: { + const curve_segment *const pcur = (const curve_segment *)pseg; + int k = gx_curve_log2_samples(sx, sy, pcur, fixed_flat); + + mark_curve_top_zero(sx, pcur->p1.x, pcur->p2.x, ex, k, zf); + break; + } + case s_gap: + case s_line: + case s_line_close: + mark_line_zero(sx, ex, zf); + break; + } + } + /* And close any open segments */ + mark_line_zero(ex, ix, zf); + fill(&table[index[iy-ibox->p.y]], zf); + psub = (const subpath *)pseg; + } + + return 0; +} + static void mark_line(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int height, int *table, int *index) { int64_t delta; @@ -385,31 +506,50 @@ static int make_bbox(gx_path * path, const gs_fixed_rect * clip, + gs_fixed_rect * bbox, gs_fixed_rect * ibox, fixed adjust) { - gs_fixed_rect bbox; int code; + int ret = 0; /* Find the bbox - fixed */ - code = gx_path_bbox(path, &bbox); + code = gx_path_bbox(path, bbox); if (code < 0) return code; + if (bbox->p.y == bbox->q.y) { + /* Zero height path */ + if (!clip || + (bbox->p.y >= clip->p.y && bbox->q.y <= clip->q.y)) { + /* Either we're not clipping, or we are vertically inside the clip */ + if (clip) { + if (bbox->p.x < clip->p.x) + bbox->p.x = clip->p.x; + if (bbox->q.x > clip->q.x) + bbox->q.x = clip->q.x; + } + if (bbox->p.x <= bbox->q.x) { + /* Zero height rectangle, not clipped completely away */ + ret = 1; + } + } + } + if (clip) { - if (bbox.p.y < clip->p.y) - bbox.p.y = clip->p.y; - if (bbox.q.y > clip->q.y) - bbox.q.y = clip->q.y; + if (bbox->p.y < clip->p.y) + bbox->p.y = clip->p.y; + if (bbox->q.y > clip->q.y) + bbox->q.y = clip->q.y; } /* Convert to bbox - int */ - ibox->p.x = fixed2int(bbox.p.x-adjust); - ibox->p.y = fixed2int(bbox.p.y-adjust); - ibox->q.x = fixed2int(bbox.q.x-adjust+fixed_1); - ibox->q.y = fixed2int(bbox.q.y-adjust+fixed_1); + ibox->p.x = fixed2int(bbox->p.x+adjust-(adjust?1:0)); + ibox->p.y = fixed2int(bbox->p.y+adjust-(adjust?1:0)); + ibox->q.x = fixed2int(bbox->q.x-adjust+fixed_1); + ibox->q.y = fixed2int(bbox->q.y-adjust+fixed_1); - return 0; + return ret; } static inline int @@ -638,7 +778,7 @@ /* Step 1 continued: index now contains a list of deltas (how the * number of intersects on line x differs from the number on line x-1). * First convert them to be the real number of intersects on that line. - * Sum these values to get us the total nunber of intersects. Then + * Sum these values to get us the total number of intersects. Then * convert the table to be a list of offsets into the real intersect * buffer. */ offset = 0; @@ -648,6 +788,9 @@ index[i] = offset; /* Offset into table for this lines data. */ offset += delta+1; /* Adjust offset for next line. */ } + /* Ensure we always have enough room for our zero height rectangle hack. */ + if (offset < 2*intersection_size) + offset += 2*intersection_size; offset *= sizeof(*table); if (offset != (int64_t)(uint)offset) { @@ -691,19 +834,29 @@ return make_table_template(pdev, path, ibox, 1, 1, scanlines, index, table); } +static void +fill_zero(int *row, const fixed *x) +{ + int n = *row = (*row)+2; /* Increment the count */ + row[n-1] = (x[0]&~1); + row[n ] = (x[1]|1); +} + int gx_scan_convert(gx_device * gs_restrict pdev, gx_path * gs_restrict path, const gs_fixed_rect * gs_restrict clip, gx_edgebuffer * gs_restrict edgebuffer, - fixed fixed_flat) + fixed fixed_flat) { gs_fixed_rect ibox; + gs_fixed_rect bbox; int scanlines; const subpath *psub; int *index; int *table; int i; int code; + int zero; edgebuffer->index = NULL; edgebuffer->table = NULL; @@ -712,9 +865,9 @@ if (path->first_subpath == NULL) return 0; - code = make_bbox(path, clip, &ibox, fixed_half); - if (code < 0) - return code; + zero = make_bbox(path, clip, &bbox, &ibox, fixed_half); + if (zero < 0) + return zero; if (ibox.q.y <= ibox.p.y) return 0; @@ -723,6 +876,10 @@ if (code < 0) return code; + if (zero) { + code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero); + } else { + /* Step 2 continued: Now we run through the path, filling in the real * values. */ for (psub = path->first_subpath; psub != 0;) { @@ -766,6 +923,7 @@ mark_line(ex, ey, ix, iy, ibox.p.y, scanlines, table, index); psub = (const subpath *)pseg; } + } /* Step 2 complete: We now have a complete list of intersection data in * table, indexed by index. */ @@ -992,14 +1150,14 @@ cr->save_iy = iy; cr->save_d = cr->d; cr->saved = 1; - } else { + } else if (cr->d != DIRN_UNSET) { /* Enter it into the table */ - assert(cr->d != DIRN_UNSET); - row = &cr->table[cr->index[iy]]; *row = count = (*row)+1; /* Increment the count */ row[2 * count - 1] = (cr->left&~1) | cr->d; row[2 * count ] = cr->right; + } else { + assert(cr->left == max_int_in_fixed && cr->right == min_int_in_fixed); } } cr->first = 0; @@ -1033,7 +1191,7 @@ /* Step the cursor in y, allowing for maybe crossing a scanline */ static inline void -cursor_step(cursor * gs_restrict cr, fixed dy, fixed x) +cursor_step(cursor * gs_restrict cr, fixed dy, fixed x, int skip) { int new_iy; int iy = fixed2int(cr->y) - cr->base; @@ -1041,7 +1199,8 @@ cr->y += dy; new_iy = fixed2int(cr->y) - cr->base; if (new_iy != iy) { - cursor_output(cr, iy); + if (!skip) + cursor_output(cr, iy); cr->left = x; cr->right = x; } else { @@ -1089,11 +1248,12 @@ /* Step the cursor in y, always by enough to cross a scanline. */ static inline void -cursor_always_step(cursor * gs_restrict cr, fixed dy, fixed x) +cursor_always_step(cursor * gs_restrict cr, fixed dy, fixed x, int skip) { int iy = fixed2int(cr->y) - cr->base; - cursor_output(cr, iy); + if (!skip) + cursor_output(cr, iy); cr->y += dy; cr->left = x; cr->right = x; @@ -1169,15 +1329,20 @@ cr->right = x; } -static inline void cursor_down(cursor * gs_restrict cr, fixed x) +static inline int cursor_down(cursor * gs_restrict cr, fixed x) { + int skip = 0; + if ((cr->y & 0xff) == 0) + skip = 1; if (cr->d == DIRN_UP) { - cursor_output(cr, fixed2int(cr->y) - cr->base); + if (!skip) + cursor_output(cr, fixed2int(cr->y) - cr->base); cr->left = x; cr->right = x; } cr->d = DIRN_DOWN; + return skip; } static inline void cursor_up(cursor * gs_restrict cr, fixed x) @@ -1201,6 +1366,11 @@ * rectangle from the start point. */ if (cr->first) { int iy = fixed2int(cr->y) - cr->base; + /* Any zero height rectangle counts as filled, except + * those on the baseline of a pixel. */ + if (cr->d == DIRN_UNSET && (cr->y & 0xff) == 0) + return; + assert(cr->left != max_int_in_fixed && cr->right != min_int_in_fixed); if (iy >= 0 && iy < cr->scanlines) { int *row = &cr->table[cr->index[iy]]; int count = *row = (*row)+2; /* Increment the count */ @@ -1236,6 +1406,14 @@ } } +static inline void +cursor_null(cursor *cr) +{ + cr->right = min_int_in_fixed; + cr->left = max_int_in_fixed; + cr->d = DIRN_UNSET; +} + static void mark_line_app(cursor * gs_restrict cr, fixed sx, fixed sy, fixed ex, fixed ey) { int isy, iey; @@ -1260,15 +1438,25 @@ dlprintf("stroke %%PS\n"); #endif - assert(cr->y == sy && cr->left <= sx && cr->right >= sx && cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); + /* Horizontal motion at the bottom of a pixel is ignored */ + if (sy == ey && (sy & 0xff) == 0) + return; + + assert(cr->y == sy && + ((cr->left <= sx && cr->right >= sx) || ((sy & 0xff) == 0)) && + cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); if (isy < iey) { /* Rising line */ if (iey < 0 || isy >= cr->scanlines) { /* All line is outside. */ + if ((ey & 0xff) == 0) + cursor_null(cr); + else { + cr->left = ex; + cr->right = ex; + } cr->y = ey; - cr->left = ex; - cr->right = ex; cr->first = 0; return; } @@ -1279,7 +1467,8 @@ int64_t dy = (int64_t)new_sy - (int64_t)sy; sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); sy = new_sy; - cursor_init(cr, sy, sx); + cursor_null(cr); + cr->y = sy; isy = 0; } truncated = iey > cr->scanlines; @@ -1298,9 +1487,13 @@ /* Falling line */ if (isy < 0 || iey >= cr->scanlines) { /* All line is outside. */ + if ((ey & 0xff) == 0) + cursor_null(cr); + else { + cr->left = ex; + cr->right = ex; + } cr->y = ey; - cr->left = ex; - cr->right = ex; cr->first = 0; return; } @@ -1321,11 +1514,15 @@ int64_t dy = (int64_t)new_sy - (int64_t)sy; sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); sy = new_sy; - cursor_init(cr, sy, sx); + cursor_null(cr); + cr->y = sy; isy = cr->scanlines; } } + cursor_left_merge(cr, sx); + cursor_right_merge(cr, sx); + assert(cr->left <= sx); assert(cr->right >= sx); assert(cr->y == sy); @@ -1353,20 +1550,38 @@ if (isy == iey) { if (saved_sy == saved_ey) { /* Horizontal line. Don't change cr->d, don't flush. */ + if ((ey & 0xff) == 0) + goto no_merge; } else if (saved_sy > saved_ey) { /* Falling line, flush if previous was rising */ - cursor_down(cr, sx); + int skip = cursor_down(cr, sx); + if ((ey & 0xff) == 0) { + /* We are falling to the baseline of a subpixel, so output + * for the current pixel, and leave the cursor nulled. */ + if (sx <= ex) { + cursor_right_merge(cr, ex); + } else { + cursor_left_merge(cr, ex); + } + if (!skip) + cursor_output(cr, fixed2int(cr->y) - cr->base); + cursor_null(cr); + goto no_merge; + } } else { /* Rising line, flush if previous was falling */ cursor_up(cr, sx); + if ((ey & 0xff) == 0) { + cursor_null(cr); + goto no_merge; + } } if (sx <= ex) { - cursor_left_merge(cr, sx); cursor_right_merge(cr, ex); } else { cursor_left_merge(cr, ex); - cursor_right_merge(cr, sx); } +no_merge: cr->y = ey; if (sy > saved_ey) goto endFalling; @@ -1393,16 +1608,16 @@ /* Vertical line. (Rising) */ /* Phase 1: */ - cursor_left_merge(cr, sx); - cursor_right_merge(cr, sx); if (phase1_y_steps) { /* If phase 1 will move us into a new scanline, then we must * flush it before we move. */ - cursor_step(cr, phase1_y_steps, sx); + cursor_step(cr, phase1_y_steps, sx, 0); sy += phase1_y_steps; y_steps -= phase1_y_steps; - if (y_steps == 0) + if (y_steps == 0) { + cursor_null(cr); goto end; + } } /* Phase 3: precalculation */ @@ -1412,7 +1627,7 @@ y_steps = fixed2int(y_steps); assert(y_steps >= 0); if (y_steps > 0) { - cursor_always_step(cr, fixed_1, sx); + cursor_always_step(cr, fixed_1, sx, 0); y_steps--; while (y_steps) { cursor_always_step_inrange_vertical(cr, fixed_1, sx); @@ -1422,24 +1637,28 @@ /* Phase 3 */ assert(cr->left == sx && cr->right == sx); - cr->y += phase3_y_steps; + if (phase3_y_steps == 0) + cursor_null(cr); + else + cr->y += phase3_y_steps; } else if (sx < ex) { /* Lines increasing in x. (Rightwards, rising) */ int phase1_x_steps, phase3_x_steps; fixed x_steps = ex - sx; /* Phase 1: */ - cursor_left_merge(cr, sx); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); sx += phase1_x_steps; cursor_right_merge(cr, sx); x_steps -= phase1_x_steps; - cursor_step(cr, phase1_y_steps, sx); + cursor_step(cr, phase1_y_steps, sx, 0); sy += phase1_y_steps; y_steps -= phase1_y_steps; - if (y_steps == 0) + if (y_steps == 0) { + cursor_null(cr); goto end; + } } /* Phase 3: precalculation */ @@ -1466,7 +1685,7 @@ if (f < 0) f += d, sx++; cursor_right_merge(cr, sx); - cursor_always_step(cr, fixed_1, sx); + cursor_always_step(cr, fixed_1, sx, 0); y_steps--; while (y_steps) { @@ -1482,25 +1701,30 @@ /* Phase 3 */ assert(cr->left <= ex && cr->right >= sx); - cursor_right(cr, ex); - cr->y += phase3_y_steps; + if (phase3_y_steps == 0) + cursor_null(cr); + else { + cursor_right(cr, ex); + cr->y += phase3_y_steps; + } } else { /* Lines decreasing in x. (Leftwards, rising) */ int phase1_x_steps, phase3_x_steps; fixed x_steps = sx - ex; /* Phase 1: */ - cursor_right_merge(cr, sx); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); x_steps -= phase1_x_steps; sx -= phase1_x_steps; cursor_left_merge(cr, sx); - cursor_step(cr, phase1_y_steps, sx); + cursor_step(cr, phase1_y_steps, sx, 0); sy += phase1_y_steps; y_steps -= phase1_y_steps; - if (y_steps == 0) + if (y_steps == 0) { + cursor_null(cr); goto end; + } } /* Phase 3: precalculation */ @@ -1527,7 +1751,7 @@ if (f < 0) f += d, sx--; cursor_left_merge(cr, sx); - cursor_always_step(cr, fixed_1, sx); + cursor_always_step(cr, fixed_1, sx, 0); y_steps--; while (y_steps) { @@ -1543,8 +1767,12 @@ /* Phase 3 */ assert(cr->right >= ex && cr->left <= sx); - cursor_left(cr, ex); - cr->y += phase3_y_steps; + if (phase3_y_steps == 0) + cursor_null(cr); + else { + cursor_left(cr, ex); + cr->y += phase3_y_steps; + } } } else { /* So lines decreasing in y. */ @@ -1558,21 +1786,19 @@ int phase3_y_steps = (-ey) & (fixed_1 - 1); ufixed y_steps = (ufixed)sy - (ufixed)ey; - cursor_down(cr, sx); + int skip = cursor_down(cr, sx); if (sx == ex) { /* Vertical line. (Falling) */ /* Phase 1: */ - cursor_left_merge(cr, sx); - cursor_right_merge(cr, sx); if (phase1_y_steps) { /* Phase 1 in a falling line never moves us into a new scanline. */ cursor_never_step_vertical(cr, -phase1_y_steps, sx); sy -= phase1_y_steps; y_steps -= phase1_y_steps; if (y_steps == 0) - goto endFalling; + goto endFallingLeftOnEdgeOfPixel; } /* Phase 3: precalculation */ @@ -1583,7 +1809,8 @@ y_steps = fixed2int(y_steps); assert(y_steps >= 0); if (y_steps) { - cursor_always_step(cr, -fixed_1, sx); + cursor_always_step(cr, -fixed_1, sx, skip); + skip = 0; y_steps--; while (y_steps) { cursor_always_step_inrange_vertical(cr, -fixed_1, sx); @@ -1592,8 +1819,12 @@ } /* Phase 3 */ - if (phase3_y_steps > 0) { - cursor_step(cr, -phase3_y_steps, sx); + if (phase3_y_steps == 0) { +endFallingLeftOnEdgeOfPixel: + cursor_always_step_inrange_vertical(cr, 0, sx); + cursor_null(cr); + } else { + cursor_step(cr, -phase3_y_steps, sx, skip); assert(cr->left == sx && cr->right == sx); } } else if (sx < ex) { @@ -1602,7 +1833,6 @@ fixed x_steps = ex - sx; /* Phase 1: */ - cursor_left_merge(cr, sx); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); x_steps -= phase1_x_steps; @@ -1612,9 +1842,8 @@ sy -= phase1_y_steps; y_steps -= phase1_y_steps; if (y_steps == 0) - goto endFalling; - } else - cursor_right_merge(cr, sx); + goto endFallingRightOnEdgeOfPixel; + } /* Phase 3: precalculation */ phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); @@ -1633,7 +1862,8 @@ int f = y_steps/2; int d = y_steps; - cursor_always_step(cr, -fixed_1, sx); + cursor_always_step(cr, -fixed_1, sx, skip); + skip = 0; sx += x_inc; f -= n_inc; if (f < 0) @@ -1653,8 +1883,12 @@ } /* Phase 3 */ - if (phase3_y_steps > 0) { - cursor_step(cr, -phase3_y_steps, sx); + if (phase3_y_steps == 0) { +endFallingRightOnEdgeOfPixel: + cursor_always_step_inrange_vertical(cr, 0, sx); + cursor_null(cr); + } else { + cursor_step(cr, -phase3_y_steps, sx, skip); cursor_right(cr, ex); assert(cr->left == sx && cr->right == ex); } @@ -1664,7 +1898,6 @@ fixed x_steps = sx - ex; /* Phase 1: */ - cursor_right_merge(cr, sx); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); x_steps -= phase1_x_steps; @@ -1674,9 +1907,8 @@ sy -= phase1_y_steps; y_steps -= phase1_y_steps; if (y_steps == 0) - goto endFalling; - } else - cursor_left_merge(cr, sx); + goto endFallingVerticalOnEdgeOfPixel; + } /* Phase 3: precalculation */ phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); @@ -1695,7 +1927,8 @@ int f = y_steps/2; int d = y_steps; - cursor_always_step(cr, -fixed_1, sx); + cursor_always_step(cr, -fixed_1, sx, skip); + skip = 0; sx -= x_inc; f -= n_inc; if (f < 0) @@ -1715,15 +1948,17 @@ } /* Phase 3 */ - if (phase3_y_steps > 0) { - cursor_step(cr, -phase3_y_steps, sx); + if (phase3_y_steps == 0) { +endFallingVerticalOnEdgeOfPixel: + cursor_always_step_inrange_vertical(cr, 0, sx); + cursor_null(cr); + } else { + cursor_step(cr, -phase3_y_steps, sx, skip); cursor_left(cr, ex); assert(cr->left == ex && cr->right == sx); } } -endFalling: - if (truncated) - cursor_output(cr, fixed2int(cr->y) - cr->base); +endFalling: {} } end: @@ -1804,6 +2039,16 @@ return make_table_template(pdev, path, ibox, 2, 0, scanlines, index, table); } +static void +fill_zero_app(int *row, const fixed *x) +{ + int n = *row = (*row)+2; /* Increment the count */ + row[2*n-3] = (x[0]&~1); + row[2*n-2] = (x[1]&~1); + row[2*n-1] = (x[1]&~1)|1; + row[2*n ] = x[1]; +} + int gx_scan_convert_app(gx_device * gs_restrict pdev, gx_path * gs_restrict path, const gs_fixed_rect * gs_restrict clip, @@ -1811,6 +2056,7 @@ fixed fixed_flat) { gs_fixed_rect ibox; + gs_fixed_rect bbox; int scanlines; const subpath *psub; int *index; @@ -1818,6 +2064,7 @@ int i; cursor cr; int code; + int zero; edgebuffer->index = NULL; edgebuffer->table = NULL; @@ -1826,9 +2073,9 @@ if (path->first_subpath == NULL) return 0; - code = make_bbox(path, clip, &ibox, 0); - if (code < 0) - return code; + zero = make_bbox(path, clip, &bbox, &ibox, 0); + if (zero < 0) + return zero; if (ibox.q.y <= ibox.p.y) return 0; @@ -1837,6 +2084,10 @@ if (code < 0) return code; + if (zero) { + code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero_app); + } else { + /* Step 2 continued: Now we run through the path, filling in the real * values. */ cr.scanlines = scanlines; @@ -1851,7 +2102,12 @@ fixed iy = ey; fixed sx, sy; - cr.left = cr.right = ex; + if ((ey & 0xff) == 0) { + cr.left = max_int_in_fixed; + cr.right = min_int_in_fixed; + } else { + cr.left = cr.right = ex; + } cr.y = ey; cr.d = DIRN_UNSET; cr.first = 1; @@ -1890,6 +2146,7 @@ cursor_flush(&cr, ex); psub = (const subpath *)pseg; } + } /* Step 2 complete: We now have a complete list of intersection data in * table, indexed by index. */ @@ -2307,6 +2564,16 @@ return make_table_template(pdev, path, ibox, 2, 1, scanlines, index, table); } +static void +fill_zero_tr(int *row, const fixed *x) +{ + int n = *row = (*row)+2; /* Increment the count */ + row[2*n-3] = x[0]; + row[2*n-2] = 0; + row[2*n-1] = x[1]; + row[2*n ] = 1; +} + int gx_scan_convert_tr(gx_device * gs_restrict pdev, gx_path * gs_restrict path, const gs_fixed_rect * gs_restrict clip, @@ -2314,6 +2581,7 @@ fixed fixed_flat) { gs_fixed_rect ibox; + gs_fixed_rect bbox; int scanlines; const subpath *psub; int *index; @@ -2321,6 +2589,7 @@ int i; int code; int id = 0; + int zero; edgebuffer->index = NULL; edgebuffer->table = NULL; @@ -2329,9 +2598,9 @@ if (path->first_subpath == NULL) return 0; - code = make_bbox(path, clip, &ibox, fixed_half); - if (code < 0) - return code; + zero = make_bbox(path, clip, &bbox, &ibox, fixed_half); + if (zero < 0) + return zero; if (ibox.q.y <= ibox.p.y) return 0; @@ -2340,6 +2609,10 @@ if (code < 0) return code; + if (zero) { + code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero_tr); + } else { + /* Step 3: Now we run through the path, filling in the real * values. */ for (psub = path->first_subpath; psub != 0;) { @@ -2383,6 +2656,18 @@ mark_line_tr(ex, ey, ix, iy, ibox.p.y, scanlines, table, index, ++id); psub = (const subpath *)pseg; } + } + + //if (zero) { + // if (table[0] == 0) { + // /* Zero height rectangle fills a span */ + // table[0] = 2; + // table[1] = int2fixed(fixed2int(bbox.p.x + fixed_half)); + // table[2] = 0; + // table[3] = int2fixed(fixed2int(bbox.q.x + fixed_half)); + // table[4] = 1; + // } + //} /* Step 2 complete: We now have a complete list of intersection data in * table, indexed by index. */ @@ -2436,7 +2721,7 @@ int gx_filter_edgebuffer_tr(gx_device * gs_restrict pdev, gx_edgebuffer * gs_restrict edgebuffer, - int rule) + int rule) { int i; @@ -2781,16 +3066,16 @@ cr->save_iy = iy; cr->save_d = cr->d; cr->saved = 1; - } else { + } else if (cr->d != DIRN_UNSET) { /* Enter it into the table */ - assert(cr->d != DIRN_UNSET); - row = &cr->table[cr->index[iy]]; *row = count = (*row)+1; /* Increment the count */ row[4 * count - 3] = cr->left; row[4 * count - 2] = cr->d | (cr->lid<<1); row[4 * count - 1] = cr->right; row[4 * count ] = cr->rid; + } else { + assert(cr->left == max_int_in_fixed && cr->right == min_int_in_fixed); } } cr->first = 0; @@ -2828,7 +3113,7 @@ /* Step the cursor in y, allowing for maybe crossing a scanline */ static inline void -cursor_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) +cursor_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id, int skip) { int new_iy; int iy = fixed2int(cr->y) - cr->base; @@ -2836,19 +3121,18 @@ cr->y += dy; new_iy = fixed2int(cr->y) - cr->base; if (new_iy != iy) { - cursor_output_tr(cr, iy); + if (!skip) + cursor_output_tr(cr, iy); cr->left = x; cr->lid = id; cr->right = x; cr->rid = id; } else { - if (x < cr->left) - { + if (x < cr->left) { cr->left = x; cr->lid = id; } - if (x > cr->right) - { + if (x > cr->right) { cr->right = x; cr->rid = id; } @@ -2898,11 +3182,12 @@ /* Step the cursor in y, always by enough to cross a scanline. */ static inline void -cursor_always_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) +cursor_always_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id, int skip) { int iy = fixed2int(cr->y) - cr->base; - cursor_output_tr(cr, iy); + if (!skip) + cursor_output_tr(cr, iy); cr->y += dy; cr->left = x; cr->lid = id; @@ -2990,17 +3275,22 @@ cr->rid = id; } -static inline void cursor_down_tr(cursor_tr * gs_restrict cr, fixed x, int id) +static inline int cursor_down_tr(cursor_tr * gs_restrict cr, fixed x, int id) { + int skip = 0; + if ((cr->y & 0xff) == 0) + skip = 1; if (cr->d == DIRN_UP) { - cursor_output_tr(cr, fixed2int(cr->y) - cr->base); + if (!skip) + cursor_output_tr(cr, fixed2int(cr->y) - cr->base); cr->left = x; cr->lid = id; cr->right = x; cr->rid = id; } cr->d = DIRN_DOWN; + return skip; } static inline void cursor_up_tr(cursor_tr * gs_restrict cr, fixed x, int id) @@ -3026,6 +3316,11 @@ * rectangle from the start point. */ if (cr->first) { int iy = fixed2int(cr->y) - cr->base; + /* Any zero height rectangle counts as filled, except + * those on the baseline of a pixel. */ + if (cr->d == DIRN_UNSET && (cr->y & 0xff) == 0) + return; + assert(cr->left != max_int_in_fixed && cr->right != min_int_in_fixed); if (iy >= 0 && iy < cr->scanlines) { int *row = &cr->table[cr->index[iy]]; int count = *row = (*row)+2; /* Increment the count */ @@ -3071,6 +3366,14 @@ } } +static inline void +cursor_null_tr(cursor_tr *cr) +{ + cr->right = min_int_in_fixed; + cr->left = max_int_in_fixed; + cr->d = DIRN_UNSET; +} + static void mark_line_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fixed ex, fixed ey, int id) { int isy, iey; @@ -3079,7 +3382,7 @@ fixed saved_ey = ey; int truncated; - if (sx == ex && sy == ey) + if (sy == ey && sx == ex) return; isy = fixed2int(sy) - cr->base; @@ -3096,17 +3399,27 @@ dlprintf("stroke %%PS\n"); #endif - assert(cr->y == sy && cr->left <= sx && cr->right >= sx && cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); + /* Horizontal motion at the bottom of a pixel is ignored */ + if (sy == ey && (sy & 0xff) == 0) + return; + + assert(cr->y == sy && + ((cr->left <= sx && cr->right >= sx) || ((sy & 0xff) == 0)) && + cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); if (isy < iey) { /* Rising line */ if (iey < 0 || isy >= cr->scanlines) { /* All line is outside. */ + if ((ey & 0xff) == 0) { + cursor_null_tr(cr); + } else { + cr->left = ex; + cr->lid = id; + cr->right = ex; + cr->rid = id; + } cr->y = ey; - cr->left = ex; - cr->lid = id; - cr->right = ex; - cr->rid = id; cr->first = 0; return; } @@ -3117,7 +3430,8 @@ int64_t dy = (int64_t)new_sy - (int64_t)sy; sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); sy = new_sy; - cursor_init_tr(cr, sy, sx, id); + cursor_null_tr(cr); + cr->y = sy; isy = 0; } truncated = iey > cr->scanlines; @@ -3136,11 +3450,15 @@ /* Falling line */ if (isy < 0 || iey >= cr->scanlines) { /* All line is outside. */ + if ((ey & 0xff) == 0) { + cursor_null_tr(cr); + } else { + cr->left = ex; + cr->lid = id; + cr->right = ex; + cr->rid = id; + } cr->y = ey; - cr->left = ex; - cr->lid = id; - cr->right = ex; - cr->rid = id; cr->first = 0; return; } @@ -3161,11 +3479,15 @@ int64_t dy = (int64_t)new_sy - (int64_t)sy; sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); sy = new_sy; - cursor_init_tr(cr, sy, sx, id); + cursor_null_tr(cr); + cr->y = sy; isy = cr->scanlines; } } + cursor_left_merge_tr(cr, sx, id); + cursor_right_merge_tr(cr, sx, id); + assert(cr->left <= sx); assert(cr->right >= sx); assert(cr->y == sy); @@ -3193,20 +3515,40 @@ if (isy == iey) { if (saved_sy == saved_ey) { /* Horizontal line. Don't change cr->d, don't flush. */ + if ((ey & 0xff) == 0) { + cursor_null_tr(cr); + goto no_merge; + } } else if (saved_sy > saved_ey) { /* Falling line, flush if previous was rising */ - cursor_down_tr(cr, sx, id); + int skip = cursor_down_tr(cr, sx, id); + if ((ey & 0xff) == 0) { + /* We are falling to the baseline of a subpixel, so output + * for the current pixel, and leave the cursor nulled. */ + if (sx <= ex) { + cursor_right_merge_tr(cr, ex, id); + } else { + cursor_left_merge_tr(cr, ex, id); + } + if (!skip) + cursor_output_tr(cr, fixed2int(cr->y) - cr->base); + cursor_null_tr(cr); + goto no_merge; + } } else { /* Rising line, flush if previous was falling */ cursor_up_tr(cr, sx, id); + if ((ey & 0xff) == 0) { + cursor_null_tr(cr); + goto no_merge; + } } if (sx <= ex) { - cursor_left_merge_tr(cr, sx, id); cursor_right_merge_tr(cr, ex, id); } else { cursor_left_merge_tr(cr, ex, id); - cursor_right_merge_tr(cr, sx, id); } +no_merge: cr->y = ey; if (sy > saved_ey) goto endFalling; @@ -3228,16 +3570,16 @@ /* Vertical line. (Rising) */ /* Phase 1: */ - cursor_left_merge_tr(cr, sx, id); - cursor_right_merge_tr(cr, sx, id); if (phase1_y_steps) { /* If phase 1 will move us into a new scanline, then we must * flush it before we move. */ - cursor_step_tr(cr, phase1_y_steps, sx, id); + cursor_step_tr(cr, phase1_y_steps, sx, id, 0); sy += phase1_y_steps; y_steps -= phase1_y_steps; - if (y_steps == 0) + if (y_steps == 0) { + cursor_null_tr(cr); goto end; + } } /* Phase 3: precalculation */ @@ -3247,7 +3589,7 @@ y_steps = fixed2int(y_steps); assert(y_steps >= 0); if (y_steps > 0) { - cursor_always_step_tr(cr, fixed_1, sx, id); + cursor_always_step_tr(cr, fixed_1, sx, id, 0); y_steps--; while (y_steps) { cursor_always_step_inrange_vertical_tr(cr, fixed_1, sx, id); @@ -3257,24 +3599,28 @@ /* Phase 3 */ assert(cr->left == sx && cr->right == sx && cr->lid == id && cr->rid == id); - cr->y += phase3_y_steps; + if (phase3_y_steps == 0) + cursor_null_tr(cr); + else + cr->y += phase3_y_steps; } else if (sx < ex) { /* Lines increasing in x. (Rightwards, rising) */ int phase1_x_steps, phase3_x_steps; fixed x_steps = ex - sx; /* Phase 1: */ - cursor_left_merge_tr(cr, sx, id); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); sx += phase1_x_steps; cursor_right_merge_tr(cr, sx, id); x_steps -= phase1_x_steps; - cursor_step_tr(cr, phase1_y_steps, sx, id); + cursor_step_tr(cr, phase1_y_steps, sx, id, 0); sy += phase1_y_steps; y_steps -= phase1_y_steps; - if (y_steps == 0) + if (y_steps == 0) { + cursor_null_tr(cr); goto end; + } } /* Phase 3: precalculation */ @@ -3301,7 +3647,7 @@ if (f < 0) f += d, sx++; cursor_right_merge_tr(cr, sx, id); - cursor_always_step_tr(cr, fixed_1, sx, id); + cursor_always_step_tr(cr, fixed_1, sx, id, 0); y_steps--; while (y_steps) { @@ -3317,25 +3663,30 @@ /* Phase 3 */ assert(cr->left <= ex && cr->lid == id && cr->right >= sx); - cursor_right_tr(cr, ex, id); - cr->y += phase3_y_steps; + if (phase3_y_steps == 0) + cursor_null_tr(cr); + else { + cursor_right_tr(cr, ex, id); + cr->y += phase3_y_steps; + } } else { /* Lines decreasing in x. (Leftwards, rising) */ int phase1_x_steps, phase3_x_steps; fixed x_steps = sx - ex; /* Phase 1: */ - cursor_right_merge_tr(cr, sx, id); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); x_steps -= phase1_x_steps; sx -= phase1_x_steps; cursor_left_merge_tr(cr, sx, id); - cursor_step_tr(cr, phase1_y_steps, sx, id); + cursor_step_tr(cr, phase1_y_steps, sx, id, 0); sy += phase1_y_steps; y_steps -= phase1_y_steps; - if (y_steps == 0) + if (y_steps == 0) { + cursor_null_tr(cr); goto end; + } } /* Phase 3: precalculation */ @@ -3362,7 +3713,7 @@ if (f < 0) f += d, sx--; cursor_left_merge_tr(cr, sx, id); - cursor_always_step_tr(cr, fixed_1, sx, id); + cursor_always_step_tr(cr, fixed_1, sx, id, 0); y_steps--; while (y_steps) { @@ -3378,8 +3729,12 @@ /* Phase 3 */ assert(cr->right >= ex && cr->rid == id && cr->left <= sx); - cursor_left_tr(cr, ex, id); - cr->y += phase3_y_steps; + if (phase3_y_steps == 0) + cursor_null_tr(cr); + else { + cursor_left_tr(cr, ex, id); + cr->y += phase3_y_steps; + } } } else { /* So lines decreasing in y. */ @@ -3393,21 +3748,19 @@ int phase3_y_steps = (-ey) & (fixed_1 - 1); ufixed y_steps = (ufixed)sy - (ufixed)ey; - cursor_down_tr(cr, sx, id); + int skip = cursor_down_tr(cr, sx, id); if (sx == ex) { /* Vertical line. (Falling) */ /* Phase 1: */ - cursor_left_merge_tr(cr, sx, id); - cursor_right_merge_tr(cr, sx, id); if (phase1_y_steps) { /* Phase 1 in a falling line never moves us into a new scanline. */ cursor_never_step_vertical_tr(cr, -phase1_y_steps, sx, id); sy -= phase1_y_steps; y_steps -= phase1_y_steps; if (y_steps == 0) - goto endFalling; + goto endFallingLeftOnEdgeOfPixel; } /* Phase 3: precalculation */ @@ -3418,7 +3771,8 @@ y_steps = fixed2int(y_steps); assert(y_steps >= 0); if (y_steps) { - cursor_always_step_tr(cr, -fixed_1, sx, id); + cursor_always_step_tr(cr, -fixed_1, sx, id, skip); + skip = 0; y_steps--; while (y_steps) { cursor_always_step_inrange_vertical_tr(cr, -fixed_1, sx, id); @@ -3427,8 +3781,12 @@ } /* Phase 3 */ - if (phase3_y_steps > 0) { - cursor_step_tr(cr, -phase3_y_steps, sx, id); + if (phase3_y_steps == 0) { +endFallingLeftOnEdgeOfPixel: + cursor_always_step_inrange_vertical_tr(cr, 0, sx, id); + cursor_null_tr(cr); + } else { + cursor_step_tr(cr, -phase3_y_steps, sx, id, skip); assert(cr->left == sx && cr->lid == id && cr->right == sx && cr->rid == id); } } else if (sx < ex) { @@ -3437,7 +3795,6 @@ fixed x_steps = ex - sx; /* Phase 1: */ - cursor_left_merge_tr(cr, sx, id); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); x_steps -= phase1_x_steps; @@ -3447,9 +3804,8 @@ sy -= phase1_y_steps; y_steps -= phase1_y_steps; if (y_steps == 0) - goto endFalling; - } else - cursor_right_merge_tr(cr, sx, id); + goto endFallingRightOnEdgeOfPixel; + } /* Phase 3: precalculation */ phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); @@ -3468,7 +3824,8 @@ int f = y_steps/2; int d = y_steps; - cursor_always_step_tr(cr, -fixed_1, sx, id); + cursor_always_step_tr(cr, -fixed_1, sx, id, skip); + skip = 0; sx += x_inc; f -= n_inc; if (f < 0) @@ -3488,8 +3845,12 @@ } /* Phase 3 */ - if (phase3_y_steps > 0) { - cursor_step_tr(cr, -phase3_y_steps, sx, id); + if (phase3_y_steps == 0) { +endFallingRightOnEdgeOfPixel: + cursor_always_step_inrange_vertical_tr(cr, 0, sx, id); + cursor_null_tr(cr); + } else { + cursor_step_tr(cr, -phase3_y_steps, sx, id, skip); cursor_right_tr(cr, ex, id); assert(cr->left == sx && cr->lid == id && cr->right == ex && cr->rid == id); } @@ -3499,7 +3860,6 @@ fixed x_steps = sx - ex; /* Phase 1: */ - cursor_right_merge_tr(cr, sx, id); if (phase1_y_steps) { phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); x_steps -= phase1_x_steps; @@ -3509,9 +3869,8 @@ sy -= phase1_y_steps; y_steps -= phase1_y_steps; if (y_steps == 0) - goto endFalling; - } else - cursor_left_merge_tr(cr, sx, id); + goto endFallingVerticalOnEdgeOfPixel; + } /* Phase 3: precalculation */ phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); @@ -3530,7 +3889,8 @@ int f = y_steps/2; int d = y_steps; - cursor_always_step_tr(cr, -fixed_1, sx, id); + cursor_always_step_tr(cr, -fixed_1, sx, id, skip); + skip = 0; sx -= x_inc; f -= n_inc; if (f < 0) @@ -3550,17 +3910,17 @@ } /* Phase 3 */ - if (phase3_y_steps > 0) { - cursor_step_tr(cr, -phase3_y_steps, sx, id); + if (phase3_y_steps == 0) { +endFallingVerticalOnEdgeOfPixel: + cursor_always_step_inrange_vertical_tr(cr, 0, sx, id); + cursor_null_tr(cr); + } else { + cursor_step_tr(cr, -phase3_y_steps, sx, id, skip); cursor_left_tr(cr, ex, id); assert(cr->left == ex && cr->lid == id && cr->right == sx && cr->rid == id); } } -endFalling: - if (truncated) - { - cursor_output_tr(cr, fixed2int(cr->y) - cr->base); - } +endFalling: {} } end: @@ -3645,6 +4005,20 @@ return make_table_template(pdev, path, ibox, 4, 0, scanlines, index, table); } +static void +fill_zero_app_tr(int *row, const fixed *x) +{ + int n = *row = (*row)+2; /* Increment the count */ + row[4*n-7] = x[0]; + row[4*n-6] = 0; + row[4*n-5] = x[1]; + row[4*n-4] = 0; + row[4*n-3] = x[1]; + row[4*n-2] = (1<<1)|1; + row[4*n-1] = x[1]; + row[4*n ] = 1; +} + int gx_scan_convert_tr_app(gx_device * gs_restrict pdev, gx_path * gs_restrict path, const gs_fixed_rect * gs_restrict clip, @@ -3652,6 +4026,7 @@ fixed fixed_flat) { gs_fixed_rect ibox; + gs_fixed_rect bbox; int scanlines; const subpath *psub; int *index; @@ -3660,6 +4035,7 @@ cursor_tr cr; int code; int id = 0; + int zero; edgebuffer->index = NULL; edgebuffer->table = NULL; @@ -3668,9 +4044,9 @@ if (path->first_subpath == NULL) return 0; - code = make_bbox(path, clip, &ibox, 0); - if (code < 0) - return code; + zero = make_bbox(path, clip, &bbox, &ibox, 0); + if (zero < 0) + return zero; if (ibox.q.y <= ibox.p.y) return 0; @@ -3679,6 +4055,10 @@ if (code < 0) return code; + if (zero) { + code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero_app_tr); + } else { + /* Step 2 continued: Now we run through the path, filling in the real * values. */ cr.scanlines = scanlines; @@ -3693,7 +4073,12 @@ fixed iy = ey; fixed sx, sy; - cr.left = cr.right = ex; + if ((ey & 0xff) == 0) { + cr.left = max_int_in_fixed; + cr.right = min_int_in_fixed; + } else { + cr.left = cr.right = ex; + } cr.lid = cr.rid = id+1; cr.y = ey; cr.d = DIRN_UNSET; @@ -3733,6 +4118,7 @@ cursor_flush_tr(&cr, ex, id); psub = (const subpath *)pseg; } + } /* Step 2 complete: We now have a complete list of intersection data in * table, indexed by index. */ diff -Nru ghostscript-9.25~dfsg+1/base/lib.mak ghostscript-9.26~dfsg+0/base/lib.mak --- ghostscript-9.25~dfsg+1/base/lib.mak 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/lib.mak 2018-11-20 09:59:43.000000000 +0000 @@ -3313,32 +3313,112 @@ $(CP_) $(GLGEN)xpsromfs0_$(UFST_BRIDGE).c $(GLGEN)xpsromfs0.c # pdl -$(GLGEN)pdlromfs1_.c : $(MKROMFS_XE) $(PS_ROMFS_DEPS) $(LIB_MAK) $(MAKEDIRS) - $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs1_.c \ +# We generate the pdl romfs in index + 4 lumps because of size + +# COMPILE_INITS + Non UFST variant +$(GLGEN)pdlromfs1_c0.c : $(GLGEN)pdlromfs1_.c + $(NO_OP) + +$(GLGEN)pdlromfs1_c1.c : $(GLGEN)pdlromfs1_.c + $(NO_OP) + +$(GLGEN)pdlromfs1_c2.c : $(GLGEN)pdlromfs1_.c + $(NO_OP) + +$(GLGEN)pdlromfs1_c3.c : $(GLGEN)pdlromfs1_.c + $(NO_OP) + +$(GLGEN)pdlromfs1_.c: $(MKROMFS_XE) $(PS_ROMFS_DEPS) $(LIB_MAK) $(MAKEDIRS) + $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs1_.c -s 4 \ -X .svn -X CVS -P $(GLSRCDIR)$(D)..$(D) iccprofiles$(D)* \ $(PCLXL_ROMFS_ARGS) $(PCLXL_FONT_ROMFS_ARGS) $(PJL_ROMFS_ARGS) \ $(XPS_ROMFS_ARGS) $(XPS_FONT_ROMFS_ARGS) \ $(PS_ROMFS_ARGS) $(PS_FONT_ROMFS_ARGS) $(GL_ROMFS_ARGS) -$(GLGEN)pdlromfs1_1.c : $(MKROMFS_XE) $(PS_ROMFS_DEPS) $(LIB_MAK) $(MAKEDIRS) - $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs1_1.c \ +# COMPILE_INITS + UFST variant +$(GLGEN)pdlromfs1_1c0.c : $(GLGEN)pdlromfs1_1.c + $(NO_OP) + +$(GLGEN)pdlromfs1_1c1.c : $(GLGEN)pdlromfs1_1.c + $(NO_OP) + +$(GLGEN)pdlromfs1_1c2.c : $(GLGEN)pdlromfs1_1.c + $(NO_OP) + +$(GLGEN)pdlromfs1_1c3.c : $(GLGEN)pdlromfs1_1.c + $(NO_OP) + +$(GLGEN)pdlromfs1_1.c: $(MKROMFS_XE) $(PS_ROMFS_DEPS) $(LIB_MAK) $(MAKEDIRS) + $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs1_1.c -s 4 \ -X .svn -X CVS -P $(GLSRCDIR)$(D)..$(D) iccprofiles$(D)* \ $(UFST_ROMFS_ARGS) $(PCLXL_ROMFS_ARGS) $(PJL_ROMFS_ARGS) $(XPS_ROMFS_ARGS) \ $(PS_ROMFS_ARGS) $(GL_ROMFS_ARGS) +# Rules to fold COMPILE_INITS +/- UFST into 1 set of targets +$(GLGEN)pdlromfs1c0.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c0.c + $(CP_) $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c0.c $(GLGEN)pdlromfs1c0.c + +$(GLGEN)pdlromfs1c1.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c1.c + $(CP_) $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c1.c $(GLGEN)pdlromfs1c1.c + +$(GLGEN)pdlromfs1c2.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c2.c + $(CP_) $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c2.c $(GLGEN)pdlromfs1c2.c + +$(GLGEN)pdlromfs1c3.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c3.c + $(CP_) $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c3.c $(GLGEN)pdlromfs1c3.c + $(GLGEN)pdlromfs1.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE).c $(LIB_MAK) $(MAKEDIRS) $(CP_) $(GLGEN)pdlromfs1_$(UFST_BRIDGE).c $(GLGEN)pdlromfs1.c +# Non COMPILE_INITS + Non UFST variant +$(GLGEN)pdlromfs0_c0.c : $(GLGEN)pdlromfs0_.c + $(NO_OP) + +$(GLGEN)pdlromfs0_c1.c : $(GLGEN)pdlromfs0_.c + $(NO_OP) + +$(GLGEN)pdlromfs0_c2.c : $(GLGEN)pdlromfs0_.c + $(NO_OP) + +$(GLGEN)pdlromfs0_c3.c : $(GLGEN)pdlromfs0_.c + $(NO_OP) + $(GLGEN)pdlromfs0_.c : $(MKROMFS_XE) $(LIB_MAK) $(MAKEDIRS) - $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs0_.c \ + $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs0_.c -s 4 \ -X .svn -X CVS -P $(GLSRCDIR)$(D)..$(D) iccprofiles$(D)* \ $(GL_ROMFS_ARGS) +# Non COMPILE_INITS + UFST variant +$(GLGEN)pdlromfs0_1c0.c : $(GLGEN)pdlromfs0_1.c + $(NO_OP) + +$(GLGEN)pdlromfs0_1c1.c : $(GLGEN)pdlromfs0_1.c + $(NO_OP) + +$(GLGEN)pdlromfs0_1c2.c : $(GLGEN)pdlromfs0_1.c + $(NO_OP) + +$(GLGEN)pdlromfs0_1c3.c : $(GLGEN)pdlromfs0_1.c + $(NO_OP) + $(GLGEN)pdlromfs0_1.c : $(MKROMFS_XE) $(LIB_MAK) $(MAKEDIRS) - $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs0_1.c \ + $(EXP)$(MKROMFS_XE) -o $(GLGEN)pdlromfs0_1.c -s 4 \ -X .svn -X CVS -P $(GLSRCDIR)$(D)..$(D) iccprofiles$(D)* \ $(GL_ROMFS_ARGS) +# Rules to fold Non COMPILE_INITS +/- UFST into 1 set of targets +$(GLGEN)pdlromfs0c0.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c0.c + $(CP_) $(GLGEN)pdlromfs0_$(UFST_BRIDGE)c0.c $(GLGEN)pdlromfs0c0.c + +$(GLGEN)pdlromfs0c1.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c1.c + $(CP_) $(GLGEN)pdlromfs0_$(UFST_BRIDGE)c1.c $(GLGEN)pdlromfs0c1.c + +$(GLGEN)pdlromfs0c2.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c2.c + $(CP_) $(GLGEN)pdlromfs0_$(UFST_BRIDGE)c2.c $(GLGEN)pdlromfs0c2.c + +$(GLGEN)pdlromfs0c3.c : $(GLGEN)pdlromfs1_$(UFST_BRIDGE)c3.c + $(CP_) $(GLGEN)pdlromfs0_$(UFST_BRIDGE)c3.c $(GLGEN)pdlromfs0c3.c + $(GLGEN)pdlromfs0.c : $(GLGEN)pdlromfs0_$(UFST_BRIDGE).c $(LIB_MAK) $(MAKEDIRS) $(CP_) $(GLGEN)pdlromfs0_$(UFST_BRIDGE).c $(GLGEN)pdlromfs0.c @@ -3384,9 +3464,33 @@ $(GLOBJ)pdlromfs0.$(OBJ) : $(GLGEN)pdlromfs0.c $(stdint__h) $(LIB_MAK) $(MAKEDIRS) $(GLCC) $(GLO_)pdlromfs0.$(OBJ) $(C_) $(GLGEN)pdlromfs0.c +$(GLOBJ)pdlromfs0c0.$(OBJ) : $(GLGEN)pdlromfs0c0.c $(stdint__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs0c0.$(OBJ) $(C_) $(GLGEN)pdlromfs0c0.c + +$(GLOBJ)pdlromfs0c1.$(OBJ) : $(GLGEN)pdlromfs0c0.c $(stdint__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs0c1.$(OBJ) $(C_) $(GLGEN)pdlromfs0c1.c + +$(GLOBJ)pdlromfs0c2.$(OBJ) : $(GLGEN)pdlromfs0c0.c $(stdint__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs0c2.$(OBJ) $(C_) $(GLGEN)pdlromfs0c2.c + +$(GLOBJ)pdlromfs0c3.$(OBJ) : $(GLGEN)pdlromfs0c0.c $(stdint__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs0c3.$(OBJ) $(C_) $(GLGEN)pdlromfs0c3.c + $(GLOBJ)pdlromfs1.$(OBJ) : $(GLOBJ)pdlromfs1.c $(time__h) $(LIB_MAK) $(MAKEDIRS) $(GLCC) $(GLO_)pdlromfs1.$(OBJ) $(C_) $(GLOBJ)pdlromfs1.c +$(GLOBJ)pdlromfs1c0.$(OBJ) : $(GLOBJ)pdlromfs1c0.c $(time__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs1c0.$(OBJ) $(C_) $(GLOBJ)pdlromfs1c0.c + +$(GLOBJ)pdlromfs1c1.$(OBJ) : $(GLOBJ)pdlromfs1c1.c $(time__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs1c1.$(OBJ) $(C_) $(GLOBJ)pdlromfs1c1.c + +$(GLOBJ)pdlromfs1c2.$(OBJ) : $(GLOBJ)pdlromfs1c2.c $(time__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs1c2.$(OBJ) $(C_) $(GLOBJ)pdlromfs1c2.c + +$(GLOBJ)pdlromfs1c3.$(OBJ) : $(GLOBJ)pdlromfs1c3.c $(time__h) $(LIB_MAK) $(MAKEDIRS) + $(GLCC) $(GLO_)pdlromfs1c3.$(OBJ) $(C_) $(GLOBJ)pdlromfs1c3.c + # Define the ZLIB modules needed by mnkromfs here to factor it out of top makefiles # Also put the .h dependencies here for the same reason MKROMFS_ZLIB_OBJS=$(AUX)compress.$(OBJ) $(AUX)deflate.$(OBJ) \ diff -Nru ghostscript-9.25~dfsg+1/base/mkromfs.c ghostscript-9.26~dfsg+0/base/mkromfs.c --- ghostscript-9.25~dfsg+1/base/mkromfs.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/mkromfs.c 2018-11-20 09:59:43.000000000 +0000 @@ -61,6 +61,7 @@ * For performance reasons, it is best to turn off compression * for the init file. Less frequently accessed files, if they * are large should still be compressed. + * -s num_files split the output into subfiles. * */ @@ -117,6 +118,13 @@ char *path; } Xlist_element; +typedef struct { + int num_splits; + int max_splits; + unsigned long *sizes; + char *outname; + char *outname_formatted; +} split_data; #define PATH_STR_LEN 1024 @@ -348,13 +356,11 @@ void put_uint32(FILE *out, const unsigned int q); void put_bytes_padded(FILE *out, unsigned char *p, unsigned int len); void inode_clear(romfs_inode* node); -void inode_write(FILE *out, romfs_inode *node, int compression, int inode_count, int*totlen); +void inode_write(FILE *out, romfs_inode *node, int compression, int inode_count, int*totlen, split_data *splits); void process_path(char *path, const char *os_prefix, const char *rom_prefix, Xlist_element *Xlist_head, int compression, - int compaction, int *inode_count, int *totlen, FILE *out); -int process_initfile(char *initfile, char *gconfig_h, const char *os_prefix, - const char *rom_prefix, - int compression, int *inode_count, int *totlen, FILE *out); + int compaction, int *inode_count, int *totlen, FILE *out, + split_data *splits); FILE *prefix_open(const char *os_prefix, const char *inname); void prefix_add(const char *prefix, const char *filename, char *prefixed_path); @@ -433,9 +439,8 @@ } } -/* write out and inode and its file data */ -void -inode_write(FILE *out, romfs_inode *node, int compression, int inode_count, int *totlen) +static unsigned long +do_inode_write(FILE *out, romfs_inode *node, int compression, int inode_count, int *totlen, int split) { int i, offset; int blocks = (node->length+ROMFS_BLOCKSIZE-1)/ROMFS_BLOCKSIZE; @@ -443,7 +448,10 @@ int clen = 0; /* compressed length */ /* write the node header */ - fprintf(out," static uint32_t node_%d[] = {\n\t", inode_count); + fprintf(out," %s const uint32_t %snode_%d[] = {\n\t", + split ? "" : "static", + split ? "mkromfs_" : "", + inode_count); /* 4 byte file length + compression flag in high bit */ put_uint32(out, node->length | (compression ? 0x80000000 : 0)); fprintf(out, "\t/* compression_flag_bit + file length */\n\t"); @@ -475,6 +483,68 @@ printf(", compressed size=%d", clen); } printf("\n"); + if (compression) + return clen; + return node->length; +} + +static void +prepare_splits(split_data *splits) +{ + if (splits->num_splits) { + /* Make sure we have a properly sized size array. */ + if (splits->num_splits > splits->max_splits) { + unsigned long *sizes = realloc(splits->sizes, sizeof(unsigned long) * splits->num_splits); + if (sizes == NULL) { + fprintf(stderr, "Failed to allocate split data array\n"); + exit(1); + } + memset(&sizes[splits->max_splits], 0, sizeof(unsigned long) * (splits->num_splits - splits->max_splits)); + splits->sizes = sizes; + splits->max_splits = splits->num_splits; + } + } +} + +static void +start_file(FILE *out) +{ + fprintf(out,"\t/* Generated data for %%rom%% device, see mkromfs.c */\n"); +#if ARCH_IS_BIG_ENDIAN + fprintf(out,"\t/* this code assumes a big endian target platform */\n"); +#else + fprintf(out,"\t/* this code assumes a little endian target platform */\n"); +#endif + fprintf(out,"\n#include \"stdint_.h\"\n"); + fprintf(out,"\n#include \"time_.h\"\n\n"); +} + +/* write out an inode and its file data */ +void +inode_write(FILE *out, romfs_inode *node, int compression, int inode_count, int *totlen, split_data *splits) +{ + prepare_splits(splits); + if (splits->max_splits) { + /* Find the smallest bin to add this to. */ + FILE *out2; + int which = 0; + int i; + for (i = 1; i < splits->max_splits; i++) { + if (splits->sizes[which] > splits->sizes[i]) + which = i; + } + + sprintf(splits->outname_formatted, splits->outname, which); + if (splits->sizes[which] == 0) { + out2 = fopen(splits->outname_formatted, "w"); + start_file(out2); + } else { + out2 = fopen(splits->outname_formatted, "a"); + } + splits->sizes[which] += do_inode_write(out2, node, compression, inode_count, totlen, 1); + fclose(out2); + } else + (void)do_inode_write(out, node, compression, inode_count, totlen, 0); } void @@ -1568,7 +1638,8 @@ /* paths are checked to see if they are an ordinary file or a path */ void process_path(char *path, const char *os_prefix, const char *rom_prefix, Xlist_element *Xlist_head, int compression, - int compaction, int *inode_count, int *totlen, FILE *out) + int compaction, int *inode_count, int *totlen, FILE *out, + split_data *splits) { int i, namelen, excluded, save_count=*inode_count; Xlist_element *Xlist_scan; @@ -1699,8 +1770,9 @@ pscompact_end(&psc); node->length = psc_len; } + /* write out data for this file */ - inode_write(out, node, compression, *inode_count, totlen); + inode_write(out, node, compression, *inode_count, totlen, splits); /* clean up */ inode_clear(node); free(node); @@ -1792,10 +1864,10 @@ return ibf->eof; } -int +static int process_initfile(char *initfile, char *gconfig_h, const char *os_prefix, const char *rom_prefix, int compression, int *inode_count, - int *totlen, FILE *out) + int *totlen, FILE *out, split_data *splits) { int ret, block, blocks; romfs_inode *node = NULL; @@ -1919,7 +1991,7 @@ } /* write data for this file */ - inode_write(out, node, compression, *inode_count, totlen); + inode_write(out, node, compression, *inode_count, totlen, splits); /* clean up */ inode_clear(node); (*inode_count)++; @@ -2312,6 +2384,43 @@ mergefile(os_prefix, inname, in, config, false); } +static void +make_split_name(split_data *splits, const char *filename) +{ + const char *s = filename; + const char *t = NULL; + char *u; + + while (*s) { + if (*s == '.') + t = s; + s++; + } + if (t == NULL) + t = s; + + free(splits->outname); + splits->outname = u = malloc(s-filename+4); + if (u == NULL) { + fprintf(stderr, "malloc failure while constructing split filename\n"); + exit(1); + } + memcpy(u, filename, t-filename); + u[t-filename] = 'c'; + u[t-filename+1] = '%'; + u[t-filename+2] = 'd'; + if (s-t) + memcpy(u+(t-filename)+3, t, s-t); + u[s-filename+3] = 0; + + free(splits->outname_formatted); + splits->outname_formatted = malloc(s-filename+4+32); + if (splits->outname_formatted == NULL) { + fprintf(stderr, "malloc failure while constructing split filename\n"); + exit(1); + } +} + int main(int argc, char *argv[]) { @@ -2328,6 +2437,7 @@ char pa[PATH_STR_LEN]; time_t buildtime = 0; char* env_source_date_epoch; + split_data splits = { 0 } ; memset(pa, 0x00, PATH_STR_LEN); @@ -2376,14 +2486,7 @@ printf(" writing romfs data to '%s'\n", outfilename); out = fopen(outfilename, "w"); - fprintf(out,"\t/* Generated data for %%rom%% device, see mkromfs.c */\n"); -#if ARCH_IS_BIG_ENDIAN - fprintf(out,"\t/* this code assumes a big endian target platform */\n"); -#else - fprintf(out,"\t/* this code assumes a little endian target platform */\n"); -#endif - fprintf(out,"\n#include \"stdint_.h\"\n"); - fprintf(out,"\n#include \"time_.h\"\n\n"); + start_file(out); if ((env_source_date_epoch = getenv("SOURCE_DATE_EPOCH"))) { buildtime = strtoul(env_source_date_epoch, NULL, 10); @@ -2416,6 +2519,18 @@ } rom_prefix = argv[atarg]; break; + case 's': + if (++atarg == argc) { + printf(" option %s missing required argument\n", argv[atarg-1]); + exit(1); + } + splits.num_splits = atoi(argv[atarg]); + if (splits.num_splits <= 0) { + printf(" Invalid number of files to split to: %s\n", argv[atarg]); + exit(1); + } + make_split_name(&splits, outfilename); + break; case 'g': { char initfile[PATH_STR_LEN] = {0}; @@ -2428,7 +2543,7 @@ atarg++; strncpy(gconfig_h, argv[atarg], PATH_STR_LEN - 1); process_initfile(initfile, gconfig_h, os_prefix, rom_prefix, compression, - &inode_count, &totlen, out); + &inode_count, &totlen, out, &splits); } break; case 'P': @@ -2459,12 +2574,30 @@ /* process a path or file */ strncpy(pa, argv[atarg], PATH_STR_LEN - (strlen(os_prefix) < strlen(rom_prefix) ? strlen(rom_prefix) : strlen(os_prefix))); process_path(pa, os_prefix, rom_prefix, Xlist_head, - compression, compaction, &inode_count, &totlen, out); + compression, compaction, &inode_count, &totlen, out, &splits); + } + + /* Now allow for the (probably never happening) case where we are splitting, but haven't written anything to one of the files */ + prepare_splits(&splits); + for (i = 0; i < splits.max_splits; i++) { + if (splits.sizes[i] == 0) { + FILE *out2; + sprintf(splits.outname_formatted, splits.outname, i); + out2 = fopen(splits.outname_formatted, "w"); + fprintf(out2, "const int mkromfs_dummy_chunk%d;\n", i); + fclose(out2); + } } + + if (splits.max_splits) { + for (i=0; itemplat = &s_DCTD_template; } } + +void +stream_dct_end_passthrough(jpeg_decompress_data *jddp) +{ + char EOI[2] = {0xff, 0xD9}; + + if (jddp->PassThrough && jddp->PassThroughfn) { + (jddp->PassThroughfn)(jddp->device, (byte *)EOI, 2); + (jddp->PassThroughfn)(jddp->device, NULL, 0); + jddp->PassThrough = 0; + jddp->PassThroughfn = NULL; + } +} diff -Nru ghostscript-9.25~dfsg+1/base/sdctd.c ghostscript-9.26~dfsg+0/base/sdctd.c --- ghostscript-9.25~dfsg+1/base/sdctd.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/sdctd.c 2018-11-20 09:59:43.000000000 +0000 @@ -70,19 +70,15 @@ src->bytes_in_buffer -= num_bytes; } } + static void dctd_term_source(j_decompress_ptr dinfo) { - char EOI[2] = {0xff, 0xD9}; - jpeg_decompress_data *jddp = (jpeg_decompress_data *) ((char *)dinfo - offset_of(jpeg_decompress_data, dinfo)); - if (jddp->PassThrough && jddp->PassThroughfn) { - (jddp->PassThroughfn)(jddp->device, (byte *)EOI, 2); - (jddp->PassThroughfn)(jddp->device, NULL, 0); - } + stream_dct_end_passthrough(jddp); return; } diff -Nru ghostscript-9.25~dfsg+1/base/sdct.h ghostscript-9.26~dfsg+0/base/sdct.h --- ghostscript-9.25~dfsg+1/base/sdct.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/sdct.h 2018-11-20 09:59:43.000000000 +0000 @@ -156,4 +156,7 @@ /* Clients do not call this. */ void s_DCT_set_defaults(stream_state * st); +void +stream_dct_end_passthrough(jpeg_decompress_data *jddp); + #endif /* sdct_INCLUDED */ diff -Nru ghostscript-9.25~dfsg+1/base/sjbig2.c ghostscript-9.26~dfsg+0/base/sjbig2.c --- ghostscript-9.25~dfsg+1/base/sjbig2.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/sjbig2.c 2018-11-20 09:59:43.000000000 +0000 @@ -66,10 +66,61 @@ if (error_data) { - if (severity == JBIG2_SEVERITY_FATAL || severity == JBIG2_SEVERITY_WARNING) { - dmlprintf3(error_data->memory, "jbig2dec %s %s %s\n", type, msg, segment); - } else { - if_debug3m('w', error_data->memory, "[w] jbig2dec %s %s %s\n", type, msg, segment); + char *message; + int len; + + len = snprintf(NULL, 0, "jbig2dec %s %s %s", type, msg, segment); + if (len < 0) + return; + + message = (char *)gs_alloc_bytes(error_data->memory, len + 1, "sjbig2decode_error(message)"); + if (message == NULL) + return; + + len = snprintf(message, len + 1, "jbig2dec %s %s %s", type, msg, segment); + if (len < 0) + { + gs_free_object(error_data->memory, message, "s_jbig2decode_error(message)"); + return; + } + + if (error_data->last_message != NULL && strcmp(message, error_data->last_message)) { + if (error_data->repeats > 1) + { + if (error_data->severity == JBIG2_SEVERITY_FATAL || error_data->severity == JBIG2_SEVERITY_WARNING) { + dmlprintf1(error_data->memory, "jbig2dec last message repeated %ld times\n", error_data->repeats); + } else { + if_debug1m('w', error_data->memory, "[w] jbig2dec last message repeated %ld times\n", error_data->repeats); + } + } + gs_free_object(error_data->memory, error_data->last_message, "s_jbig2decode_error(last_message)"); + error_data->last_message = message; + error_data->severity = severity; + error_data->type = type; + error_data->repeats = 0; + } + else if (error_data->last_message != NULL) { + error_data->repeats++; + if (error_data->repeats % 1000000 == 0) + { + if (error_data->severity == JBIG2_SEVERITY_FATAL || error_data->severity == JBIG2_SEVERITY_WARNING) { + dmlprintf1(error_data->memory, "jbig2dec last message repeated %ld times so far\n", error_data->repeats); + } else { + if_debug1m('w', error_data->memory, "[w] jbig2dec last message repeated %ld times so far\n", error_data->repeats); + } + } + gs_free_object(error_data->memory, message, "s_jbig2decode_error(message)"); + } + else if (error_data->last_message == NULL) { + if (severity == JBIG2_SEVERITY_FATAL || severity == JBIG2_SEVERITY_WARNING) { + dmlprintf1(error_data->memory, "%s\n", message); + } else { + if_debug1m('w', error_data->memory, "[w] %s\n", message); + } + error_data->last_message = message; + error_data->severity = severity; + error_data->type = type; + error_data->repeats = 0; } } else @@ -86,6 +137,29 @@ } } +static void +s_jbig2decode_flush_errors(void *callback_data) +{ + s_jbig2_callback_data_t *error_data = (s_jbig2_callback_data_t *)callback_data; + + if (error_data == NULL) + return; + + if (error_data->last_message != NULL) { + if (error_data->repeats > 1) + { + if (error_data->severity == JBIG2_SEVERITY_FATAL || error_data->severity == JBIG2_SEVERITY_WARNING) { + dmlprintf1(error_data->memory, "jbig2dec last message repeated %ld times\n", error_data->repeats); + } else { + if_debug1m('w', error_data->memory, "[w] jbig2dec last message repeated %ld times\n", error_data->repeats); + } + } + gs_free_object(error_data->memory, error_data->last_message, "s_jbig2decode_error(last_message)"); + error_data->last_message = NULL; + error_data->repeats = 0; + } +} + /* invert the bits in a buffer */ /* jbig2 and postscript have different senses of what pixel value is black, so we must invert the image */ @@ -171,6 +245,8 @@ if (state->callback_data) { state->callback_data->memory = ss->memory->non_gc_memory; state->callback_data->error = 0; + state->callback_data->last_message = NULL; + state->callback_data->repeats = 0; /* initialize the decoder with the parsed global context if any */ state->decode_ctx = jbig2_ctx_new(NULL, JBIG2_OPTIONS_EMBEDDED, global_ctx, s_jbig2decode_error, state->callback_data); @@ -249,11 +325,13 @@ if (state->decode_ctx) { if (state->image) jbig2_release_page(state->decode_ctx, state->image); state->image = NULL; + s_jbig2decode_flush_errors(state->callback_data); jbig2_ctx_free(state->decode_ctx); state->decode_ctx = NULL; } if (state->callback_data) { gs_memory_t *mem = state->callback_data->memory; + gs_free_object(state->callback_data->memory, state->callback_data->last_message, "s_jbig2decode_release(message)"); gs_free_object(mem, state->callback_data, "s_jbig2decode_release(callback_data)"); state->callback_data = NULL; } diff -Nru ghostscript-9.25~dfsg+1/base/sjbig2.h ghostscript-9.26~dfsg+0/base/sjbig2.h --- ghostscript-9.25~dfsg+1/base/sjbig2.h 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/sjbig2.h 2018-11-20 09:59:43.000000000 +0000 @@ -28,6 +28,10 @@ { gs_memory_t *memory; int error; + char *last_message; + Jbig2Severity severity; + const char *type; + long repeats; } s_jbig2_callback_data_t; /* See zfjbig2.c for details. */ diff -Nru ghostscript-9.25~dfsg+1/base/sjpegd.c ghostscript-9.26~dfsg+0/base/sjpegd.c --- ghostscript-9.25~dfsg+1/base/sjpegd.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/sjpegd.c 2018-11-20 09:59:43.000000000 +0000 @@ -84,7 +84,11 @@ int gs_jpeg_finish_decompress(stream_DCT_state * st) { + int code = 0; if (setjmp(find_jmp_buf(st->data.common->exit_jmpbuf))) - return_error(gs_jpeg_log_error(st)); - return (int)jpeg_finish_decompress(&st->data.decompress->dinfo); + code = gs_note_error(gs_jpeg_log_error(st)); + if (code >= 0) + code = (int)jpeg_finish_decompress(&st->data.decompress->dinfo); + stream_dct_end_passthrough(st->data.decompress); + return code; } diff -Nru ghostscript-9.25~dfsg+1/base/sjpx_openjpeg.c ghostscript-9.26~dfsg+0/base/sjpx_openjpeg.c --- ghostscript-9.25~dfsg+1/base/sjpx_openjpeg.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/sjpx_openjpeg.c 2018-11-20 09:59:43.000000000 +0000 @@ -106,6 +106,9 @@ assert(opj_memory != NULL); + if (size > (size_t) ARCH_MAX_UINT) + return NULL; + return (void *)gs_alloc_bytes(opj_memory, size, "opj_malloc"); } diff -Nru ghostscript-9.25~dfsg+1/base/unixinst.mak ghostscript-9.26~dfsg+0/base/unixinst.mak --- ghostscript-9.25~dfsg+1/base/unixinst.mak 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/unixinst.mak 2018-11-20 09:59:43.000000000 +0000 @@ -146,25 +146,26 @@ install-iccdata1 : # install html documentation -DOC_PAGES=API.htm C-style.htm Develop.htm GS9_Color_Management.pdf Helpers.htm \ - History4.htm History9.htm Lib.htm Ps2pdf.htm Readme.htm Use.htm \ - AUTHORS Deprecated.htm Devices.htm GS9_Color_Management.tex\ - Hershey.htm History5.htm index.html Make.htm Ps2ps2.htm Release.htm \ - WhatIsGS.htm Changes.htm Details8.htm DLL.htm gs.css History1.htm \ - History6.htm Install.htm News.htm pscet_status.txt Source.htm \ - Commprod.htm Details9.htm Drivers.htm gsdoc.el History2.htm \ - History7.htm Issues.htm Projects.htm Psfiles.htm thirdparty.htm \ - COPYING Details.htm Fonts.htm gs-vms.hlp History3.htm History8.htm\ - Language.htm Ps2epsi.htm Ps-style.htm Unix-lpr.htm \ - sample_downscale_device.htm SavedPages.htm subclass.htm\ - VectorDevices.htm gdevds32.c +DOC_PAGES=index.html API.htm C-style.htm Develop.htm DLL.htm Fonts.htm Install.htm Lib.htm \ + News.htm Psfiles.htm Readme.htm sample_downscale_device.htm Source.htm \ + thirdparty.htm Use.htm WhatIsGS.htm Commprod.htm Deprecated.htm \ + Devices.htm Drivers.htm History9.htm Language.htm Make.htm Ps2epsi.htm \ + Ps-style.htm Release.htm SavedPages.htm subclass.htm Unix-lpr.htm \ + VectorDevices.htm gs-style.css index.js pscet_status.txt style.css \ + gdevds32.c \ + GS9_Color_Management.pdf +DOC_PAGE_IMAGES=Artifex_logo.png favicon.png ghostscript_logo.png hamburger-light.png x-light.png install-doc: $(PSDOCDIR)/News.htm -mkdir -p $(DESTDIR)$(docdir) + -mkdir -p $(DESTDIR)$(docdir)/images $(SH) -c 'for f in $(DOC_PAGES) ;\ do if ( test -f $(PSDOCDIR)/$$f ); then $(INSTALL_DATA) $(PSDOCDIR)/$$f $(DESTDIR)$(docdir); fi;\ done' + $(SH) -c 'for f in $(DOC_PAGE_IMAGES) ;\ + do if ( test -f $(PSDOCDIR)/images/$$f ); then $(INSTALL_DATA) $(PSDOCDIR)/images/$$f $(DESTDIR)$(docdir)/images; fi;\ + done' # install the man pages for each locale MAN_LCDIRS=. de diff -Nru ghostscript-9.25~dfsg+1/base/unixlink.mak ghostscript-9.26~dfsg+0/base/unixlink.mak --- ghostscript-9.25~dfsg+1/base/unixlink.mak 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/unixlink.mak 2018-11-20 09:59:43.000000000 +0000 @@ -124,13 +124,22 @@ GPDL_A=$(BINDIR)$(D)$(GPDL).a $(GPDL_A): $(GPDL_PSI_TOP_OBJS) $(PCL_PXL_TOP_OBJS) $(PSI_TOP_OBJ) $(XPS_TOP_OBJ) $(MAIN_OBJ) \ $(XOBJS) $(GLOBJDIR)/pdlromfs$(COMPILE_INITS).$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c0.$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c1.$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c2.$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c3.$(OBJ) \ $(PSINT_ARCHIVE_ALL) \ $(pdlobj_tr) $(ECHOGS_XE) $(INT_ARCHIVE_ALL) $(INT_ALL) $(DEVS_ALL) \ $(UNIXLINK_MAK) rm -f $(GPDL_A) $(ECHOGS_XE) -w $(libgpdl_tr) -n - $(AR) $(ARFLAGS) $(GPDL_A) $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(GPDL_PSI_TOP_OBJS) $(PCL_PXL_TOP_OBJS) $(PSI_TOP_OBJ) $(XPS_TOP_OBJ) $(XOBJS) -s - $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(GLOBJDIR)/pdlromfs$(COMPILE_INITS).$(OBJ) $(MAIN_OBJ) -s + $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(GLOBJDIR)/pdlromfs$(COMPILE_INITS).$(OBJ) -s + $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c0.$(OBJ) -s + $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c1.$(OBJ) -s + $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c2.$(OBJ) -s + $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c3.$(OBJ) -s + $(ECHOGS_XE) -a $(libgpdl_tr) -n -s $(MAIN_OBJ) -s cat $(pdlobj_tr) >>$(libgpdl_tr) $(ECHOGS_XE) -a $(libgpdl_tr) -s - $(SH) <$(libgpdl_tr) @@ -222,11 +231,20 @@ $(GPDL_XE): $(ld_tr) $(gpdl_tr) $(INT_ARCHIVE_ALL) $(REALMAIN_OBJ) $(MAIN_OBJ) \ $(GPDL_PSI_TOP_OBJS) $(PCL_PXL_TOP_OBJS) $(PSI_TOP_OBJ) $(XPS_TOP_OBJ) \ $(XOBJS) $(GLOBJDIR)/pdlromfs$(COMPILE_INITS).$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c0.$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c1.$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c2.$(OBJ) \ + $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c3.$(OBJ) \ $(PSINT_ARCHIVE_ALL) $(UNIXLINK_MAK) $(ECHOGS_XE) -w $(gpdlldt_tr) -n - $(CCLD) $(PDL_LDFLAGS) $(XLIBDIRS) -o $(GPDL_XE) $(ECHOGS_XE) -a $(gpdlldt_tr) -n -s $(GPDL_PSI_TOP_OBJS) $(PCL_PXL_TOP_OBJS) $(PSI_TOP_OBJ) $(XPS_TOP_OBJ) $(XOBJS) -s cat $(gpdlld_tr) >> $(gpdlldt_tr) - $(ECHOGS_XE) -a $(gpdlldt_tr) -s - $(GLOBJDIR)/pdlromfs$(COMPILE_INITS).$(OBJ) $(REALMAIN_OBJ) $(MAIN_OBJ) $(EXTRALIBS) $(STDLIBS) + $(ECHOGS_XE) -a $(gpdlldt_tr) -n -s - $(GLOBJDIR)/pdlromfs$(COMPILE_INITS).$(OBJ) + $(ECHOGS_XE) -a $(gpdlldt_tr) -n -s - $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c0.$(OBJ) + $(ECHOGS_XE) -a $(gpdlldt_tr) -n -s - $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c1.$(OBJ) + $(ECHOGS_XE) -a $(gpdlldt_tr) -n -s - $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c2.$(OBJ) + $(ECHOGS_XE) -a $(gpdlldt_tr) -n -s - $(GLOBJDIR)/pdlromfs$(COMPILE_INITS)c3.$(OBJ) + $(ECHOGS_XE) -a $(gpdlldt_tr) -s - $(REALMAIN_OBJ) $(MAIN_OBJ) $(EXTRALIBS) $(STDLIBS) if [ x$(XLIBDIR) != x ]; then LD_RUN_PATH=$(XLIBDIR); export LD_RUN_PATH; fi; \ XCFLAGS= XINCLUDE= XLDFLAGS= XLIBDIRS= XLIBS= \ PCL_FEATURE_DEVS= DEVICE_DEVS= DEVICE_DEVS1= DEVICE_DEVS2= DEVICE_DEVS3= \ diff -Nru ghostscript-9.25~dfsg+1/base/version.mak ghostscript-9.26~dfsg+0/base/version.mak --- ghostscript-9.25~dfsg+1/base/version.mak 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/base/version.mak 2018-11-20 09:59:43.000000000 +0000 @@ -15,10 +15,10 @@ # Major and minor version numbers. # MINOR0 is different from MINOR only if MINOR is a single digit. GS_VERSION_MAJOR=9 -GS_VERSION_MINOR=25 -GS_VERSION_MINOR0=25 +GS_VERSION_MINOR=26 +GS_VERSION_MINOR0=26 # Revision date: year x 10000 + month x 100 + day. -GS_REVISIONDATE=20180913 +GS_REVISIONDATE=20181120 # Derived values GS_VERSION=$(GS_VERSION_MAJOR)$(GS_VERSION_MINOR0) GS_DOT_VERSION=$(GS_VERSION_MAJOR).$(GS_VERSION_MINOR0) diff -Nru ghostscript-9.25~dfsg+1/contrib/gdevgdi.c ghostscript-9.26~dfsg+0/contrib/gdevgdi.c --- ghostscript-9.25~dfsg+1/contrib/gdevgdi.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/contrib/gdevgdi.c 2018-11-20 09:59:43.000000000 +0000 @@ -151,10 +151,13 @@ /* gdi_close is only here to eject odd numbered pages in duplex mode. */ static int gdi_close(gx_device *pdev) -{ if ( ppdev->Duplex_set >= 0 && ppdev->Duplex ) - { gdev_prn_open_printer(pdev, 1); - fputs("\033&l0H", ppdev->file) ; - } +{ + if ( ppdev->Duplex_set >= 0 && ppdev->Duplex ) + { + int code = gdev_prn_open_printer(pdev, 1); + if (code >= 0) + fputs("\033&l0H", ppdev->file) ; + } return gdev_prn_close(pdev); } diff -Nru ghostscript-9.25~dfsg+1/contrib/japanese/gdevespg.c ghostscript-9.26~dfsg+0/contrib/japanese/gdevespg.c --- ghostscript-9.25~dfsg+1/contrib/japanese/gdevespg.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/contrib/japanese/gdevespg.c 2018-11-20 09:59:43.000000000 +0000 @@ -96,12 +96,14 @@ static int escpage_close(gx_device * pdev) { - gdev_prn_open_printer(pdev, 1); - if (ppdev->Duplex && (pdev->PageCount & 1)) { - fprintf(ppdev->file, "%c0dpsE", GS); + int code = gdev_prn_open_printer(pdev, 1); + if (code >= 0) { + if (ppdev->Duplex && (pdev->PageCount & 1)) { + fprintf(ppdev->file, "%c0dpsE", GS); + } + fputs(epson_remote_start, ppdev->file); + fputs(epson_remote_start, ppdev->file); } - fputs(epson_remote_start, ppdev->file); - fputs(epson_remote_start, ppdev->file); return gdev_prn_close(pdev); } diff -Nru ghostscript-9.25~dfsg+1/contrib/japanese/gdevnpdl.c ghostscript-9.26~dfsg+0/contrib/japanese/gdevnpdl.c --- ghostscript-9.25~dfsg+1/contrib/japanese/gdevnpdl.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/contrib/japanese/gdevnpdl.c 2018-11-20 09:59:43.000000000 +0000 @@ -546,8 +546,9 @@ npdl_close(gx_device *pdev) { gx_device_printer *const ppdev = (gx_device_printer *) pdev; - gdev_prn_open_printer(pdev, 1); - fputs("\033c1", ppdev->file); + int code = gdev_prn_open_printer(pdev, 1); + if (code >= 0) + fputs("\033c1", ppdev->file); return gdev_prn_close(pdev); } diff -Nru ghostscript-9.25~dfsg+1/contrib/japanese/gdevrpdl.c ghostscript-9.26~dfsg+0/contrib/japanese/gdevrpdl.c --- ghostscript-9.25~dfsg+1/contrib/japanese/gdevrpdl.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/contrib/japanese/gdevrpdl.c 2018-11-20 09:59:43.000000000 +0000 @@ -63,7 +63,9 @@ static int rpdl_close(gx_device * pdev) { - gdev_prn_open_printer(pdev, 1); + int code = gdev_prn_open_printer(pdev, 1); + if (code < 0) + return code; if (ppdev->Duplex && (pdev->PageCount & 1)) { fprintf(ppdev->file, "\014"); /* Form Feed */ } diff -Nru ghostscript-9.25~dfsg+1/contrib/lips4/gdevl4r.c ghostscript-9.26~dfsg+0/contrib/lips4/gdevl4r.c --- ghostscript-9.25~dfsg+1/contrib/lips4/gdevl4r.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/contrib/lips4/gdevl4r.c 2018-11-20 09:59:43.000000000 +0000 @@ -260,16 +260,17 @@ gx_device_printer *const ppdev = (gx_device_printer *) pdev; gx_device_lips *const lips = (gx_device_lips *) pdev; - gdev_prn_open_printer(pdev, 1); + int code = gdev_prn_open_printer(pdev, 1); - fprintf(ppdev->file, "%c0J%c", LIPS_DCS, LIPS_ST); - if (lips->pjl) - fprintf(ppdev->file, + if (code >= 0) { + fprintf(ppdev->file, "%c0J%c", LIPS_DCS, LIPS_ST); + if (lips->pjl) + fprintf(ppdev->file, "%c%%-12345X" "@PJL SET LPARM : LIPS SW2 = OFF\n" "@PJL EOJ\n" "%c%%-12345X", LIPS_ESC, LIPS_ESC); - + } return gdev_prn_close(pdev); } diff -Nru ghostscript-9.25~dfsg+1/cups/gdevcups.c ghostscript-9.26~dfsg+0/cups/gdevcups.c --- ghostscript-9.25~dfsg+1/cups/gdevcups.c 2018-09-13 10:02:01.000000000 +0000 +++ ghostscript-9.26~dfsg+0/cups/gdevcups.c 2018-11-20 09:59:43.000000000 +0000 @@ -1016,10 +1016,6 @@ (int *)&(cups->header.Jog))) < 0) goto done; - if ((code = param_write_int(plist, "LeadingEdge", - (int *)&(cups->header.LeadingEdge))) < 0) - goto done; - b = cups->header.ManualFeed; if ((code = param_write_bool(plist, "ManualFeed", &b)) < 0) goto done; @@ -2838,6 +2834,9 @@ return(code); } + /* Establish the default LeadingEdge in the cups header */ + cups->header.LeadingEdge = (cups_edge_t)(pdev->LeadingEdge & LEADINGEDGE_MASK); + if ((code = gdev_prn_open(pdev)) != 0) return(code); @@ -3241,23 +3240,6 @@ intoption(cupsRowFeed, "cupsRowFeed", unsigned) intoption(cupsRowStep, "cupsRowStep", unsigned) - /* Special handling of LeadingEdge to allow null as a valid value type */ - if ((code = param_read_int(plist, "LeadingEdge", &intval)) < 0) - { - if ((code = param_read_null(plist, "LeadingEdge")) < 0) - { - dmprintf(pdev->memory, "ERROR: Error setting LeadingEdge ...\n"); - param_signal_error(plist, "LeadingEdge", code); - goto done; - } - if (code == 0) - cups->header.LeadingEdge = CUPS_EDGE_TOP; - } - else if (code == 0) - { - cups->header.LeadingEdge = (cups_edge_t)intval; - } - #ifdef GX_COLOR_INDEX_TYPE /* * Support cupsPreferredBitsPerColor - basically, allows you to @@ -3316,6 +3298,8 @@ if ((code = gdev_prn_put_params(pdev, plist)) < 0) goto done; + cups->header.LeadingEdge = (cups_edge_t)(pdev->LeadingEdge & LEADINGEDGE_MASK); + /* If cups_set_color_info() changed the color model of the device we want to * force the raster memory to be recreated/reinitialized */ diff -Nru ghostscript-9.25~dfsg+1/debian/changelog ghostscript-9.26~dfsg+0/debian/changelog --- ghostscript-9.25~dfsg+1/debian/changelog 2018-11-12 19:00:21.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/changelog 2018-11-28 14:00:34.000000000 +0000 @@ -1,3 +1,17 @@ +ghostscript (9.26~dfsg+0-0ubuntu0.16.04.1) xenial-security; urgency=medium + + * SECURITY UPDATE: Updated to 9.26 to fix multiple security issues + - CVE-2018-19409 + - CVE-2018-19475 + - CVE-2018-19476 + - CVE-2018-19477 + * Removed patches included in new version: + - debian/patches/0218*.patch + - debian/patches/lp1800062.patch + * debian/symbols.common: updated for new version. + + -- Marc Deslauriers Wed, 28 Nov 2018 08:35:43 -0500 + ghostscript (9.25~dfsg+1-0ubuntu0.16.04.3) xenial; urgency=medium * Fix dependency for libgs9-common (LP: #1802958) diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180917~7c3e7ee.patch ghostscript-9.26~dfsg+0/debian/patches/020180917~7c3e7ee.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180917~7c3e7ee.patch 2018-10-18 20:07:42.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180917~7c3e7ee.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -Description: Implement .currentoutputdevice operator - The currentdevice operator returns the device - currently installed in the graphics state. - This can be the output/page device, - but also could be a forwarding device (bbox device), - compositor (pdf14) or subclass device (erasepage optimisation, - First/Last page etc). - . - In certain circumstances (for example during a setpagedevice) - we want to be sure we're retrieving the *actual* output/page device. - . - The new .currentoutputdevice operator uses the spec_op device method - to traverse any chain of devices - and retrieve the final device in the chain, - which should always be the output/page device. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=7c3e7ee -Author: Chris Liddell -Forwarded: yes -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -2211,7 +2211,7 @@ - /.shfill /.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring - /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile - /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams -- /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath -+ /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice - - % Used by a free user in the Library of Congress. Apparently this is used to - % draw a partial page, which is then filled in by the results of a barcode ---- a/Resource/Init/gs_setpd.ps -+++ b/Resource/Init/gs_setpd.ps -@@ -877,7 +877,13 @@ - % Stack: mark - SETPDDEBUG { (Constructing.) = pstack flush } if - -- currentdevice .devicename 2 index /OutputDevice get eq -+ % Non-obvious: we need to check the name of the output device, to tell -+ % whether we're going to have to replace the entire device chain (which -+ % may be only one device, or may be multiple devices. -+ % If we're not replacing the entire change, we have to use the device in -+ % the graphics state, so the configuration of the entire device chain is -+ % correctly set. -+ .currentoutputdevice .devicename 2 index /OutputDevice get eq - { currentdevice } - { 1 index /OutputDevice get finddevice } - ifelse ---- a/base/gdevdflt.c -+++ b/base/gdevdflt.c -@@ -1044,6 +1044,11 @@ - dev_param_req_t *request = (dev_param_req_t *)data; - return gx_default_get_param(pdev, request->Param, request->list); - } -+ case gxdso_current_output_device: -+ { -+ *(gx_device **)data = pdev; -+ return 0; -+ } - } - return_error(gs_error_undefined); - } ---- a/base/gxdevsop.h -+++ b/base/gxdevsop.h -@@ -327,6 +327,10 @@ - gxdso_JPEG_passthrough_data, - gxdso_JPEG_passthrough_end, - gxdso_supports_iccpostrender, -+ /* Retrieve the last device in a device chain -+ (either forwarding or subclass devices). -+ */ -+ gxdso_current_output_device, - /* Add new gxdso_ keys above this. */ - gxdso_pattern__LAST - }; ---- a/psi/zdevice.c -+++ b/psi/zdevice.c -@@ -57,6 +57,7 @@ - } - - /* - currentdevice */ -+/* Returns the current device in the graphics state */ - int - zcurrentdevice(i_ctx_t *i_ctx_p) - { -@@ -71,6 +72,34 @@ - return 0; - } - -+/* - .currentoutputdevice */ -+/* Returns the *output* device - which will often -+ be the same as above, but not always: if a compositor -+ or other forwarding device, or subclassing device is -+ in force, that will be referenced by the graphics state -+ rather than the output device. -+ This is equivalent of currentdevice device, but returns -+ the *device* object, rather than the dictionary describing -+ the device and device state. -+ */ -+static int -+zcurrentoutputdevice(i_ctx_t *i_ctx_p) -+{ -+ os_ptr op = osp; -+ gx_device *odev = NULL, *dev = gs_currentdevice(igs); -+ gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory; -+ int code = dev_proc(dev, dev_spec_op)(dev, -+ gxdso_current_output_device, (void *)&odev, 0); -+ if (code < 0) -+ return code; -+ -+ push(1); -+ make_tav(op, t_device, -+ (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all, -+ pdevice, odev); -+ return 0; -+} -+ - /* .devicename */ - static int - zdevicename(i_ctx_t *i_ctx_p) -@@ -614,6 +643,7 @@ - { - {"1.copydevice2", zcopydevice2}, - {"0currentdevice", zcurrentdevice}, -+ {"0.currentoutputdevice", zcurrentoutputdevice}, - {"1.devicename", zdevicename}, - {"0.doneshowpage", zdoneshowpage}, - {"0flushpage", zflushpage}, diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180918~c1657e3.patch ghostscript-9.26~dfsg+0/debian/patches/020180918~c1657e3.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180918~c1657e3.patch 2018-10-18 21:06:23.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180918~c1657e3.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -Description: Change "executeonly" to throw typecheck on gstatetype and devicetype objects - PS doesn't really have a "devicetype", - but it is not listed as an acceptable argument type to "executeonly", - so we probably should not accept it. - . - "gstate executeonly" throws typecheck in Acrobat, - so we should do the same. - . - Tested the other "access related" functions - (noaccess, readonly, rcheck, wcheck, xcheck) - and all of these accept "gstate" as an argument, - even though the PLRM says they should not. - Also our initialization code does things with wcheck and readonly - on devices and gstates. - . - So, this fix is only for "executeonly". -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=c1657e3 -Author: Nancy Durgin -Forwarded: yes -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/ztype.c -+++ b/psi/ztype.c -@@ -174,9 +174,10 @@ - zexecuteonly(i_ctx_t *i_ctx_p) - { - os_ptr op = osp; -+ ref_type rtype = r_type(op); - - check_op(1); -- if (r_has_type(op, t_dictionary)) -+ if (rtype == t_dictionary || rtype == t_astruct || rtype == t_device) - return_error(gs_error_typecheck); - return access_check(i_ctx_p, a_execute, true); - } diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180918~c76bf1c.patch ghostscript-9.26~dfsg+0/debian/patches/020180918~c76bf1c.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180918~c76bf1c.patch 2018-10-18 13:00:02.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180918~c76bf1c.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -Description: Undefine some additional internal operators. - .type, .writecvs, .setSMask, .currentSMask - . - These don't seem to be referenced anywhere - outside of the initialization code, - which binds their usages. Passes cluster if they are removed. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=c76bf1c -Author: Chris Liddell -Forwarded: yes -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -2212,6 +2212,7 @@ - /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile - /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams - /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice -+ /.type /.writecvs /.setSMask /.currentSMask - - % Used by a free user in the Library of Congress. Apparently this is used to - % draw a partial page, which is then filled in by the results of a barcode -@@ -2230,7 +2231,7 @@ - % test files/utilities, or engineers expressed a desire to keep them visible. - % - %/currentdevice /.sort /.buildfont0 /.buildfont1 /.buildfont2 /.buildfont3 /.buildfont4 /.buildfont9 /.buildfont10 /.buildfont11 -- %/.buildfotn32 /.buildfont42 /.type9mapcid /.type11mapcid /.swapcolors -+ %/.buildfont32 /.buildfont42 /.type9mapcid /.type11mapcid /.swapcolors - %/currentdevice /.quit /.setuseciecolor /.needinput /.setoverprintmode /.special_op /.dicttomark /.knownget - %/.FAPIavailable /.FAPIpassfont /.FAPIrebuildfont /.FAPIBuildGlyph /.FAPIBuildChar /.FAPIBuildGlyph9 - %/.tempfile /.numicc_components /.set_outputintent /.max /.min /.vmreclaim /.getpath /.setglobal diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180919~18e8a06.patch ghostscript-9.26~dfsg+0/debian/patches/020180919~18e8a06.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180919~18e8a06.patch 2018-10-18 21:07:57.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180919~18e8a06.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -Description: Fix handling of .needinput if used from interpreter - .needinput is meant as an internal function, - but it is exposed to the user. - I couldn't see an easy way to undefine it. - . - But if user calls it, - it returns gs_error_Fatal in a place that the code wasn't expecting, - and basically puts things in an undefined state. - This change returns a Fatal error at this point, instead. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=18e8a06 -Author: Nancy Durgin -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699793 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/imain.c -+++ b/psi/imain.c -@@ -606,8 +606,15 @@ - pexit_code, perror_object); - if (code != gs_error_NeedInput) - return code; -- return gs_main_run_string_end(minst, user_errors, -+ -+ code = gs_main_run_string_end(minst, user_errors, - pexit_code, perror_object); -+ /* Not okay for user to use .needinput -+ * This treats it as a fatal error. -+ */ -+ if (code == gs_error_NeedInput) -+ return_error(gs_error_Fatal); -+ return code; - } - - /* Set up for a suspendable run_string. */ diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180920~78ed0a8.patch ghostscript-9.26~dfsg+0/debian/patches/020180920~78ed0a8.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180920~78ed0a8.patch 2018-10-18 21:08:33.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180920~78ed0a8.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -Description: Ensure all errors are included from initialization - Previously only Level 1 errors were added during init. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=78ed0a8 -Author: Chris Liddell -Forwarded: yes -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -1110,8 +1110,7 @@ - .setglobal - } bind def - ErrorNames -- { dup .registererror /VMerror eq {exit} if -- } forall -+ { .registererror} forall - errordict begin - % The handlers for interrupt and timeout are special; there is no - % 'current object', so they push their own name. diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180920~8ed08cb.patch ghostscript-9.26~dfsg+0/debian/patches/020180920~8ed08cb.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180920~8ed08cb.patch 2018-10-18 21:11:26.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180920~8ed08cb.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -Description: setundercolorremoval memory corruption - What is happening is that we are not properly reference counting - a structure. - . - For setblackgeneration and setundercolorremoval - we need to use a continuation procedure, - which samples the supplied PostScript function - and then stores the sample map. - . - As part of this we create an internal structure to hold the map, - and we make this the current undercolorremoval/blackgeneration entry - in the graphics state. - We *also* push a reference to it onto the exec stack, - so that the continuation procedure can use it from there. - However we don't increment the reference count. - . - When we execute the 'grestore' in the function - we reset the values in the graphics state, - and because the reference count is one - we count it down and then discard the structure. - . - When we then throw an error - we try to copy data off the exec stack into an array, - when we hit the reference to the freed strcuture - we potentially are pointing to invalid memory, - leading to a seg fault. - . - To fix this, - increment the reference count of the object - when we put it on the exec stack, - and decrement it when we remove it from the exec stack. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=8ed08cb -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699797 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/zcolor.c -+++ b/psi/zcolor.c -@@ -687,6 +687,7 @@ - ++esp; - make_struct(esp, imemory_space((gs_ref_memory_t *) pgs->memory), - pmap); -+ rc_increment(pmap); - push_op_estack(finish_proc); - push_op_estack(zfor_samples); - return o_push_estack; -@@ -699,6 +700,7 @@ - int i; - gx_transfer_map *pmap = r_ptr(esp, gx_transfer_map); - -+ rc_decrement_only(pmap, "zcolor_remap_one_store"); - if (ref_stack_count(&o_stack) < transfer_map_size) - return_error(gs_error_stackunderflow); - for (i = 0; i < transfer_map_size; i++) { diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180920~90e8f8d.patch ghostscript-9.26~dfsg+0/debian/patches/020180920~90e8f8d.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180920~90e8f8d.patch 2018-10-18 21:13:45.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180920~90e8f8d.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -Description: copydevice fails after stack device copies invalidated - This isn't anything to do with .fill_identity_cmap. - A simpler example is: - . - .distillerdevice - nulldevice - copydevice - . - The problem is that when we execute nulldevice - we need to invalidate any copies, - stored on the operand stack, - of the device that was current before the nulldevice was installed. - . - We do that by setting the pdevice member of the device structure to NULL. - However the fact that a device can be invalidated - has clearly passed by a number of developers in the intervening years, - and a number of places in the code do check - the type of the operand is a device, - but they don't check to see if the device has been invalidated. - . - Add validation checks where required. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=90e8f8d -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699796 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/idisp.c -+++ b/psi/idisp.c -@@ -81,6 +81,10 @@ - * setting callback, then reopen it. - */ - check_read_type(op[-1], t_device); -+ if (op[-1].value.pdevice == NULL) -+ /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ -+ return_error(gs_error_undefined); -+ - dev = op[-1].value.pdevice; - - was_open = dev->is_open; ---- a/psi/zdevice.c -+++ b/psi/zdevice.c -@@ -46,6 +46,10 @@ - - check_read_type(op[-1], t_device); - check_type(*op, t_boolean); -+ if (op[-1].value.pdevice == NULL) -+ /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ -+ return_error(gs_error_undefined); -+ - code = gs_copydevice2(&new_dev, op[-1].value.pdevice, op->value.boolval, - imemory); - if (code < 0) -@@ -108,6 +112,10 @@ - const char *dname; - - check_read_type(*op, t_device); -+ if (op->value.pdevice == NULL) -+ /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ -+ return_error(gs_error_undefined); -+ - dname = op->value.pdevice->dname; - make_const_string(op, avm_foreign | a_readonly, strlen(dname), - (const byte *)dname); -@@ -157,6 +165,10 @@ - - check_read_type(op[-7], t_device); - dev = op[-7].value.pdevice; -+ if (dev == NULL) -+ /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ -+ return_error(gs_error_undefined); -+ - check_int_leu(op[-6], dev->width); - rect.p.x = op[-6].value.intval; - check_int_leu(op[-5], dev->height); -@@ -274,6 +286,9 @@ - } - rkeys = *op; - dev = op[-1].value.pdevice; -+ if (op[-1].value.pdevice == NULL) -+ /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ -+ return_error(gs_error_undefined); - pop(1); - stack_param_list_write(&list, &o_stack, &rkeys, iimemory); - code = gs_get_device_or_hardware_params(dev, (gs_param_list *) & list, -@@ -440,6 +455,9 @@ - check_type_only(*prequire_all, t_boolean); - check_write_type_only(*pdev, t_device); - dev = pdev->value.pdevice; -+ if (dev == NULL) -+ /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ -+ return_error(gs_error_undefined); - code = stack_param_list_read(&list, &o_stack, 0, ppolicy, - prequire_all->value.boolval, iimemory); - if (code < 0) diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180920~b0222e5.patch ghostscript-9.26~dfsg+0/debian/patches/020180920~b0222e5.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180920~b0222e5.patch 2018-10-18 10:38:21.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180920~b0222e5.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -Description: add operand checking to .setnativefontmapbuilt - .setnativefontmapbuilt .forceputs a value into systemdict - - it is intended to be a boolean, - but in this case was being called with a compound object (a dictionary). - Such an object, in local VM, being forced into systemdict - would then confuse the garbager, - since it could be restored away with the reference remaining. - . - This adds operand checking, - so .setnativefontmapbuilt will simply ignore - anything other than a boolean value, - and also removes the definition of .setnativefontmapbuilt after use, - since it is only used in two, closely related places. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=b0222e5 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699795 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_fonts.ps -+++ b/Resource/Init/gs_fonts.ps -@@ -372,9 +372,13 @@ - % of strings: what the system thinks is the ps name, - % and the access path. - /.setnativefontmapbuilt { % set whether we've been run -- systemdict exch /.nativefontmapbuilt exch .forceput -+ dup type /booleantype eq { -+ systemdict exch /.nativefontmapbuilt exch .forceput -+ } -+ {pop} -+ ifelse - } .bind executeonly def --systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt -+systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec - /.buildnativefontmap { % - .buildnativefontmap - systemdict /.nativefontmapbuilt .knownget not - { //false} if -@@ -415,9 +419,10 @@ - } forall - } if - % record that we've been run -- //true .setnativefontmapbuilt -+ //true //.setnativefontmapbuilt exec - } ifelse - } bind def -+currentdict /.setnativefontmapbuilt .forceundef - - % Create the dictionary that registers the .buildfont procedure - % (called by definefont) for each FontType. diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~2118711.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~2118711.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~2118711.patch 2018-10-18 21:14:22.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~2118711.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -Description: add object type check for AES key - Make sure the key string is a string. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=2118711 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699802 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/zfaes.c -+++ b/psi/zfaes.c -@@ -45,7 +45,7 @@ - check_dict_read(*op); - if (dict_find_string(op, "Key", &sop) <= 0) - return_error(gs_error_rangecheck); -- -+ check_type(*sop, t_string); - s_aes_set_key(&state, sop->value.const_bytes, r_size(sop)); - - /* extract the padding flag, which defaults to true for compatibility */ diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~379be67.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~379be67.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~379be67.patch 2018-10-18 21:15:13.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~379be67.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -Description: Add parameter type checking on .bigstring - If the parameter is not an integer, this would leave 65400 on the stack. - Also, if there is no argument, signal stackunderflow. - Seen with the PS sequence of bug 699794. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=379be67 -Author: Ray Johnston -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699794 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_ll3.ps -+++ b/Resource/Init/gs_ll3.ps -@@ -146,6 +146,10 @@ - } bind def - - /.bigstring { % .bigstring -+ count 1 lt { /.bigstring /stackunderflow signalerror } if -+ dup type /integertype ne { -+ /.bigstring /typecheck signalerror -+ } if - dup 65400 gt { .bytestring } { string } ifelse - } bind def - diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~7ee525f.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~7ee525f.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~7ee525f.patch 2018-10-18 21:16:33.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~7ee525f.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -Description: zparse_dsc_comments can crash with invalid dsc_state - Although zparse_dsc_comments() does check the types of its operands, - it wasn't checking the return value from dict_find_string properly. - It was effectively assuming - that the dictionary parameter was the *correct* dictionary - and would contain the key/value pair it needed. - . - Here we check to see if the key has not been found - and throw an error if so. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=7ee525f -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699801 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/zdscpars.c -+++ b/psi/zdscpars.c -@@ -457,6 +457,9 @@ - code = dict_find_string(opDict, dsc_dict_name, &pvalue); - if (code < 0) - return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ - dsc_state = r_ptr(pvalue, dsc_data_t); - /* - * Pick up the comment string to be parsed. diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~95aa78b.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~95aa78b.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~95aa78b.patch 2018-10-18 20:10:54.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~95aa78b.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -Description: Catch errors in setpagesize, .setpagesize and setpagedevice and cleanup - Bug 699794 showed that attempt to change page size in SAFER mode - when the nulldevice was the currentdevice - would leave 'false' on the stack. - Run .setdevice in stopped and clean up, - and also clean up .setpagesize -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=95aa78b -Author: Ray Johnston -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699794 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_lev2.ps -+++ b/Resource/Init/gs_lev2.ps -@@ -610,7 +610,14 @@ - .dicttomark setpagedevice - /WaitTimeout exch mark /JobTimeout 5 2 roll .dicttomark setsystemparams - } bind def --/.setpagesize { 2 array astore /PageSize .dict1 setpagedevice } bind def -+/.setpagesize -+ { 2 copy 2 array astore /PageSize .dict1 { setpagedevice } stopped { -+ pop % the setpagedevice dict -+ /setpagesize $error /errorname get signalerror -+ } { -+ pop pop % success -- pop the arguments -+ } ifelse -+ } bind def - /setduplexmode { /Duplex .dict1 setpagedevice } bind def - /setmargins - { exch 2 array astore /Margins .dict1 setpagedevice ---- a/Resource/Init/gs_setpd.ps -+++ b/Resource/Init/gs_setpd.ps -@@ -919,10 +919,15 @@ - % Stack: mark ... - SETPDDEBUG { (Installing.) = pstack flush } if - -- pop -+ pop - % .setdevice clears the current page device! - .currentpagedevice pop exch -- .setdevice pop -+ { .setdevice } stopped { -+ cleartomark exch pop -+ /setpagedevice $error /errorname get -+ signalerror -+ } if -+ pop - .setpagedevice - - % Implement UseCIEColor directly if this is a LL3 system. ---- a/Resource/Init/gs_statd.ps -+++ b/Resource/Init/gs_statd.ps -@@ -39,7 +39,13 @@ - % These procedures are also accessed as data structures during initialization, - % so the page dimensions must be the first two elements of the procedure. - --/.setpagesize { /statusdict .systemvar begin .setpagesize end } bind def -+/.setpagesize { -+ /statusdict .systemvar begin -+ { .setpagesize } stopped { -+ /setpagesize $error /errorname get signalerror -+ } if -+ end -+} bind def - - % Page sizes defined by Adobe documentation - % Note: these executable arrays should all begin with two -@@ -261,9 +267,17 @@ - % The Adobe documentation only defines setpagetype - % (a Level 1 operator) as accepting the values 0 and 1, - % so we do too. -- {/letter /note} 1 index get -- //systemdict /userdict get exch get cvx exec -- /pagetype exch def -+ dup type /integertype ne { -+ /setpage /typecheck signalerror -+ } { -+ dup 0 ne 1 index 1 ne or { -+ /setpage /rangecheck signalerror -+ } { -+ {/letter /note} 1 index get -+ //systemdict /userdict get exch get cvx exec -+ } ifelse -+ /pagetype exch def -+ } ifelse - end - } bind def - diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~9d6ac20.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~9d6ac20.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~9d6ac20.patch 2018-10-18 21:18:04.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~9d6ac20.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,188 +0,0 @@ -Description: Catch errors and cleanup stack on statusdict page size definitions - This was also found with the sequence from Bug 699794, - if .setpagesize fails, - we need to clean up the two integers (page width, height) - then signal the error. - Since some definitions "load" another (e.g. b5 loads isob5) - the command name in the error won't be correct for those, - but it will be close. - If anybody cares, we could fix it. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=9d6ac20 -Author: Ray Johnston -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699794 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_statd.ps -+++ b/Resource/Init/gs_statd.ps -@@ -50,15 +50,15 @@ - % Page sizes defined by Adobe documentation - % Note: these executable arrays should all begin with two - % integers which are the width and height (see gs_setpd.ps). -- /11x17 {792 1224 //.setpagesize exec} bind def % 11x17 portrait -- /a3 {842 1191 //.setpagesize exec} bind def -- /a4 {595 842 //.setpagesize exec} bind def -+ /11x17 {792 1224 //.setpagesize stopped { pop pop /11x17 $error /errorname get signalerror } if } bind def % 11x17 portrait -+ /a3 {842 1191 //.setpagesize stopped { pop pop /a3 $error /errorname get signalerror } if } bind def -+ /a4 {595 842 //.setpagesize stopped { pop pop /a4 $error /errorname get signalerror } if } bind def - % a4small should be a4 with an ImagingBBox of [25 25 570 817]. - /a4small /a4 load def - % b5 see below. -- /ledger {1224 792 //.setpagesize exec} bind def % 11x17 landscape -- /legal {612 1008 //.setpagesize exec} bind def -- /letter {612 792 //.setpagesize exec} bind def -+ /ledger {1224 792 //.setpagesize stopped { pop pop /ledger $error /errorname get signalerror } if } bind def % 11x17 landscape -+ /legal {612 1008 //.setpagesize stopped { pop pop /legal $error /errorname get signalerror } if } bind def -+ /letter {612 792 //.setpagesize stopped { pop pop /letter $error /errorname get signalerror } if } bind def - % lettersmall should be letter with an ImagingBBox of [25 25 587 767]. - /lettersmall /letter load def - % note should be letter (or some other size) with the ImagingBBox -@@ -68,68 +68,68 @@ - - % Other page sizes - % ISO standard paper sizes -- /a0 {2384 3370 //.setpagesize exec} bind def -- /a1 {1684 2384 //.setpagesize exec} bind def -- /a2 {1191 1684 //.setpagesize exec} bind def --% /a3 {842 1191 //.setpagesize exec} bind def % defined by Adobe --% /a4 {595 842 //.setpagesize exec} bind def % defined by Adobe -- /a5 {420 595 //.setpagesize exec} bind def -- /a6 {297 420 //.setpagesize exec} bind def -- /a7 {210 297 //.setpagesize exec} bind def -- /a8 {148 210 //.setpagesize exec} bind def -- /a9 {105 148 //.setpagesize exec} bind def -- /a10 {73 105 //.setpagesize exec} bind def -+ /a0 {2384 3370 //.setpagesize stopped { pop pop /a0 $error /errorname get signalerror } if } bind def -+ /a1 {1684 2384 //.setpagesize stopped { pop pop /a1 $error /errorname get signalerror } if } bind def -+ /a2 {1191 1684 //.setpagesize stopped { pop pop /a2 $error /errorname get signalerror } if } bind def -+% /a3 {842 1191 //.setpagesize stopped { pop pop /a3 $error /errorname get signalerror } if } bind def % defined by Adobe -+% /a4 {595 842 //.setpagesize stopped { pop pop /a4 $error /errorname get signalerror } if } bind def % defined by Adobe -+ /a5 {420 595 //.setpagesize stopped { pop pop /a5 $error /errorname get signalerror } if } bind def -+ /a6 {297 420 //.setpagesize stopped { pop pop /a6 $error /errorname get signalerror } if } bind def -+ /a7 {210 297 //.setpagesize stopped { pop pop /a7 $error /errorname get signalerror } if } bind def -+ /a8 {148 210 //.setpagesize stopped { pop pop /a8 $error /errorname get signalerror } if } bind def -+ /a9 {105 148 //.setpagesize stopped { pop pop /a9 $error /errorname get signalerror } if } bind def -+ /a10 {73 105 //.setpagesize stopped { pop pop /a10 $error /errorname get signalerror } if } bind def - % ISO and JIS B sizes are different.... -- /isob0 {2835 4008 //.setpagesize exec} bind def -+ /isob0 {2835 4008 //.setpagesize stopped { pop pop /isob0 $error /errorname get signalerror } if } bind def - /b0 /isob0 load def -- /isob1 {2004 2835 //.setpagesize exec} bind def -+ /isob1 {2004 2835 //.setpagesize stopped { pop pop /isob1 $error /errorname get signalerror } if } bind def - /b1 /isob1 load def -- /isob2 {1417 2004 //.setpagesize exec} bind def -+ /isob2 {1417 2004 //.setpagesize stopped { pop pop /isob2 $error /errorname get signalerror } if } bind def - /b2 /isob2 load def -- /isob3 {1001 1417 //.setpagesize exec} bind def -+ /isob3 {1001 1417 //.setpagesize stopped { pop pop /isob3 $error /errorname get signalerror } if } bind def - /b3 /isob3 load def -- /isob4 {709 1001 //.setpagesize exec} bind def -+ /isob4 {709 1001 //.setpagesize stopped { pop pop /isob4 $error /errorname get signalerror } if } bind def - /b4 /isob4 load def -- /isob5 {499 709 //.setpagesize exec} bind def -+ /isob5 {499 709 //.setpagesize stopped { pop pop /isob5 $error /errorname get signalerror } if } bind def - /b5 /isob5 load def -- /isob6 {354 499 //.setpagesize exec} bind def -+ /isob6 {354 499 //.setpagesize stopped { pop pop /isob6 $error /errorname get signalerror } if } bind def - /b6 /isob6 load def -- /jisb0 {2920 4127 //.setpagesize exec} bind def -- /jisb1 {2064 2920 //.setpagesize exec} bind def -- /jisb2 {1460 2064 //.setpagesize exec} bind def -- /jisb3 {1032 1460 //.setpagesize exec} bind def -- /jisb4 {729 1032 //.setpagesize exec} bind def -- /jisb5 {516 729 //.setpagesize exec} bind def -- /jisb6 {363 516 //.setpagesize exec} bind def -- /c0 {2599 3677 //.setpagesize exec} bind def -- /c1 {1837 2599 //.setpagesize exec} bind def -- /c2 {1298 1837 //.setpagesize exec} bind def -- /c3 {918 1298 //.setpagesize exec} bind def -- /c4 {649 918 //.setpagesize exec} bind def -- /c5 {459 649 //.setpagesize exec} bind def -- /c6 {323 459 //.setpagesize exec} bind def -+ /jisb0 {2920 4127 //.setpagesize stopped { pop pop /jisb0 $error /errorname get signalerror } if } bind def -+ /jisb1 {2064 2920 //.setpagesize stopped { pop pop /jisb1 $error /errorname get signalerror } if } bind def -+ /jisb2 {1460 2064 //.setpagesize stopped { pop pop /jisb2 $error /errorname get signalerror } if } bind def -+ /jisb3 {1032 1460 //.setpagesize stopped { pop pop /jisb3 $error /errorname get signalerror } if } bind def -+ /jisb4 {729 1032 //.setpagesize stopped { pop pop /jisb4 $error /errorname get signalerror } if } bind def -+ /jisb5 {516 729 //.setpagesize stopped { pop pop /jisb5 $error /errorname get signalerror } if } bind def -+ /jisb6 {363 516 //.setpagesize stopped { pop pop /jisb6 $error /errorname get signalerror } if } bind def -+ /c0 {2599 3677 //.setpagesize stopped { pop pop /c0 $error /errorname get signalerror } if } bind def -+ /c1 {1837 2599 //.setpagesize stopped { pop pop /c1 $error /errorname get signalerror } if } bind def -+ /c2 {1298 1837 //.setpagesize stopped { pop pop /c2 $error /errorname get signalerror } if } bind def -+ /c3 {918 1298 //.setpagesize stopped { pop pop /c3 $error /errorname get signalerror } if } bind def -+ /c4 {649 918 //.setpagesize stopped { pop pop /c4 $error /errorname get signalerror } if } bind def -+ /c5 {459 649 //.setpagesize stopped { pop pop /c5 $error /errorname get signalerror } if } bind def -+ /c6 {323 459 //.setpagesize stopped { pop pop /c6 $error /errorname get signalerror } if } bind def - % U.S. CAD standard paper sizes -- /archE {2592 3456 //.setpagesize exec} bind def -- /archD {1728 2592 //.setpagesize exec} bind def -- /archC {1296 1728 //.setpagesize exec} bind def -- /archB {864 1296 //.setpagesize exec} bind def -- /archA {648 864 //.setpagesize exec} bind def -+ /archE {2592 3456 //.setpagesize stopped { pop pop /archE $error /errorname get signalerror } if } bind def -+ /archD {1728 2592 //.setpagesize stopped { pop pop /archD $error /errorname get signalerror } if } bind def -+ /archC {1296 1728 //.setpagesize stopped { pop pop /archC $error /errorname get signalerror } if } bind def -+ /archB {864 1296 //.setpagesize stopped { pop pop /archB $error /errorname get signalerror } if } bind def -+ /archA {648 864 //.setpagesize stopped { pop pop /archA $error /errorname get signalerror } if } bind def - % Other paper sizes -- /flsa {612 936 //.setpagesize exec} bind def % U.S. foolscap -- /flse {612 936 //.setpagesize exec} bind def % European foolscap -- /halfletter {396 612 //.setpagesize exec} bind def -+ /flsa {612 936 //.setpagesize stopped { pop pop /flsa $error /errorname get signalerror } if } bind def % U.S. foolscap -+ /flse {612 936 //.setpagesize stopped { pop pop /flse $error /errorname get signalerror } if } bind def % European foolscap -+ /halfletter {396 612 //.setpagesize stopped { pop pop /halfletter $error /errorname get signalerror } if } bind def - % minimum of a4 and letter (a4 width, letter length) -- /pa4 {595 792 //.setpagesize exec} bind def -+ /pa4 {595 792 //.setpagesize stopped { pop pop /pa4 $error /errorname get signalerror } if } bind def - % Japanese postcard size, 100mm x 148mm -- /hagaki {283 420 //.setpagesize exec} bind def -+ /hagaki {283 420 //.setpagesize stopped { pop pop /hagaki $error /errorname get signalerror } if } bind def - % U.S. ANSI/ASME Y14.1 paper sizes - /ANSI_A //letter def - /ANSI_B //11x17 def - /tabloid //11x17 def -- /ANSI_C {1224 1585 //.setpagesize exec} bind def -- /ANSI_D {1585 2448 //.setpagesize exec} bind def -- /ANSI_E {2448 3168 //.setpagesize exec} bind def -- /ANSI_F {2016 2880 //.setpagesize exec} bind def -+ /ANSI_C {1224 1585 //.setpagesize stopped { pop pop /ANSI_C $error /errorname get signalerror } if } bind def -+ /ANSI_D {1585 2448 //.setpagesize stopped { pop pop /ANSI_D $error /errorname get signalerror } if } bind def -+ /ANSI_E {2448 3168 //.setpagesize stopped { pop pop /ANSI_E $error /errorname get signalerror } if } bind def -+ /ANSI_F {2016 2880 //.setpagesize stopped { pop pop /ANSI_F $error /errorname get signalerror } if } bind def - %END SIZES - currentdict end - dup /.setpagesize .undef -@@ -164,19 +164,19 @@ - - % Tray and format selection - -- /11x17tray {/11x17 .uservar exec} bind def -- /a3tray {/a3 .uservar exec} bind def -- /a4tray {/a4 .uservar exec} bind def -- /a5tray {/a5 .uservar exec} bind def -- /a6tray {/a6 .uservar exec} bind def -- /b4tray {/b4 .uservar exec} bind def -- /b5tray {/b5 .uservar exec} bind def -- /flsatray {/flsa .uservar exec} bind def -- /flsetray {/flse .uservar exec} bind def -- /halflettertray {/halfletter .uservar exec} bind def -- /ledgertray {/ledger .uservar exec} bind def -- /legaltray {/legal .uservar exec} bind def -- /lettertray {/letter .uservar exec} bind def -+ /11x17tray {/11x17 .uservar stopped { pop pop /11x17tray $error /errorname get signalerror } if } bind def -+ /a3tray {/a3 .uservar stopped { pop pop /a3tray $error /errorname get signalerror } if } bind def -+ /a4tray {/a4 .uservar stopped { pop pop /a4tray $error /errorname get signalerror } if } bind def -+ /a5tray {/a5 .uservar stopped { pop pop /a5tray $error /errorname get signalerror } if } bind def -+ /a6tray {/a6 .uservar stopped { pop pop /a6tray $error /errorname get signalerror } if } bind def -+ /b4tray {/b4 .uservar stopped { pop pop /b4tray $error /errorname get signalerror } if } bind def -+ /b5tray {/b5 .uservar stopped { pop pop /b5tray $error /errorname get signalerror } if } bind def -+ /flsatray {/flsa .uservar stopped { pop pop /flsatray $error /errorname get signalerror } if } bind def -+ /flsetray {/flse .uservar stopped { pop pop /flsetray $error /errorname get signalerror } if } bind def -+ /halflettertray {/halfletter .uservar stopped { pop pop /halflettertray $error /errorname get signalerror } if } bind def -+ /ledgertray {/ledger .uservar stopped { pop pop /ledgertray $error /errorname get signalerror } if } bind def -+ /legaltray {/legal .uservar stopped { pop pop /legaltray $error /errorname get signalerror } if } bind def -+ /lettertray {/letter .uservar stopped { pop pop /lettertray $error /errorname get signalerror } if } bind def - - % Per-job parameters - diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~c29ec2f.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~c29ec2f.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~c29ec2f.patch 2018-10-18 21:18:49.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~c29ec2f.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -Description: Add parameter checking in setresolution - Found in sequence for bug 699794 -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=c29ec2f -Author: Ray Johnston -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699794 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_lev2.ps -+++ b/Resource/Init/gs_lev2.ps -@@ -631,7 +631,14 @@ - .dicttomark setpagedevice - } bind def - /setresolution -- { dup 2 array astore /HWResolution .dict1 setpagedevice -+ { count 1 lt { /setresolution /stackunderflow signalerror } if -+ dup type dup /integertype eq exch /realtype eq or not -+ { -+ /setresolution /typecheck signalerror -+ } if -+ dup 2 array astore /HWResolution .dict1 { setpagedevice } stopped { -+ pop /setresolution $error /errorname get signalerror -+ } if - } bind def - %END PAGEDEVICE - diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~db606d2.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~db606d2.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~db606d2.patch 2018-10-18 21:20:23.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~db606d2.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -Description: device subclass open_device call must return child code - Even with changes to detect and clean up - from errors in setpagedevice (b5) and .bigstring, - the segfault was still possible - because the error return code from the child was being ignored, - and the device is_open was set true - when the child device was NOT open. - Attempt to 'fillpage' on a clist device that is not open - is what caused the SEGV. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=db606d2 -Author: Ray Johnston -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699794 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/base/gdevsclass.c -+++ b/base/gdevsclass.c -@@ -99,13 +99,21 @@ - */ - int default_subclass_open_device(gx_device *dev) - { -- if (dev->child) { -- dev_proc(dev->child, open_device)(dev->child); -- dev->child->is_open = true; -- gx_update_from_subclass(dev); -- } -+ int code = 0; - -- return 0; -+ /* observed with Bug 699794, don't set is_open = true if the open_device failed */ -+ /* and make sure to propagate the return code from the child device to caller. */ -+ /* Only open the child if it was closed and if child open is OK, return 1. */ -+ /* (see gs_opendevice) */ -+ if (dev->child && dev->child->is_open == 0) { -+ code = dev_proc(dev->child, open_device)(dev->child); -+ if (code >= 0) { -+ dev->child->is_open = true; -+ code = 1; /* device had been closed, but now is open */ -+ } -+ gx_update_from_subclass(dev); /* this is probably safe to do even if the open failed */ -+ } -+ return code; - } - - void default_subclass_get_initial_matrix(gx_device *dev, gs_matrix *pmat) diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~f31702b.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~f31702b.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~f31702b.patch 2018-10-18 20:50:13.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~f31702b.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,196 +0,0 @@ -Description: fix DSC comment parsing in pdfwrite - This may affect other DSC parsing utilities. - For some reason double comment (%%) marks are being interpreted - 'sometimes' in gs_init.ps as DSC comments. - This only happens when reading the init files from disk - because the ROM file system strips comments. - . - Passing these to pdfwrite causes it to drop later DSC comments, - such as %%Title: and %%Creator: - which meant the information wasn't being embedded - in the document information dictionary. - . - Fix by converting double %% to single % comments, - document this in the header of gs_init.ps. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=f31702b -Author: Ken Sharp -Forwarded: yes -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -20,6 +20,11 @@ - % %% Replace - % indicate places where the next lines should be replaced by - % the contents of , when creating a single merged init file. -+% -+% For reasons not clear to me, some cases of %% are being treated as -+% DSC comments when (and only when) the resource files are disk based -+% This can kill DSC parsing for pdfwrite at least, so avoid using -+% double % comments in this file. - - % The interpreter can call out to PostScript code. All procedures - % called in this way, and no other procedures defined in these -@@ -136,12 +141,12 @@ - ifelse - .bind def - --%% This was a debugging switch removed in 9.22, no other software --%% should have had any regard for it, and even if testing its value --%% should have checked its existence first. However pstotext, an --%% ancient and no longer maintained piece of softare, did check --%% its value unconditionally. So we retain this key in the dictionary --%% purely for backward compatibility. -+% This was a debugging switch removed in 9.22, no other software -+% should have had any regard for it, and even if testing its value -+% should have checked its existence first. However pstotext, an -+% ancient and no longer maintained piece of softare, did check -+% its value unconditionally. So we retain this key in the dictionary -+% purely for backward compatibility. - /NOBIND false def - - currentdict /BATCH known /BATCH exch def -@@ -2082,12 +2087,12 @@ - //SAFETY /safe //true .forceput % overrides readonly - } .bind executeonly odef - --%% This is only used during startup. Its required so that --%% we can detect in setpagdevice that we are in fact in startup --%% and allocate a *global* instead of local VM. We need it to be --%% global to satisfy Display PostScript (see start of /setpagdevice --%% in gs_setpd.ps) --%% -+% This is only used during startup. Its required so that -+% we can detect in setpagdevice that we are in fact in startup -+% and allocate a *global* instead of local VM. We need it to be -+% global to satisfy Display PostScript (see start of /setpagdevice -+% in gs_setpd.ps) -+% - /.locksafeglobal { - .locksafe_userparams - systemdict /getenv {pop //false} put -@@ -2116,8 +2121,8 @@ - .locksafe - } .bind executeonly odef - --%% See /.locksafeglobal above. --%% -+% See /.locksafeglobal above. -+% - /.setsafeglobal { - SAFETY /safe get not { - << -@@ -2155,22 +2160,22 @@ - - /UndefinePostScriptOperators { - -- %% This list is of Display PostScript operators. We believe that Display PostScript -- %% was never fully implemented and the only known user, GNUStep, is no longer -- %% using it. So lets remove it. -+ % This list is of Display PostScript operators. We believe that Display PostScript -+ % was never fully implemented and the only known user, GNUStep, is no longer -+ % using it. So lets remove it. - [ - /condition /currentcontext /detach /.fork /join /.localfork /lock /monitor /notify - /wait /yield /.currentscreenphase /.setscreenphase /.image2 /eoviewclip /initviewclip - /viewclip /viewclippath /defineusername -- %% NeXT DPS extensions -+ % NeXT DPS extensions - /currentalpha /setalpha /.alphaimage /composite /compositerect /dissolve /sizeimagebox /.sizeimageparams - ] - {systemdict exch .forceundef} forall - -- %% This list is of operators which no longer appear to be used, and which we do not believe -- %% to have any real use. For now we will undefine the operstors so they cannot easily be used -- %% but can be easily restored (just delete the name from the list in the array). In future -- %% we may remove the operator and the code implementation entirely. -+ % This list is of operators which no longer appear to be used, and which we do not believe -+ % to have any real use. For now we will undefine the operstors so they cannot easily be used -+ % but can be easily restored (just delete the name from the list in the array). In future -+ % we may remove the operator and the code implementation entirely. - [ - /.bitadd /.charboxpath /.cond /.countexecstack /.execstack /.runandhide /.popdevicefilter - /.execfile /.filenamesplit /.file_name_parent -@@ -2179,15 +2184,15 @@ - /.currentlimitclamp /.dotorientation /.setaccuratecurves /.setcurvejoin /.setdashadapt /.setdotorientation - /.setlimitclamp /.currentscreenlevels /.dashpath /.pathbbox /.identeq /.identne /.tokenexec /.forgetsave /.pantonecallback - -- %% Used by our own test suite files -- %%/.setdotlength % Bug687720.ps -+ % Used by our own test suite files -+ %/.setdotlength % Bug687720.ps - ] - {systemdict exch .forceundef} forall - -- %% This list of operators are used internally by various parts of the Ghostscript startup code. -- %% Since each operator is a potential security vulnerability, and any operator listed here -- %% is not required once the initialisation is complete and functions are bound, we undefine -- %% the ones that aren't needed at runtime. -+ % This list of operators are used internally by various parts of the Ghostscript startup code. -+ % Since each operator is a potential security vulnerability, and any operator listed here -+ % is not required once the initialisation is complete and functions are bound, we undefine -+ % the ones that aren't needed at runtime. - [ - /.callinstall /.callbeginpage /.callendpage - /.currentstackprotect /.setstackprotect /.errorexec /.finderrorobject /.installsystemnames /.bosobject /.fontbbox -@@ -2242,12 +2247,12 @@ - } .bind executeonly def % must be bound and hidden for .forceundef - - /UndefinePDFOperators { -- %% This list of operators are used internally by various parts of the Ghostscript PDF interpreter. -- %% Since each operator is a potential security vulnerability, and any operator listed here -- %% is not required once the initislisation is complete and functions are bound, we undefine -- %% the ones that aren't needed at runtime. -- %% This function is only called if DELAYBIND is true. It is a copy of the code at the end of pdf_main.ps -- %% and must be maintained in parallel with it. -+ % This list of operators are used internally by various parts of the Ghostscript PDF interpreter. -+ % Since each operator is a potential security vulnerability, and any operator listed here -+ % is not required once the initislisation is complete and functions are bound, we undefine -+ % the ones that aren't needed at runtime. -+ % This function is only called if DELAYBIND is true. It is a copy of the code at the end of pdf_main.ps -+ % and must be maintained in parallel with it. - [ - /.pdfawidthshow /.pdfwidthshow /.currentblackptcomp /.setblackptcomp - /.setfillcolor /.setfillcolorspace /.setstrokecolor /.setstrokecolorspace /.currentrenderingintent /.setrenderingintent -@@ -2356,13 +2361,13 @@ - - (END GLOBAL) VMDEBUG - --%% .savelocalstate is part of Display PostScript (if included). Part of the function of --%% the .savelocalstate routine is to store the 'initial saved gstate' (savedinitialgstate) --%% in systemdict. The code in dps1.c, gstate_check_space, disallows writing or creating --%% gstates in global VM in certain conditions. If we execute setpagedevice before we --%% reach this point, we must ensure that we do so using /..StartupGlobal so that --%% the dictionary is defined in global VM, because the gstate contains a pointer to the --%% device dictionary, and if that is allocated in local VM we will fail the gstate check. -+% .savelocalstate is part of Display PostScript (if included). Part of the function of -+% the .savelocalstate routine is to store the 'initial saved gstate' (savedinitialgstate) -+% in systemdict. The code in dps1.c, gstate_check_space, disallows writing or creating -+% gstates in global VM in certain conditions. If we execute setpagedevice before we -+% reach this point, we must ensure that we do so using /..StartupGlobal so that -+% the dictionary is defined in global VM, because the gstate contains a pointer to the -+% device dictionary, and if that is allocated in local VM we will fail the gstate check. - /.savelocalstate where { - % If we might create new contexts, save away copies of all dictionaries - % referenced from systemdict that are stored in local VM, -@@ -2397,8 +2402,8 @@ - currentdict /.wheredict .undef - currentdict /.renderingintentdict .undef - --%% If we are using DELAYBIND we have to defer the undefinition --%% until .bindnow. -+% If we are using DELAYBIND we have to defer the undefinition -+% until .bindnow. - DELAYBIND not { - SAFER { - //systemdict /SAFERUndefinePostScriptOperators get exec -@@ -2426,7 +2431,7 @@ - systemdict /superexec .undef - } if - --%% Can't remove this one until the last minute :-) -+% Can't remove this one until the last minute :-) - DELAYBIND not { - systemdict /.undef .undef - } if diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180921~fac7eb1.patch ghostscript-9.26~dfsg+0/debian/patches/020180921~fac7eb1.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180921~fac7eb1.patch 2018-10-18 21:22:00.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180921~fac7eb1.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,335 +0,0 @@ -Description: Check all uses of dict_find* to ensure 0 return properly handled - dict_find and friends have the surprising quirk - of returning < 0 for an error and > 0 for no error. - But they can also return 0 - which means 'not found' without it being an error. - . - From bug 699801, - if the code assumes the usual case where 0 is a success - then an attempt might be made to use the empty dictionary slot - returned by dict_find*, - which can lead to seg faults, - and certainly won't have the expected result. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=fac7eb1 -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699801 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/icontext.c -+++ b/psi/icontext.c -@@ -162,7 +162,7 @@ - uint size; - ref *system_dict = &pcst->dict_stack.system_dict; - -- if (dict_find_string(system_dict, "userparams", &puserparams) >= 0) -+ if (dict_find_string(system_dict, "userparams", &puserparams) > 0) - size = dict_length(puserparams); - else - size = 300; -@@ -286,7 +286,7 @@ - /* We need i_ctx_p for access to the d_stack. */ - i_ctx_t *i_ctx_p = pcst; - -- if (dict_find_string(systemdict, "userparams", &puserparams) < 0) -+ if (dict_find_string(systemdict, "userparams", &puserparams) <= 0) - return_error(gs_error_Fatal); - pcst->userparams = *puserparams; - } ---- a/psi/zcid.c -+++ b/psi/zcid.c -@@ -72,11 +72,13 @@ - } else - return false; /* Must not happen. */ - for (;n--; i++) { -+ int code; -+ - if (array_get(mem, DecodingArray, i, &char_code1) < 0 || - !r_has_type(&char_code1, t_integer)) - return false; /* Must not happen. */ -- if (dict_find(TT_cmap, &char_code1, &glyph_index) >= 0 && -- r_has_type(glyph_index, t_integer)) { -+ code = dict_find(TT_cmap, &char_code1, &glyph_index); -+ if (code > 0 && r_has_type(glyph_index, t_integer)) { - *c = glyph_index->value.intval; - found = true; - if (*c != 0) ---- a/psi/zfapi.c -+++ b/psi/zfapi.c -@@ -1826,6 +1826,9 @@ - - if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0) - return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ - if (r_type(pref) != t_string) - return_error(gs_error_typecheck); - *xlatmap = (char *)pref->value.bytes; -@@ -1881,11 +1884,11 @@ - ref *FAPIconfig, *options, *server_options; - i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p; - -- if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) >= 0 -+ if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) > 0 - && r_has_type(FAPIconfig, t_dictionary)) { -- if (dict_find_string(FAPIconfig, "ServerOptions", &options) >= 0 -+ if (dict_find_string(FAPIconfig, "ServerOptions", &options) > 0 - && r_has_type(options, t_dictionary)) { -- if (dict_find_string(options, (char *)subtype, &server_options) >= -+ if (dict_find_string(options, (char *)subtype, &server_options) > - 0 && r_has_type(server_options, t_string)) { - *server_param = (byte *) server_options->value.const_bytes; - *server_param_size = r_size(server_options); -@@ -2070,7 +2073,7 @@ - pdata = (font_data *) pfont->client_data; - I = pbfont->FAPI; - -- if (dict_find_string((op - 1), "SubfontId", &v) >= 0 -+ if (dict_find_string((op - 1), "SubfontId", &v) > 0 - && r_has_type(v, t_integer)) - subfont = v->value.intval; - else -@@ -2277,8 +2280,8 @@ - if (pbfont->FontType == ft_CID_TrueType && font_file_path) { - ref *pdr2, *fidr, *dummy; - pdr2 = pfont_dict(gs_rootfont(igs)); -- if (dict_find_string(pdr2, "FontInfo", &fidr) && -- dict_find_string(fidr, "GlyphNames2Unicode", &dummy)) -+ if (dict_find_string(pdr2, "FontInfo", &fidr) > 0 && -+ dict_find_string(fidr, "GlyphNames2Unicode", &dummy) > 0) - { - unsigned char uc[4] = {0}; - unsigned int cc = 0; -@@ -2417,13 +2420,13 @@ - - fdict = pfont_dict(gs_rootfont(igs)); - code = dict_find_string(fdict, "CMap", &CMapDict); -- if (code >= 0 && r_has_type(CMapDict, t_dictionary)) { -+ if (code > 0 && r_has_type(CMapDict, t_dictionary)) { - code = dict_find_string(CMapDict, "WMode", &WMode); -- if (code >= 0 && r_has_type(WMode, t_integer)) { -+ if (code > 0 && r_has_type(WMode, t_integer)) { - wmode = WMode->value.intval; - } - code = dict_find_string(CMapDict, "CMapName", &CMapName); -- if (code >= 0 && r_has_type(CMapName, t_name)) { -+ if (code > 0 && r_has_type(CMapName, t_name)) { - name_string_ref(imemory, CMapName, &CMapNameStr); - cmapnm = (char *)CMapNameStr.value.bytes; - cmapnmlen = r_size(&CMapNameStr); -@@ -2432,10 +2435,10 @@ - /* We only have to lookup the char code if we're *not* using an identity ordering - with the exception of Identity-UTF16 which is a different beast altogether */ - if (unicode_cp || (cmapnmlen > 0 && !strncmp(cmapnm, utfcmap, cmapnmlen > utfcmaplen ? utfcmaplen : cmapnmlen)) -- || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) >= 0 -+ || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) > 0 - && r_has_type(CIDSystemInfo, t_dictionary) - && dict_find_string(CIDSystemInfo, "Ordering", -- &Ordering) >= 0 -+ &Ordering) > 0 - && r_has_type(Ordering, t_string) - && strncmp((const char *)Ordering->value.bytes, - "Identity", 8) != 0)) { -@@ -2463,7 +2466,7 @@ - ref cc32; - ref *gid; - make_int(&cc32, 32); -- if (dict_find(TT_cmap, &cc32, &gid) >= 0) -+ if (dict_find(TT_cmap, &cc32, &gid) > 0) - c = gid->value.intval; - } - cr->char_codes[0] = c; -@@ -2536,7 +2539,7 @@ - if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0 - || !r_has_type(CharStrings, t_dictionary)) - return_error(gs_error_invalidfont); -- if ((dict_find(CharStrings, &char_name, &glyph_index) < 0) -+ if ((dict_find(CharStrings, &char_name, &glyph_index) <= 0) - || r_has_type(glyph_index, t_null)) { - #ifdef DEBUG - ref *pvalue; -@@ -2955,7 +2958,7 @@ - if (code < 0) - return code; - -- if (dict_find_string(op, "SubfontId", &v) >= 0 -+ if (dict_find_string(op, "SubfontId", &v) > 0 - && r_has_type(v, t_integer)) - subfont = v->value.intval; - else -@@ -2968,7 +2971,7 @@ - /* If the font dictionary contains a FAPIPlugInReq key, the the PS world wants us - * to try to use a specific FAPI plugin, so find it, and try it.... - */ -- if (dict_find_string(op, "FAPIPlugInReq", &v) >= 0 && r_type(v) == t_name) { -+ if (dict_find_string(op, "FAPIPlugInReq", &v) > 0 && r_type(v) == t_name) { - - name_string_ref(imemory, v, &reqstr); - ---- a/psi/zfcid0.c -+++ b/psi/zfcid0.c -@@ -410,13 +410,25 @@ - * from a file, GlyphData will be an integer, and DataSource will be - * a (reusable) stream. - */ -- if (code < 0 || -- (code = cid_font_data_param(op, &common, &GlyphDirectory)) < 0 || -- (code = dict_find_string(op, "FDArray", &prfda)) < 0 || -- (code = dict_find_string(op, "CIDFontName", &pCIDFontName)) <= 0 || -- (code = dict_int_param(op, "FDBytes", 0, MAX_FDBytes, -1, &FDBytes)) < 0 -- ) -+ if (code < 0) - return code; -+ code = cid_font_data_param(op, &common, &GlyphDirectory); -+ if (code < 0) -+ return code; -+ code = dict_find_string(op, "FDArray", &prfda); -+ if (code < 0) -+ return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ code = dict_find_string(op, "CIDFontName", &pCIDFontName); -+ if (code < 0) -+ return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ code = dict_int_param(op, "FDBytes", 0, MAX_FDBytes, -1, &FDBytes); -+ if (code < 0) -+ return code; -+ - /* - * Since build_gs_simple_font may resize the dictionary and cause - * pointers to become invalid, save CIDFontName -@@ -426,17 +438,24 @@ - /* Standard CIDFont, require GlyphData and CIDMapOffset. */ - ref *pGlyphData; - -- if ((code = dict_find_string(op, "GlyphData", &pGlyphData)) < 0 || -- (code = dict_uint_param(op, "CIDMapOffset", 0, max_uint - 1, -- max_uint, &CIDMapOffset)) < 0) -+ code = dict_find_string(op, "GlyphData", &pGlyphData); -+ if (code < 0) -+ return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ code = dict_uint_param(op, "CIDMapOffset", 0, max_uint - 1, max_uint, &CIDMapOffset); -+ if (code < 0) - return code; - GlyphData = *pGlyphData; - if (r_has_type(&GlyphData, t_integer)) { - ref *pds; - stream *ignore_s; - -- if ((code = dict_find_string(op, "DataSource", &pds)) < 0) -+ code = dict_find_string(op, "DataSource", &pds); -+ if (code < 0) - return code; -+ if (code == 0) -+ return_error(gs_error_undefined); - check_read_file(i_ctx_p, ignore_s, pds); - DataSource = *pds; - } else { ---- a/psi/zfcid1.c -+++ b/psi/zfcid1.c -@@ -347,11 +347,17 @@ - ref rcidmap, ignore_gdir, file, *pfile, cfnstr, *pCIDFontName, CIDFontName, *t; - ulong loca_glyph_pos[2][2]; - int code = cid_font_data_param(op, &common, &ignore_gdir); -+ if (code < 0) -+ return code; - -- if (code < 0 || -- (code = dict_find_string(op, "CIDFontName", &pCIDFontName)) <= 0 || -- (code = dict_int_param(op, "MetricsCount", 0, 4, 0, &MetricsCount)) < 0 -- ) -+ code = dict_find_string(op, "CIDFontName", &pCIDFontName); -+ if (code <= 0) { -+ if (code == 0) -+ return_error(gs_error_undefined); -+ return code; -+ } -+ code = dict_int_param(op, "MetricsCount", 0, 4, 0, &MetricsCount); -+ if (code < 0) - return code; - /* - * Since build_gs_simple_font may resize the dictionary and cause ---- a/psi/zicc.c -+++ b/psi/zicc.c -@@ -261,6 +261,8 @@ - code = dict_find_string(op, "N", &pnval); - if (code < 0) - return code; -+ if (code == 0) -+ return_error(gs_error_undefined); - ncomps = pnval->value.intval; - - /* verify the DataSource entry. Creat profile from stream */ -@@ -491,6 +493,8 @@ - code = dict_find_string(op, "N", &pnval); - if (code < 0) - return code; -+ if (code == 0) -+ return_error(gs_error_undefined); - ncomps = pnval->value.intval; - /* verify the DataSource entry. Create profile from stream */ - if (dict_find_string(op, "DataSource", &pstrmval) <= 0) ---- a/psi/zpdf_r6.c -+++ b/psi/zpdf_r6.c -@@ -145,21 +145,36 @@ - return_error(gs_error_typecheck); - - code = dict_find_string(CryptDict, "O", &Oref); -- if (code < 0 || !r_has_type(Oref, t_string)) { -+ if (code < 0) -+ return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ if (!r_has_type(Oref, t_string)) - return_error(gs_error_typecheck); -- } -+ - code = dict_find_string(CryptDict, "OE", &OEref); -- if (code < 0 || !r_has_type(OEref, t_string)) { -+ if (code < 0) -+ return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ if (!r_has_type(OEref, t_string)) - return_error(gs_error_typecheck); -- } -+ - code = dict_find_string(CryptDict, "U", &Uref); -- if (code < 0 || !r_has_type(Uref, t_string)) { -+ if (code < 0) -+ return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ if (!r_has_type(Uref, t_string)) - return_error(gs_error_typecheck); -- } -+ - code = dict_find_string(CryptDict, "UE", &UEref); -- if (code < 0 || !r_has_type(UEref, t_string)) { -+ if (code < 0) -+ return code; -+ if (code == 0) -+ return_error(gs_error_undefined); -+ if (!r_has_type(UEref, t_string)) - return_error(gs_error_typecheck); -- } - - pop(2); - op = osp; ---- a/psi/ztoken.c -+++ b/psi/ztoken.c -@@ -356,7 +356,7 @@ - int code = dict_find_string(upref, pnso->pname, &ppcproc); - - /* Update the options only if the parameter has changed. */ -- if (code >= 0) { -+ if (code > 0) { - if (r_has_type(ppcproc, t_null)) - options &= ~pnso->option; - else diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180923~863b370.patch ghostscript-9.26~dfsg+0/debian/patches/020180923~863b370.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180923~863b370.patch 2018-10-18 21:24:09.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180923~863b370.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -Description: permit Mod and CreDate pdfmarks in PDF 2.0 in pdfwrite - Bug 699807 - "-dCompatibilityLevel=2.0` prevents all metadata from being set" - . - PDF 2.0 has deprecated The Document Info dictionary, - so we prevented pdfmarks from modifying the data in it, - as a prelude to removing it potentially - when later versions of the PDF spec are approved. - . - However, as the report says, - the Creation Date and Modification Date are still required - for documents with PieceInfo (only), - so for now we will permit those two values (only) to be set. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=863b370 -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699807 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/devices/vector/gdevpdfm.c -+++ b/devices/vector/gdevpdfm.c -@@ -1970,9 +1970,6 @@ - int code = 0, i; - gs_memory_t *mem = pdev->pdf_memory; - -- if (pdev->CompatibilityLevel >= 2.0) -- return 0; -- - if (count & 1) - return_error(gs_error_rangecheck); - for (i = 0; code >= 0 && i < count; i += 2) { -@@ -1984,6 +1981,11 @@ - - vsize = 0x0badf00d; /* Quiet compiler. */ - -+ if (pdev->CompatibilityLevel >= 2.0) { -+ if (!pdf_key_eq(pairs + i, "/ModDate") && !pdf_key_eq(pairs + i, "/CreationDate")) -+ continue; -+ } -+ - if (pdev->PDFA !=0) { - const gs_param_string *p = pairs + i + 1; - if (p->size > 9 && memcmp(p->data, "(\\376\\377", 9) == 0) { diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180925~0bfd539.patch ghostscript-9.26~dfsg+0/debian/patches/020180925~0bfd539.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180925~0bfd539.patch 2018-10-18 21:25:00.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180925~0bfd539.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Description: Avoid overrunning non terminated string buffer. - Don't call strlen on something that doesn't have a terminator. - Use the stored length instead. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=0bfd539 -Author: Robin Watts -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699809 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/base/gsicc_manage.c -+++ b/base/gsicc_manage.c -@@ -3010,7 +3010,7 @@ - pval->persistent = true; - } else { - pval->data = (byte *)pgs->icc_manager->srcgtag_profile->name; -- pval->size = strlen((const char *)pval->data); -+ pval->size = pgs->icc_manager->srcgtag_profile->name_length; - pval->persistent = false; - } - } diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180925~52a37b6.patch ghostscript-9.26~dfsg+0/debian/patches/020180925~52a37b6.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180925~52a37b6.patch 2018-10-18 21:26:08.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180925~52a37b6.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -Description: Prevent SEGV in gs_setdevice_no_erase. - Prevent SEGV if gsicc_init_iccmanager fails. - . - Error created using :- - MEMENTO_FAILAT=350 ./membin/gpcl6 -sDEVICE=pbmraw -dMaxBitmap=2000 - -o /dev/null ./tests_private/pcl/pcl5cfts/fts.0070 -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=52a37b6 -Author: Shailesh Mistry -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=697545 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/base/gsdevice.c -+++ b/base/gsdevice.c -@@ -498,7 +498,9 @@ - if (libctx->io_device_table != NULL) { - cmm_dev_profile_t *dev_profile; - if (pgs->icc_manager->lab_profile == NULL) { /* pick one not set externally */ -- gsicc_init_iccmanager(pgs); -+ code = gsicc_init_iccmanager(pgs); -+ if (code < 0) -+ return(code); - } - /* Also, if the device profile is not yet set then take care of that - before we start filling pages, if we can */ -@@ -720,7 +722,8 @@ - - if ((code = gs_setdevice_no_erase(pgs, ndev)) < 0) - gs_free_object(pgs->memory, ndev, "gs_copydevice(device)"); -- gs_currentdevice_inline(pgs)->LockSafetyParams = saveLockSafety; -+ if (pgs->device != NULL) -+ pgs->device->LockSafetyParams = saveLockSafety; - } - return code; - } diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180925~efe6d83.patch ghostscript-9.26~dfsg+0/debian/patches/020180925~efe6d83.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180925~efe6d83.patch 2018-10-18 21:27:10.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180925~efe6d83.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Description: Fix uninitialised value for render_cond. - gsicc_get_srcprofile doesn't return a render_cond value in all cases. - This leads to an undefined value being read, - and this can lead to a SEGV. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=efe6d83 -Author: Robin Watts -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699809 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/base/gsicc_cache.c -+++ b/base/gsicc_cache.c -@@ -644,6 +644,7 @@ - { - (*profile) = NULL; - (*render_cond).rendering_intent = gsPERCEPTUAL; -+ (*render_cond).cmm = gsCMM_DEFAULT; - switch (graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS) { - case GS_UNKNOWN_TAG: - case GS_UNTOUCHED_TAG: diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180925~f8ccc7d.patch ghostscript-9.26~dfsg+0/debian/patches/020180925~f8ccc7d.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180925~f8ccc7d.patch 2018-10-18 20:50:20.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180925~f8ccc7d.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -Description: Hide the .needinput operator - This removes the .needinput operator from systemdict, - ensuring it can only be used in the initialization code, - and not called erroneously from random Postscript. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=f8ccc7d -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699793 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -836,12 +836,26 @@ - /.runstring { - 0 0 .systemvmstring .systemvmSFD cvx { .runexec } execute0 - } bind def -+ - % Define the procedure that the C code uses to set up for executing - % a string that may be received in pieces. -+% -+% Immediate evaluation doesn't work on operators (like .needinput) -+% so calling .runstringbegin will throw an undefined error if we -+% undefined .needinput so it cannot be accessed outside the init -+% code. But, we can store the operator in an array, use immediate -+% evaluation on the array to get the operator, then undefined the -+% array (and because they are both of the same name, the operator -+% get undefined too). -+% This prevents random Postscript from erroneously calling .needinput -+% and forcing the interpreter into an invalid state. -+/.needinput -+1 .systemvmarray dup 0 /.needinput load put -+def - /.runstringbegin { -- 1 .systemvmarray dup 0 /.needinput load put cvx % { .needinput } in systemvm -+ 1 .systemvmarray dup 0 //.needinput 0 get put cvx % { .needinput } in systemvm - 0 0 .systemvmstring .systemvmSFD cvx .runexec --} bind def -+} bind executeonly def - - % Define a special version of runlibfile that aborts on errors. - /runlibfile0 -@@ -2216,7 +2230,7 @@ - /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile - /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams - /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice -- /.type /.writecvs /.setSMask /.currentSMask -+ /.type /.writecvs /.setSMask /.currentSMask /.needinput - - % Used by a free user in the Library of Congress. Apparently this is used to - % draw a partial page, which is then filled in by the results of a barcode diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180927~9565f4c.patch ghostscript-9.26~dfsg+0/debian/patches/020180927~9565f4c.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180927~9565f4c.patch 2018-10-18 21:28:21.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180927~9565f4c.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -Description: filenameforall calls bad iodev with insufficent scratch - This was a regression introduced with commit - 65a9046ded8e9edd5d33bc812a9e94ae29607a1e - . - I hadn't realised the cleanup procedure was expected to be called - in the case of both the success *and* error conditions. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=9565f4c -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699813 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/psi/zfile.c -+++ b/psi/zfile.c -@@ -438,7 +438,6 @@ - esp -= 5; /* pop proc, pfen, devlen, iodev , mark */ - return o_pop_estack; - } else if (code > len) { /* overran string */ -- esp -= 5; /* pop proc, pfen, devlen, iodev , mark */ - return_error(gs_error_rangecheck); - } - else if (iodev != iodev_default(imemory) diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020180929~a54c9e6.patch ghostscript-9.26~dfsg+0/debian/patches/020180929~a54c9e6.patch --- ghostscript-9.25~dfsg+1/debian/patches/020180929~a54c9e6.patch 2018-10-18 10:38:23.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020180929~a54c9e6.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,389 +0,0 @@ -Description: Improve hiding of security critical custom operators - Make procedures that use .forceput/.forcedef/.forceundef - into operators. - . - The result of this is that errors get reported - against the "top" operator, - rather than the "called" operator within the procedure. - . - For example: - /myproc - { - myop - } bind def - . - If 'myop' throws an error, - the error handler will be passed the 'myop' operator. - Promoting 'myproc' to a operator means - the error handler will be passed 'myproc'. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=a54c9e6 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699816 -Bug-Debian: https://bugs.debian.org/910678 -Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2018-17961 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_diskn.ps -+++ b/Resource/Init/gs_diskn.ps -@@ -53,7 +53,7 @@ - exch .setglobal - } - if --} .bind executeonly def % must be bound and hidden for .forceput -+} .bind executeonly odef % must be bound and hidden for .forceput - - % Modify .putdevparams to force regeneration of .searchabledevs list - /.putdevparams { ---- a/Resource/Init/gs_dps.ps -+++ b/Resource/Init/gs_dps.ps -@@ -70,7 +70,7 @@ - % Save a copy of the initial gstate. - //systemdict /savedinitialgstate gstate readonly .forceput - .setglobal --} .bind executeonly def % must be bound and hidden for .forceput -+} .bind executeonly odef % must be bound and hidden for .forceput - - % Initialize local dictionaries and gstate when creating a new context. - % Note that until this completes, we are in the anomalous situation of ---- a/Resource/Init/gs_fntem.ps -+++ b/Resource/Init/gs_fntem.ps -@@ -408,7 +408,7 @@ - exit - } loop - exch setglobal --} .bind executeonly def % must be bound and hidden for .forceput -+} .bind executeonly odef % must be bound and hidden for .forceput - - currentdict end /ProcSet defineresource pop - ---- a/Resource/Init/gs_fonts.ps -+++ b/Resource/Init/gs_fonts.ps -@@ -377,8 +377,8 @@ - } - {pop} - ifelse --} .bind executeonly def --systemdict /NONATIVEFONTMAP known //.setnativefontmapbuilt exec -+} .bind executeonly odef -+systemdict /NONATIVEFONTMAP known .setnativefontmapbuilt - /.buildnativefontmap { % - .buildnativefontmap - systemdict /.nativefontmapbuilt .knownget not - { //false} if -@@ -419,7 +419,7 @@ - } forall - } if - % record that we've been run -- //true //.setnativefontmapbuilt exec -+ //true .setnativefontmapbuilt - } ifelse - } bind def - currentdict /.setnativefontmapbuilt .forceundef -@@ -1103,7 +1103,7 @@ - - % Check to make sure the font was actually loaded. - dup 3 index .fontknownget -- { dup /PathLoad 4 index //.putgstringcopy exec -+ { dup /PathLoad 4 index .putgstringcopy - 4 1 roll pop pop pop //true exit - } if - -@@ -1115,7 +1115,7 @@ - { % Stack: origfontname fontdirectory path filefontname - 2 index 1 index .fontknownget - { % Yes. Stack: origfontname fontdirectory path filefontname fontdict -- dup 4 -1 roll /PathLoad exch //.putgstringcopy exec -+ dup 4 -1 roll /PathLoad exch .putgstringcopy - % Stack: origfontname fontdirectory filefontname fontdict - 3 -1 roll pop - % Stack: origfontname filefontname fontdict ---- a/Resource/Init/gs_lev2.ps -+++ b/Resource/Init/gs_lev2.ps -@@ -163,10 +163,11 @@ - % Set them again to the new values. From here on, we are safe, - % since a context switch will consult userparams. - .setuserparams --} .bind executeonly def % must be bound and hidden for .forceput -+} .bind executeonly odef % must be bound and hidden for .forceput - - /setuserparams { % setuserparams - -- .setuserparams2 -+ {.setuserparams2} stopped -+ {/setuserparams load $error /errorname get signalerror} if - } .bind odef - % Initialize user parameters managed here. - /JobName () .definepsuserparam -@@ -415,7 +416,9 @@ - - % VMReclaim and VMThreshold are user parameters. - /setvmthreshold { % setvmthreshold - -- mark /VMThreshold 2 .argindex .dicttomark .setuserparams2 pop -+ mark /VMThreshold 2 .argindex .dicttomark {.setuserparams2} stopped -+ {pop /setvmthreshold load $error /errorname get signalerror} -+ {pop} ifelse - } odef - /vmreclaim { % vmreclaim - - dup 0 gt { -@@ -427,7 +430,9 @@ - ifelse - } { - % VMReclaim userparam controls enable/disable GC -- mark /VMReclaim 2 index .dicttomark .setuserparams2 pop -+ mark /VMReclaim 2 index .dicttomark {.setuserparams2} stopped -+ {pop /vmreclaim load $error /errorname get signalerror} -+ {pop} ifelse - } ifelse - } odef - -1 setvmthreshold ---- a/Resource/Init/gs_pdfwr.ps -+++ b/Resource/Init/gs_pdfwr.ps -@@ -660,7 +660,7 @@ - { - pop - } ifelse --} .bind executeonly def % must be bound and hidden for .forceput -+} .bind executeonly odef % must be bound and hidden for .forceput - - % Use the DSC processing hook to pass DSC comments to the driver. - % We use a pseudo-parameter named DSC whose value is an array: ---- a/Resource/Init/gs_setpd.ps -+++ b/Resource/Init/gs_setpd.ps -@@ -608,6 +608,20 @@ - % in the dictionary with the policy value, - % and we replace the key in the dictionary with its prior value - % (or remove it if it had no prior value). -+ -+% Making this an operator means we can properly hide -+% the contents - specifically .forceput -+/1Policy -+{ -+ % Roll back the failed request to its previous status. -+ SETPDDEBUG { (Rolling back.) = pstack flush } if -+ 3 index 2 index 3 -1 roll .forceput -+ 4 index 1 index .knownget -+ { 4 index 3 1 roll .forceput } -+ { 3 index exch .undef } -+ ifelse -+} bind executeonly odef -+ - /.policyprocs mark - % These procedures are called with the following on the stack: - % -@@ -631,14 +645,7 @@ - /setpagedevice .systemvar /configurationerror signalerror - } ifelse - } bind -- 1 { % Roll back the failed request to its previous status. --SETPDDEBUG { (Rolling back.) = pstack flush } if -- 3 index 2 index 3 -1 roll .forceput -- 4 index 1 index .knownget -- { 4 index 3 1 roll .forceput } -- { 3 index exch .undef } -- ifelse -- } .bind executeonly % must be bound and hidden for .forceput -+ 1 /1Policy load - 7 { % For PageSize only, just impose the request. - 1 index /PageSize eq - { pop pop 1 index /PageSize 7 put } -@@ -646,6 +653,8 @@ - ifelse - } bind - .dicttomark readonly def -+currentdict /1Policy undef -+ - /.applypolicies % .applypolicies - % - { 1 index /Policies get 1 index ---- a/Resource/Init/gs_typ32.ps -+++ b/Resource/Init/gs_typ32.ps -@@ -79,15 +79,19 @@ - .dicttomark /ProcSet defineresource pop - - /.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse --.cidfonttypes begin -- --4 % CIDFontType 4 = FontType 32 --{ dup /FontType 32 .forceput -+/CIDFontType4 -+{ -+ dup /FontType 32 .forceput - dup /CharStrings 20 dict .forceput - 1 index exch .buildfont32 exch pop --} .bind executeonly def % must be bound and hidden for .forceput -+} .bind executeonly odef -+.cidfonttypes begin -+ -+ -+4 /CIDFontType4 load def % CIDFontType 4 = FontType 32 - - end % .cidfonttypes -+currentdict /CIDFontType4 .forceundef - - % Define the BuildGlyph procedure. - % Since Type 32 fonts are indexed by CID, there is no BuildChar procedure. ---- a/Resource/Init/gs_type1.ps -+++ b/Resource/Init/gs_type1.ps -@@ -283,7 +283,7 @@ - } if - 2 copy /WeightVector exch .forceput - .setweightvector --} .bind executeonly def -+} .bind executeonly odef - end - - % Register the font types for definefont. ---- a/Resource/Init/pdf_base.ps -+++ b/Resource/Init/pdf_base.ps -@@ -218,7 +218,7 @@ - } ifelse - } ifelse - } ifelse --} bind executeonly def -+} bind executeonly odef - /PDFScanRules_true << /PDFScanRules //true >> def - /PDFScanRules_null << /PDFScanRules //null >> def - /.pdfrun { % .pdfrun - ---- a/Resource/Init/pdf_draw.ps -+++ b/Resource/Init/pdf_draw.ps -@@ -1158,7 +1158,7 @@ - Q - PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if - PDFfile exch setfileposition --} bind executeonly def -+} bind executeonly odef - - /.pdfpaintproc { - %% Get the /m from pdfopdict (must be present) -@@ -1189,7 +1189,7 @@ - { - switch_to_text_marking_ops - } if --}bind executeonly def -+}bind executeonly odef - - /resolvepattern { % resolvepattern - % Don't do the resolvestream now: just capture the data -@@ -2353,7 +2353,7 @@ - }{ - pdfdict /AppearanceNumber 0 .forceput - } ifelse --}bind executeonly def -+}bind executeonly odef - - /MakeAppearanceName { - pdfdict /AppearanceNumber get -@@ -2382,7 +2382,7 @@ - DoForm - pdfdict /.PreservePDFForm 3 -1 roll .forceput - grestore --} bind executeonly def -+} bind executeonly odef - - /DoForm { - %% save the current value, if its true we will set it to false later, in order -@@ -2541,7 +2541,7 @@ - end - } if - pdfdict /.PreservePDFForm 3 -1 roll .forceput --} bind executeonly def -+} bind executeonly odef - - /_dops_save 1 array def - ---- a/Resource/Init/pdf_font.ps -+++ b/Resource/Init/pdf_font.ps -@@ -718,7 +718,7 @@ - {pop pop pop} - ifelse - --} bind executeonly def -+} bind executeonly odef - - currentdict /.DoToUnicode? .forceundef - -@@ -1241,7 +1241,7 @@ - } bdef - dup currentdict Encoding .processToUnicode - currentdict end .completefont exch pop --} bind executeonly def -+} bind executeonly odef - /.adjustcharwidth { % .adjustcharwidth - % Enforce the metrics, in glyph space, to the values found in the PDF Font object - % - force wy == 0 (assumed, and not stored in the PDF font) -@@ -2026,7 +2026,7 @@ - } if - /findresource cvx /undefined signalerror - } loop --} bind executeonly def -+} bind executeonly odef - - /buildCIDType0 { % buildCIDType0 - dup /BaseFont get findCIDFont exch pop -@@ -2211,7 +2211,7 @@ - /Type0 //buildType0 - /Type1 //buildType1 - /MMType1 //buildType1 -- /Type3 //buildType3 -+ /Type3 /buildType3 load - /TrueType //buildTrueType - /CIDFontType0 //buildCIDType0 - /CIDFontType2 //buildCIDType2 ---- a/Resource/Init/pdf_main.ps -+++ b/Resource/Init/pdf_main.ps -@@ -660,7 +660,7 @@ - } forall - pop - } ifelse --} bind executeonly def -+} bind executeonly odef - - currentdict /pdf_collection_files .undef - -@@ -2715,7 +2715,7 @@ - .setglobal - /RepairedAnError exch def - /Repaired exch def --} bind executeonly def -+} bind executeonly odef - - % Display the contents of a page (including annotations). - /showpagecontents { % showpagecontents - ---- a/Resource/Init/pdf_ops.ps -+++ b/Resource/Init/pdf_ops.ps -@@ -193,7 +193,7 @@ - pdfformaterror - } ifelse - } if --} bind executeonly def -+} bind executeonly odef - - % Save PDF gstate - /qstate { % - qstate -@@ -451,7 +451,7 @@ - %% a gsave, so we haven't copied it to /self, if we don't do that here - %% then transparent annotations cause an invalid access error. - currentdict //nodict eq {/self dup load end 5 dict begin def} if --} bind executeonly def -+} bind executeonly odef - /AIS { .setalphaisshape } bind executeonly def - /BM { - /.setblendmode where { -@@ -1077,7 +1077,7 @@ - pdfopdict /v {inside_text_v} bind .forceput - pdfopdict /y {inside_text_y} bind .forceput - pdfopdict /re {inside_text_re} bind .forceput --} bind executeonly def -+} bind executeonly odef - - /switch_to_normal_marking_ops { - pdfopdict /m {normal_m} bind .forceput -@@ -1086,7 +1086,7 @@ - pdfopdict /v {normal_v} bind .forceput - pdfopdict /y {normal_y} bind .forceput - pdfopdict /re {normal_re} bind .forceput --} bind executeonly def -+} bind executeonly odef - - /BT { - currentdict /TextSaveMatrix known { diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181003~0269a72.patch ghostscript-9.26~dfsg+0/debian/patches/020181003~0269a72.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181003~0269a72.patch 2018-10-18 21:29:20.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181003~0269a72.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -Description: Prevent SEGV after calling gs_image_class_1_simple. - Prevent SEGV if memory allocation fails - leading to penum being freed but then used again later. - . - Error created using :- - MEMENTO_FAILAT=20913 ./membin/gpcl6 -sDEVICE=pbmraw -dMaxBitmap=2000 - -o /dev/null ./tests_private/pcl/pcl5cfts/fts.0100 -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=0269a72 -Author: Shailesh Mistry -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=697545 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/base/gxifast.c -+++ b/base/gxifast.c -@@ -110,9 +110,6 @@ - penum->line = gs_alloc_bytes(penum->memory, - penum->line_size, "image line"); - if (penum->line == 0) { -- gx_default_end_image(penum->dev, -- (gx_image_enum_common_t *) penum, -- false); - return 0; - } - #ifdef PACIFY_VALGRIND diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181003~d06af15.patch ghostscript-9.26~dfsg+0/debian/patches/020181003~d06af15.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181003~d06af15.patch 2018-10-18 21:30:52.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181003~d06af15.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -Description: don't push userdict in preparation for Type 1 fonts - Apparently, Fontographer fonts require a writable dictionary - on the dict stack. - For some reason lost in mists of time, - we pushed userdict for that purpose - - the problem is, that leaves any random redefinition of operators - in place when we interpret the font file. - . - Instead, we now push an empty, temporary dictionary - for those Fontographer fonts. - As we already explicitly push systemdict - (before the writable dictionary) - that ensures a consistent environment - for the interpretation of Type 1 fonts. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=d06af15 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699857 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_type1.ps -+++ b/Resource/Init/gs_type1.ps -@@ -166,7 +166,7 @@ - % However, we can't use any of the other well-known dictionaries - % (such as userdict), since the whole point of pushing systemdict - % is to make sure that nothing important has been redefined. -- /userdict .systemvar begin -+ 32 dict begin - % We can't just use `run', because we want to check for .PFB files. - currentpacking - { //false setpacking .loadfont1 //true setpacking } diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181004before20181002~1778db6.patch ghostscript-9.26~dfsg+0/debian/patches/020181004before20181002~1778db6.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181004before20181002~1778db6.patch 2018-10-18 20:50:25.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181004before20181002~1778db6.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -Description: add control over hiding error handlers. - With a previous commit changing error handling in SAFER - so the handler gets passed a name object - (rather than executable object), - it is less critical to hide the error handlers. - . - This introduces a -dSAFERERRORS option - to force only use of the default error handlers. - . - It also adds a .setsafererrors Postscript call, - meaning a caller, without -dSAFERERRORS, - can create their own default error handlers - (in errordict, as normal), - and then call .setsafererrors - meaning their own handlers are always called. - . - With -dSAFERERRORS or after a call to .setsafererrors, - .setsafererrors is removed. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=1778db6 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699832 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -193,6 +193,16 @@ - currentdict /PARANOIDSAFER known or % PARANOIDSAFER is equivalent - } - ifelse def -+ -+/SAFERERRORS -+currentdict /NOSAFERERRORS known -+{ -+ //false -+} -+{ -+ currentdict /SAFERERRORS known -+} ifelse def -+ - currentdict /SHORTERRORS known /SHORTERRORS exch def - currentdict /TTYPAUSE known /TTYPAUSE exch def - currentdict /WRITESYSTEMDICT known /WRITESYSTEMDICT exch def -@@ -1141,12 +1151,23 @@ - } bind def - end % errordict - --% Put all the default handlers in gserrordict --gserrordict --errordict {2 index 3 1 roll put} forall --noaccess pop --% remove the non-standard errors from errordict -+gserrordict /unknownerror errordict /unknownerror get put - errordict /unknownerror .undef -+ -+/.SAFERERRORLIST ErrorNames def -+/.setsafererrors -+{ -+% Put all the requested handlers in gserrordict -+ gserrordict -+ //.SAFERERRORLIST -+ {dup errordict exch get 2 index 3 1 roll put} forall -+ noaccess pop -+ systemdict /.setsafeerrors .forceundef -+ systemdict /.SAFERERRORLIST .forceundef -+} bind executeonly odef -+ -+SAFERERRORS {.setsafererrors} if -+ - % Define a stable private copy of handleerror that we will always use under - % JOBSERVER mode. - /.GShandleerror errordict /handleerror get def -@@ -1778,18 +1799,15 @@ - - % Bind all the operators defined as procedures. - /.bindoperators % binds operators in currentdict -- { % Temporarily disable the typecheck error. -- errordict /typecheck 2 copy get -- errordict /typecheck { pop } put % pop the command -+ { - currentdict - { dup type /operatortype eq -- { % This might be a real operator, so bind might cause a typecheck, -- % but we've made the error a no-op temporarily. -- .bind -+ { -+ % This might be a real operator, so bind might cause a typecheck -+ {.bind} .internalstopped pop - } - if pop pop - } forall -- put - } def - DELAYBIND not { .bindoperators } if - ---- a/psi/interp.c -+++ b/psi/interp.c -@@ -662,27 +662,18 @@ - if (gs_errorname(i_ctx_p, code, &error_name) < 0) - return code; /* out-of-range error code! */ - -- /* If LockFilePermissions is true, we only refer to gserrordict, which -- * is not accessible to Postcript jobs -+ /* We refer to gserrordict first, which is not accessible to Postcript jobs -+ * If we're running with SAFERERRORS all the handlers are copied to gserrordict -+ * so we'll always find the default one. If not SAFERERRORS, only gs specific -+ * errors are in gserrordict. - */ -- if (i_ctx_p->LockFilePermissions) { -- if (((dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || -- dict_find(perrordict, &error_name, &epref) <= 0)) -- ) -- return code; /* error name not in errordict??? */ -- } -- else { -- /* -- * For greater Adobe compatibility, only the standard PostScript errors -- * are defined in errordict; the rest are in gserrordict. -- */ -- if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || -- (dict_find(perrordict, &error_name, &epref) <= 0 && -- (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || -- dict_find(perrordict, &error_name, &epref) <= 0)) -- ) -- return code; /* error name not in errordict??? */ -- } -+ if (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || -+ (dict_find(perrordict, &error_name, &epref) <= 0 && -+ (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || -+ dict_find(perrordict, &error_name, &epref) <= 0)) -+ ) -+ return code; /* error name not in errordict??? */ -+ - doref = *epref; - epref = &doref; - /* Push the error object on the operand stack if appropriate. */ -@@ -695,6 +686,24 @@ - } - *osp = *perror_object; - errorexec_find(i_ctx_p, osp); -+ /* If using SAFER, hand a name object to the error handler, rather than the executable -+ * object/operator itself. -+ */ -+ if (i_ctx_p->LockFilePermissions) { -+ code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr); -+ if (code < 0) { -+ const char *unknownstr = "--unknown--"; -+ rlen = strlen(unknownstr); -+ memcpy(buf, unknownstr, rlen); -+ } -+ else { -+ buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; -+ rlen += 4; -+ } -+ code = name_ref(imemory, buf, rlen, osp, 1); -+ if (code < 0) -+ make_null(osp); -+ } - } - goto again; - } diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181004really20181002~a680739.patch ghostscript-9.26~dfsg+0/debian/patches/020181004really20181002~a680739.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181004really20181002~a680739.patch 2018-10-18 14:13:35.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181004really20181002~a680739.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -Description: For hidden operators, pass a name object to error handler. - In normal operation, - Postscript error handlers are passed the object - which triggered the error: - this is invariably an operator object. - . - The issue arises when an error is triggered by an operator - which is for internal use only, - and that operator is then passed to the error handler, - meaning it becomes visible to the error handler code. - . - By converting to a name object, the error message is still valid, - but we no longer expose internal use only operators. - . - The change in gs_dps1.ps is related to the above: - previously an error in scheck would throw an error against .gcheck, - but as .gcheck is now a hidden operator, - it resulted in a name object being passed to the error handler. - As scheck is a 'real' operator, - it's better to use the real operator, - rather than the name of an internal, hidden one. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=a680739 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699816 -Bug-Debian: https://bugs.debian.org/910678 -Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2018-17961 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ - For hidden operators, pass a name object to error handler. ---- a/Resource/Init/gs_dps1.ps -+++ b/Resource/Init/gs_dps1.ps -@@ -21,7 +21,7 @@ - % ------ Virtual memory ------ % - - /currentshared /.currentglobal load def --/scheck /.gcheck load def -+/scheck {.gcheck} bind odef - %****** FOLLOWING IS WRONG ****** - /shareddict currentdict /globaldict .knownget not { 20 dict } if def - ---- a/psi/interp.c -+++ b/psi/interp.c -@@ -678,6 +678,8 @@ - epref = &doref; - /* Push the error object on the operand stack if appropriate. */ - if (!GS_ERROR_IS_INTERRUPT(code)) { -+ byte buf[260], *bufptr; -+ uint rlen; - /* Replace the error object if within an oparray or .errorexec. */ - osp++; - if (osp >= ostop) { -@@ -686,23 +688,36 @@ - } - *osp = *perror_object; - errorexec_find(i_ctx_p, osp); -- /* If using SAFER, hand a name object to the error handler, rather than the executable -- * object/operator itself. -- */ -- if (i_ctx_p->LockFilePermissions) { -+ -+ if (!r_has_type(osp, t_string) && !r_has_type(osp, t_name)) { - code = obj_cvs(imemory, osp, buf + 2, 256, &rlen, (const byte **)&bufptr); - if (code < 0) { - const char *unknownstr = "--unknown--"; - rlen = strlen(unknownstr); - memcpy(buf, unknownstr, rlen); -+ bufptr = buf; - } - else { -- buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; -- rlen += 4; -+ ref *tobj; -+ bufptr[rlen] = '\0'; -+ /* Only pass a name object if the operator doesn't exist in systemdict -+ * i.e. it's an internal operator we have hidden -+ */ -+ code = dict_find_string(systemdict, (const char *)bufptr, &tobj); -+ if (code < 0) { -+ buf[0] = buf[1] = buf[rlen + 2] = buf[rlen + 3] = '-'; -+ rlen += 4; -+ bufptr = buf; -+ } -+ else { -+ bufptr = NULL; -+ } -+ } -+ if (bufptr) { -+ code = name_ref(imemory, buf, rlen, osp, 1); -+ if (code < 0) -+ make_null(osp); - } -- code = name_ref(imemory, buf, rlen, osp, 1); -- if (code < 0) -- make_null(osp); - } - } - goto again; diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181009~f1a0787.patch ghostscript-9.26~dfsg+0/debian/patches/020181009~f1a0787.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181009~f1a0787.patch 2018-10-18 21:31:47.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181009~f1a0787.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -Description: Explicitly exclude /unknownerror from the SAFERERRORLIST - Since we remove /unknownerror from errordict, - we want to exclude it - from the list we copy to gserrordict for SAFERERRORS -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=f1a0787 -Author: Chris Liddell -Forwarded: yes -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -1160,7 +1160,13 @@ - % Put all the requested handlers in gserrordict - gserrordict - //.SAFERERRORLIST -- {dup errordict exch get 2 index 3 1 roll put} forall -+ { -+ dup /unknownerror eq -+ {pop} -+ { -+ dup errordict exch get 2 index 3 1 roll put -+ }ifelse -+ }forall - noaccess pop - systemdict /.setsafeerrors .forceundef - systemdict /.SAFERERRORLIST .forceundef diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181010~34cc326.patch ghostscript-9.26~dfsg+0/debian/patches/020181010~34cc326.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181010~34cc326.patch 2018-10-18 20:50:33.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181010~34cc326.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,176 +0,0 @@ -Description: don't include operator arrays in execstack output - When we transfer the contents of the execution stack into the array, - take the extra step of replacing any operator arrays on the stack - with the operator that reference them. - . - This prevents the contents of Postscript defined, - internal only operators (those created with .makeoperator) being exposed - via execstack (and thus, via error handling). - . - This necessitates a change in the resource remapping 'resource', - which contains a procedure - which relies on the contents of the operators arrays being present. - As we already had internal-only variants of countexecstack and execstack - (.countexecstack and .execstack) - - using those, and leaving their operation including the operator arrays - means the procedure continues to work correctly. - . - Both .countexecstack and .execstack are undefined after initialization. - . - Also, when we store the execstack (or part thereof) - for an execstackoverflow error, - make the same oparray/operator substitution as above for execstack. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=34cc326 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699927 -Bug-Debian: https://bugs.debian.org/910758 -Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2018-18073 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -2215,7 +2215,7 @@ - % but can be easily restored (just delete the name from the list in the array). In future - % we may remove the operator and the code implementation entirely. - [ -- /.bitadd /.charboxpath /.cond /.countexecstack /.execstack /.runandhide /.popdevicefilter -+ /.bitadd /.charboxpath /.cond /.runandhide /.popdevicefilter - /.execfile /.filenamesplit /.file_name_parent - /.setdefaultmatrix /.isprocfilter /.unread /.psstringencode - /.buildsampledfunction /.isencapfunction /.currentaccuratecurves /.currentcurvejoin /.currentdashadapt /.currentdotlength -@@ -2254,7 +2254,7 @@ - /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile - /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams - /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice -- /.type /.writecvs /.setSMask /.currentSMask /.needinput -+ /.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack - - % Used by a free user in the Library of Congress. Apparently this is used to - % draw a partial page, which is then filled in by the results of a barcode ---- a/Resource/Init/gs_resmp.ps -+++ b/Resource/Init/gs_resmp.ps -@@ -183,7 +183,7 @@ - % We don't check them. - - currentglobal //false setglobal % bGlobal -- countexecstack array execstack % bGlobal [execstack] -+ //false .countexecstack array //false .execstack % bGlobal [execstack] - dup //null exch % bGlobal [execstack] null [execstack] - length 3 sub -1 0 { % bGlobal [execstack] null i - 2 index exch get % bGlobal [execstack] null proc ---- a/psi/int.mak -+++ b/psi/int.mak -@@ -323,7 +323,7 @@ - - $(PSOBJ)zcontrol.$(OBJ) : $(PSSRC)zcontrol.c $(OP) $(string__h)\ - $(estack_h) $(files_h) $(ipacked_h) $(iutil_h) $(store_h) $(stream_h)\ -- $(INT_MAK) $(MAKEDIRS) -+ $(interp_h) $(INT_MAK) $(MAKEDIRS) - $(PSCC) $(PSO_)zcontrol.$(OBJ) $(C_) $(PSSRC)zcontrol.c - - $(PSOBJ)zdict.$(OBJ) : $(PSSRC)zdict.c $(OP)\ ---- a/psi/interp.c -+++ b/psi/interp.c -@@ -142,7 +142,6 @@ - static int oparray_cleanup(i_ctx_t *); - static int zerrorexec(i_ctx_t *); - static int zfinderrorobject(i_ctx_t *); --static int errorexec_find(i_ctx_t *, ref *); - static int errorexec_pop(i_ctx_t *); - static int errorexec_cleanup(i_ctx_t *); - static int zsetstackprotect(i_ctx_t *); -@@ -761,7 +760,7 @@ - { - uint size = ref_stack_count(pstack) - skip; - uint save_space = ialloc_space(idmemory); -- int code; -+ int code, i; - - if (size > 65535) - size = 65535; -@@ -770,6 +769,15 @@ - if (code >= 0) - code = ref_stack_store(pstack, arr, size, 0, 1, true, idmemory, - "copy_stack"); -+ /* If we are copying the exec stack, try to replace any oparrays with -+ * with the operator than references them -+ */ -+ if (pstack == &e_stack) { -+ for (i = 0; i < size; i++) { -+ if (errorexec_find(i_ctx_p, &arr->value.refs[i]) < 0) -+ make_null(&arr->value.refs[i]); -+ } -+ } - ialloc_set_space(idmemory, save_space); - return code; - } -@@ -1934,7 +1942,7 @@ - * .errorexec with errobj != null, store it in *perror_object and return 1, - * otherwise return 0; - */ --static int -+int - errorexec_find(i_ctx_t *i_ctx_p, ref *perror_object) - { - long i; ---- a/psi/interp.h -+++ b/psi/interp.h -@@ -91,5 +91,7 @@ - /* Define the top-level interface to the interpreter. */ - int gs_interpret(i_ctx_t **pi_ctx_p, ref * pref, int user_errors, - int *pexit_code, ref * perror_object); -+int -+errorexec_find(i_ctx_t *i_ctx_p, ref *perror_object); - - #endif /* interp_INCLUDED */ ---- a/psi/zcontrol.c -+++ b/psi/zcontrol.c -@@ -24,6 +24,7 @@ - #include "ipacked.h" - #include "iutil.h" - #include "store.h" -+#include "interp.h" - - /* Forward references */ - static int check_for_exec(const_os_ptr); -@@ -787,7 +788,7 @@ - /* Continuation operator to do the actual transfer. */ - /* r_size(op1) was set just above. */ - static int --do_execstack(i_ctx_t *i_ctx_p, bool include_marks, os_ptr op1) -+do_execstack(i_ctx_t *i_ctx_p, bool include_marks, bool include_oparrays, os_ptr op1) - { - os_ptr op = osp; - ref *arefs = op1->value.refs; -@@ -829,6 +830,12 @@ - strlen(tname), (const byte *)tname); - break; - } -+ case t_array: -+ case t_shortarray: -+ case t_mixedarray: -+ if (!include_oparrays && errorexec_find(i_ctx_p, rq) < 0) -+ make_null(rq); -+ break; - default: - ; - } -@@ -841,14 +848,14 @@ - { - os_ptr op = osp; - -- return do_execstack(i_ctx_p, false, op); -+ return do_execstack(i_ctx_p, false, false, op); - } - static int - execstack2_continue(i_ctx_t *i_ctx_p) - { - os_ptr op = osp; - -- return do_execstack(i_ctx_p, op->value.boolval, op - 1); -+ return do_execstack(i_ctx_p, op->value.boolval, true, op - 1); - } - - /* - .needinput - */ diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181010~8d19fdf.patch ghostscript-9.26~dfsg+0/debian/patches/020181010~8d19fdf.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181010~8d19fdf.patch 2018-10-18 20:50:37.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181010~8d19fdf.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -Description: Make .forceput unavailable from '.policyprocs' helper dictionary - Bug #69963 "1Policy is a dangerous operator, any callers should be odef" - . - Leaving the .policyprocs dictionary with a procedure - which is a simple wrapper for .forceput - effectively leaves .forceput available. - . - It seems that the only reason to have .policyprocs is - to minimise the code in .applypolicies, - so we can remove the dictionary - and put the code straight into .applypolicies, - which we can then bind and make executeonly, which hides the .forceput. - Also, since we don't need .applypolicies after startup, - we can undefine that from systemdict too. - . - While we're here, review all the uses of .force* to make certain - that there are no other similar cases. - This showed a few places where we hadn't made a function executeonly, - so do that too. - Its probably not required, since I'm reasonably sure - its impossible to load those functions as packed arrays - (they are all defined as operators), - but lets have a belt and braces approach, - the additional time cost is negligible. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=8d19fdf -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699816 -Bug-Debian: https://bugs.debian.org/910678 -Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2018-17961 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_diskn.ps -+++ b/Resource/Init/gs_diskn.ps -@@ -61,7 +61,7 @@ - % doesn't get run enough to justify the complication - //.putdevparams - //systemdict /.searchabledevs .forceundef --} .bind odef % must be bound and hidden for .forceundef -+} .bind executeonly odef % must be bound and hidden for .forceundef - - % ------ extend filenameforall to handle wildcards in %dev% part of pattern -------% - /filenameforall { ---- a/Resource/Init/gs_dps.ps -+++ b/Resource/Init/gs_dps.ps -@@ -124,7 +124,7 @@ - /savedinitialgstate .systemvar setgstate gsave - % Wrap up. - end .setglobal --} odef -+} bind executeonly odef - - % Check whether an object is a procedure. - /.proccheck { % .proccheck ---- a/Resource/Init/gs_epsf.ps -+++ b/Resource/Init/gs_epsf.ps -@@ -31,7 +31,7 @@ - /EPSBoundingBoxState 5 def - /EPSBoundingBoxSetState { - //systemdict /EPSBoundingBoxState 3 -1 roll .forceput --} .bind odef % .forceput must be bound and hidden -+} .bind executeonly odef % .forceput must be bound and hidden - - % Parse 4 numbers for a bounding box - /EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false ---- a/Resource/Init/gs_fonts.ps -+++ b/Resource/Init/gs_fonts.ps -@@ -583,7 +583,7 @@ - } bind def - /.setloadingfont { - //systemdict /.loadingfont 3 -1 roll .forceput --} .bind odef % .forceput must be bound and hidden -+} .bind executeonly odef % .forceput must be bound and hidden - /.loadfont - { % Some buggy fonts leave extra junk on the stack, - % so we have to make a closure that records the stack depth -@@ -1012,7 +1012,7 @@ - dup length string copy - .forceput setglobal - } ifelse --} .bind odef % must be bound and hidden for .forceput -+} .bind executeonly odef % must be bound and hidden for .forceput - - % Attempt to load a font from a file. - /.tryloadfont { % .tryloadfont true ---- a/Resource/Init/gs_init.ps -+++ b/Resource/Init/gs_init.ps -@@ -2254,7 +2254,7 @@ - /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile - /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams - /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice -- /.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack -+ /.type /.writecvs /.setSMask /.currentSMask /.needinput /.countexecstack /.execstack /.applypolicies - - % Used by a free user in the Library of Congress. Apparently this is used to - % draw a partial page, which is then filled in by the results of a barcode ---- a/Resource/Init/gs_setpd.ps -+++ b/Resource/Init/gs_setpd.ps -@@ -609,6 +609,23 @@ - % and we replace the key in the dictionary with its prior value - % (or remove it if it had no prior value). - -+% These procedures are called with the following on the stack: -+% -+% They are expected to consume the top 2 operands. -+% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize) -+% the same as 0, i.e., we signal an error. -+/0Policy { % Set errorinfo and signal a configurationerror. -+ NOMEDIAATTRS { -+ % NOMEDIAATTRS means that the default policy is 7... -+ pop 2 index exch 7 put -+ } { -+ pop dup 4 index exch get 2 array astore -+ $error /errorinfo 3 -1 roll put -+ cleartomark -+ /setpagedevice .systemvar /configurationerror signalerror -+ } ifelse -+} bind executeonly odef -+ - % Making this an operator means we can properly hide - % the contents - specifically .forceput - /1Policy -@@ -617,59 +634,46 @@ - SETPDDEBUG { (Rolling back.) = pstack flush } if - 3 index 2 index 3 -1 roll .forceput - 4 index 1 index .knownget -- { 4 index 3 1 roll .forceput } -- { 3 index exch .undef } -+ { 4 index 3 1 roll .forceput } -+ { 3 index exch .undef } - ifelse - } bind executeonly odef - --/.policyprocs mark --% These procedures are called with the following on the stack: --% --% They are expected to consume the top 2 operands. --% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize) --% the same as 0, i.e., we signal an error. --% --% M. Sweet, Easy Software Products: --% --% Define NOMEDIAATTRS to turn off the default (but unimplementable) media --% selection policies for setpagedevice. This is used by CUPS to support --% the standard Adobe media attributes. -- 0 { % Set errorinfo and signal a configurationerror. -- NOMEDIAATTRS { -- % NOMEDIAATTRS means that the default policy is 7... -- pop 2 index exch 7 put -- } { -- pop dup 4 index exch get 2 array astore -- $error /errorinfo 3 -1 roll put -- cleartomark -- /setpagedevice .systemvar /configurationerror signalerror -- } ifelse -- } bind -- 1 /1Policy load -- 7 { % For PageSize only, just impose the request. -- 1 index /PageSize eq -- { pop pop 1 index /PageSize 7 put } -- { .policyprocs 0 get exec } -- ifelse -- } bind --.dicttomark readonly def --currentdict /1Policy undef -+/7Policy { % For PageSize only, just impose the request. -+ 1 index /PageSize eq -+ { pop pop 1 index /PageSize 7 put } -+ { .policyprocs 0 get exec } -+ ifelse -+} bind executeonly odef - - /.applypolicies % .applypolicies - % -- { 1 index /Policies get 1 index -- { type /integertype eq -- { pop % already processed -- } -- { 2 copy .knownget not { 1 index /PolicyNotFound get } if -- % Stack: -- % -- .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec -- } -- ifelse -- } -- forall pop -- } bind def -+{ -+ 1 index /Policies get 1 index -+ { type /integertype eq -+ { -+ pop % already processed -+ }{ -+ 2 copy .knownget not { 1 index /PolicyNotFound get } if -+ % Stack: -+ % -+ dup 1 eq { -+ 1Policy -+ }{ -+ dup 7 eq { -+ 7Policy -+ }{ -+ 0Policy -+ } ifelse -+ } ifelse -+ } ifelse -+ } -+ forall pop -+} bind executeonly odef -+ -+currentdict /0Policy undef -+currentdict /1Policy undef -+currentdict /7Policy undef - - % Prepare to present parameters to the device, by spreading them onto the - % operand stack and removing any that shouldn't be presented. -@@ -1017,7 +1021,7 @@ - .postinstall - } ifelse - setglobal % return to original VM allocation mode --} odef -+} bind executeonly odef - - % We break out the code after calling the Install procedure into a - % separate procedure, since it is executed even if Install causes an error. diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181010~a5a9bf8.patch ghostscript-9.26~dfsg+0/debian/patches/020181010~a5a9bf8.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181010~a5a9bf8.patch 2018-10-18 14:13:49.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181010~a5a9bf8.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -Description: .loadfontloop must be an operator - In the fix for Bug 699816, - I omitted to make .loadfontloop into an operator, - to better hide .forceundef and .putgstringcopy. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=a5a9bf8 -Author: Chris Liddell -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699938 -Bug-Debian: https://bugs.debian.org/911175 -Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2018-18284 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_fonts.ps -+++ b/Resource/Init/gs_fonts.ps -@@ -1148,7 +1148,7 @@ - - } loop % end of loop - -- } bind executeonly def % must be bound and hidden for .putgstringcopy -+ } bind executeonly odef % must be bound and hidden for .putgstringcopy - - currentdict /.putgstringcopy .undef - diff -Nru ghostscript-9.25~dfsg+1/debian/patches/020181015~30cd347.patch ghostscript-9.26~dfsg+0/debian/patches/020181015~30cd347.patch --- ghostscript-9.25~dfsg+1/debian/patches/020181015~30cd347.patch 2018-10-18 21:34:28.000000000 +0000 +++ ghostscript-9.26~dfsg+0/debian/patches/020181015~30cd347.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,338 +0,0 @@ -Description: font parsing - prevent SEGV in .cffparse - Bug #699961 "currentcolortransfer procs crash .parsecff" - . - zparsecff checked the operand for being an array - (and not a packed array) - but the returned procedures from the default currentcolortransfer - are arrays, not packed arrays. - This led to the code trying to dereference a NULL pointer. - . - Add a specific check for the 'refs' pointer being NULL - before we try to use it. - . - Additionally, - make the StartData procedure in the CFF Font Resource executeonly - to prevent pulling the hidden .parsecff operator out and using it. - Finally, extend this to other resource types. -Origin: upstream, http://git.ghostscript.com/?p=ghostpdl.git;h=30cd347 -Author: Ken Sharp -Forwarded: yes -Bug: http://bugs.ghostscript.com/show_bug.cgi?id=699961 -Last-Update: 2018-10-18 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/Resource/Init/gs_cff.ps -+++ b/Resource/Init/gs_cff.ps -@@ -199,7 +199,7 @@ - % ordinary CFF font. - /StartData { % StartData - - currentfile exch subfilefilter //false //false ReadData pop --} bind def -+} bind executeonly def - /ReadData { % ReadData - % Initialize. - -@@ -234,7 +234,7 @@ - end % FontSetInit ProcSet - /FontSet defineresource - --} bind def -+} bind executeonly def - - % ---------------- Resource category definition ---------------- % - ---- a/Resource/Init/gs_cidcm.ps -+++ b/Resource/Init/gs_cidcm.ps -@@ -327,7 +327,7 @@ - //FindResource exec - } ifelse - } ifelse --} bind def -+} bind executeonly def - - /ResourceStatus { % ResourceStatus true - % ResourceStatus false -@@ -359,7 +359,7 @@ - //false - } ifelse - } ifelse --} bind def -+} bind executeonly def - - /ResourceForAll { %