CrCmap.c revision 6c321187
1/* $Xorg: CrCmap.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
2
3/*
4
5Copyright 1989, 1998  The Open Group
6
7Permission to use, copy, modify, distribute, and sell this software and its
8documentation for any purpose is hereby granted without fee, provided that
9the above copyright notice appear in all copies and that both that
10copyright notice and this permission notice appear in supporting
11documentation.
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from The Open Group.
26
27*/
28/* $XFree86: xc/lib/Xmu/CrCmap.c,v 3.6 2001/01/17 19:42:53 dawes Exp $ */
29
30/*
31 * Author:  Donna Converse, MIT X Consortium
32 */
33
34/*
35 * CreateCmap.c - given a standard colormap description, make the map.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include <config.h>
40#endif
41#include <stdio.h>
42#include <stdlib.h>
43#include <X11/Xlib.h>
44#include <X11/Xutil.h>
45#include <X11/Xmu/StdCmap.h>
46
47/*
48 * Prototypes
49 */
50/* allocate entire map Read Only */
51static int ROmap(Display*, Colormap, unsigned long[], int, int);
52
53/* allocate a cell, prefer Read Only */
54static Status ROorRWcell(Display*, Colormap, unsigned long[], int,
55			 XColor*, unsigned long);
56
57/* allocate a cell Read Write */
58static Status RWcell(Display*, Colormap, XColor*, XColor*, unsigned long*);
59
60/* for quicksort */
61static int compare(_Xconst void*, _Xconst void*);
62
63/* find contiguous sequence of cells */
64static Status contiguous(unsigned long[], int, int, unsigned long, int*, int*);
65
66/* frees resources before quitting */
67static void free_cells(Display*, Colormap, unsigned long[], int, int);
68
69/* create a map in a RO visual type */
70static Status readonly_map(Display*, XVisualInfo*, XStandardColormap*);
71
72/* create a map in a RW visual type */
73static Status readwrite_map(Display*, XVisualInfo*, XStandardColormap*);
74
75#define lowbit(x) ((x) & (~(x) + 1))
76#define TRUEMATCH(mult,max,mask) \
77    (colormap->max * colormap->mult <= vinfo->mask && \
78     lowbit(vinfo->mask) == colormap->mult)
79
80/*
81 * To create any one colormap which is described by an XStandardColormap
82 * structure, use XmuCreateColormap().
83 *
84 * Return 0 on failure, non-zero on success.
85 * Resources created by this function are not made permanent.
86 * No argument error checking is provided.  Use at your own risk.
87 *
88 * All colormaps are created with read only allocations, with the exception
89 * of read only allocations of colors in the default map or otherwise
90 * which fail to return the expected pixel value, and these are individually
91 * defined as read/write allocations.  This is done so that all the cells
92 * defined in the default map are contiguous, for use in image processing.
93 * This typically happens with White and Black in the default map.
94 *
95 * Colormaps of static visuals are considered to be successfully created if
96 * the map of the static visual matches the definition given in the
97 * standard colormap structure.
98 */
99
100Status
101XmuCreateColormap(Display *dpy, XStandardColormap *colormap)
102     /* dpy	 - specifies the connection under which the map is created
103      * colormap - specifies the map to be created, and returns, particularly
104      *		   if the map is created as a subset of the default colormap
105      *		   of the screen, the base_pixel of the map.
106					 */
107{
108    XVisualInfo		vinfo_template;	/* template visual information */
109    XVisualInfo		*vinfo;		/* matching visual information */
110    XVisualInfo		*vpointer;	/* for freeing the entire list */
111    long		vinfo_mask;	/* specifies the visual mask value */
112    int 		n;		/* number of matching visuals */
113    int			status;
114
115    vinfo_template.visualid = colormap->visualid;
116    vinfo_mask = VisualIDMask;
117    if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
118	return 0;
119
120    /* A visual id may be valid on multiple screens.  Also, there may
121     * be multiple visuals with identical visual ids at different depths.
122     * If the colormap is the Default Colormap, use the Default Visual.
123     * Otherwise, arbitrarily, use the deepest visual.
124     */
125    vpointer = vinfo;
126    if (n > 1)
127    {
128	register int	i;
129	register int	screen_number;
130	Bool 		def_cmap;
131
132	def_cmap = False;
133	for (screen_number = ScreenCount(dpy); --screen_number >= 0; )
134	    if (colormap->colormap == DefaultColormap(dpy, screen_number)) {
135		def_cmap = True;
136		break;
137	    }
138
139	if (def_cmap) {
140	    for (i=0; i < n; i++, vinfo++) {
141		if (vinfo->visual == DefaultVisual(dpy, screen_number))
142			break;
143	    }
144	} else {
145	    int			maxdepth = 0;
146	    XVisualInfo		*v = NULL;
147
148	    for (i=0; i < n; i++, vinfo++)
149		if (vinfo->depth > maxdepth) {
150		    maxdepth = vinfo->depth;
151		    v = vinfo;
152		}
153	    vinfo = v;
154	}
155    }
156
157    if (vinfo->class == PseudoColor || vinfo->class == DirectColor ||
158	vinfo->class == GrayScale)
159	status = readwrite_map(dpy, vinfo, colormap);
160    else if (vinfo->class == TrueColor)
161	status = TRUEMATCH(red_mult, red_max, red_mask) &&
162	         TRUEMATCH(green_mult, green_max, green_mask) &&
163		 TRUEMATCH(blue_mult, blue_max, blue_mask);
164    else
165	status = readonly_map(dpy, vinfo, colormap);
166
167    XFree((char *) vpointer);
168    return status;
169}
170
171/****************************************************************************/
172static Status
173readwrite_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
174{
175    register unsigned long i, n;	/* index counters */
176    unsigned long	ncolors;	/* number of colors to be defined */
177    int			npixels;	/* number of pixels allocated R/W */
178    int			first_index;	/* first index of pixels to use */
179    int			remainder;	/* first index of remainder */
180    XColor		color;		/* the definition of a color */
181    unsigned long	*pixels;	/* array of colormap pixels */
182    unsigned long	delta;
183
184
185    /* Determine ncolors, the number of colors to be defined.
186     * Insure that 1 < ncolors <= the colormap size.
187     */
188    if (vinfo->class == DirectColor) {
189	ncolors = colormap->red_max;
190	if (colormap->green_max > ncolors)
191	    ncolors = colormap->green_max;
192	if (colormap->blue_max > ncolors)
193	    ncolors = colormap->blue_max;
194	ncolors++;
195	delta = lowbit(vinfo->red_mask) +
196	        lowbit(vinfo->green_mask) +
197		lowbit(vinfo->blue_mask);
198    } else {
199	ncolors = colormap->red_max * colormap->red_mult +
200		  colormap->green_max * colormap->green_mult +
201		  colormap->blue_max * colormap->blue_mult + 1;
202	delta = 1;
203    }
204    if (ncolors <= 1 || (int) ncolors > vinfo->colormap_size)	return 0;
205
206    /* Allocate Read/Write as much of the colormap as we can possibly get.
207     * Then insure that the pixels we were allocated are given in
208     * monotonically increasing order, using a quicksort.  Next, insure
209     * that our allocation includes a subset of contiguous pixels at least
210     * as long as the number of colors to be defined.  Now we know that
211     * these conditions are met:
212     *	1) There are no free cells in the colormap.
213     *  2) We have a contiguous sequence of pixels, monotonically
214     *     increasing, of length >= the number of colors requested.
215     *
216     * One cell at a time, we will free, compute the next color value,
217     * then allocate read only.  This takes a long time.
218     * This is done to insure that cells are allocated read only in the
219     * contiguous order which we prefer.  If the server has a choice of
220     * cells to grant to an allocation request, the server may give us any
221     * cell, so that is why we do these slow gymnastics.
222     */
223
224    if ((pixels = (unsigned long *) calloc((unsigned) vinfo->colormap_size,
225				      sizeof(unsigned long))) == NULL)
226	return 0;
227
228    if ((npixels = ROmap(dpy, colormap->colormap, pixels,
229			   vinfo->colormap_size, ncolors)) == 0) {
230	free((char *) pixels);
231	return 0;
232    }
233
234    qsort((char *) pixels, npixels, sizeof(unsigned long), compare);
235
236    if (!contiguous(pixels, npixels, ncolors, delta, &first_index, &remainder))
237    {
238	/* can't find enough contiguous cells, give up */
239	XFreeColors(dpy, colormap->colormap, pixels, npixels,
240		    (unsigned long) 0);
241	free((char *) pixels);
242	return 0;
243    }
244    colormap->base_pixel = pixels[first_index];
245
246    /* construct a gray map */
247    if (colormap->red_mult == 1 && colormap->green_mult == 1 &&
248	colormap->blue_mult == 1)
249	for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
250	{
251	    color.pixel = n;
252	    color.blue = color.green = color.red =
253		(unsigned short) ((i * 65535) / (colormap->red_max +
254						 colormap->green_max +
255						 colormap->blue_max));
256
257	    if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
258			     first_index + i))
259		return 0;
260	}
261
262    /* construct a red ramp map */
263    else if (colormap->green_max == 0 && colormap->blue_max == 0)
264    	for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
265	{
266	    color.pixel = n;
267	    color.red = (unsigned short) ((i * 65535) / colormap->red_max);
268	    color.green = color.blue = 0;
269
270	    if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
271			     first_index + i))
272		return 0;
273	}
274
275    /* construct a green ramp map */
276    else if (colormap->red_max == 0 && colormap->blue_max == 0)
277    	for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
278	{
279	    color.pixel = n;
280	    color.green = (unsigned short) ((i * 65535) / colormap->green_max);
281	    color.red = color.blue = 0;
282
283	    if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
284			     first_index + i))
285		return 0;
286	}
287
288    /* construct a blue ramp map */
289    else if (colormap->red_max == 0 && colormap->green_max == 0)
290    	for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
291	{
292	    color.pixel = n;
293	    color.blue = (unsigned short) ((i * 65535) / colormap->blue_max);
294	    color.red = color.green = 0;
295
296	    if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
297			     first_index + i))
298		return 0;
299	}
300
301    /* construct a standard red green blue cube map */
302    else
303    {
304#define calc(max,mult) (((n / colormap->mult) % \
305			 (colormap->max + 1)) * 65535) / colormap->max
306
307    	for (n=0, i=0; i < ncolors; i++, n += delta)
308	{
309	    color.pixel = n + colormap->base_pixel;
310	    color.red = calc(red_max, red_mult);
311	    color.green = calc(green_max, green_mult);
312	    color.blue = calc(blue_max, blue_mult);
313	    if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
314			     first_index + i))
315		return 0;
316	}
317#undef calc
318    }
319    /* We have a read-only map defined.  Now free unused cells,
320     * first those occuring before the contiguous sequence begins,
321     * then any following the contiguous sequence.
322     */
323
324    if (first_index)
325	XFreeColors(dpy, colormap->colormap, pixels, first_index,
326		    (unsigned long) 0);
327    if (remainder)
328	XFreeColors(dpy, colormap->colormap,
329		    &(pixels[first_index + ncolors]), remainder,
330		    (unsigned long) 0);
331
332    free((char *) pixels);
333    return 1;
334}
335
336
337/****************************************************************************/
338static int
339ROmap(Display *dpy, Colormap cmap, unsigned long pixels[], int m, int n)
340     /*
341      * dpy	- the X server connection
342      * cmap	- specifies colormap ID
343      * pixels	- returns pixel allocations
344      * m	- specifies colormap size
345      * n	- specifies number of colors
346      */
347{
348    register int	p;
349
350    /* first try to allocate the entire colormap */
351    if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
352			 (unsigned) 0, pixels, (unsigned) m))
353	return m;
354
355    /* Allocate all available cells in the colormap, using a binary
356     * algorithm to discover how many cells we can allocate in the colormap.
357     */
358    m--;
359    while (n <= m) {
360	p = n + ((m - n + 1) / 2);
361	if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
362			     (unsigned) 0, pixels, (unsigned) p)) {
363	    if (p == m)
364		return p;
365	    else {
366		XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
367		n = p;
368	    }
369	}
370	else
371	    m = p - 1;
372    }
373    return 0;
374}
375
376
377/****************************************************************************/
378static Status
379contiguous(unsigned long pixels[], int npixels, int ncolors,
380	   unsigned long delta, int *first, int *rem)
381     /* pixels	- specifies allocated pixels
382      * npixels	- specifies count of alloc'd pixels
383      * ncolors - specifies needed sequence length
384      * delta	- between pixels
385      * first	- returns first index of sequence
386      * rem	- returns first index after sequence, or 0, if none follow
387      */
388{
389    register int i = 1;		/* walking index into the pixel array */
390    register int count = 1;	/* length of sequence discovered so far */
391
392    *first = 0;
393    if (npixels == ncolors) {
394	*rem = 0;
395	return 1;
396    }
397    *rem = npixels - 1;
398    while (count < ncolors && ncolors - count <= *rem)
399    {
400	if (pixels[i-1] + delta == pixels[i])
401	    count++;
402	else {
403	    count = 1;
404	    *first = i;
405	}
406	i++;
407	(*rem)--;
408    }
409    if (count != ncolors)
410	return 0;
411    return 1;
412}
413
414
415/****************************************************************************/
416static Status
417ROorRWcell(Display *dpy, Colormap cmap, unsigned long pixels[],
418	   int npixels, XColor *color, unsigned long p)
419{
420    unsigned long	pixel;
421    XColor		request;
422
423    /* Free the read/write allocation of one cell in the colormap.
424     * Request a read only allocation of one cell in the colormap.
425     * If the read only allocation cannot be granted, give up, because
426     * there must be no free cells in the colormap.
427     * If the read only allocation is granted, but gives us a cell which
428     * is not the one that we just freed, it is probably the case that
429     * we are trying allocate White or Black or some other color which
430     * already has a read-only allocation in the map.  So we try to
431     * allocate the previously freed cell with a read/write allocation,
432     * because we want contiguous cells for image processing algorithms.
433     */
434
435    pixel = color->pixel;
436    request.red = color->red;
437    request.green = color->green;
438    request.blue = color->blue;
439
440    XFreeColors(dpy, cmap, &pixel, 1, (unsigned long) 0);
441    if (! XAllocColor(dpy, cmap, color)
442	|| (color->pixel != pixel &&
443	    (!RWcell(dpy, cmap, color, &request, &pixel))))
444    {
445	free_cells(dpy, cmap, pixels, npixels, (int)p);
446	return 0;
447    }
448    return 1;
449}
450
451
452/****************************************************************************/
453static void
454free_cells(Display *dpy, Colormap cmap, unsigned long pixels[],
455	   int npixels, int p)
456     /*
457      * pixels	- to be freed
458      *	npixels	- original number allocated
459      */
460{
461    /* One of the npixels allocated has already been freed.
462     * p is the index of the freed pixel.
463     * First free the pixels preceeding p, and there are p of them;
464     * then free the pixels following p, there are npixels - p - 1 of them.
465     */
466    XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
467    XFreeColors(dpy, cmap, &(pixels[p+1]), npixels - p - 1, (unsigned long) 0);
468    free((char *) pixels);
469}
470
471
472/****************************************************************************/
473static Status
474RWcell(Display *dpy, Colormap cmap, XColor *color, XColor *request,
475       unsigned long *pixel)
476{
477    unsigned long	n = *pixel;
478
479    XFreeColors(dpy, cmap, &(color->pixel), 1, (unsigned long)0);
480    if (! XAllocColorCells(dpy, cmap, (Bool) 0, (unsigned long *) NULL,
481			   (unsigned) 0, pixel, (unsigned) 1))
482	return 0;
483    if (*pixel != n)
484    {
485	XFreeColors(dpy, cmap, pixel, 1, (unsigned long) 0);
486	return 0;
487    }
488    color->pixel = *pixel;
489    color->flags = DoRed | DoGreen | DoBlue;
490    color->red = request->red;
491    color->green = request->green;
492    color->blue = request->blue;
493    XStoreColors(dpy, cmap, color, 1);
494    return 1;
495}
496
497
498/****************************************************************************/
499static int
500compare(_Xconst void *e1, _Xconst void *e2)
501{
502  return ((int)(*(long *)e1 - *(long *)e2));
503}
504
505
506/****************************************************************************/
507static Status
508readonly_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
509{
510    int			i, last_pixel;
511    XColor		color;
512
513    last_pixel = (colormap->red_max + 1) * (colormap->green_max + 1) *
514	(colormap->blue_max + 1) + colormap->base_pixel - 1;
515
516    for(i=colormap->base_pixel; i <= last_pixel; i++) {
517
518	color.pixel = (unsigned long) i;
519	color.red = (unsigned short)
520	    (((i/colormap->red_mult) * 65535) / colormap->red_max);
521
522	if (vinfo->class == StaticColor) {
523	    color.green = (unsigned short)
524		((((i/colormap->green_mult) % (colormap->green_max + 1)) *
525		  65535) / colormap->green_max);
526	    color.blue = (unsigned short)
527		(((i%colormap->green_mult) * 65535) / colormap->blue_max);
528	}
529	else	/* vinfo->class == GrayScale, old style allocation XXX */
530	    color.green = color.blue = color.red;
531
532	XAllocColor(dpy, colormap->colormap, &color);
533	if (color.pixel != (unsigned long) i)
534	    return 0;
535    }
536    return 1;
537}
538