1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /*  GS ICC link cache.  Initial stubbing of functions.  */
17 
18 #include "std.h"
19 #include "stdpre.h"
20 #include "gstypes.h"
21 #include "gsmemory.h"
22 #include "gsstruct.h"
23 #include "scommon.h"
24 #include "gx.h"
25 #include "gpsync.h"	/* for MAX_THREADS */
26 #include "gxgstate.h"
27 #include "smd5.h"
28 #include "gscms.h"
29 #include "gsicc_cms.h"
30 #include "gsicc_manage.h"
31 #include "gsicc_cache.h"
32 #include "gserrors.h"
33 #include "gsmalloc.h" /* Needed for named color structure allocation */
34 #include "string_.h"  /* Needed for named color structure allocation */
35 #include "gxsync.h"
36 #include "gzstate.h"
37 #include "stdint_.h"
38         /*
39          *  Note that the the external memory used to maintain
40          *  links in the CMS is generally not visible to GS.
41          *  For most CMS's the  links are 33x33x33x33x4 bytes at worst
42          *  for a CMYK to CMYK MLUT which is about 4.5Mb per link.
43          *  If the link were matrix based it would be much much smaller.
44          *  We will likely want to do at least have an estimate of the
45          *  memory used based upon how the CMS is configured.
46          *  This will be done later.  For now, just limit the number
47          *  of links.
48          */
49 #define ICC_CACHE_MAXLINKS (MAX_THREADS*2)	/* allow up to two active links per thread */
50 
51 /* Static prototypes */
52 
53 static gsicc_link_t * gsicc_alloc_link(gs_memory_t *memory, gsicc_hashlink_t hashcode);
54 
55 static int gsicc_get_cspace_hash(gsicc_manager_t *icc_manager, gx_device *dev,
56                                  cmm_profile_t *profile, int64_t *hash);
57 
58 static int gsicc_compute_linkhash(gsicc_manager_t *icc_manager, gx_device *dev,
59                                   cmm_profile_t *input_profile,
60                                   cmm_profile_t *output_profile,
61                                   gsicc_rendering_param_t *rendering_params,
62                                   gsicc_hashlink_t *hash);
63 
64 static void gsicc_remove_link(gsicc_link_t *link, const gs_memory_t *memory);
65 
66 static void gsicc_get_buff_hash(unsigned char *data, int64_t *hash, unsigned int num_bytes);
67 
68 static void rc_gsicc_link_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname);
69 
70 /* Structure pointer information */
71 
72 struct_proc_finalize(icc_link_finalize);
73 
74 gs_private_st_ptrs3_final(st_icc_link, gsicc_link_t, "gsiccmanage_link",
75                     icc_link_enum_ptrs, icc_link_reloc_ptrs, icc_link_finalize,
76                     icc_link_cache, next, lock);
77 
78 struct_proc_finalize(icc_linkcache_finalize);
79 
80 gs_private_st_ptrs3_final(st_icc_linkcache, gsicc_link_cache_t, "gsiccmanage_linkcache",
81                     icc_linkcache_enum_ptrs, icc_linkcache_reloc_ptrs, icc_linkcache_finalize,
82                     head, lock, full_wait);
83 
84 /* These are used to construct a hash for the ICC link based upon the
85    render parameters */
86 
87 #define BP_SHIFT 0
88 #define REND_SHIFT 8
89 #define PRESERVE_SHIFT 16
90 
91 /**
92  * gsicc_cache_new: Allocate a new ICC cache manager
93  * Return value: Pointer to allocated manager, or NULL on failure.
94  **/
95 
96 gsicc_link_cache_t *
gsicc_cache_new(gs_memory_t * memory)97 gsicc_cache_new(gs_memory_t *memory)
98 {
99     gsicc_link_cache_t *result;
100 
101     /* We want this to be maintained in stable_memory.  It should be be effected by the
102        save and restores */
103     result = gs_alloc_struct(memory->stable_memory, gsicc_link_cache_t, &st_icc_linkcache,
104                              "gsicc_cache_new");
105     if ( result == NULL )
106         return(NULL);
107     result->head = NULL;
108     result->num_links = 0;
109     result->cache_full = false;
110     result->memory = memory->stable_memory;
111     result->lock = gx_monitor_label(gx_monitor_alloc(memory->stable_memory),
112                                     "gsicc_cache_new");
113     if (result->lock == NULL) {
114         gs_free_object(memory->stable_memory, result, "gsicc_cache_new");
115         return(NULL);
116     }
117     result->full_wait = gx_semaphore_label(gx_semaphore_alloc(memory->stable_memory),
118                                     "gsicc_cache_new");
119     if (result->full_wait == NULL) {
120         gx_monitor_free(result->lock);
121         gs_free_object(memory->stable_memory, result, "gsicc_cache_new");
122         return(NULL);
123     }
124     rc_init_free(result, memory->stable_memory, 1, rc_gsicc_link_cache_free);
125     if_debug2m(gs_debug_flag_icc, memory,
126                "[icc] Allocating link cache = 0x%p memory = 0x%p\n",
127 	       result, result->memory);
128     return(result);
129 }
130 
131 static void
rc_gsicc_link_cache_free(gs_memory_t * mem,void * ptr_in,client_name_t cname)132 rc_gsicc_link_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname)
133 {
134     /* Ending the entire cache.  The ref counts on all the links should be 0 */
135     gsicc_link_cache_t *link_cache = (gsicc_link_cache_t * ) ptr_in;
136 
137     if_debug2m(gs_debug_flag_icc, mem,
138                "[icc] Removing link cache = 0x%p memory = 0x%p\n",
139                link_cache, link_cache->memory);
140     /* NB: freeing the link_cache will call icc_linkcache_finalize */
141     gs_free_object(mem->stable_memory, link_cache, "rc_gsicc_link_cache_free");
142 }
143 
144 /* release the monitor of the link_cache when it is freed */
145 void
icc_linkcache_finalize(const gs_memory_t * mem,void * ptr)146 icc_linkcache_finalize(const gs_memory_t *mem, void *ptr)
147 {
148     gsicc_link_cache_t *link_cache = (gsicc_link_cache_t * ) ptr;
149 
150     while (link_cache->head != NULL) {
151         if (link_cache->head->ref_count != 0) {
152             emprintf2(mem, "link at 0x%p being removed, but has ref_count = %d\n",
153                       link_cache->head, link_cache->head->ref_count);
154             link_cache->head->ref_count = 0;	/* force removal */
155         }
156         gsicc_remove_link(link_cache->head, mem);
157     }
158 #ifdef DEBUG
159     if (link_cache->num_links != 0) {
160         emprintf1(mem, "num_links is %d, should be 0.\n", link_cache->num_links);
161     }
162 #endif
163     if (link_cache->rc.ref_count == 0) {
164         gx_monitor_free(link_cache->lock);
165         link_cache->lock = NULL;
166         gx_semaphore_free(link_cache->full_wait);
167         link_cache->full_wait = 0;
168     }
169 }
170 
171 /* This is a special allocation for a link that is used by devices for
172    doing color management on post rendered data.  It is not tied into the
173    profile cache like gsicc_alloc_link. Also it goes ahead and creates
174    the link, i.e. link creation is not delayed. */
175 gsicc_link_t *
gsicc_alloc_link_dev(gs_memory_t * memory,cmm_profile_t * src_profile,cmm_profile_t * des_profile,gsicc_rendering_param_t * rendering_params)176 gsicc_alloc_link_dev(gs_memory_t *memory, cmm_profile_t *src_profile,
177     cmm_profile_t *des_profile, gsicc_rendering_param_t *rendering_params)
178 {
179     gsicc_link_t *result;
180     int cms_flags = 0;
181 
182     result = (gsicc_link_t*) gs_malloc(memory->stable_memory, 1,
183         sizeof(gsicc_link_t), "gsicc_alloc_link_dev");
184 
185     if (result == NULL)
186         return NULL;
187     result->lock = gx_monitor_label(gx_monitor_alloc(memory->stable_memory),
188         "gsicc_link_new");
189     if (result->lock == NULL) {
190         gs_free_object(memory->stable_memory, result, "gsicc_alloc_link(lock)");
191         return NULL;
192     }
193     gx_monitor_enter(result->lock);
194 
195     /* set up placeholder values */
196     result->is_monitored = false;
197     result->orig_procs.map_buffer = NULL;
198     result->orig_procs.map_color = NULL;
199     result->orig_procs.free_link = NULL;
200     result->next = NULL;
201     result->link_handle = NULL;
202     result->icc_link_cache = NULL;
203     result->procs.map_buffer = gscms_transform_color_buffer;
204     result->procs.map_color = gscms_transform_color;
205     result->procs.free_link = gscms_release_link;
206     result->hashcode.link_hashcode = 0;
207     result->hashcode.des_hash = 0;
208     result->hashcode.src_hash = 0;
209     result->hashcode.rend_hash = 0;
210     result->ref_count = 1;
211     result->includes_softproof = 0;
212     result->includes_devlink = 0;
213     result->is_identity = false;
214     result->valid = true;
215     result->memory = memory->stable_memory;
216 
217     if_debug1m('^', result->memory, "[^]icclink 0x%p init = 1\n",
218                result);
219 
220     if (src_profile->profile_handle == NULL) {
221         src_profile->profile_handle = gsicc_get_profile_handle_buffer(
222             src_profile->buffer, src_profile->buffer_size, memory->stable_memory);
223     }
224 
225     if (des_profile->profile_handle == NULL) {
226         des_profile->profile_handle = gsicc_get_profile_handle_buffer(
227             des_profile->buffer, des_profile->buffer_size, memory->stable_memory);
228     }
229 
230     /* Check for problems.. */
231     if (src_profile->profile_handle == 0 || des_profile->profile_handle == 0) {
232         gs_free_object(memory->stable_memory, result, "gsicc_alloc_link_dev");
233         return NULL;
234     }
235 
236     /* [0] is chunky, littleendian, noalpha, 16-in, 16-out */
237     result->link_handle = gscms_get_link(src_profile->profile_handle,
238         des_profile->profile_handle, rendering_params, cms_flags,
239         memory->stable_memory);
240 
241     /* Check for problems.. */
242     if (result->link_handle == NULL) {
243         gs_free_object(memory->stable_memory, result, "gsicc_alloc_link_dev");
244         return NULL;
245     }
246 
247     /* Check for identity transform */
248     if (gsicc_get_hash(src_profile) == gsicc_get_hash(des_profile))
249         result->is_identity = true;
250 
251     /* Set the rest */
252     result->data_cs = src_profile->data_cs;
253     result->num_input = src_profile->num_comps;
254     result->num_output = des_profile->num_comps;
255 
256     return result;
257 }
258 
259 /* And the related release of the link */
260 void
gsicc_free_link_dev(gs_memory_t * memory,gsicc_link_t * link)261 gsicc_free_link_dev(gs_memory_t *memory, gsicc_link_t *link)
262 {
263     gs_memory_t *nongc_mem = memory->non_gc_memory;
264     gs_free_object(nongc_mem, link, "gsicc_free_link_dev");
265 }
266 
267 static gsicc_link_t *
gsicc_alloc_link(gs_memory_t * memory,gsicc_hashlink_t hashcode)268 gsicc_alloc_link(gs_memory_t *memory, gsicc_hashlink_t hashcode)
269 {
270     gsicc_link_t *result;
271 
272     /* The link has to be added in stable memory. We want them
273        to be maintained across the gsave and grestore process */
274     result = gs_alloc_struct(memory->stable_memory, gsicc_link_t, &st_icc_link,
275                              "gsicc_alloc_link");
276     if (result == NULL)
277         return NULL;
278     /* set up placeholder values */
279     result->is_monitored = false;
280     result->orig_procs.map_buffer = NULL;
281     result->orig_procs.map_color = NULL;
282     result->orig_procs.free_link = NULL;
283     result->next = NULL;
284     result->link_handle = NULL;
285     result->procs.map_buffer = gscms_transform_color_buffer;
286     result->procs.map_color = gscms_transform_color;
287     result->procs.free_link = gscms_release_link;
288     result->hashcode.link_hashcode = hashcode.link_hashcode;
289     result->hashcode.des_hash = 0;
290     result->hashcode.src_hash = 0;
291     result->hashcode.rend_hash = 0;
292     result->ref_count = 1;		/* prevent it from being freed */
293     result->includes_softproof = 0;
294     result->includes_devlink = 0;
295     result->is_identity = false;
296     result->valid = false;		/* not yet complete */
297     result->memory = memory->stable_memory;
298 
299     result->lock = gx_monitor_label(gx_monitor_alloc(memory->stable_memory),
300                                     "gsicc_link_new");
301     if (result->lock == NULL) {
302         gs_free_object(memory->stable_memory, result, "gsicc_alloc_link(lock)");
303         return NULL;
304     }
305     gx_monitor_enter(result->lock);     /* this link is owned by this thread until built and made "valid" */
306 
307     if_debug1m('^', result->memory, "[^]icclink 0x%p init = 1\n",
308                result);
309     return result;
310 }
311 
312 static void
gsicc_set_link_data(gsicc_link_t * icc_link,void * link_handle,gsicc_hashlink_t hashcode,gx_monitor_t * lock,bool includes_softproof,bool includes_devlink,bool pageneutralcolor,gsicc_colorbuffer_t data_cs)313 gsicc_set_link_data(gsicc_link_t *icc_link, void *link_handle,
314                     gsicc_hashlink_t hashcode, gx_monitor_t *lock,
315                     bool includes_softproof, bool includes_devlink,
316                     bool pageneutralcolor, gsicc_colorbuffer_t data_cs)
317 {
318     gx_monitor_enter(lock);		/* lock the cache while changing data */
319     icc_link->link_handle = link_handle;
320     gscms_get_link_dim(link_handle, &(icc_link->num_input), &(icc_link->num_output),
321         icc_link->memory);
322     icc_link->hashcode.link_hashcode = hashcode.link_hashcode;
323     icc_link->hashcode.des_hash = hashcode.des_hash;
324     icc_link->hashcode.src_hash = hashcode.src_hash;
325     icc_link->hashcode.rend_hash = hashcode.rend_hash;
326     icc_link->includes_softproof = includes_softproof;
327     icc_link->includes_devlink = includes_devlink;
328     if ( (hashcode.src_hash == hashcode.des_hash) &&
329           !includes_softproof && !includes_devlink) {
330         icc_link->is_identity = true;
331     } else {
332         icc_link->is_identity = false;
333     }
334     /* Set up for monitoring */
335     icc_link->data_cs = data_cs;
336     if (pageneutralcolor)
337         gsicc_mcm_set_link(icc_link);
338 
339     /* release the lock of the link so it can now be used */
340     icc_link->valid = true;
341     gx_monitor_leave(icc_link->lock);
342     gx_monitor_leave(lock);	/* done with updating, let everyone run */
343 }
344 
345 static void
gsicc_link_free_contents(gsicc_link_t * icc_link)346 gsicc_link_free_contents(gsicc_link_t *icc_link)
347 {
348     icc_link->procs.free_link(icc_link);
349     gx_monitor_free(icc_link->lock);
350     icc_link->lock = NULL;
351 }
352 
353 void
gsicc_link_free(gsicc_link_t * icc_link,const gs_memory_t * memory)354 gsicc_link_free(gsicc_link_t *icc_link, const gs_memory_t *memory)
355 {
356     gsicc_link_free_contents(icc_link);
357 
358     gs_free_object(memory->stable_memory, icc_link, "gsicc_link_free");
359 }
360 
361 void
icc_link_finalize(const gs_memory_t * mem,void * ptr)362 icc_link_finalize(const gs_memory_t *mem, void *ptr)
363 {
364     gsicc_link_t *icc_link = (gsicc_link_t * ) ptr;
365 
366     gsicc_link_free_contents(icc_link);
367 }
368 
369 static void
gsicc_mash_hash(gsicc_hashlink_t * hash)370 gsicc_mash_hash(gsicc_hashlink_t *hash)
371 {
372     hash->link_hashcode =
373         (hash->des_hash >> 1) ^ (hash->rend_hash) ^ (hash->src_hash);
374 }
375 
376 int64_t
gsicc_get_hash(cmm_profile_t * profile)377 gsicc_get_hash(cmm_profile_t *profile)
378 {
379     if (!profile->hash_is_valid) {
380         int64_t hash;
381 
382         gsicc_get_icc_buff_hash(profile->buffer, &hash, profile->buffer_size);
383         profile->hashcode = hash;
384         profile->hash_is_valid = true;
385     }
386     return profile->hashcode;
387 }
388 
389 void
gsicc_get_icc_buff_hash(unsigned char * buffer,int64_t * hash,unsigned int buff_size)390 gsicc_get_icc_buff_hash(unsigned char *buffer, int64_t *hash, unsigned int buff_size)
391 {
392     gsicc_get_buff_hash(buffer, hash, buff_size);
393 }
394 
395 static void
gsicc_get_buff_hash(unsigned char * data,int64_t * hash,unsigned int num_bytes)396 gsicc_get_buff_hash(unsigned char *data, int64_t *hash, unsigned int num_bytes)
397 {
398     gs_md5_state_t md5;
399     byte digest[16];
400     int k;
401     int64_t word1,word2,shift;
402 
403    /* We could probably do something faster than this. But use this for now. */
404     gs_md5_init(&md5);
405     gs_md5_append(&md5, data, num_bytes);
406     gs_md5_finish(&md5, digest);
407 
408     /* For now, xor this into 64 bit word */
409     word1 = 0;
410     word2 = 0;
411     shift = 0;
412 
413     /* need to do it this way because of
414        potential word boundary issues */
415     for( k = 0; k<8; k++) {
416        word1 += ((int64_t) digest[k]) << shift;
417        word2 += ((int64_t) digest[k+8]) << shift;
418        shift += 8;
419     }
420     *hash = word1 ^ word2;
421 }
422 
423 /* Compute a hash code for the current transformation case.
424     This just computes a 64bit xor of upper and lower portions of
425     md5 for the input, output
426     and rendering params structure.  We may change this later */
427 static int
gsicc_compute_linkhash(gsicc_manager_t * icc_manager,gx_device * dev,cmm_profile_t * input_profile,cmm_profile_t * output_profile,gsicc_rendering_param_t * rendering_params,gsicc_hashlink_t * hash)428 gsicc_compute_linkhash(gsicc_manager_t *icc_manager, gx_device *dev,
429                        cmm_profile_t *input_profile,
430                        cmm_profile_t *output_profile,
431                        gsicc_rendering_param_t *rendering_params,
432                        gsicc_hashlink_t *hash)
433 {
434     int code;
435 
436     /* first get the hash codes for the color spaces */
437     code = gsicc_get_cspace_hash(icc_manager, dev, input_profile,
438                                  &(hash->src_hash));
439     if (code < 0)
440         return code;
441     code = gsicc_get_cspace_hash(icc_manager, dev, output_profile,
442                                  &(hash->des_hash));
443     if (code < 0)
444         return code;
445 
446     /* now for the rendering paramaters, just use the word itself.  At this
447        point in time, we only include the black point setting, the intent
448        and if we are preserving black.  We don't differentiate at this time
449        with object type since the current CMM does not create different
450        links based upon this type setting.  Other parameters such as cmm
451        and override ICC are used prior to a link creation and so should also
452        not factor into the link hash calculation */
453     hash->rend_hash = ((rendering_params->black_point_comp) << BP_SHIFT) +
454                       ((rendering_params->rendering_intent) << REND_SHIFT) +
455                       ((rendering_params->preserve_black) << PRESERVE_SHIFT);
456     /* for now, mash all of these into a link hash */
457     gsicc_mash_hash(hash);
458     return 0;
459 }
460 
461 static int
gsicc_get_cspace_hash(gsicc_manager_t * icc_manager,gx_device * dev,cmm_profile_t * cmm_icc_profile_data,int64_t * hash)462 gsicc_get_cspace_hash(gsicc_manager_t *icc_manager, gx_device *dev,
463                       cmm_profile_t *cmm_icc_profile_data, int64_t *hash)
464 {
465     cmm_dev_profile_t *dev_profile;
466     cmm_profile_t *icc_profile;
467     gsicc_rendering_param_t render_cond;
468     int code;
469 
470     if (cmm_icc_profile_data == NULL)
471     {
472         if (dev == NULL)
473             return -1;
474         code = dev_proc(dev, get_profile)(dev, &dev_profile);
475         if (code < 0)
476             return code;
477         gsicc_extract_profile(dev->graphics_type_tag, dev_profile,
478             &(icc_profile), &render_cond);
479         *hash = icc_profile->hashcode;
480         return 0;
481     }
482     if (cmm_icc_profile_data->hash_is_valid ) {
483         *hash = cmm_icc_profile_data->hashcode;
484     } else {
485         /* We need to compute for this color space */
486         gsicc_get_icc_buff_hash(cmm_icc_profile_data->buffer, hash,
487                                 cmm_icc_profile_data->buffer_size);
488         cmm_icc_profile_data->hashcode = *hash;
489         cmm_icc_profile_data->hash_is_valid = true;
490     }
491     return 0;
492 }
493 
494 gsicc_link_t*
gsicc_findcachelink(gsicc_hashlink_t hash,gsicc_link_cache_t * icc_link_cache,bool includes_proof,bool includes_devlink)495 gsicc_findcachelink(gsicc_hashlink_t hash, gsicc_link_cache_t *icc_link_cache,
496                     bool includes_proof, bool includes_devlink)
497 {
498     gsicc_link_t *curr, *prev;
499     int64_t hashcode = hash.link_hashcode;
500 
501     /* Look through the cache for the hashcode */
502     gx_monitor_enter(icc_link_cache->lock);
503 
504     /* List scanning is fast, so we scan the entire list, this includes   */
505     /* links that are currently unused, but still in the cache (zero_ref) */
506     curr = icc_link_cache->head;
507     prev = NULL;
508 
509     while (curr != NULL ) {
510         if (curr->hashcode.link_hashcode == hashcode &&
511             includes_proof == curr->includes_softproof &&
512             includes_devlink == curr->includes_devlink) {
513             /* move this one to the front of the list hoping we will use it
514                again soon */
515             if (prev != NULL) {
516                 /* if prev == NULL, curr is already the head */
517                 prev->next = curr->next;
518                 curr->next = icc_link_cache->head;
519                 icc_link_cache->head = curr;
520             }
521             /* bump the ref_count since we will be using this one */
522             curr->ref_count++;
523             if_debug3m('^', curr->memory, "[^]%s 0x%p ++ => %d\n",
524                        "icclink", curr, curr->ref_count);
525             while (curr->valid == false) {
526                 gx_monitor_leave(icc_link_cache->lock); /* exit to let other threads run briefly */
527                 gx_monitor_enter(curr->lock);			/* wait until we can acquire the lock */
528                 gx_monitor_leave(curr->lock);			/* it _should be valid now */
529                 /* If it is still not valid, but we were able to lock, it means that the thread	*/
530                 /* that was building it failed to be able to complete building it		*/
531                 /* this is probably a fatal error. MV ???					*/
532                 if (curr->valid == false) {
533 		  emprintf1(curr->memory, "link 0x%p lock released, but still not valid.\n", curr);	/* Breakpoint here */
534                 }
535                 gx_monitor_enter(icc_link_cache->lock);	/* re-enter to loop and check */
536             }
537             gx_monitor_leave(icc_link_cache->lock);
538             return(curr);	/* success */
539         }
540         prev = curr;
541         curr = curr->next;
542     }
543     gx_monitor_leave(icc_link_cache->lock);
544     return NULL;
545 }
546 
547 /* Remove link from cache.  Notify CMS and free */
548 static void
gsicc_remove_link(gsicc_link_t * link,const gs_memory_t * memory)549 gsicc_remove_link(gsicc_link_t *link, const gs_memory_t *memory)
550 {
551     gsicc_link_t *curr, *prev;
552     gsicc_link_cache_t *icc_link_cache = link->icc_link_cache;
553 
554     if_debug2m(gs_debug_flag_icc, memory,
555                "[icc] Removing link = 0x%p memory = 0x%p\n", link,
556                memory->stable_memory);
557     /* NOTE: link->ref_count must be 0: assert ? */
558     gx_monitor_enter(icc_link_cache->lock);
559     if (link->ref_count != 0) {
560       emprintf2(memory, "link at 0x%p being removed, but has ref_count = %d\n", link, link->ref_count);
561     }
562     curr = icc_link_cache->head;
563     prev = NULL;
564 
565     while (curr != NULL ) {
566         /* don't get rid of it if another thread has decided to use it */
567         if (curr == link && link->ref_count == 0) {
568             /* remove this one from the list */
569             if (prev == NULL)
570                 icc_link_cache->head = curr->next;
571             else
572                 prev->next = curr->next;
573             break;
574         }
575         prev = curr;
576         curr = curr->next;
577     }
578     /* if curr != link we didn't find it or another thread may have decided to */
579     /* use it (ref_count > 0). Skip freeing it if so.                          */
580     if (curr == link && link->ref_count == 0) {
581         icc_link_cache->num_links--;	/* no longer in the cache */
582         if (icc_link_cache->cache_full) {
583             icc_link_cache->cache_full = false;
584             gx_semaphore_signal(icc_link_cache->full_wait);	/* let a waiting thread run */
585         }
586         gx_monitor_leave(icc_link_cache->lock);
587         gsicc_link_free(link, memory);	/* outside link cache now. */
588     } else {
589         /* even if we didn't find the link to remove, unlock the cache */
590         gx_monitor_leave(icc_link_cache->lock);
591     }
592 }
593 
594 static void
gsicc_get_srcprofile(gsicc_colorbuffer_t data_cs,gs_graphics_type_tag_t graphics_type_tag,cmm_srcgtag_profile_t * srcgtag_profile,cmm_profile_t ** profile,gsicc_rendering_param_t * render_cond)595 gsicc_get_srcprofile(gsicc_colorbuffer_t data_cs,
596     gs_graphics_type_tag_t graphics_type_tag,
597     cmm_srcgtag_profile_t *srcgtag_profile, cmm_profile_t **profile,
598     gsicc_rendering_param_t *render_cond)
599 {
600     (*profile) = NULL;
601     (*render_cond).rendering_intent = gsPERCEPTUAL;
602     (*render_cond).cmm = gsCMM_DEFAULT;
603     switch (graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS) {
604     case GS_UNKNOWN_TAG:
605     case GS_UNTOUCHED_TAG:
606     default:
607         break;
608     case GS_PATH_TAG:
609         if (data_cs == gsRGB) {
610             (*profile) = srcgtag_profile->rgb_profiles[gsSRC_GRAPPRO];
611             *render_cond = srcgtag_profile->rgb_rend_cond[gsSRC_GRAPPRO];
612         }
613         else if (data_cs == gsCMYK) {
614             (*profile) = srcgtag_profile->cmyk_profiles[gsSRC_GRAPPRO];
615             *render_cond = srcgtag_profile->cmyk_rend_cond[gsSRC_GRAPPRO];
616         }
617         else if (data_cs == gsGRAY) {
618             (*profile) = srcgtag_profile->gray_profiles[gsSRC_GRAPPRO];
619             *render_cond = srcgtag_profile->gray_rend_cond[gsSRC_GRAPPRO];
620         }
621         break;
622     case GS_IMAGE_TAG:
623         if (data_cs == gsRGB) {
624             (*profile) = srcgtag_profile->rgb_profiles[gsSRC_IMAGPRO];
625             *render_cond = srcgtag_profile->rgb_rend_cond[gsSRC_IMAGPRO];
626         }
627         else if (data_cs == gsCMYK) {
628             (*profile) = srcgtag_profile->cmyk_profiles[gsSRC_IMAGPRO];
629             *render_cond = srcgtag_profile->cmyk_rend_cond[gsSRC_IMAGPRO];
630         }
631         else if (data_cs == gsGRAY) {
632             (*profile) = srcgtag_profile->gray_profiles[gsSRC_IMAGPRO];
633             *render_cond = srcgtag_profile->gray_rend_cond[gsSRC_IMAGPRO];
634         }
635         break;
636     case GS_TEXT_TAG:
637         if (data_cs == gsRGB) {
638             (*profile) = srcgtag_profile->rgb_profiles[gsSRC_TEXTPRO];
639             *render_cond = srcgtag_profile->rgb_rend_cond[gsSRC_TEXTPRO];
640         }
641         else if (data_cs == gsCMYK) {
642             (*profile) = srcgtag_profile->cmyk_profiles[gsSRC_TEXTPRO];
643             *render_cond = srcgtag_profile->cmyk_rend_cond[gsSRC_TEXTPRO];
644         }
645         else if (data_cs == gsGRAY) {
646             (*profile) = srcgtag_profile->gray_profiles[gsSRC_TEXTPRO];
647             *render_cond = srcgtag_profile->gray_rend_cond[gsSRC_TEXTPRO];
648         }
649         break;
650     }
651 }
652 
653 gsicc_link_t*
gsicc_get_link(const gs_gstate * pgs1,gx_device * dev_in,const gs_color_space * pcs_in,gs_color_space * output_colorspace,gsicc_rendering_param_t * rendering_params,gs_memory_t * memory)654 gsicc_get_link(const gs_gstate *pgs1, gx_device *dev_in,
655                const gs_color_space *pcs_in,
656                gs_color_space *output_colorspace,
657                gsicc_rendering_param_t *rendering_params, gs_memory_t *memory)
658 {
659     cmm_profile_t *gs_input_profile;
660     cmm_profile_t *gs_srcgtag_profile = NULL;
661     cmm_profile_t *gs_output_profile;
662     gs_gstate *pgs = (gs_gstate *)pgs1;
663     gx_device *dev;
664     gsicc_rendering_param_t render_cond;
665     cmm_dev_profile_t *dev_profile;
666     int code;
667     bool devicegraytok;
668     gs_color_space *input_colorspace = (gs_color_space*) pcs_in;
669 
670     if (dev_in == NULL) {
671         /* Get from the gs_gstate which is going to be a graphic state.
672            This only occurs for the other (non-ps/pdf) interpreters */
673         pgs = (gs_gstate*) pgs;
674         dev = pgs->device;
675     } else {
676         dev = dev_in;
677     }
678     if (input_colorspace->cmm_icc_profile_data == NULL) {
679         if (input_colorspace->icc_equivalent != NULL) {
680             gs_input_profile = input_colorspace->icc_equivalent->cmm_icc_profile_data;
681         } else {
682             /* Use default type */
683             gs_input_profile = gsicc_get_gscs_profile(input_colorspace,
684                                                       pgs->icc_manager);
685         }
686     } else {
687         gs_input_profile = input_colorspace->cmm_icc_profile_data;
688     }
689     code = dev_proc(dev, get_profile)(dev,  &dev_profile);
690     if (code < 0)
691         return NULL;
692     /* If present, use an graphic object defined source profile */
693     if (pgs->icc_manager != NULL &&
694         pgs->icc_manager->srcgtag_profile != NULL) {
695             if (gs_input_profile->data_cs == gsRGB
696                 || gs_input_profile->data_cs == gsCMYK
697                 || gs_input_profile->data_cs == gsGRAY) {
698                 gsicc_get_srcprofile(gs_input_profile->data_cs,
699                                       dev->graphics_type_tag,
700                                       pgs->icc_manager->srcgtag_profile,
701                                       &(gs_srcgtag_profile), &render_cond);
702                 if (gs_srcgtag_profile != NULL) {
703                     /* In this case, the user is letting the source profiles
704                        drive the color management.  Let that set the
705                        rendering intent and blackpoint compensation also as they
706                        must know what they are doing.  However, before we do
707                        this we need to check if they want to overide
708                        embedded source profiles.   See if our profile is a
709                        default one that came from DefaultRGB or DefaultCMYK
710                        for example */
711                     int csi;
712 
713                     csi = gsicc_get_default_type(gs_input_profile);
714                     if (render_cond.override_icc ||
715                         csi == gs_color_space_index_DeviceRGB ||
716                         csi == gs_color_space_index_DeviceCMYK ||
717                         csi == gs_color_space_index_DeviceGray) {
718                         gs_input_profile = gs_srcgtag_profile;
719                         (*rendering_params) = render_cond;
720                     }
721                     /* We also need to worry about the case when the source
722                        profile is actually a device link profile.  In this case
723                        we can go ahead now and the our link transform as we
724                        don't need to worry about a destination profile.
725                        However, it is possible that someone could do another
726                        device link profile associated with the device. */
727                     if (gs_input_profile->isdevlink) {
728                         /* OK. Go ahead and use this one.  Note output profile
729                            is not NULL so that we can compute a hash with out
730                            special conditional logic */
731                         rendering_params->rendering_intent =
732                             render_cond.rendering_intent & gsRI_MASK;
733                         rendering_params->black_point_comp =
734                             render_cond.black_point_comp & gsBP_MASK;
735 
736                             return gsicc_get_link_profile(pgs, dev, gs_input_profile,
737                                                           dev_profile->device_profile[0],
738                                                           rendering_params, memory,
739                                                           false);
740                     }
741                 } else {
742                     /* In this case we may be wanting for a "unmanaged color"
743                        result. This is done by specifying "None" on the
744                        particular line for that source object.  Check if this
745                        is what is desired.  If it is, then return the link now.
746                        Also need to worry about the replace case */
747                     if (render_cond.cmm == gsCMM_NONE) {
748                         gsicc_link_t *link;
749 
750                         if (gs_input_profile->data_cs == gsRGB) {
751                             link = gsicc_nocm_get_link(pgs, dev, 3);
752                         } else {
753                             link = gsicc_nocm_get_link(pgs, dev, 4);
754                         }
755                         /* Set the identity case if we are in that situation */
756                         if (link != NULL) {
757                             if (gs_input_profile->num_comps ==
758                                 dev_profile->device_profile[0]->num_comps) {
759                                 link->is_identity = true;
760                             }
761                             return link;
762                         }
763                     } else if (render_cond.cmm == gsCMM_REPLACE) {
764                         return gsicc_rcm_get_link(pgs, dev,
765                                                   gs_input_profile->data_cs);
766                         /* Note that there is never an identity case  */
767                     }
768                 }
769             }
770     }
771     if (output_colorspace != NULL) {
772         gs_output_profile = output_colorspace->cmm_icc_profile_data;
773         devicegraytok = false;
774     } else {
775         /* Use the device profile. Only use the rendering intent if it has
776            an override setting.  Also, only use the blackpoint if overide_bp
777            is set. Note that this can conflict with intents set from the source
778            objects so the user needs to understand what options to set. */
779         code = dev_proc(dev, get_profile)(dev,  &dev_profile);
780         if (code < 0)
781             return NULL;
782 
783         /* Check for unmanaged color case */
784         if (gsicc_use_fast_color(gs_input_profile) > 0 && dev_profile->usefastcolor) {
785             /* Return a "link" from the source space to the device color space */
786             gsicc_link_t *link = gsicc_nocm_get_link(pgs, dev,
787                                                      gs_input_profile->num_comps);
788             if (link != NULL) {
789                 if (gs_input_profile->num_comps ==
790                     dev_profile->device_profile[0]->num_comps) {
791                     link->is_identity = true;
792                 }
793                 return link;
794             }
795         }
796         gsicc_extract_profile(dev->graphics_type_tag, dev_profile,
797                                &(gs_output_profile), &render_cond);
798         /* Check if the incoming rendering intent was source based
799            (this can occur for high level images in the clist) in
800            that case we need to use the source ri and not the device one */
801         if (!(rendering_params->rendering_intent & gsRI_OVERRIDE)) {
802             /* No it was not.  Check if our device profile RI was specified */
803             if (render_cond.rendering_intent != gsRINOTSPECIFIED) {
804                 rendering_params->rendering_intent = render_cond.rendering_intent;
805             }
806         }
807         /* Similar for the black point compensation */
808         if (!(rendering_params->black_point_comp & gsBP_OVERRIDE)) {
809             if (render_cond.black_point_comp != gsBPNOTSPECIFIED) {
810                 rendering_params->black_point_comp = render_cond.black_point_comp;
811             }
812         }
813         /* And the Black preservation */
814         if (!(rendering_params->preserve_black & gsKP_OVERRIDE)) {
815             if (render_cond.preserve_black != gsBKPRESNOTSPECIFIED) {
816                 rendering_params->preserve_black = render_cond.preserve_black;
817             }
818         }
819         devicegraytok = dev_profile->devicegraytok;
820     }
821     /* If we are going from DeviceGray to DeviceCMYK and devicegraytok
822        is true then use the ps_gray and ps_cmyk profiles instead of these
823        profiles */
824     rendering_params->rendering_intent = rendering_params->rendering_intent & gsRI_MASK;
825     rendering_params->black_point_comp = rendering_params->black_point_comp & gsBP_MASK;
826     rendering_params->preserve_black = rendering_params->preserve_black & gsKP_MASK;
827     return gsicc_get_link_profile(pgs, dev, gs_input_profile, gs_output_profile,
828                     rendering_params, memory, devicegraytok);
829 }
830 
831 /* This operation of adding in a new link entry is actually shared amongst
832    different functions that can each add an entry.  For example, entrys may
833    come from the CMM or they may come from the non color managed approach
834    (i.e. gsicc_nocm_get_link)
835    Returns true if link was found with that has, false if alloc fails.
836 */
837 bool
gsicc_alloc_link_entry(gsicc_link_cache_t * icc_link_cache,gsicc_link_t ** ret_link,gsicc_hashlink_t hash,bool include_softproof,bool include_devlink)838 gsicc_alloc_link_entry(gsicc_link_cache_t *icc_link_cache,
839                        gsicc_link_t **ret_link, gsicc_hashlink_t hash,
840                        bool include_softproof, bool include_devlink)
841 {
842     gs_memory_t *cache_mem = icc_link_cache->memory;
843     gsicc_link_t *link;
844 
845     *ret_link = NULL;
846     /* First see if we can add a link */
847     /* TODO: this should be based on memory usage, not just num_links */
848     gx_monitor_enter(icc_link_cache->lock);
849     while (icc_link_cache->num_links >= ICC_CACHE_MAXLINKS) {
850         /* Look through the cache for first zero ref count to re-use that entry.
851            When ref counts go to zero, the icc_link will have been moved to
852            the end of the list, so the first we find is the 'oldest'.
853            If we get to the last entry we release the lock, set the cache_full
854            flag and wait on full_wait for some other thread to let this thread
855            run again after releasing a cache slot. Release the cache lock to
856            let other threads run and finish with (release) a cache entry.
857         */
858         link = icc_link_cache->head;
859         while (link != NULL ) {
860             if (link->ref_count == 0) {
861                 /* we will use this one */
862                 if_debug3m('^', cache_mem, "[^]%s 0x%lx ++ => %d\n",
863                            "icclink", (ulong)link, link->ref_count);
864                 break;
865             }
866             link = link->next;
867         }
868         if (link == NULL) {
869             icc_link_cache->cache_full = true;
870             /* unlock while waiting for a link to come available */
871             gx_monitor_leave(icc_link_cache->lock);
872             gx_semaphore_wait(icc_link_cache->full_wait);
873             /* repeat the findcachelink to see if some other thread has	*/
874             /* already started building the link we need		*/
875             *ret_link = gsicc_findcachelink(hash, icc_link_cache,
876                                             include_softproof, include_devlink);
877             /* Got a hit, return link. ref_count for the link was already bumped */
878             if (*ret_link != NULL)
879                 return true;
880 
881             gx_monitor_enter(icc_link_cache->lock);	    /* restore the lock */
882         } else {
883             /* Remove the zero ref_count link profile we found.		*/
884             /* Even if we remove this link, we may still be maxed out so*/
885             /* the outermost 'while' will check to make sure some other	*/
886             /* thread did not grab the one we remove.			*/
887             gsicc_remove_link(link, cache_mem);
888         }
889     }
890     /* insert an empty link that we will reserve so we can unlock while	*/
891     /* building the link contents. If successful, the entry will set	*/
892     /* the hash for the link, Set valid=false, and lock the profile     */
893     (*ret_link) = gsicc_alloc_link(cache_mem->stable_memory, hash);
894     /* NB: the link returned will be have the lock owned by this thread */
895     /* the lock will be released when the link becomes valid.           */
896     if (*ret_link) {
897         (*ret_link)->icc_link_cache = icc_link_cache;
898         (*ret_link)->next = icc_link_cache->head;
899         icc_link_cache->head = *ret_link;
900         icc_link_cache->num_links++;
901     }
902     /* unlock before returning */
903     gx_monitor_leave(icc_link_cache->lock);
904     return false;	/* we didn't find it, but return a link to be filled */
905 }
906 
907 /* This is the main function called to obtain a linked transform from the ICC
908    cache If the cache has the link ready, it will return it.  If not, it will
909    request one from the CMS and then return it.  We may need to do some cache
910    locking during this process to avoid multi-threaded issues (e.g. someone
911    deleting while someone is updating a reference count).  Note that if the
912    source profile is a device link profile we have no output profile but
913    may still have a proofing or another device link profile to use */
914 gsicc_link_t*
gsicc_get_link_profile(const gs_gstate * pgs,gx_device * dev,cmm_profile_t * gs_input_profile,cmm_profile_t * gs_output_profile,gsicc_rendering_param_t * rendering_params,gs_memory_t * memory,bool devicegraytok)915 gsicc_get_link_profile(const gs_gstate *pgs, gx_device *dev,
916                        cmm_profile_t *gs_input_profile,
917                        cmm_profile_t *gs_output_profile,
918                        gsicc_rendering_param_t *rendering_params,
919                        gs_memory_t *memory, bool devicegraytok)
920 {
921     gsicc_hashlink_t hash;
922     gsicc_link_t *link, *found_link;
923     gcmmhlink_t link_handle = NULL;
924     gsicc_manager_t *icc_manager = pgs->icc_manager;
925     gsicc_link_cache_t *icc_link_cache = pgs->icc_link_cache;
926     gs_memory_t *cache_mem = pgs->icc_link_cache->memory;
927     gcmmhprofile_t *cms_input_profile;
928     gcmmhprofile_t *cms_output_profile = NULL;
929     gcmmhprofile_t *cms_proof_profile = NULL;
930     gcmmhprofile_t *cms_devlink_profile = NULL;
931     int code;
932     bool include_softproof = false;
933     bool include_devicelink = false;
934     cmm_dev_profile_t *dev_profile;
935     cmm_profile_t *proof_profile = NULL;
936     cmm_profile_t *devlink_profile = NULL;
937     bool src_dev_link = gs_input_profile->isdevlink;
938     bool pageneutralcolor = false;
939     int cms_flags = 0;
940 
941     /* Determine if we are using a soft proof or device link profile */
942     if (dev != NULL ) {
943         code = dev_proc(dev, get_profile)(dev,  &dev_profile);
944         if (code < 0)
945             return NULL;
946         if (dev_profile != NULL) {
947             proof_profile = dev_profile->proof_profile;
948             devlink_profile = dev_profile->link_profile;
949             pageneutralcolor = dev_profile->pageneutralcolor;
950         }
951         /* If the source color is the same as the proofing color then we do not
952            need to apply the proofing color in this case.  This occurs in cases
953            where we have a CMYK output intent profile, a Device CMYK color, and
954            are going out to an RGB device */
955         if (proof_profile != NULL ) {
956             if (proof_profile->hashcode == gs_input_profile->hashcode) {
957                 proof_profile = NULL;
958             } else {
959                 include_softproof = true;
960             }
961         }
962         if (devlink_profile != NULL) include_devicelink = true;
963     }
964     /* First compute the hash code for the incoming case.  If the output color
965        space is NULL we will use the device profile for the output color space */
966     code = gsicc_compute_linkhash(icc_manager, dev, gs_input_profile,
967                                   gs_output_profile,
968                                   rendering_params, &hash);
969     if (code < 0)
970         return NULL;
971     /* Check the cache for a hit.  Need to check if softproofing was used */
972     found_link = gsicc_findcachelink(hash, icc_link_cache, include_softproof,
973                                      include_devicelink);
974     /* Got a hit, return link (ref_count for the link was already bumped */
975     if (found_link != NULL) {
976         if_debug2m(gs_debug_flag_icc, memory,
977                    "[icc] Found Link = 0x%p, hash = %lld \n",
978                    found_link, (long long)hash.link_hashcode);
979         if_debug2m(gs_debug_flag_icc, memory,
980                    "[icc] input_numcomps = %d, input_hash = %lld \n",
981                    gs_input_profile->num_comps,
982                    (long long)gs_input_profile->hashcode);
983         if_debug2m(gs_debug_flag_icc, memory,
984                    "[icc] output_numcomps = %d, output_hash = %lld \n",
985                    gs_output_profile->num_comps,
986                    (long long)gs_output_profile->hashcode);
987         return found_link;
988     }
989     /* Before we do anything, check if we have a case where the source profile
990        is coming from the clist and we don't even want to be doing any color
991        managment */
992     if (gs_input_profile->profile_handle == NULL &&
993         gs_input_profile->buffer == NULL &&
994         gs_input_profile->dev != NULL) {
995 
996         /* ICC profile should be in clist. This is the first call to it.  Note that
997            the profiles are not really shared amongst threads like the links are.
998            Hence the memory is for the local thread's chunk */
999         cms_input_profile =
1000             gsicc_get_profile_handle_clist(gs_input_profile,
1001                                            gs_input_profile->memory);
1002         gs_input_profile->profile_handle = cms_input_profile;
1003         /* It is possible that we are not using color management
1004            due to a setting forced from srcgtag object (the None option)
1005            which has made its way though the clist in the clist imaging
1006            code.   In this case, the srcgtag_profile structure
1007            which was part of the ICC manager is no longer available.
1008            We also have the Replace option.  */
1009         if (gs_input_profile->rend_is_valid &&
1010             gs_input_profile->rend_cond.cmm == gsCMM_NONE) {
1011 
1012             if (gs_input_profile->data_cs == gsRGB) {
1013                 link = gsicc_nocm_get_link(pgs, dev, 3);
1014             } else {
1015                 link = gsicc_nocm_get_link(pgs, dev, 4);
1016             }
1017             /* Set the identity case if we are in that situation */
1018             if (link != NULL) {
1019                 if (gs_input_profile->num_comps ==
1020                     dev_profile->device_profile[0]->num_comps) {
1021                     link->is_identity = true;
1022                 }
1023                 return link;
1024             }
1025         } else if (gs_input_profile->rend_is_valid &&
1026             gs_input_profile->rend_cond.cmm == gsCMM_REPLACE) {
1027             return gsicc_rcm_get_link(pgs, dev, gs_input_profile->data_cs);
1028             /* Note that there is never an identity case for
1029                this type.  */
1030         }
1031         /* We may have a source profile that is a device link profile and
1032            made its way through the clist.  If so get things set up to
1033            handle that properly. */
1034         src_dev_link = gs_input_profile->isdevlink;
1035     }
1036     /* No link was found so lets create a new one if there is room. This will
1037        usually return a link that is not yet valid, but may return a valid link
1038        if another thread has already created it */
1039     if (gsicc_alloc_link_entry(icc_link_cache, &link, hash, include_softproof,
1040                                include_devicelink))
1041         return link;
1042     if (link == NULL)
1043         return NULL;		/* error, couldn't allocate a link */
1044 
1045     /* Here the link was new and the contents have valid=false and we	*/
1046     /* own the lock for the link_profile. Build the profile, set valid	*/
1047     /* to true and release the lock.					*/
1048     /* Now compute the link contents */
1049     cms_input_profile = gs_input_profile->profile_handle;
1050     /*  Check if the source was generated from a PS CIE color space.  If yes,
1051         then we need to make sure that the CMM does not do something like
1052         force a white point mapping like lcms does */
1053     if (gsicc_profile_from_ps(gs_input_profile)) {
1054         cms_flags = cms_flags | gscms_avoid_white_fix_flag(memory);
1055     }
1056     if (cms_input_profile == NULL) {
1057         if (gs_input_profile->buffer != NULL) {
1058             cms_input_profile =
1059                 gsicc_get_profile_handle_buffer(gs_input_profile->buffer,
1060                                                 gs_input_profile->buffer_size,
1061                                                 memory);
1062             if (cms_input_profile == NULL)
1063                 return NULL;
1064             gs_input_profile->profile_handle = cms_input_profile;
1065             /* This *must* be a default profile that was not set up at start-up/
1066                However it could be one from the icc creator code which does not
1067                do an initialization at the time of creation from CalRGB etc. */
1068             code = gsicc_initialize_default_profile(gs_input_profile);
1069             if (code < 0) return NULL;
1070         } else {
1071             /* Cant create the link.  No profile present,
1072                nor any defaults to use for this.  Really
1073                need to throw an error for this case. */
1074             gsicc_remove_link(link, cache_mem);
1075             return NULL;
1076         }
1077     }
1078     /* No need to worry about an output profile handle if our source is a
1079        device link profile */
1080     if (!src_dev_link) {
1081         cms_output_profile = gs_output_profile->profile_handle;
1082     }
1083     if (cms_output_profile == NULL && !src_dev_link) {
1084         if (gs_output_profile->buffer != NULL) {
1085             cms_output_profile =
1086                 gsicc_get_profile_handle_buffer(gs_output_profile->buffer,
1087                                                 gs_output_profile->buffer_size,
1088                                                 memory);
1089             gs_output_profile->profile_handle = cms_output_profile;
1090             /* This *must* be a default profile that was not set up at start-up */
1091             code = gsicc_initialize_default_profile(gs_output_profile);
1092             if (code < 0) return NULL;
1093         } else {
1094               /* See if we have a clist device pointer. */
1095             if ( gs_output_profile->dev != NULL ) {
1096                 /* ICC profile should be in clist. This is
1097                    the first call to it. */
1098                 cms_output_profile =
1099                     gsicc_get_profile_handle_clist(gs_output_profile,
1100                                                    gs_output_profile->memory);
1101                 gs_output_profile->profile_handle = cms_output_profile;
1102             } else {
1103                 /* Cant create the link.  No profile present,
1104                    nor any defaults to use for this.  Really
1105                    need to throw an error for this case. */
1106                 gsicc_remove_link(link, cache_mem);
1107                 return NULL;
1108             }
1109         }
1110     }
1111     if (include_softproof) {
1112         cms_proof_profile = proof_profile->profile_handle;
1113         if (cms_proof_profile == NULL) {
1114             if (proof_profile->buffer != NULL) {
1115                 cms_proof_profile =
1116                     gsicc_get_profile_handle_buffer(proof_profile->buffer,
1117                                                     proof_profile->buffer_size,
1118                                                     memory);
1119                 proof_profile->profile_handle = cms_proof_profile;
1120                 if (!gscms_is_threadsafe())
1121                     gx_monitor_enter(proof_profile->lock);
1122             } else {
1123                 /* Cant create the link */
1124                 gsicc_remove_link(link, cache_mem);
1125                 return NULL;
1126             }
1127         }
1128     }
1129     if (include_devicelink) {
1130         cms_devlink_profile = devlink_profile->profile_handle;
1131         if (cms_devlink_profile == NULL) {
1132             if (devlink_profile->buffer != NULL) {
1133                 cms_devlink_profile =
1134                     gsicc_get_profile_handle_buffer(devlink_profile->buffer,
1135                                                     devlink_profile->buffer_size,
1136                                                     memory);
1137                 devlink_profile->profile_handle = cms_devlink_profile;
1138                 if (!gscms_is_threadsafe())
1139                     gx_monitor_enter(devlink_profile->lock);
1140             } else {
1141                 /* Cant create the link */
1142                 gsicc_remove_link(link, cache_mem);
1143                 return NULL;
1144             }
1145         }
1146     }
1147     /* Profile reading of same structure not thread safe in CMM */
1148     if (!gscms_is_threadsafe()) {
1149         gx_monitor_enter(gs_input_profile->lock);
1150         if (!src_dev_link) {
1151             gx_monitor_enter(gs_output_profile->lock);
1152         }
1153     }
1154     /* We may have to worry about special handling for DeviceGray to
1155        DeviceCMYK to ensure that Gray is mapped to K only.  This is only
1156        done once and then it is cached and the link used.  Note that Adobe
1157        appears to do this only when the source color space was DeviceGray.
1158        For us, this requirement is meant by the test of
1159        gs_input_profile->default_match == DEFAULT_GRAY */
1160     if (!src_dev_link && gs_output_profile->data_cs == gsCMYK &&
1161         gs_input_profile->data_cs == gsGRAY &&
1162         gs_input_profile->default_match == DEFAULT_GRAY &&
1163         pgs->icc_manager != NULL && devicegraytok) {
1164         if (icc_manager->graytok_profile == NULL) {
1165             icc_manager->graytok_profile =
1166                 gsicc_set_iccsmaskprofile(GRAY_TO_K, strlen(GRAY_TO_K),
1167                                           pgs->icc_manager,
1168                                           pgs->icc_manager->memory->stable_memory);
1169             if (icc_manager->graytok_profile == NULL) {
1170                 /* Cant create the link */	/* FIXME: clean up allocations and locksso far ??? */
1171                 gsicc_remove_link(link, cache_mem);
1172                 return NULL;
1173             }
1174         }
1175         if (icc_manager->smask_profiles == NULL) {
1176             code = gsicc_initialize_iccsmask(icc_manager);
1177         }
1178         cms_input_profile =
1179             icc_manager->smask_profiles->smask_gray->profile_handle;
1180         cms_output_profile =
1181             icc_manager->graytok_profile->profile_handle;
1182         /* Turn off bp compensation in this case as there is a bug in lcms */
1183         rendering_params->black_point_comp = false;
1184         cms_flags = 0;  /* Turn off any flag setting */
1185     }
1186     /* Get the link with the proof and or device link profile */
1187     if (include_softproof || include_devicelink || src_dev_link) {
1188         link_handle = gscms_get_link_proof_devlink(cms_input_profile,
1189                                                    cms_proof_profile,
1190                                                    cms_output_profile,
1191                                                    cms_devlink_profile,
1192                                                    rendering_params,
1193                                                    src_dev_link, cms_flags,
1194                                                    cache_mem->non_gc_memory);
1195     if (!gscms_is_threadsafe()) {
1196         if (include_softproof) {
1197             gx_monitor_leave(proof_profile->lock);
1198         }
1199         if (include_devicelink) {
1200             gx_monitor_leave(devlink_profile->lock);
1201         }
1202     }
1203     } else {
1204         link_handle = gscms_get_link(cms_input_profile, cms_output_profile,
1205                                      rendering_params, cms_flags,
1206                                      cache_mem->non_gc_memory);
1207     }
1208     if (!gscms_is_threadsafe()) {
1209         if (!src_dev_link) {
1210             gx_monitor_leave(gs_output_profile->lock);
1211         }
1212         gx_monitor_leave(gs_input_profile->lock);
1213     }
1214     if (link_handle != NULL) {
1215         if (gs_input_profile->data_cs == gsGRAY)
1216             pageneutralcolor = false;
1217 
1218         gsicc_set_link_data(link, link_handle, hash, icc_link_cache->lock,
1219                             include_softproof, include_devicelink, pageneutralcolor,
1220                             gs_input_profile->data_cs);
1221         if_debug2m(gs_debug_flag_icc, cache_mem,
1222                    "[icc] New Link = 0x%p, hash = %lld \n",
1223                    link, (long long)hash.link_hashcode);
1224         if_debug2m(gs_debug_flag_icc, cache_mem,
1225                    "[icc] input_numcomps = %d, input_hash = %lld \n",
1226                    gs_input_profile->num_comps,
1227                    (long long)gs_input_profile->hashcode);
1228         if_debug2m(gs_debug_flag_icc, cache_mem,
1229                    "[icc] output_numcomps = %d, output_hash = %lld \n",
1230                    gs_output_profile->num_comps,
1231                    (long long)gs_output_profile->hashcode);
1232     } else {
1233         /* If other threads are waiting, we won't have set link->valid true.	*/
1234         /* This could result in an infinite loop if other threads are waiting	*/
1235         /* for it to be made valid. (see gsicc_findcachelink).			*/
1236         link->ref_count--;	/* this thread no longer using this link entry	*/
1237         if_debug2m('^', link->memory, "[^]icclink 0x%p -- => %d\n",
1238                    link, link->ref_count);
1239 
1240         if (icc_link_cache->cache_full) {
1241             icc_link_cache->cache_full = false;
1242             gx_semaphore_signal(icc_link_cache->full_wait);	/* let a waiting thread run */
1243         }
1244         gx_monitor_leave(link->lock);
1245         gsicc_remove_link(link, cache_mem);
1246         return NULL;
1247     }
1248     return link;
1249 }
1250 
1251 /* The following is used to transform a named color value at a particular tint
1252    value to the output device values.  This function is provided only as a
1253    demonstration and will likely need to be altered and optimized for those wishing
1254    to perform full spot color look-up support.
1255 
1256    The object used to perform the transformation is typically
1257    a look-up table that contains the spot color name and a CIELAB value for
1258    100% colorant (it could also contain device values in the table).
1259    It can be more complex where-by you have a 1-D lut that
1260    provides CIELAB values or direct device values as a function of tint.  In
1261    such a case, the table would be interpolated to compute all possible tint values.
1262    If CIELAB values are provided, they can be pushed through the
1263    device profile using the CMM.  In this particular demonstration, we simply
1264    provide CIELAB for a few color names in the file
1265    toolbin/color/named_color/named_color_table.txt .
1266    The tint value is used to scale the CIELAB value from 100% colorant to a D50
1267    whitepoint.  The resulting CIELAB value is then pushed through the CMM to
1268    obtain device values for the current device.  The file named_colors.pdf
1269    which is in toolbin/color/named_color/ contains these
1270    spot colors and will enable the user to see how the code behaves.  The named
1271    color table is specified to ghostscript by the command line option
1272    -sNamedProfile=./toolbin/color/named_color/named_color_table.txt (or with
1273    full path name).  If it is desired to have ghostscript compiled with the
1274    named color table, it can be placed in the iccprofiles directory and then
1275    build ghostscript with COMPILE_INITS=1.  When specified the file contents
1276    are pointed to by the buffer member variable of the device_named profile in
1277    profile manager.  When the first call occurs in here, the contents of the
1278    buffer are parsed and placed into a custom stucture that is pointed to by
1279    the profile pointer.  Note that this pointer is not visible to the garbage
1280    collector and should be allocated in non-gc memory as is demonstrated in
1281    this sample.  The structure elements are released when the profile is
1282    destroyed through the call to gsicc_named_profile_release, which is set
1283    as the value of the profile member variable release.
1284 
1285    Note that there are calls defined in gsicc_littlecms.c that will create link
1286    transforms between Named Color ICC profiles and the output device.  Such
1287    profiles are rarely used (at least I have not run across any yet) so the
1288    code is currently not used.  Also note that for those serious about named
1289    color support, a cache as well as efficient table-look-up methods would
1290    likely be important for performance.
1291 
1292    Finally note that PANTONE is a registered trademark and PANTONE colors are a
1293    licensed product of XRITE Inc. See http://www.pantone.com
1294    for more information.  Licensees of Pantone color libraries or similar
1295    libraries should find it straight forward to interface.  Pantone names are
1296    referred to in named_color_table.txt and contained in the file named_colors.pdf.
1297 
1298    !!!!IT WILL BE NECESSARY TO PERFORM THE PROPER DEALLOCATION
1299        CLEAN-UP OF THE STRUCTURES WHEN rc_free_icc_profile OCCURS FOR THE NAMED
1300        COLOR PROFILE!!!!!!   See gsicc_named_profile_release below for an example.
1301        This is set in the profile release member variable.
1302 */
1303 
1304 /* Define the demo structure and function for named color look-up */
1305 
1306 typedef struct gsicc_namedcolortable_s {
1307     gsicc_namedcolor_t *named_color;    /* The named color */
1308     unsigned int number_entries;        /* The number of entries */
1309     gs_memory_t *memory;
1310 } gsicc_namedcolortable_t;
1311 
1312 /* Support functions for parsing buffer */
1313 
1314 static int
get_to_next_line(char ** buffptr,int * buffer_count)1315 get_to_next_line(char **buffptr, int *buffer_count)
1316 {
1317     while (1) {
1318         if (**buffptr == ';') {
1319             (*buffptr)++;
1320             (*buffer_count)--;
1321             return(0);
1322         } else {
1323             (*buffptr)++;
1324             (*buffer_count)--;
1325         }
1326         if (*buffer_count <= 0) {
1327             return -1;
1328         }
1329     }
1330 }
1331 
1332 /* Release the structures we allocated in gsicc_transform_named_color */
1333 static void
gsicc_named_profile_release(void * ptr,gs_memory_t * memory)1334 gsicc_named_profile_release(void *ptr, gs_memory_t *memory)
1335 {
1336     gsicc_namedcolortable_t *namedcolor_table = (gsicc_namedcolortable_t*) ptr;
1337     unsigned int num_entries;
1338     gs_memory_t *mem;
1339     int k;
1340     gsicc_namedcolor_t *namedcolor_data;
1341 
1342     if (namedcolor_table != NULL) {
1343         mem = namedcolor_table->memory;
1344         num_entries = namedcolor_table->number_entries;
1345         namedcolor_data = namedcolor_table->named_color;
1346 
1347         for (k = 0; k < num_entries; k++) {
1348             gs_free(mem, namedcolor_data[k].colorant_name, 1,
1349                 namedcolor_data[k].name_size + 1,
1350                 "gsicc_named_profile_release (colorant_name)");
1351         }
1352 
1353         gs_free(mem, namedcolor_data, num_entries, sizeof(gsicc_namedcolor_t),
1354             "gsicc_named_profile_release (namedcolor_data)");
1355 
1356         gs_free(namedcolor_table->memory, namedcolor_table, 1,
1357             sizeof(gsicc_namedcolortable_t),
1358             "gsicc_named_profile_release (namedcolor_table)");
1359     }
1360 }
1361 
1362 static int
create_named_profile(gs_memory_t * mem,cmm_profile_t * named_profile)1363 create_named_profile(gs_memory_t *mem, cmm_profile_t *named_profile)
1364 {
1365     /* Create the structure that we will use in searching */
1366     /*  Note that we do this in non-GC memory since the
1367         profile pointer is not GC'd */
1368     gsicc_namedcolortable_t *namedcolor_table;
1369     gsicc_namedcolor_t *namedcolor_data;
1370     char *buffptr;
1371     int buffer_count;
1372     int count;
1373     unsigned int num_entries;
1374     int code;
1375     int k, j;
1376     char *pch, *temp_ptr, *last = NULL;
1377     bool done;
1378     int curr_name_size;
1379     float lab[3];
1380 
1381     namedcolor_table =
1382         (gsicc_namedcolortable_t*)gs_malloc(mem, 1,
1383             sizeof(gsicc_namedcolortable_t), "create_named_profile");
1384     if (namedcolor_table == NULL)
1385         return_error(gs_error_VMerror);
1386     namedcolor_table->memory = mem;
1387 
1388     /* Parse buffer and load the structure we will be searching */
1389     buffptr = (char*)named_profile->buffer;
1390     buffer_count = named_profile->buffer_size;
1391     count = sscanf(buffptr, "%d", &num_entries);
1392     if (num_entries < 1 || count == 0) {
1393         gs_free(mem, namedcolor_table, 1, sizeof(gsicc_namedcolortable_t),
1394             "create_named_profile");
1395         return -1;
1396     }
1397 
1398     code = get_to_next_line(&buffptr, &buffer_count);
1399     if (code < 0) {
1400         gs_free(mem, namedcolor_table, 1, sizeof(gsicc_namedcolortable_t),
1401             "create_named_profile");
1402         return -1;
1403     }
1404     namedcolor_data =
1405         (gsicc_namedcolor_t*)gs_malloc(mem, num_entries,
1406             sizeof(gsicc_namedcolor_t), "create_named_profile");
1407     if (namedcolor_data == NULL) {
1408         gs_free(mem, namedcolor_table, num_entries,
1409             sizeof(gsicc_namedcolortable_t), "create_named_profile");
1410         return_error(gs_error_VMerror);
1411     }
1412     namedcolor_table->number_entries = num_entries;
1413     namedcolor_table->named_color = namedcolor_data;
1414     for (k = 0; k < num_entries; k++) {
1415         if (k == 0) {
1416             pch = gs_strtok(buffptr, ",;", &last);
1417         } else {
1418             pch = gs_strtok(NULL, ",;", &last);
1419         }
1420         /* Remove any /0d /0a stuff from start */
1421         temp_ptr = pch;
1422         done = 0;
1423         while (!done) {
1424             if (*temp_ptr == 0x0d || *temp_ptr == 0x0a) {
1425                 temp_ptr++;
1426             } else {
1427                 done = 1;
1428             }
1429         }
1430         curr_name_size = strlen(temp_ptr);
1431         namedcolor_data[k].name_size = curr_name_size;
1432 
1433         /* +1 for the null */
1434         namedcolor_data[k].colorant_name =
1435             (char*)gs_malloc(mem, 1, curr_name_size + 1,
1436                 "create_named_profile");
1437         if (namedcolor_data[k].colorant_name == NULL) {
1438             /* Free up all that has been allocated so far */
1439             for (j = 0; j < k; j++) {
1440                 gs_free(mem, namedcolor_table, 1, namedcolor_data[j].name_size+1,
1441                     "create_named_profile");
1442             }
1443             gs_free(mem, namedcolor_data, num_entries, sizeof(gsicc_namedcolor_t),
1444                 "create_named_profile");
1445             gs_free(mem, namedcolor_table, num_entries,
1446                 sizeof(gsicc_namedcolortable_t), "create_named_profile");
1447             return_error(gs_error_VMerror);
1448         }
1449         strncpy(namedcolor_data[k].colorant_name, temp_ptr,
1450             namedcolor_data[k].name_size + 1);
1451         for (j = 0; j < 3; j++) {
1452             pch = gs_strtok(NULL, ",;", &last);
1453             count = sscanf(pch, "%f", &(lab[j]));
1454         }
1455         lab[0] = lab[0] * 65535 / 100.0;
1456         lab[1] = (lab[1] + 128.0) * 65535 / 255;
1457         lab[2] = (lab[2] + 128.0) * 65535 / 255;
1458         for (j = 0; j < 3; j++) {
1459             if (lab[j] > 65535) lab[j] = 65535;
1460             if (lab[j] < 0) lab[j] = 0;
1461             namedcolor_data[k].lab[j] = (unsigned short)lab[j];
1462         }
1463     }
1464 
1465     /* Assign to the profile pointer */
1466     named_profile->profile_handle = namedcolor_table;
1467     named_profile->release = gsicc_named_profile_release;
1468     return 0;
1469 }
1470 
1471 
1472 /* Check for support of named color at time of install of DeviceN or Sep color space.
1473    This function returning false means that Process colorants (e.g. CMYK) will
1474    not undergo color management. */
1475 bool
gsicc_support_named_color(const gs_color_space * pcs,const gs_gstate * pgs)1476 gsicc_support_named_color(const gs_color_space *pcs, const gs_gstate *pgs)
1477 {
1478     cmm_profile_t *named_profile;
1479     gsicc_namedcolortable_t *namedcolor_table;
1480     unsigned int num_entries;
1481     int k, code, i, num_comp, num_spots=0, num_process=0, num_other=0;
1482     gs_color_space_index type = gs_color_space_get_index(pcs);
1483     char **names = NULL;
1484     byte *pname;
1485     uint name_size;
1486     bool is_supported;
1487 
1488     /* Get the data for the named profile */
1489     named_profile = pgs->icc_manager->device_named;
1490 
1491     if (named_profile->buffer != NULL &&
1492         named_profile->profile_handle == NULL) {
1493         code = create_named_profile(pgs->memory->non_gc_memory, named_profile);
1494         if (code < 0)
1495             return false;
1496     }
1497     namedcolor_table =
1498         (gsicc_namedcolortable_t*)named_profile->profile_handle;
1499     num_entries = namedcolor_table->number_entries;
1500 
1501     /* Get the color space specifics */
1502     if (type == gs_color_space_index_DeviceN) {
1503         names = pcs->params.device_n.names;
1504         num_comp = pcs->params.device_n.num_components;
1505     } else if (type == gs_color_space_index_Separation) {
1506         pname = (byte *)pcs->params.separation.sep_name;
1507         num_comp = 1;
1508     } else
1509         return false;
1510 
1511     /* Step through the color space colorants */
1512     for (i = 0; i < num_comp; i++) {
1513         if (type == gs_color_space_index_DeviceN) {
1514             pname = (byte *)names[i];
1515             name_size = strlen(names[i]);
1516         }
1517         else {
1518             name_size = strlen(pcs->params.separation.sep_name);
1519         }
1520 
1521         /* Classify */
1522         if (strncmp((char *)pname, "None", name_size) == 0 ||
1523             strncmp((char *)pname, "All", name_size) == 0) {
1524             num_other++;
1525         } else {
1526             if (strncmp((char *)pname, "Cyan", name_size) == 0 ||
1527                 strncmp((char *)pname, "Magenta", name_size) == 0 ||
1528                 strncmp((char *)pname, "Yellow", name_size) == 0 ||
1529                 strncmp((char *)pname, "Black", name_size) == 0) {
1530                 num_process++;
1531             } else {
1532                 num_spots++;
1533             }
1534         }
1535 
1536         /* Check if the colorant is supported */
1537         is_supported = false;
1538         for (k = 0; k < num_entries; k++) {
1539             if (name_size == namedcolor_table->named_color[k].name_size) {
1540                 if (strncmp((const char *)namedcolor_table->named_color[k].colorant_name,
1541                     (const char *)pname, name_size) == 0) {
1542                     is_supported = true;
1543                     break;
1544                 }
1545             }
1546         }
1547         if (!is_supported)
1548             return false;
1549     }
1550     /* If we made it this far, all the individual colorants are supported.
1551        If the names contained no spots, then let standard color management
1552        processing occur.  It may be that some applications want standard
1553        processing in other cases.  For example, [Cyan Magenta Varnish] to
1554        a tiffsep-like device one may want color management to occur for the
1555        Cyan and Magenta but Varnish to pass to the separation device unmolested.
1556        You  will then want to add "Varnish" to the list of names in the above test
1557        for the Process colorants of Cyan, Magenta, Yellow and Black to avoid
1558        "Varnish" being counted as a spot here */
1559     if (num_spots == 0)
1560         return false;
1561     return true;
1562 }
1563 
1564 /* Function returns -1 if a name is not found.  Otherwise it will transform
1565    the named colors and return 0 */
1566 int
gsicc_transform_named_color(const float tint_values[],gsicc_namedcolor_t color_names[],uint num_names,gx_color_value device_values[],const gs_gstate * pgs,gx_device * dev,cmm_profile_t * gs_output_profile,gsicc_rendering_param_t * rendering_params)1567 gsicc_transform_named_color(const float tint_values[],
1568                             gsicc_namedcolor_t color_names[],
1569                             uint num_names,
1570                             gx_color_value device_values[],
1571                             const gs_gstate *pgs, gx_device *dev,
1572                             cmm_profile_t *gs_output_profile,
1573                             gsicc_rendering_param_t *rendering_params)
1574 {
1575     unsigned int num_entries;
1576     cmm_profile_t *named_profile;
1577     gsicc_namedcolortable_t *namedcolor_table;
1578     int num_nonnone_names;
1579     uint k,j,n;
1580     int code;
1581     bool found_match;
1582     unsigned short psrc[GS_CLIENT_COLOR_MAX_COMPONENTS];
1583     unsigned short psrc_cm[GS_CLIENT_COLOR_MAX_COMPONENTS];
1584     unsigned short *psrc_temp;
1585     unsigned short white_lab[3] = {65535, 32767, 32767};
1586     gsicc_link_t *icc_link;
1587     cmm_profile_t *curr_output_profile;
1588     gsicc_rendering_param_t render_cond;
1589     cmm_dev_profile_t *dev_profile;
1590     int indices[GS_CLIENT_COLOR_MAX_COMPONENTS];
1591     gs_memory_t *nongc_mem = pgs->memory->non_gc_memory;
1592 
1593     /* Set indices to avoid use of uninitialized index. It is actually not
1594        possible to access them using real data but someone could perhaps
1595        be malicious and cause a problem */
1596     memset(&(indices[0]), 0, sizeof(indices));
1597 
1598     /* Check if the data that we have has already been generated. */
1599     if (pgs->icc_manager != NULL) {
1600         if (pgs->icc_manager->device_named != NULL) {
1601             named_profile = pgs->icc_manager->device_named;
1602             if (named_profile->buffer != NULL &&
1603                 named_profile->profile_handle == NULL) {
1604                 code = create_named_profile(nongc_mem, named_profile);
1605                 if (code < 0)
1606                     return -1;
1607             }
1608             namedcolor_table =
1609                     (gsicc_namedcolortable_t*)named_profile->profile_handle;
1610             num_entries = namedcolor_table->number_entries;
1611 
1612             /* Go through each of our spot names, getting the color value for
1613                each one. */
1614             num_nonnone_names = num_names;
1615             for (n = 0; n < num_names; n++) {
1616                 /* Search our structure for the color name.  Ignore the None
1617                    colorant names.  All is a special case that someone may
1618                    want to detect and do some special handling for.  In this
1619                    particular example we would punt with All and let the default
1620                    methods handle it */
1621                 found_match = false;
1622 
1623                 if (strncmp("None", (const char *)color_names[n].colorant_name,
1624                             color_names[n].name_size) == 0) {
1625                     num_nonnone_names--;
1626                 } else {
1627                     /* Colorant was not None */
1628                     for (k = 0; k < num_entries; k++) {
1629                         if (color_names[n].name_size ==
1630                             namedcolor_table->named_color[k].name_size) {
1631                             if (strncmp((const char *)namedcolor_table->named_color[k].colorant_name,
1632                                 (const char *)color_names[n].colorant_name, color_names[n].name_size) == 0) {
1633                                 found_match = true;
1634                                 break;
1635                             }
1636                         }
1637                     }
1638                     if (found_match) {
1639                         indices[n] = k;
1640                     } else {
1641                         /* We do not know this colorant, return -1 */
1642                         return -1;
1643                     }
1644                 }
1645             }
1646             if (num_nonnone_names < 1)
1647                 return -1; /* No non-None colorants. */
1648             /* We have all the colorants.  Lets go through and see if we can
1649                make something that looks like a merge of the various ones */
1650             /* Apply tint, blend LAB values.  Note that we may have wanted to
1651                check if we even want to do this.  It is possible that the
1652                device directly supports this particular colorant.  One may
1653                want to check the alt tint transform boolean */
1654 
1655             /* Start with white */
1656             for (j = 0; j < 3; j++) {
1657                 psrc[j] = white_lab[j];
1658             }
1659 
1660             for (n = 0; n < num_nonnone_names; n++) {
1661                 /* Blend with the current color based upon current tint value */
1662                 for (j = 0; j < 3; j++) {
1663                     psrc[j] = (unsigned short)
1664                               ((float) namedcolor_table->named_color[indices[n]].lab[j] * tint_values[n]
1665                              + (float) psrc[j] * (1.0 - tint_values[n]));
1666                 }
1667             }
1668 
1669             /* Push LAB value through CMM to get CMYK device values */
1670             /* Note that there are several options here. You could us an NCLR
1671                icc profile to compute the device colors that you want.  For,
1672                example if the output device had an NCLR profile.
1673                However, what you MUST do here is set ALL the device values.
1674                Hence, below we initialize all of them to zero and in this
1675                particular example, set only the ones that were output from
1676                the device profile */
1677             if ( gs_output_profile != NULL ) {
1678                 curr_output_profile = gs_output_profile;
1679             } else {
1680                 /* Use the device profile.  Note if one was not set for the
1681                    device, the default CMYK profile is used.  Note that
1682                    if we specified and NCLR profile it will be used here */
1683                 code = dev_proc(dev, get_profile)(dev,  &dev_profile);
1684                 gsicc_extract_profile(dev->graphics_type_tag,
1685                                       dev_profile, &(curr_output_profile),
1686                                       &render_cond);
1687             }
1688             icc_link = gsicc_get_link_profile(pgs, dev,
1689                                             pgs->icc_manager->lab_profile,
1690                                             curr_output_profile, rendering_params,
1691                                             pgs->memory, false);
1692             if (icc_link->is_identity) {
1693                 psrc_temp = &(psrc[0]);
1694             } else {
1695                 /* Transform the color */
1696                 psrc_temp = &(psrc_cm[0]);
1697                 (icc_link->procs.map_color)(dev, icc_link, psrc, psrc_temp, 2);
1698             }
1699             gsicc_release_link(icc_link);
1700 
1701             /* Clear out ALL the color values */
1702             for (k = 0; k < dev->color_info.num_components; k++){
1703                 device_values[k] = 0;
1704             }
1705             /* Set only the values that came from the profile.  By default
1706                this would generally be just CMYK values.  For the equivalent
1707                color computation case it certainly will be.  If someone
1708                specified an NCLR profile it could be more.  Note that if an
1709                NCLR profile is being used we will want to make sure the colorant
1710                order is correct */
1711             for (k = 0; k < curr_output_profile->num_comps; k++){
1712                 device_values[k] = psrc_temp[k];
1713             }
1714             return 0;
1715         }
1716     }
1717     return -1; /* Color not found */
1718 }
1719 
1720 /* Used by gs to notify the ICC manager that we are done with this link for now */
1721 /* This may release elements waiting on an icc_link_cache slot */
1722 void
gsicc_release_link(gsicc_link_t * icclink)1723 gsicc_release_link(gsicc_link_t *icclink)
1724 {
1725     gsicc_link_cache_t *icc_link_cache;
1726 
1727     if (icclink == NULL)
1728         return;
1729 
1730     icc_link_cache = icclink->icc_link_cache;
1731 
1732     gx_monitor_enter(icc_link_cache->lock);
1733     if_debug2m('^', icclink->memory, "[^]icclink 0x%p -- => %d\n",
1734                icclink, icclink->ref_count - 1);
1735     /* Decrement the reference count */
1736     if (--(icclink->ref_count) == 0) {
1737 
1738         gsicc_link_t *curr, *prev;
1739 
1740         /* Find link in cache, and move it to the end of the list.  */
1741         /* This way zero ref_count links are found LRU first	*/
1742         curr = icc_link_cache->head;
1743         prev = NULL;
1744         while (curr != icclink) {
1745             prev = curr;
1746             curr = curr->next;
1747         };
1748         if (prev == NULL) {
1749             /* this link was the head */
1750             icc_link_cache->head = curr->next;
1751         } else {
1752             prev->next = curr->next;		/* de-link this one */
1753         }
1754         /* Find the first zero-ref entry on the list */
1755         curr = icc_link_cache->head;
1756         prev = NULL;
1757         while (curr != NULL && curr->ref_count > 0) {
1758             prev = curr;
1759             curr = curr->next;
1760         }
1761         /* Found where to link this one into the tail of the list */
1762         if (prev == NULL) {
1763             icc_link_cache->head = icclink;
1764             icclink->next = icc_link_cache->head->next;
1765         } else {
1766             /* link this one in here */
1767             prev->next = icclink;
1768             icclink->next = curr;
1769         }
1770         /* Finally, if some thread was waiting because the cache was full, let it run */
1771         if (icc_link_cache->cache_full) {
1772             icc_link_cache->cache_full = false;
1773             gx_semaphore_signal(icc_link_cache->full_wait);	/* let a waiting thread run */
1774         }
1775     }
1776     gx_monitor_leave(icc_link_cache->lock);
1777 }
1778 
1779 /* Used to initialize the buffer description prior to color conversion */
1780 void
gsicc_init_buffer(gsicc_bufferdesc_t * buffer_desc,unsigned char num_chan,unsigned char bytes_per_chan,bool has_alpha,bool alpha_first,bool is_planar,int plane_stride,int row_stride,int num_rows,int pixels_per_row)1781 gsicc_init_buffer(gsicc_bufferdesc_t *buffer_desc, unsigned char num_chan, unsigned char bytes_per_chan,
1782                   bool has_alpha, bool alpha_first, bool is_planar, int plane_stride, int row_stride,
1783                   int num_rows, int pixels_per_row)
1784 {
1785     buffer_desc->num_chan = num_chan;
1786     buffer_desc->bytes_per_chan = bytes_per_chan;
1787     buffer_desc->has_alpha = has_alpha;
1788     buffer_desc->alpha_first = alpha_first;
1789     buffer_desc->is_planar = is_planar;
1790     buffer_desc->plane_stride = plane_stride;
1791     buffer_desc->row_stride = row_stride;
1792     buffer_desc->num_rows = num_rows;
1793     buffer_desc->pixels_per_row = pixels_per_row;
1794 
1795     /* sample endianess is consistent across platforms */
1796     buffer_desc->little_endian = true;
1797 
1798 }
1799 
1800 /* Return the proper component numbers based upon the profiles of the device.
1801    This is in here since it is usually called when creating and using a link
1802    from the link cache. */
1803 int
gsicc_get_device_profile_comps(const cmm_dev_profile_t * dev_profile)1804 gsicc_get_device_profile_comps(const cmm_dev_profile_t *dev_profile)
1805 {
1806     if (dev_profile->link_profile == NULL) {
1807        return dev_profile->device_profile[0]->num_comps;
1808     } else {
1809        return dev_profile->link_profile->num_comps_out;
1810     }
1811 }
1812