/* Get the link, which is the mapping procedure in this non color managed 
   transformation case. */
gsicc_link_t*
gsicc_nocm_get_link(const gs_imager_state *pis, gx_device *dev, 
                    gs_color_space_index src_index)
{
    gsicc_link_t *result;
    gsicc_hashlink_t hash;
    nocm_link_t *nocm_link;
    gs_memory_t *mem = pis->memory->non_gc_memory;
    const gx_cm_color_map_procs * cm_procs;

    /* If the cm_procs are forwarding due to the overprint device or other
       odd thing, drill down now and get the proper ones */
    if (fwd_uses_fwd_cmap_procs(dev)) {
        cm_procs = fwd_get_target_cmap_procs(dev);
    } else {
        cm_procs = dev_proc(dev, get_color_mapping_procs)(dev);
    }
    /* We will add this to the link cache so that we can avoid the issue
       of black_generation and undercolor removal being GC values.
       Since the link is not GC we would need to copy the contents over
       each time a link was requested.  This could be costly if we had 
       a lot of link requests.  */
    hash.rend_hash = 0;
    hash.des_hash = dev->color_info.num_components;
    hash.src_hash = src_index;
    hash.link_hashcode = src_index + hash.des_hash * 256;

    /* Check the cache for a hit. */
    result = gsicc_findcachelink(hash, pis->icc_link_cache, false, false);
    if (result != NULL) {
        return result;
    }
    /* If not, then lets create a new one.  This may actually return a link if 
       another thread has already created it while we were trying to do so */ 
    if (gsicc_alloc_link_entry(pis->icc_link_cache, &result, hash, false, false)) 
        return result;
    /* Now compute the link contents */
    result->procs.map_buffer = gsicc_nocm_transform_color_buffer;
    result->procs.map_color = gsicc_nocm_transform_color;
    result->procs.free_link = gsicc_nocm_freelink;
    result->hashcode = hash;
    nocm_link = (nocm_link_t *) gs_alloc_bytes(mem, sizeof(nocm_link_t),
                                               "gsicc_nocm_get_link");
    result->link_handle = (void*) nocm_link;
    nocm_link->memory = mem;
    /* Create a dummy imager state and populate the ucr/bg values.  This
       is the only part that we need */ 
    if (pis == NULL || 
       (pis->black_generation == NULL && pis->undercolor_removal == NULL)) {
        nocm_link->pis = NULL;
    } else {
        nocm_link->pis = (gs_imager_state*) 
                          gs_alloc_bytes(mem, sizeof(gs_imager_state), 
                                         "gsicc_nocm_get_link");
        nocm_link->pis->black_generation = (gx_transfer_map*)
                            gsicc_nocm_copy_curve(pis->black_generation, mem); 
        nocm_link->pis->undercolor_removal = (gx_transfer_map*)
                            gsicc_nocm_copy_curve(pis->undercolor_removal, mem); 
    }
    nocm_link->num_out = min(dev->color_info.num_components, 
                             GS_CLIENT_COLOR_MAX_COMPONENTS);
    nocm_link->cm_procs.map_cmyk = cm_procs->map_cmyk;
    nocm_link->cm_procs.map_rgb = cm_procs->map_rgb;
    nocm_link->cm_procs.map_gray = cm_procs->map_gray;
    nocm_link->num_in = src_index;
    if (result != NULL) {
        gsicc_set_link_data(result, nocm_link, NULL, hash, 
                            pis->icc_link_cache->lock, false, false);
    }
    return result;
}
/* Get the replacement color management link.  It basically needs to store
   the number of components for the source so that we know what we are 
   coming from (e.g. RGB, CMYK, Gray) */
