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