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