summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/cal.mak12
-rw-r--r--base/fapi_ft.c77
-rw-r--r--base/freetype.mak16
-rw-r--r--base/gdevabuf.c38
-rw-r--r--base/gdevdflt.c41
-rw-r--r--base/gdevepo.c3
-rw-r--r--base/gdevflp.c335
-rw-r--r--base/gdevflp.h9
-rw-r--r--base/gdevkrnlsclass.c7
-rw-r--r--base/gdevm8.c7
-rw-r--r--base/gdevmpla.c28
-rw-r--r--base/gdevnfwd.c16
-rw-r--r--base/gdevnup.c9
-rw-r--r--base/gdevoflt.c107
-rw-r--r--base/gdevp14.c160
-rw-r--r--base/gdevprn.c10
-rw-r--r--base/gdevsclass.c114
-rw-r--r--base/gdevsclass.h4
-rw-r--r--base/gsargs.c43
-rw-r--r--base/gscdefs.h9
-rw-r--r--base/gscdevn.c11
-rw-r--r--base/gscms.h5
-rw-r--r--base/gscspace.h3
-rw-r--r--base/gsdevice.c6
-rw-r--r--base/gsdparam.c113
-rw-r--r--base/gsdps1.c32
-rw-r--r--base/gsequivc.c10
-rw-r--r--base/gsequivc.h2
-rw-r--r--base/gserrors.h13
-rw-r--r--base/gsfcmap.c1
-rw-r--r--base/gsftopts.h11
-rw-r--r--base/gsgstate.c10
-rw-r--r--base/gsht.c6
-rw-r--r--base/gshtscr.c11
-rw-r--r--base/gsicc.c4
-rw-r--r--base/gsicc_blacktext.c262
-rw-r--r--base/gsicc_blacktext.h23
-rw-r--r--base/gsicc_cache.c84
-rw-r--r--base/gsicc_cache.h2
-rw-r--r--base/gsicc_cms.h2
-rw-r--r--base/gsicc_lcms2mt.c1
-rw-r--r--base/gsicc_manage.c47
-rw-r--r--base/gsicc_nocm.c10
-rw-r--r--base/gsicc_profilecache.c21
-rw-r--r--base/gsmchunk.c31
-rw-r--r--base/gsovrc.c52
-rw-r--r--base/gspaint.c118
-rw-r--r--base/gsparamx.c9
-rw-r--r--base/gspath1.c15
-rw-r--r--base/gsptype1.c21
-rw-r--r--base/gssprintf.c19
-rw-r--r--base/gssprintf.h5
-rw-r--r--base/gstext.c36
-rw-r--r--base/gstiffio.c8
-rw-r--r--base/gstiffio.h3
-rw-r--r--base/gstrans.c31
-rw-r--r--base/gstrans.h3
-rw-r--r--base/gstype2.c21
-rw-r--r--base/gstype42.c36
-rw-r--r--base/gxblend.c10
-rw-r--r--base/gxchar.c13
-rw-r--r--base/gxcldev.h6
-rw-r--r--base/gxclimag.c17
-rw-r--r--base/gxclipm.c3
-rw-r--r--base/gxclist.c4
-rw-r--r--base/gxclpath.c105
-rw-r--r--base/gxclpath.h3
-rw-r--r--base/gxclrast.c52
-rw-r--r--base/gxclread.c6
-rw-r--r--base/gxclthrd.c17
-rw-r--r--base/gxcmap.c25
-rw-r--r--base/gxcpath.c8
-rw-r--r--base/gxdevcli.h14
-rw-r--r--base/gxdevice.h10
-rw-r--r--base/gxdevsop.h10
-rw-r--r--base/gxdownscale.c2
-rw-r--r--base/gxfapi.h4
-rw-r--r--base/gxfill.c11
-rw-r--r--base/gxgstate.h8
-rw-r--r--base/gxipixel.c64
-rw-r--r--base/gxiscale.c32
-rw-r--r--base/gxp1fill.c6
-rw-r--r--base/gxpaint.c10
-rw-r--r--base/gxpcmap.c89
-rw-r--r--base/gxpcolor.h5
-rw-r--r--base/gxpflat.c10
-rw-r--r--base/gxshade6.c3
-rw-r--r--base/gxstroke.c10
-rw-r--r--base/gxtext.h4
-rw-r--r--base/gxttfb.c21
-rw-r--r--base/gxtype1.c40
-rw-r--r--base/gxtype1.h4
-rw-r--r--base/lcms2mt.mak13
-rw-r--r--base/lib.mak21
-rw-r--r--base/mkromfs.c9
-rw-r--r--base/msvclib.mak15
-rw-r--r--base/pagelist.c246
-rw-r--r--base/pagelist.h33
-rw-r--r--base/scfd.c11
-rw-r--r--base/siscale.c31
-rw-r--r--base/spdiff.c11
-rw-r--r--base/stream.c11
-rw-r--r--base/ttfmain.c41
-rw-r--r--base/ttfoutl.h4
-rw-r--r--base/ttinterp.c39
-rw-r--r--base/ttobjs.c5
-rw-r--r--base/unix-gcc.mak1
-rw-r--r--base/version.mak8
-rw-r--r--base/winlib.mak5
109 files changed, 2296 insertions, 977 deletions
diff --git a/base/cal.mak b/base/cal.mak
index 606c2f2b..51665f7a 100644
--- a/base/cal.mak
+++ b/base/cal.mak
@@ -1,4 +1,4 @@
-# Copyright (C) 2019-2021 Artifex Software, Inc.
+# Copyright (C) 2019-2022 Artifex Software, Inc.
# All Rights Reserved.
#
# This software is provided AS-IS with no warranty, either express or
@@ -82,7 +82,7 @@ $(GLOBJ)cal.dev : $(ECHOGS_XE) $(cal_OBJS) \
$(SETMOD) $(GLOBJ)cal $(cal_OBJS)
# define our specific compiler
-CAL_CC=$(CC) $(CCFLAGS) $(CAL_CFLAGS) $(I_)$(CAL_GEN)$(_I) $(I_)$(CAL_SRC)$(_I)
+CAL_CC=$(CC) $(CCFLAGS) $(CAL_CFLAGS) $(I_)$(LCMS2MTSRCDIR)$(D)include $(I_)$(CAL_GEN)$(_I) $(I_)$(CAL_SRC)$(_I)
CAL_O=$(O_)$(CAL_OBJ)$(CAL_PREFIX)
CAL_DEP=$(AK) $(CAL_MAK) $(MAKEDIRS)
@@ -103,16 +103,16 @@ $(CAL_OBJ)$(CAL_PREFIX)doubler.$(OBJ) : $(CAL_SRC)doubler.c $(cal_HDRS) $(CAL_DE
$(CAL_CC) $(CAL_SSE4_2_CFLAGS) $(CAL_NEON_CFLAGS) $(CAL_O)doubler.$(OBJ) $(C_) $(CAL_SRC)doubler.c
$(CAL_OBJ)$(CAL_PREFIX)cmsavx2.$(OBJ) : $(CAL_SRC)cmsavx2.c $(cal_HDRS) $(CAL_DEP)
- $(CAL_CC) $(CAL_AVX2_CFLAGS) $(I_)$(LCMS2MTSRCDIR)$(D)include $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)cmsavx2.$(OBJ) $(C_) $(CAL_SRC)cmsavx2.c
+ $(CAL_CC) $(CAL_AVX2_CFLAGS) $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)cmsavx2.$(OBJ) $(C_) $(CAL_SRC)cmsavx2.c
$(CAL_OBJ)$(CAL_PREFIX)cmssse42.$(OBJ) : $(CAL_SRC)cmssse42.c $(cal_HDRS) $(CAL_DEP)
- $(CAL_CC) $(CAL_SSE4_2_CFLAGS) $(I_)$(LCMS2MTSRCDIR)$(D)include $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)cmssse42.$(OBJ) $(C_) $(CAL_SRC)cmssse42.c
+ $(CAL_CC) $(CAL_SSE4_2_CFLAGS) $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)cmssse42.$(OBJ) $(C_) $(CAL_SRC)cmssse42.c
$(CAL_OBJ)$(CAL_PREFIX)cmsneon.$(OBJ) : $(CAL_SRC)cmsneon.c $(cal_HDRS) $(CAL_DEP)
- $(CAL_CC) $(CAL_SSE4_2_CFLAGS) $(CAL_NEON_CFLAGS) $(I_)$(LCMS2MTSRCDIR)$(D)include $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)cmsneon.$(OBJ) $(C_) $(CAL_SRC)cmsneon.c
+ $(CAL_CC) $(CAL_SSE4_2_CFLAGS) $(CAL_NEON_CFLAGS) $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)cmsneon.$(OBJ) $(C_) $(CAL_SRC)cmsneon.c
$(CAL_OBJ)$(CAL_PREFIX)lcms2mt_cal.$(OBJ) : $(CAL_SRC)lcms2mt_cal.c $(cal_HDRS) $(CAL_DEP) $(gsmemory_h)
- $(CAL_CC) $(I_)$(LCMS2MTSRCDIR)$(D)include $(I_)$(GLSRC) $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)lcms2mt_cal.$(OBJ) $(C_) $(CAL_SRC)lcms2mt_cal.c
+ $(CAL_CC) $(I_)$(GLSRC) $(I_)$(LCMS2MTSRCDIR)$(D)src $(CAL_O)lcms2mt_cal.$(OBJ) $(C_) $(CAL_SRC)lcms2mt_cal.c
$(CAL_OBJ)$(CAL_PREFIX)blendavx2.$(OBJ) : $(CAL_SRC)blendavx2.c $(cal_HDRS) $(CAL_DEP) $(gxblend_h)
$(CAL_CC) $(CAL_AVX2_CFLAGS) $(I_)$(GLSRC) $(CAL_O)blendavx2.$(OBJ) $(C_) $(CAL_SRC)blendavx2.c
diff --git a/base/fapi_ft.c b/base/fapi_ft.c
index c7cb22ea..a4b4fe69 100644
--- a/base/fapi_ft.c
+++ b/base/fapi_ft.c
@@ -59,7 +59,6 @@
#include FT_TRUETYPE_TABLES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_TYPE1_TABLES_H
-#include FT_SIZES_H
/* Note: structure definitions here start with FF_, which stands for 'FAPI FreeType". */
@@ -707,20 +706,6 @@ load_glyph(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font,
if (ft_error == FT_Err_Out_Of_Memory
|| ft_error == FT_Err_Array_Too_Large) {
- /* An out of memory error can leave the FT TTF hinting context in a partially initialized state.
- Meaning bad things can happen if we try to render another glyph using the same context.
- Ideally this would be handled by FT internally, but that means some implications for supporting
- out of spec fonts, and performance.
- By destroying, recreating and resetting the size, it invalidates the (possibly corrupt) hinting
- context, and ensures a fresh start in any subsequent call.
- */
- FT_Size ftsize = NULL;
- FT_Done_Size(ft_face->size);
- FT_New_Size(face->ft_face, &ftsize);
- FT_Activate_Size(ftsize);
- ft_error = FT_Set_Char_Size(face->ft_face, face->width, face->height, face->horz_res, face->vert_res);
- if (ft_error != 0) return_error(gs_error_invalidfont);
-
return (gs_error_VMerror);
}
@@ -857,7 +842,7 @@ load_glyph(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font,
FF_free(s->ftmemory, bmg);
}
}
- else {
+ else if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
FT_OutlineGlyph olg;
ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & olg);
@@ -1292,31 +1277,45 @@ gs_fapi_ft_get_scaled_font(gs_fapi_server * a_server, gs_fapi_font * a_font,
/* Get the length of the TrueType data. */
unsigned long ms;
- code = a_font->get_long(a_font, gs_fapi_font_feature_TT_size, 0, &ms);
- if (code < 0)
- return code;
- if (ms == 0)
- return_error(gs_error_invalidfont);
-
- open_args.memory_size = (FT_Long)ms;
-
- /* Load the TrueType data into a single buffer. */
- open_args.memory_base = own_font_data =
- FF_alloc(s->ftmemory, open_args.memory_size);
- if (!own_font_data)
- return_error(gs_error_VMerror);
-
- own_font_data_len = open_args.memory_size;
+ if (a_font->retrieve_tt_font != NULL) {
+ code = a_font->retrieve_tt_font(a_font, &own_font_data, &ms);
+ if (code == 0) {
+ data_owned = false;
+ open_args.memory_base = own_font_data;
+ open_args.memory_size = own_font_data_len = ms;
+ }
+ }
+ else
+ code = gs_error_unregistered;
- code = a_font->serialize_tt_font(a_font, own_font_data,
- open_args.memory_size);
- if (code < 0)
- return code;
+ if (code < 0) {
+ code = a_font->get_long(a_font, gs_fapi_font_feature_TT_size, 0, &ms);
+ if (code < 0)
+ return code;
+ if (ms == 0)
+ return_error(gs_error_invalidfont);
+
+ open_args.memory_size = (FT_Long)ms;
+
+ /* Load the TrueType data into a single buffer. */
+ open_args.memory_base = own_font_data =
+ FF_alloc(s->ftmemory, open_args.memory_size);
+ if (!own_font_data)
+ return_error(gs_error_VMerror);
+
+ own_font_data_len = open_args.memory_size;
+
+ code = a_font->serialize_tt_font(a_font, own_font_data,
+ open_args.memory_size);
+ if (code < 0)
+ return code;
+ }
/* We always load incrementally. */
ft_inc_int = new_inc_int(a_server, a_font);
if (!ft_inc_int) {
- FF_free(s->ftmemory, own_font_data);
+ if (data_owned)
+ FF_free(s->ftmemory, own_font_data);
return_error(gs_error_VMerror);
}
}
@@ -1334,7 +1333,8 @@ gs_fapi_ft_get_scaled_font(gs_fapi_server * a_server, gs_fapi_font * a_font,
&ft_face);
if (ft_error) {
delete_inc_int (a_server, ft_inc_int);
- FF_free(s->ftmemory, own_font_data);
+ if (data_owned)
+ FF_free(s->ftmemory, own_font_data);
return ft_to_gs_error(ft_error);
}
}
@@ -1344,7 +1344,8 @@ gs_fapi_ft_get_scaled_font(gs_fapi_server * a_server, gs_fapi_font * a_font,
new_face(a_server, ft_face, ft_inc_int, ft_strm,
own_font_data, own_font_data_len, data_owned);
if (!face) {
- FF_free(s->ftmemory, own_font_data);
+ if (data_owned)
+ FF_free(s->ftmemory, own_font_data);
FT_Done_Face(ft_face);
delete_inc_int(a_server, ft_inc_int);
return_error(gs_error_VMerror);
diff --git a/base/freetype.mak b/base/freetype.mak
index eda8c46c..0ee15c90 100644
--- a/base/freetype.mak
+++ b/base/freetype.mak
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2021 Artifex Software, Inc.
+# Copyright (C) 2001-2022 Artifex Software, Inc.
# All Rights Reserved.
#
# This software is provided AS-IS with no warranty, either express or
@@ -33,10 +33,9 @@ FTO_=$(O_)$(FTOBJ)
# Define our local compiler alias
# we must define FT2_BUILD_LIBRARY to get internal declarations
# If GS is using the system zlib, freetype should also do so,
-# FT_CONFIG_SYSTEM_ZLIB is set by the top makefile.
-FTCC=$(CC) $(I_)$(FTGEN)$(_I) $(I_)$(FTSRCDIR)$(D)include$(_I) \
+FTCC=$(CC) $(I_)$(FTGEN)$(_I) $(I_)$(FTSRCDIR)$(D)include$(_I) $(FT_CFLAGS) \
$(D_)FT_CONFIG_OPTIONS_H=\"$(FTCONFH)\"$(_D) $(D_)FT2_BUILD_LIBRARY$(_D) \
- $(D_)DARWIN_NO_CARBON$(_D) $(FT_CONFIG_SYSTEM_ZLIB) $(CCFLAGS)
+ $(D_)DARWIN_NO_CARBON$(_D) $(D_)FT_CONFIG_OPTION_SYSTEM_ZLIB$(_D) $(CCFLAGS)
# Define the name of this makefile.
FT_MAK=$(GLSRC)freetype.mak $(TOP_MAKEFILES)
@@ -214,6 +213,9 @@ ft_sdf=\
$(FTOBJ)ftsdfcommon.$(OBJ) \
$(FTOBJ)ftsdfrend.$(OBJ) \
+ft_svg=\
+ $(FTOBJ)ftsvg.$(OBJ)
+
# instantiate the requested build option (shared or compiled in)
$(FTGEN)freetype.dev : $(FTGEN)freetype_$(SHARE_FT).dev $(FT_MAK) $(GENFTCONFH) $(MAKEDIRS)
$(CP_) $(FTGEN)freetype_$(SHARE_FT).dev $(FTGEN)freetype.dev
@@ -228,7 +230,7 @@ $(FTGEN)freetype_0.dev : $(FT_MAK) $(ECHOGS_XE) \
$(ft_autofit) $(ft_base) $(ft_bdf) $(ft_cache) $(ft_cff) $(ft_cid) \
$(ft_gzip) $(ft_lzw) $(ft_pcf) $(ft_pfr) $(ft_psaux) $(ft_pshinter) \
$(ft_psnames) $(ft_raster) $(ft_smooth) $(ft_sfnt) $(ft_truetype) \
- $(ft_type1) $(ft_type42) $(ft_winfonts) $(ft_sdf) $(GENFTCONFH) $(MAKEDIRS)
+ $(ft_type1) $(ft_type42) $(ft_winfonts) $(ft_sdf) $(ft_svg) $(GENFTCONFH) $(MAKEDIRS)
$(SETMOD) $(FTGEN)freetype_0 $(ft_autofit)
$(ADDMOD) $(FTGEN)freetype_0 $(ft_base)
$(ADDMOD) $(FTGEN)freetype_0 $(ft_bdf)
@@ -250,6 +252,7 @@ $(FTGEN)freetype_0.dev : $(FT_MAK) $(ECHOGS_XE) \
$(ADDMOD) $(FTGEN)freetype_0 $(ft_type42)
$(ADDMOD) $(FTGEN)freetype_0 $(ft_winfonts)
$(ADDMOD) $(FTGEN)freetype_0 $(ft_sdf)
+ $(ADDMOD) $(FTGEN)freetype_0 $(ft_svg)
# custom build rules for each source file
@@ -664,3 +667,6 @@ $(FTOBJ)ftsdfcommon.$(OBJ) : $(FTSRC)sdf$(D)ftsdfcommon.c $(FT_MAK) $(GENFTCONFH
$(FTOBJ)ftsdfrend.$(OBJ) : $(FTSRC)sdf$(D)ftsdfrend.c $(FT_MAK) $(GENFTCONFH) $(MAKEDIRS)
$(FTCC) $(FTO_)ftsdfrend.$(OBJ) $(C_) $(FTSRC)sdf$(D)ftsdfrend.c
+
+$(FTOBJ)ftsvg.$(OBJ) : $(FTSRC)svg$(D)ftsvg.c $(FT_MAK) $(GENFTCONFH) $(MAKEDIRS)
+ $(FTCC) $(FTO_)ftsvg.$(OBJ) $(C_) $(FTSRC)svg$(D)ftsvg.c
diff --git a/base/gdevabuf.c b/base/gdevabuf.c
index e22418a3..7430c66e 100644
--- a/base/gdevabuf.c
+++ b/base/gdevabuf.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -22,6 +22,7 @@
#include "gdevmem.h" /* private definitions */
#include "gzstate.h"
#include "gxdevcli.h"
+#include "gxdevsop.h"
/* ================ Alpha devices ================ */
@@ -74,6 +75,7 @@ static dev_proc_copy_mono(mem_abuf_copy_mono);
static dev_proc_fill_rectangle(mem_abuf_fill_rectangle);
static dev_proc_get_clipping_box(mem_abuf_get_clipping_box);
static dev_proc_fill_rectangle_hl_color(mem_abuf_fill_rectangle_hl_color);
+static dev_proc_fill_stroke_path(mem_abuf_fill_stroke_path);
/* The device descriptor. */
static void
@@ -88,6 +90,7 @@ mem_alpha_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, copy_color, gx_default_copy_color);
set_dev_proc(dev, strip_copy_rop2, gx_no_strip_copy_rop2);
set_dev_proc(dev, fill_rectangle_hl_color, mem_abuf_fill_rectangle_hl_color);
+ set_dev_proc(dev, fill_stroke_path, mem_abuf_fill_stroke_path);
}
static const gx_device_memory mem_alpha_buffer_device =
@@ -414,6 +417,39 @@ mem_abuf_fill_rectangle_hl_color(gx_device * dev, const gs_fixed_rect *rect,
return 0;
}
+/*
+ * Fill/Stroke a path. This is the default implementation of the driver
+ * fill_path procedure.
+ */
+int
+mem_abuf_fill_stroke_path(gx_device * pdev, const gs_gstate * pgs,
+ gx_path * ppath,
+ const gx_fill_params * params_fill,
+ const gx_device_color * pdevc_fill,
+ const gx_stroke_params * params_stroke,
+ const gx_device_color * pdevc_stroke,
+ const gx_clip_path * pcpath)
+{
+ int orig_state;
+ int code;
+
+ orig_state = dev_proc(pdev, dev_spec_op)(pdev, gxdso_overprint_op, (void *)OP_STATE_FILL, 0);
+ code = dev_proc(pdev, fill_path)(pdev, pgs, ppath, params_fill, pdevc_fill, pcpath);
+
+ if (code < 0)
+ return code;
+ /* Swap colors to make sure the pgs colorspace is correct for stroke */
+ gs_swapcolors_quick(pgs);
+ (void)dev_proc(pdev, dev_spec_op)(pdev, gxdso_overprint_op, (void *)OP_STATE_STROKE, 0);
+ code = dev_proc(pdev, stroke_path)(pdev, pgs, ppath, params_stroke, pdevc_stroke, pcpath);
+ gs_swapcolors_quick(pgs);
+ if (orig_state >= 0)
+ (void)dev_proc(pdev, dev_spec_op)(pdev, gxdso_overprint_op, (void *)(intptr_t)orig_state, 0);
+
+ return code;
+}
+
+
/* Get the clipping box. We must scale this up by the number of alpha bits. */
static void
mem_abuf_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
diff --git a/base/gdevdflt.c b/base/gdevdflt.c
index f93e968d..df85e1f9 100644
--- a/base/gdevdflt.c
+++ b/base/gdevdflt.c
@@ -729,6 +729,7 @@ gx_device_fill_in_procs(register gx_device * dev)
fill_dev_proc(dev, process_page, gx_default_process_page);
fill_dev_proc(dev, transform_pixel_region, gx_default_transform_pixel_region);
fill_dev_proc(dev, fill_stroke_path, gx_default_fill_stroke_path);
+ fill_dev_proc(dev, lock_pattern, gx_default_lock_pattern);
}
@@ -1260,6 +1261,7 @@ int gx_copy_device_procs(gx_device *dest, const gx_device *src, const gx_device
set_dev_proc(dest, process_page, dev_proc(&prototype, process_page));
set_dev_proc(dest, transform_pixel_region, dev_proc(&prototype, transform_pixel_region));
set_dev_proc(dest, fill_stroke_path, dev_proc(&prototype, fill_stroke_path));
+ set_dev_proc(dest, lock_pattern, dev_proc(&prototype, lock_pattern));
/*
* We absolutely must set the 'set_graphics_type_tag' to the default subclass one
@@ -1346,6 +1348,9 @@ int gx_device_subclass(gx_device *dev_to_subclass, gx_device *new_prototype, uns
child_dev->stype = a_std;
child_dev->stype_is_dynamic = 1;
+ /* At this point, the only counted reference to the child is from its parent, and we need it to use the right allocator */
+ rc_init(child_dev, dev_to_subclass->memory->stable_memory, 1);
+
psubclass_data = (void *)gs_alloc_bytes(dev_to_subclass->memory->non_gc_memory, private_data_size, "subclass memory for subclassing device");
if (psubclass_data == 0){
gs_free_const_object(dev_to_subclass->memory->non_gc_memory, b_std, "gs_device_subclass(stype)");
@@ -1431,12 +1436,15 @@ void gx_device_unsubclass(gx_device *dev)
gx_device *parent, *child;
gs_memory_struct_type_t *a_std = 0, *b_std = 0;
int dynamic, ref_count;
+ gs_memory_t *rcmem;
/* This should not happen... */
if (!dev)
return;
ref_count = dev->rc.ref_count;
+ rcmem = dev->rc.memory;
+
child = dev->child;
psubclass_data = (generic_subclass_data *)dev->subclass_data;
parent = dev->parent;
@@ -1483,6 +1491,7 @@ void gx_device_unsubclass(gx_device *dev)
* when we copy back the subclassed device.
*/
dev->rc.ref_count = ref_count;
+ dev->rc.memory = rcmem;
/* If we have a chain of devices, make sure the chain beyond the
* device we're unsubclassing doesn't get broken, we need to
@@ -1501,12 +1510,6 @@ void gx_device_unsubclass(gx_device *dev)
* devices it's possible that their child pointer can then be NULL.
*/
if (child) {
- if (child->icc_struct)
- rc_decrement(child->icc_struct, "gx_device_unsubclass, icc_struct");
- if (child->PageList)
- rc_decrement(child->PageList, "gx_device_unsubclass, PageList");
- if (child->NupControl)
- rc_decrement(child->NupControl, "gx_device_unsubclass, NupControl");
/* We cannot afford to free the child device if its stype is not
* dynamic because we can't 'null' the finalise routine, and we
* cannot permit the device to be finalised because we have copied
@@ -1519,8 +1522,7 @@ void gx_device_unsubclass(gx_device *dev)
* just security here. */
child->parent = NULL;
child->child = NULL;
- /* Make certain the memory will be freed, zap the reference count */
- child->rc.ref_count = 0;
+
/* We *don't* want to run the finalize routine. This would free
* the stype and properly handle the icc_struct and PageList,
* but for devices with a custom finalize (eg psdcmyk) it might
@@ -1529,22 +1531,27 @@ void gx_device_unsubclass(gx_device *dev)
* variable is just to get rid of const warnings.
*/
b_std = (gs_memory_struct_type_t *)child->stype;
- b_std->finalize = NULL;
- /* Having patched the stype, we need to make sure the memory
+ gs_free_const_object(dev->memory->non_gc_memory, b_std, "gs_device_unsubclass(stype)");
+ /* Make this into a generic device */
+ child->stype = &st_device;
+ child->stype_is_dynamic = false;
+
+ /* We can't simply discard the child device, because there may be references to it elsewhere,
+ but equally, we really don't want it doing anything, so set the procs so actions are just discarded.
+ */
+ gx_copy_device_procs(child, (gx_device *)&gs_null_device, (gx_device *)&gs_null_device);
+
+ /* Having changed the stype, we need to make sure the memory
* manager uses it. It keeps a copy in its own data structure,
* and would use that copy, which would mean it would call the
* finalize routine that we just patched out.
*/
- gs_set_object_type(dev->memory->stable_memory, child, b_std);
+ gs_set_object_type(dev->memory->stable_memory, child, child->stype);
+ child->finalize = NULL;
/* Now (finally) free the child memory */
- gs_free_object(dev->memory->stable_memory, child, "gx_device_unsubclass(device)");
- /* And the stype for it */
- gs_free_const_object(dev->memory->non_gc_memory, b_std, "gs_device_unsubclass(stype)");
- child = 0;
+ rc_decrement(child, "gx_device_unsubclass(device)");
}
}
- if(child)
- child->parent = dev;
dev->parent = parent;
/* If this device has a dynamic stype, we wnt to keep using it, but we copied
diff --git a/base/gdevepo.c b/base/gdevepo.c
index f8c46c54..eea3300e 100644
--- a/base/gdevepo.c
+++ b/base/gdevepo.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -235,6 +235,7 @@ disable_self(gx_device *dev)
set_dev_proc(dev, process_page, default_subclass_process_page);
set_dev_proc(dev, transform_pixel_region, default_subclass_transform_pixel_region);
set_dev_proc(dev, fill_stroke_path, default_subclass_fill_stroke_path);
+ set_dev_proc(dev, lock_pattern, default_subclass_lock_pattern);
}
int
diff --git a/base/gdevflp.c b/base/gdevflp.c
index 3c1ad135..53928044 100644
--- a/base/gdevflp.c
+++ b/base/gdevflp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -30,6 +30,7 @@
*/
#include "math_.h"
+#include "string_.h" /* for strlen */
#include "memory_.h"
#include "gx.h"
#include "gserrors.h"
@@ -49,6 +50,7 @@
#include "gximage.h" /* For gx_image_enum */
#include "gdevsclass.h"
#include "gdevflp.h"
+#include "pagelist.h"
#include <stdlib.h>
/* GC descriptor */
@@ -137,134 +139,8 @@ gx_device_flp gs_flp_device =
static int ParsePageList(gx_device *dev, first_last_subclass_data *psubclass_data, char *PageList)
{
- char *str, *oldstr, *workstr, c, *ArgCopy;
- int LastPage, Page, byte, bit, i, prev_page = -1;
-
- psubclass_data->ProcessedPageList = true;
- if (strcmp(PageList, "even") == 0) {
- psubclass_data->EvenOdd = even;
- } else {
- if (strcmp(PageList, "odd") == 0) {
- psubclass_data->EvenOdd = odd;
- } else {
- psubclass_data->EvenOdd = none;
-
- /* validation of parameter */
- str = PageList;
- do {
- /* Must be digit, ',' or - */
- if (*str != ',' && *str != '-' && (*str < 0x30 || *str > 0x39)) {
- return (gs_note_error(gs_error_typecheck));
- }
- /* Check we don't have 2 special characters (, or -) in a row */
- if ((*str == ',' || *str == '-') && (*(str+1) == ',' || *(str+1) == '-'))
- return (gs_note_error(gs_error_typecheck));
- } while(*(++str));
-
- str = PageList;
- oldstr = str;
- do {
- str = strchr(oldstr, ',');
- /* Check for trailing ',' in parameter, zap it if we find one. */
- if (str) {
- if (*(str + 1))
- oldstr = ++str;
- else {
- *str = 0x00;
- break;
- }
- }
- }while (str);
-
- /* In case last set is a page range */
- str = strchr(oldstr, '-');
- if (!str)
- str = oldstr;
- else {
- /* We permit a trailing '-' to indicate all pages from this one to the end */
- if (*(str + 1))
- str++;
- else {
- *str = 0x00;
- str = oldstr;
- psubclass_data->FromToEnd = atoi(str);
- }
- }
- /* str should now point to the last page number (we hope!) */
- psubclass_data->LastListPage = LastPage = atoi(str);
-
- psubclass_data->PageArraySize = (LastPage + 7) / 8;
- psubclass_data->PageArray = gs_alloc_bytes(dev->memory->non_gc_memory, psubclass_data->PageArraySize, "array of pages selected");
- if (!psubclass_data->PageArray) {
- psubclass_data->PageArraySize = 0;
- return (gs_note_error(gs_error_VMerror));
- }
- memset(psubclass_data->PageArray, 0x00, psubclass_data->PageArraySize);
-
- oldstr = ArgCopy = (char *)gs_alloc_bytes(dev->memory->non_gc_memory, strlen(PageList) + 1, "temp working string");
- if (!ArgCopy) {
- gs_free_object(dev->memory->non_gc_memory, psubclass_data->PageArray, "free array of pages selected");
- psubclass_data->PageArray = 0;
- psubclass_data->PageArraySize = 0;
- return (gs_note_error(gs_error_VMerror));
- }
- memcpy(ArgCopy, PageList, strlen(PageList) + 1);
- do {
- str = strchr(oldstr, ',');
- if (str)
- *str++ = 0x00;
- /* oldstr now points to a null terminated string and is either a number or a number pair */
- workstr = strchr(oldstr, '-');
- if (workstr) {
- *workstr++ = 0x00;
- /* oldstr points to null terminated string of start, workstr to null terminated string of end */
- Page = atoi(oldstr) - 1;
- if (Page < 0)
- Page = 0;
-
- LastPage = atoi(workstr) - 1;
- if (LastPage < 0)
- LastPage = 0;
-
- if (LastPage < Page || Page <= prev_page) {
- /* Strictly monotonic increasing required */
- emprintf(dev->memory, "\n**** Error : rangecheck processing PageList\n");
- return_error(gs_error_rangecheck);
- }
- prev_page = LastPage;
-
- for (i=Page; i<= LastPage;i++) {
- if (i > psubclass_data->LastListPage - 1) {
- emprintf(dev->memory, "\n**** Error : rangecheck processing PageList\n");
- return_error(gs_error_rangecheck);
- }
- byte = (int)(i / 8);
- bit = i % 8;
- c = 0x01 << bit;
- ((char *)psubclass_data->PageArray)[byte] |= c;
- }
- } else {
- Page = atoi(oldstr) - 1;
- if (Page < 0)
- Page = 0;
- if (Page <= prev_page || Page > psubclass_data->LastListPage - 1) {
- /* Strictly monotonic increasing required */
- emprintf(dev->memory, "\n**** Error : rangecheck processing PageList\n");
- return_error(gs_error_rangecheck);
- }
- prev_page = Page;
-
- byte = (int)(Page / 8);
- bit = Page % 8;
- c = 0x01 << bit;
- ((char *)psubclass_data->PageArray)[byte] |= c;
- }
- oldstr = str;
- } while (str);
- gs_free_object(dev->memory->non_gc_memory, ArgCopy, "free temp working string");
- }
- }
- return 0;
+ return pagelist_parse_to_array(PageList, dev->memory->non_gc_memory, 0x7fffffff,
+ &(psubclass_data->page_range_array));
}
static int SkipPage(gx_device *dev)
@@ -277,51 +153,28 @@ static int SkipPage(gx_device *dev)
return 0;
/* If we haven't parsed any extant PageList, do it now */
- if (dev->PageList && !psubclass_data->ProcessedPageList) {
+ if (dev->PageList && psubclass_data->page_range_array == NULL) {
code = ParsePageList(dev, psubclass_data, dev->PageList->Pages);
- if (code < 0)
+ if (code < 0) {
+ emprintf1(dev->memory, "*** Invalid PageList=%s ***\n", dev->PageList->Pages);
return code;
- psubclass_data->ProcessedPageList = true;
+ }
}
- if (psubclass_data->PageArray) {
- if (psubclass_data->FromToEnd != 0 && psubclass_data->PageCount >= psubclass_data->FromToEnd - 1)
- return 0;
- else {
- if (psubclass_data->PageCount > psubclass_data->LastListPage - 1)
- return 1;
- else {
- int byte, bit;
- char c;
-
- byte = (int)((psubclass_data->PageCount) / 8);
- bit = (psubclass_data->PageCount) % 8;
- c = 0x01 << bit;
- if (((char *)psubclass_data->PageArray)[byte] & c)
- return 0;
- else
- return 1;
- }
- }
+ /* SkipPage can only handle PageList that moves forward */
+ if (psubclass_data->page_range_array != NULL &&
+ pagelist_test_ordered(psubclass_data->page_range_array) == false) {
+ emprintf(dev->memory, "*** Bad PageList: Must be increasing order. ***\n");
+ return gs_error_rangecheck;
+ }
+
+ if (psubclass_data->page_range_array != NULL) {
+ /* PageCount is 0 based, page_range_array starts at page 1 */
+ return pagelist_test_printed(psubclass_data->page_range_array, psubclass_data->PageCount + 1) == false;
} else {
- if (psubclass_data->EvenOdd != none) {
- /* Page count is 0 based so the even/odd tests are 'upside down' */
- if (psubclass_data->PageCount % 2 == 0) {
- if (psubclass_data->EvenOdd == odd)
- return 0;
- else
- return 1;
- } else {
- if (psubclass_data->EvenOdd == even)
- return 0;
- else
- return 1;
- }
- } else {
- if (psubclass_data->PageCount >= dev->FirstPage - 1)
- if (!dev->LastPage || psubclass_data->PageCount <= dev->LastPage - 1)
- return 0;
- }
+ if (psubclass_data->PageCount >= dev->FirstPage - 1)
+ if (!dev->LastPage || psubclass_data->PageCount <= dev->LastPage - 1)
+ return 0;
}
return 1;
}
@@ -344,11 +197,10 @@ int flp_close_device(gx_device *dev)
{
first_last_subclass_data *psubclass_data = dev->subclass_data;
- if (psubclass_data->PageArraySize)
+ if (psubclass_data->page_range_array != NULL)
{
- gs_free(dev->memory->non_gc_memory, psubclass_data->PageArray, 1, psubclass_data->PageArraySize, "array of pages selected");
- psubclass_data->PageArray = 0;
- psubclass_data->PageArraySize = 0;
+ pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
+ psubclass_data->page_range_array = NULL;
}
return default_subclass_close_device(dev);
@@ -399,7 +251,7 @@ flp_rc_free_pages_list(gs_memory_t * mem, void *ptr_in, client_name_t cname)
gdev_pagelist *PageList = (gdev_pagelist *)ptr_in;
if (PageList->rc.ref_count <= 1) {
- gs_free(mem->non_gc_memory, PageList->Pages, 1, PagesSize, "free page list");
+ gs_free(mem->non_gc_memory, PageList->Pages, 1, strlen(PageList->Pages), "free page list");
gs_free(mem->non_gc_memory, PageList, 1, sizeof(gdev_pagelist), "free structure to hold page list");
}
}
@@ -411,90 +263,91 @@ flp_put_params(gx_device * dev, gs_param_list * plist)
int code, ecode = 0;
gs_param_string pagelist;
- code = param_read_int(plist, "FirstPage", &dev->FirstPage);
+ code = param_read_bool(plist, "DisablePageHandler", &temp_bool);
if (code < 0)
ecode = code;
if (code == 0) {
- first_last_subclass_data *psubclass_data = dev->subclass_data;
+ dev->DisablePageHandler = temp_bool;
+ if (dev->DisablePageHandler == false) {
+ first_last_subclass_data *psubclass_data = dev->subclass_data;
- dev->DisablePageHandler = false;
- psubclass_data->PageCount = 0;
- if (dev->PageList) {
- rc_decrement(dev->PageList, "flp_put_params");
- dev->PageList = NULL;
- }
- if (psubclass_data->PageArray != NULL) {
- gs_free(dev->memory->non_gc_memory, psubclass_data->PageArray, 1, psubclass_data->PageArraySize, "array of pages selected");
- psubclass_data->PageArray = NULL;
- psubclass_data->PageArraySize = 0;
+ psubclass_data->PageCount = 0;
+ psubclass_data->page_range_array = NULL;
}
}
- code = param_read_int(plist, "LastPage", &dev->LastPage);
- if (code < 0)
- ecode = code;
- if (code == 0) {
- first_last_subclass_data *psubclass_data = dev->subclass_data;
+ if (dev->DisablePageHandler == false) {
+ code = param_read_int(plist, "FirstPage", &dev->FirstPage);
+ if (code < 0)
+ ecode = code;
+ if (code == 0) {
+ first_last_subclass_data *psubclass_data = dev->subclass_data;
- dev->DisablePageHandler = false;
- psubclass_data->PageCount = 0;
- if (dev->PageList) {
- rc_decrement(dev->PageList, "flp_put_params");
- dev->PageList = NULL;
- }
- if (psubclass_data->PageArray != NULL) {
- gs_free(dev->memory->non_gc_memory, psubclass_data->PageArray, 1, psubclass_data->PageArraySize, "array of pages selected");
- psubclass_data->PageArray = NULL;
- psubclass_data->PageArraySize = 0;
+ dev->DisablePageHandler = false;
+ psubclass_data->PageCount = 0;
+ psubclass_data->page_range_array = NULL;
+ if (dev->PageList) {
+ rc_decrement(dev->PageList, "flp_put_params");
+ dev->PageList = NULL;
+ }
+ if (psubclass_data->page_range_array != NULL) {
+ pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
+ psubclass_data->page_range_array = NULL;
+ }
}
- }
- code = param_read_bool(plist, "DisablePageHandler", &temp_bool);
- if (code < 0)
- ecode = code;
- if (code == 0) {
- dev->DisablePageHandler = temp_bool;
- if (dev->DisablePageHandler == false) {
+ code = param_read_int(plist, "LastPage", &dev->LastPage);
+ if (code < 0)
+ ecode = code;
+ if (code == 0) {
first_last_subclass_data *psubclass_data = dev->subclass_data;
+ dev->DisablePageHandler = false;
psubclass_data->PageCount = 0;
+ psubclass_data->page_range_array = NULL;
+ if (dev->PageList) {
+ rc_decrement(dev->PageList, "flp_put_params");
+ dev->PageList = NULL;
+ }
+ if (psubclass_data->page_range_array != NULL) {
+ pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
+ psubclass_data->page_range_array = NULL;
+ }
}
- }
- code = param_read_string(plist, "PageList", &pagelist);
- if (code < 0)
- ecode = code;
+ code = param_read_string(plist, "PageList", &pagelist);
+ if (code < 0)
+ ecode = code;
- if (code == 0 && pagelist.size > 0) {
- first_last_subclass_data *psubclass_data = dev->subclass_data;
+ if (code == 0 && pagelist.size > 0) {
+ first_last_subclass_data *psubclass_data = dev->subclass_data;
- if (dev->PageList)
- rc_decrement(dev->PageList, "flp_put_params");
+ if (dev->PageList)
+ rc_decrement(dev->PageList, "flp_put_params");
- if (psubclass_data->PageArray != NULL) {
- gs_free(dev->memory->non_gc_memory, psubclass_data->PageArray, 1, psubclass_data->PageArraySize, "array of pages selected");
- psubclass_data->PageArray = NULL;
- psubclass_data->PageArraySize = 0;
- }
+ if (psubclass_data->page_range_array != NULL) {
+ pagelist_free_range_array(dev->memory->non_gc_memory, psubclass_data->page_range_array);
+ psubclass_data->page_range_array = NULL;
+ }
- dev->PageList = (gdev_pagelist *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(gdev_pagelist), "structure to hold page list");
- if (!dev->PageList)
- return gs_note_error(gs_error_VMerror);
- dev->PageList->Pages = (void *)gs_alloc_bytes(dev->memory->non_gc_memory, pagelist.size + 1, "String to hold page list");
- if (!dev->PageList->Pages){
- gs_free(dev->memory->non_gc_memory, dev->PageList, 1, sizeof(gdev_pagelist), "free structure to hold page list");
- dev->PageList = 0;
- return gs_note_error(gs_error_VMerror);
+ dev->PageList = (gdev_pagelist *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(gdev_pagelist), "structure to hold page list");
+ if (!dev->PageList)
+ return gs_note_error(gs_error_VMerror);
+ dev->PageList->Pages = (void *)gs_alloc_bytes(dev->memory->non_gc_memory, pagelist.size + 1, "String to hold page list");
+ if (!dev->PageList->Pages){
+ gs_free(dev->memory->non_gc_memory, dev->PageList, 1, sizeof(gdev_pagelist), "free structure to hold page list");
+ dev->PageList = 0;
+ return gs_note_error(gs_error_VMerror);
+ }
+ memset(dev->PageList->Pages, 0x00, pagelist.size + 1);
+ memcpy(dev->PageList->Pages, pagelist.data, pagelist.size);
+ rc_init_free(dev->PageList, dev->memory->non_gc_memory, 1, flp_rc_free_pages_list);
+ psubclass_data->page_range_array = NULL;
+ dev->DisablePageHandler = false;
+ psubclass_data->PageCount = 0;
+ psubclass_data->page_range_array = NULL;
}
- memset(dev->PageList->Pages, 0x00, pagelist.size + 1);
- memcpy(dev->PageList->Pages, pagelist.data, pagelist.size);
- dev->PageList->PagesSize = pagelist.size + 1;
- rc_init_free(dev->PageList, dev->memory->non_gc_memory, 1, flp_rc_free_pages_list);
- psubclass_data->ProcessedPageList = false;
- dev->DisablePageHandler = false;
- psubclass_data->PageCount = 0;
}
-
code = default_subclass_put_params(dev, plist);
if (code < 0)
@@ -989,11 +842,15 @@ int flp_fill_linear_color_triangle(gx_device *dev, const gs_fill_attributes *fa,
int flp_fillpage(gx_device *dev, gs_gstate * pgs, gx_device_color *pdevc)
{
+ first_last_subclass_data *psubclass_data = dev->subclass_data;
int code = SkipPage(dev);
if (code < 0)
return code;
- if (!code)
+
+ /* allow fillpage to be processed at the first page */
+ /* This is needed to allow all parsers to start with non-ordered PageList */
+ if (!code || psubclass_data->PageCount == 0)
return default_subclass_fillpage(dev, pgs, pdevc);
return 0;
@@ -1175,4 +1032,4 @@ flp_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, process_page, flp_process_page);
set_dev_proc(dev, transform_pixel_region, flp_transform_pixel_region);
set_dev_proc(dev, fill_stroke_path, flp_fill_stroke_path);
-} \ No newline at end of file
+}
diff --git a/base/gdevflp.h b/base/gdevflp.h
index 453f401a..fb888199 100644
--- a/base/gdevflp.h
+++ b/base/gdevflp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -33,12 +33,7 @@ typedef enum {none, even, odd} flp_EOType;
typedef struct {
subclass_common;
int PageCount;
- int ProcessedPageList;
- void *PageArray;
- int PageArraySize;
- int LastListPage;
- int FromToEnd;
- flp_EOType EvenOdd;
+ int *page_range_array;
} first_last_subclass_data;
typedef struct flp_text_enum_s {
diff --git a/base/gdevkrnlsclass.c b/base/gdevkrnlsclass.c
index 8ae05fb2..cff5ae95 100644
--- a/base/gdevkrnlsclass.c
+++ b/base/gdevkrnlsclass.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -24,6 +24,11 @@
*/
#define FORCE_TESTING_SUBCLASSING 0
+/* This installs the 'kernel' device classes. If you add any devices here you should
+ * almost certainly edit gdevp14.c, gs_pdf14_device_push() and add the new device to the list
+ * of devices which the push of the compositor claims are already installed (to prevent
+ * a second copy being installed by gdev_prn_open).
+ */
int install_internal_subclass_devices(gx_device **ppdev, int *devices_loaded)
{
int code = 0;
diff --git a/base/gdevm8.c b/base/gdevm8.c
index 6717c585..a94c107f 100644
--- a/base/gdevm8.c
+++ b/base/gdevm8.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -195,6 +195,7 @@ mapped8_copyN1(chunk * dest, const byte * line, int first_bit,
goto enter7;
}
do {
+ sbyte = *sptr++;
enter0: if (sbyte & 128)
*pptr = b1;
pptr++;
@@ -219,11 +220,13 @@ mapped8_copyN1(chunk * dest, const byte * line, int first_bit,
enter7: if (sbyte & 1)
*pptr = b1;
pptr++;
- sbyte = *sptr++;
count -= 8;
} while (count >= 0);
bit = 128;
count += 8;
+ if (count > 0)
+ /* read the byte containing the trailing bits */
+ sbyte = *sptr++;
} else {
/* Less than 1 byte to do */
bit = 0x80>>first_bit;
diff --git a/base/gdevmpla.c b/base/gdevmpla.c
index 79b29116..4103b021 100644
--- a/base/gdevmpla.c
+++ b/base/gdevmpla.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -1732,6 +1732,9 @@ plane_strip_copy_rop2(gx_device_memory * mdev,
int code;
const gdev_mem_functions *fns;
int n;
+ dev_proc_encode_color(*save_encode);
+ dev_proc_get_color_mapping_procs(*save_gcmp);
+ gx_color_index save_black, save_white;
/* assert(planar_height == 0); */
@@ -1742,6 +1745,24 @@ plane_strip_copy_rop2(gx_device_memory * mdev,
* so ensure we have the right ones in there. */
set_dev_proc(mdev, get_bits_rectangle, fns->get_bits_rectangle);
set_dev_proc(mdev, fill_rectangle, fns->fill_rectangle);
+ /* We are about to change the number of components, so the cached black
+ * and white values are no longer correct. */
+ save_black = mdev->cached_colors.black;
+ save_white = mdev->cached_colors.white;
+ mdev->cached_colors.black = gx_no_color_index;
+ mdev->cached_colors.white = gx_no_color_index;
+ /* The strip_copy_rop2 routine can end up trying to calculate black
+ * and white values. For this it will call 'get_color_mapping_procs'
+ * and encode_color. We can't have it calling the devices own ones
+ * because they assume multiple planes, not just one. Store the
+ * originals, and swap them out for sane ones. It's possible that
+ * for some crazy devices, these choices might not be perfect,
+ * but it's hard to see what we could do better, so those devices
+ * might need to implement their own strip_copy_rop2. */
+ save_encode = dev_proc(mdev, encode_color);
+ save_gcmp = dev_proc(mdev, get_color_mapping_procs);
+ set_dev_proc(mdev, get_color_mapping_procs, gx_default_DevGray_get_color_mapping_procs);
+ set_dev_proc(mdev, encode_color, gx_default_gray_encode_color);
/* mdev->color_info.depth is restored by MEM_RESTORE_PARAMS below. */
mdev->color_info.depth = mdev->planes[plane].depth;
n = mdev->color_info.num_components;
@@ -1750,9 +1771,14 @@ plane_strip_copy_rop2(gx_device_memory * mdev,
id, scolors, textures, tcolors,
x, y, width, height,
phase_x, phase_y, lop, planar_height);
+ /* Restore color details. */
mdev->color_info.num_components = n;
set_dev_proc(mdev, get_bits_rectangle, mem_planar_get_bits_rectangle);
set_dev_proc(mdev, fill_rectangle, mem_planar_fill_rectangle);
+ set_dev_proc(mdev, encode_color, save_encode);
+ set_dev_proc(mdev, get_color_mapping_procs, save_gcmp);
+ mdev->cached_colors.black = save_black;
+ mdev->cached_colors.white = save_white;
/* The following effectively does: mdev->line_ptrs -= mdev->height * plane; */
MEM_RESTORE_PARAMS(mdev, save);
return code;
diff --git a/base/gdevnfwd.c b/base/gdevnfwd.c
index 948bfa09..4b23cbcb 100644
--- a/base/gdevnfwd.c
+++ b/base/gdevnfwd.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -106,6 +106,7 @@ gx_device_forward_fill_in_procs(register gx_device_forward * dev)
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);
fill_dev_proc(dev, fill_stroke_path, gx_forward_fill_stroke_path);
+ fill_dev_proc(dev, lock_pattern, gx_forward_lock_pattern);
gx_device_fill_in_procs((gx_device *) dev);
}
@@ -367,6 +368,19 @@ gx_forward_fill_stroke_path(gx_device * dev, const gs_gstate * pgs,
}
int
+gx_forward_lock_pattern(gx_device * dev, gs_gstate * pgs, gs_id pattern_id, int lock)
+{
+ gx_device_forward * const fdev = (gx_device_forward *)dev;
+ gx_device *tdev = fdev->target;
+ dev_proc_lock_pattern((*proc)) =
+ (tdev == 0 ? (tdev = dev, gx_default_lock_pattern) :
+ dev_proc(tdev, lock_pattern));
+
+ return proc(tdev, pgs, pattern_id, lock);
+
+}
+
+int
gx_forward_fill_mask(gx_device * dev,
const byte * data, int dx, int raster, gx_bitmap_id id,
int x, int y, int w, int h,
diff --git a/base/gdevnup.c b/base/gdevnup.c
index b9f4f356..fa8aa3b7 100644
--- a/base/gdevnup.c
+++ b/base/gdevnup.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -342,7 +342,12 @@ copy_and_modify_sub(gs_param_list *plto, gs_param_list *plfrom, int *present)
code = (code > 0 ? gs_note_error(gs_error_unknownerror) : code);
break;
}
- gs_param_list_set_persistent_keys(plto, key.persistent);
+ /* We used to use 'key.persistent' to determine whether we needed to copy the
+ * key (by setting persistent_keys in the param list to false), but that isn't
+ * correct! We are going to use the heap buffer 'string_key', not the original
+ * key, and since that's on the heap it is NOT persistent....
+ */
+ gs_param_list_set_persistent_keys(plto, false);
switch (value.type) {
case gs_param_type_dict:
coll_type = gs_param_collection_dict_any;
diff --git a/base/gdevoflt.c b/base/gdevoflt.c
index 98f16f49..ff9424c7 100644
--- a/base/gdevoflt.c
+++ b/base/gdevoflt.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -32,8 +32,10 @@
#include "gdevprn.h"
#include "gdevp14.h" /* Needed to patch up the procs after compositor creation */
#include "gximage.h" /* For gx_image_enum */
+#include "gximag3x.h"
#include "gdevsclass.h"
#include "gdevoflt.h"
+#include "gximag3x.h"
int gs_is_pdf14trans_compositor(const gs_composite_t * pct);
@@ -110,6 +112,7 @@ obj_filter_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, strip_copy_rop2, obj_filter_strip_copy_rop2);
set_dev_proc(dev, strip_tile_rect_devn, obj_filter_strip_tile_rect_devn);
set_dev_proc(dev, fill_stroke_path, obj_filter_fill_stroke_path);
+ set_dev_proc(dev, composite, default_subclass_composite_front);
}
const
@@ -219,8 +222,10 @@ int obj_filter_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles
typedef struct obj_filter_image_enum_s {
gx_image_enum_common;
- int y;
- int height;
+ int y, mask_y;
+ int height, mask_height;
+ int type;
+ int InterleaveType;
} obj_filter_image_enum;
gs_private_st_composite(st_obj_filter_image_enum, obj_filter_image_enum, "obj_filter_image_enum",
obj_filter_image_enum_enum_ptrs, obj_filter_image_enum_reloc_ptrs);
@@ -243,15 +248,25 @@ obj_filter_image_plane_data(gx_image_enum_common_t * info,
{
obj_filter_image_enum *pie = (obj_filter_image_enum *)info;
- if (height > pie->height - pie->y)
- height = pie->height - pie->y;
+ if (pie->type == 3 && pie->InterleaveType == interleave_separate_source) {
+ pie->y += height;
+ pie->mask_y += height;
+ *rows_used = height;
- pie->y += height;
- *rows_used = height;
+ if (pie->y < pie->height || pie->mask_y < pie->mask_height)
+ return 0;
+ return 1;
+ } else {
+ if (height > pie->height - pie->y)
+ height = pie->height - pie->y;
+
+ pie->y += height;
+ *rows_used = height;
- if (pie->y < pie->height)
- return 0;
- return 1;
+ if (pie->y < pie->height)
+ return 0;
+ return 1;
+ }
}
static int
@@ -299,8 +314,76 @@ int obj_filter_begin_typed_image(gx_device *dev, const gs_gstate *pgs, const gs_
pie->memory = memory;
pie->skipping = true;
pie->height = pim->Height;
- pie->y = 0;
-
+ pie->mask_y = pie->y = 0;
+ pie->type = pic->type->index;
+
+ if (pic->type->index == 3) {
+ const gs_image3_t *pim = (const gs_image3_t *)pic;
+
+ switch (pim->InterleaveType)
+ {
+ case interleave_chunky:
+ /* Add the mask data to the depth of the image data. */
+ pie->num_planes = 1;
+ break;
+ case interleave_scan_lines:
+ /*
+ * There is only 1 plane, with dynamically changing width & depth.
+ * Initialize it for the mask data, since that is what will be
+ * read first.
+ */
+ pie->num_planes = 1;
+ pie->plane_depths[0] = 1;
+ pie->plane_widths[0] = pim->MaskDict.Width;
+ break;
+ case interleave_separate_source:
+ /* Insert the mask data as a separate plane before the image data. */
+ pie->num_planes = 2;
+ pie->plane_depths[1] = pie->plane_depths[0];
+ pie->plane_widths[1] = pie->plane_widths[0];
+ pie->plane_widths[0] = pim->MaskDict.Width;
+ pie->plane_depths[0] = 1;
+ pie->mask_height = pim->MaskDict.Height;
+ break;
+ }
+ pie->InterleaveType = pim->InterleaveType;
+ }
+ if (pic->type->index == IMAGE3X_IMAGETYPE) {
+ const gs_image3x_t *pim = (const gs_image3x_t *)pic;
+
+ if (pim->Opacity.MaskDict.BitsPerComponent != 0) {
+ switch(pim->Opacity.InterleaveType) {
+ case interleave_separate_source:
+ pie->num_planes++;
+ pie->plane_depths[1] = pie->plane_depths[0];
+ pie->plane_widths[1] = pie->plane_widths[0];
+ pie->plane_depths[0] = pim->Opacity.MaskDict.BitsPerComponent;
+ pie->plane_widths[0] = pim->Opacity.MaskDict.Width;
+ break;
+ case interleave_chunky:
+ pie->plane_depths[0] += pim->BitsPerComponent;
+ break;
+ default: /* can't happen */
+ return_error(gs_error_Fatal);
+ }
+ }
+ if (pim->Shape.MaskDict.BitsPerComponent != 0) {
+ switch(pim->Shape.InterleaveType) {
+ case interleave_separate_source:
+ pie->num_planes++;
+ pie->plane_depths[1] = pie->plane_depths[0];
+ pie->plane_widths[1] = pie->plane_widths[0];
+ pie->plane_depths[0] = pim->Shape.MaskDict.BitsPerComponent;
+ pie->plane_widths[0] = pim->Shape.MaskDict.Width;
+ break;
+ case interleave_chunky:
+ pie->plane_depths[0] += pim->BitsPerComponent;
+ break;
+ default: /* can't happen */
+ return_error(gs_error_Fatal);
+ }
+ }
+ }
return 0;
}
diff --git a/base/gdevp14.c b/base/gdevp14.c
index b3018f85..0b47ae6d 100644
--- a/base/gdevp14.c
+++ b/base/gdevp14.c
@@ -1647,6 +1647,22 @@ pdf14_pop_transparency_group(gs_gstate *pgs, pdf14_ctx *ctx,
(nos->has_alpha_g ? 1 : 0)));
}
+ /* Before we get started, lets see if we have somehow gotten into
+ what should be an impossible situation where the group color
+ information does not match the buffer color information. This
+ can occur is there were memory issues that have perhaps blown
+ away information, or in the example of Bug 705197 the PDF interpreter
+ reuses a pattern during a circular reference causing an aliasing
+ of two nested patterns, one of which has a softmask. The change in
+ the buffer size of the inner one blows away the buffer of the
+ outer one leading to a mismatch of color spaces. Here
+ we can at least catch the case when the color space sizes have
+ changed and avoid buffer over-runs that would occur when we try
+ to do the group composition */
+ if (nos->n_chan - 1 != nos->group_color_info->num_components ||
+ tos->n_chan - 1 != tos_num_color_comp)
+ return_error(gs_error_Fatal);
+
nos_num_color_comp = nos->group_color_info->num_components - tos->num_spots;
tos_num_color_comp = tos_num_color_comp - tos->num_spots;
@@ -3119,48 +3135,6 @@ pdf14_blend_image_mixed_buffer16(byte* buf_ptr_, int width, int height, int rows
}
}
-static pdf14_buf*
-insert_empty_planes(pdf14_ctx* ctx, pdf14_buf** src_buf, int num_new_planes, int insert_index)
-{
- int planestride = (*src_buf)->planestride;
- int src_n_planes = (*src_buf)->n_planes;
- int src_n_chan = (*src_buf)->n_chan;
- int des_n_planes = src_n_planes + num_new_planes;
- int des_n_chan = src_n_chan + num_new_planes;
- byte *src_ptr = (*src_buf)->data;
- byte* des_ptr;
- byte *des_data;
- bool deep = ctx->deep;
-
- des_data = gs_alloc_bytes(ctx->memory,
- (size_t)planestride * des_n_planes + CAL_SLOP,
- "insert_empty_planes");
- if (des_data == NULL)
- return NULL;
-
- des_ptr = des_data;
-
- /* First copy portion prior to insert point */
- memcpy(des_ptr, src_ptr, (planestride * insert_index) << deep);
-
- /* New planes */
- des_ptr += (planestride * insert_index) << deep;
- src_ptr += (planestride * insert_index) << deep;
- memset(des_ptr, 0, (planestride * num_new_planes) << deep);
-
- /* Extra planes (i.e. doc spots, tags) */
- des_ptr += (planestride * num_new_planes) << deep;
- memcpy(des_ptr, src_ptr, (planestride * (src_n_planes - insert_index)) << deep);
-
- /* Set up buffer structure */
- gs_free_object(ctx->memory, (*src_buf)->data, "insert_empty_planes");
- (*src_buf)->n_planes = des_n_planes;
- (*src_buf)->n_chan = des_n_chan;
- (*src_buf)->data = des_data;
-
- return *src_buf;
-}
-
static int
pdf14_put_blended_image_cmykspot(gx_device* dev, gx_device* target,
gs_gstate* pgs, pdf14_buf* buf, int planestride_in,
@@ -3418,30 +3392,6 @@ pdf14_put_blended_image_cmykspot(gx_device* dev, gx_device* target,
tag_offset = buf->has_tags ? buf->n_chan : 0;
}
- /* We may need to pad the buffers to ensure that any additional spot
- channels that are not created by the ICC color conversion (or
- non-conversion if this is not an NCLR profile) get placed properly.
- It is up to the target device to
- handle these planes how it sees fit based upon the image data
- and/or any tags plane during any put image call. We *could*
- do something here to possibly communicate through the put_image
- call where the page related spots start, but that would/could
- be confusing, especially for long term maintenance. Easier just
- to have put_image hand all the data */
- if (dev_target_profile->spotnames != NULL &&
- dev_target_profile->spotnames->count > des_profile->num_comps) {
- int num_new_planes = dev_target_profile->spotnames->count - des_profile->num_comps;
- int insert_index = des_profile->num_comps;
- pdf14_buf* result;
-
- result = insert_empty_planes(pdev->ctx, &buf, num_new_planes, insert_index);
- if (result == NULL)
- return_error(gs_error_VMerror);
-
- num_comp = buf->n_chan;
- tag_offset = buf->has_tags ? buf->n_chan : 0;
- buf_ptr = buf->data + (rect.p.y - buf->rect.p.y) * buf->rowstride + ((rect.p.x - buf->rect.p.x) << deep);
- }
#if RAW_DUMP
/* Dump after the CS transform */
dump_raw_buffer_be(target->memory, height, width, buf->n_planes, planestride, rowstride,
@@ -3859,6 +3809,9 @@ gs_pdf14_device_copy_params(gx_device *dev, const gx_device *target)
dev->icc_struct->supports_devn = profile_targ->supports_devn;
dev->icc_struct->usefastcolor = profile_targ->usefastcolor;
dev->icc_struct->blacktext = profile_targ->blacktext;
+ dev->icc_struct->blackvector = profile_targ->blackvector;
+ dev->icc_struct->blackthresholdL = profile_targ->blackthresholdL;
+ dev->icc_struct->blackthresholdC = profile_targ->blackthresholdC;
switch (pdev->blend_cs_state) {
case PDF14_BLEND_CS_UNSPECIFIED:
@@ -5179,7 +5132,7 @@ pdf14_tile_pattern_fill(gx_device * pdev, const gs_gstate * pgs,
curr_clip_rect = cpath_intersection.rect_list->list.head->next;
for( k = 0; k < cpath_intersection.rect_list->list.count && code >= 0; k++){
if_debug5m('v', pgs->memory,
- "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %d \n",
+ "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %u \n",
curr_clip_rect->xmin, curr_clip_rect->ymin,
curr_clip_rect->xmax-curr_clip_rect->xmin,
curr_clip_rect->ymax-curr_clip_rect->ymin, (int)ptile->id);
@@ -5191,7 +5144,7 @@ pdf14_tile_pattern_fill(gx_device * pdev, const gs_gstate * pgs,
} else if (cpath_intersection.rect_list->list.count == 1) {
/* The case when there is just a single rect */
if_debug5m('v', pgs->memory,
- "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %d \n",
+ "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %u \n",
cpath_intersection.rect_list->list.single.xmin,
cpath_intersection.rect_list->list.single.ymin,
cpath_intersection.rect_list->list.single.xmax-
@@ -6292,7 +6245,17 @@ pdf14_copy_mono(gx_device * dev,
/* Set up for the start of each line of the area. */
sptr = line;
sbyte = *sptr++;
- bit = first_bit;
+ /* The +1 here is 'sacrificial', we are going to decrement it by 1 immediately in
+ * the loop below so adding 1 means that we don't fall into the bit == 0
+ * case and incorrectly read a new byte from the source. This weirdness is because
+ * the original code wouold read off the end of the buffer if the number of bits in
+ * the raster was an exact multiple of 8. If it was also a multiple of the word
+ * size we might read unallocated memory. Moving the 'sbyte = *sptr++' from the end
+ * of the loop to the beginning meant we would not read past the end of the buffer
+ * because we would drop out of the 'do ... while (count-- > 0)' loop before
+ * reading another byte.
+ */
+ bit = first_bit + 1;
count = w;
run_length = 0;
startx = x;
@@ -6301,6 +6264,13 @@ pdf14_copy_mono(gx_device * dev,
/* Loop across each pixel of a line. */
do {
+ /* Move to the next input bit. */
+ if (bit == 0) {
+ bit = 7;
+ sbyte = *sptr++;
+ }
+ else
+ bit--;
bit_value = (sbyte >> bit) & 1;
if (bit_value == current_bit) {
/* The value did not change, simply increment our run length */
@@ -6320,13 +6290,6 @@ pdf14_copy_mono(gx_device * dev,
current_color = bit_value ? one : zero;
current_bit = bit_value;
}
- /* Move to the next input bit. */
- if (bit == 0) {
- bit = 7;
- sbyte = *sptr++;
- }
- else
- bit--;
} while (--count > 0);
/* Fill the last rectangle in the line. */
if (run_length != 0 && current_color != gx_no_color_index) {
@@ -8432,6 +8395,11 @@ pdf14_cmap_separation_direct(frac all, gx_device_color * pdc, const gs_gstate *
} else {
frac comp_value[GX_DEVICE_COLOR_MAX_COMPONENTS];
+ if (pgs->color_component_map.sep_type == SEP_NONE) {
+ color_set_null(pdc);
+ return;
+ }
+
/* map to the color model */
for (i = pgs->color_component_map.num_components - 1; i >= 0; i--)
comp_value[i] = all;
@@ -8867,6 +8835,7 @@ gs_pdf14_device_push(gs_memory_t *mem, gs_gstate * pgs,
new_target->PageHandlerPushed = true;
new_target->ObjectHandlerPushed = true;
+ new_target->NupHandlerPushed = true;
/* if the device has separations already defined (by SeparationOrderNames) */
/* we need to copy them (allocating new names) so the colorants are in the */
/* same order as the target device. */
@@ -10699,7 +10668,7 @@ pdf14_clist_composite(gx_device * dev, gx_device ** pcdev,
gx_device *target = ((pdf14_device *)(tdev->save_p14dev))->target;
gs_image1_t image;
gs_color_space *pcs;
- gx_image_enum_common_t *info;
+ gx_image_enum_common_t *info = NULL;
gx_image_plane_t planes;
gsicc_rendering_param_t render_cond;
cmm_dev_profile_t *dev_profile;
@@ -10814,9 +10783,15 @@ pdf14_clist_composite(gx_device * dev, gx_device ** pcdev,
if ((code = info->procs->plane_data(info, &planes, 1, &rows_used)) < 0)
goto put_accum_error;
}
- code = info->procs->end_image(info, true);
put_accum_error:
+ if (info != NULL) {
+ if (code < 0)
+ (void)info->procs->end_image(info, true);
+ else
+ code = info->procs->end_image(info, true);
+ }
+
gs_free_object(pdev->memory, linebuf, "pdf14_put_image");
/* This will also decrement the device profile */
rc_decrement_only_cs(pcs, "pdf14_put_image");
@@ -11841,7 +11816,7 @@ c_pdf14trans_clist_read_update(gs_composite_t * pcte, gx_device * cdev,
* was buffered into the output device.
*/
pclist_devn_params = dev_proc(cdev, ret_devn_params)(cdev);
- if (pclist_devn_params != NULL && pclist_devn_params->page_spot_colors != 0) {
+ if (pclist_devn_params != NULL && pclist_devn_params->page_spot_colors > 0) {
int num_comp = p14dev->color_info.num_components;
/*
* The number of components for the PDF14 device is the sum
@@ -11850,18 +11825,23 @@ c_pdf14trans_clist_read_update(gs_composite_t * pcte, gx_device * cdev,
* device (which coming into this are the same as the p14dev)
* are smaller than the number of page spot colors then
* use that for the number of components. Otherwise use
- * the page_spot_colors.
+ * the page_spot_colors. The exception is, if we had used
+ * the sICCOutputColors setting, then just use that, which
+ * should be already baked into num_comp
*/
- p14dev->devn_params.page_spot_colors =
- pclist_devn_params->page_spot_colors;
- if (num_comp < p14dev->devn_params.page_spot_colors + 4 ) {
- p14dev->color_info.num_components = num_comp;
- } else {
- /* if page_spot_colors < 0, this will be wrong, so don't update num_components */
- if (p14dev->devn_params.page_spot_colors >= 0) {
- p14dev->color_info.num_components =
- p14dev->devn_params.num_std_colorant_names +
- p14dev->devn_params.page_spot_colors;
+
+ if (cdev->icc_struct->spotnames == NULL) {
+ p14dev->devn_params.page_spot_colors =
+ pclist_devn_params->page_spot_colors;
+ if (num_comp < p14dev->devn_params.page_spot_colors + 4 ) {
+ p14dev->color_info.num_components = num_comp;
+ } else {
+ /* if page_spot_colors < 0, this will be wrong, so don't update num_components */
+ if (p14dev->devn_params.page_spot_colors >= 0) {
+ p14dev->color_info.num_components =
+ p14dev->devn_params.num_std_colorant_names +
+ p14dev->devn_params.page_spot_colors;
+ }
}
}
/* limit the num_components to the max. */
diff --git a/base/gdevprn.c b/base/gdevprn.c
index 296e9734..e2d1da4a 100644
--- a/base/gdevprn.c
+++ b/base/gdevprn.c
@@ -303,7 +303,7 @@ gdev_prn_allocate(gx_device *pdev, gdev_space_params *new_space_params,
ppdev->orig_procs = pdev->procs;
for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) {
ulong mem_space;
- ulong pdf14_trans_buffer_size = 0;
+ size_t pdf14_trans_buffer_size = 0;
byte *base = 0;
bool bufferSpace_is_default = false;
gdev_space_params space_params;
@@ -335,7 +335,7 @@ gdev_prn_allocate(gx_device *pdev, gdev_space_params *new_space_params,
mem_space = buf_space.bits + buf_space.line_ptrs;
if (ppdev->page_uses_transparency) {
pdf14_trans_buffer_size = (ESTIMATED_PDF14_ROW_SPACE(max(1, pdev->width), pdev->color_info.num_components, deep ? 16 : 8) >> 3);
- if (new_height < (max_ulong - mem_space) / pdf14_trans_buffer_size) {
+ if (new_height < (max_size_t - mem_space) / pdf14_trans_buffer_size) {
pdf14_trans_buffer_size *= pdev->height;
} else {
size_ok = 0;
@@ -457,6 +457,7 @@ gdev_prn_allocate(gx_device *pdev, gdev_space_params *new_space_params,
pdev->procs = ppdev->orig_procs;
ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */
gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print");
+ ppdev->bg_print = NULL;
return_error(code);
}
}
@@ -505,6 +506,7 @@ gdev_prn_allocate(gx_device *pdev, gdev_space_params *new_space_params,
}
if (code < 0) {
gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print");
+ ppdev->bg_print = NULL;
}
return code;
}
@@ -1802,8 +1804,8 @@ gdev_prn_initialize_device_procs_gray(gx_device *dev)
set_dev_proc(dev, map_rgb_color, gx_default_gray_map_rgb_color);
set_dev_proc(dev, map_color_rgb, gx_default_gray_map_color_rgb);
- set_dev_proc(dev, encode_color, gx_default_gray_map_rgb_color);
- set_dev_proc(dev, decode_color, gx_default_gray_map_color_rgb);
+ set_dev_proc(dev, encode_color, gx_default_gray_encode_color);
+ set_dev_proc(dev, decode_color, gx_default_gray_decode_color);
}
void gdev_prn_initialize_device_procs_gray_bg(gx_device *dev)
diff --git a/base/gdevsclass.c b/base/gdevsclass.c
index 2f757b76..eda152eb 100644
--- a/base/gdevsclass.c
+++ b/base/gdevsclass.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -359,6 +359,99 @@ int default_subclass_get_bits_rectangle(gx_device *dev, const gs_int_rect *prect
return gx_default_get_bits_rectangle(dev, prect, params);
}
+static void subclass_composite_front_finalize(gx_device *dev)
+{
+ generic_subclass_data *psubclass_data = (generic_subclass_data *)dev->parent->subclass_data;
+
+ dev->parent->child = psubclass_data->pre_composite_device;
+ psubclass_data->saved_finalize_method(dev);
+}
+
+int default_subclass_composite_front(gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte,
+ gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev)
+{
+ int code = 0;
+ gs_pdf14trans_t *pct = (gs_pdf14trans_t *)pcte;
+ generic_subclass_data *psubclass_data = (generic_subclass_data *)dev->subclass_data;
+ gx_device *thisdev = dev;
+
+ if (dev->child) {
+ code = dev_proc(dev->child, composite)(dev->child, pcdev, pcte, pgs, memory, cdev);
+ if (code < 0)
+ return code;
+
+ if (gs_is_pdf14trans_compositor(pcte)) {
+ switch(pct->params.pdf14_op)
+ {
+ case PDF14_POP_DEVICE:
+ if (psubclass_data->pre_composite_device != NULL) {
+ if (dev->child) {
+ dev->child->parent = NULL;
+ dev->child->child = NULL;
+ dev->child->finalize = psubclass_data->saved_finalize_method;
+ rc_decrement(dev->child, "default_subclass_composite_front");
+ }
+ dev->child = psubclass_data->pre_composite_device;
+ psubclass_data->pre_composite_device = NULL;
+ psubclass_data->saved_finalize_method = NULL;
+ while (dev) {
+ memcpy(&(dev->color_info), &(dev->child->color_info), sizeof(gx_device_color_info));
+ dev = dev->parent;
+ }
+ }
+ break;
+ case PDF14_PUSH_DEVICE:
+ /* *pcdev is always returned containing a device capable of doing
+ * compositing. This may mean it is a new device. If this wants
+ * to be the new 'device' in the graphics state, then code will
+ * return as 1. */
+ if (code == 1) {
+ /* We want this device to stay ahead of the compositor; the newly created compositor has
+ * inserted itself in front of our child device, so basically we want to replace
+ * our current child with the newly created compositor. I hope !
+ */
+ psubclass_data = (generic_subclass_data *)dev->subclass_data;
+ if (psubclass_data == NULL)
+ return_error(gs_error_undefined);
+ psubclass_data->pre_composite_device = dev->child;
+ psubclass_data->saved_finalize_method = (*pcdev)->finalize;
+ (*pcdev)->finalize = subclass_composite_front_finalize;
+
+ (*pcdev)->child = dev->child;
+ dev->child = *pcdev;
+ (*pcdev)->parent = dev;
+ while (dev) {
+ memcpy(&dev->color_info, &(*pcdev)->color_info, sizeof(gx_device_color_info));
+ dev = dev->parent;
+ }
+ }
+ break;
+ default:
+ /* It seems like many operations can result in the pdf14 device altering its color
+ * info, presumably as we push different blending spaces. Ick. In order to stay in sync
+ * any time we have inserted a compositor after this class, we must update the color info
+ * of this device after every operation, in case it changes....
+ */
+ if (psubclass_data->pre_composite_device != NULL) {
+ while (dev) {
+ memcpy(&(dev->color_info), &(dev->child->color_info), sizeof(gx_device_color_info));
+ dev = dev->parent;
+ }
+ }
+ break;
+ }
+
+ }
+ /* We are inserting the compositor code after this device, or the compositor
+ * did not create a new compositor. Either way we don't want the compositor code
+ * to think we want to push a new device, so just return this device to the caller.
+ */
+ *pcdev = thisdev;
+ return 0;
+ }
+ return 0;
+}
+
int default_subclass_composite(gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte,
gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev)
{
@@ -439,7 +532,7 @@ int default_subclass_composite(gx_device *dev, gx_device **pcdev, const gs_compo
else {
/* See the 2 comments above. Now, if the child did not create a new compositor (eg its a clist)
* then it returns pcdev pointing to the passed in device (the child in our case). Now this is a
- * problem, if we return with pcdev == child->dev, and teh current device is 'dev' then the
+ * problem, if we return with pcdev == child->dev, and the current device is 'dev' then the
* compositor code will think we wanted to push a new device and will select the child device.
* so here if pcdev == dev->child we change it to be our own device, so that the calling code
* won't redirect the device in the graphics state.
@@ -757,6 +850,13 @@ int default_subclass_fill_stroke_path(gx_device *dev, const gs_gstate *pgs, gx_p
return 0;
}
+int default_subclass_lock_pattern(gx_device *dev, gs_gstate *pgs, gs_id pattern_id, int lock)
+{
+ if (dev->child)
+ return dev_proc(dev->child, lock_pattern)(dev->child, pgs, pattern_id, lock);
+ return 0;
+}
+
int default_subclass_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data)
{
if (dev->child)
@@ -776,13 +876,16 @@ void default_subclass_finalize(const gs_memory_t *cmem, void *vptr)
if (dev->finalize)
dev->finalize(dev);
+ /* Use rc_decrement_only here not rc_decrement because rc_decrement zeroes the
+ * pointer if the count reaches 0. That would be disastrous for us because we
+ * rely on recursively calling finalize in order to fix up the chain of devices.
+ */
+ rc_decrement_only(dev->child, "de-reference child device");
+
if (psubclass_data) {
gs_free_object(dev->memory->non_gc_memory, psubclass_data, "gx_epo_finalize(suclass data)");
dev->subclass_data = NULL;
}
- 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");
@@ -860,6 +963,7 @@ void default_subclass_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, process_page, default_subclass_process_page);
set_dev_proc(dev, transform_pixel_region, default_subclass_transform_pixel_region);
set_dev_proc(dev, fill_stroke_path, default_subclass_fill_stroke_path);
+ set_dev_proc(dev, lock_pattern, default_subclass_lock_pattern);
}
int
diff --git a/base/gdevsclass.h b/base/gdevsclass.h
index 2fb440d6..be8b8283 100644
--- a/base/gdevsclass.h
+++ b/base/gdevsclass.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -55,6 +55,7 @@ dev_proc_strip_tile_rectangle(default_subclass_strip_tile_rectangle);
dev_proc_get_clipping_box(default_subclass_get_clipping_box);
dev_proc_begin_typed_image(default_subclass_begin_typed_image);
dev_proc_get_bits_rectangle(default_subclass_get_bits_rectangle);
+dev_proc_composite(default_subclass_composite_front);
dev_proc_composite(default_subclass_composite);
dev_proc_get_hardware_params(default_subclass_get_hardware_params);
dev_proc_text_begin(default_subclass_text_begin);
@@ -89,6 +90,7 @@ 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);
dev_proc_fill_stroke_path(default_subclass_fill_stroke_path);
+dev_proc_lock_pattern(default_subclass_lock_pattern);
dev_page_proc_install(default_subclass_install);
dev_page_proc_begin_page(default_subclass_begin_page);
dev_page_proc_end_page(default_subclass_end_page);
diff --git a/base/gsargs.c b/base/gsargs.c
index a2023d5e..a17998f9 100644
--- a/base/gsargs.c
+++ b/base/gsargs.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -214,6 +214,7 @@ arg_next(arg_list * pal, const char **argstr, const gs_memory_t *errmem)
int c;
int i;
bool in_quote, eol;
+ int prev_c_was_equals = 0;
*argstr = NULL;
@@ -304,9 +305,10 @@ arg_next(arg_list * pal, const char **argstr, const gs_memory_t *errmem)
c = get_codepoint(pal, pas);
if (c == '\n')
c = get_codepoint(pal, pas);
+ prev_c_was_equals = 0;
continue; /* Next char */
}
- if (c == '\\') {
+ if (c == '\\' && pal->depth > 0) {
/* Check for \ followed by newline. */
c = get_codepoint(pal, pas);
if (is_eol(c)) {
@@ -315,18 +317,33 @@ arg_next(arg_list * pal, const char **argstr, const gs_memory_t *errmem)
if (c == '\n')
c = get_codepoint(pal, pas);
eol = true;
+ prev_c_was_equals = 0;
continue; /* Next char */
}
- /* \ anywhere else is treated as a printing character. */
- /* This is different from the Unix shells. */
- if (i >= arg_str_max - 1) {
- cstr[i] = 0;
- errprintf(errmem, "Command too long: %s\n", cstr);
- return_error(gs_error_Fatal);
+ {
+ char what;
+
+ if (c == '"') {
+ /* currently \" is treated as literal ". No other literals yet.
+ * We may expand this in future. */
+ what = c;
+ c = get_codepoint(pal, pas);
+ } else {
+ /* \ anywhere else is treated as a printing character. */
+ /* This is different from the Unix shells. */
+ what = '\\';
+ }
+
+ if (i >= arg_str_max - 1) {
+ cstr[i] = 0;
+ errprintf(errmem, "Command too long: %s\n", cstr);
+ return_error(gs_error_Fatal);
+ }
+ cstr[i++] = what;
+ eol = false;
+ prev_c_was_equals = 0;
+ continue; /* Next char */
}
- cstr[i++] = '\\';
- eol = false;
- continue; /* Next char */
}
/* c will become part of the argument */
if (i >= arg_str_max - 1) {
@@ -341,7 +358,7 @@ arg_next(arg_list * pal, const char **argstr, const gs_memory_t *errmem)
* have to have carefully quoted double-quotes to make them survive the
* shell anyway! */
if (c == '"' && pal->depth > 0) {
- if (i == 0 && !in_quote)
+ if ((i == 0 || prev_c_was_equals) && !in_quote)
in_quote = true;
else if (in_quote) {
/* Need to check the next char to see if we're closing at the end */
@@ -355,6 +372,7 @@ arg_next(arg_list * pal, const char **argstr, const gs_memory_t *errmem)
/* Not a close quote, just a literal quote. */
i += codepoint_to_utf8(&cstr[i], '"');
eol = false;
+ prev_c_was_equals = 0;
continue; /* Jump to the start of the loop without reading another char. */
} else
i += codepoint_to_utf8(&cstr[i], c);
@@ -362,6 +380,7 @@ arg_next(arg_list * pal, const char **argstr, const gs_memory_t *errmem)
else
i += codepoint_to_utf8(&cstr[i], c);
eol = is_eol(c);
+ prev_c_was_equals = (c == '=');
c = get_codepoint(pal, pas);
}
cstr[i] = 0;
diff --git a/base/gscdefs.h b/base/gscdefs.h
index a5cb3f91..a7b56456 100644
--- a/base/gscdefs.h
+++ b/base/gscdefs.h
@@ -17,6 +17,15 @@
# define gscdefs_INCLUDED
+/* If we are cluster testing, then we want to nobble stuff
+ * that might change between versions. */
+#ifdef CLUSTER
+#undef GS_PRODUCTFAMILY
+#define GS_PRODUCTFAMILY "GPL Ghostscript"
+#undef GS_PRODUCT
+#define GS_PRODUCT GS_PRODUCTFAMILY
+#endif
+
#define GS_STRINGIZE2(s) #s
#define GS_STRINGIZE(s) GS_STRINGIZE2(s)
diff --git a/base/gscdevn.c b/base/gscdevn.c
index ef2086b3..a7f317d6 100644
--- a/base/gscdevn.c
+++ b/base/gscdevn.c
@@ -126,6 +126,7 @@ gs_cspace_new_DeviceN(
pcsdevn->num_process_names = 0;
pcsdevn->process_names = NULL;
pcsdevn->mem = pmem->non_gc_memory;
+ pcsdevn->all_none = false;
/* Allocate space for color names list. */
code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN");
@@ -577,6 +578,7 @@ check_DeviceN_component_names(const gs_color_space * pcs, gs_gstate * pgs)
= &pgs->color_component_map;
gx_device * dev = pgs->device;
bool non_match = false;
+ int none_count = 0;
pcolor_component_map->num_components = num_comp;
pcolor_component_map->cspace_id = pcs->id;
@@ -642,10 +644,15 @@ check_DeviceN_component_names(const gs_color_space * pcs, gs_gstate * pgs)
pcolor_component_map->color_map[i] = -1 and watching
for this case later during the remap operation. */
pcolor_component_map->color_map[i] = -1;
+ none_count++;
}
}
}
pcolor_component_map->use_alt_cspace = non_match;
+
+ if (none_count == num_comp)
+ return 1;
+
return 0;
}
@@ -706,6 +713,10 @@ gx_install_DeviceN(gs_color_space * pcs, gs_gstate * pgs)
if (code < 0)
return code;
+ /* Indicates all colorants are /None */
+ if (code > 0)
+ pcs->params.device_n.all_none = true;
+
if (pgs->icc_manager->device_named != NULL) {
pcs->params.device_n.named_color_supported =
gsicc_support_named_color(pcs, pgs);
diff --git a/base/gscms.h b/base/gscms.h
index 7fb362fe..b87f6091 100644
--- a/base/gscms.h
+++ b/base/gscms.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -291,6 +291,9 @@ struct cmm_dev_profile_s {
bool pageneutralcolor; /* Only valid if graydetection true */
bool usefastcolor; /* Used when we want to use no cm */
bool blacktext; /* Force text to be pure black */
+ bool blackvector; /* Force vectors to be pure black */
+ float blackthresholdL; /* Luminance threshold */
+ float blackthresholdC; /* Chrominance threshold */
bool supports_devn; /* If the target handles devn colors */
gs_overprint_control_t overprint_control; /* enable is the default */
gsicc_namelist_t *spotnames; /* If our device profiles are devn */
diff --git a/base/gscspace.h b/base/gscspace.h
index 9804efe2..91bb7c78 100644
--- a/base/gscspace.h
+++ b/base/gscspace.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -251,6 +251,7 @@ typedef struct gs_device_n_params_s {
gs_color_space *devn_process_space;
uint num_process_names;
char **process_names;
+ bool all_none;
} gs_device_n_params;
/* Define an abstract type for the client color space data */
diff --git a/base/gsdevice.c b/base/gsdevice.c
index 9af9403d..bc58cdc7 100644
--- a/base/gsdevice.c
+++ b/base/gsdevice.c
@@ -1225,11 +1225,11 @@ int gx_device_delete_output_file(const gx_device * dev, const char *fname)
while (*fmt != 'l' && *fmt != '%')
--fmt;
if (*fmt == 'l')
- gs_snprintf(pfname, len, parsed.fname, count1);
+ gs_snprintf(pfname, gp_file_name_sizeof, parsed.fname, count1);
else
- gs_snprintf(pfname, len, parsed.fname, (int)count1);
+ gs_snprintf(pfname, gp_file_name_sizeof, parsed.fname, (int)count1);
} else if (parsed.len && strchr(parsed.fname, '%')) /* filename with "%%" but no "%nnd" */
- gs_snprintf(pfname, len, parsed.fname);
+ gs_snprintf(pfname, gp_file_name_sizeof, parsed.fname);
else
pfname[0] = 0; /* 0 to use "fname", not "pfname" */
if (pfname[0]) {
diff --git a/base/gsdparam.c b/base/gsdparam.c
index 069b2138..07863706 100644
--- a/base/gsdparam.c
+++ b/base/gsdparam.c
@@ -32,6 +32,9 @@ extern gx_device_nup gs_nup_device;
/* This is for backward compatibility only. */
#define PAGESIZE_IS_MEDIASIZE
+#define BLACKTHRESHOLDL 90
+#define BLACKTHRESHOLDC 3
+
/* Names corresponding to gs_overprint_control_t enum */
static const char *const overprint_control_names[] = {
gs_overprint_control_names, 0
@@ -96,6 +99,9 @@ int gx_default_get_param(gx_device *dev, char *Param, void *list)
bool graydetection = false;
bool usefastcolor = false; /* set for unmanaged color */
bool blacktext = false;
+ bool blackvector = false;
+ float blackthresholdL = BLACKTHRESHOLDL;
+ float blackthresholdC = BLACKTHRESHOLDC;
/* By default overprinting only valid with cmyk devices */
gs_overprint_control_t overprint_control = gs_overprint_control_enable;
bool prebandthreshold = true, temp_bool = false;
@@ -354,6 +360,9 @@ int gx_default_get_param(gx_device *dev, char *Param, void *list)
graydetection = dev_profile->graydetection;
usefastcolor = dev_profile->usefastcolor;
blacktext = dev_profile->blacktext;
+ blackvector = dev_profile->blackvector;
+ blackthresholdC = dev_profile->blackthresholdC;
+ blackthresholdL = dev_profile->blackthresholdL;
overprint_control = dev_profile->overprint_control;
prebandthreshold = dev_profile->prebandthreshold;
/* With respect to Output profiles that have non-standard colorants,
@@ -397,6 +406,15 @@ int gx_default_get_param(gx_device *dev, char *Param, void *list)
if (strcmp(Param, "BlackText") == 0) {
return param_write_bool(plist, "BlackText", &blacktext);
}
+ if (strcmp(Param, "BlackVector") == 0) {
+ return param_write_bool(plist, "BlackVector", &blackvector);
+ }
+ if (strcmp(Param, "BlackThresholdL") == 0) {
+ return param_write_float(plist, "BlackThresholdL", &blackthresholdL);
+ }
+ if (strcmp(Param, "BlackThresholdC") == 0) {
+ return param_write_float(plist, "BlackThresholdC", &blackthresholdC);
+ }
if (strcmp(Param, "Overprint") == 0) {
gs_param_string opc_name;
const char *s = overprint_control_names[(int)overprint_control];
@@ -539,6 +557,9 @@ gx_default_get_params(gx_device * dev, gs_param_list * plist)
bool graydetection = false;
bool usefastcolor = false; /* set for unmanaged color */
bool blacktext = false;
+ bool blackvector = false;
+ float blackthresholdL = BLACKTHRESHOLDL;
+ float blackthresholdC = BLACKTHRESHOLDC;
/* By default, only overprint if the device supports it */
gs_overprint_control_t overprint_control = gs_overprint_control_enable;
bool prebandthreshold = true, temp_bool;
@@ -654,6 +675,9 @@ gx_default_get_params(gx_device * dev, gs_param_list * plist)
graydetection = dev_profile->graydetection;
usefastcolor = dev_profile->usefastcolor;
blacktext = dev_profile->blacktext;
+ blackvector = dev_profile->blackvector;
+ blackthresholdC = dev_profile->blackthresholdC;
+ blackthresholdL = dev_profile->blackthresholdL;
overprint_control = dev_profile->overprint_control;
prebandthreshold = dev_profile->prebandthreshold;
/* With respect to Output profiles that have non-standard colorants,
@@ -715,6 +739,9 @@ gx_default_get_params(gx_device * dev, gs_param_list * plist)
(code = param_write_bool(plist, "GrayDetection", &graydetection)) < 0 ||
(code = param_write_bool(plist, "UseFastColor", &usefastcolor)) < 0 ||
(code = param_write_bool(plist, "BlackText", &blacktext)) < 0 ||
+ (code = param_write_bool(plist, "BlackVector", &blackvector)) < 0 ||
+ (code = param_write_float(plist, "BlackThresholdL", &blackthresholdL)) < 0 ||
+ (code = param_write_float(plist, "BlackThresholdC", &blackthresholdC)) < 0 ||
(code = param_write_bool(plist, "PreBandThreshold", &prebandthreshold)) < 0 ||
(code = param_write_string(plist,"OutputICCProfile", &(profile_array[0]))) < 0 ||
(code = param_write_string(plist,"VectorICCProfile", &(profile_array[1]))) < 0 ||
@@ -1239,6 +1266,62 @@ gx_default_put_blacktext(bool blacktext, gx_device* dev)
}
static int
+gx_default_put_blackthresholds(float blackthresholdL, float blackthresholdC, gx_device *dev)
+{
+ int code = 0;
+ cmm_dev_profile_t* profile_struct;
+
+ if (dev_proc(dev, get_profile) == NULL) {
+ if (dev->icc_struct == NULL) {
+ dev->icc_struct = gsicc_new_device_profile_array(dev);
+ if (dev->icc_struct == NULL)
+ return_error(gs_error_VMerror);
+ }
+ dev->icc_struct->blackthresholdL = blackthresholdL;
+ dev->icc_struct->blackthresholdC = blackthresholdC;
+ } else {
+ code = dev_proc(dev, get_profile)(dev, &profile_struct);
+ if (profile_struct == NULL) {
+ /* Create now */
+ dev->icc_struct = gsicc_new_device_profile_array(dev);
+ profile_struct = dev->icc_struct;
+ if (profile_struct == NULL)
+ return_error(gs_error_VMerror);
+ }
+ profile_struct->blackthresholdL = blackthresholdL;
+ profile_struct->blackthresholdC = blackthresholdC;
+ }
+ return code;
+}
+
+static int
+gx_default_put_blackvector(bool blackvector, gx_device* dev)
+{
+ int code = 0;
+ cmm_dev_profile_t* profile_struct;
+
+ if (dev_proc(dev, get_profile) == NULL) {
+ if (dev->icc_struct == NULL) {
+ dev->icc_struct = gsicc_new_device_profile_array(dev);
+ if (dev->icc_struct == NULL)
+ return_error(gs_error_VMerror);
+ }
+ dev->icc_struct->blackvector = blackvector;
+ } else {
+ code = dev_proc(dev, get_profile)(dev, &profile_struct);
+ if (profile_struct == NULL) {
+ /* Create now */
+ dev->icc_struct = gsicc_new_device_profile_array(dev);
+ profile_struct = dev->icc_struct;
+ if (profile_struct == NULL)
+ return_error(gs_error_VMerror);
+ }
+ profile_struct->blackvector = blackvector;
+ }
+ return code;
+}
+
+static int
gx_default_put_overprint_control(gs_overprint_control_t overprint_control, gx_device * dev)
{
int code = 0;
@@ -1461,7 +1544,7 @@ rc_free_pages_list(gs_memory_t * mem, void *ptr_in, client_name_t cname)
gdev_pagelist *PageList = (gdev_pagelist *)ptr_in;
if (PageList->rc.ref_count <= 1) {
- gs_free(mem->non_gc_memory, PageList->Pages, 1, PagesSize, "free page list");
+ gs_free(mem->non_gc_memory, PageList->Pages, 1, strlen(PageList->Pages), "free page list");
gs_free(mem->non_gc_memory, PageList, 1, sizeof(gdev_pagelist), "free structure to hold page list");
}
}
@@ -1515,6 +1598,9 @@ gx_default_put_params(gx_device * dev, gs_param_list * plist)
bool graydetection = false;
bool usefastcolor = false;
bool blacktext = false;
+ bool blackvector = false;
+ float blackthresholdL = BLACKTHRESHOLDL;
+ float blackthresholdC = BLACKTHRESHOLDC;
gs_overprint_control_t overprint_control = gs_overprint_control_enable;
bool prebandthreshold = false;
bool use_antidropout = dev->color_info.use_antidropout_downscaler;
@@ -1535,6 +1621,9 @@ gx_default_put_params(gx_device * dev, gs_param_list * plist)
devicegraytok = dev->icc_struct->devicegraytok;
usefastcolor = dev->icc_struct->usefastcolor;
blacktext = dev->icc_struct->blacktext;
+ blackvector = dev->icc_struct->blackvector;
+ blackthresholdL = dev->icc_struct->blackthresholdL;
+ blackthresholdC = dev->icc_struct->blackthresholdC;
prebandthreshold = dev->icc_struct->prebandthreshold;
overprint_control = dev->icc_struct->overprint_control;
} else {
@@ -1850,6 +1939,21 @@ nce:
ecode = code;
param_signal_error(plist, param_name, ecode);
}
+ if ((code = param_read_bool(plist, (param_name = "BlackVector"),
+ &blackvector)) < 0) {
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ }
+ if ((code = param_read_float(plist, (param_name = "BlackThresholdL"),
+ &blackthresholdL)) < 0) {
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ }
+ if ((code = param_read_float(plist, (param_name = "BlackThresholdC"),
+ &blackthresholdC)) < 0) {
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ }
if ((code = param_put_enum(plist, "Overprint",
(int*)&overprint_control, overprint_control_names, ecode)) < 0) {
ecode = code;
@@ -2108,7 +2212,6 @@ label:\
}
memset(dev->PageList->Pages, 0x00, pagelist.size + 1);
memcpy(dev->PageList->Pages, pagelist.data, pagelist.size);
- dev->PageList->PagesSize = pagelist.size + 1;
rc_init_free(dev->PageList, dev->memory->non_gc_memory, 1, rc_free_pages_list);
}
@@ -2296,6 +2399,12 @@ label:\
code = gx_default_put_blacktext(blacktext, dev);
if (code < 0)
return code;
+ code = gx_default_put_blackvector(blackvector, dev);
+ if (code < 0)
+ return code;
+ code = gx_default_put_blackthresholds(blackthresholdL, blackthresholdC, dev);
+ if (code < 0)
+ return code;
code = gx_default_put_overprint_control(overprint_control, dev);
if (code < 0)
return code;
diff --git a/base/gsdps1.c b/base/gsdps1.c
index 06998b7b..e06d8cae 100644
--- a/base/gsdps1.c
+++ b/base/gsdps1.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -182,6 +182,16 @@ gs_rectclip(gs_gstate * pgs, const gs_rect * pr, uint count)
return 0;
}
+/* Setup for black vector handling */
+static inline bool black_vectors(gs_gstate *pgs, gx_device *dev)
+{
+ if (dev->icc_struct != NULL && dev->icc_struct->blackvector &&
+ pgs->black_textvec_state == NULL) {
+ return gsicc_setup_blacktextvec(pgs, dev, false);
+ }
+ return false;
+}
+
/* Fill a list of rectangles. */
/* We take the trouble to do this efficiently in the simple cases. */
int
@@ -199,13 +209,16 @@ gs_rectfill(gs_gstate * pgs, const gs_rect * pr, uint count)
dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_hlcolor,
NULL, 0));
bool center_of_pixel = (pgs->fill_adjust.x == 0 && pgs->fill_adjust.y == 0);
+ bool black_vector = false;
/* Processing a fill object operation */
ensure_tag_is_set(pgs, pgs->device, GS_VECTOR_TAG); /* NB: may unset_dev_color */
+ black_vector = black_vectors(pgs, pgs->device); /* Set vector fill to black */
+
code = gx_set_dev_color(pgs);
if (code != 0)
- return code;
+ goto exit;
if ( !(pgs->device->page_uses_transparency ||
dev_proc(pgs->device, dev_spec_op)(pgs->device,
@@ -231,7 +244,7 @@ gs_rectfill(gs_gstate * pgs, const gs_rect * pr, uint count)
/* We should never plot anything for an empty clip rectangle */
if ((clip_rect.p.x >= clip_rect.q.x) &&
(clip_rect.p.y >= clip_rect.q.y))
- return 0;
+ goto exit;
for (i = 0; i < count; ++i) {
gs_fixed_point p, q;
gs_fixed_rect draw_rect;
@@ -258,7 +271,7 @@ gs_rectfill(gs_gstate * pgs, const gs_rect * pr, uint count)
code = dev_proc(pdev, fill_rectangle_hl_color)(pdev,
&draw_rect, pgs2, pdc, pcpath);
if (code < 0)
- return code;
+ goto exit;
}
} else {
int x, y, w, h;
@@ -296,7 +309,8 @@ gs_rectfill(gs_gstate * pgs, const gs_rect * pr, uint count)
goto slow;
}
}
- return 0;
+ code = 0;
+ goto exit;
slow:rlist = pr + i;
rcount = count - i;
} {
@@ -304,7 +318,7 @@ gs_rectfill(gs_gstate * pgs, const gs_rect * pr, uint count)
if (do_save) {
if ((code = gs_gsave(pgs)) < 0)
- return code;
+ goto exit;
code = gs_newpath(pgs);
}
if ((code >= 0) &&
@@ -317,6 +331,12 @@ gs_rectfill(gs_gstate * pgs, const gs_rect * pr, uint count)
else if (code < 0)
gs_newpath(pgs);
}
+
+exit:
+ if (black_vector) {
+ /* Restore color */
+ gsicc_restore_blacktextvec(pgs, false);
+ }
return code;
}
diff --git a/base/gsequivc.c b/base/gsequivc.c
index 441183ed..477fe7f6 100644
--- a/base/gsequivc.c
+++ b/base/gsequivc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -472,9 +472,10 @@ capture_spot_equivalent_cmyk_colors(gx_device * pdev, const gs_gstate * pgs,
0 /* blend_profile */, 0 /* postren_profile */,
{ {0} } /* rendercond[] */, 0 /* devicegraytok */,
0 /* graydection */, 0 /* pageneutralcolor */,
- 0 /* usefastcolor */, 0 /* blacktext */, 0 /* supports_devn */,
- 0 /* overprint_control */, 0 /* spotnames */,
- 0 /* prebandthreshold */, 0 /* memory */,
+ 0 /* usefastcolor */, 0 /* blacktext */, 0 /* blackvector */,
+ 0.0 /* blackthresholdL */, 0.0 /* blackthresholdC */,
+ 0 /* supports_devn */, 0 /* overprint_control */,
+ 0 /* spotnames */, 0 /* prebandthreshold */, 0 /* memory */,
{ 0 } /* rc_header */
};
@@ -502,6 +503,7 @@ capture_spot_equivalent_cmyk_colors(gx_device * pdev, const gs_gstate * pgs,
temp_profile.usefastcolor = false; /* This avoids a few headaches */
temp_profile.blacktext = false;
+ temp_profile.blackvector = false;
temp_profile.prebandthreshold = true;
temp_profile.supports_devn = false;
temp_profile.rendercond[0] = render_cond;
diff --git a/base/gsequivc.h b/base/gsequivc.h
index d5501b2d..4317be2d 100644
--- a/base/gsequivc.h
+++ b/base/gsequivc.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
diff --git a/base/gserrors.h b/base/gserrors.h
index 0e4982d7..d91422d6 100644
--- a/base/gserrors.h
+++ b/base/gserrors.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -62,6 +62,15 @@ enum gs_error_type {
/* invalidid is for the NeXT DPS extension. */
gs_error_invalidid = -30,
+/* We need a specific stackoverflow error for the PDF interpreter to avoid dropping into
+ * the Postscript interpreter's stack extending code, when the PDF interpreter is called from
+ * Postscript
+ */
+ gs_error_pdf_stackoverflow = -31,
+
+/* Internal error for the C-based PDF interpreter, to indicate a circular PDF reference */
+ gs_error_circular_reference = -32,
+
/* ------ Pseudo-errors used internally ------ */
gs_error_hit_detected = -99,
@@ -121,8 +130,6 @@ enum gs_error_type {
*/
gs_error_handled = -111,
-/* Internal error for the C-based PDF interpreter, to indicate a circular PDF reference */
- gs_error_circular_reference = -112,
};
/* We do provide a typedef type for external API use */
diff --git a/base/gsfcmap.c b/base/gsfcmap.c
index 3c9317d5..246a0aa3 100644
--- a/base/gsfcmap.c
+++ b/base/gsfcmap.c
@@ -586,6 +586,7 @@ gs_cmap_ToUnicode_alloc(gs_memory_t *mem, int id, int num_codes, int key_size, i
"gs_cmap_ToUnicode_alloc");
if (map == NULL) {
gs_cmap_free(*ppcmap, mem);
+ *ppcmap = NULL;
return_error(gs_error_VMerror);
}
memset(map, 0, (size_t)num_codes * (value_size + 2));
diff --git a/base/gsftopts.h b/base/gsftopts.h
index 7fcacac2..0f891e24 100644
--- a/base/gsftopts.h
+++ b/base/gsftopts.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -17,3 +17,12 @@
/* Freetype build customisations */
#undef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#undef FT_CONFIG_OPTION_USE_LZW
+#undef FT_CONFIG_OPTION_USE_ZLIB
+#undef FT_CONFIG_OPTION_USE_BZIP2
+#undef FT_CONFIG_OPTION_USE_PNG
+#undef FT_CONFIG_OPTION_USE_HARFBUZZ
+#undef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#undef TT_CONFIG_OPTION_BDF
+#undef T1_CONFIG_OPTION_NO_AFM
+#undef TT_CONFIG_OPTION_COLOR_LAYERS
diff --git a/base/gsgstate.c b/base/gsgstate.c
index 0f7d182a..76b511c5 100644
--- a/base/gsgstate.c
+++ b/base/gsgstate.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -149,7 +149,7 @@ gs_gstate_initialize(gs_gstate * pgs, gs_memory_t * mem)
pgs->icc_profile_cache = gsicc_profilecache_new(pgs->memory);
if (pgs->icc_profile_cache == NULL)
return_error(gs_error_VMerror);
- pgs->black_text_state = NULL;
+ pgs->black_textvec_state = NULL;
#if ENABLE_CUSTOM_COLOR_CALLBACK
pgs->custom_color_callback = INIT_CUSTOM_COLOR_PTR;
#endif
@@ -179,7 +179,7 @@ gs_gstate_copied(gs_gstate * pgs)
rc_increment(pgs->icc_link_cache);
rc_increment(pgs->icc_profile_cache);
rc_increment(pgs->icc_manager);
- rc_increment(pgs->black_text_state);
+ rc_increment(pgs->black_textvec_state);
}
/* Adjust reference counts before assigning one gs_gstate to another. */
@@ -209,7 +209,7 @@ gs_gstate_pre_assign(gs_gstate *pto, const gs_gstate *pfrom)
RCCOPY(icc_link_cache);
RCCOPY(icc_profile_cache);
RCCOPY(icc_manager);
- RCCOPY(black_text_state);
+ RCCOPY(black_textvec_state);
#undef RCCOPY
}
@@ -250,6 +250,6 @@ gs_gstate_release(gs_gstate * pgs)
RCDECR(icc_link_cache);
RCDECR(icc_profile_cache);
RCDECR(icc_manager);
- RCDECR(black_text_state);
+ RCDECR(black_textvec_state);
#undef RCDECR
}
diff --git a/base/gsht.c b/base/gsht.c
index 738c1661..3fc57192 100644
--- a/base/gsht.c
+++ b/base/gsht.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -1133,7 +1133,7 @@ gx_gstate_dev_ht_install(
* be cleared immediately below, so subsequently it will not be
* possible to tell if that this information is being shared.
*/
- if (pdht->components != NULL) {
+ if (pdht->components != NULL && !mem_diff) {
int input_ncomps = pdht->num_comp;
for (i = 0; i < input_ncomps; i++) {
@@ -1149,7 +1149,7 @@ gx_gstate_dev_ht_install(
memset(p_s_order, 0, sizeof(*p_s_order));
}
}
- if (used_default) {
+ if (used_default && !mem_diff) {
memset(&pdht->order, 0, sizeof(pdht->order));
}
diff --git a/base/gshtscr.c b/base/gshtscr.c
index 29cd93e1..fe6a1c5a 100644
--- a/base/gshtscr.c
+++ b/base/gshtscr.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -344,6 +344,15 @@ pick_cell_size(gs_screen_halftone * ph, const gs_matrix * pmat, ulong max_size,
if (u0 == 0 && v0 == 0)
return_error(gs_error_rangecheck);
+
+ /* We increment rt in a loop below until (u+v) * rt
+ * is at least 4. Make sure that rt has enough range
+ * to satisfy that calculation. If it doesn't then
+ * give up (silly values).
+ */
+ if ((fabs(u0) + fabs(v0)) < ((double)5.0 / max_int))
+ return_error(gs_error_rangecheck);
+
while ((fabs(u0) + fabs(v0)) * rt < 4)
++rt;
phcp->C = 0;
diff --git a/base/gsicc.c b/base/gsicc.c
index d8e2bd3a..62f68880 100644
--- a/base/gsicc.c
+++ b/base/gsicc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -474,6 +474,8 @@ gx_remap_ICC(const gs_client_color * pcc, const gs_color_space * pcs,
#endif
return_error(gs_error_unknownerror);
}
+
+
code = gx_remap_ICC_with_link(pcc, pcs, pdc, pgs, dev, select, icc_link);
/* Release the link */
gsicc_release_link(icc_link);
diff --git a/base/gsicc_blacktext.c b/base/gsicc_blacktext.c
index 82699233..d24b90d5 100644
--- a/base/gsicc_blacktext.c
+++ b/base/gsicc_blacktext.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -21,88 +21,250 @@
#include "gsstruct.h"
#include "gzstate.h"
#include "gsicc_blacktext.h"
+#include "gsicc_cache.h"
-/* gsicc_blacktext_state_t is going to be storing GCed items
+/* gsicc_blacktextvec_state_t is going to be storing GCed items
(color spaces and client colors) and so will need to be GCed */
-gs_private_st_ptrs4(st_blacktext_state, gsicc_blacktext_state_t,
- "gsicc_blacktext_state", blacktext_state_enum_ptrs,
- blacktext_state_reloc_ptrs, pcs[0], pcs[1], pcc[0], pcc[1]);
+gs_private_st_ptrs4(st_blacktextvec_state, gsicc_blacktextvec_state_t,
+ "gsicc_blacktextvec_state", blacktextvec_state_enum_ptrs,
+ blacktextvec_state_reloc_ptrs, pcs, pcs_alt, pcc, pcc_alt);
static void
-rc_gsicc_blacktext_state_free(gs_memory_t *mem, void *ptr_in,
+rc_gsicc_blacktextvec_state_free(gs_memory_t *mem, void *ptr_in,
client_name_t cname)
{
- gsicc_blacktext_state_t *state = (gsicc_blacktext_state_t*)ptr_in;
+ gsicc_blacktextvec_state_t *state = (gsicc_blacktextvec_state_t*)ptr_in;
- rc_decrement_cs(state->pcs[0], "rc_gsicc_blacktext_state_free");
- rc_decrement_cs(state->pcs[1], "rc_gsicc_blacktext_state_free");
+ rc_decrement_cs(state->pcs, "rc_gsicc_blacktextvec_state_free");
+ rc_decrement_cs(state->pcs_alt, "rc_gsicc_blacktextvec_state_free");
- gs_free_object(mem->stable_memory, state,
- "rc_gsicc_blacktext_state_free");
+ gs_free_object(state->memory, state,
+ "rc_gsicc_blacktextvec_state_free");
}
-gsicc_blacktext_state_t*
-gsicc_blacktext_state_new(gs_memory_t *memory)
+gsicc_blacktextvec_state_t*
+gsicc_blacktextvec_state_new(gs_memory_t *memory, bool is_text)
{
- gsicc_blacktext_state_t *result;
+ gsicc_blacktextvec_state_t *result;
- result = gs_alloc_struct(memory->stable_memory, gsicc_blacktext_state_t,
- &st_blacktext_state, "gsicc_blacktext_state_new");
+ result = gs_alloc_struct(memory->stable_memory, gsicc_blacktextvec_state_t,
+ &st_blacktextvec_state, "gsicc_blacktextvec_state_new");
if (result == NULL)
return NULL;
- rc_init_free(result, memory->stable_memory, 1, rc_gsicc_blacktext_state_free);
- result->memory = memory;
- result->pcs[0] = NULL;
- result->pcs[1] = NULL;
- result->pcc[0] = NULL;
- result->pcc[1] = NULL;
+ rc_init_free(result, memory->stable_memory, 1, rc_gsicc_blacktextvec_state_free);
+ result->memory = memory->stable_memory;
+ result->pcs = NULL;
+ result->pcs_alt = NULL;
+ result->pcc = NULL;
+ result->pcc_alt = NULL;
+ result->is_text = is_text;
return result;
}
+/* Crude white color check. Only valid for ICC based RGB, CMYK, Gray, and LAB CS.
+ Makes some assumptions about profile. Also may want some tolerance check. */
+bool gsicc_is_white_blacktextvec(gs_gstate *pgs, gx_device *dev, gs_color_space* pcs, gs_client_color* pcc)
+{
+ double Lstar = 0;
+ double astar = 0;
+ double bstar = 0;
+ cmm_dev_profile_t* dev_profile;
+
+ dev_proc(dev, get_profile)(dev, &dev_profile);
+
+ if (gs_color_space_get_index(pcs) == gs_color_space_index_ICC) {
+ if (pcs->cmm_icc_profile_data->data_cs == gsCIELAB) {
+ if (pcc->paint.values[0] >= dev_profile->blackthresholdL &&
+ fabs(pcc->paint.values[1]) < dev_profile->blackthresholdC &&
+ fabs(pcc->paint.values[2]) < dev_profile->blackthresholdC)
+ return true;
+ else
+ return false;
+ }
+ /* For all others, lets get to CIELAB value */
+ if (pgs->icc_manager->lab_profile != NULL) {
+ gsicc_link_t *icc_link;
+ gsicc_rendering_param_t rendering_params;
+ unsigned short psrc[4];
+ unsigned short pdes[3];
+
+ rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
+ rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
+ rendering_params.override_icc = false;
+ rendering_params.preserve_black = gsBKPRESNOTSPECIFIED;
+ rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
+ rendering_params.cmm = gsCMM_DEFAULT;
+
+ icc_link = gsicc_get_link_profile(pgs, NULL, pcs->cmm_icc_profile_data,
+ pgs->icc_manager->lab_profile, &rendering_params,
+ pgs->memory, false);
+ if (icc_link == NULL)
+ return false;
+
+ switch (pcs->cmm_icc_profile_data->data_cs) {
+ case gsGRAY:
+ psrc[0] = (unsigned short)(pcc->paint.values[0] * 65535);
+ break;
+ case gsRGB:
+ psrc[0] = (unsigned short)(pcc->paint.values[0] * 65535);
+ psrc[1] = (unsigned short)(pcc->paint.values[1] * 65535);
+ psrc[2] = (unsigned short)(pcc->paint.values[2] * 65535);
+ break;
+ case gsCMYK:
+ psrc[0] = (unsigned short)(pcc->paint.values[0] * 65535);
+ psrc[1] = (unsigned short)(pcc->paint.values[1] * 65535);
+ psrc[2] = (unsigned short)(pcc->paint.values[2] * 65535);
+ psrc[3] = (unsigned short)(pcc->paint.values[3] * 65535);
+ break;
+ default:
+ gsicc_release_link(icc_link);
+ return false;
+ }
+ (icc_link->procs.map_color)(NULL, icc_link, psrc, pdes, 2);
+ gsicc_release_link(icc_link);
+
+ Lstar = pdes[0] * 100.0 / 65535.0;
+ astar = pdes[1] * 256.0 / 65535.0 - 128.0;
+ bstar = pdes[2] * 256.0 / 65535.0 - 128.0;
+
+ if (Lstar >= dev_profile->blackthresholdL &&
+ fabs(astar) < dev_profile->blackthresholdC &&
+ fabs(bstar) < dev_profile->blackthresholdC)
+ return true;
+ else
+ return false;
+ } else {
+ /* Something to fall back on */
+ switch (pcs->cmm_icc_profile_data->data_cs) {
+ case gsGRAY:
+ if (pcc->paint.values[0] == 1.0)
+ return true;
+ else
+ return false;
+ break;
+ case gsRGB:
+ if (pcc->paint.values[0] == 1.0 && pcc->paint.values[1] == 1.0 &&
+ pcc->paint.values[2] == 1.0)
+ return true;
+ else
+ return false;
+ break;
+ case gsCMYK:
+ if (pcc->paint.values[0] == 0.0 && pcc->paint.values[1] == 0.0 &&
+ pcc->paint.values[2] == 0.0 && pcc->paint.values[3] == 0.0)
+ return true;
+ else
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+ } else
+ return false;
+}
+
+bool gsicc_setup_blacktextvec(gs_gstate *pgs, gx_device *dev, bool is_text)
+{
+ gs_color_space *pcs_curr = gs_currentcolorspace_inline(pgs);
+ gs_color_space *pcs_alt = gs_swappedcolorspace_inline(pgs);
+
+ /* If neither space is ICC then we are not doing anything */
+ if (!gs_color_space_is_ICC(pcs_curr) && !gs_color_space_is_ICC(pcs_alt))
+ return false;
+
+ /* Create a new object to hold the cs details */
+ pgs->black_textvec_state = gsicc_blacktextvec_state_new(pgs->memory, is_text);
+ if (pgs->black_textvec_state == NULL)
+ return false; /* No error just move on */
+
+ /* If curr space is ICC then store it */
+ if (gs_color_space_is_ICC(pcs_curr)) {
+ rc_increment_cs(pcs_curr); /* We are storing the cs. Will decrement when structure is released */
+ pgs->black_textvec_state->pcs = pcs_curr;
+ pgs->black_textvec_state->pcc = pgs->color[0].ccolor;
+ cs_adjust_color_count(pgs, 1); /* The set_gray will do a decrement, only need if pattern */
+ pgs->black_textvec_state->value[0] = pgs->color[0].ccolor->paint.values[0];
+
+ if (gsicc_is_white_blacktextvec(pgs, dev, pcs_curr, pgs->color[0].ccolor))
+ gs_setgray(pgs, 1.0);
+ else
+ gs_setgray(pgs, 0.0);
+ }
+
+ /* If alt space is ICC then store it */
+ if (gs_color_space_is_ICC(pcs_alt)) {
+ rc_increment_cs(pcs_alt); /* We are storing the cs. Will decrement when structure is released */
+ pgs->black_textvec_state->pcs_alt = pcs_alt;
+
+ gs_swapcolors_quick(pgs); /* Have to swap for set_gray and adjust color count */
+ pgs->black_textvec_state->pcc_alt = pgs->color[0].ccolor;
+ cs_adjust_color_count(pgs, 1); /* The set_gray will do a decrement, only need if pattern */
+ pgs->black_textvec_state->value[1] = pgs->color[0].ccolor->paint.values[0];
+
+ if (gsicc_is_white_blacktextvec(pgs, dev, pcs_alt, pgs->color[0].ccolor))
+ gs_setgray(pgs, 1.0);
+ else
+ gs_setgray(pgs, 0.0);
+ gs_swapcolors_quick(pgs);
+ }
+
+ pgs->black_textvec_state->is_fill = pgs->is_fill_color;
+ return true; /* Need to clean up */
+}
+
void
-gsicc_restore_black_text(gs_gstate *pgs)
+gsicc_restore_blacktextvec(gs_gstate *pgs, bool is_text)
{
- gsicc_blacktext_state_t *state = pgs->black_text_state;
+ gsicc_blacktextvec_state_t *state = pgs->black_textvec_state;
int code;
if (state == NULL)
return;
+ if (is_text != state->is_text)
+ return;
+
/* Make sure state and original are same fill_color condition */
if (state->rc.ref_count == 1) {
- if ((state->is_fill && pgs->is_fill_color) ||
- (!state->is_fill && !pgs->is_fill_color)) {
-
- if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[0])) >= 0) {
- /* current client color is gray. no need to decrement */
- pgs->color[0].ccolor = pgs->black_text_state->pcc[0];
- pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[0];
+ if ((state->is_fill && pgs->is_fill_color) || (!state->is_fill && !pgs->is_fill_color)) {
+ if (pgs->black_textvec_state->pcs != NULL) {
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs)) >= 0) {
+ /* current client color is gray. no need to decrement */
+ pgs->color[0].ccolor = pgs->black_textvec_state->pcc;
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[0];
+ }
+ gx_unset_dev_color(pgs);
}
- gs_swapcolors_quick(pgs);
- if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[1])) >= 0) {
- pgs->color[0].ccolor = pgs->black_text_state->pcc[1];
- pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[1];
-
+ if (pgs->black_textvec_state->pcs_alt != NULL) {
+ gs_swapcolors_quick(pgs);
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs_alt)) >= 0) {
+ pgs->color[0].ccolor = pgs->black_textvec_state->pcc_alt;
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[1];
+ }
+ gs_swapcolors_quick(pgs);
+ gx_unset_alt_dev_color(pgs);
}
- gs_swapcolors_quick(pgs);
-
} else {
-
- if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[1])) >= 0) {
- pgs->color[0].ccolor = pgs->black_text_state->pcc[1];
- pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[1];
+ if (pgs->black_textvec_state->pcs_alt != NULL) {
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs_alt)) >= 0) {
+ pgs->color[0].ccolor = pgs->black_textvec_state->pcc_alt;
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[1];
+ }
+ gx_unset_dev_color(pgs);
}
- gs_swapcolors_quick(pgs);
- if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[0])) >= 0) {
- pgs->color[0].ccolor = pgs->black_text_state->pcc[0];
- pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[0];
+ if (pgs->black_textvec_state->pcs != NULL) {
+ gs_swapcolors_quick(pgs);
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs)) >= 0) {
+ pgs->color[0].ccolor = pgs->black_textvec_state->pcc;
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[0];
+ }
+ gs_swapcolors_quick(pgs);
+ gx_unset_alt_dev_color(pgs);
}
- gs_swapcolors_quick(pgs);
}
- gx_unset_dev_color(pgs);
- gx_unset_alt_dev_color(pgs);
}
rc_decrement(state, "gsicc_restore_black_text");
- pgs->black_text_state = NULL;
+ pgs->black_textvec_state = NULL;
} \ No newline at end of file
diff --git a/base/gsicc_blacktext.h b/base/gsicc_blacktext.h
index 09d541a5..30311659 100644
--- a/base/gsicc_blacktext.h
+++ b/base/gsicc_blacktext.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -16,19 +16,22 @@
#ifndef gsicc_blacktext_INCLUDED
# define gsicc_blacktext_INCLUDED
-typedef struct gsicc_blacktext_state_s gsicc_blacktext_state_t;
+typedef struct gsicc_blacktextvec_state_s gsicc_blacktextvec_state_t;
-struct gsicc_blacktext_state_s {
+struct gsicc_blacktextvec_state_s {
gs_memory_t *memory;
rc_header rc;
bool is_fill; /* Needed for proper color restore */
- gs_color_space *pcs[2]; /* If doing black text, color spaces to restore */
- gs_client_color *pcc[2]; /* If doing black text, client colors to restore */
- float value[2]; /* DeviceGray setting blows away the client color
- zero value */
+ gs_color_space *pcs; /* color spaces to restore */
+ gs_color_space *pcs_alt;
+ gs_client_color *pcc; /* client colors to restore */
+ gs_client_color *pcc_alt; /* client colors to restore */
+ float value[2]; /* DeviceGray setting blows away the client color zero value */
+ bool is_text;
};
-gsicc_blacktext_state_t* gsicc_blacktext_state_new(gs_memory_t *memory);
-void gsicc_restore_black_text(gs_gstate *pgs);
-
+gsicc_blacktextvec_state_t* gsicc_blacktextvec_state_new(gs_memory_t *memory, bool is_text);
+void gsicc_restore_blacktextvec(gs_gstate *pgs, bool is_text);
+bool gsicc_setup_blacktextvec(gs_gstate *pgs, gx_device *dev, bool is_text);
+bool gsicc_is_white_blacktextvec(gs_gstate *pgs, gx_device *dev, gs_color_space *pcs, gs_client_color *pcc);
#endif
diff --git a/base/gsicc_cache.c b/base/gsicc_cache.c
index 13eb003a..fd1f78b5 100644
--- a/base/gsicc_cache.c
+++ b/base/gsicc_cache.c
@@ -35,6 +35,7 @@
#include "gxsync.h"
#include "gzstate.h"
#include "stdint_.h"
+#include "assert_.h"
/*
* Note that the the external memory used to maintain
* links in the CMS is generally not visible to GS.
@@ -62,7 +63,7 @@ static int gsicc_compute_linkhash(gsicc_manager_t *icc_manager, gx_device *dev,
gsicc_rendering_param_t *rendering_params,
gsicc_hashlink_t *hash);
-static void gsicc_remove_link(gsicc_link_t *link, const gs_memory_t *memory);
+static void gsicc_remove_link(gsicc_link_t *link);
static void gsicc_get_buff_hash(unsigned char *data, int64_t *hash, unsigned int num_bytes);
@@ -101,24 +102,25 @@ gsicc_cache_new(gs_memory_t *memory)
/* We want this to be maintained in stable_memory. It should be be effected by the
save and restores */
- result = gs_alloc_struct(memory->stable_memory, gsicc_link_cache_t, &st_icc_linkcache,
+ memory = memory->stable_memory;
+ result = gs_alloc_struct(memory, gsicc_link_cache_t, &st_icc_linkcache,
"gsicc_cache_new");
if ( result == NULL )
return(NULL);
result->head = NULL;
result->num_links = 0;
result->cache_full = false;
- result->memory = memory->stable_memory;
+ result->memory = memory;
result->full_wait = NULL; /* Required so finaliser can work when result freed. */
- rc_init_free(result, memory->stable_memory, 1, rc_gsicc_link_cache_free);
- result->lock = gx_monitor_label(gx_monitor_alloc(memory->stable_memory),
+ rc_init_free(result, memory, 1, rc_gsicc_link_cache_free);
+ result->lock = gx_monitor_label(gx_monitor_alloc(memory),
"gsicc_cache_new");
if (result->lock == NULL) {
rc_decrement(result, "gsicc_cache_new");
return(NULL);
}
- result->full_wait = gx_semaphore_label(gx_semaphore_alloc(memory->stable_memory),
- "gsicc_cache_new");
+ result->full_wait = gx_semaphore_label(gx_semaphore_alloc(memory),
+ "gsicc_cache_new");
if (result->full_wait == NULL) {
/* Don't free result->lock, as the finaliser for result does that! */
rc_decrement(result, "gsicc_cache_new");
@@ -136,11 +138,15 @@ rc_gsicc_link_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname)
/* Ending the entire cache. The ref counts on all the links should be 0 */
gsicc_link_cache_t *link_cache = (gsicc_link_cache_t * ) ptr_in;
- if_debug2m(gs_debug_flag_icc, mem,
+ /* mem is unused, but we are passed it anyway by the ref counting mechanisms. */
+ assert(link_cache != NULL && mem == link_cache->memory);
+ if (link_cache == NULL)
+ return;
+ if_debug2m(gs_debug_flag_icc, link_cache->memory,
"[icc] Removing link cache = "PRI_INTPTR" memory = "PRI_INTPTR"\n",
(intptr_t)link_cache, (intptr_t)link_cache->memory);
/* NB: freeing the link_cache will call icc_linkcache_finalize */
- gs_free_object(mem->stable_memory, link_cache, "rc_gsicc_link_cache_free");
+ gs_free_object(link_cache->memory, link_cache, "rc_gsicc_link_cache_free");
}
/* release the monitor of the link_cache when it is freed */
@@ -149,17 +155,21 @@ icc_linkcache_finalize(const gs_memory_t *mem, void *ptr)
{
gsicc_link_cache_t *link_cache = (gsicc_link_cache_t * ) ptr;
+ /* mem is unused, but we are passed it anyway by the ref counting mechanisms. */
+ assert(link_cache != NULL && mem == link_cache->memory);
+ if (link_cache == NULL)
+ return;
while (link_cache->head != NULL) {
if (link_cache->head->ref_count != 0) {
- emprintf2(mem, "link at "PRI_INTPTR" being removed, but has ref_count = %d\n",
+ emprintf2(link_cache->memory, "link at "PRI_INTPTR" being removed, but has ref_count = %d\n",
(intptr_t)link_cache->head, link_cache->head->ref_count);
link_cache->head->ref_count = 0; /* force removal */
}
- gsicc_remove_link(link_cache->head, mem);
+ gsicc_remove_link(link_cache->head);
}
#ifdef DEBUG
if (link_cache->num_links != 0) {
- emprintf1(mem, "num_links is %d, should be 0.\n", link_cache->num_links);
+ emprintf1(link_cache->memory, "num_links is %d, should be 0.\n", link_cache->num_links);
}
#endif
if (link_cache->rc.ref_count == 0) {
@@ -276,7 +286,8 @@ gsicc_alloc_link(gs_memory_t *memory, gsicc_hashlink_t hashcode)
/* The link has to be added in stable memory. We want them
to be maintained across the gsave and grestore process */
- result = gs_alloc_struct(memory->stable_memory, gsicc_link_t, &st_icc_link,
+ memory = memory->stable_memory;
+ result = gs_alloc_struct(memory, gsicc_link_t, &st_icc_link,
"gsicc_alloc_link");
if (result == NULL)
return NULL;
@@ -299,12 +310,12 @@ gsicc_alloc_link(gs_memory_t *memory, gsicc_hashlink_t hashcode)
result->includes_devlink = 0;
result->is_identity = false;
result->valid = false; /* not yet complete */
- result->memory = memory->stable_memory;
+ result->memory = memory;
- result->lock = gx_monitor_label(gx_monitor_alloc(memory->stable_memory),
+ result->lock = gx_monitor_label(gx_monitor_alloc(memory),
"gsicc_link_new");
if (result->lock == NULL) {
- gs_free_object(memory->stable_memory, result, "gsicc_alloc_link(lock)");
+ gs_free_object(memory, result, "gsicc_alloc_link(lock)");
return NULL;
}
gx_monitor_enter(result->lock); /* this link is owned by this thread until built and made "valid" */
@@ -356,11 +367,13 @@ gsicc_link_free_contents(gsicc_link_t *icc_link)
}
void
-gsicc_link_free(gsicc_link_t *icc_link, const gs_memory_t *memory)
+gsicc_link_free(gsicc_link_t *icc_link)
{
+ if (icc_link == NULL)
+ return;
gsicc_link_free_contents(icc_link);
- gs_free_object(memory->stable_memory, icc_link, "gsicc_link_free");
+ gs_free_object(icc_link->memory, icc_link, "gsicc_link_free");
}
void
@@ -589,14 +602,15 @@ gsicc_findcachelink(gsicc_hashlink_t hash, gsicc_link_cache_t *icc_link_cache,
/* Remove link from cache. Notify CMS and free */
static void
-gsicc_remove_link(gsicc_link_t *link, const gs_memory_t *memory)
+gsicc_remove_link(gsicc_link_t *link)
{
gsicc_link_t *curr, *prev;
gsicc_link_cache_t *icc_link_cache = link->icc_link_cache;
+ const gs_memory_t *memory = link->memory;
if_debug2m(gs_debug_flag_icc, memory,
"[icc] Removing link = "PRI_INTPTR" memory = "PRI_INTPTR"\n",
- (intptr_t)link, (intptr_t)memory->stable_memory);
+ (intptr_t)link, (intptr_t)memory);
/* NOTE: link->ref_count must be 0: assert ? */
gx_monitor_enter(icc_link_cache->lock);
if (link->ref_count != 0) {
@@ -627,7 +641,7 @@ gsicc_remove_link(gsicc_link_t *link, const gs_memory_t *memory)
gx_semaphore_signal(icc_link_cache->full_wait); /* let a waiting thread run */
}
gx_monitor_leave(icc_link_cache->lock);
- gsicc_link_free(link, memory); /* outside link cache now. */
+ gsicc_link_free(link); /* outside link cache now. */
} else {
/* even if we didn't find the link to remove, unlock the cache */
gx_monitor_leave(icc_link_cache->lock);
@@ -789,11 +803,8 @@ gsicc_get_link(const gs_gstate *pgs1, gx_device *dev_in,
if (render_cond.cmm == gsCMM_NONE) {
gsicc_link_t *link;
- if (gs_input_profile->data_cs == gsRGB) {
- link = gsicc_nocm_get_link(pgs, dev, 3);
- } else {
- link = gsicc_nocm_get_link(pgs, dev, 4);
- }
+ link = gsicc_nocm_get_link(pgs, dev, gs_input_profile->num_comps);
+
/* Set the identity case if we are in that situation */
if (link != NULL) {
if (gs_input_profile->num_comps ==
@@ -885,6 +896,8 @@ gsicc_alloc_link_entry(gsicc_link_cache_t *icc_link_cache,
gsicc_link_t *link;
int retries = 0;
+ assert(cache_mem == cache_mem->stable_memory);
+
*ret_link = NULL;
/* First see if we can add a link */
/* TODO: this should be based on memory usage, not just num_links */
@@ -931,13 +944,13 @@ gsicc_alloc_link_entry(gsicc_link_cache_t *icc_link_cache,
/* Even if we remove this link, we may still be maxed out so*/
/* the outermost 'while' will check to make sure some other */
/* thread did not grab the one we remove. */
- gsicc_remove_link(link, cache_mem);
+ gsicc_remove_link(link);
}
}
/* insert an empty link that we will reserve so we can unlock while */
/* building the link contents. If successful, the entry will set */
/* the hash for the link, Set valid=false, and lock the profile */
- (*ret_link) = gsicc_alloc_link(cache_mem->stable_memory, hash);
+ (*ret_link) = gsicc_alloc_link(cache_mem, hash);
/* NB: the link returned will be have the lock owned by this thread */
/* the lock will be released when the link becomes valid. */
if (*ret_link) {
@@ -1056,14 +1069,12 @@ gsicc_get_link_profile(const gs_gstate *pgs, gx_device *dev,
We also have the Replace option. */
if (gs_input_profile->rend_is_valid &&
gs_input_profile->rend_cond.cmm == gsCMM_NONE) {
- if (gs_input_profile->data_cs == gsRGB) {
- link = gsicc_nocm_get_link(pgs, dev, 3);
- } else {
- link = gsicc_nocm_get_link(pgs, dev, 4);
- }
+
+ link = gsicc_nocm_get_link(pgs, dev, gs_input_profile->num_comps);
+
/* Set the identity case if we are in that situation */
if (link != NULL) {
- if (gs_input_profile->num_comps ==
+ if (dev_profile != NULL && gs_input_profile->num_comps ==
dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE]->num_comps) {
link->is_identity = true;
}
@@ -1218,10 +1229,11 @@ gsicc_get_link_profile(const gs_gstate *pgs, gx_device *dev,
gs_input_profile->default_match == DEFAULT_GRAY &&
pgs->icc_manager != NULL && devicegraytok) {
if (icc_manager->graytok_profile == NULL) {
+ assert(pgs->icc_manager->memory == pgs->icc_manager->memory->stable_memory);
icc_manager->graytok_profile =
gsicc_set_iccsmaskprofile(GRAY_TO_K, strlen(GRAY_TO_K),
pgs->icc_manager,
- pgs->icc_manager->memory->stable_memory);
+ pgs->icc_manager->memory);
if (icc_manager->graytok_profile == NULL) {
/* Cant create the link */
link->ref_count--;
@@ -1307,7 +1319,7 @@ icc_link_error:
does not maintain an invalid entry. Any other allocations
(e.g. profile handles) would get freed when the profiles
are freed */
- gsicc_remove_link(link, cache_mem);
+ gsicc_remove_link(link);
return NULL;
}
diff --git a/base/gsicc_cache.h b/base/gsicc_cache.h
index c9f51b3b..cbd223b5 100644
--- a/base/gsicc_cache.h
+++ b/base/gsicc_cache.h
@@ -51,7 +51,7 @@ gsicc_link_t* gsicc_get_link_profile(const gs_gstate *pgs, gx_device *dev,
gsicc_rendering_param_t *rendering_params,
gs_memory_t *memory, bool devicegraytok);
void gsicc_release_link(gsicc_link_t *icclink);
-void gsicc_link_free(gsicc_link_t *icc_link, const gs_memory_t *memory);
+void gsicc_link_free(gsicc_link_t *icc_link);
bool gsicc_profiles_equal(cmm_profile_t *profile1, cmm_profile_t *profile2);
void gsicc_get_icc_buff_hash(unsigned char *buffer, int64_t *hash, unsigned int buff_size);
int64_t gsicc_get_hash(cmm_profile_t *profile);
diff --git a/base/gsicc_cms.h b/base/gsicc_cms.h
index d3e0e1de..8f768c7b 100644
--- a/base/gsicc_cms.h
+++ b/base/gsicc_cms.h
@@ -41,7 +41,7 @@ int gsicc_mcm_begin_monitor(gsicc_link_cache_t *cache, gx_device *dev);
gsicc_link_t* gsicc_rcm_get_link(const gs_gstate *pgs, gx_device *dev,
gsicc_colorbuffer_t data_cs);
gsicc_link_t* gsicc_nocm_get_link(const gs_gstate *pgs, gx_device *dev,
- gs_color_space_index src_index );
+ int num_input );
gcmmhprofile_t gscms_get_profile_handle_mem(unsigned char *buffer,
unsigned int input_size,
gs_memory_t *mem);
diff --git a/base/gsicc_lcms2mt.c b/base/gsicc_lcms2mt.c
index ac83787b..0506b278 100644
--- a/base/gsicc_lcms2mt.c
+++ b/base/gsicc_lcms2mt.c
@@ -892,7 +892,6 @@ gscms_create(gs_memory_t *memory)
#endif
#ifdef WITH_CAL
- cmsPlugin(ctx, cal_cms_extensions());
cmsPlugin(ctx, cal_cms_extensions2());
#endif
diff --git a/base/gsicc_manage.c b/base/gsicc_manage.c
index 91be6537..08d5bf19 100644
--- a/base/gsicc_manage.c
+++ b/base/gsicc_manage.c
@@ -40,6 +40,7 @@
#include "gpmisc.h"
#include "gxdevice.h"
#include "gxdevsop.h"
+#include "assert_.h"
#define ICC_HEADER_SIZE 128
#define CREATE_V2_DATA 0
@@ -251,19 +252,17 @@ gsicc_initialize_iccsmask(gsicc_manager_t *icc_manager)
/* Load the gray, rgb, and cmyk profiles */
if ((icc_manager->smask_profiles->smask_gray =
gsicc_set_iccsmaskprofile(SMASK_GRAY_ICC, strlen(SMASK_GRAY_ICC),
- icc_manager, stable_mem) ) == NULL) {
- return gs_throw(-1, "failed to load gray smask profile");
- }
+ icc_manager, stable_mem) ) == NULL)
+ goto error;
if ((icc_manager->smask_profiles->smask_rgb =
gsicc_set_iccsmaskprofile(SMASK_RGB_ICC, strlen(SMASK_RGB_ICC),
- icc_manager, stable_mem)) == NULL) {
- return gs_throw(-1, "failed to load rgb smask profile");
- }
+ icc_manager, stable_mem)) == NULL)
+ goto error;
if ((icc_manager->smask_profiles->smask_cmyk =
gsicc_set_iccsmaskprofile(SMASK_CMYK_ICC, strlen(SMASK_CMYK_ICC),
- icc_manager, stable_mem)) == NULL) {
- return gs_throw(-1, "failed to load cmyk smask profile");
- }
+ icc_manager, stable_mem)) == NULL)
+ goto error;
+
/* Set these as "default" so that pdfwrite or other high level devices
will know that these are manufactured profiles, and default spaces
should be used */
@@ -271,6 +270,20 @@ gsicc_initialize_iccsmask(gsicc_manager_t *icc_manager)
icc_manager->smask_profiles->smask_rgb->default_match = DEFAULT_RGB;
icc_manager->smask_profiles->smask_cmyk->default_match = DEFAULT_CMYK;
return 0;
+
+error:
+ if (icc_manager->smask_profiles->smask_gray)
+ rc_free_icc_profile(stable_mem, icc_manager->smask_profiles->smask_gray, "gsicc_initialize_iccsmask");
+ icc_manager->smask_profiles->smask_gray = NULL;
+ if (icc_manager->smask_profiles->smask_rgb)
+ rc_free_icc_profile(stable_mem, icc_manager->smask_profiles->smask_rgb, "gsicc_initialize_iccsmask");
+ icc_manager->smask_profiles->smask_rgb = NULL;
+ if (icc_manager->smask_profiles->smask_cmyk)
+ rc_free_icc_profile(stable_mem, icc_manager->smask_profiles->smask_cmyk, "gsicc_initialize_iccsmask");
+ icc_manager->smask_profiles->smask_cmyk = NULL;
+ gs_free_object(stable_mem, icc_manager->smask_profiles, "gsicc_initialize_iccsmask");
+ icc_manager->smask_profiles = NULL;
+ return gs_throw(-1, "failed to load an smask profile");
}
static int
@@ -1455,6 +1468,7 @@ gsicc_new_device_profile_array(gx_device *dev)
result->pageneutralcolor = false;
result->usefastcolor = false; /* Default is to not use fast color */
result->blacktext = false;
+ result->blackvector = false;
result->prebandthreshold = true;
result->supports_devn = false;
result->overprint_control = gs_overprint_control_enable; /* Default overprint if the device can */
@@ -2358,11 +2372,12 @@ gsicc_manager_new(gs_memory_t *memory)
/* Allocated in stable gc memory. This done since the profiles
may be introduced late in the process. */
- result = gs_alloc_struct(memory->stable_memory, gsicc_manager_t, &st_gsicc_manager,
+ memory = memory->stable_memory;
+ result = gs_alloc_struct(memory, gsicc_manager_t, &st_gsicc_manager,
"gsicc_manager_new");
if ( result == NULL )
return NULL;
- rc_init_free(result, memory->stable_memory, 1, rc_gsicc_manager_free);
+ rc_init_free(result, memory, 1, rc_gsicc_manager_free);
result->default_gray = NULL;
result->default_rgb = NULL;
result->default_cmyk = NULL;
@@ -2372,14 +2387,14 @@ gsicc_manager_new(gs_memory_t *memory)
result->device_named = NULL;
result->device_n = NULL;
result->smask_profiles = NULL;
- result->memory = memory->stable_memory;
+ result->memory = memory;
result->srcgtag_profile = NULL;
result->override_internal = false;
return result;
}
static void gsicc_manager_free_contents(gsicc_manager_t *icc_manager,
- client_name_t cname)
+ client_name_t cname)
{
int k;
gsicc_devicen_entry_t *device_n, *device_n_next;
@@ -2419,6 +2434,8 @@ rc_gsicc_manager_free(gs_memory_t * mem, void *ptr_in, client_name_t cname)
and then free the structure */
gsicc_manager_t *icc_manager = (gsicc_manager_t * ) ptr_in;
+ assert(mem == icc_manager->memory);
+
gs_free_object(icc_manager->memory, icc_manager, "rc_gsicc_manager_free");
}
@@ -2466,7 +2483,7 @@ gsicc_load_profile_buffer(cmm_profile_t *profile, stream *s,
/* Allocates and loads the named color structure from the stream. */
static int
gsicc_load_namedcolor_buffer(cmm_profile_t *profile, stream *s,
- gs_memory_t *memory)
+ gs_memory_t *memory)
{
int num_bytes,profile_size;
unsigned char *buffer_ptr;
@@ -2484,7 +2501,7 @@ gsicc_load_namedcolor_buffer(cmm_profile_t *profile, stream *s,
return code;
/* Allocate the buffer, stuff with the profile */
buffer_ptr = gs_alloc_bytes(memory->non_gc_memory, profile_size,
- "gsicc_load_profile");
+ "gsicc_load_profile");
if (buffer_ptr == NULL)
return gs_throw(gs_error_VMerror, "Insufficient memory for profile buffer");
num_bytes = sfread(buffer_ptr,sizeof(unsigned char),profile_size,s);
diff --git a/base/gsicc_nocm.c b/base/gsicc_nocm.c
index a592e3b1..18b99dc3 100644
--- a/base/gsicc_nocm.c
+++ b/base/gsicc_nocm.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -349,7 +349,7 @@ gsicc_nocm_copy_curve(gx_transfer_map *in_map, gs_memory_t *mem)
transformation case. */
gsicc_link_t*
gsicc_nocm_get_link(const gs_gstate *pgs, gx_device *dev,
- gs_color_space_index src_index)
+ int num_input)
{
gsicc_link_t *result;
gsicc_hashlink_t hash;
@@ -378,8 +378,8 @@ gsicc_nocm_get_link(const gs_gstate *pgs, gx_device *dev,
a lot of link requests. */
hash.rend_hash = gsCMM_NONE;
hash.des_hash = dev->color_info.num_components;
- hash.src_hash = src_index;
- hash.link_hashcode = src_index + hash.des_hash * 256 + hash.rend_hash * 4096;
+ hash.src_hash = num_input;
+ hash.link_hashcode = num_input + hash.des_hash * 256 + hash.rend_hash * 4096;
/* Check the cache for a hit. */
result = gsicc_findcachelink(hash, pgs->icc_link_cache, false, false);
@@ -426,7 +426,7 @@ gsicc_nocm_get_link(const gs_gstate *pgs, gx_device *dev,
}
nocm_link->num_out = min(dev->color_info.num_components,
GS_CLIENT_COLOR_MAX_COMPONENTS);
- nocm_link->num_in = src_index;
+ nocm_link->num_in = num_input;
result->num_input = nocm_link->num_in;
result->num_output = nocm_link->num_out;
diff --git a/base/gsicc_profilecache.c b/base/gsicc_profilecache.c
index 3accf4c8..5f545059 100644
--- a/base/gsicc_profilecache.c
+++ b/base/gsicc_profilecache.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -28,6 +28,7 @@
#include "gscms.h"
#include "gsicc_profilecache.h"
#include "gserrors.h"
+#include "assert_.h"
#define ICC_CACHE_MAXPROFILE 50
@@ -54,11 +55,12 @@ gsicc_profilecache_new(gs_memory_t *memory)
/* We want this to be maintained in stable_memory. It should not be effected by the
save and restores */
- result = gs_alloc_struct(memory->stable_memory, gsicc_profile_cache_t,
+ memory = memory->stable_memory;
+ result = gs_alloc_struct(memory, gsicc_profile_cache_t,
&st_profile_cache, "gsicc_profilecache_new");
if ( result == NULL )
return(NULL);
- rc_init_free(result, memory->stable_memory, 1, rc_gsicc_profile_cache_free);
+ rc_init_free(result, memory, 1, rc_gsicc_profile_cache_free);
result->head = NULL;
result->num_entries = 0;
result->memory = memory;
@@ -71,10 +73,11 @@ rc_gsicc_profile_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname
gsicc_profile_cache_t *profile_cache = (gsicc_profile_cache_t * ) ptr_in;
gsicc_profile_entry_t *curr = profile_cache->head, *next;
+ assert(mem->stable_memory == profile_cache->memory);
while (curr != NULL ){
next = curr->next;
rc_decrement(curr->color_space, "rc_gsicc_profile_cache_free");
- gs_free_object(profile_cache->memory->stable_memory, curr,
+ gs_free_object(profile_cache->memory, curr,
"rc_gsicc_profile_cache_free");
profile_cache->num_entries--;
curr = next;
@@ -84,7 +87,7 @@ rc_gsicc_profile_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname
emprintf1(mem,"gsicc_profile_cache_free, num_entries is %d (should be 0).\n",
profile_cache->num_entries);
#endif
- gs_free_object(profile_cache->memory->stable_memory, profile_cache,
+ gs_free_object(profile_cache->memory, profile_cache,
"rc_gsicc_profile_cache_free");
}
@@ -100,8 +103,8 @@ gsicc_add_cs(gs_gstate * pgs, gs_color_space * colorspace, uint64_t dictkey)
/* The entry has to be added in stable memory. We want them
to be maintained across the gsave and grestore process */
- result = gs_alloc_struct(memory->stable_memory, gsicc_profile_entry_t,
- &st_profile_entry, "gsicc_add_cs");
+ result = gs_alloc_struct(memory, gsicc_profile_entry_t,
+ &st_profile_entry, "gsicc_add_cs");
if (result == NULL)
return; /* FIXME */
@@ -178,7 +181,7 @@ gsicc_remove_cs_entry(gsicc_profile_cache_t *profile_cache)
#ifdef DEBUG
if (profile_cache->num_entries != 0) {
emprintf1(memory, "profile cache list empty, but list has num_entries=%d.\n",
- profile_cache->num_entries);
+ profile_cache->num_entries);
}
#endif
} else {
@@ -191,5 +194,5 @@ gsicc_remove_cs_entry(gsicc_profile_cache_t *profile_cache)
"[icc] Remove cs from cache = "PRI_INTPTR", hash = %"PRIu64"\n",
(intptr_t)curr->color_space, (uint64_t)curr->key);
rc_decrement(curr->color_space, "gsicc_remove_cs_entry");
- gs_free_object(memory->stable_memory, curr, "gsicc_remove_cs_entry");
+ gs_free_object(memory, curr, "gsicc_remove_cs_entry");
}
diff --git a/base/gsmchunk.c b/base/gsmchunk.c
index f221ac30..5d3dbebe 100644
--- a/base/gsmchunk.c
+++ b/base/gsmchunk.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -369,6 +369,20 @@ static int dump_free_size(gs_memory_t *mem, chunk_free_node_t *node, int depth,
return 1 + count + dump_free_size(mem, node->right_size, depth + 2 + (depth&1), size, addr);
}
+#ifdef DEBUG_CHUNK_PRINT
+static size_t
+largest_free_block(chunk_free_node_t *size)
+{
+ if (size == NULL)
+ return 0;
+ while (1) {
+ if (size->right_size == NULL)
+ return size->size;
+ size = size->right_size;
+ }
+}
+#endif
+
void
gs_memory_chunk_dump_memory(const gs_memory_t *mem)
{
@@ -381,10 +395,12 @@ gs_memory_chunk_dump_memory(const gs_memory_t *mem)
#ifdef DEBUG_CHUNK_PRINT
dmlprintf1(cmem->target, "Chunk "PRI_INTPTR":\n", (intptr_t)cmem);
+ dmlprintf3(cmem->target, "Used=%"PRIxSIZE", Max Used=%"PRIxSIZE", Total Free=%"PRIxSIZE"\n", cmem->used, cmem->max_used, cmem->total_free);
+ dmlprintf1(cmem->target, "Largest free block=%d bytes\n", largest_free_block(cmem->free_size));
#ifdef DEBUG_CHUNK_PRINT_SLABS
{
chunk_slab_t *slab;
- dmlprintf(cmem->target, "Slabs\n");
+ dmlprintf(cmem->target, "Slabs:\n");
for (slab = cmem->slabs; slab != NULL; slab = slab->next)
dmlprintf1(cmem->target, " "PRI_INTPTR"\n", (intptr_t)slab);
}
@@ -778,16 +794,16 @@ chunk_obj_alloc(gs_memory_t *mem, size_t size, gs_memory_type_ptr_t type, client
#ifdef DEBUG_CHUNK_PRINT
#ifdef DEBUG_SEQ
- dmlprintf4(cmem->target, "Event %x: malloc(chunk="PRI_INTPTR", size="PRIxSIZE", cname=%s)\n",
+ dmlprintf4(mem, "Event %x: malloc(chunk="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
cmem->sequence, (intptr_t)cmem, newsize, cname);
#else
- dmlprintf3(cmem->target, "malloc(chunk="PRI_INTPTR", size="PRIxSIZE", cname=%s)\n",
+ dmlprintf3(mem, "malloc(chunk="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
(intptr_t)cmem, newsize, cname);
#endif
#endif
/* Large blocks are allocated directly */
- if (SINGLE_OBJECT_CHUNK(newsize)) {
+ if (SINGLE_OBJECT_CHUNK(size)) {
obj = (chunk_obj_node_t *)gs_alloc_bytes_immovable(cmem->target, newsize, cname);
if (obj == NULL)
return NULL;
@@ -906,6 +922,7 @@ chunk_obj_alloc(gs_memory_t *mem, size_t size, gs_memory_type_ptr_t type, client
/* No appropriate free space slot. We need to allocate a new slab. */
chunk_slab_t *slab;
uint slab_size = newsize + SIZEOF_ROUND_ALIGN(chunk_slab_t);
+
if (slab_size <= (CHUNK_SIZE>>1))
slab_size = CHUNK_SIZE;
slab = (chunk_slab_t *)gs_alloc_bytes_immovable(cmem->target, slab_size, cname);
@@ -956,10 +973,10 @@ chunk_obj_alloc(gs_memory_t *mem, size_t size, gs_memory_type_ptr_t type, client
client_name_string(cname), size, (intptr_t) obj);
#ifdef DEBUG_CHUNK_PRINT
#ifdef DEBUG_SEQ
- dmlprintf5(cmem->target, "Event %x: malloced(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
+ dmlprintf5(mem, "Event %x: malloced(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
obj->sequence, (intptr_t)cmem, (intptr_t)obj, obj->size, cname);
#else
- dmlprintf4(cmem->target, "malloced(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%"PRI_xSIZE", cname=%s)\n",
+ dmlprintf4(mem, "malloced(chunk="PRI_INTPTR", addr="PRI_INTPTR", size=%"PRIxSIZE", cname=%s)\n",
(intptr_t)cmem, (intptr_t)obj, obj->size, cname);
#endif
#endif
diff --git a/base/gsovrc.c b/base/gsovrc.c
index 745ebfbe..574e1e2e 100644
--- a/base/gsovrc.c
+++ b/base/gsovrc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -424,6 +424,7 @@ nooverprint_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, copy_planes, gx_forward_copy_planes);
set_dev_proc(dev, copy_alpha_hl_color, gx_forward_copy_alpha_hl_color);
set_dev_proc(dev, fill_stroke_path, gx_forward_fill_stroke_path);
+ set_dev_proc(dev, lock_pattern, gx_forward_lock_pattern);
}
/*
@@ -903,7 +904,9 @@ overprint_copy_alpha_hl_color(gx_device * dev, const byte * data, int data_x,
overprint_device_t * opdev = (overprint_device_t *)dev;
int code;
- opdev->copy_alpha_hl = true;
+ if ((opdev->op_state == OP_STATE_FILL && !opdev->retain_none_fill) ||
+ (opdev->op_state == OP_STATE_STROKE && !opdev->retain_none_stroke))
+ opdev->copy_alpha_hl = true;
code = gx_default_copy_alpha_hl_color(dev, data, data_x, raster, id, x, y,
width, height, pdcolor, depth);
opdev->copy_alpha_hl = false;
@@ -930,7 +933,7 @@ overprint_copy_planes(gx_device * dev, const byte * data, int data_x, int raster
uchar num_comps;
uchar k,j;
gs_memory_t * mem = dev->memory;
- gx_color_index comps = opdev->op_state == OP_STATE_FILL ? opdev->drawn_comps_fill : opdev->drawn_comps_stroke;
+ gx_color_index comps_orig = opdev->op_state == OP_STATE_FILL ? opdev->drawn_comps_fill : opdev->drawn_comps_stroke;
byte *curr_data = (byte *) data + data_x;
int row, offset;
@@ -972,6 +975,7 @@ overprint_copy_planes(gx_device * dev, const byte * data, int data_x, int raster
/* step through the height */
row = 0;
while (h-- > 0 && code >= 0) {
+ gx_color_index comps = comps_orig;
gb_rect.p.y = y++;
gb_rect.q.y = y;
offset = row * raster_in + data_x;
@@ -981,23 +985,23 @@ overprint_copy_planes(gx_device * dev, const byte * data, int data_x, int raster
for (k = 0; k < tdev->color_info.num_components; k++) {
/* First set the params to zero for all planes except the one we want */
for (j = 0; j < tdev->color_info.num_components; j++)
- gb_params.data[j] = 0;
- gb_params.data[k] = gb_buff + k * raster;
- code = dev_proc(tdev, get_bits_rectangle) (tdev, &gb_rect,
- &gb_params);
- if (code < 0) {
- gs_free_object(mem, gb_buff, "overprint_copy_planes" );
- return code;
- }
- /* Skip the plane if this component is not to be drawn. If
- its the one that we want to draw, replace it with our
- buffer data */
- if ((comps & 0x01) == 1) {
- memcpy(gb_params.data[k], curr_data, w);
- }
- /* Next plane */
- curr_data += plane_height * raster_in;
- comps >>= 1;
+ gb_params.data[j] = 0;
+ gb_params.data[k] = gb_buff + k * raster;
+ code = dev_proc(tdev, get_bits_rectangle) (tdev, &gb_rect,
+ &gb_params);
+ if (code < 0) {
+ gs_free_object(mem, gb_buff, "overprint_copy_planes" );
+ return code;
+ }
+ /* Skip the plane if this component is not to be drawn. If
+ its the one that we want to draw, replace it with our
+ buffer data */
+ if ((comps & 0x01) == 1) {
+ memcpy(gb_params.data[k], curr_data, w);
+ }
+ /* Next plane */
+ curr_data += plane_height * raster_in;
+ comps >>= 1;
}
code = dev_proc(tdev, copy_planes)(tdev, gb_buff, 0, raster,
gs_no_bitmap_id, x, y - 1, w, 1, 1);
@@ -1300,6 +1304,14 @@ overprint_dev_spec_op(gx_device* pdev, int dev_spec_op,
if (dev_spec_op == gxdso_overprint_active)
return !opdev->is_idle;
+ if (dev_spec_op == gxdso_overprint_op)
+ {
+ int ret = opdev->op_state;
+ if ((intptr_t)data >= 0)
+ opdev->op_state = (intptr_t)data;
+ return ret;
+ }
+
if (dev_spec_op == gxdso_device_child) {
gxdso_device_child_request *d = (gxdso_device_child_request *)data;
if (d->target == pdev) {
diff --git a/base/gspaint.c b/base/gspaint.c
index f7127e0e..d67ef36b 100644
--- a/base/gspaint.c
+++ b/base/gspaint.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -273,10 +273,23 @@ alpha_buffer_release(gs_gstate * pgs, bool newpath)
return code;
}
+/* Setup for black vector handling */
+static inline bool black_vectors(gs_gstate *pgs, gx_device *dev)
+{
+ if (dev->icc_struct != NULL && dev->icc_struct->blackvector &&
+ pgs->black_textvec_state == NULL) {
+ return gsicc_setup_blacktextvec(pgs, dev, false);
+ }
+ return false;
+}
+
static int do_fill(gs_gstate *pgs, int rule)
{
int code, abits, acode, rcode = 0;
bool devn;
+ bool black_vector = false;
+ bool in_smask =
+ (dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_in_smask_construction, NULL, 0)) > 0;
/* We need to distinguish text from vectors to set the object tag.
@@ -294,17 +307,18 @@ static int do_fill(gs_gstate *pgs, int rule)
handle that, we'll have to add a flag to the path structure, or to the path
segment structure (depending on how fine grained we require it to be).
*/
- if (pgs->show_gstate == NULL)
+ if (pgs->show_gstate == NULL && !in_smask) {
ensure_tag_is_set(pgs, pgs->device, GS_VECTOR_TAG); /* NB: may unset_dev_color */
- else
+ black_vector = black_vectors(pgs, pgs->device); /* Set vector fill to black */
+ } else
ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
code = gx_set_dev_color(pgs);
if (code != 0)
- return code;
+ goto out;
code = gs_gstate_color_load(pgs);
if (code < 0)
- return code;
+ goto out;
if (pgs->overprint || (!pgs->overprint && dev_proc(pgs->device, dev_spec_op)(pgs->device,
gxdso_overprint_active, NULL, 0))) {
@@ -314,7 +328,7 @@ static int do_fill(gs_gstate *pgs, int rule)
"[overprint] Fill Overprint\n");
code = gs_do_set_overprint(pgs);
if (code < 0)
- return code;
+ goto out;
op_params.op_state = OP_STATE_FILL;
gs_gstate_update_overprint(pgs, &op_params);
@@ -330,10 +344,14 @@ static int do_fill(gs_gstate *pgs, int rule)
if (abits > 1) {
acode = alpha_buffer_init(pgs, pgs->fill_adjust.x,
pgs->fill_adjust.y, abits, devn);
- if (acode == 2) /* Special case for no fill required */
- return 0;
- if (acode < 0)
- return acode;
+ if (acode == 2) { /* Special case for no fill required */
+ code = 0;
+ goto out;
+ }
+ if (acode < 0) {
+ code = acode;
+ goto out;
+ }
} else
acode = 0;
code = gx_fill_path(pgs->path, gs_currentdevicecolor_inline(pgs), pgs, rule,
@@ -343,6 +361,12 @@ static int do_fill(gs_gstate *pgs, int rule)
if (code >= 0 && rcode < 0)
code = rcode;
+out:
+ if (black_vector) {
+ /* Restore color */
+ gsicc_restore_blacktextvec(pgs, false);
+ }
+
return code;
}
@@ -397,6 +421,10 @@ do_stroke(gs_gstate * pgs)
int code, abits, acode, rcode = 0;
bool devn;
bool is_fill_correct = true;
+ bool black_vector = false;
+ bool in_smask =
+ (dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_in_smask_construction, NULL, 0)) > 0;
+
/* We need to distinguish text from vectors to set the object tag.
@@ -414,17 +442,18 @@ do_stroke(gs_gstate * pgs)
handle that, we'll have to add a flag to the path structure, or to the path
segment structure (depending on how fine grained we require it to be).
*/
- if (pgs->show_gstate == NULL)
+ if (pgs->show_gstate == NULL && !in_smask) {
ensure_tag_is_set(pgs, pgs->device, GS_VECTOR_TAG); /* NB: may unset_dev_color */
- else
+ black_vector = black_vectors(pgs, pgs->device);
+ } else
ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
code = gx_set_dev_color(pgs);
if (code != 0)
- return code;
+ goto out;
code = gs_gstate_color_load(pgs);
if (code < 0)
- return code;
+ goto out;
if (pgs->stroke_overprint || (!pgs->stroke_overprint && dev_proc(pgs->device, dev_spec_op)(pgs->device,
@@ -446,7 +475,7 @@ do_stroke(gs_gstate * pgs)
if (!is_fill_correct) {
pgs->is_fill_color = true;
}
- return code;
+ goto out;
}
op_params.op_state = OP_STATE_STROKE;
@@ -487,13 +516,15 @@ do_stroke(gs_gstate * pgs)
if (!is_fill_correct) {
pgs->is_fill_color = true;
}
- return 0;
+ code = 0;
+ goto out;
}
if (acode < 0) {
if (!is_fill_correct) {
pgs->is_fill_color = true;
}
- return acode;
+ code = acode;
+ goto out;
}
gs_setlinewidth(pgs, new_width);
scale_dash_pattern(pgs, scale);
@@ -523,6 +554,12 @@ do_stroke(gs_gstate * pgs)
if (!is_fill_correct) {
pgs->is_fill_color = true;
}
+
+out:
+ if (black_vector) {
+ /* Restore color */
+ gsicc_restore_blacktextvec(pgs, false);
+ }
return code;
}
@@ -603,6 +640,10 @@ static int do_fill_stroke(gs_gstate *pgs, int rule, int *restart)
int code, abits, acode = 0, rcode = 0;
bool devn;
float orig_width, scale, orig_flatness;
+ bool black_vector = false;
+ bool in_smask =
+ (dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_in_smask_construction, NULL, 0)) > 0;
+
/* It is either our first time, or the stroke was a pattern and
we are coming back from the error if restart < 1 (0 is first
@@ -615,7 +656,7 @@ static int do_fill_stroke(gs_gstate *pgs, int rule, int *restart)
if(gs_currentdevicecolor_inline(pgs)->colors.pattern.p_tile != NULL) {
id = gs_currentdevicecolor_inline(pgs)->colors.pattern.p_tile->id;
- code = gx_pattern_cache_entry_set_lock(pgs, id, true);
+ code = dev_proc(pgs->device, lock_pattern)(pgs->device, pgs, id, true);
} else {
code = 0;
}
@@ -643,30 +684,31 @@ static int do_fill_stroke(gs_gstate *pgs, int rule, int *restart)
handle that, we'll have to add a flag to the path structure, or to the path
segment structure (depending on how fine grained we require it to be).
*/
- if (pgs->show_gstate == NULL)
+ if (pgs->show_gstate == NULL && !in_smask) {
ensure_tag_is_set(pgs, pgs->device, GS_VECTOR_TAG); /* NB: may unset_dev_color */
- else
+ black_vector = black_vectors(pgs, pgs->device);
+ } else
ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
/* if we are at restart == 0, we set the stroke color. */
code = gx_set_dev_color(pgs);
if (code != 0)
- return code; /* may be gs_error_Remap_color or real error */
+ goto out2; /* may be gs_error_Remap_color or real error */
code = gs_gstate_color_load(pgs);
if (code < 0)
- return code;
+ goto out2;
/* If this was a pattern color, make sure and lock it in the pattern_cache */
if (gx_dc_is_pattern1_color(gs_currentdevicecolor_inline(pgs))) {
gs_id id;
if(gs_currentdevicecolor_inline(pgs)->colors.pattern.p_tile != NULL) {
id = gs_currentdevicecolor_inline(pgs)->colors.pattern.p_tile->id;
- code = gx_pattern_cache_entry_set_lock(pgs, id, true);
+ code = dev_proc(pgs->device, lock_pattern)(pgs->device, pgs, id, true);
} else {
code = 0;
}
- if (code < 0)
- return code; /* lock failed -- tile not in cache? */
+ if (code < 0)
+ goto out2; /* lock failed -- tile not in cache? */
}
}
@@ -676,7 +718,7 @@ static int do_fill_stroke(gs_gstate *pgs, int rule, int *restart)
"[overprint] StrokeFill Stroke Set Overprint\n");
code = gs_do_set_overprint(pgs);
if (code < 0)
- return code;
+ goto out2;
}
*restart = 1; /* finished, successfully with stroke_color */
@@ -690,7 +732,7 @@ static int do_fill_stroke(gs_gstate *pgs, int rule, int *restart)
code = gx_set_dev_color(pgs);
if (code != 0) {
- return code;
+ goto out2;
}
code = gs_gstate_color_load(pgs);
if (code < 0) {
@@ -769,23 +811,28 @@ static int do_fill_stroke(gs_gstate *pgs, int rule, int *restart)
if(gs_currentdevicecolor_inline(pgs)->colors.pattern.p_tile != NULL) {
id = gs_currentdevicecolor_inline(pgs)->colors.pattern.p_tile->id;
- code = gx_pattern_cache_entry_set_lock(pgs, id, false);
+ code = dev_proc(pgs->device, lock_pattern)(pgs->device, pgs, id, false);
} else {
code = 0;
}
if (code < 0)
- return code; /* lock failed -- tile not in cache? */
+ goto out2; /* lock failed -- tile not in cache? */
}
}
out:
+ if (black_vector) {
+ /* Restore color */
+ gsicc_restore_blacktextvec(pgs, false);
+ }
+
if (gx_dc_is_pattern1_color(gs_swappeddevicecolor_inline(pgs))) {
gs_id id;
if (gs_swappeddevicecolor_inline(pgs)->colors.pattern.p_tile != NULL) {
id = gs_swappeddevicecolor_inline(pgs)->colors.pattern.p_tile->id;
- rcode = gx_pattern_cache_entry_set_lock(pgs, id, false);
- if (rcode < 0)
- return rcode; /* unlock failed -- shouldn't be possible */
+ rcode = dev_proc(pgs->device, lock_pattern)(pgs->device, pgs, id, false);
+ if (rcode < 0)
+ return rcode; /* unlock failed -- shouldn't be possible */
} else {
code = 0;
}
@@ -793,6 +840,13 @@ out:
if (code >= 0 && acode < 0)
code = acode;
return code;
+
+out2:
+ if (black_vector) {
+ /* Restore color */
+ gsicc_restore_blacktextvec(pgs, false);
+ }
+ return code;
}
/* Fill the current path using a specified rule. */
diff --git a/base/gsparamx.c b/base/gsparamx.c
index 8ca19a5b..2009c53c 100644
--- a/base/gsparamx.c
+++ b/base/gsparamx.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -144,7 +144,12 @@ param_list_copy(gs_param_list *plto, gs_param_list *plfrom)
code = (code > 0 ? gs_note_error(gs_error_unknownerror) : code);
break;
}
- gs_param_list_set_persistent_keys(plto, key.persistent);
+ /* We used to use 'key.persistent' to determine whether we needed to copy the
+ * key (by setting persistent_keys in the param list to false), but that isn't
+ * correct! We are going to use the heap buffer 'string_key', not the original
+ * key, and since that's on the heap it is NOT persistent....
+ */
+ gs_param_list_set_persistent_keys(plto, false);
switch (value.type) {
case gs_param_type_dict:
coll_type = gs_param_collection_dict_any;
diff --git a/base/gspath1.c b/base/gspath1.c
index e9b91b06..cc56cb1d 100644
--- a/base/gspath1.c
+++ b/base/gspath1.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -219,6 +219,9 @@ gs_gstate_arc_add(gx_path * ppath, gs_gstate * pgs, bool clockwise,
ang2 += 180;
ar = -ar;
}
+ if (ang1 > (max_int - 360) || ang2 > (max_int - 360))
+ return_error(gs_error_limitcheck);
+
arc.radius = ar;
arc.action = (add_line ? arc_lineto : arc_moveto);
arc.notes = sn_none;
@@ -228,8 +231,9 @@ gs_gstate_arc_add(gx_path * ppath, gs_gstate * pgs, bool clockwise,
arc.p3.x = axc + ar * arc.sincos.cos;
arc.p3.y = ayc + ar * arc.sincos.sin;
if (clockwise) {
- while (ang1 < ang2)
- ang2 -= 360;
+ if (ang1 < ang2) {
+ ang2 -= ceil((ang2 - ang1) / 360) * 360;
+ }
if (ang2 < 0) {
double adjust = ceil(-ang2 / 360) * 360;
@@ -258,8 +262,9 @@ gs_gstate_arc_add(gx_path * ppath, gs_gstate * pgs, bool clockwise,
arc.notes = sn_not_first;
}
} else {
- while (ang2 < ang1)
- ang2 += 360;
+ if (ang2 < ang1) {
+ ang2 += ceil((ang1 - ang2) / 360) * 360;
+ }
if (ang1 < 0) {
double adjust = ceil(-ang1 / 360) * 360;
diff --git a/base/gsptype1.c b/base/gsptype1.c
index 28a88d02..2e032716 100644
--- a/base/gsptype1.c
+++ b/base/gsptype1.c
@@ -227,13 +227,14 @@ gs_pattern1_make_pattern(gs_client_color * pcc,
* losing content. */
inst.size.x = (int)floor(bbw+0.5);
inst.size.y = (int)floor(bbh+0.5);
- /* Ensure we never round down to 0. */
- if (bbw > 0 && inst.size.x == 0)
- inst.size.x = 1;
- if (bbh > 0 && inst.size.y == 0)
- inst.size.y = 1;
}
+ /* Ensure we never round down to 0. Or below zero (bug 705768). */
+ if (inst.size.x <= 0)
+ inst.size.x = bbw > 0 ? 1 : 0;
+ if (inst.size.y <= 0)
+ inst.size.y = bbh > 0 ? 1 : 0;
+
/* After compute_inst_matrix above, we are guaranteed that
* inst.step_matrix.xx > 0 and inst.step_matrix.yy > 0.
* Similarly, we are guaranteed that inst.size.x >= 0 and
@@ -1615,10 +1616,10 @@ gx_pattern_cache_lookup(gx_device_color * pdevc, const gs_gstate * pgs,
return true;
}
if (pcache != 0) {
- gx_color_tile *ctile = &pcache->tiles[id % pcache->num_tiles];
+ gx_color_tile *ctile = gx_pattern_cache_find_tile_for_id(pcache, id);
bool internal_accum = true;
if (pgs->have_pattern_streams) {
- int code = dev_proc(dev, dev_spec_op)(dev, gxdso_pattern_load, NULL, id);
+ int code = dev_proc(dev, dev_spec_op)(dev, gxdso_pattern_load, &id, sizeof(gx_bitmap_id));
internal_accum = (code == 0);
if (code < 0)
return false;
@@ -1960,7 +1961,7 @@ gx_dc_pattern_write(
Just write the tile id. */
gs_id id = ptile->id; /* Ensure sizeof(gs_id). */
if_debug2m('v', dev->memory,
- "[v*] Writing trans tile ID into clist, uid = %ld id = %ld \n",
+ "[v*] Writing trans tile ID into clist, uid = %ld id = %u \n",
ptile->uid.id, ptile->id);
memcpy(dp, &ptile->id, sizeof(id));
*psize = sizeof(gs_id);
@@ -1972,7 +1973,7 @@ gx_dc_pattern_write(
the clist */
if (ptile->ttrans != NULL) {
if_debug2m('v', dev->memory,
- "[v*] Writing trans tile into clist, uid = %ld id = %ld \n",
+ "[v*] Writing trans tile into clist, uid = %ld id = %u \n",
ptile->uid.id, ptile->id);
return gx_dc_pattern_trans_write_raster(ptile, offset, data, psize);
}
@@ -2286,7 +2287,7 @@ gx_dc_pattern_read(
ptile->ttrans->deep = deep;
pdevc->type = &gx_dc_pattern_trans;
if_debug2m('v', pgs->memory,
- "[v*] Reading trans tile from clist into cache, uid = %ld id = %ld \n",
+ "[v*] Reading trans tile from clist into cache, uid = %ld id = %u \n",
ptile->uid.id, ptile->id);
code = gx_dc_pattern_read_trans_buff(ptile, offset1, dp, left, mem);
diff --git a/base/gssprintf.c b/base/gssprintf.c
index 2b24580e..e2e1702c 100644
--- a/base/gssprintf.c
+++ b/base/gssprintf.c
@@ -1472,25 +1472,6 @@ int gs_snprintf(char *buf, int len,
return (cc == -1) ? (int)len - 1 : cc;
}
-int gs_sprintf(char *buf, const char *format, ...)
-{
- int cc;
- va_list ap;
- apr_vformatter_buff_t vbuff;
-
- /* save one byte for nul terminator */
- vbuff.curpos = buf;
- vbuff.endpos = buf + NUM_BUF_SIZE - 1;
-
- va_start(ap, format);
- cc = apr_vformatter(snprintf_flush, &vbuff, format, ap);
- va_end(ap);
- *vbuff.curpos = '\0';
-
- return cc;
-}
-
-
int gs_vsnprintf(char *buf, int len, const char *format,
va_list ap)
{
diff --git a/base/gssprintf.h b/base/gssprintf.h
index 0b5f6d3d..961a68b9 100644
--- a/base/gssprintf.h
+++ b/base/gssprintf.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -28,8 +28,5 @@ int
gs_vsprintf(char *zBuf, const char *zFormat, va_list ap);
int
-gs_sprintf(char *zBuf, const char *zFormat, ...);
-
-int
gs_sscanf(char *buf, const char *format, ...);
#endif
diff --git a/base/gstext.c b/base/gstext.c
index 306c476d..07cdb549 100644
--- a/base/gstext.c
+++ b/base/gstext.c
@@ -324,34 +324,8 @@ gs_text_begin(gs_gstate * pgs, const gs_text_params_t * text,
/* Processing a text object operation */
ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
- if (black_text && pgs->black_text_state == NULL) {
- gs_color_space *pcs_curr = gs_currentcolorspace_inline(pgs);
- gs_color_space *pcs_alt = gs_swappedcolorspace_inline(pgs);
-
- pgs->black_text_state = gsicc_blacktext_state_new(pgs->memory);
- if (pgs->black_text_state == NULL)
- return gs_error_VMerror;
-
- rc_increment_cs(pcs_curr);
- rc_increment_cs(pcs_alt);
- pgs->black_text_state->pcs[0] = pcs_curr;
- pgs->black_text_state->pcs[1] = pcs_alt;
-
- pgs->black_text_state->pcc[0] = pgs->color[0].ccolor;
- cs_adjust_color_count(pgs, 1); /* The set_gray will do a decrement */
- pgs->black_text_state->value[0] = pgs->color[0].ccolor->paint.values[0];
- gs_setgray(pgs, 0.0);
-
- gs_swapcolors_quick(pgs);
-
- pgs->black_text_state->pcc[1] = pgs->color[0].ccolor;
- cs_adjust_color_count(pgs, 1);
- pgs->black_text_state->value[1] = pgs->color[0].ccolor->paint.values[0];
- gs_setgray(pgs, 0.0);
-
- gs_swapcolors_quick(pgs);
-
- pgs->black_text_state->is_fill = pgs->is_fill_color;
+ if (black_text && pgs->black_textvec_state == NULL) {
+ gsicc_setup_blacktextvec(pgs, (gx_device *)pgs->device, true);
}
code = gx_set_dev_color(pgs);
@@ -405,7 +379,7 @@ gs_text_begin(gs_gstate * pgs, const gs_text_params_t * text,
/* we need to know if we are doing a highlevel device.
Also we need to know if we are doing any stroke
or stroke fill operations. This determines when
- we need to release the black_text_state structure. */
+ we need to release the black_textvec_state structure. */
if (code >= 0 && *ppte != NULL) {
if (black_text) {
if (!((*ppte)->k_text_release)) {
@@ -821,8 +795,8 @@ rc_free_text_enum(gs_memory_t * mem, void *obj, client_name_t cname)
void
gs_text_release(gs_gstate *pgs, gs_text_enum_t * pte, client_name_t cname)
{
- if (pgs != NULL && pgs->black_text_state != NULL)
- gsicc_restore_black_text(pgs);
+ if (pgs != NULL && pgs->black_textvec_state != NULL)
+ gsicc_restore_blacktextvec(pgs, true);
rc_decrement_only(pte, cname);
}
diff --git a/base/gstiffio.c b/base/gstiffio.c
index bb2ce85e..919ffab6 100644
--- a/base/gstiffio.c
+++ b/base/gstiffio.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -170,6 +170,12 @@ tiff_from_filep(gx_device_printer *dev, const char *name, gp_file *filep, int b
return t;
}
+int tiff_filename_from_tiff(TIFF *t, char **name)
+{
+ *name = (char *)TIFFFileName(t);
+ return 0;
+}
+
static void
gs_tifsWarningHandlerEx(thandle_t client_data, const char* module, const char* fmt, va_list ap)
{
diff --git a/base/gstiffio.h b/base/gstiffio.h
index 405e0fac..9ab9bfad 100644
--- a/base/gstiffio.h
+++ b/base/gstiffio.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -23,5 +23,6 @@
TIFF *
tiff_from_filep(gx_device_printer *dev, const char *name, gp_file *filep, int big_endian, bool usebigtiff);
void tiff_set_handlers (void);
+int tiff_filename_from_tiff(TIFF *t, char **name);
#endif /* gstiffio_INCLUDED */
diff --git a/base/gstrans.c b/base/gstrans.c
index 42207f99..d57b02ee 100644
--- a/base/gstrans.c
+++ b/base/gstrans.c
@@ -222,6 +222,7 @@ gs_begin_transparency_group(gs_gstate *pgs,
params.blend_mode = pgs->blend_mode;
params.text_group = ptgp->text_group;
params.shade_group = ptgp->shade_group;
+ params.ColorSpace = ptgp->ColorSpace;
/* This function is called during the c-list writer side.
Store some information so that we know what the color space is
so that we can adjust according later during the clist reader.
@@ -560,6 +561,7 @@ gs_begin_transparency_mask(gs_gstate * pgs,
params.subtype = ptmp->subtype;
params.Background_components = ptmp->Background_components;
memcpy(params.Background, ptmp->Background, l);
+ params.ColorSpace = ptmp->ColorSpace;
params.Matte_components = ptmp->Matte_components;
memcpy(params.Matte, ptmp->Matte, m);
params.GrayBackground = ptmp->GrayBackground;
@@ -820,16 +822,27 @@ gs_push_pdf14trans_device(gs_gstate * pgs, bool is_pattern, bool retain,
params.overprint_sim_push = true;
}
- /* If we have an NCLR ICC profile, the extra spot colorants do not
- get included in the transparency buffers. This is also true
- for any extra colorant names listed, which go beyond the profile.
- Finally, we could have a CMYK profile with colorants listed, that
- go beyond CMYK. To detect, simply look at dev_profile->spotnames */
+ /* If we have an NCLR ICC profile, the extra spot colorants do
+ * get included in the transparency buffers. Trying to avoid
+ * including them became a rube goldberg mess in terms of knowing
+ * which colorants are on the page vs what has been specified and
+ * any aliasing between these two. Just too many things to go wrong.
+ * So we allocate all and carry around. If you are doing special
+ * spot handling with transparency this is the cost. */
+
if (dev_profile->spotnames != NULL && dev_profile->spotnames->count > 4) {
- /* Making an assumption here, that list is CMYK + extra. */
- int delta = dev_profile->spotnames->count - 4;
- params.num_spot_colors_int -= delta;
- params.num_spot_colors -= delta;
+ /* Making an assumption here, that list is CMYK + extra.
+ An error should have been thrown by the target device if not. */
+ int avail_page_spots = pgs->device->color_info.num_components - 4;
+ params.num_spot_colors_int = avail_page_spots;
+ params.num_spot_colors = avail_page_spots;
+
+ /* This should not be possible, but lets be safe. We can't have a negative
+ number of source spots to carry forward, so apply threshold. */
+ if (params.num_spot_colors_int < 0)
+ params.num_spot_colors_int = 0;
+ if (params.num_spot_colors < 0)
+ params.num_spot_colors = 0;
}
/* If we happen to be in a situation where we are going out to a device
diff --git a/base/gstrans.h b/base/gstrans.h
index d7bf1e0d..65bf017d 100644
--- a/base/gstrans.h
+++ b/base/gstrans.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -107,6 +107,7 @@ struct gs_pdf14trans_params_s {
bool function_is_identity;
int Background_components;
float Background[GS_CLIENT_COLOR_MAX_COMPONENTS];
+ const gs_color_space *ColorSpace;
int Matte_components;
float Matte[GS_CLIENT_COLOR_MAX_COMPONENTS];
float GrayBackground; /* This is used to determine if the
diff --git a/base/gstype2.c b/base/gstype2.c
index a4a44335..e6d70f13 100644
--- a/base/gstype2.c
+++ b/base/gstype2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -49,6 +49,7 @@
BEGIN\
if ( pcis->init_done < 0 )\
{ ipsp->ip = cip, ipsp->dstate = state;\
+ ipsp->ip_end = endp;\
return type2_sbw(pcis, csp, cstack, ipsp, explicit_width);\
}\
END
@@ -130,7 +131,7 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
cs_ptr csp;
#define clear CLEAR_CSTACK(cstack, csp)
ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
- register const byte *cip;
+ register const byte *cip, *endp = NULL;
register crypt_state state;
register int c;
cs_ptr ap;
@@ -176,9 +177,15 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
cip = pgd->bits.data;
if (cip == 0)
return (gs_note_error(gs_error_invalidfont));
+ endp = cip + pgd->bits.size;
goto call;
for (;;) {
- uint c0 = *cip++;
+ uint c0;
+
+ if (endp != NULL && cip > endp)
+ return_error(gs_error_invalidfont);
+
+ c0 = *cip++;
charstring_next(c0, state, c, encrypted);
if (c >= c_num1) {
@@ -223,6 +230,7 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
return_error(gs_error_invalidfont);
case c_callsubr:
if (CS_CHECK_CSTACK_BOUNDS(csp, cstack)) {
+ CS_CHECK_IPSTACK(&(ipsp[1]), pcis->ipstack);
c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
code = pdata->procs.subr_data
(pfont, c, false, &ipsp[1].cs_data);
@@ -241,6 +249,7 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
cont: if (ipsp < pcis->ipstack || ipsp->ip == 0)
return (gs_note_error(gs_error_invalidfont));
cip = ipsp->ip;
+ endp = ipsp->ip_end;
state = ipsp->dstate;
continue;
case c_undoc15:
@@ -465,6 +474,7 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
}
if_debug0m('1', pfont->memory, "\n");
ipsp->ip = cip;
+ ipsp->ip_end = endp;
ipsp->dstate = state;
if (c == c2_cntrmask) {
/****** NYI ******/
@@ -556,6 +566,7 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
continue;
case c2_callgsubr:
if (CS_CHECK_CSTACK_BOUNDS(csp, cstack)) {
+ CS_CHECK_IPSTACK(&(ipsp[1]), pcis->ipstack);
c = fixed2int_var(*csp) + pdata->gsubrNumberBias;
code = pdata->procs.subr_data
(pfont, c, true, &ipsp[1].cs_data);
@@ -573,8 +584,10 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
}
--csp;
ipsp->ip = cip, ipsp->dstate = state;
+ ipsp->ip_end = endp;
++ipsp;
cip = ipsp->cs_data.bits.data;
+ endp = cip + ipsp->cs_data.bits.size;
call:
state = crypt_charstring_seed;
if (encrypted) {
@@ -688,6 +701,8 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
csp -= 3;
break;
case ce2_neg:
+ if (!CS_CHECK_CSTACK_BOUNDS(csp, cstack))
+ return_error(gs_error_invalidfont);
*csp = -*csp;
break;
case ce2_eq:
diff --git a/base/gstype42.c b/base/gstype42.c
index 3cc92213..5ef1c227 100644
--- a/base/gstype42.c
+++ b/base/gstype42.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -68,6 +68,8 @@ font_proc_font_info(gs_truetype_font_info); /* Type check. */
#define PUTU16(p, n, offs) {(p + offs)[0] = n >> 8 & 255; (p + offs)[1] = n & 255;}
+static byte const ver10[4] = {0x00, 0x01, 0x00, 0x00};
+static byte const ver20[4] = {0x00, 0x02, 0x00, 0x00};
/* ---------------- Font level ---------------- */
@@ -207,7 +209,14 @@ gs_type42_font_init(gs_font_type42 * pfont, int subfontID)
if (!memcmp(tab, "cmap", 4))
pfont->data.cmap = offset;
else if (!memcmp(tab, "post", 4)) {
- pfont->data.post_offset = offset;
+ byte ver[4];
+ READ_SFNTS(pfont, offset, 4, ver);
+ if (memcmp(ver, ver10, 4) == 0 || memcmp(ver, ver20, 4) == 0) {
+ pfont->data.post_offset = offset;
+ }
+ else {
+ pfont->data.post_offset = 0;
+ }
}
else if (!memcmp(tab, "glyf", 4)) {
pfont->data.glyf = offset;
@@ -269,8 +278,13 @@ gs_type42_font_init(gs_font_type42 * pfont, int subfontID)
pfont->data.os2_offset = offset;
}
}
- loca_size >>= pfont->data.indexToLocFormat + 1;
+ loca_size >>= (pfont->data.indexToLocFormat == 0 ? 1 : 2);
pfont->data.numGlyphs = loca_size - 1;
+ if (pfont->data.numGlyphs > 65535) {
+ pfont->data.numGlyphs = 65535;
+ loca_size = (65536 << (pfont->data.indexToLocFormat == 0 ? 1 : 2));
+ }
+
if (pfont->data.numGlyphs > (int)pfont->data.trueNumGlyphs) {
/* pfont->key_name.chars is ASCIIZ due to copy_font_name. */
char buf[gs_font_name_max + 2];
@@ -403,8 +417,10 @@ gs_type42_font_init(gs_font_type42 * pfont, int subfontID)
qsort(psortary, loca_size, sizeof(gs_type42_font_init_sort_t), gs_type42_font_init_compare);
while (num_valid_loca_elm > 0 && psortary[num_valid_loca_elm - 1].glyph_offset > glyph_size)
num_valid_loca_elm --;
- if (0 == num_valid_loca_elm)
+ if (0 == num_valid_loca_elm) {
+ gs_free_object(pfont->memory, psortary, "gs_type42_font_init(sort loca)");
return_error(gs_error_invalidfont);
+ }
for (i = num_valid_loca_elm; i--;) {
long old_length;
@@ -754,8 +770,6 @@ gs_type42_find_post_name(gs_font_type42 * pfont, gs_glyph glyph, gs_string *gnam
if (pfont->FontType == ft_TrueType) {
if (pfont->data.post_offset != 0) {
byte ver[4];
- byte const ver10[4] = {0x00, 0x01, 0x00, 0x00};
- byte const ver20[4] = {0x00, 0x02, 0x00, 0x00};
READ_SFNTS(pfont, pfont->data.post_offset, 4, ver);
if (!memcmp(ver, ver10, 4)){
@@ -801,6 +815,9 @@ gs_type42_find_post_name(gs_font_type42 * pfont, gs_glyph glyph, gs_string *gnam
}
}
}
+ else {
+ code2 = gs_error_invalidfont;
+ }
}
}
else
@@ -1283,8 +1300,13 @@ parse_pieces(gs_font_type42 *pfont, gs_glyph glyph, gs_glyph *pieces,
memset(&mat, 0, sizeof(mat)); /* arbitrary */
for (i = 0; flags & TT_CG_MORE_COMPONENTS; ++i) {
- if (pieces)
+ if (pieces) {
pieces[i] = U16(gdata + 2) + GS_MIN_GLYPH_INDEX;
+ if (U16(gdata + 2) > pfont->data.numGlyphs) {
+ *pnum_pieces = 0;
+ return_error(gs_error_invalidfont);
+ }
+ }
gs_type42_parse_component(&gdata, &flags, &mat, NULL, pfont, &mat);
}
*pnum_pieces = i;
diff --git a/base/gxblend.c b/base/gxblend.c
index bd36994b..afb5ea94 100644
--- a/base/gxblend.c
+++ b/base/gxblend.c
@@ -2716,7 +2716,7 @@ do_dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
dlprintf2("%02d)%s.pam\n",global_index,filename);dflush();
gs_snprintf(full_file_name,sizeof(full_file_name),"%02d)%s.pam",global_index,filename);
fid = gp_fopen(mem,full_file_name,"wb");
- fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 2\nMAXVAL %d\nTUPLTYPE GRAYSCALE_ALPHA\nENDHDR\n",
+ gp_fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 2\nMAXVAL %d\nTUPLTYPE GRAYSCALE_ALPHA\nENDHDR\n",
width, num_rows, deep ? 65535 : 255);
if (deep) {
for(y=0; y<num_rows; y++)
@@ -2737,7 +2737,7 @@ do_dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
dlprintf2("%02d)%s_shape.pgm\n",global_index,filename);dflush();
gs_snprintf(full_file_name,sizeof(full_file_name),"%02d)%s_shape.pgm",global_index,filename);
fid = gp_fopen(mem,full_file_name,"wb");
- fprintf(fid, "P5\n%d %d %d\n",
+ gp_fprintf(fid, "P5\n%d %d %d\n",
width, num_rows, deep ? 65535 : 255);
if (deep) {
for(y=0; y<num_rows; y++)
@@ -2759,7 +2759,7 @@ do_dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
dprintf2("%02d)%s.pam\n",global_index,filename);dflush();
gs_snprintf(full_file_name,sizeof(full_file_name),"%02d)%s.pam",global_index,filename);
fid = gp_fopen(mem,full_file_name,"wb");
- fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL %d\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
+ gp_fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL %d\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
width, num_rows, deep ? 65535 : 255);
if (deep) {
for(y=0; y<num_rows; y++)
@@ -2779,7 +2779,7 @@ do_dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
if (n_chan > 4) {
gs_snprintf(full_file_name,sizeof(full_file_name),"%02d)%s_shape.pgm",global_index,filename);
fid = gp_fopen(mem,full_file_name,"wb");
- fprintf(fid, "P5\n%d %d %d\n",
+ gp_fprintf(fid, "P5\n%d %d %d\n",
width, num_rows, deep ? 65535 : 255);
if (deep) {
for(y=0; y<num_rows; y++)
@@ -2798,7 +2798,7 @@ do_dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
if (n_chan == 6) {
gs_snprintf(full_file_name,sizeof(full_file_name),"%02d)%s_tags.pgm",global_index,filename);
fid = gp_fopen(mem, full_file_name,"wb");
- fprintf(fid, "P5\n%d %d 255\n", width, num_rows);
+ gp_fprintf(fid, "P5\n%d %d 255\n", width, num_rows);
if (deep) {
for(y=0; y<num_rows; y++)
for(x=0; x<width; x++)
diff --git a/base/gxchar.c b/base/gxchar.c
index 1c534ccb..e3ffa83e 100644
--- a/base/gxchar.c
+++ b/base/gxchar.c
@@ -168,12 +168,19 @@ gx_default_text_begin(gx_device * dev, gs_gstate * pgs1,
if (dev_null == 0)
return_error(gs_error_VMerror);
+
+ /* Set up a null device that forwards xfont requests properly. */
+ /* We have to set the device up here, so the contents are
+ initialised, and safe to free in the event of an error.
+ */
+ gs_make_null_device(dev_null, gs_currentdevice_inline(pgs), mem);
+
/* Do an extra gsave and suppress output */
- if ((code = gs_gsave(pgs)) < 0)
+ if ((code = gs_gsave(pgs)) < 0) {
+ gs_free_object(mem, dev_null, "gx_default_text_begin");
return code;
+ }
penum->level = pgs->level; /* for level check in show_update */
- /* Set up a null device that forwards xfont requests properly. */
- gs_make_null_device(dev_null, gs_currentdevice_inline(pgs), mem);
pgs->ctm_default_set = false;
penum->dev_null = dev_null;
/* Retain this device, since it is referenced from the enumerator. */
diff --git a/base/gxcldev.h b/base/gxcldev.h
index 66020503..708b1779 100644
--- a/base/gxcldev.h
+++ b/base/gxcldev.h
@@ -204,7 +204,7 @@ typedef enum {
cmd_op_path = 0xf0, /* (see below) */
cmd_opv_fill = 0xf0,
cmd_opv_rgapto = 0xf1, /* dx%, dy% */
- /* UNUSED 0xf2 */
+ cmd_opv_lock_pattern = 0xf2, /* lock, id */
cmd_opv_eofill = 0xf3,
cmd_opv_fill_stroke = 0xf4,
cmd_opv_eofill_stroke = 0xf5,
@@ -220,12 +220,12 @@ typedef enum {
/* UNUSED 0xff */
#define cmd_path_op_name_strings\
- "fill", "rgapto", "?f2?", "eofill",\
+ "fill", "rgapto", "lock_pattern", "eofill",\
"fill_stroke", "eofill_stroke", "stroke", "?f7?",\
"?f8?", "polyfill", "?fa?", "?fb?",\
"fill_trapezoid", "?fd?", "?fe?", "?ff?"
-/* unused cmd_op values: 0xf2, 0xf7, 0xf8, 0xfa, 0xfb, 0xfd, 0xfe, 0xff */
+/* unused cmd_op values: 0xf7, 0xf8, 0xfa, 0xfb, 0xfd, 0xfe, 0xff */
} gx_cmd_op;
#define cmd_op_name_strings\
diff --git a/base/gxclimag.c b/base/gxclimag.c
index 4f99e481..c1996569 100644
--- a/base/gxclimag.c
+++ b/base/gxclimag.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -1885,6 +1885,17 @@ image_band_box(gx_device * dev, const clist_image_enum * pie, int y, int h,
return (pbox->p.x < pbox->q.x && pbox->p.y < pbox->q.y);
}
+inline static bool
+icc_info_notequal(clist_icc_color_t info1, clist_icc_color_t info2)
+{
+ if (info1.data_cs != info2.data_cs || info1.default_match != info2.default_match ||
+ info1.icc_num_components != info2.icc_num_components || info1.is_lab != info2.is_lab ||
+ info1.icc_hash != info2.icc_hash)
+ return true;
+ else
+ return false;
+}
+
/* Determine which image-related properties are unknown */
static uint /* mask of unknown properties(see pcls->known) */
clist_image_unknowns(gx_device *dev, const clist_image_enum *pie)
@@ -1914,10 +1925,12 @@ clist_image_unknowns(gx_device *dev, const clist_image_enum *pie)
cdev->color_space.space = 0; /* for GC */
} else { /* not masked */
if (cdev->color_space.id != pie->color_space.id ||
- cdev->color_space.space != pie->color_space.space) {
+ cdev->color_space.space != pie->color_space.space ||
+ icc_info_notequal(cdev->color_space.icc_info, pie->color_space.icc_info)) {
unknown |= color_space_known;
cdev->color_space.space = pie->color_space.space;
cdev->color_space = pie->color_space;
+ memcpy(&(cdev->color_space.icc_info), &(pie->color_space.icc_info), sizeof(clist_icc_color_t));
}
}
if (cdev->gs_gstate.fill_adjust.x != pgs->fill_adjust.x ||
diff --git a/base/gxclipm.c b/base/gxclipm.c
index 627f28a5..b4cd6555 100644
--- a/base/gxclipm.c
+++ b/base/gxclipm.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -77,6 +77,7 @@ mask_clip_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, copy_alpha_hl_color, mask_clip_copy_alpha_hl_color);
set_dev_proc(dev, transform_pixel_region, gx_default_transform_pixel_region);
set_dev_proc(dev, fill_stroke_path, gx_forward_fill_stroke_path);
+ set_dev_proc(dev, lock_pattern, gx_forward_lock_pattern);
/* Ideally these defaults would be set up automatically for us. */
set_dev_proc(dev, open_device, gx_default_open_device);
diff --git a/base/gxclist.c b/base/gxclist.c
index 3b778f53..488875ba 100644
--- a/base/gxclist.c
+++ b/base/gxclist.c
@@ -174,6 +174,7 @@ clist_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, copy_alpha_hl_color, clist_copy_alpha_hl_color);
set_dev_proc(dev, process_page, clist_process_page);
set_dev_proc(dev, fill_stroke_path, clist_fill_stroke_path);
+ set_dev_proc(dev, lock_pattern, clist_lock_pattern);
}
/*------------------- Choose the implementation -----------------------
@@ -708,6 +709,7 @@ clist_open(gx_device *dev)
errxit:
/* prevent leak */
gs_free_object(cdev->memory->non_gc_memory, cdev->cache_chunk, "free tile cache for clist");
+ dev->is_open = save_is_open;
cdev->cache_chunk = NULL;
return code;
}
@@ -1543,5 +1545,7 @@ open_c:
pdev->buf = NULL;
}
}
+ if (code < 0)
+ pdev->is_open = save_is_open;
return code;
}
diff --git a/base/gxclpath.c b/base/gxclpath.c
index c202178c..83cb44e0 100644
--- a/base/gxclpath.c
+++ b/base/gxclpath.c
@@ -927,6 +927,28 @@ clist_fill_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath,
return 0;
}
+int clist_lock_pattern(gx_device * pdev, gs_gstate * pgs, gs_id pattern, int lock)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)pdev)->writer;
+ byte *dp;
+ int code;
+
+ /* We need to both lock now, and ensure that we lock on reading this back. */
+ code = gx_pattern_cache_entry_set_lock(pgs, pattern, lock);
+ if (code < 0)
+ return code;
+
+ code = set_cmd_put_all_op(&dp, cdev, cmd_opv_lock_pattern,
+ 1 + 1 + sizeof(pattern));
+
+ if (code < 0)
+ return code;
+ dp[1] = lock;
+ memcpy(dp+2, &pattern, sizeof(pattern));
+ return 0;
+}
+
int
clist_fill_stroke_path(gx_device * pdev, const gs_gstate * pgs,
gx_path * ppath,
@@ -1563,6 +1585,47 @@ cmd_put_segment(cmd_segment_writer * psw, byte op,
#define cmd_put_rlineto(psw, operands, notes)\
cmd_put_segment(psw, cmd_opv_rlineto, operands, notes)
+
+/* Bug 693235 shows a problem with a 'large' stroke, that
+ * extends from almost the minimum extent permissible
+ * to almost the positive extent permissible. When we band
+ * that, and play it back, we subtract the y offset of the band
+ * from it, and that causes a very negative number to tip over
+ * to being a very positive number.
+ *
+ * To avoid this, we spot 'far out' entries in the path, and
+ * reduce them to being 'less far out'.
+ *
+ * We pick 'far out' as being outside the central 1/4 of our
+ * 2d plane. This is far larger than is ever going to be used
+ * by a real device (famous last words!).
+ *
+ * We reduce the lines by moving to 1/4 of the way along them.
+ *
+ * If we only ever actually want to render the central 1/16 of
+ * the plane (which is still far more generous than we'd expect),
+ * the reduced lines should be suitably small not to overflow,
+ * and yet not be reduced so much that the reduction is ever visible.
+ *
+ * In practice this gives us a 4 million x 4 million maximum
+ * resolution.
+ */
+
+static int
+far_out(gs_fixed_point out)
+{
+ return (out.y >= max_fixed/2 || out.y <= -(max_fixed/2) || out.x >= max_fixed/2 || out.x <= -(max_fixed/2));
+}
+
+static void
+reduce_line(fixed *m0, fixed *m1, fixed x0, fixed y0, fixed x1, fixed y1)
+{
+ /* We want to find m0, m1, 1/4 of the way from x0, y0 to x1, y1. */
+ /* Sacrifice 2 bits of accuracy to avoid overflow. */
+ *m0 = (x0/4) + 3*(x1/4);
+ *m1 = (y0/4) + 3*(y1/4);
+}
+
/*
* Write a path. We go to a lot of trouble to omit segments that are
* entirely outside the band.
@@ -1716,6 +1779,20 @@ cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls,
}
/* If we skipped any segments, put out a moveto/lineto. */
if (side && ((open < 0) || (px != out.x || py != out.y || first_point()))) {
+ if (far_out(out)) {
+ /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */
+ if (open >= 0) {
+ fixed mid[2];
+ fixed m0, m1;
+ reduce_line(&m0, &m1, out.x, out.y, px, py);
+ mid[0] = m0 - px, mid[1] = m1 - py;
+ code = cmd_put_rlineto(&writer, mid, out_notes);
+ if (code < 0)
+ return code;
+ px = m0, py = m1;
+ }
+ reduce_line(&out.x, &out.y, out.x, out.y, A, B);
+ }
C = out.x - px, D = out.y - py;
if (open < 0) {
first = out;
@@ -1758,6 +1835,20 @@ cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls,
}
/* If we skipped any segments, put out a moveto/lineto. */
if (side && ((open < 0) || (px != out.x || py != out.y || first_point()))) {
+ if (far_out(out)) {
+ /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */
+ if (open >= 0) {
+ fixed mid[2];
+ fixed m0, m1;
+ reduce_line(&m0, &m1, out.x, out.y, px, py);
+ mid[0] = m0 - px, mid[1] = m1 - py;
+ code = cmd_put_rlineto(&writer, mid, out_notes);
+ if (code < 0)
+ return code;
+ px = m0, py = m1;
+ }
+ reduce_line(&out.x, &out.y, out.x, out.y, A, B);
+ }
C = out.x - px, D = out.y - py;
if (open < 0) {
first = out;
@@ -1805,6 +1896,20 @@ cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls,
/* we skipped any segments at the beginning of the path. */
close:if (side != start_side) { /* If we skipped any segments, put out a moveto/lineto. */
if (side && (px != out.x || py != out.y || first_point())) {
+ if (far_out(out)) {
+ /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */
+ if (open >= 0) {
+ fixed mid[2];
+ fixed m0, m1;
+ reduce_line(&m0, &m1, out.x, out.y, px, py);
+ mid[0] = m0 - px, mid[1] = m1 - py;
+ code = cmd_put_rlineto(&writer, mid, out_notes);
+ if (code < 0)
+ return code;
+ px = m0, py = m1;
+ }
+ reduce_line(&out.x, &out.y, out.x, out.y, A, B);
+ }
C = out.x - px, D = out.y - py;
code = cmd_put_rlineto(&writer, &C, out_notes);
if (code < 0)
diff --git a/base/gxclpath.h b/base/gxclpath.h
index c334222c..ccf12353 100644
--- a/base/gxclpath.h
+++ b/base/gxclpath.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -132,6 +132,7 @@ extern const char *cmd_extend_op_names[256];
dev_proc_fill_path(clist_fill_path);
dev_proc_stroke_path(clist_stroke_path);
dev_proc_fill_stroke_path(clist_fill_stroke_path);
+dev_proc_lock_pattern(clist_lock_pattern);
dev_proc_fill_parallelogram(clist_fill_parallelogram);
dev_proc_fill_triangle(clist_fill_triangle);
diff --git a/base/gxclrast.c b/base/gxclrast.c
index c38faa49..d3049ebc 100644
--- a/base/gxclrast.c
+++ b/base/gxclrast.c
@@ -747,9 +747,9 @@ in: /* Initialize for a new page. */
op = *cbp++;
#ifdef DEBUG
if (gs_debug_c('L')) {
- long offset = (long)clist_file_offset(st, cbp - 1 - cbuf.data);
+ int64_t offset = clist_file_offset(st, cbp - 1 - cbuf.data);
- dmlprintf1(mem, "[L] %ld:", offset);
+ dmlprintf1(mem, "[L] %"PRIu64":", offset);
clist_debug_op(mem, cbp-1);
}
#endif
@@ -1146,6 +1146,8 @@ do_opv_set_bits:
cbp = cmd_read_data(&cbuf, plane_bits, 1, cbp);
if (width_bytes > 0 && state.rect.height > 0)
memset(plane_bits+1, *plane_bits, width_bytes * state.rect.height - 1);
+ if (pln == 0)
+ source = data_bits;
} else if (compression) { /* Decompress the image data. */
stream_cursor_read r;
@@ -2014,14 +2016,26 @@ idata: data_size = 0;
}
continue;
case cmd_op_path >> 4:
- {
+ if (op == cmd_opv_rgapto)
+ goto rgapto;
+ else if (op == cmd_opv_lock_pattern) {
+ gs_id id;
+ int lock = *cbp++;
+ cmd_get_value(id, cbp);
+ if_debug2m('L', mem, "id=0x%lx, lock=%d\n", id, lock);
+ /* We currently lock the pattern in all the bands, even in ones
+ * where we haven't used the pattern. This can cause the following
+ * call to return with 'undefined' because the pattern is not
+ * found. Just swallow this error and continue. */
+ code = gx_pattern_cache_entry_set_lock(&gs_gstate, id, lock);
+ if (code == gs_error_undefined)
+ code = 0;
+ if (code < 0)
+ goto out;
+ continue;
+ } else {
gx_path fpath;
- gx_path *ppath;
-
- if (op == cmd_opv_rgapto)
- goto rgapto;
-
- ppath = &path;
+ gx_path *ppath = &path;
if_debug0m('L', mem, "\n");
/* if in clip, flatten path first */
@@ -2059,26 +2073,6 @@ idata: data_size = 0;
code = (*dev_proc(tdev, fill_stroke_path))(tdev, &gs_gstate, ppath,
&fill_params, &fill_color,
&stroke_params, &stroke_color, pcpath);
- /* if the color is a pattern, it may have had the "is_locked" flag set */
- /* clear those now (see do_fill_stroke). */
- if (gx_dc_is_pattern1_color(&stroke_color)) {
- if (stroke_color.colors.pattern.p_tile != NULL) {
- gs_id id = stroke_color.colors.pattern.p_tile->id;
-
- code = gx_pattern_cache_entry_set_lock(&gs_gstate, id, false);
- if (code < 0)
- return code; /* unlock failed -- should not happen */
- }
- }
- if (gx_dc_is_pattern1_color(&fill_color)) {
- if (fill_color.colors.pattern.p_tile != NULL) {
- gs_id id = fill_color.colors.pattern.p_tile->id;
-
- code = gx_pattern_cache_entry_set_lock(&gs_gstate, id, false);
- if (code < 0)
- return code; /* unlock failed -- should not happen */
- }
- }
break;
case cmd_opv_stroke:
stroke_params.flatness = gs_gstate.flatness;
diff --git a/base/gxclread.c b/base/gxclread.c
index 03945e81..b17d5a1e 100644
--- a/base/gxclread.c
+++ b/base/gxclread.c
@@ -294,6 +294,12 @@ buffer_segment_index(const stream_band_read_state *ss, uint buffer_offset, uint
return i;
}
}
+ /* Now cope with the case where we've read exactly to the end of the buffer.
+ * There might be more data still to come. */
+ if (buffer_offset == offset) {
+ *poffset0 = offset0;
+ return i-1;
+ }
#ifdef EXTRA_OFFSET_MAP_DEBUGGING
dmlprintf1(ss->local_memory, "buffer_segment_index fail: buffer_offset=%d not found\n", buffer_offset);
exit(1);
diff --git a/base/gxclthrd.c b/base/gxclthrd.c
index 6af40a7f..c12af70c 100644
--- a/base/gxclthrd.c
+++ b/base/gxclthrd.c
@@ -113,12 +113,15 @@ setup_device_and_mem_for_thread(gs_memory_t *chunk_base_mem, gx_device *dev, boo
* will spot the same profile being used, and treat it as a no-op. Otherwise it will try to find
* a profile with the 'special' name "OI_PROFILE" and throw an error.
*/
- if (!gscms_is_threadsafe() || (dev->icc_struct != NULL &&
- ((dev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE] != NULL &&
- strncmp(dev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE]->name,
- OI_PROFILE, strlen(OI_PROFILE)) == 0)
- || (dev->icc_struct->proof_profile != NULL &&
- strncmp(dev->icc_struct->proof_profile->name, OI_PROFILE, strlen(OI_PROFILE)) == 0)))) {
+#define DEV_PROFILE_IS(DEV, PROFILE, MATCH) \
+ ((DEV)->icc_struct != NULL &&\
+ (DEV)->icc_struct->PROFILE != NULL &&\
+ strcmp((DEV)->icc_struct->PROFILE->name, MATCH) == 0)
+
+ if (bg_print ||
+ !gscms_is_threadsafe() ||
+ DEV_PROFILE_IS(dev, device_profile[GS_DEFAULT_DEVICE_PROFILE], OI_PROFILE) ||
+ DEV_PROFILE_IS(dev, proof_profile, OI_PROFILE)) {
ndev->icc_struct = gsicc_new_device_profile_array(ndev);
if (!ndev->icc_struct) {
emprintf1(ndev->memory,
@@ -252,7 +255,7 @@ setup_device_and_mem_for_thread(gs_memory_t *chunk_base_mem, gx_device *dev, boo
}
rc_increment(*cachep);
ncdev->icc_cache_cl = *cachep;
- } else if ((ncdev->icc_cache_cl = gsicc_cache_new(thread_mem)) == NULL)
+ } else if ((ncdev->icc_cache_cl = gsicc_cache_new(thread_mem->thread_safe_memory)) == NULL)
goto out_cleanup;
}
if (bg_print) {
diff --git a/base/gxcmap.c b/base/gxcmap.c
index 067d18b7..bdf83cba 100644
--- a/base/gxcmap.c
+++ b/base/gxcmap.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -1361,6 +1361,11 @@ cmap_separation_halftoned(frac all, gx_device_color * pdc,
for (i = 0; i < pgs->color_component_map.num_colorants; i++)
cm_comps[i] = comp_value;
} else {
+ if (pgs->color_component_map.sep_type == SEP_NONE) {
+ color_set_null(pdc);
+ return;
+ }
+
/* map to the color model */
map_components_to_colorants(&all, &(pgs->color_component_map), cm_comps,
pgs->color_component_map.num_colorants);
@@ -1427,8 +1432,12 @@ cmap_separation_direct(frac all, gx_device_color * pdc, const gs_gstate * pgs,
if (des_profile->data_cs == gsCIELAB || des_profile->islab) {
use_rgb2dev_icc = true;
}
- }
- else {
+ } else {
+ if (pgs->color_component_map.sep_type == SEP_NONE) {
+ color_set_null(pdc);
+ return;
+ }
+
/* map to the color model */
map_components_to_colorants(&comp_value, &(pgs->color_component_map), cm_comps,
pgs->color_component_map.num_colorants);
@@ -1532,6 +1541,11 @@ cmap_devicen_halftoned(const frac * pcc,
cmm_dev_profile_t *dev_profile = NULL;
cmm_profile_t *des_profile = NULL;
+ if (pcs->params.device_n.all_none == true) {
+ color_set_null(pdc);
+ return;
+ }
+
dev_proc(dev, get_profile)(dev, &dev_profile);
gsicc_extract_profile(dev->graphics_type_tag,
dev_profile, &des_profile, &render_cond);
@@ -1579,6 +1593,11 @@ cmap_devicen_direct(const frac * pcc,
cmm_dev_profile_t *dev_profile = NULL;
cmm_profile_t *des_profile = NULL;
+ if (pcs->params.device_n.all_none == true) {
+ color_set_null(pdc);
+ return;
+ }
+
dev_proc(dev, get_profile)(dev, &dev_profile);
gsicc_extract_profile(dev->graphics_type_tag,
dev_profile, &des_profile, &render_cond);
diff --git a/base/gxcpath.c b/base/gxcpath.c
index 437b0654..c1c5453f 100644
--- a/base/gxcpath.c
+++ b/base/gxcpath.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -562,9 +562,11 @@ cpath_set_rectangle(gx_clip_path * pcpath, gs_fixed_rect * pbox)
int code = cpath_alloc_list(&pcpath->rect_list, pcpath->path.memory,
"gx_cpath_from_rectangle");
- rc_decrement(rlist, "gx_cpath_from_rectangle");
- if (code < 0)
+ if (code < 0) {
+ pcpath->rect_list = rlist;
return code;
+ }
+ rc_decrement(rlist, "gx_cpath_from_rectangle");
rlist = pcpath->rect_list;
}
cpath_init_rectangle(pcpath, pbox);
diff --git a/base/gxdevcli.h b/base/gxdevcli.h
index 2476ea33..5c9831b9 100644
--- a/base/gxdevcli.h
+++ b/base/gxdevcli.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -705,7 +705,6 @@ typedef struct gdev_nupcontrol_s {
typedef struct gdev_pagelist_s {
rc_header rc;
char *Pages;
- int PagesSize;
} gdev_pagelist;
#define dev_t_proc_initialize_device_procs(proc, dev_t)\
@@ -997,6 +996,16 @@ typedef enum FILTER_FLAGS {
#define dev_proc_fill_stroke_path(proc)\
dev_t_proc_fill_stroke_path(proc, gx_device)
+ /* Added in release 9.57 */
+
+#define dev_t_proc_lock_pattern(proc, dev_t)\
+ int proc(dev_t *dev,\
+ gs_gstate *pgs,\
+ gs_id pattern_id,\
+ int lock)
+#define dev_proc_lock_pattern(proc)\
+ dev_t_proc_lock_pattern(proc, gx_device)
+
/* Added in release 3.60 */
#define dev_t_proc_fill_mask(proc, dev_t)\
@@ -1508,6 +1517,7 @@ typedef struct {
dev_t_proc_process_page((*process_page), dev_t);\
dev_t_proc_transform_pixel_region((*transform_pixel_region), dev_t);\
dev_t_proc_fill_stroke_path((*fill_stroke_path), dev_t);\
+ dev_t_proc_lock_pattern((*lock_pattern), dev_t);\
}
/*
diff --git a/base/gxdevice.h b/base/gxdevice.h
index d9b0134d..99dd610e 100644
--- a/base/gxdevice.h
+++ b/base/gxdevice.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -318,6 +318,7 @@ 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_fill_stroke_path(gx_default_fill_stroke_path);
+dev_proc_lock_pattern(gx_default_lock_pattern);
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);
@@ -418,6 +419,7 @@ 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);
dev_proc_fill_stroke_path(gx_forward_fill_stroke_path);
+dev_proc_lock_pattern(gx_forward_lock_pattern);
void gx_forward_device_initialize_procs(gx_device *dev);
/* ---------------- Implementation utilities ---------------- */
@@ -665,13 +667,17 @@ int gs_is_pdf14trans_compositor(const gs_composite_t * pct);
#define subclass_common\
t_dev_proc_composite *saved_compositor_method;\
- gx_device_forward *forwarding_dev
+ gx_device_forward *forwarding_dev;\
+ gx_device *pre_composite_device;\
+ void (*saved_finalize_method)(gx_device *)
typedef int (t_dev_proc_composite) (gx_device *dev, gx_device **pcdev, const gs_composite_t *pcte, gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev);
typedef struct {
t_dev_proc_composite *saved_compositor_method;
gx_device_forward *forwarding_dev;
+ gx_device *pre_composite_device;
+ void (*saved_finalize_method)(gx_device *);
} generic_subclass_data;
int gx_copy_device_procs(gx_device *dest, const gx_device *src, const gx_device *prototype);
diff --git a/base/gxdevsop.h b/base/gxdevsop.h
index cfde902a..89eed4b3 100644
--- a/base/gxdevsop.h
+++ b/base/gxdevsop.h
@@ -353,7 +353,7 @@ enum {
gxdso_is_encoding_direct,
/* gxdso_event_info:
* data = dev_param_req_t
- * size = sizeof(dev_param-req_t
+ * size = sizeof(dev_param_req_t)
* Passes a single name in request->Param, naming the event which occurred.
* Used to send a warning to pdfwrite that some event has happened we want to know about.
* Currently this is used in pdf_font.ps to signal that a substittue font has been
@@ -450,6 +450,14 @@ enum {
*/
gxdso_overprintsim_state,
+ /* Get/Set information about the overprint op state.
+ * data = overprint op state to set (OP_STATE_{NONE, FILL, STROKE}) or -1
+ * for no change.
+ * size = 0
+ * Returns -1 if unhandled, otherwise the current state.
+ */
+ gxdso_overprint_op,
+
/* Add new gxdso_ keys above this. */
gxdso_pattern__LAST
};
diff --git a/base/gxdownscale.c b/base/gxdownscale.c
index 1f8138cb..8ed12267 100644
--- a/base/gxdownscale.c
+++ b/base/gxdownscale.c
@@ -2168,7 +2168,7 @@ static int
planar_skew_line(gx_downscale_liner *liner_, void *params_, int row)
{
liner_skew *liner = (liner_skew *)liner_;
- int code;
+ int code = 0;
gs_get_bits_params_t *params = (gs_get_bits_params_t *)params_;
int i;
diff --git a/base/gxfapi.h b/base/gxfapi.h
index 1ff8018f..f9ba46d3 100644
--- a/base/gxfapi.h
+++ b/base/gxfapi.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -200,6 +200,8 @@ struct gs_fapi_font_s
int (*serialize_tt_font) (gs_fapi_font *ff, void *buf, int buf_size);
+ int (*retrieve_tt_font) (gs_fapi_font *ff, void **buf, int *buf_size);
+
int (*get_charstring) (gs_fapi_font *ff, int index, byte *buf, ushort buf_length);
int (*get_charstring_name) (gs_fapi_font *ff, int index, byte *buf, ushort buf_length);
diff --git a/base/gxfill.c b/base/gxfill.c
index e33cb778..81b5ba50 100644
--- a/base/gxfill.c
+++ b/base/gxfill.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -670,6 +670,15 @@ gx_default_fill_path(gx_device * pdev, const gs_gstate * pgs,
return gx_general_fill_path(pdev, pgs, ppath, params, pdevc, pcpath);
}
+int
+gx_default_lock_pattern(gx_device *pdev,
+ gs_gstate *pgs,
+ gs_id pattern_id,
+ int lock)
+{
+ return gx_pattern_cache_entry_set_lock(pgs, pattern_id, lock);
+}
+
/*
* Fill/Stroke a path. This is the default implementation of the driver
* fill_path procedure.
diff --git a/base/gxgstate.h b/base/gxgstate.h
index b1ce6a08..c199a958 100644
--- a/base/gxgstate.h
+++ b/base/gxgstate.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -270,7 +270,7 @@ struct gs_gstate_s {
gsicc_manager_t *icc_manager; /* ICC color manager, profile */
gsicc_link_cache_t *icc_link_cache; /* ICC linked transforms */
gsicc_profile_cache_t *icc_profile_cache; /* ICC profiles from PS. */
- gsicc_blacktext_state_t *black_text_state; /* Used to store and restore cs for black text */
+ gsicc_blacktextvec_state_t *black_textvec_state; /* Used to store and restore cs for black text */
CUSTOM_COLOR_PTR /* Pointer to custom color callback struct */
const gx_color_map_procs *
@@ -378,7 +378,7 @@ struct gs_gstate_s {
s->icc_link_cache = __state_init.icc_link_cache; \
s->icc_profile_cache = __state_init.icc_profile_cache; \
s->get_cmap_procs = __state_init.get_cmap_procs; \
- s->black_text_state = NULL; \
+ s->black_textvec_state = NULL; \
s->show_gstate = NULL; \
s->is_fill_color = 1; \
s->strokeconstantalpha = 1.0; \
@@ -422,7 +422,7 @@ struct_proc_finalize(gs_gstate_finalize);
m(17, font) \
m(18, root_font) \
m(19, show_gstate) \
- m(20, black_text_state)
+ m(20, black_textvec_state)
#define gs_gstate_num_ptrs 21
diff --git a/base/gxipixel.c b/base/gxipixel.c
index 2f367e14..8b81aaa5 100644
--- a/base/gxipixel.c
+++ b/base/gxipixel.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -434,7 +434,7 @@ gx_image_enum_begin(gx_device * dev, const gs_gstate * pgs,
/* Can we restrict the amount of image we need? */
while (pcpath) /* So we can break out of it */
{
- gs_rect rect, rect_out;
+ gs_rect rect, rect_src;
gs_matrix mi;
const gs_matrix *m = pgs != NULL ? &ctm_only(pgs) : NULL;
gs_fixed_rect obox;
@@ -449,15 +449,42 @@ gx_image_enum_begin(gx_device * dev, const gs_gstate * pgs,
rect.p.y = fixed2float(obox.p.y);
rect.q.x = fixed2float(obox.q.x);
rect.q.y = fixed2float(obox.q.y);
- code = gs_bbox_transform(&rect, &mi, &rect_out);
+ /* rect is in destination space. Calculate rect_src, in source space. */
+ code = gs_bbox_transform(&rect, &mi, &rect_src);
if (code < 0) {
/* Give up trying to shrink the render/decode boxes, but continue processing */
break;
}
- irect.p.x = (int)(rect_out.p.x-1.0);
- irect.p.y = (int)(rect_out.p.y-1.0);
- irect.q.x = (int)(rect_out.q.x+1.0);
- irect.q.y = (int)(rect_out.q.y+1.0);
+ /* Need to expand the region to allow for the fact that the mitchell
+ * scaler reads multiple pixels in. */
+ /* If mi.{xx,yy} > 1 then we are downscaling. During downscaling,
+ * the support increases to ensure that we don't lose pixels contributions
+ * entirely. */
+ {
+ float support = any_abs(mi.xx);
+ int isupport;
+ if (any_abs(mi.yy) > support)
+ support = any_abs(mi.yy);
+ if (any_abs(mi.xy) > support)
+ support = any_abs(mi.xy);
+ if (any_abs(mi.yx) > support)
+ support = any_abs(mi.yx);
+ /* If upscaling (support < 1) then we need 2 extra lines on each side of the source region
+ * (2 being the maximum support for mitchell scaling).
+ * If downscaling, then the number of lines is increased to avoid individual
+ * contributions dropping out. */
+ isupport = 2; /* Mitchell support. */
+ if (support > 1)
+ isupport = (int)ceil(isupport * support);
+ rect_src.p.x -= isupport;
+ rect_src.p.y -= isupport;
+ rect_src.q.x += isupport;
+ rect_src.q.y += isupport;
+ }
+ irect.p.x = (int)floor(rect_src.p.x);
+ irect.p.y = (int)floor(rect_src.p.y);
+ irect.q.x = (int)ceil(rect_src.q.x);
+ irect.q.y = (int)ceil(rect_src.q.y);
/* We therefore only need to render within irect. Restrict rrect to this. */
if (penum->rrect.x < irect.p.x) {
penum->rrect.w -= irect.p.x - penum->rrect.x;
@@ -481,29 +508,6 @@ gx_image_enum_begin(gx_device * dev, const gs_gstate * pgs,
if (penum->rrect.h < 0)
penum->rrect.h = 0;
}
- /* Need to expand the region to allow for the fact that the mitchell
- * scaler reads multiple pixels in. */
- /* If mi.{xx,yy} > 1 then we are downscaling. During downscaling,
- * the support increases to ensure that we don't lose pixels contributions
- * entirely. */
- /* I do not understand the need for the +/- 1 fudge factors,
- * but they seem to be required. Increasing the decode rectangle can
- * never be bad at least... RJW */
- {
- float support = any_abs(mi.xx);
- int isupport;
- if (any_abs(mi.yy) > support)
- support = any_abs(mi.yy);
- if (any_abs(mi.xy) > support)
- support = any_abs(mi.xy);
- if (any_abs(mi.yx) > support)
- support = any_abs(mi.yx);
- isupport = (int)(MAX_ISCALE_SUPPORT * (support+1)) + 1;
- irect.p.x -= isupport;
- irect.p.y -= isupport;
- irect.q.x += isupport;
- irect.q.y += isupport;
- }
if (penum->drect.x < irect.p.x) {
penum->drect.w -= irect.p.x - penum->drect.x;
if (penum->drect.w < 0)
diff --git a/base/gxiscale.c b/base/gxiscale.c
index 7cd34f9b..90e52786 100644
--- a/base/gxiscale.c
+++ b/base/gxiscale.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -643,6 +643,25 @@ gs_image_class_0_interpolate(gx_image_enum * penum, irender_proc_t *render_fn)
&image_render_interpolate_landscape_icc);
return 0;
} else {
+
+ /* If we are doing fastcolor we may still have
+ a decode situation. To avoid yet another
+ variable, use the existing one in the
+ icc setup */
+ if (dev_profile->usefastcolor) {
+ int k;
+ int src_num_comp = cs_num_components(penum->pcs);
+
+ 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;
+ }
+ }
+ }
+
*render_fn = (penum->posture == image_portrait ?
&image_render_interpolate :
&image_render_interpolate_landscape);
@@ -677,8 +696,15 @@ initial_decode(gx_image_enum * penum, const byte * buffer, int data_x, int h,
cs is neither a device color nor a CIE color (i.e. if it's DeviceN,
Index or Separation) The color space cannot be a pattern for an image */
need_decode = (penum->icc_setup.need_decode || is_devn_sep_index);
- } else
- need_decode = is_devn_sep_index;
+ } else {
+ cmm_dev_profile_t *dev_profile;
+
+ dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile);
+ if (dev_profile != NULL && dev_profile->usefastcolor)
+ need_decode = (penum->icc_setup.need_decode || is_devn_sep_index);
+ else
+ need_decode = is_devn_sep_index;
+ }
if (h != 0) {
/* Convert the unpacked data to concrete values in the source buffer. */
diff --git a/base/gxp1fill.c b/base/gxp1fill.c
index 15b395da..519e853c 100644
--- a/base/gxp1fill.c
+++ b/base/gxp1fill.c
@@ -368,8 +368,9 @@ gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y,
bits = &ptile->tbits;
code = tile_fill_init(&state, pdevc, dev, false); /* This _may_ allocate state.cdev */
- if (code < 0)
- return code;
+ if (code < 0) {
+ goto exit;
+ }
if (ptile->is_simple && ptile->cdev == NULL) {
int px =
imod(-(int)fastfloor(ptile->step_matrix.tx - state.phase.x + 0.5),
@@ -417,6 +418,7 @@ gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y,
&tbits, tile_pattern_clist);
}
}
+exit:
if (CLIPDEV_INSTALLED) {
tile_clip_free((gx_device_tile_clip *)state.cdev);
state.cdev = NULL;
diff --git a/base/gxpaint.c b/base/gxpaint.c
index 2e4955c1..cd0f573e 100644
--- a/base/gxpaint.c
+++ b/base/gxpaint.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -72,8 +72,8 @@ gx_stroke_fill(gx_path * ppath, gs_gstate * pgs)
(dev, (const gs_gstate *)pgs, ppath, &params,
gs_currentdevicecolor_inline(pgs), pcpath);
- if (pgs->black_text_state) {
- gsicc_restore_black_text(pgs);
+ if (pgs->black_textvec_state) {
+ gsicc_restore_blacktextvec(pgs, true);
}
return code;
@@ -103,8 +103,8 @@ gx_fill_stroke_path(gs_gstate * pgs, int rule)
&stroke_params, gs_swappeddevicecolor_inline(pgs),
pcpath);
- if (pgs->black_text_state) {
- gsicc_restore_black_text(pgs);
+ if (pgs->black_textvec_state) {
+ gsicc_restore_blacktextvec(pgs, true);
}
return code;
diff --git a/base/gxpcmap.c b/base/gxpcmap.c
index 86af0885..e8b28b64 100644
--- a/base/gxpcmap.c
+++ b/base/gxpcmap.c
@@ -40,6 +40,8 @@
#include "gdevp14.h"
#include "gxgetbit.h"
#include "gscoord.h"
+#include "gsicc_blacktext.h"
+#include "gscspace.h"
#if RAW_PATTERN_DUMP
unsigned int global_pat_index = 0;
@@ -133,6 +135,7 @@ pattern_accum_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, strip_tile_rect_devn, gx_default_strip_tile_rect_devn);
set_dev_proc(dev, transform_pixel_region, gx_default_transform_pixel_region);
set_dev_proc(dev, fill_stroke_path, gx_default_fill_stroke_path);
+ set_dev_proc(dev, lock_pattern, gx_default_lock_pattern);
set_dev_proc(dev, copy_alpha_hl_color, gx_default_copy_alpha_hl_color);
}
@@ -946,7 +949,7 @@ gx_pattern_cache_free_entry(gx_pattern_cache * pcache, gx_color_tile * ctile)
if (ctile->ttrans != NULL) {
if_debug2m('v', mem,
- "[v*] Freeing trans pattern from cache, uid = %ld id = %ld\n",
+ "[v*] Freeing trans pattern from cache, uid = %ld id = %u\n",
ctile->uid.id, ctile->id);
if ( ctile->ttrans->pdev14 == NULL) {
/* This can happen if we came from the clist */
@@ -979,6 +982,41 @@ gx_pattern_cache_free_entry(gx_pattern_cache * pcache, gx_color_tile * ctile)
}
}
+/*
+ Historically, the pattern cache has used a very simple hashing
+ scheme whereby pattern A goes into slot idx = (A.id % num_tiles).
+ Unfortunately, now we allow tiles to be 'locked' into the
+ pattern cache, we might run into the case where we want both
+ tiles A and B to be in the cache at once where:
+ (A.id % num_tiles) == (B.id % num_tiles).
+
+ We have a maximum of 2 locked tiles, and one of those can be
+ placed while the other one is locked. So we only need to cope
+ with a single 'collision'.
+
+ We therefore allow tiles to either go in at idx or at
+ (idx + 1) % num_tiles. This means we need to be prepared to
+ search a bit further for them, hence we now have 2 helper
+ functions to do this.
+*/
+
+/* We can have at most 1 locked tile while looking for a place to
+ * put another tile. */
+gx_color_tile *
+gx_pattern_cache_find_tile_for_id(gx_pattern_cache *pcache, gs_id id)
+{
+ gx_color_tile *ctile = &pcache->tiles[id % pcache->num_tiles];
+ gx_color_tile *ctile2 = &pcache->tiles[(id+1) % pcache->num_tiles];
+ if (ctile->id == id || ctile->id == gs_no_id)
+ return ctile;
+ if (ctile2->id == id || ctile2->id == gs_no_id)
+ return ctile2;
+ if (!ctile->is_locked)
+ return ctile;
+ return ctile2;
+}
+
+
/* Given the size of a new pattern tile, free entries from the cache until */
/* enough space is available (or nothing left to free). */
/* This will allow 1 oversized entry */
@@ -1123,7 +1161,7 @@ gx_pattern_cache_add_entry(gs_gstate * pgs,
used = size_b + size_c;
}
id = pinst->id;
- ctile = &pcache->tiles[id % pcache->num_tiles];
+ ctile = gx_pattern_cache_find_tile_for_id(pcache, id);
gx_pattern_cache_free_entry(pcache, ctile); /* ensure that this cache slot is empty */
ctile->id = id;
ctile->is_planar = pinst->is_planar;
@@ -1156,7 +1194,7 @@ gx_pattern_cache_add_entry(gs_gstate * pgs,
ctile->tmask.data = 0;
if (trans != 0) {
if_debug2m('v', pgs->memory,
- "[v*] Adding trans pattern to cache, uid = %ld id = %ld\n",
+ "[v*] Adding trans pattern to cache, uid = %ld id = %u\n",
ctile->uid.id, ctile->id);
ctile->ttrans = trans;
}
@@ -1193,15 +1231,13 @@ gx_pattern_cache_add_entry(gs_gstate * pgs,
int
gx_pattern_cache_entry_set_lock(gs_gstate *pgs, gs_id id, bool new_lock_value)
{
- gx_pattern_cache *pcache;
gx_color_tile *ctile;
int code = ensure_pattern_cache(pgs);
if (code < 0)
return code;
- pcache = pgs->pattern_cache;
- ctile = &pcache->tiles[id % pcache->num_tiles];
- if (ctile->id != id)
+ ctile = gx_pattern_cache_find_tile_for_id(pgs->pattern_cache, id);
+ if (ctile == NULL)
return_error(gs_error_undefined);
ctile->is_locked = new_lock_value;
return 0;
@@ -1218,7 +1254,7 @@ gx_pattern_cache_get_entry(gs_gstate * pgs, gs_id id, gx_color_tile ** pctile)
if (code < 0)
return code;
pcache = pgs->pattern_cache;
- ctile = &pcache->tiles[id % pcache->num_tiles];
+ ctile = gx_pattern_cache_find_tile_for_id(pcache, id);
gx_pattern_cache_free_entry(pgs->pattern_cache, ctile);
ctile->id = id;
*pctile = ctile;
@@ -1245,7 +1281,7 @@ gx_pattern_cache_add_dummy_entry(gs_gstate *pgs,
if (code < 0)
return code;
pcache = pgs->pattern_cache;
- ctile = &pcache->tiles[id % pcache->num_tiles];
+ ctile = gx_pattern_cache_find_tile_for_id(pcache, id);
gx_pattern_cache_free_entry(pcache, ctile);
ctile->id = id;
ctile->depth = depth;
@@ -1490,7 +1526,7 @@ gx_pattern_load(gx_device_color * pdc, const gs_gstate * pgs,
if (code < 0)
goto fail;
if (pinst->templat.uses_transparency) {
- if_debug0m('v', mem, "gx_pattern_load: pushing the pdf14 compositor device into this graphics state\n");
+ if_debug1m('v', mem, "gx_pattern_load: pushing the pdf14 compositor device into this graphics state pat_id = %u\n", pinst->id);
if ((code = gs_push_pdf14trans_device(saved, true, false, 0, 0)) < 0) /* spot_color_count taken from pdf14 target values */
return code;
saved->device->is_open = true;
@@ -1550,7 +1586,7 @@ gx_pattern_load(gx_device_color * pdc, const gs_gstate * pgs,
/* Send the compositor command to close the PDF14 device */
code = gs_pop_pdf14trans_device(saved, true);
if (code < 0)
- return code;
+ goto fail;
} else {
/* Not a clist, get PDF14 buffer information */
code =
@@ -1561,7 +1597,7 @@ gx_pattern_load(gx_device_color * pdc, const gs_gstate * pgs,
/* PDF14 device (and buffer) is destroyed when pattern cache
entry is removed */
if (code < 0)
- return code;
+ goto fail;
}
}
/* We REALLY don't like the following cast.... */
@@ -1610,6 +1646,8 @@ fail:
cdev->common.data = 0;
}
dev_proc(adev, close_device)((gx_device *)adev);
+ gx_device_set_target(adev, NULL);
+ rc_decrement(adev, "gx_pattern_load");
gs_gstate_free_chain(saved);
return code;
}
@@ -1633,10 +1671,29 @@ gs_pattern1_remap_color(const gs_client_color * pc, const gs_color_space * pcs,
return 0;
}
if (pinst->templat.PaintType == 2) { /* uncolored */
- if (pcs->base_space)
- code = (pcs->base_space->type->remap_color)
- (pc, pcs->base_space, pdc, pgs, dev, select);
- else
+ if (pcs->base_space) {
+ if (dev->icc_struct != NULL && dev->icc_struct->blackvector) {
+ gs_client_color temppc;
+ gs_color_space *graycs = gs_cspace_new_DeviceGray(pgs->memory);
+
+ if (graycs == NULL) {
+ code = (pcs->base_space->type->remap_color)
+ (pc, pcs->base_space, pdc, pgs, dev, select);
+ } else {
+ if (gsicc_is_white_blacktextvec((gs_gstate*) pgs,
+ dev, (gs_color_space*) pcs, (gs_client_color*) pc))
+ temppc.paint.values[0] = 1.0;
+ else
+ temppc.paint.values[0] = 0.0;
+ code = (graycs->type->remap_color)
+ (&temppc, graycs, pdc, pgs, dev, select);
+ rc_decrement_cs(graycs, "gs_pattern1_remap_color");
+ }
+ } else {
+ code = (pcs->base_space->type->remap_color)
+ (pc, pcs->base_space, pdc, pgs, dev, select);
+ }
+ } else
code = gs_note_error(gs_error_unregistered);
if (code < 0)
return code;
diff --git a/base/gxpcolor.h b/base/gxpcolor.h
index 197b7532..043a296e 100644
--- a/base/gxpcolor.h
+++ b/base/gxpcolor.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -296,6 +296,9 @@ bool gx_device_is_pattern_accum(gx_device *dev);
/* This will allow 1 oversized entry */
void gx_pattern_cache_ensure_space(gs_gstate * pgs, size_t needed);
+gx_color_tile *
+gx_pattern_cache_find_tile_for_id(gx_pattern_cache *pcache, gs_id id);
+
void gx_pattern_cache_update_used(gs_gstate *pgs, size_t used);
/* Update cache tile space */
diff --git a/base/gxpflat.c b/base/gxpflat.c
index 61d43ee4..23aa0cd8 100644
--- a/base/gxpflat.c
+++ b/base/gxpflat.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -560,7 +560,13 @@ top :
return code;
notes |= sn_not_first;
goto top;
- } else if (k == -1) {
+ } else if (k < 0) {
+ /* This used to be k == -1, but... If we have a very long curve, we will first
+ * go through the code above to split the long curve into 2. In fact for very
+ * long curves we can go through that multiple times. This can lead to k being
+ * < -1 by the time we finish subdividing the curve, and that meant we did not
+ * satisfy the exit condition here, leading to a loop until VM error.
+ */
/* fixme : Don't need to init the iterator. Just wanted to check in_range. */
return gx_path_add_curve_notes(ppath, pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
pc->pt.x, pc->pt.y, notes);
diff --git a/base/gxshade6.c b/base/gxshade6.c
index 334e05a6..5183e607 100644
--- a/base/gxshade6.c
+++ b/base/gxshade6.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -295,6 +295,7 @@ init_patch_fill_state(patch_fill_state_t *pfs)
pfs->color_stack = NULL;
pfs->color_stack_limit = NULL;
pfs->unlinear = !is_linear_color_applicable(pfs);
+ pfs->pcic = NULL;
return alloc_patch_fill_memory(pfs, pfs->pgs->memory, pcs);
}
diff --git a/base/gxstroke.c b/base/gxstroke.c
index 6546e00b..34537843 100644
--- a/base/gxstroke.c
+++ b/base/gxstroke.c
@@ -558,7 +558,7 @@ gx_stroke_path_only_aux(gx_path *ppath, /* lgtm[cpp/use-of-goto] */
double device_dot_length = pgs_lp->dot_length * fixed_1;
const subpath *psub;
gs_matrix initial_matrix;
- bool initial_matrix_reflected;
+ bool initial_matrix_reflected, flattened_path = false;
note_flags flags;
(*dev_proc(pdev, get_initial_matrix)) (pdev, &initial_matrix);
@@ -741,6 +741,7 @@ gx_stroke_path_only_aux(gx_path *ppath, /* lgtm[cpp/use-of-goto] */
)
return code;
spath = &fpath;
+ flattened_path = true;
}
if (dash_count) {
float max_dash_len = 0;
@@ -1137,7 +1138,8 @@ gx_stroke_path_only_aux(gx_path *ppath, /* lgtm[cpp/use-of-goto] */
exf:
if (dash_count)
gx_path_free(&dpath, "gx_stroke_path exit(dash path)");
- if (ppath->curve_count)
+ /* If we flattened the path then we set spath to &fpath. If we flattned the path then now we need to free fpath */
+ if(flattened_path)
gx_path_free(&fpath, "gx_stroke_path exit(flattened path)");
return code;
}
@@ -2728,7 +2730,9 @@ add_pie_join(gx_path * ppath, pl_ptr plp, pl_ptr nplp, bool reflected,
r = (double)(nplp->width.x) /* x2 */ * (plp->width.y) /* y1 */;
if (l == r) {
- if (cap)
+ /* Colinear. Suppress drawing a cap unless the path reverses direction. */
+ if (cap &&
+ ((double)(plp->width.x) * (nplp->width.x) + (double)(nplp->width.y) * (plp->width.y)) < 0)
return add_pie_cap(ppath, &plp->e);
else
return gx_path_add_line(ppath, plp->e.ce.x, plp->e.ce.y);
diff --git a/base/gxtext.h b/base/gxtext.h
index babaaf1e..100c70e5 100644
--- a/base/gxtext.h
+++ b/base/gxtext.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -124,7 +124,7 @@ rc_free_proc(rc_free_text_enum);
int bytes_decoded; \
gs_point FontBBox_as_Metrics2; /* used with FontType 9,11 && WMode 1 */\
ulong text_enum_id; /* debug purpose only - not used by algorythm. */\
- bool k_text_release; /* Set at time of gs_text_begin to know to do release of black_text_state */\
+ bool k_text_release; /* Set at time of gs_text_begin to know to do release of black_textvec_state */\
/* The following is controlled by a device. */\
bool device_disabled_grid_fitting;\
/* Following two members moved from the show enumerator */\
diff --git a/base/gxttfb.c b/base/gxttfb.c
index 582c05c8..2e4a7e15 100644
--- a/base/gxttfb.c
+++ b/base/gxttfb.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -687,9 +687,9 @@ static int grid_fit(gx_device_spot_analyzer *padev, gx_path *path,
o->post_transform.a = o->post_transform.d = 1;
o->post_transform.b = o->post_transform.c = 0;
o->post_transform.tx = o->post_transform.ty = 0;
- ttfOutliner__DrawGlyphOutline(o);
- if (e->error < 0)
- return e->error;
+ code = ttfOutliner__DrawGlyphOutline(o);
+ if (code < 0)
+ return code;
code = t1_hinter__set_font42_data(&h.super, FontType, &pfont->data, false);
if (code < 0)
return code;
@@ -734,8 +734,8 @@ static int grid_fit(gx_device_spot_analyzer *padev, gx_path *path,
return code;
code = t1_hinter__endglyph(&h.super);
} else {
- ttfOutliner__DrawGlyphOutline(o);
- if (e->error < 0)
+ code = ttfOutliner__DrawGlyphOutline(o);
+ if (code < 0)
return e->error;
}
return code;
@@ -755,6 +755,7 @@ int gx_ttf_outline(ttfFont *ttf, gx_ttfReader *r, gs_font_type42 *pfont, int gly
bool dg;
uint gftt = gs_currentgridfittt(pfont->dir);
bool ttin = (gftt & 1);
+ int code;
/* gs_currentgridfittt values (binary) :
00 - no grid fitting;
01 - Grid fit with TT interpreter; On failure warn and render unhinted.
@@ -801,14 +802,16 @@ int gx_ttf_outline(ttfFont *ttf, gx_ttfReader *r, gs_font_type42 *pfont, int gly
case fNoError:
if (!design_grid && !ttin && auth)
return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
- ttfOutliner__DrawGlyphOutline(&o);
- if (e.error)
- return e.error;
+ code = ttfOutliner__DrawGlyphOutline(&o);
+ if (code < 0)
+ return code;
return 0;
case fMemoryError:
return_error(gs_error_VMerror);
case fUnimplemented:
return_error(gs_error_unregistered);
+ case fBadFontData:
+ return_error(gs_error_invalidfont);
default:
{ int code = r->super.Error(&r->super);
diff --git a/base/gxtype1.c b/base/gxtype1.c
index d3af50ec..b2b593a4 100644
--- a/base/gxtype1.c
+++ b/base/gxtype1.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -459,6 +459,7 @@ gs_type1_piece_codes(/*const*/ gs_font_type1 *pfont, /* lgtm[cpp/use-of-goto] */
else {
c = fixed2int_var(*csp) + pdata->gsubrNumberBias;
}
+ CS_CHECK_IPSTACK(ipsp + 1, ipstack);
code = pdata->procs.subr_data
(pfont, c, true, &ipsp[1].cs_data);
if (code < 0)
@@ -479,6 +480,7 @@ gs_type1_piece_codes(/*const*/ gs_font_type1 *pfont, /* lgtm[cpp/use-of-goto] */
else {
c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
}
+ CS_CHECK_IPSTACK(ipsp + 1, ipstack);
code = pdata->procs.subr_data
(pfont, c, false, &ipsp[1].cs_data);
if (code < 0)
@@ -498,6 +500,7 @@ c_return:
else
call_depth--;
gs_glyph_data_free(&ipsp->cs_data, "gs_type1_piece_codes");
+ CS_CHECK_IPSTACK(ipsp, ipstack);
--ipsp;
if (ipsp < ipstack)
return (gs_note_error(gs_error_invalidfont));
@@ -545,21 +548,26 @@ c_return:
case ce1_seac:
goto do_seac;
case ce1_callothersubr:
- switch (fixed2int_var(*csp)) {
- default:
- goto out;
- case 3:
- if (csp >= &(cstack[1]))
- csp -= 2;
- goto top;
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- case 18:
- cnext;
+ if (CS_CHECK_CSTACK_BOUNDS(csp, cstack)) {
+ switch (fixed2int_var(*csp)) {
+ default:
+ goto out;
+ case 3:
+ if (csp >= &(cstack[1]))
+ csp -= 2;
+ goto top;
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ cnext;
+ }
+ }
+ else {
+ return_error(gs_error_invalidfont);
}
}
}
diff --git a/base/gxtype1.h b/base/gxtype1.h
index 86911386..0c382396 100644
--- a/base/gxtype1.h
+++ b/base/gxtype1.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -196,7 +196,7 @@ typedef fixed *cs_ptr;
#define CS_CHECK_IPSTACK(ips, ipstack)\
BEGIN\
- if (ips > &ipstack[ipstack_size + 1] \
+ if (ips > &ipstack[ipstack_size] \
|| ips < &ipstack[0])\
return_error(gs_error_invalidfont);\
END
diff --git a/base/lcms2mt.mak b/base/lcms2mt.mak
index e03e7e34..7897d1c8 100644
--- a/base/lcms2mt.mak
+++ b/base/lcms2mt.mak
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2021 Artifex Software, Inc.
+# Copyright (C) 2001-2022 Artifex Software, Inc.
# All Rights Reserved.
#
# This software is provided AS-IS with no warranty, either express or
@@ -166,8 +166,15 @@ $(LCMS2OBJ)cmswtpnt.$(OBJ) : $(LCMS2SRC)cmswtpnt.c $(LCMS2_DEPS)
$(LCMS2OBJ)cmsvirt.$(OBJ) : $(LCMS2SRC)cmsvirt.c $(LCMS2_DEPS)
$(LCMS2_CC) $(LCMS2O_)cmsvirt.$(OBJ) $(C_) $(LCMS2SRC)cmsvirt.c
-$(LCMS2OBJ)cmsxform.$(OBJ) : $(LCMS2SRC)cmsxform.c $(LCMS2_DEPS)
- $(LCMS2_CC) $(LCMS2O_)cmsxform.$(OBJ) $(C_) $(LCMS2SRC)cmsxform.c
+$(LCMS2OBJ)cmsxform_0.$(OBJ) : $(LCMS2SRC)cmsxform.c $(LCMS2_DEPS)
+ $(LCMS2_CC) $(LCMS2O_)cmsxform_0.$(OBJ) $(C_) $(LCMS2SRC)cmsxform.c
+
+$(LCMS2OBJ)cmsxform_1.$(OBJ) : $(LCMS2SRC)cmsxform.c $(CAL_SRC)$(D)cal_cms.h $(LCMS2_DEPS)
+ $(LCMS2_CC) $(LCMS2O_)cmsxform_1.$(OBJ) $(I_)$(CAL_SRC)$(_I) $(D_)WITH_CAL$(_D) $(C_) $(LCMS2SRC)cmsxform.c
+
+$(LCMS2OBJ)cmsxform.$(OBJ) : $(LCMS2OBJ)cmsxform_$(WITH_CAL).$(OBJ) $(AK) \
+ $(LIB_MAK) $(MAKEDIRS)
+ $(CP_) $(LCMS2OBJ)cmsxform_$(WITH_CAL).$(OBJ) $(LCMS2OBJ)cmsxform.$(OBJ)
$(LCMS2OBJ)cmsalpha.$(OBJ) : $(LCMS2SRC)cmsalpha.c $(LCMS2_DEPS)
$(LCMS2_CC) $(LCMS2O_)cmsalpha.$(OBJ) $(C_) $(LCMS2SRC)cmsalpha.c
diff --git a/base/lib.mak b/base/lib.mak
index 4dc6c26e..dc3c9501 100644
--- a/base/lib.mak
+++ b/base/lib.mak
@@ -196,6 +196,7 @@ gxsync_h=$(GLSRC)gxsync.h
gxclthrd_h=$(GLSRC)gxclthrd.h
gxdevsop_h=$(GLSRC)gxdevsop.h
gdevflp_h=$(GLSRC)gdevflp.h
+pagelist_h=$(GLSRC)pagelist.h
gdevkrnlsclass_h=$(GLSRC)gdevkrnlsclass.h
gdevsclass_h=$(GLSRC)gdevsclass.h
@@ -1415,11 +1416,15 @@ $(GLOBJ)gxdownscale_1.$(OBJ) : $(GLSRC)gxdownscale.c $(AK) $(string__h)\
$(GLOBJ)gxdownscale.$(OBJ) : $(GLOBJ)gxdownscale_$(WITH_CAL).$(OBJ) $(AK) $(gp_h)
$(CP_) $(GLOBJ)gxdownscale_$(WITH_CAL).$(OBJ) $(GLOBJ)gxdownscale.$(OBJ)
+# ---- Various subclass devices ----
+subclass_=$(GLOBJ)gdevflp.$(OBJ) $(GLOBJ)gdevkrnlsclass.$(OBJ) $(GLOBJ)gdevepo.$(OBJ) \
+ $(GLOBJ)gdevoflt.$(OBJ) $(GLOBJ)gdevnup.$(OBJ) $(GLOBJ)gdevsclass.$(OBJ)
+
###### Create a pseudo-"feature" for the entire graphics library.
-LIB0s=$(GLOBJ)gpmisc.$(OBJ) $(GLOBJ)stream.$(OBJ) $(GLOBJ)strmio.$(OBJ)
-LIB1s=$(GLOBJ)gsalloc.$(OBJ) $(GLOBJ)gxdownscale.$(OBJ) $(downscale_) $(GLOBJ)gdevprn.$(OBJ) $(GLOBJ)gdevflp.$(OBJ) $(GLOBJ)gdevkrnlsclass.$(OBJ) $(GLOBJ)gdevepo.$(OBJ)
-LIB2s=$(GLOBJ)gdevmplt.$(OBJ) $(GLOBJ)gsbitcom.$(OBJ) $(GLOBJ)gsbitops.$(OBJ) $(GLOBJ)gsbittab.$(OBJ) $(GLOBJ)gdevoflt.$(OBJ) $(GLOBJ)gdevnup.$(OBJ) $(GLOBJ)gdevsclass.$(OBJ)
+LIB0s=$(GLOBJ)gpmisc.$(OBJ) $(GLOBJ)stream.$(OBJ) $(GLOBJ)strmio.$(OBJ) $(GLOBJ)pagelist.$(OBJ)
+LIB1s=$(GLOBJ)gsalloc.$(OBJ) $(GLOBJ)gxdownscale.$(OBJ) $(downscale_) $(GLOBJ)gdevprn.$(OBJ) $(subclass_)
+LIB2s=$(GLOBJ)gdevmplt.$(OBJ) $(GLOBJ)gsbitcom.$(OBJ) $(GLOBJ)gsbitops.$(OBJ) $(GLOBJ)gsbittab.$(OBJ)
# Note: gschar.c is no longer required for a standard build;
# we include it only for backward compatibility for library clients.
LIB3s=$(GLOBJ)gscedata.$(OBJ) $(GLOBJ)gscencs.$(OBJ) $(GLOBJ)gschar.$(OBJ) $(GLOBJ)gscolor.$(OBJ)
@@ -2072,11 +2077,14 @@ $(GLOBJ)gdevmplt.$(OBJ) : $(GLSRC)gdevmplt.c $(gdevmplt_h) $(gdevp14_h)\
$(memory__h)
$(GLCC) $(GLO_)gdevmplt.$(OBJ) $(C_) $(GLSRC)gdevmplt.c
+$(GLOBJ)pagelist.$(OBJ) : $(GLSRC)pagelist.c $(pagelist_h) $(gserrors_h) $(memory__h)
+ $(GLCC) $(GLO_)pagelist.$(OBJ) $(C_) $(GLSRC)pagelist.c
+
$(GLOBJ)gdevflp.$(OBJ) : $(GLSRC)gdevflp.c $(gdevflp_h) $(gdevp14_h) \
$(gdevprn_h) $(gdevsclass_h) $(gsdevice_h) $(gserrors_h) $(gsparam_h)\
$(gsstype_h) $(gx_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h) \
$(gxgstate_h) $(gximage_h) $(gxiparam_h) $(gxpaint_h) $(gxpath_h) $(math__h)\
- $(memory__h)
+ $(string__h) $(memory__h)
$(GLCC) $(GLO_)gdevflp.$(OBJ) $(C_) $(GLSRC)gdevflp.c
$(GLOBJ)gdevepo.$(OBJ) : $(GLSRC)gdevepo.c $(gdevepo_h) $(gdevp14_h) \
@@ -2650,7 +2658,8 @@ $(GLOBJ)gxpcmap.$(OBJ) : $(GLSRC)gxpcmap.c $(AK) $(gx_h) $(gserrors_h)\
$(gsstruct_h) $(gsutil_h) $(gp_h) $(gxcoord_h) $(gxgetbit_h)\
$(gxcolor2_h) $(gxcspace_h) $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h)\
$(gxfixed_h) $(gxmatrix_h) $(gxpcolor_h) $(gxclist_h) $(gxcldev_h)\
- $(gzstate_h) $(gdevp14_h) $(gdevmpla_h) $(LIB_MAK) $(MAKEDIRS)
+ $(gzstate_h) $(gdevp14_h) $(gdevmpla_h) $(gsicc_blacktext_h)\
+ $(gscspace_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gxpcmap.$(OBJ) $(C_) $(GLSRC)gxpcmap.c
# ---------------- PostScript Type 1 (and Type 4) fonts ---------------- #
@@ -3000,7 +3009,7 @@ $(GLOBJ)gsicc_profilecache.$(OBJ) : $(GLSRC)gsicc_profilecache.c $(AK)\
$(GLOBJ)gsicc_blacktext.$(OBJ) : $(GLSRC)gsicc_blacktext.c $(AK)\
$(gsmemory_h) $(gsstruct_h) $(gzstate_h) $(gsicc_blacktext_h)\
- $(LIB_MAK) $(MAKEDIRS)
+ $(gsicc_cache_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gsicc_blacktext.$(OBJ) $(C_) $(GLSRC)gsicc_blacktext.c
$(GLOBJ)gsicc_lcms2mt_1_0.$(OBJ) : $(GLSRC)gsicc_lcms2mt.c\
diff --git a/base/mkromfs.c b/base/mkromfs.c
index d46450b5..2b9d4363 100644
--- a/base/mkromfs.c
+++ b/base/mkromfs.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -2690,6 +2690,11 @@ main(int argc, char *argv[])
Xlist_head = Xlist_scan;
}
printf("Total %%rom%% structure size is %d bytes.\n", totlen);
-
+ if (splits.outname != NULL)
+ free(splits.outname);
+ if (splits.outname_formatted != NULL)
+ free(splits.outname_formatted);
+ if (splits.sizes != NULL)
+ free(splits.sizes);
return 0;
}
diff --git a/base/msvclib.mak b/base/msvclib.mak
index ba70f67c..61b90106 100644
--- a/base/msvclib.mak
+++ b/base/msvclib.mak
@@ -665,6 +665,21 @@ MS_TOOLSET_VERSION=14.29.30133
MSVC_VERSION=16
MS_TOOLSET_VERSION=14.29.30133
!endif
+!if "$(_NMAKE_VER)" == "14.29.30142.1"
+# VS2019 (Toolset v142)
+MSVC_VERSION=16
+MS_TOOLSET_VERSION=14.29.30133
+!endif
+!if "$(_NMAKE_VER)" == "14.29.30145.0"
+# VS2019 (Toolset v142)
+MSVC_VERSION=16
+MS_TOOLSET_VERSION=14.29.30133
+!endif
+!if "$(_NMAKE_VER)" == "14.29.30146.0"
+# VS2019 (Toolset v142)
+MSVC_VERSION=16
+MS_TOOLSET_VERSION=14.29.30133
+!endif
!endif
!ifndef MSVC_VERSION
diff --git a/base/pagelist.c b/base/pagelist.c
new file mode 100644
index 00000000..c687b7b9
--- /dev/null
+++ b/base/pagelist.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 2022-2022 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* Functions to parse a PageList string and processing utilitiess */
+
+
+#include "memory_.h"
+#include "string_.h" /* for strcspn */
+#include <stdlib.h> /* for atoi */
+#include "gsmemory.h"
+#include "gserrors.h"
+#include "pagelist.h"
+
+/* array contains an "ordered" flag, then even/odd, start, end triples */
+
+/* Allocate an array of ranges. A range of 0-0 terminates the list */
+/* Note the first int 0 is order unknown, < 0 is unordered, > 0 is */
+/* ordered and thus is suitable for sequential parsers like PS or PCL. */
+/* This first int is also used by test_printed as the offset into the */
+/* array for fast processing by SkipPage. */
+/* returns error code < 0 or number of ranges if success. */
+int
+pagelist_parse_to_array(char *page_list, gs_memory_t *mem, int num_pages, int **parray)
+{
+ int i = 0, range_count = 0;
+ int *pagelist_array = NULL;
+ char *p = page_list;
+ int prev_end = 0; /* used to track if the ranges are ordered */
+ int ordered = 1; /* default is ordered, until it's not */
+ int comma, len;
+
+ *parray = NULL; /* in case PageList is empty */
+ if (page_list[0] == 0)
+ return gs_error_rangecheck; /* empty list not valid */
+
+ do {
+ len = strlen(p);
+ comma = strcspn(p, ",");
+ p += comma + 1;
+ if (comma > 0)
+ range_count++;
+ } while (comma < len);
+ if (range_count == 0)
+ return gs_error_rangecheck; /* not valid */
+
+ range_count++; /* room for the end of list marker: 0, 0, 0 */
+ pagelist_array = (int *)gs_alloc_byte_array(mem, 1 + (range_count * 3), sizeof(int), "pagelist_parse_to_array");
+ *parray = pagelist_array; /* return the array (NULL is OK) */
+ if (pagelist_array == NULL)
+ return gs_error_VMerror;
+
+ memset(pagelist_array, 0, (1 + range_count * 3) * sizeof(int));
+ /* Fill the array */
+
+ p = page_list; /* go back to start of string */
+ for (i=1; i < (range_count - 1) * 3; ) {
+ /* Parsing method from Michael Vrhel's code in xps */
+ int dash, start, end, even_odd;
+
+ even_odd = 0;
+ start = 1;
+ end = -1; /* internal flag for last page */
+ len = strlen(p);
+ comma = strcspn(p, ",");
+ dash = strcspn(p, "-");
+
+ if (comma == 0) {
+ p++;
+ continue; /* skip leading or adjacent commas */
+ }
+ if (strncmp(p, "even", 4) == 0) {
+ even_odd = 2;
+ p += 4;
+ } else if (strncmp(p, "odd", 3) == 0) {
+ even_odd = 1;
+ p += 3;
+ }
+ /* check if the next after "even" or "odd" is ':' */
+ if (even_odd != 0) {
+ start = even_odd; /* default is entire range */
+ end = -1;
+ if (*p == ':')
+ p++; /* skip to the range */
+ len = strlen(p);
+ comma = strcspn(p, ",");
+ dash = strcspn(p, "-");
+ }
+ if (comma > 0 && *p != 0) {
+ /* We have a range to process */
+ if (dash < comma) {
+ /* Dash at start */
+ if (dash == 0) {
+ start = -1;
+ end = atoi(p + dash + 1);
+ } else {
+ start = atoi(p);
+ /* Dash at end */
+ if (p[dash + 1] == 0 || p[dash + 1] == ',') {
+ end = -1;
+ } else {
+ end = atoi(p + dash + 1);
+ }
+ }
+ } else {
+ start = atoi(p);
+ end = start;
+ }
+ }
+ if (comma == len)
+ p += comma;
+ else
+ p += comma + 1;
+
+ /* If even or odd, and we have a "num_pages" flag == -1, adjust to proper value */
+ if (even_odd == 2) {
+ if (start == -1)
+ start = num_pages & -2;
+ if (end == -1)
+ end = num_pages & -2;
+ } else if (even_odd == 1) {
+ if (start == -1)
+ start = num_pages - (1 & (num_pages ^ 1));
+ if (end == -1)
+ end = num_pages - (1 & (num_pages ^ 1));
+ } else {
+ if (start == -1)
+ start = num_pages;
+ if (end == -1)
+ end = num_pages;
+ }
+ /* Store this range, bump the index as we do */
+ pagelist_array[i++] = even_odd;
+ pagelist_array[i++] = start;
+ pagelist_array[i++] = end;
+
+ if (start <= prev_end || start > end)
+ ordered = -1;
+ prev_end = end;
+ }
+ /* Note final array entries are 0, 0, 0 from memset above */
+ pagelist_array[0] = ordered;
+ return range_count;
+}
+
+/* function to calculate the total number of pages to be output */
+int
+pagelist_number_of_pages(const int *parray)
+{
+ int count = 0, i;
+
+ /* loop over ranges until start == 0 */
+ for (i=1; parray[i+1] != 0; i += 3) {
+ int start = parray[i+1];
+ int end = parray[i+2];
+
+ if (end >= start)
+ count += 1 + end - start;
+ else
+ count += 1 + start - end;
+ }
+ return count;
+}
+
+/* Return true if this pagelist is in strict increasing order */
+bool
+pagelist_test_ordered(int *parray)
+{
+ int prev;
+ int i;
+
+ /* check flag (fast for use by the flp SkipPage function */
+ if (parray[0] > 0)
+ return true;
+ if (parray[0] < 0)
+ return false;
+
+ /* parray[0] == 0, scan until start of range is 0 */
+ prev = 0; /* page 1 or more is legal */
+ for (i=1; parray[i+1] != 0; i += 3) {
+ if (parray[i+1] <= prev || parray[i+1] < parray[i+2])
+ break; /* NOT ordered */
+ prev = parray[i+2]; /* advance to end of range */
+ }
+ /* if we made it to the marker at the end, then the list is ordered */
+ parray[0] = (parray[i+1] == 0) ? 1 : -1;
+ return parray[0] > 0;
+}
+
+/* Return true if this page is to be printed. (For sequential processing) */
+/* This assumes/requires that the PageList is strictly sequential. */
+bool
+pagelist_test_printed(int *parray, int pagenum)
+{
+ int i = parray[0];
+
+ if (i <= 0) { /* shouldn't happen */
+ pagelist_test_ordered(parray); /* in case caller didn't do this */
+ i = parray[0];
+ if (i < 0)
+ return false; /* list is NOT ordered, punt */
+ }
+
+ /* advance to next range if pagenum past the end of this range */
+ /* stopping at the 0, 0, 0 marker (start == 0) */
+ while (pagenum > parray[i+2] && parray[i+1] != 0) {
+ i += 3; /* bump to next range for next call */
+ parray[0] = i; /* update for next entry */
+ }
+ if (parray[i+1] == 0)
+ return false; /* reached end of ranges */
+
+ /* First Test even, then odd */
+ if (parray[i] == 2 && (pagenum & 1) == 1)
+ return false;
+ if (parray[i] == 1 && (pagenum & 1) == 0)
+ return false;
+
+ /* Fast case for ordered list and sequential page numbers (FLP device) */
+ if (i > 0) {
+ if (pagenum >= parray[i+1] && pagenum <= parray[i+2]) {
+ return true; /* page was in this range */
+ } else {
+ if (pagenum < parray[i+1])
+ return false; /* pagennum in between ranges that skip */
+ }
+ }
+ return false;
+}
+
+void
+pagelist_free_range_array(gs_memory_t *mem, int *parray)
+{
+ gs_free_object(mem, parray, "flp_close_device");
+}
diff --git a/base/pagelist.h b/base/pagelist.h
new file mode 100644
index 00000000..832b2157
--- /dev/null
+++ b/base/pagelist.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2022-2022 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* Functions to parse a PageList string and processing utilitiess */
+
+/* Allocate an array of ranges. A range of 0-0 terminates the list */
+/* array contains even/odd flag, start, end (3 ints per range). */
+/* returns error code < 0 or number of ranges if success */
+int pagelist_parse_to_array(char *pPageList, gs_memory_t *mem, int num_pages, int **parray);
+
+/* function to calculate the total number of pages to be output */
+int pagelist_number_of_pages(const int *parray);
+
+/* Return true if this pagelist is in strict increasing order */
+bool pagelist_test_ordered(int *parray);
+
+/* Return true if this page is to be printed (for sequential processing) */
+/* This assumes that the PageList is strictly sequential, tested by client. */
+bool pagelist_test_printed(int *parray, int pagenum);
+
+void pagelist_free_range_array(gs_memory_t *mem, int *parray);
diff --git a/base/scfd.c b/base/scfd.c
index 03085fbf..6d538890 100644
--- a/base/scfd.c
+++ b/base/scfd.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -211,17 +211,18 @@ static inline int skip_data(stream_CFD_state *ss, stream_cursor_read *pr, int rl
static inline int invert_data(stream_CFD_state *ss, stream_cursor_read *pr, int *rlen, byte black_byte)
{
+ byte *qlim = ss->lbuf + ss->raster + CFD_BUFFER_SLOP;
cfd_declare_state;
cfd_load_state();
(void)rlimit;
- if (q >= ss->lbuf + ss->raster + CFD_BUFFER_SLOP || q < ss->lbufstart) {
+ if (q >= qlim || q < ss->lbufstart) {
return(-1);
}
if ( (*rlen) > qbit )
{
- if (q + ((*rlen - qbit) >> 3) > ss->lbuf + ss->raster + CFD_BUFFER_SLOP) {
+ if (q + ((*rlen - qbit) >> 3) > qlim) {
return(-1);
}
@@ -233,6 +234,10 @@ static inline int invert_data(stream_CFD_state *ss, stream_cursor_read *pr, int
}
(*rlen) -= qbit;
+ if (q + ((*rlen) >> 3) >= qlim) {
+ return(-1);
+ }
+
switch ( (*rlen) >> 3 )
{
case 7: /* original rlen possibly >= 64 */
diff --git a/base/siscale.c b/base/siscale.c
index 5bf212c1..128b1fad 100644
--- a/base/siscale.c
+++ b/base/siscale.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -210,7 +210,7 @@ calculate_contrib(
int i, j;
int last_index = -1;
- if_debug1('w', "[w]calculate_contrib scale=%lg\n", scale);
+ if_debug1('W', "[W]calculate_contrib scale=%lg\n", scale);
if (scale < 1.0) {
double clamped_scale = max(scale, min_scale);
WidthIn = ((double)fWidthIn) / clamped_scale;
@@ -250,7 +250,7 @@ calculate_contrib(
int last_pixel = clamp_pixel(right);
CONTRIB *p;
- if_debug4('w', "[w]i=%d, i+offset=%lg scale=%lg center=%lg : ", starting_output_index + i,
+ if_debug4('W', "[W]i=%d, i+offset=%lg scale=%lg center=%lg : ", starting_output_index + i,
starting_output_index + i + (double)src_y_offset / src_size * dst_size, scale, center);
if (last_pixel > last_index)
last_index = last_pixel;
@@ -275,7 +275,7 @@ calculate_contrib(
ie = (int)(e + 0.5);
p[k].weight += ie;
e -= ie;
- if_debug2('w', " %d %f", k, (float)p[k].weight);
+ if_debug2('W', " %d %f", k, (float)p[k].weight);
}
} else {
@@ -293,10 +293,10 @@ calculate_contrib(
ie = (int)(e + 0.5);
p[k].weight += ie;
e -= ie;
- if_debug2('w', " %d %f", k, (float)p[k].weight);
+ if_debug2('W', " %d %f", k, (float)p[k].weight);
}
}
- if_debug0('w', "\n");
+ if_debug0('W', "\n");
}
return last_index;
}
@@ -860,16 +860,18 @@ calculate_dst_contrib(stream_IScale_state * ss, int y)
int limited_WidthOut = (ss->params.WidthOut + abs_interp_limit - 1) / abs_interp_limit;
int limited_EntireHeightOut = (ss->params.EntireHeightOut + abs_interp_limit - 1) / abs_interp_limit;
uint row_size = limited_WidthOut * ss->params.spp_interp;
- int last_index =
- calculate_contrib(&ss->dst_next_list, ss->dst_items,
+ int last_index, first_index_mod;
+
+ if_debug2m('W', ss->memory, "[W]calculate_dst_contrib for y = %d, y+offset=%d\n", y, y + ss->src_y_offset);
+
+ last_index = calculate_contrib(&ss->dst_next_list, ss->dst_items,
(double)limited_EntireHeightOut / ss->params.EntireHeightIn,
y, ss->src_y_offset, limited_EntireHeightOut, ss->params.EntireHeightIn,
1, ss->params.HeightIn, ss->max_support, row_size,
(double)ss->params.MaxValueOut / 255, ss->filter_width,
ss->filter, ss->min_scale);
- int first_index_mod = ss->dst_next_list.first_pixel / row_size;
+ first_index_mod = ss->dst_next_list.first_pixel / row_size;
- if_debug2m('w', ss->memory, "[W]calculate_dst_contrib for y = %d, y+offset=%d\n", y, y + ss->src_y_offset);
ss->dst_last_index = last_index;
last_index %= ss->max_support;
if (last_index < first_index_mod) { /* Shuffle the indices to account for wraparound. */
@@ -1101,7 +1103,8 @@ s_IScale_process(stream_state * st, stream_cursor_read * pr,
row = ss->dst;
}
/* Apply filter to zoom vertically from tmp to dst. */
- if (ss->params.Active)
+ if (ss->params.Active) {
+ if_debug1('w', "[w]zoom_y y = %d\n", ss->dst_y);
ss->zoom_y(row, /* Where to scale to */
ss->tmp, /* Line buffer */
limited_LeftMarginOut, /* Skip */
@@ -1109,6 +1112,7 @@ s_IScale_process(stream_state * st, stream_cursor_read * pr,
limited_WidthOut, /* Stride */
ss->params.spp_interp, /* Color count */
&ss->dst_next_list, ss->dst_items);
+ }
/* Idiotic C coercion rules allow T* and void* to be */
/* inter-assigned freely, but not compared! */
if ((void *)row != ss->dst) /* no buffering */
@@ -1156,8 +1160,9 @@ s_IScale_process(stream_state * st, stream_cursor_read * pr,
ss->src_offset = 0;
}
/* Apply filter to zoom horizontally from src to tmp. */
- if_debug2('w', "[w]zoom_x y = %d to tmp row %d\n",
- ss->src_y, (ss->src_y % ss->max_support));
+ if_debug3('w', "[w]zoom_x y = %d to tmp row %d%s\n",
+ ss->src_y, (ss->src_y % ss->max_support),
+ ss->params.Active ? "" : " (Inactive)");
if (ss->params.Active)
ss->zoom_x(/* Where to scale to (dst line address in tmp buffer) */
ss->tmp + (ss->src_y % ss->max_support) *
diff --git a/base/spdiff.c b/base/spdiff.c
index c5df1bf0..eeef2101 100644
--- a/base/spdiff.c
+++ b/base/spdiff.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -19,6 +19,7 @@
#include "memory_.h"
#include "strimpl.h"
#include "spdiffx.h"
+#include "gserrors.h"
/* ------ PixelDifferenceEncode/Decode ------ */
@@ -64,6 +65,9 @@ s_PDiffE_init(stream_state * st)
0, 0, 0, 0, 0, 0, 0, cBits16
};
+ if (ss->Colors > s_PDiff_max_Colors)
+ return_error(gs_error_rangecheck);
+
ss->row_count = (bits_per_row + 7) >> 3;
ss->end_mask = (1 << (-bits_per_row & 7)) - 1;
ss->case_index =
@@ -76,11 +80,12 @@ s_PDiffE_init(stream_state * st)
static int
s_PDiffD_init(stream_state * st)
{
+ int code = 0;
stream_PDiff_state *const ss = (stream_PDiff_state *) st;
- s_PDiffE_init(st);
+ code = s_PDiffE_init(st);
ss->case_index += cDecode - cEncode;
- return 0;
+ return code;
}
/* Process a buffer. Note that this handles both Encode and Decode. */
diff --git a/base/stream.c b/base/stream.c
index 6f68d7c2..5c4c3d1d 100644
--- a/base/stream.c
+++ b/base/stream.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -110,6 +110,8 @@ s_init(stream *s, gs_memory_t * mem)
s->prev = s->next = 0; /* clean for GC */
s->file_name.data = 0; /* ibid. */
s->file_name.size = 0;
+ s->end_status = 0;
+ s->modes = 0;
s->close_strm = false; /* default */
s->close_at_eod = true; /* default */
s->cbuf_string_memory = NULL;
@@ -1294,6 +1296,7 @@ s_add_filter(stream **ps, const stream_template *templat,
int
s_close_filters(stream **ps, stream *target)
{
+ int code = 0;
while (*ps != target) {
stream *s = *ps;
gs_memory_t *mem = s->state->memory;
@@ -1304,8 +1307,8 @@ s_close_filters(stream **ps, stream *target)
int status = sclose(s);
stream_state *ss = s->state; /* sclose may set this to s */
- if (status < 0)
- return status;
+ if (code == 0)
+ code = status;
if (s->cbuf_string_memory != NULL) { /* stream owns string buffer, so free it */
gs_free_object(cbuf_string_memory, cbuf, "s_close_filters(cbuf)");
@@ -1320,7 +1323,7 @@ s_close_filters(stream **ps, stream *target)
}
*ps = next;
}
- return 0;
+ return code;
}
/* ------ Stream closing ------ */
diff --git a/base/ttfmain.c b/base/ttfmain.c
index 4ee5dfd8..82593a00 100644
--- a/base/ttfmain.c
+++ b/base/ttfmain.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -533,6 +533,10 @@ retry:
subglyph.bbox.xMax = ttfReader__Short(r);
subglyph.bbox.yMax = ttfReader__Short(r);
+ if (exec->metrics.x_scale1 == 0 || exec->metrics.x_scale2 == 0
+ || exec->metrics.y_scale1 == 0 || exec->metrics.y_scale2 == 0) {
+ goto errex;
+ }
gOutline->xMinB = Scale_X(&exec->metrics, subglyph.bbox.xMin);
gOutline->yMinB = Scale_Y(&exec->metrics, subglyph.bbox.yMin);
gOutline->xMaxB = Scale_X(&exec->metrics, subglyph.bbox.xMax);
@@ -646,8 +650,15 @@ retry:
e->m.tx = Scale_X( &exec->metrics, e->arg1 ) << 10;
e->m.ty = Scale_Y( &exec->metrics, e->arg2 ) << 10;
} else {
- e->m.tx = (pts->org_x[e->arg1] - pts->org_x[gOutline->pointCount + e->arg2]) << 10;
- e->m.ty = (pts->org_y[e->arg1] - pts->org_y[gOutline->pointCount + e->arg2]) << 10;
+ if (e->arg1 < 0 || e->arg1 > pts->n_points
+ || ((int)gOutline->pointCount + e->arg2) < 0 || (gOutline->pointCount + e->arg2) > pts->n_points) {
+ error = fBadFontData;
+ goto ex;
+ }
+ else {
+ e->m.tx = (pts->org_x[e->arg1] - pts->org_x[gOutline->pointCount + e->arg2]) << 10;
+ e->m.ty = (pts->org_y[e->arg1] - pts->org_y[gOutline->pointCount + e->arg2]) << 10;
+ }
}
MoveGlyphOutline(pts, nPointsStored, &out, &e->m);
for (j = nContoursStored; j < out.contourCount + nContoursStored; j++)
@@ -875,7 +886,7 @@ static FontError ttfOutliner__BuildGlyphOutline(ttfOutliner *self, int glyphInde
#define AVECTOR_BUG 1 /* Work around a bug in AVector fonts. */
-void ttfOutliner__DrawGlyphOutline(ttfOutliner *self)
+int ttfOutliner__DrawGlyphOutline(ttfOutliner *self)
{ ttfGlyphOutline* out = &self->out;
FloatMatrix *m = &self->post_transform;
ttfFont *pFont = self->pFont;
@@ -890,10 +901,23 @@ void ttfOutliner__DrawGlyphOutline(ttfOutliner *self)
short sp, ctr;
FloatPoint p0, p1, p2, p3;
# if AVECTOR_BUG
- F26Dot6 expand_x = Scale_X(&exec->metrics, pFont->nUnitsPerEm * 2);
- F26Dot6 expand_y = Scale_Y(&exec->metrics, pFont->nUnitsPerEm * 2);
- F26Dot6 xMin = out->xMinB - expand_x, xMax = out->xMaxB + expand_x;
- F26Dot6 yMin = out->yMinB - expand_y, yMax = out->yMaxB + expand_y;
+ F26Dot6 expand_x;
+ F26Dot6 expand_y;
+ F26Dot6 xMin, xMax;
+ F26Dot6 yMin, yMax;
+
+
+ if (exec->metrics.x_scale1 == 0 || exec->metrics.x_scale2 == 0
+ || exec->metrics.y_scale1 == 0 || exec->metrics.y_scale2 == 0) {
+ return_error(gs_error_invalidfont);
+ }
+
+ expand_x = Scale_X(&exec->metrics, pFont->nUnitsPerEm * 2);
+ expand_y = Scale_Y(&exec->metrics, pFont->nUnitsPerEm * 2);
+ xMin = out->xMinB - expand_x;
+ xMax = out->xMaxB + expand_x;
+ yMin = out->yMinB - expand_y;
+ yMax = out->yMaxB + expand_y;
# endif
TransformF26Dot6PointFloat(&p1, out->advance.x, out->advance.y, m);
@@ -1014,6 +1038,7 @@ void ttfOutliner__DrawGlyphOutline(ttfOutliner *self)
onCurve += pts;
sp = *endP++;
}
+ return 0;
}
FontError ttfOutliner__Outline(ttfOutliner *self, int glyphIndex,
diff --git a/base/ttfoutl.h b/base/ttfoutl.h
index 32dd8d22..e339e973 100644
--- a/base/ttfoutl.h
+++ b/base/ttfoutl.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -195,6 +195,6 @@ void ttfOutliner__init(ttfOutliner *, ttfFont *f, ttfReader *r, ttfExport *exp,
bool bOutline, bool bFirst, bool bVertical);
FontError ttfOutliner__Outline(ttfOutliner *this, int glyphIndex,
float orig_x, float orig_y, FloatMatrix *m1);
-void ttfOutliner__DrawGlyphOutline(ttfOutliner *this);
+int ttfOutliner__DrawGlyphOutline(ttfOutliner *this);
#endif
diff --git a/base/ttinterp.c b/base/ttinterp.c
index fe44a844..4429439b 100644
--- a/base/ttinterp.c
+++ b/base/ttinterp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -1825,6 +1825,12 @@ static int nInstrCount=0;
{
if ( args[1] == 0 )
{
+ if ( BOUNDS(CUR.IP + args[0], CUR.codeSize ) )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
CUR.IP += (Int)(args[0]);
CUR.step_ins = FALSE;
@@ -2319,7 +2325,8 @@ static int nInstrCount=0;
L = (Int)CUR.code[CUR.IP + 1];
- if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) )
+ if ( BOUNDS( L, CUR.stackSize+1-CUR.top )
+ || BOUNDS( L, CUR.codeSize+1-CUR.IP))
{
CUR.error = TT_Err_Stack_Overflow;
return;
@@ -2343,7 +2350,9 @@ static int nInstrCount=0;
L = (Int)CUR.code[CUR.IP + 1];
- if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) )
+ /* GET_ShortIns() reads two values from the execution stream */
+ if ( BOUNDS( L, CUR.stackSize+1-CUR.top )
+ || BOUNDS( L * 2, CUR.codeSize+1-CUR.IP))
{
CUR.error = TT_Err_Stack_Overflow;
return;
@@ -4059,7 +4068,8 @@ static int nInstrCount=0;
if ( BOUNDS( b0, CUR.zp0.n_points ) ||
BOUNDS( b1, CUR.zp0.n_points ) ||
BOUNDS( a0, CUR.zp1.n_points ) ||
- BOUNDS( a1, CUR.zp1.n_points ) )
+ BOUNDS( a1, CUR.zp1.n_points ) ||
+ BOUNDS( point, CUR.zp2.n_points) )
{
CUR.error = TT_Err_Invalid_Reference;
return;
@@ -4378,9 +4388,15 @@ static int nInstrCount=0;
end_point = CUR.pts.contours[contour];
first_point = point;
- while ( point <= end_point && (CUR.pts.touch[point] & mask) == 0 )
+ while ( point <= end_point && point < CUR.pts.n_points && (CUR.pts.touch[point] & mask) == 0 )
point++;
+ if (BOUNDS(point, CUR.pts.n_points ))
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
if ( point <= end_point )
{
first_touched = point;
@@ -4392,12 +4408,21 @@ static int nInstrCount=0;
{
if ( (CUR.pts.touch[point] & mask) != 0 )
{
- Interp( (Int)(cur_touched + 1),
+ if (BOUNDS(cur_touched, CUR.pts.n_points)
+ || BOUNDS(point, CUR.pts.n_points))
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ else
+ {
+ Interp( (Int)(cur_touched + 1),
(Int)(point - 1),
(Int)cur_touched,
(Int)point,
&V );
- cur_touched = point;
+ cur_touched = point;
+ }
}
point++;
diff --git a/base/ttobjs.c b/base/ttobjs.c
index 75eacb9c..5fa95a88 100644
--- a/base/ttobjs.c
+++ b/base/ttobjs.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -303,6 +303,9 @@ static int free_aux(ttfMemory *mem, void *ptr)
if (n_points < 100)
n_points = 100; /* Bug 689907 */
+ exec->n_contours = exec->n_points = 0;
+ exec->twilight.n_points = 0;
+
if ( ALLOC_ARRAY( exec->callStack, exec->callSize, callSize, TCallRecord ) ||
/* reserve interpreter call stack */
diff --git a/base/unix-gcc.mak b/base/unix-gcc.mak
index 04ebcff8..5d659fa3 100644
--- a/base/unix-gcc.mak
+++ b/base/unix-gcc.mak
@@ -201,7 +201,6 @@ SHARE_FT=0
FTSRCDIR=./freetype
FT_CFLAGS=-I./freetype/include
FT_LIBS=
-FT_CONFIG_SYSTEM_ZLIB=
# Define whether to compile in UFST.
# FAPI/UFST depends on UFST_BRIDGE being undefined - hence the construct below.
diff --git a/base/version.mak b/base/version.mak
index 98fb46e1..f5abe371 100644
--- a/base/version.mak
+++ b/base/version.mak
@@ -13,11 +13,11 @@
# Makefile fragment containing the current revision identification.
# Major, minor and patch version numbers.
-GS_VERSION_MAJOR=9
-GS_VERSION_MINOR=56
-GS_VERSION_PATCH=1
+GS_VERSION_MAJOR=10
+GS_VERSION_MINOR=00
+GS_VERSION_PATCH=0
# Revision date: year x 10000 + month x 100 + day.
-GS_REVISIONDATE=20220404
+GS_REVISIONDATE=20220921
# Derived values
GS_VERSION=$(GS_VERSION_MAJOR)$(GS_VERSION_MINOR)$(GS_VERSION_PATCH)
GS_DOT_VERSION=$(GS_VERSION_MAJOR).$(GS_VERSION_MINOR).$(GS_VERSION_PATCH)
diff --git a/base/winlib.mak b/base/winlib.mak
index 5664a61b..ea561491 100644
--- a/base/winlib.mak
+++ b/base/winlib.mak
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2021 Artifex Software, Inc.
+# Copyright (C) 2001-2022 Artifex Software, Inc.
# All Rights Reserved.
#
# This software is provided AS-IS with no warranty, either express or
@@ -128,7 +128,8 @@ BEGINFILES=$(GLGENDIR)\ccf32.tr\
$(GLOBJDIR)\*.res $(GLOBJDIR)\*.ico\
$(BINDIR)\$(GSDLL).dll $(BINDIR)\$(GSCONSOLE).exe\
$(BINDIR)\setupgs.exe $(BINDIR)\uninstgs.exe\
- $(GLOBJDIR)\cups\*.h $(AUXDIR)\*.sbr $(AUXDIR)\*.pdb \
+ $(GLOBJDIR)\cups\*.h $(GLOBJDIR)\*.h $(GLOBJDIR)\*.c $(AUXDIR)\*.sbr \
+ $(AUXDIR)\*.pdb \
$(BEGINFILES2)
# Include the generic makefiles.