diff options
Diffstat (limited to 'base')
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, ¶ms, 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. |