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 
441 /************************************************************************
442  *									*
443  *			PRIVATE ROUTINES				*
444  *									*
445  ************************************************************************/
446 
447 /*
448  *	NAME
449  *		LINEAR_RGB_InitSCCData()
450  *
451  *	SYNOPSIS
452  */
453 static Status
LINEAR_RGB_InitSCCData(Display * dpy,int screenNumber,XcmsPerScrnInfo * pPerScrnInfo)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 (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 
798 FreeBlueTblElements: _X_UNUSED
799     Xfree(pScreenData->pBlueTbl->pBase);
800 
801 FreeBlueTbl:
802     Xfree(pScreenData->pBlueTbl);
803 
804 FreeGreenTblElements:
805     Xfree(pScreenData->pGreenTbl->pBase);
806 
807 FreeGreenTbl:
808     Xfree(pScreenData->pGreenTbl);
809 
810 FreeRedTblElements:
811     Xfree(pScreenData->pRedTbl->pBase);
812 
813 FreeRedTbl:
814     Xfree(pScreenData->pRedTbl);
815 
816 Free_property_return:
817     Xfree (property_return);
818 
819 FreeSCCData:
820     Xfree(pScreenDefaultData);
821     pPerScrnInfo->state = XcmsInitNone;
822     return(XcmsFailure);
823 }
824 
825 
826 /*
827  *	NAME
828  *		LINEAR_RGB_FreeSCCData()
829  *
830  *	SYNOPSIS
831  */
832 static void
LINEAR_RGB_FreeSCCData(XPointer pScreenDataTemp)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 (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  */
893 static Status
_XcmsGetTableType0(IntensityTbl * pTbl,int format,char ** pChar,unsigned long * pCount)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  */
954 static Status
_XcmsGetTableType1(IntensityTbl * pTbl,int format,char ** pChar,unsigned long * pCount)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  */
1016 static int
_XcmsValueCmp(IntensityRec * p1,IntensityRec * p2)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  */
1041 static int
_XcmsIntensityCmp(IntensityRec * p1,IntensityRec * p2)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 */
1072 static int
_XcmsValueInterpolation(IntensityRec * key,IntensityRec * lo,IntensityRec * hi,IntensityRec * answer,int bitsPerRGB)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  */
1102 static int
_XcmsIntensityInterpolation(IntensityRec * key,IntensityRec * lo,IntensityRec * hi,IntensityRec * answer,int bitsPerRGB)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 
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
_XcmsTableSearch(char * key,int bitsPerRGB,char * base,unsigned nel,unsigned nKeyPtrSize,int (* compar)(char * p1,char * p2),int (* interpol)(char * key,char * lo,char * hi,char * answer,int bitsPerRGB),char * answer)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  */
_XcmsMatVec(XcmsFloat * pMat,XcmsFloat * pIn,XcmsFloat * pOut)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 
1256 /************************************************************************
1257  *									*
1258  *			 PUBLIC ROUTINES				*
1259  *									*
1260  ************************************************************************/
1261 
1262 
1263 /*
1264  *	NAME
1265  *		XcmsLRGB_RGB_ParseString
1266  *
1267  *	SYNOPSIS
1268  */
1269 static int
XcmsLRGB_RGB_ParseString(register char * spec,XcmsColor * pColor)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 = (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  */
1387 static int
XcmsLRGB_RGBi_ParseString(register char * spec,XcmsColor * pColor)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     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 */
1466 Status
XcmsCIEXYZToRGBi(XcmsCCC ccc,XcmsColor * pXcmsColors_in_out,unsigned int nColors,Bool * pCompressed)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 
1581 /*
1582  *	NAME
1583  *		LINEAR_RGBi_to_CIEXYZ - convert RGBi to CIEXYZ
1584  *
1585  *	SYNOPSIS
1586  */
1587 /* ARGSUSED */
1588 Status
XcmsRGBiToCIEXYZ(XcmsCCC ccc,XcmsColor * pXcmsColors_in_out,unsigned int nColors,Bool * pCompressed)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 
1634 /*
1635  *	NAME
1636  *		XcmsRGBiToRGB
1637  *
1638  *	SYNOPSIS
1639  */
1640 /* ARGSUSED */
1641 Status
XcmsRGBiToRGB(XcmsCCC ccc,XcmsColor * pXcmsColors_in_out,unsigned int nColors,Bool * pCompressed)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 
1717 /*
1718  *	NAME
1719  *		XcmsRGBToRGBi
1720  *
1721  *	SYNOPSIS
1722  */
1723 /* ARGSUSED */
1724 Status
XcmsRGBToRGBi(XcmsCCC ccc,XcmsColor * pXcmsColors_in_out,unsigned int nColors,Bool * pCompressed)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 
1797 /*
1798  *	NAME
1799  *		_XcmsInitScrnDefaultInfo
1800  *
1801  *	SYNOPSIS
1802  */
1803 /* ARGSUSED */
1804 int
_XcmsLRGB_InitScrnDefault(Display * dpy,int screenNumber,XcmsPerScrnInfo * pPerScrnInfo)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