gsicc_link_t*
gsicc_rcm_get_link(const gs_imager_state *pis, gx_device *dev, 
                   gsicc_colorbuffer_t data_cs)
{
    gsicc_link_t *result;
    gsicc_hashlink_t hash;
    rcm_link_t *rcm_link;
    gs_memory_t *mem = dev->memory->non_gc_memory;
    const gx_cm_color_map_procs * cm_procs;
    bool pageneutralcolor = false;
    cmm_dev_profile_t *dev_profile;
    int code;

    /* Need to check if we need to monitor for color */
    if (dev != NULL ) {
        code = dev_proc(dev, get_profile)(dev,  &dev_profile);
        if (code < 0)
            return NULL;
        if (dev_profile != NULL) {
            pageneutralcolor = dev_profile->pageneutralcolor;
        }
     }

    /* If the cm_procs are forwarding due to the overprint device or other
       odd thing, drill down now and get the proper ones */
    if (fwd_uses_fwd_cmap_procs(dev)) {
        cm_procs = fwd_get_target_cmap_procs(dev);
    } else {
        cm_procs = get_color_mapping_procs_subclass(dev);
    }

    hash.rend_hash = gsCMM_REPLACE;
    hash.des_hash = dev->color_info.num_components;
    hash.src_hash = data_cs;
    hash.link_hashcode = data_cs + hash.des_hash * 256 + hash.rend_hash * 4096;

    /* Check the cache for a hit. */
    result = gsicc_findcachelink(hash, pis->icc_link_cache, false, false);
    if (result != NULL) {
        return result;
    }
    /* If not, then lets create a new one.  This may actually return a link if 
       another thread has already created it while we were trying to do so */ 
    if (gsicc_alloc_link_entry(pis->icc_link_cache, &result, hash, false, false)) 
        return result;

    if (result == NULL)
        return result;

    /* Now compute the link contents */
    /* Lock the cache as we alter the procs */
    gx_monitor_enter(pis->icc_link_cache->lock);	

    result->procs.map_buffer = gsicc_rcm_transform_color_buffer;
    result->procs.map_color = gsicc_rcm_transform_color;
    result->procs.free_link = gsicc_rcm_freelink;
    result->hashcode = hash;
    result->is_identity = false;
    rcm_link = (rcm_link_t *) gs_alloc_bytes(mem, sizeof(rcm_link_t),
                                               "gsicc_rcm_get_link");
    if (rcm_link == NULL)
        return NULL;
    result->link_handle = (void*) rcm_link;
    rcm_link->memory = mem;
    rcm_link->num_out = min(dev->color_info.num_components, 
                             GS_CLIENT_COLOR_MAX_COMPONENTS);
    rcm_link->data_cs_in = data_cs;
    rcm_link->cm_procs.map_cmyk = cm_procs->map_cmyk;
    rcm_link->cm_procs.map_rgb = cm_procs->map_rgb;
    rcm_link->cm_procs.map_gray = cm_procs->map_gray;

    switch (data_cs) {
        case gsGRAY:
            rcm_link->num_in = 1;
            break;
        case gsRGB:
        case gsCIELAB:
            rcm_link->num_in = 3;
            break;
        case gsCMYK:
            rcm_link->num_in = 4;
            break;
        default:
            result->procs.free_link(result);
            return NULL;
    }
    /* Likely set if we have something like a table or procs */    
    rcm_link->context = NULL;  

    result->num_input = rcm_link->num_in;
    result->num_output = rcm_link->num_out;
    result->link_handle = rcm_link;
    result->hashcode.link_hashcode = hash.link_hashcode;
    result->hashcode.des_hash = hash.des_hash;
    result->hashcode.src_hash = hash.src_hash;
    result->hashcode.rend_hash = hash.rend_hash;
    result->includes_softproof = false;
    result->includes_devlink = false;
    if (hash.src_hash == hash.des_hash) {
        result->is_identity = true;
    } else {
        result->is_identity = false;
    }
    result->valid = true;

    /* Set up for monitoring non gray color spaces */
    if (pageneutralcolor && data_cs != gsGRAY)
        gsicc_mcm_set_link(result);

    /* Now release any tasks/threads waiting for these contents */
    while (result->num_waiting > 0) {
        gx_semaphore_signal(result->wait);
        result->num_waiting--;
    }
    gx_monitor_leave(pis->icc_link_cache->lock);	/* done with updating, let everyone run */

    return result;
}
Exemple #3
0
gsicc_link_t*
gsicc_get_link_profile(gs_imager_state *pis, 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 include_softproof)
{
    gsicc_hashlink_t hash;
    gsicc_link_t *link, *found_link;
    gcmmhlink_t link_handle = NULL;
    void **contextptr = NULL;
    gsicc_manager_t *icc_manager = pis->icc_manager;
    gsicc_link_cache_t *icc_link_cache = pis->icc_link_cache;
    gs_memory_t *cache_mem = pis->icc_link_cache->memory;

    gcmmhprofile_t *cms_input_profile;
    gcmmhprofile_t *cms_output_profile;

    /* First compute the hash code for the incoming case */
    /* If the output color space is NULL we will use the device profile for the output color space */
    gsicc_compute_linkhash(icc_manager, dev, gs_input_profile, gs_output_profile,
                            rendering_params, &hash);

    /* Check the cache for a hit.  Need to check if softproofing was used */
    found_link = gsicc_findcachelink(hash, icc_link_cache, include_softproof);

    /* Got a hit, return link (ref_count for the link was already bumped */
    if (found_link != NULL)
        return(found_link);  /* TO FIX: We are really not going to want to have the members
                          of this object visible outside gsiccmange */

    /* If not, then lets create a new one if there is room or return NULL */
    /* Caller will need to try later */

    /* First see if we can add a link */
    /* TODO: this should be based on memory usage, not just num_links */
    gx_monitor_enter(icc_link_cache->lock);
    while (icc_link_cache->num_links >= ICC_CACHE_MAXLINKS) {
        /* If not, see if there is anything we can remove from cache. */
	while ((link = gsicc_find_zeroref_cache(icc_link_cache)) == NULL) {
	    icc_link_cache->num_waiting++;
	    /* safe to unlock since above will make sure semaphore is signalled */
	    gx_monitor_leave(icc_link_cache->lock);
	    /* we get signalled (released from wait) when a link goes to zero ref */
	    gx_semaphore_wait(icc_link_cache->wait);

	    /* repeat the findcachelink to see if some other thread has	*/
	    /*already started building the link	we need			*/
	    found_link = gsicc_findcachelink(hash, icc_link_cache, include_softproof);

	    /* Got a hit, return link (ref_count for the link was already bumped */
	    if (found_link != NULL)
		return(found_link);  /* TO FIX: We are really not going to want to have the members
				  of this object visible outside gsiccmange */

	    gx_monitor_enter(icc_link_cache->lock);	    /* restore the lock */
	    /* we will re-test the num_links above while locked to insure */
	    /* that some other thread didn't grab the slot and max us out */
	}
	/* Remove the zero ref_count link profile we found.		*/
	/* Even if we remove this link, we may still be maxed out so	*/
	/* the outermost 'while' will check to make sure some other	*/
	/* thread did not grab the one we remove.			*/
	gsicc_remove_link(link, cache_mem);
        icc_link_cache->num_links--;
    }
    /* insert an empty link that we will reserve so we */
    /* can unlock while building the link contents     */
    link = gsicc_alloc_link(cache_mem->stable_memory, hash);
    link->icc_link_cache = icc_link_cache;
    link->next = icc_link_cache->head;
    icc_link_cache->head = link;
    icc_link_cache->num_links++;
    gx_monitor_leave(icc_link_cache->lock);	/* now that we own this link we can release */
					/* the lock since it is not valid */

    /* Now compute the link contents */
    cms_input_profile = gs_input_profile->profile_handle;
    if (cms_input_profile == NULL) {
        if (gs_input_profile->buffer != NULL) {
            cms_input_profile =
                gsicc_get_profile_handle_buffer(gs_input_profile->buffer,
                                                gs_input_profile->buffer_size);
            gs_input_profile->profile_handle = cms_input_profile;
        } else {
            /* See if we have a clist device pointer. */
            if ( gs_input_profile->dev != NULL ) {
                /* ICC profile should be in clist. This is
                   the first call to it.  Note that the profiles are not
                   really shared amongst threads like the links are.  Hence
                   the memory is for the local thread's chunk */
                cms_input_profile =
                    gsicc_get_profile_handle_clist(gs_input_profile,
                                                   gs_input_profile->memory);
                gs_input_profile->profile_handle = cms_input_profile;
            } else {
                /* Cant create the link.  No profile present,
                   nor any defaults to use for this.  Really
                   need to throw an error for this case. */
		gsicc_remove_link(link, cache_mem);
                icc_link_cache->num_links--;
                return(NULL);
            }
        }
    }

    cms_output_profile = gs_output_profile->profile_handle;
    if (cms_output_profile == NULL) {
        if (gs_output_profile->buffer != NULL) {
            cms_input_profile =
                gsicc_get_profile_handle_buffer(gs_input_profile->buffer,
                                                gs_input_profile->buffer_size);
            gs_output_profile->profile_handle = cms_output_profile;
        } else {
              /* See if we have a clist device pointer. */
            if ( gs_output_profile->dev != NULL ) {
                /* ICC profile should be in clist. This is
                   the first call to it. */
                cms_output_profile =
                    gsicc_get_profile_handle_clist(gs_output_profile,
                                                   gs_output_profile->memory);
                gs_output_profile->profile_handle = cms_output_profile;
            } else {
                /* Cant create the link.  No profile present,
                   nor any defaults to use for this.  Really
                   need to throw an error for this case. */
		gsicc_remove_link(link, cache_mem);
                icc_link_cache->num_links--;
                return(NULL);
            }
        }
    }
    link_handle = gscms_get_link(cms_input_profile, cms_output_profile,
                                    rendering_params);
    if (link_handle != NULL) {
	gsicc_set_link_data(link, link_handle, contextptr, hash, icc_link_cache->lock);
    } else {
	gsicc_remove_link(link, cache_mem);
        icc_link_cache->num_links--;
        return(NULL);
    }
    return(link);
}