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