summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2020-05-26 12:05:46 -0700
committerMichael Vrhel <michael.vrhel@artifex.com>2020-10-12 10:31:46 -0700
commit02e3169b57724f63ce01c994d39c20647be5c20b (patch)
treee461bb6ebb65b3185d15a4235cd1727dd6909797 /base
parent1ff2ddac001612df3d54b504b49f6ee8e0685be7 (diff)
downloadghostpdl-02e3169b57724f63ce01c994d39c20647be5c20b.tar.gz
Bug 702192 Map text to black
Map all text to black. This is achieved by altering the color space to DeviceGray with a fill of black during gs_text_begin. When gs_text_release occurs, the color space is restored. This will only occur with the option -dBlackText and if the text is actually to be drawn. When going to a raster device, the stroke and stroke fill of the text is handled with a stroke or stroke fill command. My original plan of storing the old color spaces and client color in the text enumerator will not work in this situation as it the enumerator will have already been destroyed when the stroke or stroke/fill command occurs. For this reason I store the old color space information for the current and alternate color spaces in the graphic state. The structure holding the information is garbage collected as it is holding objects that may be garbage collected. We also need to know if the target was a high level device like pdfwrite, as that device will handle the fill AND stroke, and we will need to restore the color space when we tear down the text enumerator. gs_text_release needed to have the pgs added as a parameter to allow the possible release of the blacktext structure when the text is released from the other languages. This did not seem to be too big of an issue as gs_text_begin passes the pgs also. If the pgs is not available, NULL can be passed, and that is done in several locations. A new special op was added to let us avoid doing the black text setting if we are constructing a soft mask. If we did not do this the mask could result in the loss of the text. Finally, Type 3 fonts will NOT be affected by this process. Type 3 fonts are often used for actual graphic logos etc. Ken Sharp suggested we not have them affected by this setting. There were also issues with trying to do type 3 fonts in in that the PDF interpreter does some color space settings of its state when dealing with type 3 fonts and this put the interpreter's state out of sync with the graphic library state. This was tested with a forced setting of black text enabled. No seg faults or errors occurred. There were obviously a lot of differences reported (over 33,000). All the images that were available to me with bmpcmp were gone through. Problems were found and addressed (the soft mask issue for example was found, as were issues with color spaces not getting properly restored).
Diffstat (limited to 'base')
-rw-r--r--base/gdevp14.c3
-rw-r--r--base/gschar.c2
-rw-r--r--base/gscms.h1
-rw-r--r--base/gsdparam.c45
-rw-r--r--base/gsequivc.c3
-rw-r--r--base/gsgstate.c4
-rw-r--r--base/gsicc_blacktext.c108
-rw-r--r--base/gsicc_blacktext.h34
-rw-r--r--base/gsicc_manage.c1
-rw-r--r--base/gstext.c77
-rw-r--r--base/gstext.h2
-rw-r--r--base/gxcspace.h1
-rw-r--r--base/gxdevsop.h8
-rw-r--r--base/gxgstate.h14
-rw-r--r--base/gxpaint.c18
-rw-r--r--base/gxtext.h1
-rw-r--r--base/lib.mak12
17 files changed, 320 insertions, 14 deletions
diff --git a/base/gdevp14.c b/base/gdevp14.c
index 671b070f6..927c2ceb4 100644
--- a/base/gdevp14.c
+++ b/base/gdevp14.c
@@ -3526,6 +3526,7 @@ gs_pdf14_device_copy_params(gx_device *dev, const gx_device *target)
dev->icc_struct->pageneutralcolor = profile_targ->pageneutralcolor;
dev->icc_struct->supports_devn = profile_targ->supports_devn;
dev->icc_struct->usefastcolor = profile_targ->usefastcolor;
+ dev->icc_struct->blacktext = profile_targ->blacktext;
if (pdev->using_blend_cs) {
/* Swap the device profile and the blend profile. */
@@ -7824,6 +7825,8 @@ pdf14_dev_spec_op(gx_device *pdev, int dev_spec_op,
return p14dev->overprint || p14dev->stroke_overprint;
}
}
+ if (dev_spec_op == gxdso_in_smask_construction)
+ return p14dev->in_smask_construction > 0;
if (dev_spec_op == gxdso_in_smask)
return p14dev->in_smask_construction > 0 || p14dev->depth_within_smask;
diff --git a/base/gschar.c b/base/gschar.c
index c01019d8d..e0ed7fd42 100644
--- a/base/gschar.c
+++ b/base/gschar.c
@@ -187,7 +187,7 @@ show_n_begin(gs_show_enum *penum, gs_gstate *pgs, int code, gs_text_enum_t *pte)
dev_proc_text_begin((*text_begin)) = dev_proc(dev, text_begin);
text = pte->text;
- gs_text_release(pte, "show_n_begin");
+ gs_text_release(NULL, pte, "show_n_begin");
/* Temporarily reset the text_begin procedure to the default. */
set_dev_proc(dev, text_begin, gx_default_text_begin);
code = gs_text_begin(pgs, &text, mem, &pte);
diff --git a/base/gscms.h b/base/gscms.h
index dfface693..4b77e3caf 100644
--- a/base/gscms.h
+++ b/base/gscms.h
@@ -277,6 +277,7 @@ struct cmm_dev_profile_s {
bool graydetection; /* Device param for monitoring for gray only page */
bool pageneutralcolor; /* Only valid if graydetection true */
bool usefastcolor; /* Used when we want to use no cm */
+ bool blacktext; /* Force text to be pure black */
bool supports_devn; /* If the target handles devn colors */
bool sim_overprint; /* Indicates we want to do overprint blending */
gsicc_namelist_t *spotnames; /* If our device profiles are devn */
diff --git a/base/gsdparam.c b/base/gsdparam.c
index a07a7c332..3af8e856f 100644
--- a/base/gsdparam.c
+++ b/base/gsdparam.c
@@ -87,6 +87,7 @@ int gx_default_get_param(gx_device *dev, char *Param, void *list)
bool devicegraytok = true; /* Default if device profile stuct not set */
bool graydetection = false;
bool usefastcolor = false; /* set for unmanaged color */
+ bool blacktext = false;
bool sim_overprint = true; /* By default simulate overprinting (only valid with cmyk devices) */
bool prebandthreshold = true, temp_bool = false;
@@ -340,6 +341,7 @@ int gx_default_get_param(gx_device *dev, char *Param, void *list)
devicegraytok = dev_profile->devicegraytok;
graydetection = dev_profile->graydetection;
usefastcolor = dev_profile->usefastcolor;
+ blacktext = dev_profile->blacktext;
sim_overprint = dev_profile->sim_overprint;
prebandthreshold = dev_profile->prebandthreshold;
/* With respect to Output profiles that have non-standard colorants,
@@ -380,6 +382,9 @@ int gx_default_get_param(gx_device *dev, char *Param, void *list)
if (strcmp(Param, "UseFastColor") == 0) {
return param_write_bool(plist, "UseFastColor", &usefastcolor);
}
+ if (strcmp(Param, "BlackText") == 0) {
+ return param_write_bool(plist, "BlackText", &blacktext);
+ }
if (strcmp(Param, "SimulateOverprint") == 0) {
return param_write_bool(plist, "SimulateOverprint", &sim_overprint);
}
@@ -506,6 +511,7 @@ gx_default_get_params(gx_device * dev, gs_param_list * plist)
bool devicegraytok = true; /* Default if device profile stuct not set */
bool graydetection = false;
bool usefastcolor = false; /* set for unmanaged color */
+ bool blacktext = false;
bool sim_overprint = true; /* By default simulate overprinting */
bool prebandthreshold = true, temp_bool;
int k;
@@ -619,6 +625,7 @@ gx_default_get_params(gx_device * dev, gs_param_list * plist)
devicegraytok = dev_profile->devicegraytok;
graydetection = dev_profile->graydetection;
usefastcolor = dev_profile->usefastcolor;
+ blacktext = dev_profile->blacktext;
sim_overprint = dev_profile->sim_overprint;
prebandthreshold = dev_profile->prebandthreshold;
/* With respect to Output profiles that have non-standard colorants,
@@ -679,6 +686,7 @@ gx_default_get_params(gx_device * dev, gs_param_list * plist)
(code = param_write_bool(plist, "DeviceGrayToK", &devicegraytok)) < 0 ||
(code = param_write_bool(plist, "GrayDetection", &graydetection)) < 0 ||
(code = param_write_bool(plist, "UseFastColor", &usefastcolor)) < 0 ||
+ (code = param_write_bool(plist, "BlackText", &blacktext)) < 0 ||
(code = param_write_bool(plist, "SimulateOverprint", &sim_overprint)) < 0 ||
(code = param_write_bool(plist, "PreBandThreshold", &prebandthreshold)) < 0 ||
(code = param_write_string(plist,"OutputICCProfile", &(profile_array[0]))) < 0 ||
@@ -1160,6 +1168,33 @@ gx_default_put_usefastcolor(bool fastcolor, gx_device * dev)
}
static int
+gx_default_put_blacktext(bool blacktext, gx_device* dev)
+{
+ int code = 0;
+ cmm_dev_profile_t* profile_struct;
+
+ if (dev_proc(dev, get_profile) == NULL) {
+ if (dev->icc_struct == NULL) {
+ dev->icc_struct = gsicc_new_device_profile_array(dev->memory);
+ if (dev->icc_struct == NULL)
+ return_error(gs_error_VMerror);
+ }
+ dev->icc_struct->blacktext = blacktext;
+ } else {
+ code = dev_proc(dev, get_profile)(dev, &profile_struct);
+ if (profile_struct == NULL) {
+ /* Create now */
+ dev->icc_struct = gsicc_new_device_profile_array(dev->memory);
+ profile_struct = dev->icc_struct;
+ if (profile_struct == NULL)
+ return_error(gs_error_VMerror);
+ }
+ profile_struct->blacktext = blacktext;
+ }
+ return code;
+}
+
+static int
gx_default_put_simulateoverprint(bool sim_overprint, gx_device * dev)
{
int code = 0;
@@ -1421,6 +1456,7 @@ gx_default_put_params(gx_device * dev, gs_param_list * plist)
bool devicegraytok = true;
bool graydetection = false;
bool usefastcolor = false;
+ bool blacktext = false;
bool sim_overprint = true;
bool prebandthreshold = false;
bool use_antidropout = dev->color_info.use_antidropout_downscaler;
@@ -1440,6 +1476,7 @@ gx_default_put_params(gx_device * dev, gs_param_list * plist)
graydetection = dev->icc_struct->graydetection;
devicegraytok = dev->icc_struct->devicegraytok;
usefastcolor = dev->icc_struct->usefastcolor;
+ blacktext = dev->icc_struct->blacktext;
prebandthreshold = dev->icc_struct->prebandthreshold;
sim_overprint = dev->icc_struct->sim_overprint;
} else {
@@ -1750,6 +1787,11 @@ nce:
ecode = code;
param_signal_error(plist, param_name, ecode);
}
+ if ((code = param_read_bool(plist, (param_name = "BlackText"),
+ &blacktext)) < 0) {
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ }
if ((code = param_read_bool(plist, (param_name = "SimulateOverprint"),
&sim_overprint)) < 0) {
ecode = code;
@@ -2130,6 +2172,9 @@ label:\
code = gx_default_put_usefastcolor(usefastcolor, dev);
if (code < 0)
return code;
+ code = gx_default_put_blacktext(blacktext, dev);
+ if (code < 0)
+ return code;
code = gx_default_put_simulateoverprint(sim_overprint, dev);
if (code < 0)
return code;
diff --git a/base/gsequivc.c b/base/gsequivc.c
index c268fb6d2..d61d300d7 100644
--- a/base/gsequivc.c
+++ b/base/gsequivc.c
@@ -478,7 +478,7 @@ capture_spot_equivalent_cmyk_colors(gx_device * pdev, const gs_gstate * pgs,
0 /* blend_profile */, 0 /* postren_profile */,
{ {0} } /* rendercond[] */, 0 /* devicegraytok */,
0 /* graydection */, 0 /* pageneutralcolor */,
- 0 /* usefastcolor */, 0 /* supports_devn */,
+ 0 /* usefastcolor */, 0 /* blacktext */, 0 /* supports_devn */,
0 /* sim_overprint */, 0 /* spotnames */,
0 /* prebandthreshold */, 0 /* memory */,
{ 0 } /* rc_header */
@@ -499,6 +499,7 @@ capture_spot_equivalent_cmyk_colors(gx_device * pdev, const gs_gstate * pgs,
temp_device.memory = pgs->memory;
temp_profile.usefastcolor = false; /* This avoids a few headaches */
+ temp_profile.blacktext = false;
temp_profile.prebandthreshold = true;
temp_profile.supports_devn = false;
temp_profile.rendercond[0] = render_cond;
diff --git a/base/gsgstate.c b/base/gsgstate.c
index d74a6f094..65788bf2e 100644
--- a/base/gsgstate.c
+++ b/base/gsgstate.c
@@ -142,6 +142,7 @@ gs_gstate_initialize(gs_gstate * pgs, gs_memory_t * mem)
pgs->icc_link_cache = gsicc_cache_new(pgs->memory);
pgs->icc_manager = gsicc_manager_new(pgs->memory);
pgs->icc_profile_cache = gsicc_profilecache_new(pgs->memory);
+ pgs->black_text_state = NULL;
#if ENABLE_CUSTOM_COLOR_CALLBACK
pgs->custom_color_callback = INIT_CUSTOM_COLOR_PTR;
#endif
@@ -168,6 +169,7 @@ gs_gstate_copied(gs_gstate * pgs)
rc_increment(pgs->icc_link_cache);
rc_increment(pgs->icc_profile_cache);
rc_increment(pgs->icc_manager);
+ rc_increment(pgs->black_text_state);
}
/* Adjust reference counts before assigning one gs_gstate to another. */
@@ -195,6 +197,7 @@ gs_gstate_pre_assign(gs_gstate *pto, const gs_gstate *pfrom)
RCCOPY(icc_link_cache);
RCCOPY(icc_profile_cache);
RCCOPY(icc_manager);
+ RCCOPY(black_text_state);
#undef RCCOPY
}
@@ -231,5 +234,6 @@ gs_gstate_release(gs_gstate * pgs)
RCDECR(icc_link_cache);
RCDECR(icc_profile_cache);
RCDECR(icc_manager);
+ RCDECR(black_text_state);
#undef RCDECR
}
diff --git a/base/gsicc_blacktext.c b/base/gsicc_blacktext.c
new file mode 100644
index 000000000..0868bd9cb
--- /dev/null
+++ b/base/gsicc_blacktext.c
@@ -0,0 +1,108 @@
+/* Copyright (C) 2001-2020 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* Handling of color spaces stored during replacement of all
+ * text with black.
+*/
+
+#include "gsmemory.h"
+#include "gsstruct.h"
+#include "gzstate.h"
+#include "gsicc_blacktext.h"
+
+/* gsicc_blacktext_state_t is going to be storing GCed items
+ (color spaces and client colors) and so will need to be GCed */
+gs_private_st_ptrs4(st_blacktext_state, gsicc_blacktext_state_t,
+ "gsicc_blacktext_state", blacktext_state_enum_ptrs,
+ blacktext_state_reloc_ptrs, pcs[0], pcs[1], pcc[0], pcc[1]);
+
+static void
+rc_gsicc_blacktext_state_free(gs_memory_t *mem, void *ptr_in,
+ client_name_t cname)
+{
+ gsicc_blacktext_state_t *state = (gsicc_blacktext_state_t*)ptr_in;
+
+ rc_decrement_cs(state->pcs[0], "rc_gsicc_blacktext_state_free");
+ rc_decrement_cs(state->pcs[1], "rc_gsicc_blacktext_state_free");
+
+ gs_free_object(mem->stable_memory, state,
+ "rc_gsicc_blacktext_state_free");
+}
+
+gsicc_blacktext_state_t*
+gsicc_blacktext_state_new(gs_memory_t *memory)
+{
+ gsicc_blacktext_state_t *result;
+
+ result = gs_alloc_struct(memory->stable_memory, gsicc_blacktext_state_t,
+ &st_blacktext_state, "gsicc_blacktext_state_new");
+ if (result == NULL)
+ return NULL;
+ rc_init_free(result, memory->stable_memory, 1, rc_gsicc_blacktext_state_free);
+ result->memory = memory;
+ result->pcs[0] = NULL;
+ result->pcs[1] = NULL;
+ result->pcc[0] = NULL;
+ result->pcc[1] = NULL;
+
+ return result;
+}
+
+void
+gsicc_restore_black_text(gs_gstate *pgs)
+{
+ gsicc_blacktext_state_t *state = pgs->black_text_state;
+ int code;
+
+ if (state == NULL)
+ return;
+
+ /* Make sure state and original are same fill_color condition */
+ if (state->rc.ref_count == 1) {
+ if ((state->is_fill && pgs->is_fill_color) ||
+ (!state->is_fill && !pgs->is_fill_color)) {
+
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[0])) >= 0) {
+ /* current client color is gray. no need to decrement */
+ pgs->color[0].ccolor = pgs->black_text_state->pcc[0];
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[0];
+ }
+ gs_swapcolors_quick(pgs);
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[1])) >= 0) {
+ pgs->color[0].ccolor = pgs->black_text_state->pcc[1];
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[1];
+
+ }
+ gs_swapcolors_quick(pgs);
+
+ } else {
+
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[1])) >= 0) {
+ pgs->color[0].ccolor = pgs->black_text_state->pcc[1];
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[1];
+ }
+ gs_swapcolors_quick(pgs);
+ if ((code = gs_setcolorspace_only(pgs, pgs->black_text_state->pcs[0])) >= 0) {
+ pgs->color[0].ccolor = pgs->black_text_state->pcc[0];
+ pgs->color[0].ccolor->paint.values[0] = pgs->black_text_state->value[0];
+ }
+ gs_swapcolors_quick(pgs);
+ }
+ gx_unset_dev_color(pgs);
+ gx_unset_alt_dev_color(pgs);
+ }
+ rc_decrement(state, "gsicc_restore_black_text");
+ pgs->black_text_state = NULL;
+} \ No newline at end of file
diff --git a/base/gsicc_blacktext.h b/base/gsicc_blacktext.h
new file mode 100644
index 000000000..cfd45b9aa
--- /dev/null
+++ b/base/gsicc_blacktext.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2001-2020 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+#ifndef gsicc_blacktext_INCLUDED
+# define gsicc_blacktext_INCLUDED
+
+typedef struct gsicc_blacktext_state_s gsicc_blacktext_state_t;
+
+struct gsicc_blacktext_state_s {
+ gs_memory_t *memory;
+ rc_header rc;
+ bool is_fill; /* Needed for proper color restore */
+ gs_color_space *pcs[2]; /* If doing black text, color spaces to restore */
+ gs_client_color *pcc[2]; /* If doing black text, client colors to restore */
+ float value[2]; /* DeviceGray setting blows away the client color
+ zero value */
+};
+
+gsicc_blacktext_state_t* gsicc_blacktext_state_new(gs_memory_t *memory);
+void gsicc_restore_black_text(gs_gstate *pgs);
+
+#endif
diff --git a/base/gsicc_manage.c b/base/gsicc_manage.c
index 8d28bcf11..cf314a7e2 100644
--- a/base/gsicc_manage.c
+++ b/base/gsicc_manage.c
@@ -1453,6 +1453,7 @@ gsicc_new_device_profile_array(gs_memory_t *memory)
result->graydetection = false;
result->pageneutralcolor = false;
result->usefastcolor = false; /* Default is to not use fast color */
+ result->blacktext = false;
result->prebandthreshold = true;
result->supports_devn = false;
result->sim_overprint = true; /* Default is to simulate overprint */
diff --git a/base/gstext.c b/base/gstext.c
index bcf21ec59..cf78b6356 100644
--- a/base/gstext.c
+++ b/base/gstext.c
@@ -32,6 +32,8 @@
#include "gzstate.h"
#include "gsutil.h"
#include "gxdevsop.h"
+#include "gscspace.h"
+#include "gsicc_blacktext.h"
/* GC descriptors */
public_st_gs_text_params();
@@ -212,6 +214,7 @@ gs_text_enum_init(gs_text_enum_t *pte, const gs_text_enum_procs_t *procs,
pte->log2_scale.x = pte->log2_scale.y = 0;
/* init_dynamic sets index, xy_index, fstack */
code = gs_text_enum_init_dynamic(pte, font);
+ pte->k_text_release = 0;
if (code >= 0)
rc_increment(dev);
return code;
@@ -278,6 +281,23 @@ gs_text_begin(gs_gstate * pgs, const gs_text_params_t * text,
(pgs->text_rendering_mode == 0));
bool text_op_stroke = ((pgs->stroke_overprint || (!pgs->stroke_overprint && op_active)) &&
(pgs->text_rendering_mode == 1));
+ bool type3 = (pgs->font->FontType == ft_user_defined ||
+ pgs->font->FontType == ft_PDF_user_defined ||
+ pgs->font->FontType == ft_PCL_user_defined ||
+ pgs->font->FontType == ft_MicroType ||
+ pgs->font->FontType == ft_GL2_stick_user_defined ||
+ pgs->font->FontType == ft_GL2_531);
+ bool in_smask =
+ (dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_in_smask_construction, NULL, 0)) > 0;
+ bool black_text = (text->operation & (TEXT_DO_DRAW | TEXT_DO_ANY_CHARPATH)) &&
+ !type3 && !in_smask;
+ cmm_dev_profile_t *icc_struct;
+
+ code = dev_proc(pgs->device, get_profile)((gx_device *)pgs->device, &icc_struct);
+ if (code < 0)
+ black_text = 0;
+ else
+ black_text = black_text && icc_struct->blacktext;
/*
* Detect nocurrentpoint now, even if the string is empty, for Adobe
@@ -311,9 +331,40 @@ gs_text_begin(gs_gstate * pgs, const gs_text_params_t * text,
/* Processing a text object operation */
ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
+ if (black_text && pgs->black_text_state == NULL) {
+ gs_color_space *pcs_curr = gs_currentcolorspace_inline(pgs);
+ gs_color_space *pcs_alt = gs_altcolorspace_inline(pgs);
+
+ pgs->black_text_state = gsicc_blacktext_state_new(pgs->memory);
+ if (pgs->black_text_state == NULL)
+ return gs_error_VMerror;
+
+ rc_increment_cs(pcs_curr);
+ rc_increment_cs(pcs_alt);
+ pgs->black_text_state->pcs[0] = pcs_curr;
+ pgs->black_text_state->pcs[1] = pcs_alt;
+
+ pgs->black_text_state->pcc[0] = pgs->color[0].ccolor;
+ cs_adjust_color_count(pgs, 1); /* The set_gray will do a decrement */
+ pgs->black_text_state->value[0] = pgs->color[0].ccolor->paint.values[0];
+ gs_setgray(pgs, 0.0);
+
+ gs_swapcolors_quick(pgs);
+
+ pgs->black_text_state->pcc[1] = pgs->color[0].ccolor;
+ cs_adjust_color_count(pgs, 1);
+ pgs->black_text_state->value[1] = pgs->color[0].ccolor->paint.values[0];
+ gs_setgray(pgs, 0.0);
+
+ gs_swapcolors_quick(pgs);
+
+ pgs->black_text_state->is_fill = pgs->is_fill_color;
+ }
+
code = gx_set_dev_color(pgs);
if (code != 0)
return code;
+
code = gs_gstate_color_load(pgs);
if (code < 0)
return code;
@@ -354,10 +405,30 @@ gs_text_begin(gs_gstate * pgs, const gs_text_params_t * text,
}
pgs->device->sgr.stroke_stored = false;
- return gx_device_text_begin(pgs->device, pgs,
+ code = gx_device_text_begin(pgs->device, pgs,
text, pgs->font, pgs->path,
gs_currentdevicecolor_inline(pgs),
pcpath, mem, ppte);
+
+ /* we need to know if we are doing a highlevel device.
+ Also we need to know if we are doing any stroke
+ or stroke fill operations. This determines when
+ we need to release the black_text_state structure. */
+ if (*ppte != NULL) {
+ if (black_text) {
+ if (!((*ppte)->k_text_release)) {
+ /* Not a high level device */
+ if (pgs->text_rendering_mode == 0 ||
+ pgs->text_rendering_mode == 4) {
+ /* No stroke */
+ (*ppte)->k_text_release = 1;
+ }
+ }
+ } else
+ (*ppte)->k_text_release = 0;
+ }
+
+ return code;
}
/*
@@ -762,8 +833,10 @@ rc_free_text_enum(gs_memory_t * mem, void *obj, client_name_t cname)
rc_free_struct_only(mem, obj, cname);
}
void
-gs_text_release(gs_text_enum_t * pte, client_name_t cname)
+gs_text_release(gs_gstate *pgs, gs_text_enum_t * pte, client_name_t cname)
{
+ if (pgs != NULL && pgs->black_text_state != NULL)
+ gsicc_restore_black_text(pgs);
rc_decrement_only(pte, cname);
}
diff --git a/base/gstext.h b/base/gstext.h
index 9b87c8f66..39381d80f 100644
--- a/base/gstext.h
+++ b/base/gstext.h
@@ -299,7 +299,7 @@ int
int gs_text_retry(gs_text_enum_t *pte);
/* Release the text processing structures. */
-void gs_text_release(gs_text_enum_t *pte, client_name_t cname);
+void gs_text_release(gs_gstate *pgs, gs_text_enum_t *pte, client_name_t cname);
/* Compute the number of characters in a text. */
int gs_text_count_chars(gs_gstate * pgs, gs_text_params_t *text, gs_memory_t * mem);
diff --git a/base/gxcspace.h b/base/gxcspace.h
index 3218019c8..ff1963b83 100644
--- a/base/gxcspace.h
+++ b/base/gxcspace.h
@@ -165,6 +165,7 @@ struct gs_color_space_type_s {
#define cs_proc_adjust_color_count(proc)\
void proc(const gs_client_color *, const gs_color_space *, int)
+
#define cs_adjust_color_count(pgs, delta)\
(*gs_currentcolorspace_inline(pgs)->type->adjust_color_count)\
(gs_currentcolor_inline(pgs), gs_currentcolorspace_inline(pgs), delta)
diff --git a/base/gxdevsop.h b/base/gxdevsop.h
index f41a780a9..e2c6a774e 100644
--- a/base/gxdevsop.h
+++ b/base/gxdevsop.h
@@ -366,7 +366,13 @@ enum {
* 0 otherwise.
*/
gxdso_in_smask,
-
+ /* gxdso_in_smask_construction:
+ * data = NULL
+ * size = 0
+ * Returns 1 if we are within an smask construction,
+ * 0 otherwise.
+ */
+ gxdso_in_smask_construction,
/* Debug only dsos follow here */
#ifdef DEBUG
/* Private dso used to check that a printer device properly forwards to the default */
diff --git a/base/gxgstate.h b/base/gxgstate.h
index 2ab96a3fe..07d4a6743 100644
--- a/base/gxgstate.h
+++ b/base/gxgstate.h
@@ -42,6 +42,7 @@
#include "gsccolor.h"
#include "gsht1.h"
#include "gxclipsr.h"
+#include "gsicc_blacktext.h"
/*
@@ -202,6 +203,8 @@ typedef struct gs_xstate_trans_flags {
#define gs_currentcolor_inline(pgs) ((pgs)->color[0].ccolor)
#define gs_currentcolorspace_inline(pgs) ((pgs)->color[0].color_space)
#define gs_altdevicecolor_inline(pgs) ((pgs)->color[1].dev_color)
+#define gs_altcolor_inline(pgs) ((pgs)->color[1].ccolor)
+#define gs_altcolorspace_inline(pgs) ((pgs)->color[1].color_space)
#define gs_currentcolor_eopm(pgs) ((pgs)->color[0].effective_opm)
#define char_tm_only(pgs) *(gs_matrix *)&(pgs)->char_tm
@@ -261,6 +264,8 @@ struct gs_gstate_s {
gsicc_manager_t *icc_manager; /* ICC color manager, profile */
gsicc_link_cache_t *icc_link_cache; /* ICC linked transforms */
gsicc_profile_cache_t *icc_profile_cache; /* ICC profiles from PS. */
+ gsicc_blacktext_state_t *black_text_state; /* Used to store and restore cs for black text */
+
CUSTOM_COLOR_PTR /* Pointer to custom color callback struct */
const gx_color_map_procs *
(*get_cmap_procs)(const gs_gstate *, const gx_device *);
@@ -326,7 +331,7 @@ struct gs_gstate_s {
lop_default, BLEND_MODE_Compatible,\
{0, 0}, 0, 1/*true*/, 0, 0/*false*/, 0, 0/*false*/, 0, 0/*false*/, 1.0, \
{ fixed_half, fixed_half }, 0/*false*/, 1/*true*/, 0/*false*/, (float)0.02,\
- 1, 1/* bpt true */, 0, 0, 0, INIT_CUSTOM_COLOR_PTR /* 'Custom color' callback pointer */ \
+ 1, 1/* bpt true */, 0, 0, 0, 0, INIT_CUSTOM_COLOR_PTR /* 'Custom color' callback pointer */ \
gx_default_get_cmap_procs
#define GS_STATE_INIT_VALUES(s, scale) \
@@ -364,6 +369,7 @@ struct gs_gstate_s {
s->icc_link_cache = __state_init.icc_link_cache; \
s->icc_profile_cache = __state_init.icc_profile_cache; \
s->get_cmap_procs = __state_init.get_cmap_procs; \
+ s->black_text_state = NULL; \
s->show_gstate = NULL; \
s->is_fill_color = 1; \
s->strokeconstantalpha = 1.0; \
@@ -406,9 +412,10 @@ struct_proc_finalize(gs_gstate_finalize);
m(16, color[1].dev_color)\
m(17, font) \
m(18, root_font) \
- m(19, show_gstate)
+ m(19, show_gstate) \
+ m(20, black_text_state)
-#define gs_gstate_num_ptrs 20
+#define gs_gstate_num_ptrs 21
/* The '+1' in the following is because gs_gstate.device
* is handled specially
@@ -430,7 +437,6 @@ void gs_gstate_pre_assign(gs_gstate *to, const gs_gstate *from);
void gs_gstate_release(gs_gstate * pgs);
int gs_currentscreenphase_pgs(const gs_gstate *, gs_int_point *, gs_color_select_t);
-
/* The following macro is used for development purpose for designating places
where current point is changed. Clients must not use it. */
#define gx_setcurrentpoint(pgs, xx, yy)\
diff --git a/base/gxpaint.c b/base/gxpaint.c
index f570334ec..1afe6819a 100644
--- a/base/gxpaint.c
+++ b/base/gxpaint.c
@@ -67,9 +67,16 @@ gx_stroke_fill(gx_path * ppath, gs_gstate * pgs)
return code;
params.flatness = (caching_an_outline_font(pgs) ? 0.0 : pgs->flatness);
params.traditional = false;
- return (*dev_proc(dev, stroke_path))
+
+ code = (*dev_proc(dev, stroke_path))
(dev, (const gs_gstate *)pgs, ppath, &params,
gs_currentdevicecolor_inline(pgs), pcpath);
+
+ if (pgs->black_text_state) {
+ gsicc_restore_black_text(pgs);
+ }
+
+ return code;
}
int
@@ -89,11 +96,18 @@ gx_fill_stroke_path(gs_gstate * pgs, int rule)
fill_params.flatness = (caching_an_outline_font(pgs) ? 0.0 : pgs->flatness);
stroke_params.flatness = (caching_an_outline_font(pgs) ? 0.0 : pgs->flatness);
stroke_params.traditional = false;
- return (*dev_proc(dev, fill_stroke_path))
+
+ code = (*dev_proc(dev, fill_stroke_path))
(dev, (const gs_gstate *)pgs, pgs->path,
&fill_params, gs_currentdevicecolor_inline(pgs),
&stroke_params, gs_altdevicecolor_inline(pgs),
pcpath);
+
+ if (pgs->black_text_state) {
+ gsicc_restore_black_text(pgs);
+ }
+
+ return code;
}
int
diff --git a/base/gxtext.h b/base/gxtext.h
index ba18fca8e..67ec70291 100644
--- a/base/gxtext.h
+++ b/base/gxtext.h
@@ -126,6 +126,7 @@ rc_free_proc(rc_free_text_enum);
int bytes_decoded; \
gs_point FontBBox_as_Metrics2; /* used with FontType 9,11 && WMode 1 */\
ulong text_enum_id; /* debug purpose only - not used by algorythm. */\
+ bool k_text_release; /* Set at time of gs_text_begin to know to do release of black_text_state */\
/* The following is controlled by a device. */\
bool device_disabled_grid_fitting;\
/* Following two members moved from the show enumerator */\
diff --git a/base/lib.mak b/base/lib.mak
index 62105ccd4..5030a0141 100644
--- a/base/lib.mak
+++ b/base/lib.mak
@@ -1106,7 +1106,8 @@ $(GLOBJ)gsstate.$(OBJ) : $(GLSRC)gsstate.c $(AK) $(gx_h) $(gserrors_h)\
$(GLOBJ)gstext.$(OBJ) : $(GLSRC)gstext.c $(AK) $(memory__h) $(gdebug_h)\
$(gserrors_h) $(gsmemory_h) $(gsstruct_h) $(gstypes_h)\
$(gxfcache_h) $(gxdevcli_h) $(gxdcolor_h) $(gxfont_h) $(gxpath_h)\
- $(gxtext_h) $(gzstate_h) $(gsutil_h) $(gxdevsop_h) $(LIB_MAK) $(MAKEDIRS)
+ $(gxtext_h) $(gzstate_h) $(gsutil_h) $(gxdevsop_h)\
+ $(gscspace_h) $(gsicc_blacktext_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gstext.$(OBJ) $(C_) $(GLSRC)gstext.c
# We make gsiodevs a separate module so the PS interpreter can replace it.
@@ -2959,7 +2960,8 @@ $(GLOBJ)gxctable.$(OBJ) : $(GLSRC)gxctable.c $(AK) $(gx_h)\
gsicc_=$(GLOBJ)gsicc_manage.$(OBJ) $(GLOBJ)gsicc_cache.$(OBJ)\
$(GLOBJ)gsicc_$(WHICH_CMS).$(OBJ) $(GLOBJ)gsicc_profilecache.$(OBJ)\
$(GLOBJ)gsicc_create.$(OBJ) $(GLOBJ)gsicc_nocm.$(OBJ)\
- $(GLOBJ)gsicc_replacecm.$(OBJ) $(GLOBJ)gsicc_monitorcm.$(OBJ)
+ $(GLOBJ)gsicc_replacecm.$(OBJ) $(GLOBJ)gsicc_monitorcm.$(OBJ)\
+ $(GLOBJ)gsicc_blacktext.$(OBJ)
sicclib_=$(GLOBJ)gsicc.$(OBJ)
$(GLD)sicclib.dev : $(LIB_MAK) $(ECHOGS_XE) $(sicclib_) $(gsicc_) $(md5_)\
@@ -2980,6 +2982,7 @@ gsicc_cms_h=$(GLSRC)gsicc_cms.h
gsicc_manage_h=$(GLSRC)gsicc_manage.h
gsicc_cache_h=$(GLSRC)gsicc_cache.h
gsicc_profilecache_h=$(GLSRC)gsicc_profilecache.h
+gsicc_blacktext_h=$(GLSRC)gsicc_blacktext.h
$(GLOBJ)gsicc_monitorcm.$(OBJ) : $(GLSRC)gsicc_monitorcm.c $(AK) $(std_h)\
$(stdpre_h) $(gstypes_h) $(gsmemory_h) $(gxdevcli_h)\
@@ -3020,6 +3023,11 @@ $(GLOBJ)gsicc_profilecache.$(OBJ) : $(GLSRC)gsicc_profilecache.c $(AK)\
$(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gsicc_profilecache.$(OBJ) $(C_) $(GLSRC)gsicc_profilecache.c
+$(GLOBJ)gsicc_blacktext.$(OBJ) : $(GLSRC)gsicc_blacktext.c $(AK)\
+ $(gsmemory_h) $(gsstruct_h) $(gzstate_h) $(gsicc_blacktext_h)\
+ $(LIB_MAK) $(MAKEDIRS)
+ $(GLCC) $(GLO_)gsicc_blacktext.$(OBJ) $(C_) $(GLSRC)gsicc_blacktext.c
+
$(GLOBJ)gsicc_lcms2mt_1_0.$(OBJ) : $(GLSRC)gsicc_lcms2mt.c\
$(memory__h) $(gsicc_cms_h) $(gslibctx_h) $(gserrors_h) $(gxdevice_h) $(LIB_MAK) $(MAKEDIRS)
$(GLLCMS2MTCC) $(GLO_)gsicc_lcms2mt_1_0.$(OBJ) $(C_) $(GLSRC)gsicc_lcms2mt.c