diff options
-rw-r--r-- | base/gdevdflt.c | 1 | ||||
-rw-r--r-- | base/gdevp14.c | 2420 | ||||
-rw-r--r-- | base/gdevp14.h | 42 | ||||
-rw-r--r-- | base/gsicc_cache.c | 6 | ||||
-rw-r--r-- | base/gstparam.h | 6 | ||||
-rw-r--r-- | base/gstrans.c | 41 | ||||
-rw-r--r-- | base/gstrans.h | 4 | ||||
-rw-r--r-- | base/gxblend.h | 4 | ||||
-rw-r--r-- | base/gxblend1.c | 264 | ||||
-rw-r--r-- | base/gxdevsop.h | 7 | ||||
-rw-r--r-- | devices/devs.mak | 2 | ||||
-rw-r--r-- | devices/gdevpng.c | 17 | ||||
-rw-r--r-- | devices/vector/gdevpdft.c | 2 |
13 files changed, 1681 insertions, 1135 deletions
diff --git a/base/gdevdflt.c b/base/gdevdflt.c index bd0e0c4d3..96b8a8eee 100644 --- a/base/gdevdflt.c +++ b/base/gdevdflt.c @@ -1026,6 +1026,7 @@ gx_default_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size) case gxdso_supports_saved_pages: case gxdso_needs_invariant_palette: case gxdso_supports_iccpostrender: + case gxdso_supports_alpha: return 0; case gxdso_pattern_shfill_doesnt_need_path: return (dev_proc(pdev, fill_path) == gx_default_fill_path); diff --git a/base/gdevp14.c b/base/gdevp14.c index 30cca0e69..4bddb116a 100644 --- a/base/gdevp14.c +++ b/base/gdevp14.c @@ -135,13 +135,13 @@ static void pdf14_debug_mask_stack_state(pdf14_ctx *ctx); gs_private_st_ptrs7(st_pdf14_buf, pdf14_buf, "pdf14_buf", pdf14_buf_enum_ptrs, pdf14_buf_reloc_ptrs, saved, data, backdrop, transfer_fn, mask_stack, - matte, parent_color_info); + matte, group_color_info); -gs_private_st_ptrs2(st_pdf14_ctx, pdf14_ctx, "pdf14_ctx", +gs_private_st_ptrs3(st_pdf14_ctx, pdf14_ctx, "pdf14_ctx", pdf14_ctx_enum_ptrs, pdf14_ctx_reloc_ptrs, - stack, mask_stack); + stack, mask_stack, base_color); -gs_private_st_ptrs1(st_pdf14_clr, pdf14_parent_color_t, "pdf14_clr", +gs_private_st_ptrs1(st_pdf14_clr, pdf14_group_color_t, "pdf14_clr", pdf14_clr_enum_ptrs, pdf14_clr_reloc_ptrs, previous); gs_private_st_ptrs2(st_pdf14_mask, pdf14_mask_t, "pdf_mask", @@ -341,23 +341,21 @@ static int pdf14_cmykspot_put_image(gx_device * dev, gs_gstate * pgs, static int pdf14_custom_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target); -/* Used to alter device color mapping procs based upon group or softmask color space */ -static int pdf14_update_device_color_procs(gx_device *dev, +/* Alter pdf14 device color model based upon group or softmask. This occurs + post clist or in immediate rendering case. Data stored with buffer */ +static pdf14_group_color_t* pdf14_push_color_model(gx_device *dev, gs_transparency_color_t group_color, int64_t icc_hashcode, - gs_gstate *pgs, cmm_profile_t *iccprofile, bool is_mask); + cmm_profile_t *iccprofile, bool is_mask); +static void pdf14_pop_color_model(gx_device* dev, pdf14_group_color_t* group_color); -/* Used to alter device color mapping procs based upon group or softmask color space */ -/* Uses color procs stack so that it can be used with clist writer */ -static int -pdf14_update_device_color_procs_push_c(gx_device *dev, - gs_transparency_color_t group_color, int64_t icc_hashcode, - gs_gstate *pgs, cmm_profile_t *iccprofile, bool is_mask); - -static int -pdf14_update_device_color_procs_pop_c(gx_device *dev,gs_gstate *pgs); +/* Alter clist writer device color model based upon group or softmask. Data + stored in the device color model stack */ +static int pdf14_clist_push_color_model(gx_device* dev, gx_device* cdev, gs_gstate* pgs, + const gs_pdf14trans_t* pdf14pct, gs_memory_t* mem, bool is_mask); +static int pdf14_clist_pop_color_model(gx_device* dev, gs_gstate* pgs); -static void pdf14_push_parent_color(gx_device *dev, const gs_gstate *pgs); -static void pdf14_pop_parent_color(gx_device *dev, const gs_gstate *pgs); +/* Used for cleaning up the stack if things go wrong */ +static void pdf14_pop_group_color(gx_device *dev, const gs_gstate *pgs); static const pdf14_procs_t gray_pdf14_procs = { pdf14_unpack_additive, @@ -775,7 +773,7 @@ ENUM_PTRS_WITH(pdf14_device_enum_ptrs, pdf14_device *pdev) return 0; } case 0: return ENUM_OBJ(pdev->ctx); -case 1: return ENUM_OBJ(pdev->trans_group_parent_cmap_procs); +case 1: return ENUM_OBJ(pdev->color_model_stack); case 2: return ENUM_OBJ(pdev->smaskcolor); case 3: ENUM_RETURN(gx_device_enum_ptr(pdev->target)); case 4: ENUM_RETURN(gx_device_enum_ptr(pdev->pclist_device)); @@ -792,7 +790,7 @@ static RELOC_PTRS_WITH(pdf14_device_reloc_ptrs, pdf14_device *pdev) } RELOC_VAR(pdev->ctx); RELOC_VAR(pdev->smaskcolor); - RELOC_VAR(pdev->trans_group_parent_cmap_procs); + RELOC_VAR(pdev->color_model_stack); pdev->target = gx_device_reloc_ptr(pdev->target, gcst); pdev->pclist_device = gx_device_reloc_ptr(pdev->pclist_device, gcst); } @@ -889,12 +887,13 @@ resolve_matte(pdf14_buf *maskbuf, byte *src_data, int src_planestride, int src_r need to do the offset to our data in the buffer. Bug 700686: If we are in a softmask that includes a matte entry, then we need to undo the matte entry here at this time in the image's native color space not the parent - color space. */ + color space. The big_endian term here is only set to true if the data + has been baked as such during the put_image blending operation. */ static forceinline pdf14_buf* template_transform_color_buffer(gs_gstate *pgs, pdf14_ctx *ctx, gx_device *dev, pdf14_buf *src_buf, byte *src_data, cmm_profile_t *src_profile, cmm_profile_t *des_profile, int x0, int y0, int width, int height, bool *did_alloc, - bool has_matte, bool deep) + bool has_matte, bool deep, bool big_endian) { gsicc_rendering_param_t rendering_params; gsicc_link_t *icc_link; @@ -970,6 +969,11 @@ template_transform_color_buffer(gs_gstate *pgs, pdf14_ctx *ctx, gx_device *dev, gsicc_init_buffer(&des_buff_desc, des_profile->num_comps, 1<<deep, false, false, true, des_planestride, des_rowstride, height, width); + if (big_endian) { + src_buff_desc.little_endian = false; + des_buff_desc.little_endian = false; + } + /* If we have a matte entry, undo the pre-blending now. Also set pdf14 context to ensure that this is not done again during the group composition */ @@ -1040,28 +1044,28 @@ static pdf14_buf* pdf14_transform_color_buffer_no_matte(gs_gstate *pgs, pdf14_ctx *ctx, gx_device *dev, pdf14_buf *src_buf, byte *src_data, cmm_profile_t *src_profile, cmm_profile_t *des_profile, int x0, int y0, int width, int height, bool *did_alloc, - bool deep) + bool deep, bool big_endian) { if (deep) return template_transform_color_buffer(pgs, ctx, dev, src_buf, src_data, src_profile, - des_profile, x0, y0, width, height, did_alloc, false, true); + des_profile, x0, y0, width, height, did_alloc, false, true, big_endian); else return template_transform_color_buffer(pgs, ctx, dev, src_buf, src_data, src_profile, - des_profile, x0, y0, width, height, did_alloc, false, false); + des_profile, x0, y0, width, height, did_alloc, false, false, big_endian); } static pdf14_buf* pdf14_transform_color_buffer_with_matte(gs_gstate *pgs, pdf14_ctx *ctx, gx_device *dev, pdf14_buf *src_buf, byte *src_data, cmm_profile_t *src_profile, cmm_profile_t *des_profile, int x0, int y0, int width, int height, bool *did_alloc, - bool deep) + bool deep, bool big_endian) { if (deep) return template_transform_color_buffer(pgs, ctx, dev, src_buf, src_data, src_profile, - des_profile, x0, y0, width, height, did_alloc, true, true); + des_profile, x0, y0, width, height, did_alloc, true, true, big_endian); else return template_transform_color_buffer(pgs, ctx, dev, src_buf, src_data, src_profile, - des_profile, x0, y0, width, height, did_alloc, true, false); + des_profile, x0, y0, width, height, did_alloc, true, false, big_endian); } /** @@ -1082,7 +1086,6 @@ pdf14_buf_new(gs_int_rect *rect, bool has_tags, bool has_alpha_g, /* yet another plane */ pdf14_buf *result; - pdf14_parent_color_t *new_parent_color; int rowstride = ((rect->q.x - rect->p.x + 3) & -4)<<deep; int height = (rect->q.y - rect->p.y); int n_planes = n_chan + (has_shape ? 1 : 0) + (has_alpha_g ? 1 : 0) + @@ -1120,21 +1123,9 @@ pdf14_buf_new(gs_int_rect *rect, bool has_tags, bool has_alpha_g, result->num_spots = num_spots; result->deep = deep; result->page_group = false; - new_parent_color = gs_alloc_struct(memory, pdf14_parent_color_t, &st_pdf14_clr, - "pdf14_buf_new"); - if (new_parent_color == NULL) { - gs_free_object(memory, result, "pdf14_buf_new"); - return NULL; - } + result->group_color_info = NULL; + result->group_popped = false; - result->parent_color_info = new_parent_color; - result->parent_color_info->get_cmap_procs = NULL; - result->parent_color_info->parent_color_mapping_procs = NULL; - result->parent_color_info->parent_color_comp_index = NULL; - result->parent_color_info->icc_profile = NULL; - result->parent_color_info->previous = NULL; - result->parent_color_info->encode = NULL; - result->parent_color_info->decode = NULL; if (idle || height <= 0) { /* Empty clipping - will skip all drawings. */ result->planestride = 0; @@ -1173,7 +1164,7 @@ pdf14_buf_new(gs_int_rect *rect, bool has_tags, bool has_alpha_g, static void pdf14_buf_free(pdf14_buf *buf) { - pdf14_parent_color_t *old_parent_color_info = buf->parent_color_info; + pdf14_group_color_t *group_color_info = buf->group_color_info; gs_memory_t *memory = buf->memory; if (buf->mask_stack && buf->mask_stack->rc_mask) @@ -1184,13 +1175,13 @@ pdf14_buf_free(pdf14_buf *buf) gs_free_object(memory, buf->matte, "pdf14_buf_free"); gs_free_object(memory, buf->data, "pdf14_buf_free"); - while (old_parent_color_info) { - if (old_parent_color_info->icc_profile != NULL) { - gsicc_adjust_profile_rc(old_parent_color_info->icc_profile, -1, "pdf14_buf_free"); + while (group_color_info) { + if (group_color_info->icc_profile != NULL) { + gsicc_adjust_profile_rc(group_color_info->icc_profile, -1, "pdf14_buf_free"); } - buf->parent_color_info = old_parent_color_info->previous; - gs_free_object(memory, old_parent_color_info, "pdf14_buf_free"); - old_parent_color_info = buf->parent_color_info; + buf->group_color_info = group_color_info->previous; + gs_free_object(memory, group_color_info, "pdf14_buf_free"); + group_color_info = buf->group_color_info; } gs_free_object(memory, buf->backdrop, "pdf14_buf_free"); @@ -1216,63 +1207,31 @@ pdf14_rcmask_new(gs_memory_t *memory) result = gs_alloc_struct(memory, pdf14_rcmask_t, &st_pdf14_rcmask, "pdf14_maskbuf_new"); - if ( result == NULL ) - return(NULL); + if (result == NULL) + return NULL; rc_init_free(result, memory, 1, rc_pdf14_maskbuf_free); result->mask_buf = NULL; result->memory = memory; - return(result); + return result; } static pdf14_ctx * -pdf14_ctx_new(gs_int_rect *rect, int n_chan, bool additive, gx_device *dev, bool deep) +pdf14_ctx_new(gx_device *dev, bool deep) { pdf14_ctx *result; - pdf14_buf *buf; gs_memory_t *memory = dev->memory->stable_memory; - bool has_tags = device_encodes_tags(dev); - pdf14_device *pdev = (pdf14_device *)dev; - int num_spots; - + result = gs_alloc_struct(memory, pdf14_ctx, &st_pdf14_ctx, "pdf14_ctx_new"); if (result == NULL) return result; - /* Note: buffer creation expects alpha to be in number of channels */ - /* Old code here used num_spots = pdev->devn_params.page_spot_colors, - * but this fails for devices like psdcmykog, which does not expand - * to take on new spot colors, over and above the 2 it has built in. - * Accordingly, we calculate the number of spot colors to be the - * number of channels we've been asked for, less the number of - * 'standard' colorants. */ - num_spots = n_chan - pdev->num_std_colorants; - buf = pdf14_buf_new(rect, has_tags, false, false, false, n_chan + 1, - num_spots, memory, deep); - if (buf == NULL) { - gs_free_object(memory, result, "pdf14_ctx_new"); - return NULL; - } - if_debug5m('v', memory, - "[v]base buf: %d x %d, %d color channels, %d planes, deep=%d\n", - buf->rect.q.x, buf->rect.q.y, buf->n_chan, buf->n_planes, deep); - if (buf->data != NULL) { - /* Memsetting by 0, so this copes with the deep case too */ - if (buf->has_tags) { - memset(buf->data, 0, buf->planestride * (buf->n_planes-1)); - } else { - memset(buf->data, 0, buf->planestride * buf->n_planes); - } - } - buf->saved = NULL; - result->stack = buf; + result->stack = NULL; result->mask_stack = pdf14_mask_element_new(memory); result->mask_stack->rc_mask = pdf14_rcmask_new(memory); - result->n_chan = n_chan; result->memory = memory; - result->rect = *rect; - result->additive = additive; result->smask_depth = 0; result->smask_blend = false; result->deep = deep; + result->base_color = NULL; return result; } @@ -1281,10 +1240,14 @@ pdf14_ctx_free(pdf14_ctx *ctx) { pdf14_buf *buf, *next; + if (ctx->base_color) { + gsicc_adjust_profile_rc(ctx->base_color->icc_profile, -1, "pdf14_ctx_free"); + gs_free_object(ctx->memory, ctx->base_color, "pdf14_ctx_free"); + } if (ctx->mask_stack) { /* A mask was created but was not used in this band. */ rc_decrement(ctx->mask_stack->rc_mask, "pdf14_ctx_free"); - gs_free_object(ctx->memory,ctx->mask_stack,"pdf14_ctx_free"); + gs_free_object(ctx->memory, ctx->mask_stack, "pdf14_ctx_free"); } for (buf = ctx->stack; buf != NULL; buf = next) { next = buf->saved; @@ -1333,44 +1296,182 @@ pdf14_find_backdrop_buf(pdf14_ctx *ctx, bool *is_backdrop) return NULL; } +static pdf14_group_color_t* +pdf14_make_base_group_color(gx_device* dev) +{ + pdf14_device* pdev = (pdf14_device*)dev; + pdf14_group_color_t* group_color; + bool deep = pdev->ctx->deep; + + if_debug0m('v', dev->memory, "[v]pdf14_make_base_group_color\n"); + + group_color = gs_alloc_struct(pdev->ctx->memory, + pdf14_group_color_t, &st_pdf14_clr, + "pdf14_make_base_group_color"); + + if (group_color == NULL) + return NULL; + memset(group_color, 0, sizeof(pdf14_group_color_t)); + + group_color->blend_procs = pdev->blend_procs; + group_color->polarity = pdev->color_info.polarity; + group_color->num_components = pdev->color_info.num_components; + group_color->isadditive = pdev->ctx->additive; + group_color->unpack_procs = pdev->pdf14_procs; + group_color->max_color = pdev->color_info.max_color = deep ? 65535 : 255; + group_color->max_gray = pdev->color_info.max_gray = deep ? 65535 : 255; + group_color->depth = pdev->color_info.depth; + group_color->decode = dev_proc(pdev, decode_color); + group_color->encode = dev_proc(pdev, encode_color); + group_color->group_color_mapping_procs = dev_proc(pdev, get_color_mapping_procs); + group_color->group_color_comp_index = dev_proc(pdev, get_color_comp_index); + memcpy(&(group_color->comp_bits), &(pdev->color_info.comp_bits), + GX_DEVICE_COLOR_MAX_COMPONENTS); + memcpy(&(group_color->comp_shift), &(pdev->color_info.comp_shift), + GX_DEVICE_COLOR_MAX_COMPONENTS); + group_color->get_cmap_procs = pdf14_get_cmap_procs; + group_color->icc_profile = pdev->icc_struct->device_profile[0]; + gsicc_adjust_profile_rc(group_color->icc_profile, 1, "pdf14_make_base_group_color"); + + return group_color; +} + +/* This wil create the first buffer when we have + either the first drawing operation or transparency + group push. At that time, the color space in which + we are going to be doing the alpha blend will be known. */ +static int +pdf14_initialize_ctx(gx_device* dev, int n_chan, bool additive, const gs_gstate* pgs) +{ + pdf14_device* pdev = (pdf14_device*)dev; + bool has_tags = device_encodes_tags(dev); + int num_spots = pdev->ctx->num_spots; + pdf14_buf* buf; + gs_memory_t* memory = dev->memory->stable_memory; + + /* Check for a blank idle group as a base group */ + if (pdev->ctx->stack != NULL && pdev->ctx->stack->group_popped && + pdev->ctx->stack->idle) { + pdf14_buf_free(pdev->ctx->stack); + pdev->ctx->stack = NULL; + } + + if (pdev->ctx->stack != NULL) + return 0; + + if_debug2m('v', dev->memory, "[v]pdf14_initialize_ctx: width = %d, height = %d\n", + dev->width, dev->height); + + buf = pdf14_buf_new(&(pdev->ctx->rect), has_tags, false, false, false, n_chan + 1, + num_spots, memory, pdev->ctx->deep); + if (buf == NULL) { + return gs_error_VMerror; + } + if_debug5m('v', memory, + "[v]base buf: %d x %d, %d color channels, %d planes, deep=%d\n", + buf->rect.q.x, buf->rect.q.y, buf->n_chan, buf->n_planes, pdev->ctx->deep); + + /* This check is not really needed */ + if (buf->data != NULL) { + /* Memsetting by 0, so this copes with the deep case too */ + if (buf->has_tags) { + memset(buf->data, 0, buf->planestride * (buf->n_planes - 1)); + } + else { + memset(buf->data, 0, buf->planestride * buf->n_planes); + } + } + buf->saved = NULL; + pdev->ctx->stack = buf; + pdev->ctx->n_chan = n_chan; + pdev->ctx->additive = additive; + + /* Every buffer needs group color information including the base + one that is created for when we have no group */ + buf->group_color_info = gs_alloc_struct(pdev->memory->stable_memory, + pdf14_group_color_t, &st_pdf14_clr, "pdf14_initialize_ctx"); + if (buf->group_color_info == NULL) + return gs_error_VMerror; + + if (pgs != NULL) + buf->group_color_info->get_cmap_procs = pgs->get_cmap_procs; + else + buf->group_color_info->get_cmap_procs = pdf14_get_cmap_procs; + + buf->group_color_info->group_color_mapping_procs = + dev_proc(pdev, get_color_mapping_procs); + buf->group_color_info->group_color_comp_index = + dev_proc(pdev, get_color_comp_index); + buf->group_color_info->blend_procs = pdev->blend_procs; + buf->group_color_info->polarity = pdev->color_info.polarity; + buf->group_color_info->num_components = pdev->color_info.num_components; + buf->group_color_info->isadditive = pdev->ctx->additive; + buf->group_color_info->unpack_procs = pdev->pdf14_procs; + buf->group_color_info->depth = pdev->color_info.depth; + buf->group_color_info->max_color = pdev->color_info.max_color; + buf->group_color_info->max_gray = pdev->color_info.max_gray; + buf->group_color_info->encode = dev_proc(pdev, encode_color); + buf->group_color_info->decode = dev_proc(pdev, decode_color); + memcpy(&(buf->group_color_info->comp_bits), &(pdev->color_info.comp_bits), + GX_DEVICE_COLOR_MAX_COMPONENTS); + memcpy(&(buf->group_color_info->comp_shift), &(pdev->color_info.comp_shift), + GX_DEVICE_COLOR_MAX_COMPONENTS); + buf->group_color_info->previous = NULL; /* used during clist writing */ + buf->group_color_info->icc_profile = pdev->icc_struct->device_profile[0]; + if (buf->group_color_info->icc_profile != NULL) + gsicc_adjust_profile_rc(buf->group_color_info->icc_profile, 1, "pdf14_initialize_ctx"); + + return 0; +} + +static pdf14_group_color_t* +pdf14_clone_group_color_info(gx_device* pdev, pdf14_group_color_t* src) +{ + pdf14_group_color_t* des = gs_alloc_struct(pdev->memory->stable_memory, + pdf14_group_color_t, &st_pdf14_clr, "pdf14_clone_group_color_info"); + if (des == NULL) + return NULL; + + memcpy(des, src, sizeof(pdf14_group_color_t)); + if (des->icc_profile != NULL) + gsicc_adjust_profile_rc(des->icc_profile, 1, "pdf14_clone_group_color_info"); + des->previous = NULL; /* used during clist writing for state stack */ + + return des; +} + static int pdf14_push_transparency_group(pdf14_ctx *ctx, gs_int_rect *rect, bool isolated, bool knockout, uint16_t alpha, uint16_t shape, uint16_t opacity, gs_blend_mode_t blend_mode, bool idle, uint mask_id, - int numcomps, bool cm_back_drop, - cmm_profile_t *group_profile, - cmm_profile_t *tos_profile, gs_gstate *pgs, + int numcomps, bool cm_back_drop, bool shade_group, + cmm_profile_t *group_profile, cmm_profile_t *tos_profile, + pdf14_group_color_t* group_color, gs_gstate *pgs, gx_device *dev) { pdf14_buf *tos = ctx->stack; pdf14_buf *buf, * pdf14_backdrop; - bool has_shape, has_tags, is_backdrop; + bool has_shape = false; + bool is_backdrop; + int num_spots; if_debug1m('v', ctx->memory, "[v]pdf14_push_transparency_group, idle = %d\n", idle); - /* We are going to use the shape in the knockout computation. If previous - buffer has a shape or if this is a knockout then we will have a shape here */ - has_shape = tos->has_shape || tos->knockout; - /* If previous buffer has tags, then add tags here */ - has_tags = tos->has_tags; + if (tos != NULL) + has_shape = tos->has_shape || tos->knockout; - /* If the group is NOT isolated we add in the alpha_g plane. This enables - recompositing to be performed ala art_pdf_recomposite_group_8 so that - the backdrop is only included one time in the computation. + if (ctx->smask_depth > 0) + num_spots = 0; + else + num_spots = ctx->num_spots; - For shape and alpha, backdrop removal is accomplished by maintaining - two sets of variables to hold the accumulated values. The group shape - and alpha, f_g and alpha_g, accumulate only the shape and alpha of the group - elements, excluding the group backdrop. - */ - /* Order of buffer data is color data, followed by alpha channel, followed by - shape (if present), then alpha_g (if present), then tags (if present) */ - buf = pdf14_buf_new(rect, has_tags, !isolated, has_shape, idle, numcomps + 1, - tos->num_spots, ctx->memory, ctx->deep); + buf = pdf14_buf_new(rect, ctx->has_tags, !isolated, has_shape, idle, numcomps + 1, + num_spots, ctx->memory, ctx->deep); if (buf == NULL) return_error(gs_error_VMerror); + if_debug4m('v', ctx->memory, "[v]base buf: %d x %d, %d color channels, %d planes\n", buf->rect.q.x, buf->rect.q.y, buf->n_chan, buf->n_planes); @@ -1386,8 +1487,9 @@ pdf14_push_transparency_group(pdf14_ctx *ctx, gs_int_rect *rect, bool isolated, ctx->mask_stack = NULL; /* Clean the mask field for rendering this group. See pdf14_pop_transparency_group how to handle it. */ buf->saved = tos; + buf->group_color_info = group_color; - if (tos->saved == NULL) + if (tos == NULL) buf->page_group = true; ctx->stack = buf; @@ -1469,30 +1571,71 @@ pdf14_pop_transparency_group(gs_gstate *pgs, pdf14_ctx *ctx, pdf14_buf *maskbuf; int x0, x1, y0, y1; int nos_num_color_comp; - bool icc_match; + bool no_icc_match; pdf14_device *pdev = (pdf14_device *)dev; bool overprint = pdev->overprint; gx_color_index drawn_comps = pdev->drawn_comps_stroke | pdev->drawn_comps_fill; bool has_matte = false; - if (nos == NULL) - return_error(gs_error_unknownerror); /* Unmatched group pop */ - - nos_num_color_comp = nos->parent_color_info->num_components - nos->num_spots; - tos_num_color_comp = tos_num_color_comp - tos->num_spots; - #ifdef DEBUG pdf14_debug_mask_stack_state(ctx); #endif if (mask_stack == NULL) { maskbuf = NULL; - } else { + } + else { maskbuf = mask_stack->rc_mask->mask_buf; } if (maskbuf != NULL && maskbuf->matte != NULL) has_matte = true; + /* Check if this is our last buffer, if yes, there is nothing to + compose to. Keep this buffer until we have the put image. + If we have another group push, this group must be destroyed. + This only occurs sometimes when at clist creation time + push_shfill_group occured and nothing was drawn in this group. + There is also the complication if we have a softmask. There + are two approaches to this problem. Apply the softmask during + the put image or handle it now. I choose the later as the + put_image code is already way to complicated. */ + if (nos == NULL && maskbuf == NULL) { + tos->group_popped = true; + return 0; + } + + /* Here is the case with the soft mask. Go ahead and create a new + target buffer (nos) with the same color information etc, but blank + and go ahead and do the blend with the softmask so that it gets applied. */ + if (nos == NULL && maskbuf != NULL) { + nos = pdf14_buf_new(&(tos->rect), ctx->has_tags, !tos->isolated, tos->has_shape, + tos->idle, tos->n_chan, tos->num_spots, ctx->memory, ctx->deep); + if (nos == NULL) + return gs_error_VMerror; + + if_debug4m('v', ctx->memory, + "[v] special buffer for softmask application: %d x %d, %d color channels, %d planes\n", + nos->rect.q.x, nos->rect.q.y, nos->n_chan, nos->n_planes); + + nos->dirty = tos->dirty; + nos->isolated = tos->isolated; + nos->knockout = tos->knockout; + nos->alpha = 65535; + nos->shape = 65535; + nos->opacity = 65535; + nos->blend_mode = tos->blend_mode; + nos->mask_id = tos->mask_id; + nos->group_color_info = pdf14_clone_group_color_info(dev, tos->group_color_info); + + if (nos->data != NULL) + memset(nos->data, 0, nos->planestride * (nos->n_chan + + (nos->has_shape ? 1 : 0) + + (nos->has_alpha_g ? 1 : 0))); + } + + nos_num_color_comp = nos->group_color_info->num_components - tos->num_spots; + tos_num_color_comp = tos_num_color_comp - tos->num_spots; + /* Sanitise the dirty rectangles, in case some of the drawing routines * have made them overly large. */ rect_intersect(tos->dirty, tos->rect); @@ -1540,32 +1683,32 @@ pdf14_pop_transparency_group(gs_gstate *pgs, pdf14_ctx *ctx, operations called in the tile transparency code. Instead we may want to look at pdf14_begin_transparency_group and pdf14_end_transparency group which is where all the ICC information is handled. We will return to look at that later */ - if (nos->parent_color_info->icc_profile != NULL) { - icc_match = (nos->parent_color_info->icc_profile->hashcode != + if (nos->group_color_info->icc_profile != NULL) { + no_icc_match = (nos->group_color_info->icc_profile->hashcode != curr_icc_profile->hashcode); } else { /* Let the other tests make the decision if we need to transform */ - icc_match = false; + no_icc_match = false; } /* If the color spaces are different and we actually did do a swap of the procs for color */ - if ((nos->parent_color_info->parent_color_mapping_procs != NULL && - nos_num_color_comp != tos_num_color_comp) || icc_match) { + if ((nos->group_color_info->group_color_mapping_procs != NULL && + nos_num_color_comp != tos_num_color_comp) || no_icc_match) { if (x0 < x1 && y0 < y1) { pdf14_buf *result; bool did_alloc; /* We don't care here */ if (has_matte) { result = pdf14_transform_color_buffer_with_matte(pgs, ctx, dev, - tos, tos->data, curr_icc_profile, nos->parent_color_info->icc_profile, + tos, tos->data, curr_icc_profile, nos->group_color_info->icc_profile, tos->rect.p.x, tos->rect.p.y, tos->rect.q.x - tos->rect.p.x, - tos->rect.q.y - tos->rect.p.y, &did_alloc, tos->deep); + tos->rect.q.y - tos->rect.p.y, &did_alloc, tos->deep, false); has_matte = false; } else { result = pdf14_transform_color_buffer_no_matte(pgs, ctx, dev, - tos, tos->data, curr_icc_profile, nos->parent_color_info->icc_profile, + tos, tos->data, curr_icc_profile, nos->group_color_info->icc_profile, tos->rect.p.x, tos->rect.p.y, tos->rect.q.x - tos->rect.p.x, - tos->rect.q.y - tos->rect.p.y, &did_alloc, tos->deep); + tos->rect.q.y - tos->rect.p.y, &did_alloc, tos->deep, false); } if (result == NULL) return_error(gs_error_unknownerror); /* transform failed */ @@ -1581,8 +1724,8 @@ pdf14_pop_transparency_group(gs_gstate *pgs, pdf14_ctx *ctx, #endif /* compose. never do overprint in this case */ pdf14_compose_group(tos, nos, maskbuf, x0, x1, y0, y1, nos->n_chan, - nos->parent_color_info->isadditive, - nos->parent_color_info->parent_blending_procs, + nos->group_color_info->isadditive, + nos->group_color_info->blend_procs, has_matte, false, drawn_comps, ctx->memory, dev); } } else { @@ -1620,7 +1763,8 @@ pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect, uint16_t bg_alph gs_transparency_mask_subtype_t subtype, int numcomps, int Background_components, const float Background[], int Matte_components, - const float Matte[], const float GrayBackground) + const float Matte[], const float GrayBackground, + pdf14_group_color_t* group_color) { pdf14_buf *buf; int i; @@ -1630,13 +1774,17 @@ pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect, uint16_t bg_alph idle, replacing); ctx->smask_depth += 1; + if (ctx->stack == NULL) { + return_error(gs_error_VMerror); + } + /* An optimization to consider is that if the SubType is Alpha then we really should only be allocating the alpha band and only draw with that channel. Current architecture makes that a bit tricky. We need to create this based upon the size of the color space + an alpha channel. NOT the device size or the previous ctx size */ - /* A mask doesnt worry about tags */ + /* A mask doesn't worry about tags */ buf = pdf14_buf_new(rect, false, false, false, idle, numcomps + 1, 0, ctx->memory, ctx->deep); if (buf == NULL) @@ -1650,6 +1798,8 @@ pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect, uint16_t bg_alph buf->blend_mode = BLEND_MODE_Normal; buf->transfer_fn = transfer_fn; buf->matte_num_comps = Matte_components; + buf->group_color_info = group_color; + if (Matte_components) { buf->matte = (uint16_t *)gs_alloc_bytes(ctx->memory, Matte_components * sizeof(uint16_t), "pdf14_push_transparency_mask"); @@ -1684,7 +1834,7 @@ pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect, uint16_t bg_alph /* Soft Mask related information so we know how to compute luminosity when we pop the soft mask */ buf->SMask_SubType = subtype; - if (buf->data != NULL){ + if (buf->data != NULL) { /* We need to initialize it to the BC if it existed */ /* According to the spec, the CS has to be the same */ /* If the back ground component is black, then don't bother @@ -1739,10 +1889,11 @@ static void pdf14_free_mask_stack(pdf14_ctx *ctx, gs_memory_t *memory) static int pdf14_pop_transparency_mask(pdf14_ctx *ctx, gs_gstate *pgs, gx_device *dev) { - pdf14_buf *tos = ctx->stack; + pdf14_buf* tos = ctx->stack; + pdf14_buf* nos = tos->saved; byte *new_data_buf; int icc_match; - cmm_profile_t *des_profile = tos->parent_color_info->icc_profile; /* If set, this should be a gray profile */ + cmm_profile_t *des_profile = nos->group_color_info->icc_profile; /* If set, this should be a gray profile */ cmm_profile_t *src_profile; gsicc_rendering_param_t rendering_params; gsicc_link_t *icc_link; @@ -1756,7 +1907,7 @@ pdf14_pop_transparency_mask(pdf14_ctx *ctx, gs_gstate *pgs, gx_device *dev) /* icc_match == -1 means old non-icc code. icc_match == 0 means use icc code icc_match == 1 mean no conversion needed */ - if ( des_profile != NULL && src_profile != NULL ) { + if (des_profile != NULL && src_profile != NULL ) { icc_match = (des_profile->hashcode == src_profile->hashcode); } else { icc_match = -1; @@ -1838,7 +1989,7 @@ pdf14_pop_transparency_mask(pdf14_ctx *ctx, gs_gstate *pgs, gx_device *dev) global_index++; #endif } else { - if ( icc_match == 1 || tos->n_chan == 2) { + if (icc_match == 1 || tos->n_chan == 2) { #if RAW_DUMP /* Dump the current buffer to see what we have. */ dump_raw_buffer(ctx->memory, @@ -1939,11 +2090,13 @@ pdf14_mask_element_new(gs_memory_t *memory) result = gs_alloc_struct(memory, pdf14_mask_t, &st_pdf14_mask, "pdf14_mask_element_new"); + if (result == NULL) + return NULL; /* Get the reference counted mask */ result->rc_mask = NULL; result->previous = NULL; result->memory = memory; - return(result); + return result; } static int @@ -1961,7 +2114,7 @@ pdf14_push_transparency_state(gx_device *dev, gs_gstate *pgs) /* We need to push the current mask buffer */ /* Allocate a new element for the stack. Don't do anything if there is no mask present.*/ - if ( ctx->mask_stack != NULL ) { + if (ctx->mask_stack != NULL) { new_mask = pdf14_mask_element_new(ctx->memory); /* Duplicate and make the link */ new_mask->rc_mask = ctx->mask_stack->rc_mask; @@ -1972,7 +2125,7 @@ pdf14_push_transparency_state(gx_device *dev, gs_gstate *pgs) #ifdef DEBUG pdf14_debug_mask_stack_state(pdev->ctx); #endif - return(0); + return 0; } static int @@ -2014,25 +2167,25 @@ static int pdf14_open(gx_device *dev) { pdf14_device *pdev = (pdf14_device *)dev; - gs_int_rect rect; - if_debug2m('v', dev->memory, "[v]pdf14_open: width = %d, height = %d\n", - dev->width, dev->height); - rect.p.x = 0; - rect.p.y = 0; - rect.q.x = dev->width; - rect.q.y = dev->height; /* If we are reenabling the device dont create a new ctx. Bug 697456 */ if (pdev->ctx == NULL) { bool has_tags = device_encodes_tags(dev); int bits_per_comp = ((dev->color_info.depth - has_tags*8) / dev->color_info.num_components); - pdev->ctx = pdf14_ctx_new(&rect, dev->color_info.num_components, - pdev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, dev, - bits_per_comp > 8); + pdev->ctx = pdf14_ctx_new(dev, bits_per_comp > 8); + if (pdev->ctx == NULL) + return_error(gs_error_VMerror); + + pdev->ctx->rect.p.x = 0; + pdev->ctx->rect.p.y = 0; + pdev->ctx->rect.q.x = dev->width; + pdev->ctx->rect.q.y = dev->height; + pdev->ctx->has_tags = has_tags; + pdev->ctx->num_spots = pdev->color_info.num_components - pdev->num_std_colorants; + pdev->ctx->additive = (pdev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE); + pdev->ctx->n_chan = pdev->color_info.num_components; } - if (pdev->ctx == NULL) - return_error(gs_error_VMerror); pdev->free_devicen = true; pdev->text_group = PDF14_TEXTGROUP_NO_BT; return 0; @@ -2225,12 +2378,65 @@ pdf14_get_buffer_information(const gx_device * dev, global_index++; #endif } - return(0); + return 0; } typedef void(*blend_image_row_proc_t) (const byte *gs_restrict buf_ptr, int planestride, int width, int num_comp, uint16_t bg, byte *gs_restrict linebuf); + +static int +pdf14_put_image_color_convert(const pdf14_device* dev, gs_gstate* pgs, cmm_profile_t* src_profile, + cmm_dev_profile_t* dev_target_profile, pdf14_buf** buf, + byte** buf_ptr, bool was_blended, int x, int y, int width, int height) +{ + pdf14_buf* cm_result = NULL; + cmm_profile_t* des_profile; + gsicc_rendering_param_t render_cond; + bool did_alloc; + bool big_endian; + + gsicc_extract_profile(GS_UNKNOWN_TAG, dev_target_profile, &des_profile, + &render_cond); + +#if RAW_DUMP + dump_raw_buffer(dev->ctx->memory, + height, width, (*buf)->n_planes, (*buf)->planestride, + (*buf)->rowstride, "pdf14_put_image_color_convert_pre", *buf_ptr, (*buf)->deep); + global_index++; +#endif + + /* If we are doing a 16 bit buffer it will be big endian if we have already done the + blend, otherwise it will be native endian */ + if (was_blended && (*buf)->deep) { + big_endian = true; + } else { + big_endian = false; + } + + cm_result = pdf14_transform_color_buffer_no_matte(pgs, dev->ctx, (gx_device*) dev, *buf, + *buf_ptr, src_profile, des_profile, x, y, width, + height, &did_alloc, (*buf)->deep, big_endian); + + if (cm_result == NULL) + return_error(gs_error_VMerror); + + /* Update */ + *buf = cm_result; + + /* Make sure our buf_ptr is pointing to the proper location */ + if (did_alloc) + *buf_ptr = cm_result->data; /* Note the lack of offset */ + +#if RAW_DUMP + dump_raw_buffer(dev->ctx->memory, + height, width, (*buf)->n_planes, (*buf)->planestride, + (*buf)->rowstride, "pdf14_put_image_color_convert_post", *buf_ptr, (*buf)->deep); + global_index++; +#endif + return 0; +} + /** * pdf14_put_image: Put rendered image to target device. * @pdev: The PDF 1.4 rendering device. @@ -2250,27 +2456,42 @@ pdf14_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) gs_image1_t image; gx_image_enum_common_t *info; pdf14_buf *buf = pdev->ctx->stack; - gs_int_rect rect = buf->rect; + gs_int_rect rect; int y; - int num_comp = buf->n_chan - 1; + int num_comp; byte *linebuf, *linebuf_unaligned; gs_color_space *pcs; int x1, y1, width, height; - byte *buf_ptr, *buf16_ptr = NULL; + byte *buf_ptr; bool data_blended = false; int num_rows_left; - gsicc_rendering_param_t render_cond; - cmm_dev_profile_t *dev_profile; + cmm_profile_t* src_profile = NULL; + cmm_profile_t* des_profile = NULL; + cmm_dev_profile_t *pdf14dev_profile; cmm_dev_profile_t *dev_target_profile; - uint16_t bg = pdev->ctx->additive ? 65535 : 0; + uint16_t bg; bool has_tags = device_encodes_tags(dev); - int bits_per_comp = ((dev->color_info.depth - has_tags*8) / - dev->color_info.num_components); bool deep = pdev->ctx->deep; - bool expand = (!deep && bits_per_comp > 8); - int planestride = buf->planestride; - int rowstride = buf->rowstride; + int planestride; + int rowstride; blend_image_row_proc_t blend_row; + bool color_mismatch = false; + bool supports_alpha = false; + int i; + int alpha_offset, tag_offset; + const byte* buf_ptrs[GS_CLIENT_COLOR_MAX_COMPONENTS]; + + /* Nothing was ever drawn. */ + if (buf == NULL) + return 0; + + bg = buf->group_color_info->isadditive ? 65535 : 0; + src_profile = buf->group_color_info->icc_profile; + + num_comp = buf->n_chan - 1; + rect = buf->rect; + planestride = buf->planestride; + rowstride = buf->rowstride; /* Make sure that this is the only item on the stack. Fuzzing revealed a potential problem. Bug 694190 */ @@ -2288,7 +2509,7 @@ pdf14_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) #endif if (width <= 0 || height <= 0 || buf->data == NULL) return 0; - buf_ptr = buf->data + rect.p.y * rowstride + (rect.p.x<<deep); + buf_ptr = buf->data + (rect.p.y - buf->rect.p.y) * buf->rowstride + ((rect.p.x - buf->rect.p.x) << deep); /* Check that target is OK. From fuzzing results the target could have been destroyed, for e.g if it were a pattern accumulator that was closed @@ -2300,148 +2521,158 @@ pdf14_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) if (dev_target_profile == NULL) return gs_throw_code(gs_error_Fatal); - /* See if the target device can handle the image data directly. If it cannot, then we will need to - use the begin_typed_image interface, which cannot pass along tag nor - alpha data to the target device. */ - { - pdf14_buf *cm_result = NULL; - int alpha_offset, tag_offset; - const byte *buf_ptrs[GS_CLIENT_COLOR_MAX_COMPONENTS]; - int i; + if (src_profile == NULL) { + code = dev_proc(dev, get_profile)(dev, &pdf14dev_profile); + if (code < 0) { + return code; + } + src_profile = pdf14dev_profile->device_profile[0]; + } - /* If we are using a blending color space, take care of that first */ - if (pdev->using_blend_cs) { - cmm_profile_t *src_profile; - cmm_profile_t *des_profile; - bool did_alloc; + /* Check if we have a color conversion issue */ + if (!(src_profile->hash_is_valid)) { + gsicc_get_icc_buff_hash(src_profile->buffer, + &(src_profile->hashcode), + src_profile->buffer_size); + src_profile->hash_is_valid = true; + } - code = dev_proc(dev, get_profile)(dev, &dev_profile); - if (code < 0) { - return code; - } - gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, &src_profile, - &render_cond); - gsicc_extract_profile(GS_UNKNOWN_TAG, dev_target_profile, &des_profile, - &render_cond); + des_profile = dev_target_profile->device_profile[0]; + if (!(des_profile->hash_is_valid)) { + gsicc_get_icc_buff_hash(des_profile->buffer, + &(des_profile->hashcode), + des_profile->buffer_size); + des_profile->hash_is_valid = true; + } + + if (pdev->using_blend_cs || + des_profile->hashcode != src_profile->hashcode) + color_mismatch = true; + + /* Check if target supports alpha */ + supports_alpha = dev_proc(target, dev_spec_op)(target, gxdso_supports_alpha, NULL, 0); + code = 0; #if RAW_DUMP - dump_raw_buffer(pdev->ctx->memory, - height, width, buf->n_planes, planestride, - rowstride, "pre_blend_cs", buf_ptr, deep); - global_index++; + dump_raw_buffer(pdev->ctx->memory, height, width, buf->n_planes, + pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride, + "pre_final_blend", buf_ptr, deep); #endif - cm_result = pdf14_transform_color_buffer_no_matte(pgs, pdev->ctx, dev, buf, - buf_ptr, src_profile, des_profile, rect.p.x, rect.p.y, width, - height, &did_alloc, buf->deep); + /* Note. The logic below will need a little rework if we ever + have a device that has tags and alpha support */ + if (supports_alpha) { + if (!color_mismatch) { + alpha_offset = num_comp; + tag_offset = buf->has_tags ? buf->n_chan : 0; - if (cm_result == NULL) - return_error(gs_error_VMerror); + for (i = 0; i < buf->n_planes; i++) + buf_ptrs[i] = buf_ptr + i * planestride; + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, + rect.p.x, rect.p.y, width, height, + rowstride, alpha_offset, + tag_offset); + /* Right now code has number of rows written */ + } else { + /* In this case, just color convert and maintain alpha. This is a case + where we either either blend in the right color space and have no + alpha for the output device or hand back the wrong color space with + alpha data. We choose the later. */ + code = pdf14_put_image_color_convert(pdev, pgs, src_profile, + dev_target_profile, &buf, &buf_ptr, false, rect.p.x, rect.p.y, + width, height); + if (code < 0) + return code; - /* Based upon our transform, do a bit of updating */ - buf = cm_result; + /* reset */ + rowstride = buf->rowstride; + planestride = buf->planestride; num_comp = buf->n_chan - 1; + alpha_offset = num_comp; + tag_offset = buf->has_tags ? buf->n_chan : 0; - /* Make sure our buf_ptr is pointing to the proper location */ - if (did_alloc) - buf_ptr = cm_result->data; /* Note the lack of offset */ + /* And then out */ + for (i = 0; i < buf->n_planes; i++) + buf_ptrs[i] = buf_ptr + i * planestride; + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, + rect.p.x, rect.p.y, width, height, rowstride, alpha_offset, + tag_offset); + /* Right now code has number of rows written */ + } + } else if (has_tags) { + /* We are going out to a device that supports tags */ + if (deep) { + gx_blend_image_buffer16(buf_ptr, width, height, rowstride, + buf->planestride, num_comp, bg); + } else { + gx_blend_image_buffer(buf_ptr, width, height, rowstride, + buf->planestride, num_comp, bg >> 8); + } + +#if RAW_DUMP + dump_raw_buffer(pdev->ctx->memory, height, width, buf->n_planes, + pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride, + "post_final_blend", buf_ptr, deep); +#endif + + /* Take care of color issues */ + if (color_mismatch) { + /* In this case, just color convert and maintain alpha. This is a case + where we either either blend in the right color space and have no + alpha for the output device or hand back the wrong color space with + alpha data. We choose the later. */ + code = pdf14_put_image_color_convert(pdev, pgs, src_profile, dev_target_profile, + &buf, &buf_ptr, true, rect.p.x, rect.p.y, width, height); + if (code < 0) + return code; #if RAW_DUMP - dump_raw_buffer(pdev->ctx->memory, - height, width, buf->n_planes, planestride, - rowstride, "post_blend_cs", buf_ptr, deep); + dump_raw_buffer(pdev->ctx->memory, height, width, buf->n_planes, + pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride, + "final_color_manage", buf_ptr, deep); global_index++; #endif - /* May need to adjust background value due to color space change */ - if (des_profile->num_comps == 4) - bg = 0; - else - bg = 65535; } - alpha_offset = num_comp; + + /* reset */ + rowstride = buf->rowstride; + planestride = buf->planestride; + num_comp = buf->n_chan - 1; + alpha_offset = 0; /* It is there but this indicates we have done the blend */ tag_offset = buf->has_tags ? buf->n_chan : 0; - /* See if the target device can handle the data with alpha component */ + /* And then out */ for (i = 0; i < buf->n_planes; i++) buf_ptrs[i] = buf_ptr + i * planestride; code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, - rect.p.x, rect.p.y, width, height, - rowstride, alpha_offset, - tag_offset); - if (code == 0) { - /* Device could not handle the alpha data. Go ahead and preblend - now. Note that if we do this, and we end up in the default below, - we only need to repack in chunky not blend */ -#if RAW_DUMP - dump_raw_buffer(pdev->ctx->memory, - height, width, buf->n_planes, - pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride, - "pre_final_blend",buf_ptr,deep); - global_index++; -#endif - if (expand) { - buf16_ptr = gs_alloc_bytes(pdev->memory, - planestride * num_comp * 2, "pdf14_put_image"); - gx_blend_image_buffer8to16(buf_ptr, (unsigned short*) buf16_ptr, - width, height, rowstride, planestride, num_comp, bg>>8); - planestride = planestride * 2; - rowstride = rowstride * 2; - for (i = 0; i < num_comp; i++) - buf_ptrs[i] = buf16_ptr + i * planestride; - } else { - if (deep) { - gx_blend_image_buffer16(buf_ptr, width, height, rowstride, - buf->planestride, num_comp, bg); - } else { - gx_blend_image_buffer(buf_ptr, width, height, rowstride, - buf->planestride, num_comp, bg>>8); - } -#if RAW_DUMP - dump_raw_buffer_be(pdev->ctx->memory, - height, width, buf->n_planes, - pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride, - "post_final_blend", buf_ptr, deep); - global_index++; - clist_band_count++; -#endif - } - data_blended = true; + rect.p.x, rect.p.y, width, height, rowstride, alpha_offset, + tag_offset); + /* Right now code has number of rows written */ + + } - /* Try again now with just the tags */ - alpha_offset = 0; + /* If code > 0 then put image worked. Let it finish and then exit */ + if (code > 0) { + /* We processed some or all of the rows. Continue until we are done */ + num_rows_left = height - code; + while (num_rows_left > 0) { code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, - rect.p.x, rect.p.y, width, height, - rowstride, alpha_offset, - tag_offset); - } - if (code > 0) { - /* We processed some or all of the rows. Continue until we are done */ - num_rows_left = height - code; - while (num_rows_left > 0) { - code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, - rect.p.x, rect.p.y + code, width, - num_rows_left, rowstride, - alpha_offset, tag_offset); - num_rows_left = num_rows_left - code; - } - if (buf16_ptr != NULL) - gs_free_object(pdev->memory, buf16_ptr, "pdf14_put_image"); - return 0; + rect.p.x, rect.p.y + code, width, + num_rows_left, rowstride, + alpha_offset, tag_offset); + num_rows_left = num_rows_left - code; } + return 0; } - /* + /* Target device did not support alpha or tags. * Set color space in preparation for sending an image. + * color conversion will occur after blending with through + * the begin typed image work flow. */ - if (buf16_ptr != NULL) { - /* If we ever hit this, then we've laboriously blended the - * entire image for nothing. Check this doesn't happen in - * normal use. */ - gs_free_object(pdev->memory, buf16_ptr, "pdf14_put_image"); - } + planestride = buf->planestride; rowstride = buf->rowstride; - code = gs_cspace_build_ICC(&pcs, NULL, pgs->memory); if (code < 0) return code; @@ -2452,13 +2683,8 @@ pdf14_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) for the pdf14 device to RGB and the target will be CIELAB. In addition, the case when we have a blend color space that is different than the target device color space */ - code = dev_proc(dev, get_profile)(dev, &dev_profile); - if (code < 0) { - rc_decrement_only_cs(pcs, "pdf14_put_image"); - return code; - } - gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, - &(pcs->cmm_icc_profile_data), &render_cond); + pcs->cmm_icc_profile_data = src_profile; + /* pcs takes a reference to the profile data it just retrieved. */ gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, 1, "pdf14_put_image"); gsicc_set_icc_range(&(pcs->cmm_icc_profile_data)); @@ -2468,6 +2694,7 @@ pdf14_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) image.Width = width; image.Height = height; image.BitsPerComponent = deep ? 16 : 8; + image.ColorSpace = pcs; ctm_only_writable(pgs).xx = (float)width; ctm_only_writable(pgs).xy = 0; ctm_only_writable(pgs).yx = 0; @@ -2556,6 +2783,452 @@ pdf14_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) return code; } +/* This is for the case where we have mixture of spots and additive color. + For example, RGB + spots or Gray + spots */ +static void +gx_blend_image_mixed_buffer(byte* buf_ptr, int width, int height, int rowstride, + int planestride, int num_comp, int spot_start) +{ + int x, y; + int position; + byte comp, a; + int tmp, comp_num; + + for (y = 0; y < height; y++) { + position = y * rowstride; + for (x = 0; x < width; x++) { + a = buf_ptr[position + planestride * num_comp]; + if ((a + 1) & 0xfe) { + a ^= 0xff; + for (comp_num = 0; comp_num < spot_start; comp_num++) { + comp = buf_ptr[position + planestride * comp_num]; + tmp = ((0xff - comp) * a) + 0x80; + comp += (tmp + (tmp >> 8)) >> 8; + buf_ptr[position + planestride * comp_num] = comp; + } + for (comp_num = spot_start; comp_num < num_comp; comp_num++) { + comp = buf_ptr[position + planestride * comp_num]; + tmp = ((-comp) * a) + 0x80; + comp += (tmp + (tmp >> 8)) >> 8; + buf_ptr[position + planestride * comp_num] = comp; + } + } else if (a == 0) { + for (comp_num = 0; comp_num < spot_start; comp_num++) { + buf_ptr[position + planestride * comp_num] = 0xff; + } + for (comp_num = spot_start; comp_num < num_comp; comp_num++) { + buf_ptr[position + planestride * comp_num] = 0; + } + } + position += 1; + } + } +} + +static void +gx_blend_image_mixed_buffer16(byte* buf_ptr_, int width, int height, int rowstride, + int planestride, int num_comp, int spot_start) +{ + uint16_t* buf_ptr = (uint16_t*)(void*)buf_ptr_; + int x, y; + int position; + int comp, a; + int tmp, comp_num; + + /* planestride and rowstride are in bytes, and we want them in shorts */ + planestride >>= 1; + rowstride >>= 1; + + /* Note that the input here is native endian, and the output must be in big endian! */ + for (y = 0; y < height; y++) { + position = y * rowstride; + for (x = 0; x < width; x++) { + /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ + a = buf_ptr[position + planestride * num_comp]; + if (a == 0) { + for (comp_num = 0; comp_num < spot_start; comp_num++) { + buf_ptr[position + planestride * comp_num] = 0xffff; + } + for (comp_num = spot_start; comp_num < num_comp; comp_num++) { + buf_ptr[position + planestride * comp_num] = 0; + } + } else if (a == 0xffff) { +#if ARCH_IS_BIG_ENDIAN +#else + /* Convert from native -> big endian */ + for (comp_num = 0; comp_num < num_comp; comp_num++) { + comp = buf_ptr[position + planestride * comp_num]; + ((byte*)&buf_ptr[position + planestride * comp_num])[0] = comp >> 8; + ((byte*)&buf_ptr[position + planestride * comp_num])[1] = comp; + } +#endif + } else { + a ^= 0xffff; + a += a >> 15; /* a is now 0 to 0x10000 */ + a >>= 1; /* We can only use 15 bits as bg-comp has a sign bit we can't lose */ + for (comp_num = 0; comp_num < spot_start; comp_num++) { + comp = buf_ptr[position + planestride * comp_num]; + tmp = ((0xffff - comp) * a) + 0x4000; + comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */ + /* Store as big endian */ + ((byte*)&buf_ptr[position + planestride * comp_num])[0] = comp >> 8; + ((byte*)&buf_ptr[position + planestride * comp_num])[1] = comp; + } + for (comp_num = spot_start; comp_num < num_comp; comp_num++) { + comp = buf_ptr[position + planestride * comp_num]; + tmp = ((0 - comp) * a) + 0x4000; + comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */ + /* Store as big endian */ + ((byte*)&buf_ptr[position + planestride * comp_num])[0] = comp >> 8; + ((byte*)&buf_ptr[position + planestride * comp_num])[1] = comp; + } + } + position += 1; + } + } +} + +static int +pdf14_put_blended_image_cmykspot(gx_device* dev, gx_device* target, + gs_gstate* pgs, pdf14_buf* buf, int planestride_in, + int rowstride_in, int x0, int y0, int width, int height, + int num_comp, uint16_t bg, bool has_tags, gs_int_rect rect_in, + gs_separations* pseparations, bool deep) +{ + const pdf14_device* pdev = (pdf14_device*)dev; + int code = 0; + int x, y, tmp, comp_num, output_comp_num; + gx_color_index color; + gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS]; + gx_color_value comp; + int input_map[GX_DEVICE_COLOR_MAX_COMPONENTS]; + int output_map[GX_DEVICE_COLOR_MAX_COMPONENTS]; + int num_known_comp = 0; + int output_num_comp = target->color_info.num_components; + int num_sep = pseparations->num_separations++; + int num_rows_left; + int i; + gx_drawing_color pdcolor; + gs_int_rect rect = rect_in; + gs_fixed_rect rect_fixed; + int planestride = planestride_in; + int rowstride = rowstride_in; + byte* buf_ptr = NULL; + cmm_profile_t* src_profile = buf->group_color_info->icc_profile; + cmm_profile_t* des_profile = NULL; + cmm_dev_profile_t* dev_target_profile; + cmm_dev_profile_t* pdf14dev_profile; + bool color_mismatch = false; + bool supports_alpha = false; + const byte* buf_ptrs[GS_CLIENT_COLOR_MAX_COMPONENTS]; + int alpha_offset = num_comp; + int tag_offset = has_tags ? num_comp + 1 : 0; + + /* + * The process color model for the PDF 1.4 compositor device is CMYK plus + * spot colors. The target device may have only some of these colorants due + * to the SeparationOrder device parameter. Thus we need to determine the + * mapping between the PDF 1.4 compositor and the target device. Note: + * There should not be a spot colorant in the PDF 1.4 device that is not + * present in the target device. + */ + /* Check if target processes CMYK colorants. */ + for (comp_num = 0; comp_num < 4; comp_num++) { + const char* pcomp_name = (const char*)DeviceCMYKComponents[comp_num]; + + output_comp_num = dev_proc(target, get_color_comp_index) + (target, pcomp_name, strlen(pcomp_name), NO_COMP_NAME_TYPE); + if (output_comp_num >= 0 && + output_comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS) { + output_map[num_known_comp] = output_comp_num; + input_map[num_known_comp++] = comp_num; + } + } + /* Check if target processes our spot colorants. */ + for (comp_num = 0; comp_num < num_sep; comp_num++) { + output_comp_num = dev_proc(target, get_color_comp_index) + (target, (const char*)(pseparations->names[comp_num].data), + pseparations->names[comp_num].size, NO_COMP_NAME_TYPE); + if (output_comp_num >= 0 && + output_comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS) { + output_map[num_known_comp] = output_comp_num; + input_map[num_known_comp++] = comp_num + 4; + } + } + + /* Check if group color space is CMYK based */ + code = dev_proc(target, get_profile)(target, &dev_target_profile); + if (code < 0) + return code; + if (dev_target_profile == NULL) + return gs_throw_code(gs_error_Fatal); + + if (src_profile == NULL) { + code = dev_proc(dev, get_profile)(dev, &pdf14dev_profile); + if (code < 0) { + return code; + } + src_profile = pdf14dev_profile->device_profile[0]; + } + + /* Check if we have a color conversion issue */ + if (!(src_profile->hash_is_valid)) { + gsicc_get_icc_buff_hash(src_profile->buffer, + &(src_profile->hashcode), + src_profile->buffer_size); + src_profile->hash_is_valid = true; + } + + des_profile = dev_target_profile->device_profile[0]; + if (!(des_profile->hash_is_valid)) { + gsicc_get_icc_buff_hash(des_profile->buffer, + &(des_profile->hashcode), + des_profile->buffer_size); + des_profile->hash_is_valid = true; + } + + if (pdev->using_blend_cs || + des_profile->hashcode != src_profile->hashcode) + color_mismatch = true; + + /* Check if target supports alpha */ + supports_alpha = dev_proc(target, dev_spec_op)(target, gxdso_supports_alpha, NULL, 0); + code = 0; + + buf_ptr = buf->data + (rect.p.y - buf->rect.p.y) * buf->rowstride + ((rect.p.x - buf->rect.p.x) << deep); + + /* Note. The logic below will need a little rework if we ever + have a device that has tags and alpha support */ + if (supports_alpha) { + if (!color_mismatch) { + for (i = 0; i < buf->n_planes; i++) + buf_ptrs[i] = buf_ptr + i * planestride; + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, + rect.p.x, rect.p.y, width, height, + rowstride, alpha_offset, tag_offset); + /* Right now code has number of rows written */ + } else { + /* In this case, just color convert and maintain alpha. + This is a case where we either either blend in the + right color space and have no alpha for the output + device or hand back the wrong color space with + alpha data. We choose the later. */ + code = pdf14_put_image_color_convert(pdev, pgs, src_profile, + dev_target_profile, &buf, &buf_ptr, false, rect.p.x, + rect.p.y, width, height); + if (code < 0) + return code; + + /* reset */ + rowstride = buf->rowstride; + planestride = buf->planestride; + num_comp = buf->n_chan - 1; + alpha_offset = num_comp; + tag_offset = buf->has_tags ? buf->n_chan : 0; + + /* And then out */ + for (i = 0; i < buf->n_planes; i++) + buf_ptrs[i] = buf_ptr + i * planestride; + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, + rect.p.x, rect.p.y, width, height, rowstride, alpha_offset, + tag_offset); + /* Right now code has number of rows written */ + } + } else { + /* Device could not handle the alpha data (we actually don't have + a device that does spot colorants and has an alpha channel so + the above code is untested. Go ahead and + preblend now and then color convert if needed */ +#if RAW_DUMP + /* Dump before and after the blend to make sure we are doing that ok */ + dump_raw_buffer(target->memory, height, width, num_comp + 1, planestride, rowstride, + "pre_final_blend", buf_ptr, deep); + global_index++; +#endif + if (color_mismatch && (src_profile->data_cs == gsRGB || src_profile->data_cs == gsGRAY)) { + if (deep) { + gx_blend_image_mixed_buffer16(buf_ptr, width, height, rowstride, + planestride, num_comp, src_profile->num_comps); + } else { + gx_blend_image_mixed_buffer(buf_ptr, width, height, rowstride, + planestride, num_comp, src_profile->num_comps); + } + } else { + if (deep) { + gx_blend_image_buffer16(buf_ptr, width, height, rowstride, + planestride, num_comp, bg); + } else { + gx_blend_image_buffer(buf_ptr, width, height, rowstride, + planestride, num_comp, bg >> 8); + } + } + + if (color_mismatch) { + code = pdf14_put_image_color_convert(pdev, pgs, src_profile, dev_target_profile, + &buf, &buf_ptr, true, rect.p.x, rect.p.y, width, height); + if (code < 0) + return code; + + /* reset */ + rowstride = buf->rowstride; + planestride = buf->planestride; + num_comp = buf->n_chan - 1; + alpha_offset = num_comp; + tag_offset = buf->has_tags ? buf->n_chan : 0; + } + + +#if RAW_DUMP + /* Dump before and after the blend to make sure we are doing that ok */ + dump_raw_buffer_be(target->memory, height, width, num_comp, planestride, rowstride, + "post_final_blend", buf_ptr, deep); + global_index++; + /* clist_band_count++; */ +#endif + /* Try put_image again now */ + alpha_offset = 0; + for (i = 0; i < buf->n_planes; i++) + buf_ptrs[i] = buf_ptr + i * planestride; + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, + rect.p.x, rect.p.y, width, height, + rowstride, alpha_offset, tag_offset); + } + if (code > 0) { + /* We processed some or all of the rows. Continue until we are done */ + num_rows_left = height - code; + while (num_rows_left > 0) { + code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, + rect.p.x, rect.p.y + code, width, + num_rows_left, rowstride, + alpha_offset, tag_offset); + if (code < 0) { + return code; + } + num_rows_left = num_rows_left - code; + } + return 0; + } + + /* No put_image working at all. Resort to fill_rect */ + + planestride = planestride_in; + rowstride = rowstride_in; + + /* Clear all output colorants first */ + for (comp_num = 0; comp_num < output_num_comp; comp_num++) + cv[comp_num] = 0; + + /* Send pixel data to the target device. */ + if (deep) { + /* NOTE: buf_ptr points to big endian data */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + + /* composite CMYKA, etc. pixel with over solid background */ +#define GET16_BE2NATIVE(v) \ +((((byte *)&(v))[0]<<8) | (((byte *)&(v))[1])) + uint16_t a = GET16_BE2NATIVE(buf_ptr[x + planestride * num_comp]); + + if (a == 0) { + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + cv[output_map[comp_num]] = bg; + } + } else if (a == 0xffff) { + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + comp = GET16_BE2NATIVE(buf_ptr[x + planestride * input_map[comp_num]]); + cv[output_map[comp_num]] = comp; + } + } else { + /* a ^= 0xff; */ /* No inversion here! Bug 689895 */ + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + comp = GET16_BE2NATIVE(buf_ptr[x + planestride * input_map[comp_num]]); + tmp = ((comp - bg) * a) + 0x8000; + comp += (tmp + (tmp >> 16)) >> 16; + cv[output_map[comp_num]] = comp; + } + } + + /* If we have spot colors we need to encode and fill as a high level + color if the device supports it which should always be the case + if we are in this procedure */ + if (dev_proc(target, dev_spec_op)(target, gxdso_supports_devn, NULL, 0)) { + for (i = 0; i < output_num_comp; i++) { + pdcolor.colors.devn.values[i] = cv[i]; + } + pdcolor.type = gx_dc_type_devn; + rect_fixed.p.x = int2fixed(x + x0); + rect_fixed.p.y = int2fixed(y + y0); + rect_fixed.q.x = int2fixed(x + x0 + 1); + rect_fixed.q.y = int2fixed(y + y0 + 1); + code = dev_proc(target, fill_rectangle_hl_color)(target, &rect_fixed, + NULL, &pdcolor, NULL); + } else { + /* encode as a color index */ + color = dev_proc(target, encode_color)(target, cv); + code = dev_proc(target, fill_rectangle)(target, x + x0, y + y0, 1, 1, color); + } + if (code < 0) + return code; + } + + buf_ptr += rowstride; + } + } else { + bg >>= 8; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + + /* composite CMYKA, etc. pixel with over solid background */ + byte a = buf_ptr[x + planestride * num_comp]; + + if ((a + 1) & 0xfe) { + /* a ^= 0xff; */ /* No inversion here! Bug 689895 */ + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + comp = buf_ptr[x + planestride * input_map[comp_num]]; + tmp = ((comp - bg) * a) + 0x80; + comp += tmp + (tmp >> 8); + cv[output_map[comp_num]] = comp; + } + } else if (a == 0) { + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + cv[output_map[comp_num]] = bg; + } + } else { + for (comp_num = 0; comp_num < num_known_comp; comp_num++) { + comp = buf_ptr[x + planestride * input_map[comp_num]]; + cv[output_map[comp_num]] = (comp << 8) + comp; + } + } + + /* If we have spot colors we need to encode and fill as a high level + color if the device supports it which should always be the case + if we are in this procedure */ + if (dev_proc(target, dev_spec_op)(target, gxdso_supports_devn, NULL, 0)) { + for (i = 0; i < output_num_comp; i++) { + pdcolor.colors.devn.values[i] = cv[i]; + } + pdcolor.type = gx_dc_type_devn; + rect_fixed.p.x = int2fixed(x + x0); + rect_fixed.p.y = int2fixed(y + y0); + rect_fixed.q.x = int2fixed(x + x0 + 1); + rect_fixed.q.y = int2fixed(y + y0 + 1); + code = dev_proc(target, fill_rectangle_hl_color)(target, &rect_fixed, + NULL, &pdcolor, NULL); + } else { + /* encode as a color index */ + color = dev_proc(target, encode_color)(target, cv); + code = dev_proc(target, fill_rectangle)(target, x + x0, y + y0, 1, 1, color); + } + if (code < 0) + return code; + } + + buf_ptr += rowstride; + } + } + return code; +} + /** * pdf14_cmykspot_put_image: Put rendered image to target device. * @pdev: The PDF 1.4 rendering device. @@ -2568,20 +3241,29 @@ pdf14_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) * Return code: negative on error. **/ static int -pdf14_cmykspot_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) +pdf14_cmykspot_put_image(gx_device *dev, gs_gstate *pgs, gx_device *target) { - pdf14_device * pdev = (pdf14_device *)dev; + pdf14_device *pdev = (pdf14_device *)dev; pdf14_buf *buf = pdev->ctx->stack; - gs_int_rect rect = buf->rect; + gs_int_rect rect; int x1, y1, width, height; - gs_devn_params * pdevn_params = &pdev->devn_params; - gs_separations * pseparations = &pdevn_params->separations; - int planestride = buf->planestride; - int rowstride = buf->rowstride; + gs_devn_params *pdevn_params = &pdev->devn_params; + gs_separations *pseparations = &pdevn_params->separations; + int planestride; + int rowstride; bool deep = pdev->ctx->deep; - const uint16_t bg = pdev->ctx->additive ? 65535 : 0; - int num_comp = buf->n_chan - 1; - byte *buf_ptr; + uint16_t bg; + int num_comp; + + /* Nothing was ever drawn. */ + if (buf == NULL) + return 0; + + bg = buf->group_color_info->isadditive ? 65535 : 0; + num_comp = buf->n_chan - 1; + rect = buf->rect; + planestride = buf->planestride; + rowstride = buf->rowstride; /* Make sure that this is the only item on the stack. Fuzzing revealed a potential problem. Bug 694190 */ @@ -2596,7 +3278,7 @@ pdf14_cmykspot_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) height = y1 - rect.p.y; if (width <= 0 || height <= 0 || buf->data == NULL) return 0; - buf_ptr = buf->data + rect.p.y * buf->rowstride + (rect.p.x<<deep); + #if RAW_DUMP /* Dump the current buffer to see what we have. */ dump_raw_buffer(pdev->ctx->memory, @@ -2610,7 +3292,9 @@ pdf14_cmykspot_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) global_index++; clist_band_count++; #endif - return gx_put_blended_image_cmykspot(target, buf_ptr, planestride, rowstride, + + return pdf14_put_blended_image_cmykspot(dev, target, pgs, + buf, planestride, rowstride, rect.p.x, rect.p.y, width, height, num_comp, bg, buf->has_tags, rect, pseparations, deep); } @@ -2632,15 +3316,27 @@ pdf14_custom_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) pdf14_device * pdev = (pdf14_device *)dev; pdf14_buf *buf = pdev->ctx->stack; bool deep = pdev->ctx->deep; - gs_int_rect rect = buf->rect; - int x0 = rect.p.x, y0 = rect.p.y; - int planestride = buf->planestride; - int rowstride = buf->rowstride; - int num_comp = buf->n_chan - 1; - const uint16_t bg = pdev->ctx->additive ? 0xffff : 0; + gs_int_rect rect; + int x0, y0; + int planestride; + int rowstride; + int num_comp; + uint16_t bg; int x1, y1, width, height; byte *buf_ptr; + /* Nothing was ever drawn. */ + if (buf == NULL) + return 0; + + bg = pdev->ctx->additive ? 0xffff : 0; + num_comp = buf->n_chan - 1; + rect = buf->rect; + x0 = rect.p.x; + y0 = rect.p.y; + planestride = buf->planestride; + rowstride = buf->rowstride; + /* Make sure that this is the only item on the stack. Fuzzing revealed a potential problem. Bug 694190 */ if (buf->saved != NULL) { @@ -2654,7 +3350,7 @@ pdf14_custom_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) height = y1 - rect.p.y; if (width <= 0 || height <= 0 || buf->data == NULL) return 0; - buf_ptr = buf->data + rect.p.y * buf->rowstride + (rect.p.x<<deep); + buf_ptr = buf->data + (rect.p.y - buf->rect.p.y) * buf->rowstride + ((rect.p.x - buf->rect.p.x)<<deep); return gx_put_blended_image_custom(target, buf_ptr, planestride, rowstride, @@ -2665,16 +3361,16 @@ pdf14_custom_put_image(gx_device * dev, gs_gstate * pgs, gx_device * target) * of one or more groups, we have to cycle through any ICC profile changes since the push * putting everything back how it was, and cleaning up the reference counts. */ -static void pdf14_cleanup_parent_color_profiles (pdf14_device *pdev) +static void pdf14_cleanup_group_color_profiles (pdf14_device *pdev) { - if (pdev->ctx) { + if (pdev->ctx && pdev->ctx->stack) { pdf14_buf *buf, *next; - for (buf = pdev->ctx->stack; buf != NULL; buf = next) { - pdf14_parent_color_t *old_parent_color_info = buf->parent_color_info; + for (buf = pdev->ctx->stack->saved; buf != NULL; buf = next) { + pdf14_group_color_t *group_color_info = buf->group_color_info; next = buf->saved; - while (old_parent_color_info) { - if (old_parent_color_info->icc_profile != NULL) { + while (group_color_info) { + if (group_color_info->icc_profile != NULL) { cmm_profile_t *group_profile; gsicc_rendering_param_t render_cond; cmm_dev_profile_t *dev_profile; @@ -2685,12 +3381,12 @@ static void pdf14_cleanup_parent_color_profiles (pdf14_device *pdev) &render_cond); gsicc_adjust_profile_rc(pdev->icc_struct->device_profile[0], -1, "pdf14_end_transparency_group"); - pdev->icc_struct->device_profile[0] = old_parent_color_info->icc_profile; - old_parent_color_info->icc_profile = NULL; + pdev->icc_struct->device_profile[0] = group_color_info->icc_profile; + group_color_info->icc_profile = NULL; } } - old_parent_color_info = old_parent_color_info->previous; + group_color_info = group_color_info->previous; } } } @@ -2701,7 +3397,7 @@ pdf14_close(gx_device *dev) { pdf14_device *pdev = (pdf14_device *)dev; - pdf14_cleanup_parent_color_profiles (pdev); + pdf14_cleanup_group_color_profiles(pdev); if (pdev->ctx) { pdf14_ctx_free(pdev->ctx); @@ -2720,7 +3416,7 @@ pdf14_discard_trans_layer(gx_device *dev, gs_gstate * pgs) /* The things that need to be cleaned up */ pdf14_ctx *ctx = pdev->ctx; pdf14_smaskcolor_t *smaskcolor = pdev->smaskcolor; - pdf14_parent_color_t *group_procs = pdev->trans_group_parent_cmap_procs; + pdf14_group_color_t *group_color = pdev->color_model_stack; /* Free up the smask color */ if (smaskcolor != NULL) { @@ -2730,17 +3426,17 @@ pdf14_discard_trans_layer(gx_device *dev, gs_gstate * pgs) } /* Free up the nested color procs and decrement the profiles */ - if (group_procs != NULL) { - while (group_procs->previous != NULL) - pdf14_pop_parent_color(dev, pgs); - gs_free_object(dev->memory->stable_memory, group_procs, "pdf14_discard_trans_layer"); - pdev->trans_group_parent_cmap_procs = NULL; + if (group_color != NULL) { + while (group_color->previous != NULL) + pdf14_pop_group_color(dev, pgs); + gs_free_object(dev->memory->stable_memory, group_color, "pdf14_discard_trans_layer"); + pdev->color_model_stack = NULL; } /* Start the context clean up */ if (ctx != NULL) { pdf14_buf *buf, *next; - pdf14_parent_color_t *procs, *prev_procs; + pdf14_group_color_t *procs, *prev_procs; if (ctx->mask_stack != NULL) { pdf14_free_mask_stack(ctx, ctx->memory); @@ -2758,14 +3454,14 @@ pdf14_discard_trans_layer(gx_device *dev, gs_gstate * pgs) the ctx to the tos mask_stack. We are done with this now so it is safe to free this one object */ gs_free_object(ctx->memory, buf->mask_stack, "pdf14_discard_trans_layer"); - for (procs = buf->parent_color_info; procs != NULL; procs = prev_procs) { + for (procs = buf->group_color_info; procs != NULL; procs = prev_procs) { prev_procs = procs->previous; gs_free_object(ctx->memory, procs, "pdf14_discard_trans_layer"); } gs_free_object(ctx->memory, buf, "pdf14_discard_trans_layer"); } /* Finally the context itself */ - gs_free_object (ctx->memory, ctx, "pdf14_discard_trans_layer"); + gs_free_object(ctx->memory, ctx, "pdf14_discard_trans_layer"); pdev->ctx = NULL; } return 0; @@ -2994,6 +3690,8 @@ push_shfill_group(pdf14_clist_device *pdev, gs_rect cb; gs_gstate fudged_pgs = *pgs; + params.shade_group = true; + /* gs_begin_transparency_group takes a bbox that it then * transforms by ctm. Our bbox has already been transformed, * so clear out the ctm. */ @@ -3010,6 +3708,7 @@ push_shfill_group(pdf14_clist_device *pdev, params.Isolated = false; params.Knockout = true; + params.page_group = false; params.group_opacity = fudged_pgs.fillconstantalpha; params.group_shape = 1.0; code = gs_begin_transparency_group(&fudged_pgs, ¶ms, &cb, PDF14_BEGIN_TRANS_GROUP); @@ -3050,6 +3749,11 @@ pdf14_fill_path(gx_device *dev, const gs_gstate *pgs, gs_pattern2_instance_t *pinst = NULL; int push_group = 0; + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, pgs); + if (code < 0) + return code; + if (pdcolor == NULL) return_error(gs_error_unknownerror); /* color must be defined */ if (gx_dc_is_pattern1_color(pdcolor)){ @@ -3177,6 +3881,12 @@ pdf14_stroke_path(gx_device *dev, const gs_gstate *pgs, if (pdcolor == NULL) return_error(gs_error_unknownerror); /* color must be defined */ + + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, pgs); + if (code < 0) + return code; + if (gx_dc_is_pattern2_color(pdcolor)) { /* Non-idempotent blends require a transparency * group to be pushed because shadings might @@ -3278,6 +3988,11 @@ pdf14_fill_stroke_path(gx_device *dev, const gs_gstate *cpgs, gx_path *ppath, (pgs->ctm.xx == 0.0 && pgs->ctm.xy == 0.0 && pgs->ctm.yx == 0.0 && pgs->ctm.yy == 0.0)) return 0; + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, cpgs); + if (code < 0) + return code; + code = gx_curr_fixed_bbox(pgs, &clip_bbox, NO_PATH); if (code < 0 && code != gs_error_unknownerror) return code; @@ -3321,8 +4036,9 @@ pdf14_fill_stroke_path(gx_device *dev, const gs_gstate *cpgs, gx_path *ppath, compatible overprint mode. Group will be composited with original alpha and blend mode */ params.Isolated = false; - params.group_color = UNKNOWN; + params.group_color_type = UNKNOWN; params.Knockout = false; + params.page_group = false; params.group_opacity = 1.0; params.group_shape = fill_alpha; @@ -3353,8 +4069,9 @@ pdf14_fill_stroke_path(gx_device *dev, const gs_gstate *cpgs, gx_path *ppath, /* Push a non-isolated knockout group. Do not change the alpha or blend modes. Note: we need to draw those that have alpha = 0 */ params.Isolated = false; - params.group_color = UNKNOWN; + params.group_color_type = UNKNOWN; params.Knockout = true; + params.page_group = false; params.group_shape = 1.0; params.group_opacity = 1.0; @@ -3811,6 +4528,12 @@ pdf14_copy_alpha_color(gx_device * dev, const byte * data, int data_x, int depth, bool devn) { bool deep = device_is_deep(dev); + int code; + + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, NULL); + if (code < 0) + return code; if (deep) return do_pdf14_copy_alpha_color_16(dev, data, data_x, aa_raster, @@ -3841,6 +4564,12 @@ pdf14_fill_mask(gx_device * orig_dev, if (pdcolor == NULL) return_error(gs_error_unknownerror); /* color must be defined */ + + code = pdf14_initialize_ctx(orig_dev, orig_dev->color_info.num_components, + orig_dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, NULL); + if (code < 0) + return code; + /* If we are doing a fill with a pattern that has a transparency then go ahead and do a push and a pop of the transparency group */ if (gx_dc_is_pattern1_color(pdcolor)) { @@ -3874,9 +4603,15 @@ pdf14_fill_mask(gx_device * orig_dev, group_rect.q.x = x + w; group_rect.q.y = y + h; if (!(w <= 0 || h <= 0)) { + + pdf14_group_color_t *group_color_info = pdf14_clone_group_color_info((gx_device *) p14dev, p14dev->ctx->stack->group_color_info); + if (group_color_info == NULL) + return gs_error_VMerror; + code = pdf14_push_transparency_group(p14dev->ctx, &group_rect, 1, 0, 65535, 65535, 65535, ptile->blending_mode, 0, 0, - ptile->ttrans->n_chan-1, false, NULL, NULL, NULL, NULL); + ptile->ttrans->n_chan-1, false, false, NULL, NULL, + group_color_info, NULL, NULL); if (code < 0) return code; /* Set up the output buffer information now that we have @@ -3921,6 +4656,8 @@ pdf14_fill_mask(gx_device * orig_dev, return code; } + + /* Used for filling rects when we are doing a fill with a pattern that has transparency */ static int @@ -3944,6 +4681,7 @@ pdf14_tile_pattern_fill(gx_device * pdev, const gs_gstate * pgs, gx_clip_path cpath_intersection; gx_path path_ttrans; gs_blend_mode_t blend_mode; + pdf14_group_color_t *group_color_info; if (ppath == NULL) return_error(gs_error_unknownerror); /* should not happen */ @@ -4026,11 +4764,15 @@ pdf14_tile_pattern_fill(gx_device * pdev, const gs_gstate * pgs, } blend_mode = ptile->blending_mode; memcpy(&save_pdf14_dev, p14dev, sizeof(pdf14_device)); + + group_color_info = pdf14_clone_group_color_info(pdev, p14dev->ctx->stack->group_color_info); + if (group_color_info == NULL) + return gs_error_VMerror; + code = pdf14_push_transparency_group(p14dev->ctx, &rect, 1, 0, (uint16_t)floor(65535 * p14dev->alpha + 0.5), - (uint16_t)floor(65535 * p14dev->shape + 0.5), (uint16_t)floor(65535 * p14dev->opacity + 0.5), - blend_mode, 0, 0, n_chan_tile-1, - false, NULL, NULL, pgs_noconst, - pdev); + (uint16_t)floor(65535 * p14dev->shape + 0.5), (uint16_t)floor(65535 * p14dev->opacity + 0.5), + blend_mode, 0, 0, n_chan_tile - 1, false, false, + NULL, NULL, group_color_info, pgs_noconst, pdev); if (code < 0) return code; @@ -4269,18 +5011,22 @@ pdf14_patt_trans_image_fill(gx_device * dev, const gs_gstate * pgs, if_debug2m('v', p14dev->ctx->memory, "[v*] Pushing trans group patt_trans_image_fill, uid = %ld id = %ld \n", ptile->uid.id, ptile->id); + code = pdf14_push_transparency_group(p14dev->ctx, &group_rect, 1, 0, 65535, 65535, 65535, pgs->blend_mode, 0, 0, - ptile->ttrans->n_chan-1, false, NULL, - NULL, (gs_gstate *)pgs, dev); + ptile->ttrans->n_chan-1, false, false, + NULL, NULL, NULL, (gs_gstate *)pgs, dev); + /* Set up the output buffer information now that we have pushed the group */ fill_trans_buffer = new_pattern_trans_buff(pgs->memory); pdf14_get_buffer_information(dev, fill_trans_buffer, NULL, false); + /* Store this in the appropriate place in pdcolor. This is released later in pdf14_pattern_trans_render when we are all done with the mask fill */ ptile->ttrans->fill_trans_buffer = fill_trans_buffer; + /* Change the renderer to handle this case so we can catch the end. We will then pop the group and reset the pdcolor proc. Keep the base renderer also. */ @@ -4303,6 +5049,11 @@ pdf14_begin_typed_image(gx_device * dev, const gs_gstate * pgs, const gs_image_t *pim = (const gs_image_t *)pic; int code; + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, pgs); + if (code < 0) + return code; + /* If we are filling an image mask with a pattern that has a transparency then we need to do some special handling */ if (pim->ImageMask) { @@ -4989,6 +5740,7 @@ pdf14_push_text_group(gx_device *dev, gs_gstate *pgs, mode are correct */ params.Isolated = false; params.Knockout = true; + params.page_group = false; params.text_group = PDF14_TEXTGROUP_BT_PUSHED; params.group_opacity = 1.0; params.group_shape = 1.0; @@ -5033,6 +5785,11 @@ pdf14_text_begin(gx_device * dev, gs_gstate * pgs, bool text_stroke = (text_mode == 1 || text_mode == 2 || text_mode == 5 || text_mode == 6); bool text_fill = (text_mode == 0 || text_mode == 2 || text_mode == 4 || text_mode == 6); + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, (const gs_gstate*) pgs); + if (code < 0) + return code; + if_debug0m('v', memory, "[v]pdf14_text_begin\n"); pdf14_set_marking_params(dev, pgs); code = gx_default_text_begin(dev, pgs, text, font, path, pdcolor, pcpath, @@ -5083,7 +5840,7 @@ pdf14_finish_copydevice(gx_device *new_dev, const gx_device *from_dev) pdf14_device *pdev = (pdf14_device*)new_dev; pdev->ctx = NULL; - pdev->trans_group_parent_cmap_procs = NULL; + pdev->color_model_stack = NULL; pdev->smaskcolor = NULL; /* Only allow copying the prototype. */ @@ -5210,7 +5967,7 @@ pdf14_copy_planes(gx_device * dev, const byte * data, int data_x, int raster, fake_tos.n_chan = dev->color_info.num_components; fake_tos.n_planes = dev->color_info.num_components; fake_tos.num_spots = 0; - fake_tos.parent_color_info = NULL; + fake_tos.group_color_info = NULL; fake_tos.planestride = raster * plane_height; fake_tos.rect.p.x = x; fake_tos.rect.p.y = y; @@ -5232,11 +5989,18 @@ pdf14_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect, const gx_clip_path *pcpath) { pdf14_device *pdev = (pdf14_device *)dev; - pdf14_buf *buf = pdev->ctx->stack; + pdf14_buf* buf; + int code; int x = fixed2int(rect->p.x); int y = fixed2int(rect->p.y); int w = fixed2int(rect->q.x) - x; - int h = fixed2int(rect->q.y) -y; + int h = fixed2int(rect->q.y) - y; + + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, pgs); + if (code < 0) + return code; + buf = pdev->ctx->stack; fit_fill_xywh(dev, x, y, w, h); if (w <= 0 || h <= 0) @@ -5253,7 +6017,15 @@ pdf14_fill_rectangle(gx_device * dev, int x, int y, int w, int h, gx_color_index color) { pdf14_device *pdev = (pdf14_device *)dev; - pdf14_buf *buf = pdev->ctx->stack; + pdf14_buf *buf; + int code; + + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, NULL); + if (code < 0) + return code; + + buf = pdev->ctx->stack; fit_fill_xywh(dev, x, y, w, h); if (w <= 0 || h <= 0) @@ -5300,59 +6072,64 @@ compute_group_device_int_rect(pdf14_device *pdev, gs_int_rect *rect, } static int -pdf14_begin_transparency_group(gx_device *dev, - const gs_transparency_group_params_t *ptgp, - const gs_rect *pbbox, - gs_gstate *pgs, gs_memory_t *mem) +pdf14_begin_transparency_group(gx_device* dev, + const gs_transparency_group_params_t* ptgp, + const gs_rect* pbbox, + gs_gstate* pgs, gs_memory_t* mem) { - pdf14_device *pdev = (pdf14_device *)dev; + pdf14_device* pdev = (pdf14_device*)dev; double alpha = ptgp->group_opacity * ptgp->group_shape; gs_int_rect rect; int code; bool isolated = ptgp->Isolated; - gs_transparency_color_t group_color; - cmm_profile_t *group_profile; - cmm_profile_t *tos_profile; + gs_transparency_color_t group_color_type; + cmm_profile_t* group_profile; + cmm_profile_t* tos_profile; gsicc_rendering_param_t render_cond; - cmm_dev_profile_t *dev_profile; + cmm_dev_profile_t* dev_profile; bool cm_back_drop = false; bool new_icc = false; + pdf14_group_color_t* group_color_info; - code = dev_proc(dev, get_profile)(dev, &dev_profile); + code = dev_proc(dev, get_profile)(dev, &dev_profile); if (code < 0) return code; gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, &tos_profile, &render_cond); if (ptgp->text_group == PDF14_TEXTGROUP_BT_PUSHED) { - rect = pdev->ctx->rect; /* Use parent group for text_group. */ pdev->text_group = PDF14_TEXTGROUP_BT_PUSHED; /* For immediate mode and clist reading */ - } else + } + + if (ptgp->text_group == PDF14_TEXTGROUP_BT_PUSHED) + rect = pdev->ctx->rect; /* Use parent group for text_group. */ + else code = compute_group_device_int_rect(pdev, &rect, pbbox, pgs); if (code < 0) return code; - if_debug4m('v', pdev->memory, - "[v]pdf14_begin_transparency_group, I = %d, K = %d, alpha = %g, bm = %d\n", - ptgp->Isolated, ptgp->Knockout, alpha, pgs->blend_mode); + if_debug5m('v', pdev->memory, + "[v]pdf14_begin_transparency_group, I = %d, K = %d, alpha = %g, bm = %d page_group = %d\n", + ptgp->Isolated, ptgp->Knockout, alpha, pgs->blend_mode, ptgp->page_group); /* If the group color is unknown then use the current device profile. */ - if (ptgp->group_color == UNKNOWN){ - group_color = ICC; + if (ptgp->group_color_type == UNKNOWN) { + group_color_type = ICC; group_profile = tos_profile; - } else { - group_color = ptgp->group_color; + } + else { + group_color_type = ptgp->group_color_type; group_profile = ptgp->iccprofile; } /* We have to handle case where the profile is in the clist */ if (group_profile == NULL && pdev->pclist_device != NULL) { /* Get the serialized data from the clist. */ - gx_device_clist_reader *pcrdev = (gx_device_clist_reader *)(pdev->pclist_device); - group_profile = gsicc_read_serial_icc((gx_device *) pcrdev, ptgp->icc_hashcode); + gx_device_clist_reader* pcrdev = (gx_device_clist_reader*)(pdev->pclist_device); + group_profile = gsicc_read_serial_icc((gx_device*)pcrdev, ptgp->icc_hashcode); if (group_profile == NULL) return gs_throw(gs_error_unknownerror, "ICC data not found in clist"); /* Keep a pointer to the clist device */ - group_profile->dev = (gx_device *) pcrdev; + group_profile->dev = (gx_device*)pcrdev; new_icc = true; } if (group_profile != NULL) { @@ -5360,8 +6137,8 @@ pdf14_begin_transparency_group(gx_device *dev, we will need to CM the backdrop. */ if (!(group_profile->hash_is_valid)) { gsicc_get_icc_buff_hash(group_profile->buffer, - &(group_profile->hashcode), - group_profile->buffer_size); + &(group_profile->hashcode), + group_profile->buffer_size); group_profile->hash_is_valid = true; } if (group_profile->hashcode != tos_profile->hashcode) { @@ -5369,93 +6146,122 @@ pdf14_begin_transparency_group(gx_device *dev, } } - code = pdf14_update_device_color_procs(dev, group_color, ptgp->icc_hashcode, - pgs, group_profile, false); + /* Always create the base color group information as it is only through + groups that we can have a color space change. This will survive + the life of the context. */ + if (pdev->ctx->base_color == NULL) { + pdev->ctx->base_color = pdf14_make_base_group_color(dev); + } + + /* If this is not the page group and we don't yet have a group, we need + to create a buffer for the whole page so that we can handle stuff drawn + outside this current group (e.g. two non inclusive groups drawn independently) */ + if (pdev->ctx->stack == NULL && !ptgp->page_group) { + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, NULL); + if (code < 0) + return code; + pdev->ctx->stack->isolated = true; + } + + group_color_info = pdf14_push_color_model(dev, group_color_type, ptgp->icc_hashcode, + group_profile, false); + if (group_color_info == NULL) + return gs_error_VMerror; + if_debug0m('v', dev->memory, "[v]Transparency group color space update\n"); if (code < 0) return code; + code = pdf14_push_transparency_group(pdev->ctx, &rect, isolated, ptgp->Knockout, (uint16_t)floor (65535 * alpha + 0.5), (uint16_t)floor(65535 * ptgp->group_shape + 0.5), (uint16_t)floor(65535 * ptgp->group_opacity + 0.5), pgs->blend_mode, ptgp->idle, ptgp->mask_id, pdev->color_info.num_components, - cm_back_drop, group_profile, tos_profile, - pgs, dev); + cm_back_drop, ptgp->shade_group, + group_profile, tos_profile, group_color_info, pgs, dev); if (new_icc) gsicc_adjust_profile_rc(group_profile, -1, "pdf14_begin_transparency_group"); return code; } +static void +pdf14_pop_color_model(gx_device* dev, pdf14_group_color_t* group_color) +{ + pdf14_device* pdev = (pdf14_device*)dev; + + if (group_color != NULL && + !(group_color->group_color_mapping_procs == NULL && + group_color->group_color_comp_index == NULL)) { + set_dev_proc(pdev, get_color_mapping_procs, group_color->group_color_mapping_procs); + set_dev_proc(pdev, get_color_comp_index, group_color->group_color_comp_index); + pdev->color_info.polarity = group_color->polarity; + pdev->color_info.num_components = group_color->num_components; + pdev->blend_procs = group_color->blend_procs; + pdev->ctx->additive = group_color->isadditive; + pdev->pdf14_procs = group_color->unpack_procs; + pdev->color_info.depth = group_color->depth; + pdev->color_info.max_color = group_color->max_color; + pdev->color_info.max_gray = group_color->max_gray; + memcpy(&(pdev->color_info.comp_bits), &(group_color->comp_bits), + GX_DEVICE_COLOR_MAX_COMPONENTS); + memcpy(&(pdev->color_info.comp_shift), &(group_color->comp_shift), + GX_DEVICE_COLOR_MAX_COMPONENTS); + if (group_color->icc_profile != NULL) { + /* make sure to decrement the device profile. If it was allocated + with the push then it will be freed. */ + gsicc_adjust_profile_rc(pdev->icc_struct->device_profile[0], -1, + "pdf14_pop_color_model"); + pdev->icc_struct->device_profile[0] = group_color->icc_profile; + } + } +} + static int -pdf14_end_transparency_group(gx_device *dev, - gs_gstate *pgs) +pdf14_end_transparency_group(gx_device* dev, gs_gstate* pgs) { - pdf14_device *pdev = (pdf14_device *)dev; + pdf14_device* pdev = (pdf14_device*)dev; int code; - pdf14_parent_color_t *parent_color; - cmm_profile_t *group_profile; + cmm_profile_t* group_profile; gsicc_rendering_param_t render_cond; - cmm_dev_profile_t *dev_profile; + cmm_dev_profile_t* dev_profile; - code = dev_proc(dev, get_profile)(dev, &dev_profile); + code = dev_proc(dev, get_profile)(dev, &dev_profile); if (code < 0) return code; + gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, &group_profile, - &render_cond); + &render_cond); if_debug0m('v', dev->memory, "[v]pdf14_end_transparency_group\n"); + code = pdf14_pop_transparency_group(pgs, pdev->ctx, pdev->blend_procs, - pdev->color_info.num_components, group_profile, - (gx_device *) pdev); + pdev->color_info.num_components, group_profile, (gx_device*)pdev); #ifdef DEBUG pdf14_debug_mask_stack_state(pdev->ctx); #endif - /* May need to reset some color stuff related - * to a mismatch between the parents color space - * and the group blending space */ - parent_color = pdev->ctx->stack->parent_color_info; - if (!(parent_color->parent_color_mapping_procs == NULL && - parent_color->parent_color_comp_index == NULL)) { - pgs->get_cmap_procs = parent_color->get_cmap_procs; - gx_set_cmap_procs(pgs, dev); - set_dev_proc(pdev, get_color_mapping_procs, parent_color->parent_color_mapping_procs); - set_dev_proc(pdev, get_color_comp_index, parent_color->parent_color_comp_index); - pdev->color_info.polarity = parent_color->polarity; - pdev->color_info.num_components = parent_color->num_components; - pdev->blend_procs = parent_color->parent_blending_procs; - pdev->ctx->additive = parent_color->isadditive; - pdev->pdf14_procs = parent_color->unpack_procs; - pdev->color_info.depth = parent_color->depth; - pdev->color_info.max_color = parent_color->max_color; - pdev->color_info.max_gray = parent_color->max_gray; - memcpy(&(pdev->color_info.comp_bits),&(parent_color->comp_bits), - GX_DEVICE_COLOR_MAX_COMPONENTS); - memcpy(&(pdev->color_info.comp_shift),&(parent_color->comp_shift), - GX_DEVICE_COLOR_MAX_COMPONENTS); - parent_color->get_cmap_procs = NULL; - parent_color->parent_color_comp_index = NULL; - parent_color->parent_color_mapping_procs = NULL; - if (parent_color->icc_profile != NULL) { - /* make sure to decrement the device profile. If it was allocated - with the push then it will be freed. */ - gsicc_adjust_profile_rc(dev->icc_struct->device_profile[0], -1, "pdf14_end_transparency_group"); - dev->icc_struct->device_profile[0] = parent_color->icc_profile; - parent_color->icc_profile = NULL; - } + /* If this group is the base group, then restore the color model + of the device at this time. Note that during the actual device pop + we will need to use the profile of the buffer not the pdf14 device + as the source color space */ + if (pdev->ctx->stack->group_popped) { + pdf14_pop_color_model(dev, pdev->ctx->base_color); + } else { + pdf14_pop_color_model(dev, pdev->ctx->stack->group_color_info); } + return code; } -static int -pdf14_update_device_color_procs(gx_device *dev, - gs_transparency_color_t group_color, - int64_t icc_hashcode, gs_gstate *pgs, - cmm_profile_t *iccprofile, bool is_mask) +static pdf14_group_color_t* +pdf14_push_color_model(gx_device *dev, gs_transparency_color_t group_color_type, + int64_t icc_hashcode, cmm_profile_t *iccprofile, + bool is_mask) { pdf14_device *pdevproto = NULL; pdf14_device *pdev = (pdf14_device *)dev; const pdf14_procs_t *new_14procs = NULL; - pdf14_parent_color_t *parent_color_info; + pdf14_group_color_t *group_color; gx_color_polarity_t new_polarity; uchar new_num_comps; bool new_additive; @@ -5464,37 +6270,19 @@ pdf14_update_device_color_procs(gx_device *dev, byte comp_shift[GX_DEVICE_COLOR_MAX_COMPONENTS]; int k; bool has_tags = device_encodes_tags(dev); - gsicc_rendering_param_t render_cond; - cmm_dev_profile_t *dev_profile; bool deep = pdev->ctx->deep; - if (pdev->ctx->stack != NULL){ - parent_color_info = pdev->ctx->stack->parent_color_info; - } else { - /* This should not occur */ - return_error(gs_error_undefined); - } - if_debug0m('v', dev->memory, "[v]pdf14_update_device_color_procs\n"); + if_debug0m('v', dev->memory, "[v]pdf14_push_color_model\n"); - memset(comp_bits, 0, GX_DEVICE_COLOR_MAX_COMPONENTS); - memset(comp_shift, 0, GX_DEVICE_COLOR_MAX_COMPONENTS); + group_color = gs_alloc_struct(dev->memory->stable_memory, + pdf14_group_color_t, &st_pdf14_clr, + "pdf14_push_color_model"); + if (group_color == NULL) + return NULL; + + memset(group_color, 0, sizeof(pdf14_group_color_t)); - /* Update the device procs at this stage. Many of the procs are based upon - the color space of the device. We want to remain in the color space - defined by the color space of the soft mask or transparency group as - opposed to the device color space. Later, when we pop the softmask we will - collapse it to a single band and then compose with it to the device color - space (or the parent layer space). In the case where we pop an isolated - transparency group, we will do the blending in the proper color space and - then transform the data when we pop the group. Remember that only isolated - groups can have color spaces that are different than their parent. - Separation devices that have to maintain separate spot color planes need - special handling here */ - parent_color_info->get_cmap_procs = NULL; - parent_color_info->parent_color_mapping_procs = NULL; - parent_color_info->parent_color_comp_index = NULL; - - switch (group_color) { + switch (group_color_type) { case GRAY_SCALE: new_polarity = GX_CINFO_POLARITY_ADDITIVE; new_num_comps = 1; @@ -5543,16 +6331,19 @@ pdf14_update_device_color_procs(gx_device *dev, iccprofile = gsicc_read_serial_icc((gx_device *) pcrdev, icc_hashcode); if (iccprofile == NULL) - return gs_throw(gs_error_unknownerror, "ICC data not found in clist"); + return NULL; /* Keep a pointer to the clist device */ iccprofile->dev = (gx_device *) pcrdev; } else { /* Go ahead and rc increment right now. This way when we pop, we will make sure to decrement and avoid a - leak for the above profile that we just created */ + leak for the above profile that we just created. This + goes with the assignment to the device's profile. + Note that we still do the increment for the group_color + assignment below. */ if (iccprofile == NULL) - return gs_throw(gs_error_unknownerror, "ICC data unknown"); - gsicc_adjust_profile_rc(iccprofile, 1, "pdf14_update_device_color_procs"); + return NULL; + gsicc_adjust_profile_rc(iccprofile, 1, "pdf14_push_color_model"); } new_num_comps = iccprofile->num_comps; if (new_num_comps == 4) { @@ -5602,48 +6393,25 @@ pdf14_update_device_color_procs(gx_device *dev, } break; default: - return_error(gs_error_rangecheck); + return NULL; break; } break; default: - return_error(gs_error_rangecheck); + return NULL; break; } - /* Save the old information */ - parent_color_info->get_cmap_procs = pgs->get_cmap_procs; - parent_color_info->parent_color_mapping_procs = - dev_proc(pdev, get_color_mapping_procs); - parent_color_info->parent_color_comp_index = - dev_proc(pdev, get_color_comp_index); - parent_color_info->parent_blending_procs = pdev->blend_procs; - parent_color_info->polarity = pdev->color_info.polarity; - parent_color_info->num_components = pdev->color_info.num_components; - parent_color_info->isadditive = pdev->ctx->additive; - parent_color_info->unpack_procs = pdev->pdf14_procs; - parent_color_info->depth = pdev->color_info.depth; - parent_color_info->max_color = pdev->color_info.max_color; - parent_color_info->max_gray = pdev->color_info.max_gray; - parent_color_info->encode = dev_proc(pdev, encode_color); - parent_color_info->decode = dev_proc(pdev, decode_color); - memcpy(&(parent_color_info->comp_bits), &(pdev->color_info.comp_bits), - GX_DEVICE_COLOR_MAX_COMPONENTS); - memcpy(&(parent_color_info->comp_shift), &(pdev->color_info.comp_shift), - GX_DEVICE_COLOR_MAX_COMPONENTS); - - /* Don't increment the space since we are going to remove it from the - ICC manager anyway. */ - if (group_color == ICC && iccprofile != NULL) { - dev_proc(dev, get_profile)(dev, &dev_profile); - gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, - &(parent_color_info->icc_profile), &render_cond); - } - /* Set new information */ + + if (group_color_type == ICC && iccprofile != NULL) { + group_color->icc_profile = iccprofile; + gsicc_adjust_profile_rc(iccprofile, 1, "pdf14_push_color_model"); + } + /* If we are a sep device and this is not a softmask, ensure we maintain the spot colorants and know how to index into them */ if (pdev->sep_device && !is_mask) { - int num_spots = parent_color_info->num_components - - parent_color_info->icc_profile->num_comps; + int num_spots = dev->color_info.num_components - + dev->icc_struct->device_profile[0]->num_comps; if (num_spots > 0) { new_num_comps += num_spots; @@ -5653,16 +6421,19 @@ pdf14_update_device_color_procs(gx_device *dev, } } } + + /* Set device values now and store settings in group_color. Then they + are available when we pop the previous group */ if_debug2m('v', pdev->memory, - "[v]pdf14_update_device_color_procs,num_components_old = %d num_components_new = %d\n", + "[v]pdf14_push_color_model, num_components_old = %d num_components_new = %d\n", pdev->color_info.num_components,new_num_comps); set_dev_proc(pdev, get_color_mapping_procs, pdevproto->static_procs->get_color_mapping_procs); set_dev_proc(pdev, get_color_comp_index, pdevproto->static_procs->get_color_comp_index); - pdev->blend_procs = pdevproto->blend_procs; - pdev->color_info.polarity = new_polarity; - pdev->color_info.num_components = new_num_comps; - pdev->ctx->additive = new_additive; - pdev->pdf14_procs = new_14procs; + group_color->blend_procs = pdev->blend_procs = pdevproto->blend_procs; + group_color->polarity = pdev->color_info.polarity = new_polarity; + group_color->num_components = pdev->color_info.num_components = new_num_comps; + group_color->isadditive = pdev->ctx->additive = new_additive; + group_color->unpack_procs = pdev->pdf14_procs = new_14procs; pdev->color_info.depth = new_num_comps * (8<<deep); memset(&(pdev->color_info.comp_bits), 0, GX_DEVICE_COLOR_MAX_COMPONENTS); memset(&(pdev->color_info.comp_shift), 0, GX_DEVICE_COLOR_MAX_COMPONENTS); @@ -5672,34 +6443,43 @@ pdf14_update_device_color_procs(gx_device *dev, pdev->color_info.comp_shift[pdev->color_info.num_components] = pdev->color_info.depth; pdev->color_info.depth += 8; } - pdev->color_info.max_color = deep ? 65535 : 255; - pdev->color_info.max_gray = deep ? 65535 : 255; + group_color->max_color = pdev->color_info.max_color = deep ? 65535 : 255; + group_color->max_gray = pdev->color_info.max_gray = deep ? 65535 : 255; + group_color->depth = pdev->color_info.depth; + group_color->decode = dev_proc(pdev, decode_color); + group_color->encode = dev_proc(pdev, encode_color); + group_color->group_color_mapping_procs = dev_proc(pdev, get_color_mapping_procs); + group_color->group_color_comp_index = dev_proc(pdev, get_color_comp_index); + memcpy(&(group_color->comp_bits), &(pdev->color_info.comp_bits), + GX_DEVICE_COLOR_MAX_COMPONENTS); + memcpy(&(group_color->comp_shift), &(pdev->color_info.comp_shift), + GX_DEVICE_COLOR_MAX_COMPONENTS); + group_color->get_cmap_procs = pdf14_get_cmap_procs; + /* If the CS was ICC based, we need to update the device ICC profile in the ICC manager, since that is the profile that is used for the PDF14 device */ - if (group_color == ICC && iccprofile != NULL) { + if (group_color_type == ICC && iccprofile != NULL) { /* iccprofile was incremented above if we had not just created it. When we do the pop we will decrement and if we just created it, it will be destroyed */ dev->icc_struct->device_profile[0] = iccprofile; } - return 1; /* Lets us detect that we did do an update */ + return group_color; } -/* A new version that works with the color_procs stack - for transparency groups */ static int -pdf14_update_device_color_procs_push_c(gx_device *dev, - gs_transparency_color_t group_color, - int64_t icc_hashcode, - gs_gstate *pgs, - cmm_profile_t *icc_profile, - bool is_mask) -{ - pdf14_device *pdevproto; - pdf14_device *pdev = (pdf14_device *)dev; - gx_device_clist_writer * cldev = (gx_device_clist_writer *)pdev->pclist_device; - const pdf14_procs_t *new_14procs; +pdf14_clist_push_color_model(gx_device *dev, gx_device* cdev, gs_gstate *pgs, + const gs_pdf14trans_t *pdf14pct, gs_memory_t* mem, + bool is_mask) +{ + pdf14_device* pdev = (pdf14_device*)dev; + pdf14_group_color_t* new_group_color; + gsicc_rendering_param_t render_cond; + cmm_dev_profile_t* dev_profile; + pdf14_device* pdevproto; + gx_device_clist_writer* cldev = (gx_device_clist_writer*)pdev->pclist_device; + const pdf14_procs_t* new_14procs; bool update_color_info; gx_color_polarity_t new_polarity; int new_num_comps; @@ -5709,146 +6489,192 @@ pdf14_update_device_color_procs_push_c(gx_device *dev, byte comp_shift[GX_DEVICE_COLOR_MAX_COMPONENTS]; int k; bool has_tags = device_encodes_tags(dev); - cmm_profile_t *icc_profile_dev = NULL; - gsicc_rendering_param_t render_cond; - cmm_dev_profile_t *dev_profile; bool deep = device_is_deep(dev); + gs_transparency_color_t group_color_type = pdf14pct->params.group_color_type; + cmm_profile_t *new_profile = pdf14pct->params.iccprofile; + cmm_profile_t *old_profile = NULL; + + dev_proc(dev, get_profile)(dev, &dev_profile); + gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, &old_profile, + &render_cond); + if_debug0m('v', dev->memory, "[v]pdf14_clist_push_color_model\n"); + + /* Allocate a new one */ + new_group_color = gs_alloc_struct(dev->memory->stable_memory, pdf14_group_color_t, + &st_pdf14_clr, "pdf14_clist_push_color_model"); + + /* Link to old one */ + new_group_color->previous = pdev->color_model_stack; + + /* Reassign new one to dev */ + pdev->color_model_stack = new_group_color; + + /* Initialize with values */ + new_group_color->get_cmap_procs = pgs->get_cmap_procs; + new_group_color->group_color_mapping_procs = + dev_proc(pdev, get_color_mapping_procs); + new_group_color->group_color_comp_index = + dev_proc(pdev, get_color_comp_index); + new_group_color->blend_procs = pdev->blend_procs; + new_group_color->polarity = pdev->color_info.polarity; + new_group_color->num_components = pdev->color_info.num_components; + new_group_color->unpack_procs = pdev->pdf14_procs; + new_group_color->depth = pdev->color_info.depth; + new_group_color->max_color = pdev->color_info.max_color; + new_group_color->max_gray = pdev->color_info.max_gray; + new_group_color->decode = dev_proc(pdev, decode_color); + new_group_color->encode = dev_proc(pdev, encode_color); + memcpy(&(new_group_color->comp_bits), &(pdev->color_info.comp_bits), + GX_DEVICE_COLOR_MAX_COMPONENTS); + memcpy(&(new_group_color->comp_shift), &(pdev->color_info.comp_shift), + GX_DEVICE_COLOR_MAX_COMPONENTS); + + if (new_profile == NULL) + new_group_color->icc_profile = NULL; + + /* isadditive is only used in ctx */ + if (pdev->ctx) { + new_group_color->isadditive = pdev->ctx->additive; + } memset(comp_bits, 0, GX_DEVICE_COLOR_MAX_COMPONENTS); memset(comp_shift, 0, GX_DEVICE_COLOR_MAX_COMPONENTS); - if (group_color == ICC && icc_profile == NULL) + if (group_color_type == ICC && new_profile == NULL) return gs_throw(gs_error_undefinedresult, "Missing ICC data"); - if_debug0m('v', cldev->memory, "[v]pdf14_update_device_color_procs_push_c\n"); - /* Check if we need to alter the device procs at this stage. Many of the procs - are based upon the color space of the device. We want to remain in the - color space defined by the color space of the soft mask or transparency - group as opposed to the device color space. Later, when we pop the softmask - we will collapse it to a single band and then compose with it to the device - color space (or the parent layer space). In the case where we pop an - isolated transparency group, we will do the blending in the proper color - space and then transform the data when we pop the group. Remember that only - isolated groups can have color spaces that are different than their parent. */ + if_debug0m('v', cldev->memory, "[v]pdf14_clist_push_color_model\n"); + /* Check if we need to alter the device procs at this stage. Many of the procs + are based upon the color space of the device. We want to remain in the + color space defined by the color space of the soft mask or transparency + group as opposed to the device color space. Later, when we pop the softmask + we will collapse it to a single band and then compose with it to the device + color space (or the parent layer space). In the case where we pop an + isolated transparency group, we will do the blending in the proper color + space and then transform the data when we pop the group. Remember that only + isolated groups can have color spaces that are different than their parent. */ update_color_info = false; - switch (group_color) { - case GRAY_SCALE: - if (pdev->color_info.num_components != 1){ - update_color_info = true; + switch (group_color_type) { + case GRAY_SCALE: + if (pdev->color_info.num_components != 1) { + update_color_info = true; + new_polarity = GX_CINFO_POLARITY_ADDITIVE; + new_num_comps = 1; + pdevproto = (pdf14_device*)&gs_pdf14_Gray_device; + new_additive = true; + new_14procs = &gray_pdf14_procs; + new_depth = 8 << deep; + comp_bits[0] = 8 << deep; + comp_shift[0] = 0; + } + break; + case DEVICE_RGB: + case CIE_XYZ: + if (pdev->color_info.num_components != 3) { + update_color_info = true; + new_polarity = GX_CINFO_POLARITY_ADDITIVE; + new_num_comps = 3; + pdevproto = (pdf14_device*)&gs_pdf14_RGB_device; + new_additive = true; + new_14procs = &rgb_pdf14_procs; + new_depth = 24 << deep; + for (k = 0; k < 3; k++) { + comp_bits[k] = 8 << deep; + comp_shift[k] = (2 - k) * (8 << deep); + } + } + break; + case DEVICE_CMYK: + if (pdev->color_info.num_components != 4) { + update_color_info = true; + new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE; + new_num_comps = 4; + pdevproto = (pdf14_device*)&gs_pdf14_CMYK_device; + new_additive = false; + /* This is needed due to the mismatched compressed encode decode + between the device procs and the pdf14 procs */ + if (dev->color_info.num_components > 4) { + new_14procs = &cmykspot_pdf14_procs; + } + else { + new_14procs = &cmyk_pdf14_procs; + } + new_depth = 32 << deep; + for (k = 0; k < 4; k++) { + comp_bits[k] = 8 << deep; + comp_shift[k] = (3 - k) * (8 << deep); + } + } + break; + case ICC: + /* Check if the profile is different. */ + if (old_profile->hashcode != new_profile->hashcode) { + update_color_info = true; + new_num_comps = new_profile->num_comps; + new_depth = new_profile->num_comps * (8 << deep); + switch (new_num_comps) { + case 1: + if (pdev->sep_device && !is_mask) { + pdevproto = (pdf14_device*)&gs_pdf14_Grayspot_device; + new_14procs = &grayspot_pdf14_procs; + } + else { + pdevproto = (pdf14_device*)&gs_pdf14_Gray_device; + new_14procs = &gray_pdf14_procs; + } new_polarity = GX_CINFO_POLARITY_ADDITIVE; - new_num_comps = 1; - pdevproto = (pdf14_device *)&gs_pdf14_Gray_device; new_additive = true; - new_14procs = &gray_pdf14_procs; - new_depth = 8<<deep; - comp_bits[0] = 8<<deep; + comp_bits[0] = 8 << deep; comp_shift[0] = 0; - } - break; - case DEVICE_RGB: - case CIE_XYZ: - if (pdev->color_info.num_components != 3){ - update_color_info = true; + break; + case 3: + if (pdev->sep_device) { + pdevproto = (pdf14_device*)&gs_pdf14_RGBspot_device; + new_14procs = &rgbspot_pdf14_procs; + } + else { + pdevproto = (pdf14_device*)&gs_pdf14_RGB_device; + new_14procs = &rgb_pdf14_procs; + } new_polarity = GX_CINFO_POLARITY_ADDITIVE; - new_num_comps = 3; - pdevproto = (pdf14_device *)&gs_pdf14_RGB_device; new_additive = true; - new_14procs = &rgb_pdf14_procs; - new_depth = 24<<deep; for (k = 0; k < 3; k++) { - comp_bits[k] = 8<<deep; - comp_shift[k] = (2-k)*(8<<deep); + comp_bits[k] = 8 << deep; + comp_shift[k] = (2 - k) * (8 << deep); } - } - break; - case DEVICE_CMYK: - if (pdev->color_info.num_components != 4){ - update_color_info = true; - new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE; - new_num_comps = 4; - pdevproto = (pdf14_device *)&gs_pdf14_CMYK_device; - new_additive = false; - /* This is needed due to the mismatched compressed encode decode - between the device procs and the pdf14 procs */ - if (dev->color_info.num_components > 4){ + break; + case 4: + if (pdev->sep_device) { + pdevproto = (pdf14_device*)&gs_pdf14_CMYKspot_device; new_14procs = &cmykspot_pdf14_procs; - } else { + } + else { + pdevproto = (pdf14_device*)&gs_pdf14_CMYK_device; new_14procs = &cmyk_pdf14_procs; } - new_depth = 32<<deep; + new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE; + new_additive = false; for (k = 0; k < 4; k++) { - comp_bits[k] = 8<<deep; - comp_shift[k] = (3-k)*(8<<deep); - } - } - break; - case ICC: - /* Check if the profile is different. */ - dev_proc(dev, get_profile)(dev, &dev_profile); - gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, - &icc_profile_dev, &render_cond); - if (icc_profile_dev->hashcode != icc_profile->hashcode) { - update_color_info = true; - new_num_comps = icc_profile->num_comps; - new_depth = icc_profile->num_comps * (8<<deep); - switch (new_num_comps) { - case 1: - if (pdev->sep_device && !is_mask) { - pdevproto = (pdf14_device *)&gs_pdf14_Grayspot_device; - new_14procs = &grayspot_pdf14_procs; - } else { - pdevproto = (pdf14_device *)&gs_pdf14_Gray_device; - new_14procs = &gray_pdf14_procs; - } - new_polarity = GX_CINFO_POLARITY_ADDITIVE; - new_additive = true; - comp_bits[0] = 8<<deep; - comp_shift[0] = 0; - break; - case 3: - if (pdev->sep_device) { - pdevproto = (pdf14_device *)&gs_pdf14_RGBspot_device; - new_14procs = &rgbspot_pdf14_procs; - } else { - pdevproto = (pdf14_device *)&gs_pdf14_RGB_device; - new_14procs = &rgb_pdf14_procs; - } - new_polarity = GX_CINFO_POLARITY_ADDITIVE; - new_additive = true; - for (k = 0; k < 3; k++) { - comp_bits[k] = 8<<deep; - comp_shift[k] = (2-k)*(8<<deep); - } - break; - case 4: - if (pdev->sep_device) { - pdevproto = (pdf14_device *)&gs_pdf14_CMYKspot_device; - new_14procs = &cmykspot_pdf14_procs; - } else { - pdevproto = (pdf14_device *)&gs_pdf14_CMYK_device; - new_14procs = &cmyk_pdf14_procs; - } - new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE; - new_additive = false; - for (k = 0; k < 4; k++) { - comp_bits[k] = 8<<deep; - comp_shift[k] = (3-k)*(8<<deep); - } - break; - default: - return gs_throw(gs_error_undefinedresult, - "ICC Number of colorants illegal"); + comp_bits[k] = 8 << deep; + comp_shift[k] = (3 - k) * (8 << deep); } + break; + default: + return gs_throw(gs_error_undefinedresult, + "ICC Number of colorants illegal"); } - break; - case UNKNOWN: - return 0; - break; - default: - return_error(gs_error_rangecheck); - break; + } + break; + case UNKNOWN: + return 0; + break; + default: + return_error(gs_error_rangecheck); + break; } if (!update_color_info) { + /* Profile not updated */ + new_group_color->icc_profile = NULL; if_debug0m('v', pdev->memory, "[v]procs not updated\n"); return 0; } @@ -5856,26 +6682,26 @@ pdf14_update_device_color_procs_push_c(gx_device *dev, if (pdev->sep_device && !is_mask) { int num_spots; - if (icc_profile_dev == NULL) + if (old_profile == NULL) return_error(gs_error_undefined); - num_spots = pdev->color_info.num_components - icc_profile_dev->num_comps; + num_spots = pdev->color_info.num_components - old_profile->num_comps; if (num_spots > 0) { new_num_comps += num_spots; for (k = 0; k < new_num_comps; k++) { - comp_bits[k] = 8<<deep; - comp_shift[k] = (new_num_comps - k - 1) * (8<<deep); + comp_bits[k] = 8 << deep; + comp_shift[k] = (new_num_comps - k - 1) * (8 << deep); } - new_depth = (8<<deep) * new_num_comps; + new_depth = (8 << deep) * new_num_comps; } } if (has_tags) { new_depth += 8; } if_debug2m('v', pdev->memory, - "[v]pdf14_update_device_color_procs_push_c,num_components_old = %d num_components_new = %d\n", - pdev->color_info.num_components,new_num_comps); + "[v]pdf14_clist_push_color_model, num_components_old = %d num_components_new = %d\n", + pdev->color_info.num_components, new_num_comps); /* Set new information in the device */ set_dev_proc(pdev, get_color_mapping_procs, pdevproto->static_procs->get_color_mapping_procs); set_dev_proc(pdev, get_color_comp_index, pdevproto->static_procs->get_color_comp_index); @@ -5886,8 +6712,8 @@ pdf14_update_device_color_procs_push_c(gx_device *dev, pdev->color_info.max_gray = deep ? 65535 : 255; pdev->pdf14_procs = new_14procs; pdev->color_info.depth = new_depth; - memset(&(pdev->color_info.comp_bits),0,GX_DEVICE_COLOR_MAX_COMPONENTS); - memset(&(pdev->color_info.comp_shift),0,GX_DEVICE_COLOR_MAX_COMPONENTS); + memset(&(pdev->color_info.comp_bits), 0, GX_DEVICE_COLOR_MAX_COMPONENTS); + memset(&(pdev->color_info.comp_shift), 0, GX_DEVICE_COLOR_MAX_COMPONENTS); memcpy(&(pdev->color_info.comp_bits), comp_bits, new_num_comps); memcpy(&(pdev->color_info.comp_shift), comp_shift, new_num_comps); pdev->color_info.comp_shift[new_num_comps] = new_depth - 8; /* in case we has_tags is set */ @@ -5905,55 +6731,55 @@ pdf14_update_device_color_procs_push_c(gx_device *dev, cldev->clist_color_info.max_color = pdev->color_info.max_color; cldev->clist_color_info.max_gray = pdev->color_info.max_gray; /* For the ICC profiles, we want to update the ICC profile for the - device in the ICC manager. We already stored in in pdf14_parent_color_t. + device. We store the original in group_color. That will be stored in the clist and restored during the reading phase. */ - if (group_color == ICC) { - gsicc_adjust_profile_rc(icc_profile, 1, "pdf14_update_device_color_procs_push_c"); - gsicc_adjust_profile_rc(dev->icc_struct->device_profile[0], -1, "pdf14_update_device_color_procs_push_c"); - dev->icc_struct->device_profile[0] = icc_profile; + if (group_color_type == ICC) { + gsicc_adjust_profile_rc(new_profile, 1, "pdf14_clist_push_color_model"); + new_group_color->icc_profile = dev->icc_struct->device_profile[0]; + dev->icc_struct->device_profile[0] = new_profile; } if (pdev->ctx) { pdev->ctx->additive = new_additive; } - return(1); /* Lets us detect that we did do an update */ + return 1; /* Lets us detect that we did do an update */ } static int -pdf14_update_device_color_procs_pop_c(gx_device *dev,gs_gstate *pgs) +pdf14_clist_pop_color_model(gx_device *dev, gs_gstate *pgs) { pdf14_device *pdev = (pdf14_device *)dev; - pdf14_parent_color_t *parent_color = pdev->trans_group_parent_cmap_procs; + pdf14_group_color_t *group_color = pdev->color_model_stack; gx_device_clist_writer * cldev = (gx_device_clist_writer *)pdev->pclist_device; - if (parent_color == NULL) + if (group_color == NULL) return_error(gs_error_unknownerror); /* Unmatched group pop */ - if_debug0m('v', pdev->memory, "[v]pdf14_update_device_color_procs_pop_c\n"); + if_debug0m('v', pdev->memory, "[v]pdf14_clist_pop_color_model\n"); /* The color procs are always pushed. Simply restore them. */ - if (parent_color->parent_color_mapping_procs == NULL && - parent_color->parent_color_comp_index == NULL) { - if_debug0m('v', dev->memory, "[v]pdf14_update_device_color_procs_pop_c ERROR \n"); + if (group_color->group_color_mapping_procs == NULL && + group_color->group_color_comp_index == NULL) { + if_debug0m('v', dev->memory, "[v]pdf14_clist_pop_color_model ERROR \n"); } else { if_debug2m('v', pdev->memory, - "[v]pdf14_update_device_color_procs_pop_c,num_components_old = %d num_components_new = %d\n", - pdev->color_info.num_components,parent_color->num_components); - pgs->get_cmap_procs = parent_color->get_cmap_procs; + "[v]pdf14_clist_pop_color_model, num_components_old = %d num_components_new = %d\n", + pdev->color_info.num_components,group_color->num_components); + pgs->get_cmap_procs = group_color->get_cmap_procs; gx_set_cmap_procs(pgs, dev); - set_dev_proc(pdev, get_color_mapping_procs, parent_color->parent_color_mapping_procs); - set_dev_proc(pdev, get_color_comp_index, parent_color->parent_color_comp_index); - pdev->color_info.polarity = parent_color->polarity; - pdev->color_info.depth = parent_color->depth; - pdev->color_info.num_components = parent_color->num_components; - pdev->blend_procs = parent_color->parent_blending_procs; - pdev->pdf14_procs = parent_color->unpack_procs; - pdev->color_info.max_color = parent_color->max_color; - pdev->color_info.max_gray = parent_color->max_gray; - set_dev_proc(pdev, encode_color, parent_color->encode); - set_dev_proc(pdev, decode_color, parent_color->decode); - memcpy(&(pdev->color_info.comp_bits),&(parent_color->comp_bits), + set_dev_proc(pdev, get_color_mapping_procs, group_color->group_color_mapping_procs); + set_dev_proc(pdev, get_color_comp_index, group_color->group_color_comp_index); + pdev->color_info.polarity = group_color->polarity; + pdev->color_info.depth = group_color->depth; + pdev->color_info.num_components = group_color->num_components; + pdev->blend_procs = group_color->blend_procs; + pdev->pdf14_procs = group_color->unpack_procs; + pdev->color_info.max_color = group_color->max_color; + pdev->color_info.max_gray = group_color->max_gray; + set_dev_proc(pdev, encode_color, group_color->encode); + set_dev_proc(pdev, decode_color, group_color->decode); + memcpy(&(pdev->color_info.comp_bits),&(group_color->comp_bits), GX_DEVICE_COLOR_MAX_COMPONENTS); - memcpy(&(pdev->color_info.comp_shift),&(parent_color->comp_shift), + memcpy(&(pdev->color_info.comp_shift),&(group_color->comp_shift), GX_DEVICE_COLOR_MAX_COMPONENTS); /* clist writer fill rect has no access to gs_gstate */ /* and it forwards the target device. this information */ @@ -5963,95 +6789,42 @@ pdf14_update_device_color_procs_pop_c(gx_device *dev,gs_gstate *pgs) cldev->clist_color_info.num_components = pdev->color_info.num_components; cldev->clist_color_info.max_color = pdev->color_info.max_color; cldev->clist_color_info.max_gray = pdev->color_info.max_gray; - memcpy(&(cldev->clist_color_info.comp_bits),&(parent_color->comp_bits), + memcpy(&(cldev->clist_color_info.comp_bits),&(group_color->comp_bits), GX_DEVICE_COLOR_MAX_COMPONENTS); - memcpy(&(cldev->clist_color_info.comp_shift),&(parent_color->comp_shift), + memcpy(&(cldev->clist_color_info.comp_shift),&(group_color->comp_shift), GX_DEVICE_COLOR_MAX_COMPONENTS); if (pdev->ctx){ - pdev->ctx->additive = parent_color->isadditive; + pdev->ctx->additive = group_color->isadditive; } /* The device profile must be restored. */ - gsicc_adjust_profile_rc(dev->icc_struct->device_profile[0], -1, "pdf14_update_device_color_procs_pop_c"); - dev->icc_struct->device_profile[0] = parent_color->icc_profile; - parent_color->icc_profile = NULL; + if (group_color->icc_profile != NULL) { + gsicc_adjust_profile_rc(dev->icc_struct->device_profile[0], -1, "pdf14_clist_pop_color_model"); + dev->icc_struct->device_profile[0] = group_color->icc_profile; + } if_debug0m('v', dev->memory, "[v]procs updated\n"); } - pdf14_pop_parent_color(dev, pgs); + pdf14_pop_group_color(dev, pgs); return 0; } -/* When a transparency group is pushed, the parent colorprocs are initialized. - Since the color mapping procs are all based upon the device, we must have - a nested list based upon the transparency group color space. This nesting - must be outside the nested ctx structures to allow the nesting for the clist - writer */ -static void -pdf14_push_parent_color(gx_device *dev, const gs_gstate *pgs) -{ - pdf14_device *pdev = (pdf14_device *)dev; - pdf14_parent_color_t *new_parent_color; - cmm_profile_t *icc_profile; - gsicc_rendering_param_t render_cond; - cmm_dev_profile_t *dev_profile; - - dev_proc(dev, get_profile)(dev, &dev_profile); - gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, &icc_profile, - &render_cond); - if_debug0m('v', dev->memory, "[v]pdf14_push_parent_color\n"); - /* Allocate a new one */ - new_parent_color = gs_alloc_struct(dev->memory->stable_memory, pdf14_parent_color_t, - &st_pdf14_clr,"pdf14_clr_new"); - /* Link to old one */ - new_parent_color->previous = pdev->trans_group_parent_cmap_procs; - /* Reassign new one to dev */ - pdev->trans_group_parent_cmap_procs = new_parent_color; - /* Initialize with values */ - new_parent_color->get_cmap_procs = pgs->get_cmap_procs; - new_parent_color->parent_color_mapping_procs = - dev_proc(pdev, get_color_mapping_procs); - new_parent_color->parent_color_comp_index = - dev_proc(pdev, get_color_comp_index); - new_parent_color->parent_blending_procs = pdev->blend_procs; - new_parent_color->polarity = pdev->color_info.polarity; - new_parent_color->num_components = pdev->color_info.num_components; - new_parent_color->unpack_procs = pdev->pdf14_procs; - new_parent_color->depth = pdev->color_info.depth; - new_parent_color->max_color = pdev->color_info.max_color; - new_parent_color->max_gray = pdev->color_info.max_gray; - new_parent_color->decode = dev_proc(pdev, decode_color); - new_parent_color->encode = dev_proc(pdev, encode_color); - memcpy(&(new_parent_color->comp_bits), &(pdev->color_info.comp_bits), - GX_DEVICE_COLOR_MAX_COMPONENTS); - memcpy(&(new_parent_color->comp_shift), &(pdev->color_info.comp_shift), - GX_DEVICE_COLOR_MAX_COMPONENTS); - /* The ICC manager has the ICC profile for the device */ - new_parent_color->icc_profile = icc_profile; - gsicc_adjust_profile_rc(icc_profile, 1, "pdf14_push_parent_color"); - /* isadditive is only used in ctx */ - if (pdev->ctx) { - new_parent_color->isadditive = pdev->ctx->additive; - } -} - /* When a transparency group is popped, the parent colorprocs must be restored. Since the color mapping procs are all based upon the device, we must have a nested list based upon the transparency group color space. This nesting must be outside the nested ctx structures to allow the nesting for the clist writer */ static void -pdf14_pop_parent_color(gx_device *dev, const gs_gstate *pgs) +pdf14_pop_group_color(gx_device *dev, const gs_gstate *pgs) { pdf14_device *pdev = (pdf14_device *)dev; - pdf14_parent_color_t *old_parent_color_info = pdev->trans_group_parent_cmap_procs; + pdf14_group_color_t *group_color = pdev->color_model_stack; + + if_debug0m('v', dev->memory, "[v]pdf14_pop_group_color\n"); - if_debug0m('v', dev->memory, "[v]pdf14_pop_parent_color\n"); - /* We need to compliment pdf14_push_parent color */ - if (old_parent_color_info->icc_profile != NULL) - gsicc_adjust_profile_rc(old_parent_color_info->icc_profile, -1, "pdf14_pop_parent_color"); /* Update the link */ - pdev->trans_group_parent_cmap_procs = old_parent_color_info->previous; + pdev->color_model_stack = group_color->previous; + /* Free the old one */ - gs_free_object(dev->memory->stable_memory, old_parent_color_info, "pdf14_clr_free"); + gs_free_object(dev->memory->stable_memory, group_color, "pdf14_clr_free"); } static int @@ -6066,8 +6839,14 @@ pdf14_begin_transparency_mask(gx_device *dev, gs_int_rect rect; int code; int group_color_numcomps; - gs_transparency_color_t group_color; + gs_transparency_color_t group_color_type; bool deep = device_is_deep(dev); + pdf14_group_color_t* group_color_info; + + code = pdf14_initialize_ctx(dev, dev->color_info.num_components, + dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, (const gs_gstate*)pgs); + if (code < 0) + return code; if (ptmp->subtype == TRANSPARENCY_MASK_None) { pdf14_ctx *ctx = pdev->ctx; @@ -6096,7 +6875,7 @@ pdf14_begin_transparency_mask(gx_device *dev, memcpy(transfer_fn, ptmp->transfer_fn, (256+deep)<<deep); /* If the group color is unknown, then we must use the previous group color space or the device process color space */ - if (ptmp->group_color == UNKNOWN){ + if (ptmp->group_color_type == UNKNOWN){ if (pdev->ctx->stack){ /* Use previous group color space */ group_color_numcomps = pdev->ctx->stack->n_chan-1; /* Remove alpha */ @@ -6106,30 +6885,30 @@ pdf14_begin_transparency_mask(gx_device *dev, } switch (group_color_numcomps) { case 1: - group_color = GRAY_SCALE; + group_color_type = GRAY_SCALE; break; case 3: - group_color = DEVICE_RGB; + group_color_type = DEVICE_RGB; break; case 4: - group_color = DEVICE_CMYK; + group_color_type = DEVICE_CMYK; break; default: /* We can end up here if we are in a deviceN color space and we have a sep output device */ - group_color = DEVICEN; + group_color_type = DEVICEN; break; } } else { - group_color = ptmp->group_color; + group_color_type = ptmp->group_color_type; group_color_numcomps = ptmp->group_color_numcomps; } - /* Always update the color mapping procs. Otherwise we end up - fowarding to the target device. */ - code = pdf14_update_device_color_procs(dev, group_color, ptmp->icc_hashcode, - pgs, ptmp->iccprofile, true); - if (code < 0) - return code; + + group_color_info = pdf14_push_color_model(dev, group_color_type, ptmp->icc_hashcode, + ptmp->iccprofile, true); + if (group_color_info == NULL) + return gs_error_VMerror; + /* Note that the soft mask always follows the group color requirements even when we have a separable device */ code = pdf14_push_transparency_mask(pdev->ctx, &rect, bg_alpha, @@ -6141,7 +6920,8 @@ pdf14_begin_transparency_mask(gx_device *dev, ptmp->Background, ptmp->Matte_components, ptmp->Matte, - ptmp->GrayBackground); + ptmp->GrayBackground, + group_color_info); if (code < 0) return code; @@ -6152,7 +6932,7 @@ static int pdf14_end_transparency_mask(gx_device *dev, gs_gstate *pgs) { pdf14_device *pdev = (pdf14_device *)dev; - pdf14_parent_color_t *parent_color; + pdf14_group_color_t *group_color; int ok; if_debug0m('v', dev->memory, "pdf14_end_transparency_mask\n"); @@ -6165,35 +6945,31 @@ pdf14_end_transparency_mask(gx_device *dev, gs_gstate *pgs) * to a mismatch between the Smask color space * and the Smask blending space */ if (pdev->ctx->stack != NULL ) { - parent_color = pdev->ctx->stack->parent_color_info; - if (!(parent_color->parent_color_mapping_procs == NULL && - parent_color->parent_color_comp_index == NULL)) { - pgs->get_cmap_procs = parent_color->get_cmap_procs; + group_color = pdev->ctx->stack->group_color_info; + if (!(group_color->group_color_mapping_procs == NULL && + group_color->group_color_comp_index == NULL)) { + pgs->get_cmap_procs = group_color->get_cmap_procs; gx_set_cmap_procs(pgs, dev); - set_dev_proc(pdev, get_color_mapping_procs, parent_color->parent_color_mapping_procs); - set_dev_proc(pdev, get_color_comp_index, parent_color->parent_color_comp_index); - pdev->color_info.polarity = parent_color->polarity; - pdev->color_info.num_components = parent_color->num_components; - pdev->color_info.depth = parent_color->depth; - pdev->blend_procs = parent_color->parent_blending_procs; - pdev->ctx->additive = parent_color->isadditive; - pdev->pdf14_procs = parent_color->unpack_procs; - pdev->color_info.max_color = parent_color->max_color; - pdev->color_info.max_gray = parent_color->max_gray; - parent_color->get_cmap_procs = NULL; - parent_color->parent_color_comp_index = NULL; - parent_color->parent_color_mapping_procs = NULL; - set_dev_proc(pdev, encode_color, parent_color->encode); - set_dev_proc(pdev, decode_color, parent_color->decode); - memcpy(&(pdev->color_info.comp_bits),&(parent_color->comp_bits), + set_dev_proc(pdev, get_color_mapping_procs, group_color->group_color_mapping_procs); + set_dev_proc(pdev, get_color_comp_index, group_color->group_color_comp_index); + pdev->color_info.polarity = group_color->polarity; + pdev->color_info.num_components = group_color->num_components; + pdev->color_info.depth = group_color->depth; + pdev->blend_procs = group_color->blend_procs; + pdev->ctx->additive = group_color->isadditive; + pdev->pdf14_procs = group_color->unpack_procs; + pdev->color_info.max_color = group_color->max_color; + pdev->color_info.max_gray = group_color->max_gray; + set_dev_proc(pdev, encode_color, group_color->encode); + set_dev_proc(pdev, decode_color, group_color->decode); + memcpy(&(pdev->color_info.comp_bits),&(group_color->comp_bits), GX_DEVICE_COLOR_MAX_COMPONENTS); - memcpy(&(pdev->color_info.comp_shift),&(parent_color->comp_shift), + memcpy(&(pdev->color_info.comp_shift),&(group_color->comp_shift), GX_DEVICE_COLOR_MAX_COMPONENTS); /* Take care of the ICC profile */ - if (parent_color->icc_profile != NULL) { + if (group_color->icc_profile != NULL) { gsicc_adjust_profile_rc(dev->icc_struct->device_profile[0], -1, "pdf14_end_transparency_mask"); - dev->icc_struct->device_profile[0] = parent_color->icc_profile; - parent_color->icc_profile = NULL; + dev->icc_struct->device_profile[0] = group_color->icc_profile; } } } @@ -7156,12 +7932,14 @@ gs_pdf14_device_push(gs_memory_t *mem, gs_gstate * pgs, p14dev->color_info.comp_shift[p14dev->color_info.num_components] = p14dev->color_info.depth; p14dev->color_info.depth += 8; } + /* by definition pdf14_encode _is_ standard */ p14dev->color_info.separable_and_linear = GX_CINFO_SEP_LIN_STANDARD; gx_device_fill_in_procs((gx_device *)p14dev); p14dev->save_get_cmap_procs = pgs->get_cmap_procs; pgs->get_cmap_procs = pdf14_get_cmap_procs; gx_set_cmap_procs(pgs, (gx_device *)p14dev); + /* Components shift, etc have to be based upon 8 (or 16) bit */ for (k = 0; k < p14dev->color_info.num_components; k++) { p14dev->color_info.comp_bits[k] = 8<<deep; @@ -7178,21 +7956,19 @@ gs_pdf14_device_push(gs_memory_t *mem, gs_gstate * pgs, code = dev_proc((gx_device *) p14dev, open_device) ((gx_device *) p14dev); *pdev = (gx_device *) p14dev; pdf14_set_marking_params((gx_device *)p14dev, pgs); - p14dev->trans_group_parent_cmap_procs = NULL; + p14dev->color_model_stack = NULL; + /* In case we have alphabits set */ p14dev->color_info.anti_alias = target->color_info.anti_alias; -#if RAW_DUMP - /* Dump the current buffer to see what we have. */ - dump_raw_buffer(p14dev->ctx->memory, - p14dev->ctx->stack->rect.q.y-p14dev->ctx->stack->rect.p.y, - p14dev->ctx->stack->rect.q.x-p14dev->ctx->stack->rect.p.x, - p14dev->ctx->stack->n_planes, - p14dev->ctx->stack->planestride, p14dev->ctx->stack->rowstride, - "Device_Push", p14dev->ctx->stack->data, - p14dev->ctx->stack->deep); - global_index++; -#endif + if (pdf14pct->params.is_pattern) { + code = pdf14_initialize_ctx((gx_device*)p14dev, + p14dev->color_info.num_components, + p14dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, (const gs_gstate*) pgs); + if (code < 0) + return code; + } + /* We should never go into this when using a blend color space */ if (use_pdf14_accum) { const gx_device_pdf14_accum *accum_proto = NULL; @@ -7412,18 +8188,20 @@ c_pdf14trans_write(const gs_composite_t * pct, byte * data, uint * psize, return code; *pbuf++ = (pparams->Isolated & 1) + ((pparams->Knockout & 1) << 1); *pbuf++ = pparams->blend_mode; - *pbuf++ = pparams->group_color; + *pbuf++ = pparams->group_color_type; + *pbuf++ = pparams->page_group; put_value(pbuf, pparams->group_color_numcomps); put_value(pbuf, pparams->opacity); put_value(pbuf, pparams->shape); put_value(pbuf, pparams->bbox); + put_value(pbuf, pparams->shade_group); put_value(pbuf, pparams->text_group); mask_id = pparams->mask_id; put_value(pbuf, mask_id); /* Color space information maybe ICC based in this case we need to store the ICC profile or the ID if it is cached already */ - if (pparams->group_color == ICC) { + if (pparams->group_color_type == ICC) { /* Check if it is already in the ICC clist table */ hashcode = pparams->iccprofile->hashcode; found_icc = clist_icc_searchtable(cdev, hashcode); @@ -7448,7 +8226,7 @@ c_pdf14trans_write(const gs_composite_t * pct, byte * data, uint * psize, if (code < 0) return code; put_value(pbuf, pparams->subtype); - *pbuf++ = pparams->group_color; + *pbuf++ = pparams->group_color_type; put_value(pbuf, pparams->group_color_numcomps); *pbuf++ = pparams->replacing; *pbuf++ = (pparams->function_is_identity) | (deep<<1); @@ -7476,7 +8254,7 @@ c_pdf14trans_write(const gs_composite_t * pct, byte * data, uint * psize, /* Color space information may be ICC based in this case we need to store the ICC profile or the ID if it is cached already */ - if (pparams->group_color == ICC) { + if (pparams->group_color_type == ICC) { /* Check if it is already in the ICC clist table */ hashcode = pparams->iccprofile->hashcode; found_icc = clist_icc_searchtable(cdev, hashcode); @@ -7632,11 +8410,13 @@ c_pdf14trans_read(gs_composite_t * * ppct, const byte * data, params.Isolated = (*data) & 1; params.Knockout = (*data++ >> 1) & 1; params.blend_mode = *data++; - params.group_color = *data++; /* Trans group color */ + params.group_color_type = *data++; /* Trans group color */ + params.page_group = *data++; read_value(data,params.group_color_numcomps); /* color group size */ read_value(data, params.opacity); read_value(data, params.shape); read_value(data, params.bbox); + read_value(data, params.shade_group); read_value(data, params.text_group); read_value(data, params.mask_id); read_value(data, params.icc_hash); @@ -7656,7 +8436,7 @@ c_pdf14trans_read(gs_composite_t * * ppct, const byte * data, */ data = cmd_read_matrix(¶ms.ctm, data); read_value(data, params.subtype); - params.group_color = *data++; + params.group_color_type = *data++; read_value(data, params.group_color_numcomps); params.replacing = *data++; params.function_is_identity = *data & 1; @@ -8559,7 +9339,7 @@ pdf14_ret_devn_params(gx_device *pdev) { pdf14_device *p14dev = (pdf14_device *)pdev; - return(&(p14dev->devn_params)); + return &(p14dev->devn_params); } /* @@ -8570,7 +9350,7 @@ pdf14_accum_ret_devn_params(gx_device *pdev) { gx_device_pdf14_accum *p14dev = (gx_device_pdf14_accum *)pdev; - return(&(p14dev->devn_params)); + return &(p14dev->devn_params); } static int @@ -8822,18 +9602,15 @@ pdf14_clist_create_compositor(gx_device * dev, gx_device ** pcdev, pdf14pct->params.Background_components != pdev->color_info.num_components) return_error(gs_error_rangecheck); + /* We need to update the clist writer device procs based upon the - the group color space. For simplicity, the list item is + the group color space. This ensures the proper color data is + written out to the device. For simplicity, the list item is created even if the color space did not change */ - /* First store the current ones */ - pdf14_push_parent_color(dev, pgs); - - code = pdf14_update_device_color_procs_push_c(dev, - pdf14pct->params.group_color, - pdf14pct->params.icc_hash, pgs, - pdf14pct->params.iccprofile, false); + code = pdf14_clist_push_color_model(dev, cdev, pgs, pdf14pct, mem, false); if (code < 0) return code; + break; case PDF14_BEGIN_TRANS_MASK: /* We need to update the clist writer device procs based upon the @@ -8842,32 +9619,12 @@ pdf14_clist_create_compositor(gx_device * dev, gx_device ** pcdev, /* First store the current ones */ if (pdf14pct->params.subtype == TRANSPARENCY_MASK_None) break; - pdf14_push_parent_color(dev, pgs); - /* If we are playing back from a clist, the iccprofile may need to be loaded */ - if (pdf14pct->params.iccprofile == NULL) { - gs_pdf14trans_params_t *pparams_noconst = (gs_pdf14trans_params_t *)&(pdf14pct->params); - - pparams_noconst->iccprofile = gsicc_read_serial_icc((gx_device *) cdev, - pdf14pct->params.icc_hash); - if (pparams_noconst->iccprofile == NULL) - return gs_throw(-1, "ICC data not found in clist"); - /* Keep a pointer to the clist device */ - pparams_noconst->iccprofile->dev = (gx_device *)cdev; - /* Now we need to load the rest of the profile buffer */ - if (pparams_noconst->iccprofile->buffer == NULL) { - gcmmhprofile_t dummy = gsicc_get_profile_handle_clist(pparams_noconst->iccprofile, mem); - - if (dummy == NULL) - return_error(gs_error_VMerror); - } - } - /* Now update the device procs */ - code = pdf14_update_device_color_procs_push_c(dev, - pdf14pct->params.group_color, - pdf14pct->params.icc_hash, pgs, - pdf14pct->params.iccprofile, true); + + /* Update the color settings of the clist writer. Store information in stack */ + code = pdf14_clist_push_color_model(dev, cdev, pgs, pdf14pct, mem, true); if (code < 0) return code; + /* Also, if the BC is a value that may end up as something other than transparent. We must use the parent colors bounding box in determining the range of bands in which this mask can affect. @@ -8888,7 +9645,7 @@ pdf14_clist_create_compositor(gx_device * dev, gx_device ** pcdev, return 0; /* Avoids spurious ET calls in interpreter */ } pdev->text_group = PDF14_TEXTGROUP_NO_BT; /* These can't be nested */ - code = pdf14_update_device_color_procs_pop_c(dev, pgs); + code = pdf14_clist_pop_color_model(dev, pgs); if (code < 0) return code; break; @@ -8902,7 +9659,7 @@ pdf14_clist_create_compositor(gx_device * dev, gx_device ** pcdev, case PDF14_END_TRANS_GROUP: /* We need to update the clist writer device procs based upon the the group color space. */ - code = pdf14_update_device_color_procs_pop_c(dev,pgs); + code = pdf14_clist_pop_color_model(dev, pgs); if (pdev->depth_within_smask) pdev->depth_within_smask--; if (code < 0) @@ -9323,7 +10080,7 @@ pdf14_clist_stroke_path(gx_device *dev, const gs_gstate *pgs, * paint several pixels twice. */ push_group = pgs->strokeconstantalpha != 1.0 || !blend_is_idempotent(gs_currentblendmode(pgs)); - if (pdev->trans_group_parent_cmap_procs != NULL) { + if (pdev->color_model_stack != NULL) { pinst = (gs_pattern2_instance_t *)pdcolor->ccolor.pattern; pinst->saved->has_transparency = true; @@ -9470,8 +10227,9 @@ pdf14_clist_fill_stroke_path_pattern_setup(gx_device* dev, const gs_gstate* cpgs dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE) { params.Isolated = false; - params.group_color = UNKNOWN; + params.group_color_type = UNKNOWN; params.Knockout = false; + params.page_group = false; params.group_opacity = fill_alpha; params.group_shape = 1.0; @@ -9497,8 +10255,9 @@ pdf14_clist_fill_stroke_path_pattern_setup(gx_device* dev, const gs_gstate* cpgs /* Push a non-isolated knockout group. Do not change the alpha or blend modes */ params.Isolated = false; - params.group_color = UNKNOWN; + params.group_color_type = UNKNOWN; params.Knockout = true; + params.page_group = false; params.group_opacity = 1.0; params.group_shape = 1.0; @@ -9795,6 +10554,7 @@ pdf14_clist_begin_typed_image(gx_device * dev, const gs_gstate * pgs, if_debug0m('v', pgs->memory, "[v]Pushing special trans group for image\n"); tgp.Isolated = true; tgp.Knockout = false; + tgp.page_group = false; tgp.mask_id = 0; tgp.image_with_SMask = false; tgp.idle = false; @@ -10124,7 +10884,7 @@ c_pdf14trans_clist_read_update(gs_composite_t * pcte, gx_device * cdev, writing. */ cdev->color_info = p14dev->saved_target_color_info; # endif - break; + break; default: break; /* do nothing for remaining ops */ @@ -10388,9 +11148,13 @@ pdf14_increment_smask_color(gs_gstate * pgs, gx_device * dev) result = gs_alloc_struct(pdev->memory->stable_memory, pdf14_smaskcolor_t, &st_pdf14_smaskcolor, "pdf14_increment_smask_color"); - if (result == NULL ) return(-1); + if (result == NULL) + return gs_error_VMerror; + result->profiles = gsicc_new_iccsmask(pdev->memory->stable_memory); - if (result->profiles == NULL ) return(-1); + if (result->profiles == NULL) + return gs_error_VMerror; + pdev->smaskcolor = result; result->profiles->smask_gray = pgs->icc_manager->default_gray; @@ -10445,7 +11209,7 @@ pdf14_increment_smask_color(gs_gstate * pgs, gx_device * dev) } } } - return(0); + return 0; } static int @@ -10527,7 +11291,7 @@ pdf14_decrement_smask_color(gs_gstate * pgs, gx_device * dev) pdf14_free_smask_color(pdev); } } - return(0); + return 0; } static void @@ -10552,15 +11316,15 @@ pdf14_device_finalize(const gs_memory_t *cmem, void *vptr) gx_device * const dev = (gx_device *)vptr; pdf14_device * pdev = (pdf14_device *)dev; - pdf14_cleanup_parent_color_profiles (pdev); + pdf14_cleanup_group_color_profiles (pdev); if (pdev->ctx) { pdf14_ctx_free(pdev->ctx); pdev->ctx = NULL; } - while (pdev->trans_group_parent_cmap_procs) { - pdf14_pop_parent_color(dev, NULL); + while (pdev->color_model_stack) { + pdf14_pop_group_color(dev, NULL); } gx_device_finalize(cmem, vptr); } diff --git a/base/gdevp14.h b/base/gdevp14.h index 12186ddf1..635ab1113 100644 --- a/base/gdevp14.h +++ b/base/gdevp14.h @@ -97,18 +97,15 @@ struct pdf14_mask_s { }; -/* A structure to hold information - * about the parent color related - * procs and other information. - * These may change depending upon - * if the blending space is different - * than the base space. The structure - * is a list that is updated upon - * every transparency group push and pop */ - -typedef struct pdf14_parent_color_s pdf14_parent_color_t; - -struct pdf14_parent_color_s { +/* A structure to hold information about the group color related + * procs and other information. These may change depending upon + * if the blending space is different than the base space. + * The structure is a list that is updated upo every transparency + * group push and pop */ + +typedef struct pdf14_group_color_s pdf14_group_color_t; + +struct pdf14_group_color_s { int num_components; bool isadditive; gx_color_polarity_t polarity; @@ -119,14 +116,14 @@ struct pdf14_parent_color_s { uint max_color; /* Causes issues if these are not maintained */ const gx_color_map_procs *(*get_cmap_procs)(const gs_gstate *, const gx_device *); - const gx_cm_color_map_procs *(*parent_color_mapping_procs)(const gx_device *); + const gx_cm_color_map_procs *(*group_color_mapping_procs)(const gx_device *); gx_color_index (*encode)(gx_device *, const gx_color_value value[]); int (*decode)(gx_device *, gx_color_index, gx_color_value *); - int (*parent_color_comp_index)(gx_device *, const char *, int, int); + int (*group_color_comp_index)(gx_device *, const char *, int, int); const pdf14_procs_t * unpack_procs; - const pdf14_nonseparable_blending_procs_t * parent_blending_procs; + const pdf14_nonseparable_blending_procs_t * blend_procs; cmm_profile_t *icc_profile; /* Opaque to GC. Allocated in non-gc memory */ - pdf14_parent_color_t *previous; + pdf14_group_color_t *previous; }; typedef struct pdf14_ctx_s pdf14_ctx; @@ -146,7 +143,9 @@ struct pdf14_buf_s { bool has_tags; bool deep; /* false => 8 bits, true => 16 bits */ bool page_group; - + bool group_popped; /* Can occur in cases where clist created shading groups */ + /* If there is a group and is pushed and popped, with + nothing drawn AND the clist created shading groups */ gs_int_rect rect; /* Note: the traditional GS name for rowstride is "raster" */ @@ -169,7 +168,7 @@ struct pdf14_buf_s { gs_transparency_mask_subtype_t SMask_SubType; uint mask_id; - pdf14_parent_color_t *parent_color_info; + pdf14_group_color_t *group_color_info; gs_transparency_color_t color_space; /* Different groups can have different spaces for blending */ gs_memory_t *memory; @@ -190,6 +189,9 @@ struct pdf14_ctx_s { int smask_depth; /* used to catch smasks embedded in smasks. bug691803 */ bool smask_blend; bool deep; /* If true, 16 bit data, false, 8 bit data. */ + bool has_tags; + int num_spots; + pdf14_group_color_t* base_color; }; typedef struct gs_pdf14trans_params_s gs_pdf14trans_params_t; @@ -268,7 +270,7 @@ typedef struct pdf14_device_s { dev_proc_get_color_mapping_procs(*my_get_color_mapping_procs); dev_proc_get_color_comp_index(*my_get_color_comp_index); - pdf14_parent_color_t *trans_group_parent_cmap_procs; + pdf14_group_color_t *color_model_stack; } pdf14_device_t; @@ -318,4 +320,6 @@ int gs_pdf14_device_color_mon_set(gx_device *pdev, bool monitoring); /* depth are critical since these must match when reading back colors. */ bool pdf14_ok_to_optimize(gx_device *bdev); + + #endif /* gdevp14_INCLUDED */ diff --git a/base/gsicc_cache.c b/base/gsicc_cache.c index f77232e10..bc1d7a9f5 100644 --- a/base/gsicc_cache.c +++ b/base/gsicc_cache.c @@ -1790,9 +1790,11 @@ gsicc_init_buffer(gsicc_bufferdesc_t *buffer_desc, unsigned char num_chan, unsig buffer_desc->num_rows = num_rows; buffer_desc->pixels_per_row = pixels_per_row; - /* sample endianess is consistent across platforms */ +#if ARCH_IS_BIG_ENDIAN + buffer_desc->little_endian = false; +#else buffer_desc->little_endian = true; - +#endif } /* Return the proper component numbers based upon the profiles of the device. diff --git a/base/gstparam.h b/base/gstparam.h index 10b37a4b9..44093bc93 100644 --- a/base/gstparam.h +++ b/base/gstparam.h @@ -76,10 +76,12 @@ typedef struct gs_transparency_group_params_s { float group_opacity; bool image_with_SMask; int text_group; + bool shade_group; + bool page_group; bool idle; uint mask_id; int group_color_numcomps; - gs_transparency_color_t group_color; + gs_transparency_color_t group_color_type; int64_t icc_hashcode; /* Needed when we are doing clist reading */ cmm_profile_t *iccprofile; /* The profile */ } gs_transparency_group_params_t; @@ -117,7 +119,7 @@ typedef struct gs_transparency_mask_params_s { typedef struct gx_transparency_mask_params_s { gs_transparency_mask_subtype_t subtype; int group_color_numcomps; - gs_transparency_color_t group_color; + gs_transparency_color_t group_color_type; int Background_components; int Matte_components; float Background[GS_CLIENT_COLOR_MAX_COMPONENTS]; diff --git a/base/gstrans.c b/base/gstrans.c index 1d8d6f07d..fba21f7b0 100644 --- a/base/gstrans.c +++ b/base/gstrans.c @@ -170,12 +170,14 @@ gs_trans_group_params_init(gs_transparency_group_params_t *ptgp, float opacity) ptgp->ColorSpace = NULL; /* bogus, but can't do better */ ptgp->Isolated = false; ptgp->Knockout = false; + ptgp->page_group = false; ptgp->text_group = PDF14_TEXTGROUP_NO_BT; ptgp->image_with_SMask = false; ptgp->mask_id = 0; ptgp->iccprofile = NULL; ptgp->group_opacity = opacity; ptgp->group_shape = 1.0; + ptgp->shade_group = false; } int @@ -209,12 +211,14 @@ gs_begin_transparency_group(gs_gstate *pgs, params.pdf14_op = group_type; params.Isolated = ptgp->Isolated; params.Knockout = ptgp->Knockout; + if (group_type == PDF14_BEGIN_TRANS_PAGE_GROUP) + params.page_group = true; params.image_with_SMask = ptgp->image_with_SMask; params.opacity = ptgp->group_opacity; params.shape = ptgp->group_shape; params.blend_mode = pgs->blend_mode; params.text_group = ptgp->text_group; - + params.shade_group = ptgp->shade_group; /* 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. @@ -239,11 +243,14 @@ gs_begin_transparency_group(gs_gstate *pgs, target device (process color model). Here we just want to set it as a unknown type for clist writing, as we will take care of using the parent group color space later during clist reading. - */ - + Also, if the group was not isolated we MUST use the parent group + color space regardless of what the group color space is specified to be. + Note that the page group should always be isolated */ + if (group_type == PDF14_BEGIN_TRANS_PAGE_GROUP) + params.Isolated = true; if (ptgp->ColorSpace == NULL || params.Isolated != true) { - params.group_color = UNKNOWN; + params.group_color_type = UNKNOWN; params.group_color_numcomps = 0; } else { /* The /CS parameter was present. Use what was set. Currently @@ -258,7 +265,7 @@ gs_begin_transparency_group(gs_gstate *pgs, /* Blending space is ICC based. If we are doing c-list rendering we will need to write this color space into the clist. */ - params.group_color = ICC; + params.group_color_type = ICC; params.group_color_numcomps = blend_color_space->cmm_icc_profile_data->num_comps; /* Get the ICC profile */ @@ -281,12 +288,12 @@ gs_begin_transparency_group(gs_gstate *pgs, /* We can end up here if we are in a deviceN color space and we have a sep output device */ profile = NULL; - params.group_color = DEVICEN; + params.group_color_type = DEVICEN; params.group_color_numcomps = cs_num_components(blend_color_space); break; } if (profile != NULL) { - params.group_color = ICC; + params.group_color_type = ICC; params.group_color_numcomps = profile->num_comps; params.iccprofile = profile; params.icc_hash = profile->hashcode; @@ -306,8 +313,8 @@ gs_begin_transparency_group(gs_gstate *pgs, else dmputs(pgs->memory, " (no CS)"); - dmprintf3(pgs->memory, " Isolated = %d Knockout = %d text_group = %d\n", - ptgp->Isolated, ptgp->Knockout, ptgp->text_group); + dmprintf4(pgs->memory, " Isolated = %d Knockout = %d text_group = %d page_group = %d\n", + ptgp->Isolated, ptgp->Knockout, ptgp->text_group, ptgp->page_group); } #endif params.bbox = *pbbox; @@ -326,12 +333,14 @@ gx_begin_transparency_group(gs_gstate * pgs, gx_device * pdev, return_error(gs_error_rangecheck); tgp.Isolated = pparams->Isolated; tgp.Knockout = pparams->Knockout; + tgp.page_group = pparams->page_group; tgp.idle = pparams->idle; tgp.mask_id = pparams->mask_id; tgp.text_group = pparams->text_group; + tgp.shade_group = pparams->shade_group; /* Needed so that we do proper blending */ - tgp.group_color = pparams->group_color; + tgp.group_color_type = pparams->group_color_type; tgp.group_color_numcomps = pparams->group_color_numcomps; tgp.iccprofile = pparams->iccprofile; tgp.icc_hashcode = pparams->icc_hash; @@ -355,8 +364,8 @@ gx_begin_transparency_group(gs_gstate * pgs, gx_device * pdev, cs_names[(int)gs_color_space_get_index(tgp.ColorSpace)]); else dmputs(pdev->memory, " (no CS)"); - dmprintf2(pdev->memory, " Isolated = %d Knockout = %d\n", - tgp.Isolated, tgp.Knockout); + dmprintf2(pdev->memory, " Isolated = %d Knockout = %d page_group = %d\n", + tgp.Isolated, tgp.Knockout, tgp.page_group); if (tgp.iccprofile) dmprintf(pdev->memory, " Have ICC Profile for blending\n"); @@ -615,7 +624,7 @@ gs_begin_transparency_mask(gs_gstate * pgs, if ( blend_color_space->cmm_icc_profile_data != NULL ) { /* Blending space is ICC based. If we are doing c-list rendering we will need to write this color space into the clist. */ - params.group_color = ICC; + params.group_color_type = ICC; params.group_color_numcomps = blend_color_space->cmm_icc_profile_data->num_comps; /* Get the ICC profile */ @@ -625,7 +634,7 @@ gs_begin_transparency_mask(gs_gstate * pgs, params.iccprofile = blend_color_space->cmm_icc_profile_data; params.icc_hash = blend_color_space->cmm_icc_profile_data->hashcode; } else { - params.group_color = GRAY_SCALE; + params.group_color_type = GRAY_SCALE; params.group_color_numcomps = 1; /* Need to check */ } /* Explicitly decrement the profile data since blend_color_space may not @@ -647,7 +656,7 @@ gx_begin_transparency_mask(gs_gstate * pgs, gx_device * pdev, const int l = sizeof(pparams->Background[0]) * pparams->Background_components; const int m = sizeof(pparams->Matte[0]) * pparams->Matte_components; - tmp.group_color = pparams->group_color; + tmp.group_color_type = pparams->group_color_type; tmp.subtype = pparams->subtype; tmp.group_color_numcomps = pparams->group_color_numcomps; tmp.Background_components = pparams->Background_components; @@ -660,7 +669,7 @@ gx_begin_transparency_mask(gs_gstate * pgs, gx_device * pdev, tmp.replacing = pparams->replacing; tmp.mask_id = pparams->mask_id; - if (tmp.group_color == ICC ) { + if (tmp.group_color_type == ICC ) { /* Do I need to ref count here? */ tmp.iccprofile = pparams->iccprofile; tmp.icc_hashcode = pparams->icc_hash; diff --git a/base/gstrans.h b/base/gstrans.h index 1a2f77d5f..a441bbef8 100644 --- a/base/gstrans.h +++ b/base/gstrans.h @@ -119,7 +119,9 @@ struct gs_pdf14trans_params_s { gs_blend_mode_t blend_mode; bool text_knockout; int text_group; + bool page_group; bool ais; + bool shade_group; float opacity; float shape; float fillconstantalpha; @@ -134,7 +136,7 @@ struct gs_pdf14trans_params_s { bool idle; /* For clist reader.*/ uint mask_id; /* For clist reader.*/ int group_color_numcomps; - gs_transparency_color_t group_color; + gs_transparency_color_t group_color_type; int64_t icc_hash; cmm_profile_t *iccprofile; /* The profile */ bool crop_blend_params; /* This is used when the blend params are updated diff --git a/base/gxblend.h b/base/gxblend.h index da15f7f39..0ac938776 100644 --- a/base/gxblend.h +++ b/base/gxblend.h @@ -392,10 +392,6 @@ void gx_blend_image_buffer16(byte *buf_ptr, int width, int height, int rowstride, int planestride, int num_comp, uint16_t bg); void gx_blend_image_buffer8to16(const byte *buf_ptr, unsigned short *buf_ptr_out, int width, int height, int rowstride, int planestride, int num_comp, byte bg); -int gx_put_blended_image_cmykspot(gx_device *target, byte *buf_ptr, - int planestride, int rowstride, - int x0, int y0, int width, int height, int num_comp, uint16_t bg, - bool has_tags, gs_int_rect rect, gs_separations *pseparations, bool deep); int gx_put_blended_image_custom(gx_device *target, byte *buf_ptr, int planestride, int rowstride, int x0, int y0, int width, int height, int num_comp, uint16_t bg, bool deep); diff --git a/base/gxblend1.c b/base/gxblend1.c index ae66583f5..4a10be4e6 100644 --- a/base/gxblend1.c +++ b/base/gxblend1.c @@ -867,14 +867,14 @@ gx_blend_image_buffer16(byte *buf_ptr_, int width, int height, int rowstride, buf_ptr[position + planestride * comp_num] = bebg; } } else if (a == 0xffff) { - /* Convert from native -> big endian */ - /* FIXME: Are compilers smart enough to spot that this is - * a no-op on big endian hosts? */ +#if ARCH_IS_BIG_ENDIAN +#else for (comp_num = 0; comp_num < num_comp; comp_num++) { comp = buf_ptr[position + planestride * comp_num]; ((byte *)&buf_ptr[position + planestride * comp_num])[0] = comp>>8; ((byte *)&buf_ptr[position + planestride * comp_num])[1] = comp; } +#endif } else { a ^= 0xffff; a += a>>15; /* a is now 0 to 0x10000 */ @@ -935,262 +935,6 @@ gx_blend_image_buffer8to16(const byte *buf_ptr_in, unsigned short *buf_ptr_out, } int -gx_put_blended_image_cmykspot(gx_device *target, byte *buf_ptr, int planestride_in, - int rowstride_in, int x0, int y0, int width, int height, - int num_comp, uint16_t bg, bool has_tags, gs_int_rect rect, - gs_separations * pseparations, bool deep) -{ - int code = 0; - int x, y, tmp, comp_num, output_comp_num; - gx_color_index color; - gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS]; - gx_color_value comp; - int input_map[GX_DEVICE_COLOR_MAX_COMPONENTS]; - int output_map[GX_DEVICE_COLOR_MAX_COMPONENTS]; - int num_known_comp = 0; - int output_num_comp = target->color_info.num_components; - int num_sep = pseparations->num_separations++; - int num_rows_left; - int i; - gx_drawing_color pdcolor; - gs_fixed_rect rect_fixed; - int bits_per_comp = ((target->color_info.depth - has_tags*8) / - target->color_info.num_components); - bool expand = (!deep && bits_per_comp > 8); - int planestride = planestride_in; - int rowstride = rowstride_in; - byte *buf16_ptr = NULL; - - /* - * The process color model for the PDF 1.4 compositor device is CMYK plus - * spot colors. The target device may have only some of these colorants due - * to the SeparationOrder device parameter. Thus we need to determine the - * mapping between the PDF 1.4 compositor and the target device. Note: - * There should not be a spot colorant in the PDF 1.4 device that is not - * present in the target device. - */ - /* Check if target processes CMYK colorants. */ - for (comp_num = 0; comp_num < 4; comp_num++) { - const char * pcomp_name = (const char *)DeviceCMYKComponents[comp_num]; - - output_comp_num = dev_proc(target, get_color_comp_index) - (target, pcomp_name, strlen(pcomp_name), NO_COMP_NAME_TYPE); - if (output_comp_num >=0 && - output_comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS) { - output_map[num_known_comp] = output_comp_num; - input_map[num_known_comp++] = comp_num; - } - } - /* Check if target processes our spot colorants. */ - for (comp_num = 0; comp_num < num_sep; comp_num++) { - output_comp_num = dev_proc(target, get_color_comp_index) - (target, (const char *)(pseparations->names[comp_num].data), - pseparations->names[comp_num].size, NO_COMP_NAME_TYPE); - if (output_comp_num >= 0 && - output_comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS) { - output_map[num_known_comp] = output_comp_num; - input_map[num_known_comp++] = comp_num + 4; - } - } - - { - /* See if the target device can handle the data in its current - form with the alpha component */ - int alpha_offset = num_comp; - int tag_offset = has_tags ? num_comp + 1 : 0; - const byte *buf_ptrs[GS_CLIENT_COLOR_MAX_COMPONENTS]; - - for (i = 0; i < num_comp; i++) - buf_ptrs[i] = buf_ptr + i * planestride; - code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, - rect.p.x, rect.p.y, width, height, - rowstride, - num_comp, tag_offset); - if (code == 0) { - /* Device could not handle the alpha data. Go ahead and - preblend now. Note that if we do this, and we end up in the - default below, we only need to repack in chunky not blend. Add - in conversion to 16 bits if the target device is planar and - a 16 bit device. */ -#if RAW_DUMP - /* Dump before and after the blend to make sure we are doing that ok */ - dump_raw_buffer(target->memory, height, width, num_comp + 1, planestride, rowstride, - "pre_final_blend", buf_ptr, deep); - global_index++; -#endif - if (expand) { - buf16_ptr = gs_alloc_bytes(target->memory, - planestride * num_comp * 2, "gx_put_blended_image_cmykspot"); - gx_blend_image_buffer8to16(buf_ptr, (unsigned short*)buf16_ptr, width, height, - rowstride, planestride, num_comp, bg>>8); - planestride = planestride_in * 2; - rowstride = rowstride_in * 2; - for (i = 0; i < num_comp; i++) - buf_ptrs[i] = buf16_ptr + i * planestride; - } else { - if (deep) { - gx_blend_image_buffer16(buf_ptr, width, height, rowstride, - planestride, num_comp, bg); - } else { - gx_blend_image_buffer(buf_ptr, width, height, rowstride, - planestride, num_comp, bg>>8); - } -#if RAW_DUMP - /* Dump before and after the blend to make sure we are doing that ok */ - dump_raw_buffer_be(target->memory, height, width, num_comp, planestride, rowstride, - "post_final_blend", buf_ptr, deep); - global_index++; - /* clist_band_count++; */ -#endif - } - /* Try again now */ - alpha_offset = 0; - code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, - rect.p.x, rect.p.y, width, height, - rowstride, alpha_offset, tag_offset); - if (code > 0) { - /* We processed some or all of the rows. Continue until we are done */ - num_rows_left = height - code; - while (num_rows_left > 0) { - code = dev_proc(target, put_image) (target, target, buf_ptrs, num_comp, - rect.p.x, rect.p.y + code, width, - num_rows_left, rowstride, - alpha_offset, tag_offset); - if (code < 0) { - if (buf16_ptr != NULL) - gs_free_object(target->memory, buf16_ptr, "gx_put_blended_image_cmykspot"); - return code; - } - num_rows_left = num_rows_left - code; - } - } - if (buf16_ptr != NULL) - gs_free_object(target->memory, buf16_ptr, "gx_put_blended_image_cmykspot"); - return 0; - } - } - - if (buf16_ptr != NULL) - gs_free_object(target->memory, buf16_ptr, "gx_put_blended_image_cmykspot"); - planestride = planestride_in; - rowstride = rowstride_in; - - /* Clear all output colorants first */ - for (comp_num = 0; comp_num < output_num_comp; comp_num++) - cv[comp_num] = 0; - - /* Send pixel data to the target device. */ - if (deep) { - /* NOTE: buf_ptr points to big endian data */ - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - - /* composite CMYKA, etc. pixel with over solid background */ -#define GET16_BE2NATIVE(v) \ - ((((byte *)&(v))[0]<<8) | (((byte *)&(v))[1])) - uint16_t a = GET16_BE2NATIVE(buf_ptr[x + planestride * num_comp]); - - if (a == 0) { - for (comp_num = 0; comp_num < num_known_comp; comp_num++) { - cv[output_map[comp_num]] = bg; - } - } else if (a == 0xffff) { - for (comp_num = 0; comp_num < num_known_comp; comp_num++) { - comp = GET16_BE2NATIVE(buf_ptr[x + planestride * input_map[comp_num]]); - cv[output_map[comp_num]] = comp; - } - } else { - /* a ^= 0xff; */ /* No inversion here! Bug 689895 */ - for (comp_num = 0; comp_num < num_known_comp; comp_num++) { - comp = GET16_BE2NATIVE(buf_ptr[x + planestride * input_map[comp_num]]); - tmp = ((comp - bg) * a) + 0x8000; - comp += (tmp + (tmp >> 16))>>16; - cv[output_map[comp_num]] = comp; - } - } - - /* If we have spot colors we need to encode and fill as a high level - color if the device supports it which should always be the case - if we are in this procedure */ - if (dev_proc(target, dev_spec_op)(target, gxdso_supports_devn, NULL, 0)) { - for (i = 0; i < output_num_comp; i++) { - pdcolor.colors.devn.values[i] = cv[i]; - } - pdcolor.type = gx_dc_type_devn; - rect_fixed.p.x = int2fixed(x + x0); - rect_fixed.p.y = int2fixed(y + y0); - rect_fixed.q.x = int2fixed(x + x0 + 1); - rect_fixed.q.y = int2fixed(y + y0 + 1); - code = dev_proc(target, fill_rectangle_hl_color)(target, &rect_fixed, - NULL, &pdcolor, NULL); - } else { - /* encode as a color index */ - color = dev_proc(target, encode_color)(target, cv); - code = dev_proc(target, fill_rectangle)(target, x + x0, y + y0, 1, 1, color); - } - if (code < 0) - return code; - } - - buf_ptr += rowstride; - } - } else { - bg >>= 8; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - - /* composite CMYKA, etc. pixel with over solid background */ - byte a = buf_ptr[x + planestride * num_comp]; - - if ((a + 1) & 0xfe) { - /* a ^= 0xff; */ /* No inversion here! Bug 689895 */ - for (comp_num = 0; comp_num < num_known_comp; comp_num++) { - comp = buf_ptr[x + planestride * input_map[comp_num]]; - tmp = ((comp - bg) * a) + 0x80; - comp += tmp + (tmp >> 8); - cv[output_map[comp_num]] = comp; - } - } else if (a == 0) { - for (comp_num = 0; comp_num < num_known_comp; comp_num++) { - cv[output_map[comp_num]] = bg; - } - } else { - for (comp_num = 0; comp_num < num_known_comp; comp_num++) { - comp = buf_ptr[x + planestride * input_map[comp_num]]; - cv[output_map[comp_num]] = (comp << 8) + comp; - } - } - - /* If we have spot colors we need to encode and fill as a high level - color if the device supports it which should always be the case - if we are in this procedure */ - if (dev_proc(target, dev_spec_op)(target, gxdso_supports_devn, NULL, 0)) { - for (i = 0; i < output_num_comp; i++) { - pdcolor.colors.devn.values[i] = cv[i]; - } - pdcolor.type = gx_dc_type_devn; - rect_fixed.p.x = int2fixed(x + x0); - rect_fixed.p.y = int2fixed(y + y0); - rect_fixed.q.x = int2fixed(x + x0 + 1); - rect_fixed.q.y = int2fixed(y + y0 + 1); - code = dev_proc(target, fill_rectangle_hl_color)(target, &rect_fixed, - NULL, &pdcolor, NULL); - } else { - /* encode as a color index */ - color = dev_proc(target, encode_color)(target, cv); - code = dev_proc(target, fill_rectangle)(target, x + x0, y + y0, 1, 1, color); - } - if (code < 0) - return code; - } - - buf_ptr += rowstride; - } - } - return code; -} - -int gx_put_blended_image_custom(gx_device *target, byte *buf_ptr_, int planestride, int rowstride, int x0, int y0, int width, int height, @@ -1275,4 +1019,4 @@ gx_put_blended_image_custom(gx_device *target, byte *buf_ptr_, } } return code; -} +}
\ No newline at end of file diff --git a/base/gxdevsop.h b/base/gxdevsop.h index dc7f05acf..3ba09fd2b 100644 --- a/base/gxdevsop.h +++ b/base/gxdevsop.h @@ -372,6 +372,13 @@ enum { /* Private dso used to check that a printer device properly forwards to the default */ gxdso_debug_printer_check, #endif + /* gxdso_supports_alpha: + * data = NULL + * size = 0 + * Returns 1 if the rendering device supports alpha, + * 0 otherwise. + */ + gxdso_supports_alpha, /* Add new gxdso_ keys above this. */ gxdso_pattern__LAST }; diff --git a/devices/devs.mak b/devices/devs.mak index c687339dc..fe736800a 100644 --- a/devices/devs.mak +++ b/devices/devs.mak @@ -1464,7 +1464,7 @@ libpng_dev=$(PNGGENDIR)$(D)libpng.dev png_i_=-include $(PNGGENDIR)$(D)libpng $(DEVOBJ)gdevpng.$(OBJ) : $(DEVSRC)gdevpng.c\ - $(gdevprn_h) $(gdevpccm_h) $(gscdefs_h) $(png__h) $(DEVS_MAK) $(MAKEDIRS) + $(gdevprn_h) $(gdevpccm_h) $(gscdefs_h) $(png__h) $(gxdevsop_h) $(DEVS_MAK) $(MAKEDIRS) $(CC_) $(I_)$(DEVI_) $(II)$(PI_)$(_I) $(PCF_) $(GLF_) $(DEVO_)gdevpng.$(OBJ) $(C_) $(DEVSRC)gdevpng.c $(DD)pngmono.dev : $(libpng_dev) $(png_) $(GLD)page.dev $(GDEV) \ diff --git a/devices/gdevpng.c b/devices/gdevpng.c index 4ab844fc1..fbfb3e060 100644 --- a/devices/gdevpng.c +++ b/devices/gdevpng.c @@ -55,6 +55,7 @@ #include "gdevpccm.h" #include "gscdefs.h" #include "gxdownscale.h" +#include "gxdevsop.h" /* ------ The device descriptors ------ */ @@ -79,6 +80,7 @@ static dev_proc_get_params(png_get_params_downscale); static dev_proc_put_params(png_put_params_downscale); static dev_proc_get_params(png_get_params_downscale_mfs); static dev_proc_put_params(png_put_params_downscale_mfs); +static dev_proc_dev_spec_op(pngalpha_spec_op); typedef struct gx_device_png_s gx_device_png; struct gx_device_png_s { @@ -280,7 +282,8 @@ static const gx_device_procs pngalpha_procs = pngalpha_fillpage, NULL, /* push_transparency_state */ NULL, /* pop_transparency_state */ - pngalpha_put_image + pngalpha_put_image, + pngalpha_spec_op /* dev_spec_op */\ }; const gx_device_pngalpha gs_pngalpha_device = { @@ -1072,3 +1075,15 @@ pngalpha_copy_alpha(gx_device * dev, const byte * data, int data_x, return code; } } + +static int +pngalpha_spec_op(gx_device* pdev, int dso, void* ptr, int size) +{ + switch (dso) + { + case gxdso_supports_alpha: + return 1; + } + + return gdev_prn_dev_spec_op(pdev, dso, ptr, size); +} diff --git a/devices/vector/gdevpdft.c b/devices/vector/gdevpdft.c index 82ed9f4b1..a963cb512 100644 --- a/devices/vector/gdevpdft.c +++ b/devices/vector/gdevpdft.c @@ -107,7 +107,7 @@ pdf_make_group_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams a group color specified. In this case, the parent group is inherited from the previous group or the device color space */ - if (pgs != NULL && pparams->group_color != UNKNOWN) { + if (pgs != NULL && pparams->group_color_type != UNKNOWN) { const gs_color_space *cs = gs_currentcolorspace_inline(pgs); code = pdf_color_space_named(pdev, pgs, &cs_value, NULL, cs, |