LRGB.c revision 1ab64890
1/* $Xorg: LRGB.c,v 1.3 2000/08/17 19:44:39 cpqbld Exp $ */
2
3/*
4 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
5 * 	All Rights Reserved
6 *
7 * This file is a component of an X Window System-specific implementation
8 * of Xcms based on the TekColor Color Management System.  Permission is
9 * hereby granted to use, copy, modify, sell, and otherwise distribute this
10 * software and its documentation for any purpose and without fee, provided
11 * that this copyright, permission, and disclaimer notice is reproduced in
12 * all copies of this software and in supporting documentation.  TekColor
13 * is a trademark of Tektronix, Inc.
14 *
15 * Tektronix makes no representation about the suitability of this software
16 * for any purpose.  It is provided "as is" and with all faults.
17 *
18 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
19 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
21 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
22 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
23 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
24 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
25 *
26 *
27 *	NAME
28 *		XcmsLRGB.c
29 *
30 *	DESCRIPTION
31 *		This file contains the conversion routines:
32 *		    1. CIE XYZ to RGB intensity
33 *		    2. RGB intensity to device RGB
34 *		    3. device RGB to RGB intensity
35 *		    4. RGB intensity to CIE XYZ
36 *
37 */
38/* $XFree86: xc/lib/X11/LRGB.c,v 3.6 2003/04/13 19:22:16 dawes Exp $ */
39
40#ifdef HAVE_CONFIG_H
41#include <config.h>
42#endif
43#include <stdio.h>
44#include <X11/Xos.h>
45#include <X11/Xatom.h>
46#include "Xlibint.h"
47#include "Xcmsint.h"
48#include "Cv.h"
49
50/*
51 *      LOCAL DEFINES
52 *		#define declarations local to this package.
53 */
54#define EPS	0.001
55#ifndef MIN
56#define MIN(x,y) ((x) > (y) ? (y) : (x))
57#endif /* MIN */
58#ifndef MAX
59#define MAX(x,y) ((x) > (y) ? (x) : (y))
60#endif /* MAX */
61#ifndef MIN3
62#define MIN3(x,y,z) ((x) > (MIN((y), (z))) ? (MIN((y), (z))) : (x))
63#endif /* MIN3 */
64#ifndef MAX3
65#define MAX3(x,y,z) ((x) > (MAX((y), (z))) ? (x) : (MAX((y), (z))))
66#endif /* MAX3 */
67
68/*
69 *      LOCAL TYPEDEFS
70 *              typedefs local to this package (for use with local vars).
71 *
72 */
73
74/*
75 *      FORWARD DECLARATIONS
76 */
77static void LINEAR_RGB_FreeSCCData(XPointer pScreenDataTemp);
78static int LINEAR_RGB_InitSCCData(Display *dpy,
79    int screenNumber, XcmsPerScrnInfo *pPerScrnInfo);
80static int XcmsLRGB_RGB_ParseString(register char *spec, XcmsColor *pColor);
81static int XcmsLRGB_RGBi_ParseString(register char *spec, XcmsColor *pColor);
82static Status
83_XcmsGetTableType0(
84    IntensityTbl *pTbl,
85    int	  format,
86    char **pChar,
87    unsigned long *pCount);
88static Status
89_XcmsGetTableType1(
90    IntensityTbl *pTbl,
91    int	  format,
92    char **pChar,
93    unsigned long *pCount);
94
95/*
96 *      LOCALS VARIABLES
97 *		Variables local to this package.
98 *		    Usage example:
99 *		        static int	ExampleLocalVar;
100 */
101
102static unsigned short const MASK[17] = {
103    0x0000,	/*  0 bitsPerRGB */
104    0x8000,	/*  1 bitsPerRGB */
105    0xc000,	/*  2 bitsPerRGB */
106    0xe000,	/*  3 bitsPerRGB */
107    0xf000,	/*  4 bitsPerRGB */
108    0xf800,	/*  5 bitsPerRGB */
109    0xfc00,	/*  6 bitsPerRGB */
110    0xfe00,	/*  7 bitsPerRGB */
111    0xff00,	/*  8 bitsPerRGB */
112    0xff80,	/*  9 bitsPerRGB */
113    0xffc0,	/* 10 bitsPerRGB */
114    0xffe0,	/* 11 bitsPerRGB */
115    0xfff0,	/* 12 bitsPerRGB */
116    0xfff8,	/* 13 bitsPerRGB */
117    0xfffc,	/* 14 bitsPerRGB */
118    0xfffe,	/* 15 bitsPerRGB */
119    0xffff	/* 16 bitsPerRGB */
120};
121
122
123    /*
124     * A NULL terminated array of function pointers that when applied
125     * in series will convert an XcmsColor structure from XcmsRGBFormat
126     * to XcmsCIEXYZFormat.
127     */
128static XcmsConversionProc Fl_RGB_to_CIEXYZ[] = {
129    (XcmsConversionProc)XcmsRGBToRGBi,
130    (XcmsConversionProc)XcmsRGBiToCIEXYZ,
131    NULL
132};
133
134    /*
135     * A NULL terminated array of function pointers that when applied
136     * in series will convert an XcmsColor structure from XcmsCIEXYZFormat
137     * to XcmsRGBFormat.
138     */
139static XcmsConversionProc Fl_CIEXYZ_to_RGB[] = {
140    (XcmsConversionProc)XcmsCIEXYZToRGBi,
141    (XcmsConversionProc)XcmsRGBiToRGB,
142    NULL
143};
144
145    /*
146     * A NULL terminated array of function pointers that when applied
147     * in series will convert an XcmsColor structure from XcmsRGBiFormat
148     * to XcmsCIEXYZFormat.
149     */
150static XcmsConversionProc Fl_RGBi_to_CIEXYZ[] = {
151    (XcmsConversionProc)XcmsRGBiToCIEXYZ,
152    NULL
153};
154
155    /*
156     * A NULL terminated array of function pointers that when applied
157     * in series will convert an XcmsColor structure from XcmsCIEXYZFormat
158     * to XcmsRGBiFormat.
159     */
160static XcmsConversionProc Fl_CIEXYZ_to_RGBi[] = {
161    (XcmsConversionProc)XcmsCIEXYZToRGBi,
162    NULL
163};
164
165    /*
166     * RGBi Color Spaces
167     */
168XcmsColorSpace	XcmsRGBiColorSpace =
169    {
170	_XcmsRGBi_prefix,	/* prefix */
171	XcmsRGBiFormat,		/* id */
172	XcmsLRGB_RGBi_ParseString,	/* parseString */
173	Fl_RGBi_to_CIEXYZ,	/* to_CIEXYZ */
174	Fl_CIEXYZ_to_RGBi,	/* from_CIEXYZ */
175	1
176    };
177
178    /*
179     * RGB Color Spaces
180     */
181XcmsColorSpace	XcmsRGBColorSpace =
182    {
183	_XcmsRGB_prefix,		/* prefix */
184	XcmsRGBFormat,		/* id */
185	XcmsLRGB_RGB_ParseString,	/* parseString */
186	Fl_RGB_to_CIEXYZ,	/* to_CIEXYZ */
187	Fl_CIEXYZ_to_RGB,	/* from_CIEXYZ */
188	1
189    };
190
191    /*
192     * Device-Independent Color Spaces known to the
193     * LINEAR_RGB Screen Color Characteristics Function Set.
194     */
195static XcmsColorSpace	*DDColorSpaces[] = {
196    &XcmsRGBColorSpace,
197    &XcmsRGBiColorSpace,
198    NULL
199};
200
201
202/*
203 *      GLOBALS
204 *              Variables declared in this package that are allowed
205 *		to be used globally.
206 */
207
208    /*
209     * LINEAR_RGB Screen Color Characteristics Function Set.
210     */
211XcmsFunctionSet	XcmsLinearRGBFunctionSet =
212    {
213	&DDColorSpaces[0],	/* pDDColorSpaces */
214	LINEAR_RGB_InitSCCData,	/* pInitScrnFunc */
215	LINEAR_RGB_FreeSCCData	/* pFreeSCCData */
216    };
217
218/*
219 *	DESCRIPTION
220 *		Contents of Default SCCData should be replaced if other
221 *		data should be used as default.
222 *
223 *
224 */
225
226/*
227 * NAME		Tektronix 19" (Sony) CRT
228 * PART_NUMBER		119-2451-00
229 * MODEL		Tek4300, Tek4800
230 */
231
232static IntensityRec const Default_RGB_RedTuples[] = {
233    /* {unsigned short value, XcmsFloat intensity} */
234            { 0x0000,    0.000000 },
235            { 0x0909,    0.000000 },
236            { 0x0a0a,    0.000936 },
237            { 0x0f0f,    0.001481 },
238            { 0x1414,    0.002329 },
239            { 0x1919,    0.003529 },
240            { 0x1e1e,    0.005127 },
241            { 0x2323,    0.007169 },
242            { 0x2828,    0.009699 },
243            { 0x2d2d,    0.012759 },
244            { 0x3232,    0.016392 },
245            { 0x3737,    0.020637 },
246            { 0x3c3c,    0.025533 },
247            { 0x4141,    0.031119 },
248            { 0x4646,    0.037431 },
249            { 0x4b4b,    0.044504 },
250            { 0x5050,    0.052373 },
251            { 0x5555,    0.061069 },
252            { 0x5a5a,    0.070624 },
253            { 0x5f5f,    0.081070 },
254            { 0x6464,    0.092433 },
255            { 0x6969,    0.104744 },
256            { 0x6e6e,    0.118026 },
257            { 0x7373,    0.132307 },
258            { 0x7878,    0.147610 },
259            { 0x7d7d,    0.163958 },
260            { 0x8282,    0.181371 },
261            { 0x8787,    0.199871 },
262            { 0x8c8c,    0.219475 },
263            { 0x9191,    0.240202 },
264            { 0x9696,    0.262069 },
265            { 0x9b9b,    0.285089 },
266            { 0xa0a0,    0.309278 },
267            { 0xa5a5,    0.334647 },
268            { 0xaaaa,    0.361208 },
269            { 0xafaf,    0.388971 },
270            { 0xb4b4,    0.417945 },
271            { 0xb9b9,    0.448138 },
272            { 0xbebe,    0.479555 },
273            { 0xc3c3,    0.512202 },
274            { 0xc8c8,    0.546082 },
275            { 0xcdcd,    0.581199 },
276            { 0xd2d2,    0.617552 },
277            { 0xd7d7,    0.655144 },
278            { 0xdcdc,    0.693971 },
279            { 0xe1e1,    0.734031 },
280            { 0xe6e6,    0.775322 },
281            { 0xebeb,    0.817837 },
282            { 0xf0f0,    0.861571 },
283            { 0xf5f5,    0.906515 },
284            { 0xfafa,    0.952662 },
285            { 0xffff,    1.000000 }
286};
287
288static IntensityRec const Default_RGB_GreenTuples[] = {
289    /* {unsigned short value, XcmsFloat intensity} */
290            { 0x0000,    0.000000 },
291            { 0x1313,    0.000000 },
292            { 0x1414,    0.000832 },
293            { 0x1919,    0.001998 },
294            { 0x1e1e,    0.003612 },
295            { 0x2323,    0.005736 },
296            { 0x2828,    0.008428 },
297            { 0x2d2d,    0.011745 },
298            { 0x3232,    0.015740 },
299            { 0x3737,    0.020463 },
300            { 0x3c3c,    0.025960 },
301            { 0x4141,    0.032275 },
302            { 0x4646,    0.039449 },
303            { 0x4b4b,    0.047519 },
304            { 0x5050,    0.056520 },
305            { 0x5555,    0.066484 },
306            { 0x5a5a,    0.077439 },
307            { 0x5f5f,    0.089409 },
308            { 0x6464,    0.102418 },
309            { 0x6969,    0.116485 },
310            { 0x6e6e,    0.131625 },
311            { 0x7373,    0.147853 },
312            { 0x7878,    0.165176 },
313            { 0x7d7d,    0.183604 },
314            { 0x8282,    0.203140 },
315            { 0x8787,    0.223783 },
316            { 0x8c8c,    0.245533 },
317            { 0x9191,    0.268384 },
318            { 0x9696,    0.292327 },
319            { 0x9b9b,    0.317351 },
320            { 0xa0a0,    0.343441 },
321            { 0xa5a5,    0.370580 },
322            { 0xaaaa,    0.398747 },
323            { 0xafaf,    0.427919 },
324            { 0xb4b4,    0.458068 },
325            { 0xb9b9,    0.489165 },
326            { 0xbebe,    0.521176 },
327            { 0xc3c3,    0.554067 },
328            { 0xc8c8,    0.587797 },
329            { 0xcdcd,    0.622324 },
330            { 0xd2d2,    0.657604 },
331            { 0xd7d7,    0.693588 },
332            { 0xdcdc,    0.730225 },
333            { 0xe1e1,    0.767459 },
334            { 0xe6e6,    0.805235 },
335            { 0xebeb,    0.843491 },
336            { 0xf0f0,    0.882164 },
337            { 0xf5f5,    0.921187 },
338            { 0xfafa,    0.960490 },
339            { 0xffff,    1.000000 }
340};
341
342static IntensityRec const Default_RGB_BlueTuples[] = {
343    /* {unsigned short value, XcmsFloat intensity} */
344            { 0x0000,    0.000000 },
345            { 0x0e0e,    0.000000 },
346            { 0x0f0f,    0.001341 },
347            { 0x1414,    0.002080 },
348            { 0x1919,    0.003188 },
349            { 0x1e1e,    0.004729 },
350            { 0x2323,    0.006766 },
351            { 0x2828,    0.009357 },
352            { 0x2d2d,    0.012559 },
353            { 0x3232,    0.016424 },
354            { 0x3737,    0.021004 },
355            { 0x3c3c,    0.026344 },
356            { 0x4141,    0.032489 },
357            { 0x4646,    0.039481 },
358            { 0x4b4b,    0.047357 },
359            { 0x5050,    0.056154 },
360            { 0x5555,    0.065903 },
361            { 0x5a5a,    0.076634 },
362            { 0x5f5f,    0.088373 },
363            { 0x6464,    0.101145 },
364            { 0x6969,    0.114968 },
365            { 0x6e6e,    0.129862 },
366            { 0x7373,    0.145841 },
367            { 0x7878,    0.162915 },
368            { 0x7d7d,    0.181095 },
369            { 0x8282,    0.200386 },
370            { 0x8787,    0.220791 },
371            { 0x8c8c,    0.242309 },
372            { 0x9191,    0.264937 },
373            { 0x9696,    0.288670 },
374            { 0x9b9b,    0.313499 },
375            { 0xa0a0,    0.339410 },
376            { 0xa5a5,    0.366390 },
377            { 0xaaaa,    0.394421 },
378            { 0xafaf,    0.423481 },
379            { 0xb4b4,    0.453547 },
380            { 0xb9b9,    0.484592 },
381            { 0xbebe,    0.516587 },
382            { 0xc3c3,    0.549498 },
383            { 0xc8c8,    0.583291 },
384            { 0xcdcd,    0.617925 },
385            { 0xd2d2,    0.653361 },
386            { 0xd7d7,    0.689553 },
387            { 0xdcdc,    0.726454 },
388            { 0xe1e1,    0.764013 },
389            { 0xe6e6,    0.802178 },
390            { 0xebeb,    0.840891 },
391            { 0xf0f0,    0.880093 },
392            { 0xf5f5,    0.919723 },
393            { 0xfafa,    0.959715 },
394	    { 0xffff,    1.00000 }
395};
396
397static IntensityTbl Default_RGB_RedTbl = {
398    /* IntensityRec *pBase */
399	(IntensityRec *) Default_RGB_RedTuples,
400    /* unsigned int nEntries */
401	52
402};
403
404static IntensityTbl Default_RGB_GreenTbl = {
405    /* IntensityRec *pBase */
406	(IntensityRec *)Default_RGB_GreenTuples,
407    /* unsigned int nEntries */
408	50
409};
410
411static IntensityTbl Default_RGB_BlueTbl = {
412    /* IntensityRec *pBase */
413	(IntensityRec *)Default_RGB_BlueTuples,
414    /* unsigned int nEntries */
415	51
416};
417
418static LINEAR_RGB_SCCData Default_RGB_SCCData = {
419    /* XcmsFloat XYZtoRGBmatrix[3][3] */
420  {
421    { 3.48340481253539000, -1.52176374927285200, -0.55923133354049780 },
422    {-1.07152751306193600,  1.96593795204372400,  0.03673691339553462 },
423    { 0.06351179790497788, -0.20020501000496480,  0.81070942031648220 }
424  },
425
426    /* XcmsFloat RGBtoXYZmatrix[3][3] */
427  {
428    { 0.38106149108714790, 0.32025712365352110, 0.24834578525933100 },
429    { 0.20729745115140850, 0.68054638776373240, 0.11215616108485920 },
430    { 0.02133944350088028, 0.14297193020246480, 1.24172892629665500 }
431  },
432
433    /* IntensityTbl *pRedTbl */
434	&Default_RGB_RedTbl,
435
436    /* IntensityTbl *pGreenTbl */
437	&Default_RGB_GreenTbl,
438
439    /* IntensityTbl *pBlueTbl */
440	&Default_RGB_BlueTbl
441};
442
443/************************************************************************
444 *									*
445 *			PRIVATE ROUTINES				*
446 *									*
447 ************************************************************************/
448
449/*
450 *	NAME
451 *		LINEAR_RGB_InitSCCData()
452 *
453 *	SYNOPSIS
454 */
455static Status
456LINEAR_RGB_InitSCCData(
457    Display *dpy,
458    int screenNumber,
459    XcmsPerScrnInfo *pPerScrnInfo)
460/*
461 *	DESCRIPTION
462 *
463 *	RETURNS
464 *		XcmsFailure if failed.
465 *		XcmsSuccess if succeeded.
466 *
467 */
468{
469    Atom  CorrectAtom = XInternAtom (dpy, XDCCC_CORRECT_ATOM_NAME, True);
470    Atom  MatrixAtom  = XInternAtom (dpy, XDCCC_MATRIX_ATOM_NAME, True);
471    int	  format_return, count, cType, nTables;
472    unsigned long nitems, nbytes_return;
473    char *property_return, *pChar;
474    XcmsFloat *pValue;
475#ifdef ALLDEBUG
476    IntensityRec *pIRec;
477#endif /* ALLDEBUG */
478    VisualID visualID;
479
480    LINEAR_RGB_SCCData *pScreenData, *pScreenDefaultData;
481    XcmsIntensityMap *pNewMap;
482
483    /*
484     * Allocate memory for pScreenData
485     */
486    if (!(pScreenData = pScreenDefaultData = (LINEAR_RGB_SCCData *)
487		      Xcalloc (1, sizeof(LINEAR_RGB_SCCData)))) {
488	return(XcmsFailure);
489    }
490
491    /*
492     *  1. Get the XYZ->RGB and RGB->XYZ matrices
493     */
494
495    if (MatrixAtom == None ||
496	!_XcmsGetProperty (dpy, RootWindow(dpy, screenNumber), MatrixAtom,
497	   &format_return, &nitems, &nbytes_return, &property_return) ||
498	   nitems != 18 || format_return != 32) {
499	/*
500	 * As per the XDCCC, there must be 18 data items and each must be
501	 * in 32 bits !
502	 */
503	goto FreeSCCData;
504
505    } else {
506
507	/*
508	 * RGBtoXYZ and XYZtoRGB matrices
509	 */
510	pValue = (XcmsFloat *) pScreenData;
511	pChar = property_return;
512	for (count = 0; count < 18; count++) {
513	    *pValue++ = (long)_XcmsGetElement(format_return, &pChar,
514		    &nitems) / (XcmsFloat)XDCCC_NUMBER;
515	}
516	Xfree ((char *)property_return);
517	pPerScrnInfo->screenWhitePt.spec.CIEXYZ.X =
518		pScreenData->RGBtoXYZmatrix[0][0] +
519		pScreenData->RGBtoXYZmatrix[0][1] +
520		pScreenData->RGBtoXYZmatrix[0][2];
521	pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y =
522		pScreenData->RGBtoXYZmatrix[1][0] +
523		pScreenData->RGBtoXYZmatrix[1][1] +
524		pScreenData->RGBtoXYZmatrix[1][2];
525	pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Z =
526		pScreenData->RGBtoXYZmatrix[2][0] +
527		pScreenData->RGBtoXYZmatrix[2][1] +
528		pScreenData->RGBtoXYZmatrix[2][2];
529
530	/*
531	 * Compute the Screen White Point
532	 */
533	if ((pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y < (1.0 - EPS) )
534		|| (pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y > (1.0 + EPS))) {
535	    goto FreeSCCData;
536	} else {
537	    pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y = 1.0;
538	}
539	pPerScrnInfo->screenWhitePt.format = XcmsCIEXYZFormat;
540	pPerScrnInfo->screenWhitePt.pixel = 0;
541
542#ifdef PDEBUG
543	printf ("RGB to XYZ Matrix values:\n");
544	printf ("       %f %f %f\n       %f %f %f\n       %f %f %f\n",
545		pScreenData->RGBtoXYZmatrix[0][0],
546		pScreenData->RGBtoXYZmatrix[0][1],
547		pScreenData->RGBtoXYZmatrix[0][2],
548		pScreenData->RGBtoXYZmatrix[1][0],
549		pScreenData->RGBtoXYZmatrix[1][1],
550		pScreenData->RGBtoXYZmatrix[1][2],
551		pScreenData->RGBtoXYZmatrix[2][0],
552		pScreenData->RGBtoXYZmatrix[2][1],
553		pScreenData->RGBtoXYZmatrix[2][2]);
554	printf ("XYZ to RGB Matrix values:\n");
555	printf ("       %f %f %f\n       %f %f %f\n       %f %f %f\n",
556		pScreenData->XYZtoRGBmatrix[0][0],
557		pScreenData->XYZtoRGBmatrix[0][1],
558		pScreenData->XYZtoRGBmatrix[0][2],
559		pScreenData->XYZtoRGBmatrix[1][0],
560		pScreenData->XYZtoRGBmatrix[1][1],
561		pScreenData->XYZtoRGBmatrix[1][2],
562		pScreenData->XYZtoRGBmatrix[2][0],
563		pScreenData->XYZtoRGBmatrix[2][1],
564		pScreenData->XYZtoRGBmatrix[2][2]);
565	printf ("Screen White Pt value: %f %f %f\n",
566		pPerScrnInfo->screenWhitePt.spec.CIEXYZ.X,
567		pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y,
568		pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Z);
569#endif /* PDEBUG */
570    }
571
572    /*
573     *	2. Get the Intensity Profile
574     */
575    if (CorrectAtom == None ||
576	!_XcmsGetProperty (dpy, RootWindow(dpy, screenNumber), CorrectAtom,
577	   &format_return, &nitems, &nbytes_return, &property_return)) {
578	Xfree ((char *)property_return);
579	goto FreeSCCData;
580    }
581
582    pChar = property_return;
583
584    while (nitems) {
585	switch (format_return) {
586	  case 8:
587	    /*
588	     * Must have at least:
589	     *		VisualID0
590	     *		VisualID1
591	     *		VisualID2
592	     *		VisualID3
593	     *		type
594	     *		count
595	     *		length
596	     *		intensity1
597	     *		intensity2
598	     */
599	    if (nitems < 9) {
600		Xfree ((char *)property_return);
601		goto FreeSCCData;
602	    }
603	    count = 3;
604	    break;
605	  case 16:
606	    /*
607	     * Must have at least:
608	     *		VisualID0
609	     *		VisualID3
610	     *		type
611	     *		count
612	     *		length
613	     *		intensity1
614	     *		intensity2
615	     */
616	    if (nitems < 7) {
617		Xfree ((char *)property_return);
618		goto FreeSCCData;
619	    }
620	    count = 1;
621	    break;
622	  case 32:
623	    /*
624	     * Must have at least:
625	     *		VisualID0
626	     *		type
627	     *		count
628	     *		length
629	     *		intensity1
630	     *		intensity2
631	     */
632	    if (nitems < 6) {
633		Xfree ((char *)property_return);
634		goto FreeSCCData;
635	    }
636	    count = 0;
637	    break;
638	  default:
639	    Xfree ((char *)property_return);
640	    goto FreeSCCData;
641	}
642
643	/*
644	 * Get VisualID
645	 */
646	visualID = _XcmsGetElement(format_return, &pChar, &nitems);
647	while (count--) {
648	    visualID = visualID << format_return;
649	    visualID |= _XcmsGetElement(format_return, &pChar, &nitems);
650	}
651
652	if (visualID == 0) {
653	    /*
654	     * This is a shared intensity table
655	     */
656	    pScreenData = pScreenDefaultData;
657	} else {
658	    /*
659	     * This is a per-Visual intensity table
660	     */
661	    if (!(pScreenData = (LINEAR_RGB_SCCData *)
662			      Xcalloc (1, sizeof(LINEAR_RGB_SCCData)))) {
663		return(XcmsFailure);
664	    }
665	    /* copy matrices */
666	    memcpy((char *)pScreenData, (char *)pScreenDefaultData,
667		   18 * sizeof(XcmsFloat));
668
669	    /* Create, initialize, and add map */
670	    if (!(pNewMap = (XcmsIntensityMap *)
671			      Xcalloc (1, sizeof(XcmsIntensityMap)))) {
672		Xfree((char *)pScreenData);
673		return(XcmsFailure);
674	    }
675	    pNewMap->visualID = visualID;
676	    pNewMap->screenData = (XPointer)pScreenData;
677	    pNewMap->pFreeScreenData = LINEAR_RGB_FreeSCCData;
678	    pNewMap->pNext =
679		    (XcmsIntensityMap *)dpy->cms.perVisualIntensityMaps;
680	    dpy->cms.perVisualIntensityMaps = (XPointer)pNewMap;
681	    dpy->free_funcs->intensityMaps = _XcmsFreeIntensityMaps;
682	}
683
684	cType = _XcmsGetElement(format_return, &pChar, &nitems);
685	nTables = _XcmsGetElement(format_return, &pChar, &nitems);
686
687	if (cType == 0) {
688
689	    /* Red Intensity Table */
690	    if (!(pScreenData->pRedTbl = (IntensityTbl *)
691		    Xcalloc (1, sizeof(IntensityTbl)))) {
692		goto FreeSCCData;
693	    }
694	    if (_XcmsGetTableType0(pScreenData->pRedTbl, format_return, &pChar,
695		    &nitems) == XcmsFailure) {
696		goto FreeRedTbl;
697	    }
698
699	    if (nTables == 1) {
700		/* Green Intensity Table */
701		pScreenData->pGreenTbl = pScreenData->pRedTbl;
702		/* Blue Intensity Table */
703		pScreenData->pBlueTbl = pScreenData->pRedTbl;
704	    } else {
705		/* Green Intensity Table */
706		if (!(pScreenData->pGreenTbl = (IntensityTbl *)
707			Xcalloc (1, sizeof(IntensityTbl)))) {
708		    goto FreeRedTblElements;
709		}
710		if (_XcmsGetTableType0(pScreenData->pGreenTbl, format_return, &pChar,
711			&nitems) == XcmsFailure) {
712		    goto FreeGreenTbl;
713		}
714
715		/* Blue Intensity Table */
716		if (!(pScreenData->pBlueTbl = (IntensityTbl *)
717			Xcalloc (1, sizeof(IntensityTbl)))) {
718		    goto FreeGreenTblElements;
719		}
720		if (_XcmsGetTableType0(pScreenData->pBlueTbl, format_return, &pChar,
721			&nitems) == XcmsFailure) {
722		    goto FreeBlueTbl;
723		}
724	    }
725	} else if (cType == 1) {
726	    /* Red Intensity Table */
727	    if (!(pScreenData->pRedTbl = (IntensityTbl *)
728		    Xcalloc (1, sizeof(IntensityTbl)))) {
729		goto FreeSCCData;
730	    }
731	    if (_XcmsGetTableType1(pScreenData->pRedTbl, format_return, &pChar,
732		    &nitems) == XcmsFailure) {
733		goto FreeRedTbl;
734	    }
735
736	    if (nTables == 1) {
737
738		/* Green Intensity Table */
739		pScreenData->pGreenTbl = pScreenData->pRedTbl;
740		/* Blue Intensity Table */
741		pScreenData->pBlueTbl = pScreenData->pRedTbl;
742
743	    } else {
744
745		/* Green Intensity Table */
746		if (!(pScreenData->pGreenTbl = (IntensityTbl *)
747			Xcalloc (1, sizeof(IntensityTbl)))) {
748		    goto FreeRedTblElements;
749		}
750		if (_XcmsGetTableType1(pScreenData->pGreenTbl, format_return, &pChar,
751			&nitems) == XcmsFailure) {
752		    goto FreeGreenTbl;
753		}
754
755		/* Blue Intensity Table */
756		if (!(pScreenData->pBlueTbl = (IntensityTbl *)
757			Xcalloc (1, sizeof(IntensityTbl)))) {
758		    goto FreeBlueTblElements;
759		}
760		if (_XcmsGetTableType1(pScreenData->pBlueTbl, format_return, &pChar,
761			&nitems) == XcmsFailure) {
762		    goto FreeBlueTbl;
763		}
764	    }
765	} else {
766	    Xfree ((char *)property_return);
767	    goto FreeSCCData;
768	}
769
770#ifdef ALLDEBUG
771	printf ("Intensity Table  RED    %d\n", pScreenData->pRedTbl->nEntries);
772	pIRec = (IntensityRec *) pScreenData->pRedTbl->pBase;
773	for (count = 0; count < pScreenData->pRedTbl->nEntries; count++, pIRec++) {
774	    printf ("\t0x%4x\t%f\n", pIRec->value, pIRec->intensity);
775	}
776	if (pScreenData->pGreenTbl->pBase != pScreenData->pRedTbl->pBase) {
777	    printf ("Intensity Table  GREEN  %d\n", pScreenData->pGreenTbl->nEntries);
778	    pIRec = (IntensityRec *)pScreenData->pGreenTbl->pBase;
779	    for (count = 0; count < pScreenData->pGreenTbl->nEntries; count++, pIRec++) {
780		printf ("\t0x%4x\t%f\n", pIRec->value, pIRec->intensity);
781	    }
782	}
783	if (pScreenData->pBlueTbl->pBase != pScreenData->pRedTbl->pBase) {
784	    printf ("Intensity Table  BLUE   %d\n", pScreenData->pBlueTbl->nEntries);
785	    pIRec = (IntensityRec *) pScreenData->pBlueTbl->pBase;
786	    for (count = 0; count < pScreenData->pBlueTbl->nEntries; count++, pIRec++) {
787		printf ("\t0x%4x\t%f\n", pIRec->value, pIRec->intensity);
788	    }
789	}
790#endif /* ALLDEBUG */
791    }
792
793    Xfree ((char *)property_return);
794
795    /* Free the old memory and use the new structure created. */
796    LINEAR_RGB_FreeSCCData(pPerScrnInfo->screenData);
797
798    pPerScrnInfo->functionSet = (XPointer) &XcmsLinearRGBFunctionSet;
799
800    pPerScrnInfo->screenData = (XPointer) pScreenData;
801
802    pPerScrnInfo->state = XcmsInitSuccess;
803
804    return(XcmsSuccess);
805
806FreeBlueTblElements:
807    Xfree((char *)pScreenData->pBlueTbl->pBase);
808
809FreeBlueTbl:
810    Xfree((char *)pScreenData->pBlueTbl);
811
812FreeGreenTblElements:
813    Xfree((char *)pScreenData->pBlueTbl->pBase);
814
815FreeGreenTbl:
816    Xfree((char *)pScreenData->pGreenTbl);
817
818FreeRedTblElements:
819    Xfree((char *)pScreenData->pRedTbl->pBase);
820
821FreeRedTbl:
822    Xfree((char *)pScreenData->pRedTbl);
823
824FreeSCCData:
825    Xfree((char *)pScreenData);
826    pPerScrnInfo->state = XcmsInitNone;
827    return(XcmsFailure);
828}
829
830
831/*
832 *	NAME
833 *		LINEAR_RGB_FreeSCCData()
834 *
835 *	SYNOPSIS
836 */
837static void
838LINEAR_RGB_FreeSCCData(
839    XPointer pScreenDataTemp)
840/*
841 *	DESCRIPTION
842 *
843 *	RETURNS
844 *		0 if failed.
845 *		1 if succeeded with no modifications.
846 *
847 */
848{
849    LINEAR_RGB_SCCData *pScreenData = (LINEAR_RGB_SCCData *) pScreenDataTemp;
850
851    if (pScreenData && pScreenData != &Default_RGB_SCCData) {
852	if (pScreenData->pRedTbl) {
853	    if (pScreenData->pGreenTbl) {
854		if (pScreenData->pRedTbl->pBase !=
855		    pScreenData->pGreenTbl->pBase) {
856		    if (pScreenData->pGreenTbl->pBase) {
857			Xfree ((char *)pScreenData->pGreenTbl->pBase);
858		    }
859		}
860		if (pScreenData->pGreenTbl != pScreenData->pRedTbl) {
861		    Xfree ((char *)pScreenData->pGreenTbl);
862		}
863	    }
864	    if (pScreenData->pBlueTbl) {
865		if (pScreenData->pRedTbl->pBase !=
866		    pScreenData->pBlueTbl->pBase) {
867		    if (pScreenData->pBlueTbl->pBase) {
868			Xfree ((char *)pScreenData->pBlueTbl->pBase);
869		    }
870		}
871		if (pScreenData->pBlueTbl != pScreenData->pRedTbl) {
872		    Xfree ((char *)pScreenData->pBlueTbl);
873		}
874	    }
875	    if (pScreenData->pRedTbl->pBase) {
876		Xfree ((char *)pScreenData->pRedTbl->pBase);
877	    }
878	    Xfree ((char *)pScreenData->pRedTbl);
879	}
880	Xfree ((char *)pScreenData);
881    }
882}
883
884
885
886/************************************************************************
887 *									*
888 *			API PRIVATE ROUTINES				*
889 *									*
890 ************************************************************************/
891
892/*
893 *	NAME
894 *		_XcmsGetTableType0
895 *
896 *	SYNOPSIS
897 */
898static Status
899_XcmsGetTableType0(
900    IntensityTbl *pTbl,
901    int	  format,
902    char **pChar,
903    unsigned long *pCount)
904/*
905 *	DESCRIPTION
906 *
907 *	RETURNS
908 *		XcmsFailure if failed.
909 *		XcmsSuccess if succeeded.
910 *
911 */
912{
913    unsigned int nElements;
914    IntensityRec *pIRec;
915
916    nElements = pTbl->nEntries =
917	    _XcmsGetElement(format, pChar, pCount) + 1;
918    if (!(pIRec = pTbl->pBase = (IntensityRec *)
919	  Xcalloc (nElements, sizeof(IntensityRec)))) {
920	return(XcmsFailure);
921    }
922
923    switch (format) {
924      case 8:
925	for (; nElements--; pIRec++) {
926	    /* 0xFFFF/0xFF = 0x101 */
927	    pIRec->value = _XcmsGetElement (format, pChar, pCount) * 0x101;
928	    pIRec->intensity =
929		    _XcmsGetElement (format, pChar, pCount) / (XcmsFloat)255.0;
930	}
931	break;
932      case 16:
933	for (; nElements--; pIRec++) {
934	    pIRec->value = _XcmsGetElement (format, pChar, pCount);
935	    pIRec->intensity = _XcmsGetElement (format, pChar, pCount)
936		    / (XcmsFloat)65535.0;
937	}
938	break;
939      case 32:
940	for (; nElements--; pIRec++) {
941	    pIRec->value = _XcmsGetElement (format, pChar, pCount);
942	    pIRec->intensity = _XcmsGetElement (format, pChar, pCount)
943		    / (XcmsFloat)4294967295.0;
944	}
945	break;
946      default:
947	return(XcmsFailure);
948    }
949    return(XcmsSuccess);
950}
951
952
953/*
954 *	NAME
955 *		_XcmsGetTableType1
956 *
957 *	SYNOPSIS
958 */
959static Status
960_XcmsGetTableType1(
961    IntensityTbl *pTbl,
962    int	  format,
963    char **pChar,
964    unsigned long *pCount)
965/*
966 *	DESCRIPTION
967 *
968 *	RETURNS
969 *		XcmsFailure if failed.
970 *		XcmsSuccess if succeeded.
971 *
972 */
973{
974    int count;
975    unsigned int max_index;
976    IntensityRec *pIRec;
977
978    max_index = _XcmsGetElement(format, pChar, pCount);
979    pTbl->nEntries = max_index + 1;
980    if (!(pIRec = pTbl->pBase = (IntensityRec *)
981	  Xcalloc (max_index+1, sizeof(IntensityRec)))) {
982	return(XcmsFailure);
983    }
984
985    switch (format) {
986      case 8:
987	for (count = 0; count < max_index+1; count++, pIRec++) {
988	    pIRec->value = (count * 65535) / max_index;
989	    pIRec->intensity = _XcmsGetElement (format, pChar, pCount)
990		    / (XcmsFloat)255.0;
991	}
992	break;
993      case 16:
994	for (count = 0; count < max_index+1; count++, pIRec++) {
995	    pIRec->value = (count * 65535) / max_index;
996	    pIRec->intensity = _XcmsGetElement (format, pChar, pCount)
997		    / (XcmsFloat)65535.0;
998	}
999	break;
1000      case 32:
1001	for (count = 0; count < max_index+1; count++, pIRec++) {
1002	    pIRec->value = (count * 65535) / max_index;
1003	    pIRec->intensity = _XcmsGetElement (format, pChar, pCount)
1004		    / (XcmsFloat)4294967295.0;
1005	}
1006	break;
1007      default:
1008	return(XcmsFailure);
1009    }
1010
1011    return(XcmsSuccess);
1012}
1013
1014
1015/*
1016 *	NAME
1017 *		ValueCmp
1018 *
1019 *	SYNOPSIS
1020 */
1021static int
1022_XcmsValueCmp(
1023    IntensityRec *p1, IntensityRec *p2)
1024/*
1025 *	DESCRIPTION
1026 *		Compares the value component of two IntensityRec
1027 *		structures.
1028 *
1029 *	RETURNS
1030 *		0 if p1->value is equal to p2->value
1031 *		< 0 if p1->value is less than p2->value
1032 *		> 0 if p1->value is greater than p2->value
1033 *
1034 */
1035{
1036    return (p1->value - p2->value);
1037}
1038
1039
1040/*
1041 *	NAME
1042 *		IntensityCmp
1043 *
1044 *	SYNOPSIS
1045 */
1046static int
1047_XcmsIntensityCmp(
1048    IntensityRec *p1, IntensityRec *p2)
1049/*
1050 *	DESCRIPTION
1051 *		Compares the intensity component of two IntensityRec
1052 *		structures.
1053 *
1054 *	RETURNS
1055 *		0 if equal;
1056 *		< 0 if first precedes second
1057 *		> 0 if first succeeds second
1058 *
1059 */
1060{
1061    if (p1->intensity < p2->intensity) {
1062	return (-1);
1063    }
1064    if (p1->intensity > p2->intensity) {
1065	return (XcmsSuccess);
1066    }
1067    return (XcmsFailure);
1068}
1069
1070/*
1071 *	NAME
1072 *		ValueInterpolation
1073 *
1074 *	SYNOPSIS
1075 */
1076/* ARGSUSED */
1077static int
1078_XcmsValueInterpolation(
1079    IntensityRec *key, IntensityRec *lo, IntensityRec *hi, IntensityRec *answer,
1080    int bitsPerRGB)
1081/*
1082 *	DESCRIPTION
1083 *		Based on a given value, performs a linear interpolation
1084 *		on the intensities between two IntensityRec structures.
1085 *		Note that the bitsPerRGB parameter is ignored.
1086 *
1087 *	RETURNS
1088 *		Returns 0 if failed; otherwise non-zero.
1089 */
1090{
1091    XcmsFloat ratio;
1092
1093    ratio = ((XcmsFloat)key->value - (XcmsFloat)lo->value) /
1094	((XcmsFloat)hi->value - (XcmsFloat)lo->value);
1095    answer->value = key->value;
1096    answer->intensity = (hi->intensity - lo->intensity) * ratio;
1097    answer->intensity += lo->intensity;
1098    return (XcmsSuccess);
1099}
1100
1101/*
1102 *	NAME
1103 *		IntensityInterpolation
1104 *
1105 *	SYNOPSIS
1106 */
1107static int
1108_XcmsIntensityInterpolation(
1109    IntensityRec *key, IntensityRec *lo, IntensityRec *hi, IntensityRec *answer,
1110    int bitsPerRGB)
1111/*
1112 *	DESCRIPTION
1113 *		Based on a given intensity, performs a linear interpolation
1114 *		on the values between two IntensityRec structures.
1115 *		The bitsPerRGB parameter is necessary to perform rounding
1116 *		to the correct number of significant bits.
1117 *
1118 *	RETURNS
1119 *		Returns 0 if failed; otherwise non-zero.
1120 */
1121{
1122    XcmsFloat ratio;
1123    long target, up, down;
1124    int shift = 16 - bitsPerRGB;
1125    int max_color = (1 << bitsPerRGB) - 1;
1126
1127    ratio = (key->intensity - lo->intensity) / (hi->intensity - lo->intensity);
1128    answer->intensity = key->intensity;
1129    target = hi->value - lo->value;
1130    target *= ratio;
1131    target += lo->value;
1132
1133    /*
1134     * Ok now, lets find the closest in respects to bits per RGB
1135     */
1136    up = ((target >> shift) * 0xFFFF) / max_color;
1137    if (up < target) {
1138	down = up;
1139	up = (MIN((down >> shift) + 1, max_color) * 0xFFFF) / max_color;
1140    } else {
1141	down = (MAX((up >> shift) - 1, 0) * 0xFFFF) / max_color;
1142    }
1143    answer->value = ((up - target) < (target - down) ? up : down);
1144    answer->value &= MASK[bitsPerRGB];
1145    return (XcmsSuccess);
1146}
1147
1148
1149
1150typedef int (*comparProcp)(
1151    char *p1,
1152    char *p2);
1153typedef int (*interpolProcp)(
1154    char *key,
1155    char *lo,
1156    char *hi,
1157    char *answer,
1158    int bitsPerRGB);
1159
1160/*
1161 *	NAME
1162 *		_XcmsTableSearch
1163 *
1164 *	SYNOPSIS
1165 */
1166static int
1167_XcmsTableSearch(
1168    char *key,
1169    int bitsPerRGB,
1170    char *base,
1171    unsigned nel,
1172    unsigned nKeyPtrSize,
1173    int (*compar)(
1174        char *p1,
1175        char *p2),
1176    int (*interpol)(
1177        char *key,
1178        char *lo,
1179        char *hi,
1180        char *answer,
1181        int bitsPerRGB),
1182    char *answer)
1183
1184/*
1185 *	DESCRIPTION
1186 *		A binary search through the specificied table.
1187 *
1188 *	RETURNS
1189 *		Returns 0 if failed; otherwise non-zero.
1190 *
1191 */
1192{
1193    char *hi, *lo, *mid, *last;
1194    int result;
1195
1196    last = hi = base + ((nel - 1) * nKeyPtrSize);
1197    mid = lo = base;
1198
1199    /* use only the significants bits, then scale into 16 bits */
1200    ((IntensityRec *)key)->value = ((unsigned long)
1201	    (((IntensityRec *)key)->value >> (16 - bitsPerRGB)) * 0xFFFF)
1202	    / ((1 << bitsPerRGB) - 1);
1203
1204    /* Special case so that zero intensity always maps to zero value */
1205    if ((*compar) (key,lo) <= 0) {
1206	memcpy (answer, lo, nKeyPtrSize);
1207	((IntensityRec *)answer)->value &= MASK[bitsPerRGB];
1208	return XcmsSuccess;
1209    }
1210    while (mid != last) {
1211	last = mid;
1212	mid = lo + (((unsigned)(hi - lo) / nKeyPtrSize) / 2) * nKeyPtrSize;
1213	result = (*compar) (key, mid);
1214	if (result == 0) {
1215
1216	    memcpy(answer, mid, nKeyPtrSize);
1217	    ((IntensityRec *)answer)->value &= MASK[bitsPerRGB];
1218	    return (XcmsSuccess);
1219	} else if (result < 0) {
1220	    hi = mid;
1221	} else {
1222	    lo = mid;
1223	}
1224    }
1225
1226    /*
1227     * If we got to here, we didn't find a solution, so we
1228     * need to apply interpolation.
1229     */
1230    return ((*interpol)(key, lo, hi, answer, bitsPerRGB));
1231}
1232
1233
1234/*
1235 *      NAME
1236 *		_XcmsMatVec - multiply a 3 x 3 by a 3 x 1 vector
1237 *
1238 *	SYNOPSIS
1239 */
1240static void _XcmsMatVec(
1241    XcmsFloat *pMat, XcmsFloat *pIn, XcmsFloat *pOut)
1242/*
1243 *      DESCRIPTION
1244 *		Multiply the passed vector by the passed matrix to return a
1245 *		vector. Matrix is 3x3, vectors are of length 3.
1246 *
1247 *	RETURNS
1248 *		void
1249 */
1250{
1251    int i, j;
1252
1253    for (i = 0; i < 3; i++) {
1254	pOut[i] = 0.0;
1255	for (j = 0; j < 3; j++)
1256	    pOut[i] += *(pMat+(i*3)+j) * pIn[j];
1257    }
1258}
1259
1260
1261/************************************************************************
1262 *									*
1263 *			 PUBLIC ROUTINES				*
1264 *									*
1265 ************************************************************************/
1266
1267
1268/*
1269 *	NAME
1270 *		XcmsLRGB_RGB_ParseString
1271 *
1272 *	SYNOPSIS
1273 */
1274static int
1275XcmsLRGB_RGB_ParseString(
1276    register char *spec,
1277    XcmsColor *pColor)
1278/*
1279 *	DESCRIPTION
1280 *		This routines takes a string and attempts to convert
1281 *		it into a XcmsColor structure with XcmsRGBFormat.
1282 *
1283 *	RETURNS
1284 *		0 if failed, non-zero otherwise.
1285 */
1286{
1287    register int n, i;
1288    unsigned short r, g, b;
1289    char c;
1290    char *pchar;
1291    unsigned short *pShort;
1292
1293    /*
1294     * Check for old # format
1295     */
1296    if (*spec == '#') {
1297	/*
1298	 * Attempt to parse the value portion.
1299	 */
1300	spec++;
1301	n = strlen(spec);
1302	if (n != 3 && n != 6 && n != 9 && n != 12) {
1303	    return(XcmsFailure);
1304	}
1305
1306	n /= 3;
1307	g = b = 0;
1308	do {
1309	    r = g;
1310	    g = b;
1311	    b = 0;
1312	    for (i = n; --i >= 0; ) {
1313		c = *spec++;
1314		b <<= 4;
1315		if (c >= '0' && c <= '9')
1316		    b |= c - '0';
1317		/* assume string in lowercase
1318		else if (c >= 'A' && c <= 'F')
1319		    b |= c - ('A' - 10);
1320		*/
1321		else if (c >= 'a' && c <= 'f')
1322		    b |= c - ('a' - 10);
1323		else return (XcmsFailure);
1324	    }
1325	} while (*spec != '\0');
1326
1327	/*
1328	 * Succeeded !
1329	 */
1330	n <<= 2;
1331	n = 16 - n;
1332	/* shift instead of scale, to match old broken semantics */
1333	pColor->spec.RGB.red = r << n;
1334	pColor->spec.RGB.green = g << n;
1335	pColor->spec.RGB.blue =  b << n;
1336    } else {
1337	if ((pchar = strchr(spec, ':')) == NULL) {
1338	    return(XcmsFailure);
1339	}
1340	n = (int)(pchar - spec);
1341
1342	/*
1343	 * Check for proper prefix.
1344	 */
1345	if (strncmp(spec, _XcmsRGB_prefix, n) != 0) {
1346	    return(XcmsFailure);
1347	}
1348
1349	/*
1350	 * Attempt to parse the value portion.
1351	 */
1352	spec += (n + 1);
1353	pShort = &pColor->spec.RGB.red;
1354	for (i = 0; i < 3; i++, pShort++, spec++) {
1355	    n = 0;
1356	    *pShort = 0;
1357	    while (*spec != '/' && *spec != '\0') {
1358		if (++n > 4) {
1359		    return(XcmsFailure);
1360		}
1361		c = *spec++;
1362		*pShort <<= 4;
1363		if (c >= '0' && c <= '9')
1364		    *pShort |= c - '0';
1365		/* assume string in lowercase
1366		else if (c >= 'A' && c <= 'F')
1367		    *pShort |= c - ('A' - 10);
1368		*/
1369		else if (c >= 'a' && c <= 'f')
1370		    *pShort |= c - ('a' - 10);
1371		else return (XcmsFailure);
1372	    }
1373	    if (n == 0)
1374		return (XcmsFailure);
1375	    if (n < 4) {
1376		*pShort = ((unsigned long)*pShort * 0xFFFF) / ((1 << n*4) - 1);
1377	    }
1378	}
1379    }
1380    pColor->format = XcmsRGBFormat;
1381    pColor->pixel = 0;
1382    return (XcmsSuccess);
1383}
1384
1385
1386/*
1387 *	NAME
1388 *		XcmsLRGB_RGBi_ParseString
1389 *
1390 *	SYNOPSIS
1391 */
1392static int
1393XcmsLRGB_RGBi_ParseString(
1394    register char *spec,
1395    XcmsColor *pColor)
1396/*
1397 *	DESCRIPTION
1398 *		This routines takes a string and attempts to convert
1399 *		it into a XcmsColor structure with XcmsRGBiFormat.
1400 *		The assumed RGBi string syntax is:
1401 *		    RGBi:<r>/<g>/<b>
1402 *		Where r, g, and b are in string input format for floats
1403 *		consisting of:
1404 *		    a. an optional sign
1405 *		    b. a string of numbers possibly containing a decimal point,
1406 *		    c. an optional exponent field containing an 'E' or 'e'
1407 *			followed by a possibly signed integer string.
1408 *
1409 *	RETURNS
1410 *		0 if failed, non-zero otherwise.
1411 */
1412{
1413    int n;
1414    char *pchar;
1415
1416    if ((pchar = strchr(spec, ':')) == NULL) {
1417	return(XcmsFailure);
1418    }
1419    n = (int)(pchar - spec);
1420
1421    /*
1422     * Check for proper prefix.
1423     */
1424    if (strncmp(spec, _XcmsRGBi_prefix, n) != 0) {
1425	return(XcmsFailure);
1426    }
1427
1428    /*
1429     * Attempt to parse the value portion.
1430     */
1431    if (sscanf(spec + n + 1, "%lf/%lf/%lf",
1432	    &pColor->spec.RGBi.red,
1433	    &pColor->spec.RGBi.green,
1434	    &pColor->spec.RGBi.blue) != 3) {
1435        char *s; /* Maybe failed due to locale */
1436        int f;
1437        if ((s = strdup(spec))) {
1438            for (f = 0; s[f]; ++f)
1439                if (s[f] == '.')
1440                    s[f] = ',';
1441                else if (s[f] == ',')
1442                    s[f] = '.';
1443	    if (sscanf(s + n + 1, "%lf/%lf/%lf",
1444		       &pColor->spec.RGBi.red,
1445		       &pColor->spec.RGBi.green,
1446		       &pColor->spec.RGBi.blue) != 3) {
1447                free(s);
1448                return(XcmsFailure);
1449            }
1450            free(s);
1451        } else
1452	    return(XcmsFailure);
1453    }
1454
1455    /*
1456     * Succeeded !
1457     */
1458    pColor->format = XcmsRGBiFormat;
1459    pColor->pixel = 0;
1460    return (XcmsSuccess);
1461}
1462
1463
1464/*
1465 *	NAME
1466 *		XcmsCIEXYZToRGBi - convert CIE XYZ to RGB
1467 *
1468 *	SYNOPSIS
1469 */
1470/* ARGSUSED */
1471Status
1472XcmsCIEXYZToRGBi(
1473    XcmsCCC ccc,
1474    XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert 	*/
1475    unsigned int nColors,	/* Number of colors			*/
1476    Bool *pCompressed)		/* pointer to an array of Bool		*/
1477/*
1478 *	DESCRIPTION
1479 *		Converts color specifications in an array of XcmsColor
1480 *		structures from RGB format to RGBi format.
1481 *
1482 *	RETURNS
1483 *		XcmsFailure if failed,
1484 *		XcmsSuccess if succeeded without gamut compression.
1485 *		XcmsSuccessWithCompression if succeeded with gamut
1486 *			compression.
1487 */
1488{
1489    LINEAR_RGB_SCCData *pScreenData;
1490    XcmsFloat tmp[3];
1491    int hasCompressed = 0;
1492    unsigned int i;
1493    XcmsColor *pColor = pXcmsColors_in_out;
1494
1495    if (ccc == NULL) {
1496	return(XcmsFailure);
1497    }
1498
1499    pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData;
1500
1501    /*
1502     * XcmsColors should be White Point Adjusted, if necessary, by now!
1503     */
1504
1505    /*
1506     * NEW!!! for extended gamut compression
1507     *
1508     * 1. Need to zero out pCompressed
1509     *
1510     * 2. Need to save initial address of pColor
1511     *
1512     * 3. Need to save initial address of pCompressed
1513     */
1514
1515    for (i = 0; i < nColors; i++) {
1516
1517	/* Make sure format is XcmsCIEXYZFormat */
1518	if (pColor->format != XcmsCIEXYZFormat) {
1519	    return(XcmsFailure);
1520	}
1521
1522	/* Multiply [A]-1 * [XYZ] to get RGB intensity */
1523	_XcmsMatVec((XcmsFloat *) pScreenData->XYZtoRGBmatrix,
1524		(XcmsFloat *) &pColor->spec, tmp);
1525
1526	if ((MIN3 (tmp[0], tmp[1], tmp[2]) < -EPS) ||
1527	    (MAX3 (tmp[0], tmp[1], tmp[2]) > (1.0 + EPS))) {
1528
1529	    /*
1530	     * RGBi out of screen's gamut
1531	     */
1532
1533	    if (ccc->gamutCompProc == NULL) {
1534		/*
1535		 * Aha!! Here's that little trick that will allow
1536		 * gamut compression routines to get the out of bound
1537		 * RGBi.
1538		 */
1539		memcpy((char *)&pColor->spec, (char *)tmp, sizeof(tmp));
1540		pColor->format = XcmsRGBiFormat;
1541		return(XcmsFailure);
1542	    } else if ((*ccc->gamutCompProc)(ccc, pXcmsColors_in_out, nColors,
1543		    i, pCompressed) == 0) {
1544		return(XcmsFailure);
1545	    }
1546
1547	    /*
1548	     * The gamut compression function should return colors in CIEXYZ
1549	     *	Also check again to if the new color is within gamut.
1550	     */
1551	    if (pColor->format != XcmsCIEXYZFormat) {
1552		return(XcmsFailure);
1553	    }
1554	    _XcmsMatVec((XcmsFloat *) pScreenData->XYZtoRGBmatrix,
1555		    (XcmsFloat *) &pColor->spec, tmp);
1556	    if ((MIN3 (tmp[0], tmp[1], tmp[2]) < -EPS) ||
1557		(MAX3 (tmp[0], tmp[1], tmp[2]) > (1.0 + EPS))) {
1558		return(XcmsFailure);
1559	    }
1560	    hasCompressed++;
1561	}
1562	memcpy((char *)&pColor->spec, (char *)tmp, sizeof(tmp));
1563	/* These if statements are done to ensure the fudge factor is */
1564	/* is taken into account. */
1565	if (pColor->spec.RGBi.red < 0.0) {
1566		pColor->spec.RGBi.red = 0.0;
1567	} else if (pColor->spec.RGBi.red > 1.0) {
1568		pColor->spec.RGBi.red = 1.0;
1569	}
1570	if (pColor->spec.RGBi.green < 0.0) {
1571		pColor->spec.RGBi.green = 0.0;
1572	} else if (pColor->spec.RGBi.green > 1.0) {
1573		pColor->spec.RGBi.green = 1.0;
1574	}
1575	if (pColor->spec.RGBi.blue < 0.0) {
1576		pColor->spec.RGBi.blue = 0.0;
1577	} else if (pColor->spec.RGBi.blue > 1.0) {
1578		pColor->spec.RGBi.blue = 1.0;
1579	}
1580	(pColor++)->format = XcmsRGBiFormat;
1581    }
1582    return (hasCompressed ? XcmsSuccessWithCompression : XcmsSuccess);
1583}
1584
1585
1586/*
1587 *	NAME
1588 *		LINEAR_RGBi_to_CIEXYZ - convert RGBi to CIEXYZ
1589 *
1590 *	SYNOPSIS
1591 */
1592/* ARGSUSED */
1593Status
1594XcmsRGBiToCIEXYZ(
1595    XcmsCCC ccc,
1596    XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert 	*/
1597    unsigned int nColors,	/* Number of colors			*/
1598    Bool *pCompressed)		/* pointer to a bit array		*/
1599/*
1600 *	DESCRIPTION
1601 *		Converts color specifications in an array of XcmsColor
1602 *		structures from RGBi format to CIEXYZ format.
1603 *
1604 *	RETURNS
1605 *		XcmsFailure if failed,
1606 *		XcmsSuccess if succeeded.
1607 */
1608{
1609    LINEAR_RGB_SCCData *pScreenData;
1610    XcmsFloat tmp[3];
1611
1612    /*
1613     * pCompressed ignored in this function.
1614     */
1615
1616    if (ccc == NULL) {
1617	return(XcmsFailure);
1618    }
1619
1620    pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData;
1621
1622    /*
1623     * XcmsColors should be White Point Adjusted, if necessary, by now!
1624     */
1625
1626    while (nColors--) {
1627
1628	/* Multiply [A]-1 * [XYZ] to get RGB intensity */
1629	_XcmsMatVec((XcmsFloat *) pScreenData->RGBtoXYZmatrix,
1630		(XcmsFloat *) &pXcmsColors_in_out->spec, tmp);
1631
1632	memcpy((char *)&pXcmsColors_in_out->spec, (char *)tmp, sizeof(tmp));
1633	(pXcmsColors_in_out++)->format = XcmsCIEXYZFormat;
1634    }
1635    return(XcmsSuccess);
1636}
1637
1638
1639/*
1640 *	NAME
1641 *		XcmsRGBiToRGB
1642 *
1643 *	SYNOPSIS
1644 */
1645/* ARGSUSED */
1646Status
1647XcmsRGBiToRGB(
1648    XcmsCCC ccc,
1649    XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert 	*/
1650    unsigned int nColors,	/* Number of colors			*/
1651    Bool *pCompressed)		/* pointer to a bit array		*/
1652/*
1653 *	DESCRIPTION
1654 *		Converts color specifications in an array of XcmsColor
1655 *		structures from RGBi format to RGB format.
1656 *
1657 *	RETURNS
1658 *		XcmsFailure if failed,
1659 *		XcmsSuccess if succeeded without gamut compression.
1660 *		XcmsSuccessWithCompression if succeeded with gamut
1661 *			compression.
1662 */
1663{
1664    LINEAR_RGB_SCCData *pScreenData;
1665    XcmsRGB tmpRGB;
1666    IntensityRec keyIRec, answerIRec;
1667
1668    /*
1669     * pCompressed ignored in this function.
1670     */
1671
1672    if (ccc == NULL) {
1673	return(XcmsFailure);
1674    }
1675
1676    pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData;
1677
1678    while (nColors--) {
1679
1680	/* Make sure format is XcmsRGBiFormat */
1681	if (pXcmsColors_in_out->format != XcmsRGBiFormat) {
1682	    return(XcmsFailure);
1683	}
1684
1685	keyIRec.intensity = pXcmsColors_in_out->spec.RGBi.red;
1686	if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb,
1687		(char *)pScreenData->pRedTbl->pBase,
1688		(unsigned)pScreenData->pRedTbl->nEntries,
1689		(unsigned)sizeof(IntensityRec),
1690		(comparProcp)_XcmsIntensityCmp, (interpolProcp)_XcmsIntensityInterpolation, (char *)&answerIRec)) {
1691	    return(XcmsFailure);
1692	}
1693	tmpRGB.red = answerIRec.value;
1694
1695	keyIRec.intensity = pXcmsColors_in_out->spec.RGBi.green;
1696	if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb,
1697		(char *)pScreenData->pGreenTbl->pBase,
1698		(unsigned)pScreenData->pGreenTbl->nEntries,
1699		(unsigned)sizeof(IntensityRec),
1700		(comparProcp)_XcmsIntensityCmp, (interpolProcp)_XcmsIntensityInterpolation, (char *)&answerIRec)) {
1701	    return(XcmsFailure);
1702	}
1703	tmpRGB.green = answerIRec.value;
1704
1705	keyIRec.intensity = pXcmsColors_in_out->spec.RGBi.blue;
1706	if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb,
1707		(char *)pScreenData->pBlueTbl->pBase,
1708		(unsigned)pScreenData->pBlueTbl->nEntries,
1709		(unsigned)sizeof(IntensityRec),
1710		(comparProcp)_XcmsIntensityCmp, (interpolProcp)_XcmsIntensityInterpolation, (char *)&answerIRec)) {
1711	    return(XcmsFailure);
1712	}
1713	tmpRGB.blue = answerIRec.value;
1714
1715	memcpy((char *)&pXcmsColors_in_out->spec, (char *)&tmpRGB, sizeof(XcmsRGB));
1716	(pXcmsColors_in_out++)->format = XcmsRGBFormat;
1717    }
1718    return(XcmsSuccess);
1719}
1720
1721
1722/*
1723 *	NAME
1724 *		XcmsRGBToRGBi
1725 *
1726 *	SYNOPSIS
1727 */
1728/* ARGSUSED */
1729Status
1730XcmsRGBToRGBi(
1731    XcmsCCC ccc,
1732    XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert 	*/
1733    unsigned int nColors,	/* Number of colors			*/
1734    Bool *pCompressed)		/* pointer to a bit array		*/
1735/*
1736 *	DESCRIPTION
1737 *		Converts color specifications in an array of XcmsColor
1738 *		structures from RGB format to RGBi format.
1739 *
1740 *	RETURNS
1741 *		XcmsFailure if failed,
1742 *		XcmsSuccess if succeeded.
1743 */
1744{
1745    LINEAR_RGB_SCCData *pScreenData;
1746    XcmsRGBi tmpRGBi;
1747    IntensityRec keyIRec, answerIRec;
1748
1749    /*
1750     * pCompressed ignored in this function.
1751     */
1752
1753    if (ccc == NULL) {
1754	return(XcmsFailure);
1755    }
1756
1757    pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData;
1758
1759    while (nColors--) {
1760
1761	/* Make sure format is XcmsRGBFormat */
1762	if (pXcmsColors_in_out->format != XcmsRGBFormat) {
1763	    return(XcmsFailure);
1764	}
1765
1766	keyIRec.value = pXcmsColors_in_out->spec.RGB.red;
1767	if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb,
1768		(char *)pScreenData->pRedTbl->pBase,
1769		(unsigned)pScreenData->pRedTbl->nEntries,
1770		(unsigned)sizeof(IntensityRec),
1771		(comparProcp)_XcmsValueCmp, (interpolProcp)_XcmsValueInterpolation, (char *)&answerIRec)) {
1772	    return(XcmsFailure);
1773	}
1774	tmpRGBi.red = answerIRec.intensity;
1775
1776	keyIRec.value = pXcmsColors_in_out->spec.RGB.green;
1777	if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb,
1778		(char *)pScreenData->pGreenTbl->pBase,
1779		(unsigned)pScreenData->pGreenTbl->nEntries,
1780		(unsigned)sizeof(IntensityRec),
1781		(comparProcp)_XcmsValueCmp, (interpolProcp)_XcmsValueInterpolation, (char *)&answerIRec)) {
1782	    return(XcmsFailure);
1783	}
1784	tmpRGBi.green = answerIRec.intensity;
1785
1786	keyIRec.value = pXcmsColors_in_out->spec.RGB.blue;
1787	if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb,
1788		(char *)pScreenData->pBlueTbl->pBase,
1789		(unsigned)pScreenData->pBlueTbl->nEntries,
1790		(unsigned)sizeof(IntensityRec),
1791		(comparProcp)_XcmsValueCmp, (interpolProcp)_XcmsValueInterpolation, (char *)&answerIRec)) {
1792	    return(XcmsFailure);
1793	}
1794	tmpRGBi.blue = answerIRec.intensity;
1795
1796	memcpy((char *)&pXcmsColors_in_out->spec, (char *)&tmpRGBi, sizeof(XcmsRGBi));
1797	(pXcmsColors_in_out++)->format = XcmsRGBiFormat;
1798    }
1799    return(XcmsSuccess);
1800}
1801
1802/*
1803 *	NAME
1804 *		_XcmsInitScrnDefaultInfo
1805 *
1806 *	SYNOPSIS
1807 */
1808/* ARGSUSED */
1809int
1810_XcmsLRGB_InitScrnDefault(
1811    Display *dpy,
1812    int screenNumber,
1813    XcmsPerScrnInfo *pPerScrnInfo)
1814/*
1815 *	DESCRIPTION
1816 *		Given a display and screen number, this routine attempts
1817 *		to initialize the Xcms per Screen Info structure
1818 *		(XcmsPerScrnInfo) with defaults.
1819 *
1820 *	RETURNS
1821 *		Returns zero if initialization failed; non-zero otherwise.
1822 */
1823{
1824    pPerScrnInfo->screenData = (XPointer)&Default_RGB_SCCData;
1825    pPerScrnInfo->screenWhitePt.spec.CIEXYZ.X =
1826		Default_RGB_SCCData.RGBtoXYZmatrix[0][0] +
1827		Default_RGB_SCCData.RGBtoXYZmatrix[0][1] +
1828		Default_RGB_SCCData.RGBtoXYZmatrix[0][2];
1829    pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y =
1830		Default_RGB_SCCData.RGBtoXYZmatrix[1][0] +
1831		Default_RGB_SCCData.RGBtoXYZmatrix[1][1] +
1832		Default_RGB_SCCData.RGBtoXYZmatrix[1][2];
1833    pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Z =
1834		Default_RGB_SCCData.RGBtoXYZmatrix[2][0] +
1835		Default_RGB_SCCData.RGBtoXYZmatrix[2][1] +
1836		Default_RGB_SCCData.RGBtoXYZmatrix[2][2];
1837    if ((pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y < (1.0 - EPS) )
1838	    || (pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y > (1.0 + EPS))) {
1839	pPerScrnInfo->screenData = (XPointer)NULL;
1840	pPerScrnInfo->state = XcmsInitNone;
1841	return(0);
1842    }
1843    pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y = 1.0;
1844    pPerScrnInfo->screenWhitePt.format = XcmsCIEXYZFormat;
1845    pPerScrnInfo->screenWhitePt.pixel = 0;
1846    pPerScrnInfo->functionSet = (XPointer)&XcmsLinearRGBFunctionSet;
1847    pPerScrnInfo->state = XcmsInitFailure; /* default initialization */
1848    return(1);
1849}
1850