Home | History | Annotate | Line # | Download | only in xcms
      1 
      2 /*
      3  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
      4  * 	All Rights Reserved
      5  *
      6  * This file is a component of an X Window System-specific implementation
      7  * of Xcms based on the TekColor Color Management System.  Permission is
      8  * hereby granted to use, copy, modify, sell, and otherwise distribute this
      9  * software and its documentation for any purpose and without fee, provided
     10  * that this copyright, permission, and disclaimer notice is reproduced in
     11  * all copies of this software and in supporting documentation.  TekColor
     12  * is a trademark of Tektronix, Inc.
     13  *
     14  * Tektronix makes no representation about the suitability of this software
     15  * for any purpose.  It is provided "as is" and with all faults.
     16  *
     17  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
     18  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     19  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
     20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
     21  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
     22  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     23  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
     24  *
     25  *
     26  *	NAME
     27  *		XcmsCvCols.c
     28  *
     29  *	DESCRIPTION
     30  *		Xcms API routine that converts between the
     31  *		device-independent color spaces.
     32  *
     33  *
     34  */
     35 
     36 #ifdef HAVE_CONFIG_H
     37 #include <config.h>
     38 #endif
     39 #include "Xlibint.h"
     40 #include "Xcmsint.h"
     41 #include "Cv.h"
     42 #include "reallocarray.h"
     43 
     44 /*
     45  *      LOCAL DEFINES
     46  */
     47 #define	DD_FORMAT	0x01
     48 #define	DI_FORMAT	0x02
     49 #define	MIX_FORMAT	0x04
     50 #ifndef MAX
     51 #  define MAX(x,y) ((x) > (y) ? (x) : (y))
     52 #endif
     53 
     54 
     55 /************************************************************************
     57  *									*
     58  *			 PRIVATE ROUTINES				*
     59  *									*
     60  ************************************************************************/
     61 
     62 /*
     63  *	NAME
     64  *		EqualCIEXYZ
     65  *
     66  *	SYNOPSIS
     67  */
     68 static int
     69 EqualCIEXYZ(
     70     XcmsColor *p1, XcmsColor *p2)
     71 /*
     72  *	DESCRIPTION
     73  *		Compares two XcmsColor structures that are in XcmsCIEXYZFormat
     74  *
     75  *	RETURNS
     76  *		Returns 1 if equal; 0 otherwise.
     77  *
     78  */
     79 {
     80     if (p1->format != XcmsCIEXYZFormat || p2->format != XcmsCIEXYZFormat) {
     81 	return(0);
     82     }
     83     if ((p1->spec.CIEXYZ.X != p2->spec.CIEXYZ.X)
     84 	    || (p1->spec.CIEXYZ.Y != p2->spec.CIEXYZ.Y)
     85 	    || (p1->spec.CIEXYZ.Z != p2->spec.CIEXYZ.Z)) {
     86 	return(0);
     87     }
     88     return(1);
     89 }
     90 
     91 
     92 /*
     94  *	NAME
     95  *		XcmsColorSpace
     96  *
     97  *	SYNOPSIS
     98  */
     99 static XcmsColorSpace *
    100 ColorSpaceOfID(
    101     XcmsCCC ccc,
    102     XcmsColorFormat	id)
    103 /*
    104  *	DESCRIPTION
    105  *		Returns a pointer to the color space structure
    106  *		(XcmsColorSpace) associated with the specified color space
    107  *		ID.
    108  *
    109  *	RETURNS
    110  *		Pointer to matching XcmsColorSpace structure if found;
    111  *		otherwise NULL.
    112  */
    113 {
    114     XcmsColorSpace	**papColorSpaces;
    115 
    116     if (ccc == NULL) {
    117 	return(NULL);
    118     }
    119 
    120     /*
    121      * First try Device-Independent color spaces
    122      */
    123     papColorSpaces = _XcmsDIColorSpaces;
    124     if (papColorSpaces != NULL) {
    125 	while (*papColorSpaces != NULL) {
    126 	    if ((*papColorSpaces)->id == id) {
    127 		return(*papColorSpaces);
    128 	    }
    129 	    papColorSpaces++;
    130 	}
    131     }
    132 
    133     /*
    134      * Next try Device-Dependent color spaces
    135      */
    136     papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
    137     if (papColorSpaces != NULL) {
    138 	while (*papColorSpaces != NULL) {
    139 	    if ((*papColorSpaces)->id == id) {
    140 		return(*papColorSpaces);
    141 	    }
    142 	    papColorSpaces++;
    143 	}
    144     }
    145 
    146     return(NULL);
    147 }
    148 
    149 
    150 /*
    152  *	NAME
    153  *		ValidDIColorSpaceID
    154  *
    155  *	SYNOPSIS
    156  */
    157 static int
    158 ValidDIColorSpaceID(
    159     XcmsColorFormat id)
    160 /*
    161  *	DESCRIPTION
    162  *		Determines if the specified color space ID is a valid
    163  *		Device-Independent color space in the specified Color
    164  *		Conversion Context.
    165  *
    166  *	RETURNS
    167  *		Returns zero if not valid; otherwise non-zero.
    168  */
    169 {
    170     XcmsColorSpace **papRec;
    171     papRec = _XcmsDIColorSpaces;
    172     if (papRec != NULL) {
    173 	while (*papRec != NULL) {
    174 	    if ((*papRec)->id == id) {
    175 		return(1);
    176 	    }
    177 	    papRec++;
    178 	}
    179     }
    180     return(0);
    181 }
    182 
    183 
    184 /*
    186  *	NAME
    187  *		ValidDDColorSpaceID
    188  *
    189  *	SYNOPSIS
    190  */
    191 static int
    192 ValidDDColorSpaceID(
    193     XcmsCCC ccc,
    194     XcmsColorFormat id)
    195 /*
    196  *	DESCRIPTION
    197  *		Determines if the specified color space ID is a valid
    198  *		Device-Dependent color space in the specified Color
    199  *		Conversion Context.
    200  *
    201  *	RETURNS
    202  *		Returns zero if not valid; otherwise non-zero.
    203  */
    204 {
    205     XcmsColorSpace **papRec;
    206 
    207     if (ccc->pPerScrnInfo->state != XcmsInitNone) {
    208 	papRec = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
    209 	while (*papRec != NULL) {
    210 	    if ((*papRec)->id == id) {
    211 		return(1);
    212 	    }
    213 	    papRec++;
    214 	}
    215     }
    216     return(0);
    217 }
    218 
    219 
    220 /*
    222  *	NAME
    223  *		ConvertMixedColors - Convert XcmsColor structures
    224  *
    225  *	SYNOPSIS
    226  */
    227 static Status
    228 ConvertMixedColors(
    229     XcmsCCC ccc,
    230     XcmsColor *pColors_in_out,
    231     XcmsColor *pWhitePt,
    232     unsigned int nColors,
    233     XcmsColorFormat targetFormat,
    234     unsigned char format_flag)
    235 /*
    236  *	DESCRIPTION
    237  *		This routine will only convert the following types of
    238  *		batches:
    239  *			DI to DI
    240  *			DD to DD
    241  *			DD to CIEXYZ
    242  *		In other words, it will not convert the following types of
    243  *		batches:
    244  *			DI to DD
    245  *			DD to DI(not CIEXYZ)
    246  *
    247  *		format_flag:
    248  *		    0x01 : convert Device-Dependent only specifications to the
    249  *			target format.
    250  *		    0x02 : convert Device-Independent only specifications to the
    251  *			target format.
    252  *		    0x03 : convert all specifications to the target format.
    253  *
    254  *	RETURNS
    255  *		XcmsFailure if failed,
    256  *		XcmsSuccess if none of the color specifications were
    257  *			compressed in the conversion process
    258  *		XcmsSuccessWithCompression if at least one of the
    259  *			color specifications were compressed in the
    260  *			conversion process.
    261  *
    262  */
    263 {
    264     XcmsColor *pColor, *pColors_start;
    265     XcmsColorFormat format;
    266     Status retval_tmp;
    267     Status retval = XcmsSuccess;
    268     unsigned int iColors;
    269     unsigned int nBatch;
    270 
    271     /*
    272      * Convert array of mixed color specifications in batches of
    273      * contiguous formats to the target format
    274      */
    275     iColors = 0;
    276     while (iColors < nColors) {
    277 	/*
    278 	 * Find contiguous array of color specifications with the
    279 	 * same format
    280 	 */
    281 	pColor = pColors_start = pColors_in_out + iColors;
    282 	format = pColors_start->format;
    283 	nBatch = 0;
    284 	while (iColors < nColors && pColor->format == format) {
    285 		pColor++;
    286 		nBatch++;
    287 		iColors++;
    288 	}
    289 	if (format != targetFormat) {
    290 	    /*
    291 	     * Need to convert this batch from current format to target format.
    292 	     */
    293 	    if (XCMS_DI_ID(format) && (format_flag & DI_FORMAT) &&
    294 		XCMS_DI_ID(targetFormat)) {
    295 		/*
    296 		 * DI->DI
    297 		 *
    298 		 * Format of interest is Device-Independent,
    299 		 * This batch contains Device-Independent specifications, and
    300 		 * the Target format is Device-Independent.
    301 		 */
    302 		retval_tmp = _XcmsDIConvertColors(ccc, pColors_start, pWhitePt,
    303 			nBatch, targetFormat);
    304 	    } else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) &&
    305 		    (targetFormat == XcmsCIEXYZFormat)) {
    306 		/*
    307 		 * DD->CIEXYZ
    308 		 *
    309 		 * Format of interest is Device-Dependent,
    310 		 * This batch contains Device-Dependent specifications, and
    311 		 * the Target format is CIEXYZ.
    312 		 *
    313 		 * Since DD->CIEXYZ we can use NULL instead of pCompressed.
    314 		 */
    315 		if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc,
    316 			pWhitePt, ScreenWhitePointOfCCC(ccc))) {
    317 		    /*
    318 		     * Need to call WhiteAdjustProc (Screen White Point to
    319 		     *   White Point).
    320 		     */
    321 		    retval_tmp = (*ccc->whitePtAdjProc)(ccc,
    322 			    ScreenWhitePointOfCCC(ccc), pWhitePt,
    323 			    XcmsCIEXYZFormat, pColors_start, nBatch,
    324 			    (Bool *)NULL);
    325 		} else {
    326 		    retval_tmp = _XcmsDDConvertColors(ccc, pColors_start,
    327 			    nBatch, XcmsCIEXYZFormat, (Bool *)NULL);
    328 		}
    329 	    } else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) &&
    330 		    XCMS_DD_ID(targetFormat)) {
    331 		/*
    332 		 * DD->DD(not CIEXYZ)
    333 		 *
    334 		 * Format of interest is Device-Dependent,
    335 		 * This batch contains Device-Dependent specifications, and
    336 		 * the Target format is Device-Dependent and not CIEXYZ.
    337 		 */
    338 		retval_tmp = _XcmsDDConvertColors(ccc, pColors_start, nBatch,
    339 			targetFormat, (Bool *)NULL);
    340 	    } else {
    341 		/*
    342 		 * This routine is called for the wrong reason.
    343 		 */
    344 		return(XcmsFailure);
    345 	    }
    346 	    if (retval_tmp == XcmsFailure) {
    347 		return(XcmsFailure);
    348 	    }
    349 	    retval = MAX(retval, retval_tmp);
    350 	}
    351     }
    352     return(retval);
    353 }
    354 
    355 
    356 /************************************************************************
    358  *									*
    359  *			 API PRIVATE ROUTINES				*
    360  *									*
    361  ************************************************************************/
    362 
    363 /*
    364  *	NAME
    365  *		_XcmsEqualWhitePts
    366  *
    367  *	SYNOPSIS
    368  */
    369 int
    370 _XcmsEqualWhitePts(XcmsCCC ccc, XcmsColor *pWhitePt1, XcmsColor *pWhitePt2)
    371 /*
    372  *	DESCRIPTION
    373  *
    374  *	RETURNS
    375  *		Returns 0 if not equal; otherwise 1.
    376  *
    377  */
    378 {
    379     XcmsColor tmp1, tmp2;
    380 
    381     memcpy((char *)&tmp1, (char *)pWhitePt1, sizeof(XcmsColor));
    382     memcpy((char *)&tmp2, (char *)pWhitePt2, sizeof(XcmsColor));
    383 
    384     if (tmp1.format != XcmsCIEXYZFormat) {
    385 	if (_XcmsDIConvertColors(ccc, &tmp1, (XcmsColor *) NULL, 1,
    386 		XcmsCIEXYZFormat)==0) {
    387 	    return(0);
    388 	}
    389     }
    390 
    391     if (tmp2.format != XcmsCIEXYZFormat) {
    392 	if (_XcmsDIConvertColors(ccc, &tmp2, (XcmsColor *) NULL, 1,
    393 		XcmsCIEXYZFormat)==0) {
    394 	    return(0);
    395 	}
    396     }
    397 
    398     return (EqualCIEXYZ(&tmp1, &tmp2));
    399 }
    400 
    401 
    402 /*
    404  *	NAME
    405  *		_XcmsDIConvertColors - Convert XcmsColor structures
    406  *
    407  *	SYNOPSIS
    408  */
    409 Status
    410 _XcmsDIConvertColors(
    411     XcmsCCC ccc,
    412     XcmsColor *pColors_in_out,
    413     XcmsColor *pWhitePt,
    414     unsigned int nColors,
    415     XcmsColorFormat newFormat)
    416 /*
    417  *	DESCRIPTION
    418  *		Convert XcmsColor structures to another Device-Independent
    419  *		form.
    420  *
    421  *		Here are some assumptions that this routine makes:
    422  *		1. The calling routine has already checked if
    423  *		    pColors_in_out->format == newFormat, therefore
    424  *		    there is no need to check again here.
    425  *		2. The calling routine has already checked nColors,
    426  *		    therefore this routine assumes nColors > 0.
    427  *		3. The calling routine may want to convert only between
    428  *			CIExyY <-> CIEXYZ <-> CIEuvY
    429  *		    therefore, this routine allows pWhitePt to equal NULL.
    430  *
    431  *
    432  *	RETURNS
    433  *		XcmsFailure if failed,
    434  *		XcmsSuccess if succeeded.
    435  *
    436  */
    437 {
    438     XcmsColorSpace *pFrom, *pTo;
    439     XcmsDIConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ;
    440     XcmsDIConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ;
    441     XcmsDIConversionProc *to_CIEXYZ_stop, *from_CIEXYZ_start;
    442     XcmsDIConversionProc *tmp;
    443 
    444     /*
    445      * Allow pWhitePt to equal NULL.  This appropriate when converting
    446      *    anywhere between:
    447      *		CIExyY <-> CIEXYZ <-> CIEuvY
    448      */
    449 
    450     if (pColors_in_out == NULL ||
    451 	    !ValidDIColorSpaceID(pColors_in_out->format) ||
    452 	    !ValidDIColorSpaceID(newFormat)) {
    453 	return(XcmsFailure);
    454     }
    455 
    456     /*
    457      * Get a handle on the function list for the current specification format
    458      */
    459     if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format))
    460 	    == NULL) {
    461 	return(XcmsFailure);
    462     }
    463 
    464     /*
    465      * Get a handle on the function list for the new specification format
    466      */
    467     if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) {
    468 	return(XcmsFailure);
    469     }
    470 
    471     src_to_CIEXYZ = pFrom->to_CIEXYZ;
    472     src_from_CIEXYZ = pFrom->from_CIEXYZ;
    473     dest_to_CIEXYZ = pTo->to_CIEXYZ;
    474     dest_from_CIEXYZ = pTo->from_CIEXYZ;
    475 
    476     if (pTo->inverse_flag && pFrom->inverse_flag) {
    477 	/*
    478 	 * Find common function pointers
    479 	 */
    480 	for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){
    481 	    for (tmp = dest_to_CIEXYZ; *tmp; tmp++) {
    482 		if (*to_CIEXYZ_stop == *tmp) {
    483 		    goto Continue;
    484 		}
    485 	    }
    486 	}
    487 
    488 Continue:
    489 
    490 	/*
    491 	 * Execute the functions to CIEXYZ, stopping short as necessary
    492 	 */
    493 	while (src_to_CIEXYZ != to_CIEXYZ_stop) {
    494 	    if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out,
    495 		    nColors) == XcmsFailure) {
    496 		return(XcmsFailure);
    497 	    }
    498 	}
    499 
    500 	/*
    501 	 * Determine where to start on the from_CIEXYZ path.
    502 	 */
    503 	from_CIEXYZ_start = dest_from_CIEXYZ;
    504 	tmp = src_from_CIEXYZ;
    505 	while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) {
    506 	    from_CIEXYZ_start++;
    507 	    tmp++;
    508 	}
    509 
    510     } else {
    511 	/*
    512 	 * The function in at least one of the Color Spaces are not
    513 	 * complementary, i.e.,
    514 	 *	for an i, 0 <= i < n elements
    515 	 *	from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i]
    516 	 *
    517 	 * Execute the functions all the way to CIEXYZ
    518 	 */
    519 	while (*src_to_CIEXYZ) {
    520 	    if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out,
    521 		    nColors) == XcmsFailure) {
    522 		return(XcmsFailure);
    523 	    }
    524 	}
    525 
    526 	/*
    527 	 * Determine where to start on the from_CIEXYZ path.
    528 	 */
    529 	from_CIEXYZ_start = dest_from_CIEXYZ;
    530     }
    531 
    532 
    533     /*
    534      * Execute the functions from CIEXYZ.
    535      */
    536     while (*from_CIEXYZ_start) {
    537 	if ((*from_CIEXYZ_start++)(ccc, pWhitePt, pColors_in_out,
    538 		nColors) == XcmsFailure) {
    539 	    return(XcmsFailure);
    540 	}
    541     }
    542 
    543     return(XcmsSuccess);
    544 }
    545 
    546 
    547 /*
    549  *	NAME
    550  *		_XcmsDDConvertColors - Convert XcmsColor structures
    551  *
    552  *	SYNOPSIS
    553  */
    554 Status
    555 _XcmsDDConvertColors(
    556     XcmsCCC ccc,
    557     XcmsColor *pColors_in_out,
    558     unsigned int nColors,
    559     XcmsColorFormat newFormat,
    560     Bool *pCompressed)
    561 /*
    562  *	DESCRIPTION
    563  *		Convert XcmsColor structures:
    564  *
    565  *		1. From CIEXYZ to Device-Dependent formats (typically RGB and
    566  *			RGBi),
    567  *		    or
    568  *		2. Between Device-Dependent formats (typically RGB and RGBi).
    569  *
    570  *		Assumes that these specifications have already been white point
    571  *		adjusted if necessary from Client White Point to Screen
    572  *		White Point.  Therefore, the white point now associated
    573  *		with the specifications is the Screen White Point.
    574  *
    575  *		pCompressed may be NULL.  If so this indicates that the
    576  *		calling routine is not interested in knowing exactly which
    577  *		color was compressed, if any.
    578  *
    579  *
    580  *	RETURNS
    581  *		XcmsFailure if failed,
    582  *		XcmsSuccess if none of the color specifications were
    583  *			compressed in the conversion process
    584  *		XcmsSuccessWithCompression if at least one of the
    585  *			color specifications were compressed in the
    586  *			conversion process.
    587  *
    588  */
    589 {
    590     XcmsColorSpace *pFrom, *pTo;
    591     XcmsDDConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ;
    592     XcmsDDConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ;
    593     XcmsDDConversionProc *from_CIEXYZ_start, *to_CIEXYZ_stop;
    594     XcmsDDConversionProc *tmp;
    595     int	retval;
    596     int hasCompressed = 0;
    597 
    598     if (ccc == NULL || pColors_in_out == NULL) {
    599 	return(XcmsFailure);
    600     }
    601 
    602     if (nColors == 0 || pColors_in_out->format == newFormat) {
    603 	/* do nothing */
    604 	return(XcmsSuccess);
    605     }
    606 
    607     if (((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet) == NULL) {
    608 	return(XcmsFailure);	/* hmm, an internal error? */
    609     }
    610 
    611     /*
    612      * Its ok if pColors_in_out->format == XcmsCIEXYZFormat
    613      *	or
    614      * if newFormat == XcmsCIEXYZFormat
    615      */
    616     if ( !( ValidDDColorSpaceID(ccc, pColors_in_out->format)
    617 	    ||
    618 	    (pColors_in_out->format == XcmsCIEXYZFormat))
    619 	 ||
    620 	 !(ValidDDColorSpaceID(ccc, newFormat)
    621 	    ||
    622 	    newFormat == XcmsCIEXYZFormat)) {
    623 	return(XcmsFailure);
    624     }
    625 
    626     if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format)) == NULL){
    627 	return(XcmsFailure);
    628     }
    629 
    630     if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) {
    631 	return(XcmsFailure);
    632     }
    633 
    634     src_to_CIEXYZ = (XcmsDDConversionProc *)pFrom->to_CIEXYZ;
    635     src_from_CIEXYZ = (XcmsDDConversionProc *)pFrom->from_CIEXYZ;
    636     dest_to_CIEXYZ = (XcmsDDConversionProc *)pTo->to_CIEXYZ;
    637     dest_from_CIEXYZ = (XcmsDDConversionProc *)pTo->from_CIEXYZ;
    638 
    639     if (pTo->inverse_flag && pFrom->inverse_flag) {
    640 	/*
    641 	 * Find common function pointers
    642 	 */
    643 	for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){
    644 	    for (tmp = dest_to_CIEXYZ; *tmp; tmp++) {
    645 		if (*to_CIEXYZ_stop == *tmp) {
    646 		    goto Continue;
    647 		}
    648 	    }
    649 	}
    650 Continue:
    651 
    652 	/*
    653 	 * Execute the functions
    654 	 */
    655 	while (src_to_CIEXYZ != to_CIEXYZ_stop) {
    656 	    retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors,
    657 		    pCompressed);
    658 	    if (retval == XcmsFailure) {
    659 		return(XcmsFailure);
    660 	    }
    661 	    hasCompressed |= (retval == XcmsSuccessWithCompression);
    662 	}
    663 
    664 	/*
    665 	 * Determine where to start on the from_CIEXYZ path.
    666 	 */
    667 	from_CIEXYZ_start = dest_from_CIEXYZ;
    668 	tmp = src_from_CIEXYZ;
    669 	while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) {
    670 	    from_CIEXYZ_start++;
    671 	    tmp++;
    672 	}
    673 
    674     } else {
    675 	/*
    676 	 * The function in at least one of the Color Spaces are not
    677 	 * complementary, i.e.,
    678 	 *	for an i, 0 <= i < n elements
    679 	 *	from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i]
    680 	 *
    681 	 * Execute the functions all the way to CIEXYZ
    682 	 */
    683 	while (*src_to_CIEXYZ) {
    684 	    retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors,
    685 		    pCompressed);
    686 	    if (retval == XcmsFailure) {
    687 		return(XcmsFailure);
    688 	    }
    689 	    hasCompressed |= (retval == XcmsSuccessWithCompression);
    690 	}
    691 
    692 	/*
    693 	 * Determine where to start on the from_CIEXYZ path.
    694 	 */
    695 	from_CIEXYZ_start = dest_from_CIEXYZ;
    696     }
    697 
    698     while (*from_CIEXYZ_start) {
    699 	retval = (*from_CIEXYZ_start++)(ccc, pColors_in_out, nColors,
    700 		pCompressed);
    701 	if (retval == XcmsFailure) {
    702 	    return(XcmsFailure);
    703 	}
    704 	hasCompressed |= (retval == XcmsSuccessWithCompression);
    705     }
    706 
    707     return(hasCompressed ? XcmsSuccessWithCompression : XcmsSuccess);
    708 }
    709 
    710 
    711 /************************************************************************
    713  *									*
    714  *			 PUBLIC ROUTINES				*
    715  *									*
    716  ************************************************************************/
    717 
    718 /*
    719  *	NAME
    720  *		XcmsConvertColors - Convert XcmsColor structures
    721  *
    722  *	SYNOPSIS
    723  */
    724 Status
    725 XcmsConvertColors(
    726     XcmsCCC ccc,
    727     XcmsColor *pColors_in_out,
    728     unsigned int nColors,
    729     XcmsColorFormat targetFormat,
    730     Bool *pCompressed)
    731 /*
    732  *	DESCRIPTION
    733  *		Convert XcmsColor structures to another format
    734  *
    735  *	RETURNS
    736  *		XcmsFailure if failed,
    737  *		XcmsSuccess if succeeded without gamut compression,
    738  *		XcmsSuccessWithCompression if succeeded with gamut
    739  *			compression.
    740  *
    741  */
    742 {
    743     XcmsColor clientWhitePt;
    744     XcmsColor Color1;
    745     XcmsColor *pColors_tmp;
    746     int callWhiteAdjustProc = 0;
    747     XcmsColorFormat format;
    748     Status retval;
    749     unsigned char contents_flag = 0x00;
    750     unsigned int iColors;
    751 
    752     if (ccc == NULL || pColors_in_out == NULL ||
    753 		!(ValidDIColorSpaceID(targetFormat) ||
    754 		ValidDDColorSpaceID(ccc, targetFormat))) {
    755 	return(XcmsFailure);
    756     }
    757 
    758     /*
    759      * Check formats in color specification array
    760      */
    761     format = pColors_in_out->format;
    762     for (pColors_tmp = pColors_in_out, iColors = nColors; iColors; pColors_tmp++, iColors--) {
    763 	if (!(ValidDIColorSpaceID(pColors_tmp->format) ||
    764 		ValidDDColorSpaceID(ccc, pColors_tmp->format))) {
    765 	    return(XcmsFailure);
    766 	}
    767 	if (XCMS_DI_ID(pColors_tmp->format)) {
    768 	    contents_flag |= DI_FORMAT;
    769 	} else {
    770 	    contents_flag |= DD_FORMAT;
    771 	}
    772 	if (pColors_tmp->format != format) {
    773 	    contents_flag |= MIX_FORMAT;
    774 	}
    775     }
    776 
    777     /*
    778      * Check if we need the Client White Point.
    779      */
    780     if ((contents_flag & DI_FORMAT) || XCMS_DI_ID(targetFormat)) {
    781 	/* To proceed, we need to get the Client White Point */
    782 	memcpy((char *)&clientWhitePt, (char *)&ccc->clientWhitePt,
    783 	       sizeof(XcmsColor));
    784 	if (clientWhitePt.format == XcmsUndefinedFormat) {
    785 	    /*
    786 	     * Client White Point is undefined, therefore set to the Screen
    787 	     *   White Point.
    788 	     * Since Client White Point == Screen White Point, WhiteAdjustProc
    789 	     *   is not called.
    790 	     */
    791 	    memcpy((char *)&clientWhitePt,
    792 		   (char *)&ccc->pPerScrnInfo->screenWhitePt,
    793 		   sizeof(XcmsColor));
    794 	} else if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc,
    795 		&clientWhitePt, ScreenWhitePointOfCCC(ccc))) {
    796 	    /*
    797 	     * Client White Point != Screen White Point, and WhiteAdjustProc
    798 	     *   is not NULL, therefore, will need to call it when
    799 	     *   converting between DI and DD specifications.
    800 	     */
    801 	    callWhiteAdjustProc = 1;
    802 	}
    803     }
    804 
    805     /*
    806      * Make copy of array of color specifications
    807      */
    808     if (nColors > 1) {
    809 	pColors_tmp = Xmallocarray(nColors, sizeof(XcmsColor));
    810 	if (pColors_tmp == NULL)
    811 	    return(XcmsFailure);
    812     } else {
    813 	pColors_tmp = &Color1;
    814     }
    815     memcpy((char *)pColors_tmp, (char *)pColors_in_out,
    816 	   nColors * sizeof(XcmsColor));
    817 
    818     /*
    819      * zero out pCompressed
    820      */
    821     if (pCompressed) {
    822 	bzero((char *)pCompressed, nColors * sizeof(Bool));
    823     }
    824 
    825     if (contents_flag == DD_FORMAT || contents_flag == DI_FORMAT) {
    826 	/*
    827 	 * ENTIRE ARRAY IS IN ONE FORMAT.
    828 	 */
    829 	if (XCMS_DI_ID(format) && XCMS_DI_ID(targetFormat)) {
    830 	    /*
    831 	     * DI-to-DI only conversion
    832 	     */
    833 	    retval = _XcmsDIConvertColors(ccc, pColors_tmp,
    834 		    &clientWhitePt, nColors, targetFormat);
    835 	} else if (XCMS_DD_ID(format) && XCMS_DD_ID(targetFormat)) {
    836 	    /*
    837 	     * DD-to-DD only conversion
    838 	     *   Since DD->DD there will be no compressed thus we can
    839 	     *   pass NULL instead of pCompressed.
    840 	     */
    841 	    retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
    842 		    targetFormat, (Bool *)NULL);
    843 	} else {
    844 	    /*
    845 	     * Otherwise we have:
    846 	     *    1. Device-Independent to Device-Dependent Conversion
    847 	     *		OR
    848 	     *    2. Device-Dependent to Device-Independent Conversion
    849 	     *
    850 	     *  We need to go from oldFormat -> CIEXYZ -> targetFormat
    851 	     *	adjusting for white points as necessary.
    852 	     */
    853 
    854 	    if (XCMS_DI_ID(format)) {
    855 		/*
    856 		 *    1. Device-Independent to Device-Dependent Conversion
    857 		 */
    858 		if (callWhiteAdjustProc) {
    859 		    /*
    860 		     * White Point Adjustment
    861 		     *		Client White Point to Screen White Point
    862 		     */
    863 		    retval = (*ccc->whitePtAdjProc)(ccc, &clientWhitePt,
    864 			    ScreenWhitePointOfCCC(ccc), targetFormat,
    865 			    pColors_tmp, nColors, pCompressed);
    866 		} else {
    867 		    if (_XcmsDIConvertColors(ccc, pColors_tmp,
    868 			    &clientWhitePt, nColors, XcmsCIEXYZFormat)
    869 			    == XcmsFailure) {
    870 			goto Failure;
    871 		    }
    872 		    retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
    873 			    targetFormat, pCompressed);
    874 		}
    875 	    } else {
    876 		/*
    877 		 *    2. Device-Dependent to Device-Independent Conversion
    878 		 */
    879 		if (callWhiteAdjustProc) {
    880 		    /*
    881 		     * White Point Adjustment
    882 		     *		Screen White Point to Client White Point
    883 		     */
    884 		    retval = (*ccc->whitePtAdjProc)(ccc,
    885 			    ScreenWhitePointOfCCC(ccc), &clientWhitePt,
    886 			    targetFormat, pColors_tmp, nColors, pCompressed);
    887 		} else {
    888 		    /*
    889 		     * Since DD->CIEXYZ, no compression takes place therefore
    890 		     * we can pass NULL instead of pCompressed.
    891 		     */
    892 		    if (_XcmsDDConvertColors(ccc, pColors_tmp, nColors,
    893 			    XcmsCIEXYZFormat, (Bool *)NULL) == XcmsFailure) {
    894 			goto Failure;
    895 		    }
    896 		    retval = _XcmsDIConvertColors(ccc, pColors_tmp,
    897 			    &clientWhitePt, nColors, targetFormat);
    898 		}
    899 	    }
    900 	}
    901     } else {
    902 	/*
    903 	 * ARRAY HAS MIXED FORMATS.
    904 	 */
    905 	if ((contents_flag == (DI_FORMAT | MIX_FORMAT)) &&
    906 		XCMS_DI_ID(targetFormat)) {
    907 	    /*
    908 	     * Convert from DI to DI in batches of contiguous formats
    909 	     *
    910 	     * Because DI->DI, WhiteAdjustProc not called.
    911 	     */
    912 	    retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
    913 		    nColors, targetFormat, (unsigned char)DI_FORMAT);
    914 	} else if ((contents_flag == (DD_FORMAT | MIX_FORMAT)) &&
    915 		XCMS_DD_ID(targetFormat)) {
    916 	    /*
    917 	     * Convert from DD to DD in batches of contiguous formats
    918 	     *
    919 	     * Because DD->DD, WhiteAdjustProc not called.
    920 	     */
    921 	    retval = ConvertMixedColors(ccc, pColors_tmp,
    922 		    (XcmsColor *)NULL, nColors, targetFormat,
    923 		    (unsigned char)DD_FORMAT);
    924 	} else if (XCMS_DI_ID(targetFormat)) {
    925 	    /*
    926 	     * We need to convert from DI-to-DI and DD-to-DI, therefore
    927 	     *   1. convert DD specifications to CIEXYZ, then
    928 	     *   2. convert all in batches to the target DI format.
    929 	     *
    930 	     * Note that ConvertMixedColors will call WhiteAdjustProc
    931 	     * as necessary.
    932 	     */
    933 
    934 	    /*
    935 	     * Convert only DD specifications in batches of contiguous formats
    936 	     * to CIEXYZ
    937 	     *
    938 	     * Since DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc
    939 	     * if required.
    940 	     */
    941 	    retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
    942 		    nColors, XcmsCIEXYZFormat, (unsigned char)DD_FORMAT);
    943 
    944 	    /*
    945 	     * Because at this point we may have a mix of DI formats
    946 	     * (e.g., CIEXYZ, CIELuv) we must convert the specs to the
    947 	     * target DI format in batches of contiguous source formats.
    948 	     */
    949 	    retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
    950 		    nColors, targetFormat, (unsigned char)DI_FORMAT);
    951 	} else {
    952 	    /*
    953 	     * We need to convert from DI-to-DD and DD-to-DD, therefore
    954 	     *   1. convert DI specifications to CIEXYZ, then
    955 	     *   2. convert all to the DD target format.
    956 	     *
    957 	     *   This allows white point adjustment and gamut compression
    958 	     *	 to be applied to all the color specifications in one
    959 	     *   swoop if those functions do in fact modify the entire
    960 	     *   group of color specifications.
    961 	     */
    962 
    963 	    /*
    964 	     * Convert in batches to CIEXYZ
    965 	     *
    966 	     * If DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc
    967 	     * if required.
    968 	     */
    969 	    if ((retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
    970 		    nColors, XcmsCIEXYZFormat,
    971 		    (unsigned char)(DI_FORMAT | DD_FORMAT))) == XcmsFailure) {
    972 		goto Failure;
    973 	    }
    974 
    975 	    /*
    976 	     * Convert all specifications (now in CIEXYZ format) to
    977 	     * the target DD format.
    978 	     * Since CIEXYZ->DD, compression MAY take place therefore
    979 	     * we must pass pCompressed.
    980 	     * Note that WhiteAdjustProc must be used if necessary.
    981 	     */
    982 	    if (callWhiteAdjustProc) {
    983 		/*
    984 		 * White Point Adjustment
    985 		 *	Client White Point to Screen White Point
    986 		 */
    987 		retval = (*ccc->whitePtAdjProc)(ccc,
    988 			&clientWhitePt, ScreenWhitePointOfCCC(ccc),
    989 			targetFormat, pColors_tmp, nColors, pCompressed);
    990 	    } else {
    991 		retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
    992 			targetFormat, pCompressed);
    993 	    }
    994 	}
    995     }
    996 
    997     if (retval != XcmsFailure) {
    998 	memcpy((char *)pColors_in_out, (char *)pColors_tmp,
    999 	       nColors * sizeof(XcmsColor));
   1000     }
   1001     if (nColors > 1) {
   1002 	Xfree(pColors_tmp);
   1003     }
   1004     return(retval);
   1005 
   1006 Failure:
   1007     if (nColors > 1) {
   1008 	Xfree(pColors_tmp);
   1009     }
   1010     return(XcmsFailure);
   1011 }
   1012 
   1013 
   1014 /*
   1016  *	NAME
   1017  *		XcmsRegFormatOfPrefix
   1018  *
   1019  *	SYNOPSIS
   1020  */
   1021 XcmsColorFormat
   1022 _XcmsRegFormatOfPrefix(
   1023     _Xconst char *prefix)
   1024 /*
   1025  *	DESCRIPTION
   1026  *		Returns a color space ID associated with the specified
   1027  *		X Consortium registered color space prefix.
   1028  *
   1029  *	RETURNS
   1030  *		The color space ID if found;
   1031  *		otherwise NULL.
   1032  */
   1033 {
   1034     XcmsRegColorSpaceEntry *pEntry = _XcmsRegColorSpaces;
   1035 
   1036     while (pEntry->prefix != NULL) {
   1037 	if (strcmp(prefix, pEntry->prefix) == 0) {
   1038 	    return(pEntry->id);
   1039 	}
   1040 	pEntry++;
   1041     }
   1042     return(XcmsUndefinedFormat);
   1043 }
   1044