Tizen 2.1 base
[framework/uifw/xorg/lib/libx11.git] / src / xcms / LRGB.c
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  */
75 static void LINEAR_RGB_FreeSCCData(XPointer pScreenDataTemp);
76 static int LINEAR_RGB_InitSCCData(Display *dpy,
77     int screenNumber, XcmsPerScrnInfo *pPerScrnInfo);
78 static int XcmsLRGB_RGB_ParseString(register char *spec, XcmsColor *pColor);
79 static int XcmsLRGB_RGBi_ParseString(register char *spec, XcmsColor *pColor);
80 static Status
81 _XcmsGetTableType0(
82     IntensityTbl *pTbl,
83     int   format,
84     char **pChar,
85     unsigned long *pCount);
86 static 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
100 static 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      */
126 static 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      */
137 static 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      */
148 static 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      */
158 static XcmsConversionProc Fl_CIEXYZ_to_RGBi[] = {
159     (XcmsConversionProc)XcmsCIEXYZToRGBi,
160     NULL
161 };
162
163     /*
164      * RGBi Color Spaces
165      */
166 XcmsColorSpace  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      */
179 XcmsColorSpace  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      */
193 static 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      */
209 XcmsFunctionSet 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
230 static 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
286 static 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
340 static 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
395 static IntensityTbl Default_RGB_RedTbl = {
396     /* IntensityRec *pBase */
397         (IntensityRec *) Default_RGB_RedTuples,
398     /* unsigned int nEntries */
399         52
400 };
401
402 static IntensityTbl Default_RGB_GreenTbl = {
403     /* IntensityRec *pBase */
404         (IntensityRec *)Default_RGB_GreenTuples,
405     /* unsigned int nEntries */
406         50
407 };
408
409 static IntensityTbl Default_RGB_BlueTbl = {
410     /* IntensityRec *pBase */
411         (IntensityRec *)Default_RGB_BlueTuples,
412     /* unsigned int nEntries */
413         51
414 };
415
416 static 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 \f
441 /************************************************************************
442  *                                                                      *
443  *                      PRIVATE ROUTINES                                *
444  *                                                                      *
445  ************************************************************************/
446
447 /*
448  *      NAME
449  *              LINEAR_RGB_InitSCCData()
450  *
451  *      SYNOPSIS
452  */
453 static Status
454 LINEAR_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 ((char *)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((char *)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 ((char *)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
798 FreeBlueTblElements:
799     Xfree((char *)pScreenData->pBlueTbl->pBase);
800
801 FreeBlueTbl:
802     Xfree((char *)pScreenData->pBlueTbl);
803
804 FreeGreenTblElements:
805     Xfree((char *)pScreenData->pGreenTbl->pBase);
806
807 FreeGreenTbl:
808     Xfree((char *)pScreenData->pGreenTbl);
809
810 FreeRedTblElements:
811     Xfree((char *)pScreenData->pRedTbl->pBase);
812
813 FreeRedTbl:
814     Xfree((char *)pScreenData->pRedTbl);
815
816 Free_property_return:
817     Xfree ((char *)property_return);
818
819 FreeSCCData:
820     Xfree((char *)pScreenDefaultData);
821     pPerScrnInfo->state = XcmsInitNone;
822     return(XcmsFailure);
823 }
824
825 \f
826 /*
827  *      NAME
828  *              LINEAR_RGB_FreeSCCData()
829  *
830  *      SYNOPSIS
831  */
832 static void
833 LINEAR_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 ((char *)pScreenData->pGreenTbl->pBase);
853                     }
854                 }
855                 if (pScreenData->pGreenTbl != pScreenData->pRedTbl) {
856                     Xfree ((char *)pScreenData->pGreenTbl);
857                 }
858             }
859             if (pScreenData->pBlueTbl) {
860                 if (pScreenData->pRedTbl->pBase !=
861                     pScreenData->pBlueTbl->pBase) {
862                     if (pScreenData->pBlueTbl->pBase) {
863                         Xfree ((char *)pScreenData->pBlueTbl->pBase);
864                     }
865                 }
866                 if (pScreenData->pBlueTbl != pScreenData->pRedTbl) {
867                     Xfree ((char *)pScreenData->pBlueTbl);
868                 }
869             }
870             if (pScreenData->pRedTbl->pBase) {
871                 Xfree ((char *)pScreenData->pRedTbl->pBase);
872             }
873             Xfree ((char *)pScreenData->pRedTbl);
874         }
875         Xfree ((char *)pScreenData);
876     }
877 }
878
879
880 \f
881 /************************************************************************
882  *                                                                      *
883  *                      API PRIVATE ROUTINES                            *
884  *                                                                      *
885  ************************************************************************/
886
887 /*
888  *      NAME
889  *              _XcmsGetTableType0
890  *
891  *      SYNOPSIS
892  */
893 static 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 \f
948 /*
949  *      NAME
950  *              _XcmsGetTableType1
951  *
952  *      SYNOPSIS
953  */
954 static 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     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 \f
1010 /*
1011  *      NAME
1012  *              ValueCmp
1013  *
1014  *      SYNOPSIS
1015  */
1016 static 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 \f
1035 /*
1036  *      NAME
1037  *              IntensityCmp
1038  *
1039  *      SYNOPSIS
1040  */
1041 static 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 \f
1065 /*
1066  *      NAME
1067  *              ValueInterpolation
1068  *
1069  *      SYNOPSIS
1070  */
1071 /* ARGSUSED */
1072 static 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 \f
1096 /*
1097  *      NAME
1098  *              IntensityInterpolation
1099  *
1100  *      SYNOPSIS
1101  */
1102 static 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 \f
1144
1145 typedef int (*comparProcp)(
1146     char *p1,
1147     char *p2);
1148 typedef 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  */
1161 static 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 specificied 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 \f
1229 /*
1230  *      NAME
1231  *              _XcmsMatVec - multiply a 3 x 3 by a 3 x 1 vector
1232  *
1233  *      SYNOPSIS
1234  */
1235 static 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 \f
1256 /************************************************************************
1257  *                                                                      *
1258  *                       PUBLIC ROUTINES                                *
1259  *                                                                      *
1260  ************************************************************************/
1261
1262
1263 /*
1264  *      NAME
1265  *              XcmsLRGB_RGB_ParseString
1266  *
1267  *      SYNOPSIS
1268  */
1269 static int
1270 XcmsLRGB_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 = 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, 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 \f
1381 /*
1382  *      NAME
1383  *              XcmsLRGB_RGBi_ParseString
1384  *
1385  *      SYNOPSIS
1386  */
1387 static int
1388 XcmsLRGB_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     int n;
1409     char *pchar;
1410
1411     if ((pchar = strchr(spec, ':')) == NULL) {
1412         return(XcmsFailure);
1413     }
1414     n = (int)(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 \f
1459 /*
1460  *      NAME
1461  *              XcmsCIEXYZToRGBi - convert CIE XYZ to RGB
1462  *
1463  *      SYNOPSIS
1464  */
1465 /* ARGSUSED */
1466 Status
1467 XcmsCIEXYZToRGBi(
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 \f
1581 /*
1582  *      NAME
1583  *              LINEAR_RGBi_to_CIEXYZ - convert RGBi to CIEXYZ
1584  *
1585  *      SYNOPSIS
1586  */
1587 /* ARGSUSED */
1588 Status
1589 XcmsRGBiToCIEXYZ(
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 \f
1634 /*
1635  *      NAME
1636  *              XcmsRGBiToRGB
1637  *
1638  *      SYNOPSIS
1639  */
1640 /* ARGSUSED */
1641 Status
1642 XcmsRGBiToRGB(
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 \f
1717 /*
1718  *      NAME
1719  *              XcmsRGBToRGBi
1720  *
1721  *      SYNOPSIS
1722  */
1723 /* ARGSUSED */
1724 Status
1725 XcmsRGBToRGBi(
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 \f
1797 /*
1798  *      NAME
1799  *              _XcmsInitScrnDefaultInfo
1800  *
1801  *      SYNOPSIS
1802  */
1803 /* ARGSUSED */
1804 int
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 }