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  *		XcmsInt.c - Xcms API utility routines
28  *
29  *	DESCRIPTION
30  *		Xcms Application Program Interface (API) utility
31  *		routines for hanging information directly onto
32  *		the Display structure.
33  *
34  *
35  */
36 
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40 #include <stdio.h>
41 #include "Xlibint.h"
42 #include "Xcmsint.h"
43 #include "Cv.h"
44 #include "reallocarray.h"
45 
46 #ifndef XCMSCOMPPROC
47 #  define XCMSCOMPPROC	XcmsTekHVCClipC
48 #endif
49 
50 /* forward/static */
51 static void _XcmsFreeDefaultCCCs(Display *dpy);
52 
53 
54 /************************************************************************
55  *									*
56  *			   API PRIVATE ROUTINES				*
57  *									*
58  ************************************************************************/
59 
60 /*
61  *	NAME
62  *		_XcmsCopyPointerArray
63  *
64  *	SYNOPSIS
65  */
66 XPointer *
_XcmsCopyPointerArray(XPointer * pap)67 _XcmsCopyPointerArray(
68     XPointer *pap)
69 /*
70  *	DESCRIPTION
71  *		Copies an array of NULL terminated pointers.
72  *
73  *	RETURNS
74  *		Returns NULL if failed; otherwise the address to
75  *		the copy.
76  *
77  */
78 {
79     XPointer *newArray;
80     char **tmp;
81     int n;
82 
83     for (tmp = pap, n = 0; *tmp != NULL; tmp++, n++);
84     n++; /* add 1 to include the NULL pointer */
85 
86     if ((newArray = Xmallocarray(n, sizeof(XPointer)))) {
87 	memcpy((char *)newArray, (char *)pap,
88 	       (unsigned)(n * sizeof(XPointer)));
89     }
90     return((XPointer *)newArray);
91 }
92 
93 /*
94  *	NAME
95  *		_XcmsFreePointerArray
96  *
97  *	SYNOPSIS
98  */
99 void
_XcmsFreePointerArray(XPointer * pap)100 _XcmsFreePointerArray(
101     XPointer *pap)
102 /*
103  *	DESCRIPTION
104  *		Frees an array of NULL terminated pointers.
105  *
106  *	RETURNS
107  *		void
108  *
109  */
110 {
111     Xfree(pap);
112 }
113 
114 /*
115  *	NAME
116  *		_XcmsPushPointerArray
117  *
118  *	SYNOPSIS
119  */
120 XPointer *
_XcmsPushPointerArray(XPointer * pap,XPointer p,XPointer * papNoFree)121 _XcmsPushPointerArray(
122     XPointer *pap,
123     XPointer p,
124     XPointer *papNoFree)
125 /*
126  *	DESCRIPTION
127  *		Places the specified pointer at the head of an array of NULL
128  *		terminated pointers.
129  *
130  *	RETURNS
131  *		Returns NULL if failed; otherwise the address to
132  *		the head of the array.
133  *
134  */
135 {
136     XPointer *newArray;
137     char **tmp;
138     int n;
139 
140     for (tmp = pap, n = 0; *tmp != NULL; tmp++, n++);
141 
142     /* add 2: 1 for the new pointer and another for the NULL pointer */
143     n += 2;
144 
145     if ((newArray = Xmallocarray(n, sizeof(XPointer)))) {
146 	memcpy((char *)(newArray+1),(char *)pap,
147 	       (unsigned)((n-1) * sizeof(XPointer)));
148 	*newArray = p;
149     }
150     if (pap != papNoFree) {
151         _XcmsFreePointerArray(pap);
152     }
153     return((XPointer *)newArray);
154 }
155 
156 /*
157  *	NAME
158  *		_XcmsInitDefaultCCCs
159  *
160  *	SYNOPSIS
161  */
162 int
_XcmsInitDefaultCCCs(Display * dpy)163 _XcmsInitDefaultCCCs(
164     Display *dpy)
165 /*
166  *	DESCRIPTION
167  *		Initializes the Xcms per Display Info structure
168  *		(XcmsPerDpyInfo).
169  *
170  *	RETURNS
171  *		Returns 0 if failed; otherwise non-zero.
172  *
173  */
174 {
175     int nScrn = ScreenCount(dpy);
176     int i;
177     XcmsCCC ccc;
178 
179     if (nScrn <= 0) {
180 	return(0);
181     }
182 
183     /*
184      * Create an array of XcmsCCC structures, one for each screen.
185      * They serve as the screen's default CCC.
186      */
187     if (!(ccc = Xcalloc((unsigned)nScrn, sizeof(XcmsCCCRec)))) {
188 	return(0);
189     }
190     dpy->cms.defaultCCCs = (XPointer)ccc;
191     dpy->free_funcs->defaultCCCs = _XcmsFreeDefaultCCCs;
192 
193     for (i = 0; i < nScrn; i++, ccc++) {
194 	ccc->dpy = dpy;
195 	ccc->screenNumber = i;
196 	ccc->visual = DefaultVisual(dpy, i);
197 	/*
198 	 * Used calloc to allocate memory so:
199 	 *	ccc->clientWhitePt->format == XcmsUndefinedFormat
200 	 *	ccc->gamutCompProc == NULL
201 	 *	ccc->whitePtAdjProc == NULL
202 	 *	ccc->pPerScrnInfo = NULL
203 	 *
204 	 * Don't need to create XcmsPerScrnInfo and its functionSet and
205 	 * pScreenData components until the default CCC is accessed.
206 	 * Note that the XcmsDefaultCCC routine calls _XcmsInitScrnInto
207 	 * to do this.
208 	 */
209 	ccc->gamutCompProc = XCMSCOMPPROC;
210     }
211 
212     return(1);
213 }
214 
215 
216 /*
217  *	NAME
218  *		_XcmsFreeDefaultCCCs - Free Default CCCs and its PerScrnInfo
219  *
220  *	SYNOPSIS
221  */
222 static void
_XcmsFreeDefaultCCCs(Display * dpy)223 _XcmsFreeDefaultCCCs(
224     Display *dpy)
225 /*
226  *	DESCRIPTION
227  *		This routine frees the default XcmsCCC's associated with
228  *		each screen and its associated substructures as necessary.
229  *
230  *	RETURNS
231  *		void
232  *
233  *
234  */
235 {
236     int nScrn = ScreenCount(dpy);
237     XcmsCCC ccc;
238     int i;
239 
240     /*
241      * Free Screen data in each DefaultCCC
242      *		Do not use XcmsFreeCCC here because it will not free
243      *		DefaultCCC's.
244      */
245     ccc = (XcmsCCC)dpy->cms.defaultCCCs;
246     for (i = nScrn; i--; ccc++) {
247 	/*
248 	 * Check if XcmsPerScrnInfo exists.
249 	 *
250 	 * This is the only place where XcmsPerScrnInfo structures
251 	 * are freed since there is only one allocated per Screen.
252 	 * It just so happens that we place its reference in the
253 	 * default CCC.
254 	 */
255 	if (ccc->pPerScrnInfo) {
256 	    /* Check if SCCData exists */
257 	    if (ccc->pPerScrnInfo->state != XcmsInitNone
258 		    && ccc->pPerScrnInfo->screenData) {
259 		(*((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->screenFreeProc)
260 			(ccc->pPerScrnInfo->screenData);
261 	    }
262 	    Xfree(ccc->pPerScrnInfo);
263 	}
264     }
265 
266     /*
267      * Free the array of XcmsCCC structures
268      */
269     Xfree(dpy->cms.defaultCCCs);
270     dpy->cms.defaultCCCs = (XPointer)NULL;
271 }
272 
273 
274 
275 /*
276  *	NAME
277  *		_XcmsInitScrnInfo
278  *
279  *	SYNOPSIS
280  */
281 int
_XcmsInitScrnInfo(register Display * dpy,int screenNumber)282 _XcmsInitScrnInfo(
283     register Display *dpy,
284     int screenNumber)
285 /*
286  *	DESCRIPTION
287  *		Given a display and screen number, this routine attempts
288  *		to initialize the Xcms per Screen Info structure
289  *		(XcmsPerScrnInfo).
290  *
291  *	RETURNS
292  *		Returns zero if initialization failed; non-zero otherwise.
293  */
294 {
295     XcmsFunctionSet **papSCCFuncSet = _XcmsSCCFuncSets;
296     XcmsCCC defaultccc;
297 
298     /*
299      * Check if the XcmsCCC's for each screen has been created.
300      * Really don't need to be created until some routine uses the Xcms
301      * API routines.
302      */
303     if ((XcmsCCC)dpy->cms.defaultCCCs == NULL) {
304 	if (!_XcmsInitDefaultCCCs(dpy)) {
305 	    return(0);
306 	}
307     }
308 
309     defaultccc = (XcmsCCC)dpy->cms.defaultCCCs + screenNumber;
310 
311     /*
312      * For each SCCFuncSet, try its pInitScrnFunc.
313      *	If the function succeeds, then we got it!
314      */
315 
316     if (!defaultccc->pPerScrnInfo) {
317 	/*
318 	 * This is one of two places where XcmsPerScrnInfo structures
319 	 * are allocated.  There is one allocated per Screen that is
320 	 * shared among visuals that do not have specific intensity
321 	 * tables.  Other XcmsPerScrnInfo structures are created
322 	 * for the latter (see XcmsCreateCCC).  The ones created
323 	 * here are referenced by the default CCC.
324 	 */
325 	if (!(defaultccc->pPerScrnInfo =
326 		Xcalloc(1, sizeof(XcmsPerScrnInfo)))) {
327 	    return(0);
328 	}
329 	defaultccc->pPerScrnInfo->state = XcmsInitNone;
330     }
331 
332     while (*papSCCFuncSet != NULL) {
333 	if ((*(*papSCCFuncSet)->screenInitProc)(dpy, screenNumber,
334 		defaultccc->pPerScrnInfo)) {
335 	    defaultccc->pPerScrnInfo->state = XcmsInitSuccess;
336 	    return(1);
337 	}
338 	papSCCFuncSet++;
339     }
340 
341     /*
342      * Use Default SCCData
343      */
344     return(_XcmsLRGB_InitScrnDefault(dpy, screenNumber, defaultccc->pPerScrnInfo));
345 }
346 
347 
348 /*
349  *	NAME
350  *		_XcmsFreeIntensityMaps
351  *
352  *	SYNOPSIS
353  */
354 void
_XcmsFreeIntensityMaps(Display * dpy)355 _XcmsFreeIntensityMaps(
356     Display *dpy)
357 /*
358  *	DESCRIPTION
359  *		Frees all XcmsIntensityMap structures in the linked list
360  *		and sets dpy->cms.perVisualIntensityMaps to NULL.
361  *
362  *	RETURNS
363  *		void
364  *
365  */
366 {
367     XcmsIntensityMap *pNext, *pFree;
368 
369     pNext = (XcmsIntensityMap *)dpy->cms.perVisualIntensityMaps;
370     while (pNext != NULL) {
371 	pFree = pNext;
372 	pNext = pNext->pNext;
373 	(*pFree->pFreeScreenData)(pFree->screenData);
374 	/* Now free the XcmsIntensityMap structure */
375 	Xfree(pFree);
376     }
377     dpy->cms.perVisualIntensityMaps = (XPointer)NULL;
378 }
379 
380 
381 /*
382  *	NAME
383  *		_XcmsGetIntensityMap
384  *
385  *	SYNOPSIS
386  */
387 XcmsIntensityMap *
_XcmsGetIntensityMap(Display * dpy,Visual * visual)388 _XcmsGetIntensityMap(
389     Display *dpy,
390     Visual *visual)
391 /*
392  *	DESCRIPTION
393  *		Attempts to return a per-Visual intensity map.
394  *
395  *	RETURNS
396  *		Pointer to the XcmsIntensityMap structure if found;
397  *		otherwise NULL
398  *
399  */
400 {
401     VisualID targetID = visual->visualid;
402     XcmsIntensityMap *pNext;
403 
404     pNext = (XcmsIntensityMap *)dpy->cms.perVisualIntensityMaps;
405     while (pNext != NULL) {
406 	if (targetID == pNext->visualID) {
407 	    return(pNext);
408 	}
409 	pNext = pNext->pNext;
410     }
411     return((XcmsIntensityMap *)NULL);
412 }
413