1/*********************************************************** 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25 26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46******************************************************************/ 47 48 49#ifdef HAVE_DIX_CONFIG_H 50#include <dix-config.h> 51#endif 52 53#include <X11/X.h> 54#include <X11/Xproto.h> 55#include <stdio.h> 56#include <string.h> 57#include <strings.h> 58#include "misc.h" 59#include "dix.h" 60#include "dixstruct.h" 61#include "colormapst.h" 62#include "os.h" 63#include "scrnintstr.h" 64#include "resource.h" 65#include "windowstr.h" 66#include "privates.h" 67#include "xace.h" 68 69static Pixel FindBestPixel( 70 EntryPtr /*pentFirst*/, 71 int /*size*/, 72 xrgb * /*prgb*/, 73 int /*channel*/ 74); 75 76static int AllComp( 77 EntryPtr /*pent*/, 78 xrgb * /*prgb*/ 79); 80 81static int RedComp( 82 EntryPtr /*pent*/, 83 xrgb * /*prgb*/ 84); 85 86static int GreenComp( 87 EntryPtr /*pent*/, 88 xrgb * /*prgb*/ 89); 90 91static int BlueComp( 92 EntryPtr /*pent*/, 93 xrgb * /*prgb*/ 94); 95 96static void FreePixels( 97 ColormapPtr /*pmap*/, 98 int /*client*/ 99); 100 101static void CopyFree( 102 int /*channel*/, 103 int /*client*/, 104 ColormapPtr /*pmapSrc*/, 105 ColormapPtr /*pmapDst*/ 106); 107 108static void FreeCell( 109 ColormapPtr /*pmap*/, 110 Pixel /*i*/, 111 int /*channel*/ 112); 113 114static void UpdateColors( 115 ColormapPtr /*pmap*/ 116); 117 118static int AllocDirect( 119 int /*client*/, 120 ColormapPtr /*pmap*/, 121 int /*c*/, 122 int /*r*/, 123 int /*g*/, 124 int /*b*/, 125 Bool /*contig*/, 126 Pixel * /*pixels*/, 127 Pixel * /*prmask*/, 128 Pixel * /*pgmask*/, 129 Pixel * /*pbmask*/ 130); 131 132static int AllocPseudo( 133 int /*client*/, 134 ColormapPtr /*pmap*/, 135 int /*c*/, 136 int /*r*/, 137 Bool /*contig*/, 138 Pixel * /*pixels*/, 139 Pixel * /*pmask*/, 140 Pixel ** /*pppixFirst*/ 141); 142 143static Bool AllocCP( 144 ColormapPtr /*pmap*/, 145 EntryPtr /*pentFirst*/, 146 int /*count*/, 147 int /*planes*/, 148 Bool /*contig*/, 149 Pixel * /*pixels*/, 150 Pixel * /*pMask*/ 151); 152 153static Bool AllocShared( 154 ColormapPtr /*pmap*/, 155 Pixel * /*ppix*/, 156 int /*c*/, 157 int /*r*/, 158 int /*g*/, 159 int /*b*/, 160 Pixel /*rmask*/, 161 Pixel /*gmask*/, 162 Pixel /*bmask*/, 163 Pixel * /*ppixFirst*/ 164); 165 166static int FreeCo( 167 ColormapPtr /*pmap*/, 168 int /*client*/, 169 int /*color*/, 170 int /*npixIn*/, 171 Pixel * /*ppixIn*/, 172 Pixel /*mask*/ 173); 174 175static int TellNoMap( 176 WindowPtr /*pwin*/, 177 Colormap * /*pmid*/ 178); 179 180static void FindColorInRootCmap ( 181 ColormapPtr /* pmap */, 182 EntryPtr /* pentFirst */, 183 int /* size */, 184 xrgb* /* prgb */, 185 Pixel* /* pPixel */, 186 int /* channel */, 187 ColorCompareProcPtr /* comp */ 188); 189 190#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1) 191#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1) 192#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1) 193#if COMPOSITE 194#define ALPHAMASK(vis) ((vis)->nplanes < 32 ? 0 : \ 195 (CARD32) ~((vis)->redMask|(vis)->greenMask|(vis)->blueMask)) 196#else 197#define ALPHAMASK(vis) 0 198#endif 199 200#define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask | ALPHAMASK(vis)) 201 202/* GetNextBitsOrBreak(bits, mask, base) -- 203 * (Suggestion: First read the macro, then read this explanation. 204 * 205 * Either generate the next value to OR in to a pixel or break out of this 206 * while loop 207 * 208 * This macro is used when we're trying to generate all 2^n combinations of 209 * bits in mask. What we're doing here is counting in binary, except that 210 * the bits we use to count may not be contiguous. This macro will be 211 * called 2^n times, returning a different value in bits each time. Then 212 * it will cause us to break out of a surrounding loop. (It will always be 213 * called from within a while loop.) 214 * On call: mask is the value we want to find all the combinations for 215 * base has 1 bit set where the least significant bit of mask is set 216 * 217 * For example,if mask is 01010, base should be 0010 and we count like this: 218 * 00010 (see this isn't so hard), 219 * then we add base to bits and get 0100. (bits & ~mask) is (0100 & 0100) so 220 * we add that to bits getting (0100 + 0100) = 221 * 01000 for our next value. 222 * then we add 0010 to get 223 * 01010 and we're done (easy as 1, 2, 3) 224 */ 225#define GetNextBitsOrBreak(bits, mask, base) \ 226 if((bits) == (mask)) \ 227 break; \ 228 (bits) += (base); \ 229 while((bits) & ~(mask)) \ 230 (bits) += ((bits) & ~(mask)); 231/* ID of server as client */ 232#define SERVER_ID 0 233 234typedef struct _colorResource 235{ 236 Colormap mid; 237 int client; 238} colorResource; 239 240/* Invariants: 241 * refcnt == 0 means entry is empty 242 * refcnt > 0 means entry is useable by many clients, so it can't be changed 243 * refcnt == AllocPrivate means entry owned by one client only 244 * fShared should only be set if refcnt == AllocPrivate, and only in red map 245 */ 246 247 248/** 249 * Create and initialize the color map 250 * 251 * \param mid resource to use for this colormap 252 * \param alloc 1 iff all entries are allocated writable 253 */ 254int 255CreateColormap (Colormap mid, ScreenPtr pScreen, VisualPtr pVisual, 256 ColormapPtr *ppcmap, int alloc, int client) 257{ 258 int class, size; 259 unsigned long sizebytes; 260 ColormapPtr pmap; 261 EntryPtr pent; 262 int i; 263 Pixel *ppix, **pptr; 264 265 class = pVisual->class; 266 if(!(class & DynamicClass) && (alloc != AllocNone) && (client != SERVER_ID)) 267 return BadMatch; 268 269 size = pVisual->ColormapEntries; 270 sizebytes = (size * sizeof(Entry)) + 271 (MAXCLIENTS * sizeof(Pixel *)) + 272 (MAXCLIENTS * sizeof(int)); 273 if ((class | DynamicClass) == DirectColor) 274 sizebytes *= 3; 275 sizebytes += sizeof(ColormapRec); 276 if (mid == pScreen->defColormap) { 277 pmap = malloc(sizebytes); 278 if (!pmap) 279 return BadAlloc; 280 if (!dixAllocatePrivates(&pmap->devPrivates, PRIVATE_COLORMAP)) { 281 free (pmap); 282 return BadAlloc; 283 } 284 } else { 285 pmap = _dixAllocateObjectWithPrivates(sizebytes, sizebytes, 286 offsetof(ColormapRec, devPrivates), PRIVATE_COLORMAP); 287 if (!pmap) 288 return BadAlloc; 289 } 290#if defined(_XSERVER64) 291 pmap->pad0 = 0; 292 pmap->pad1 = 0; 293#if (X_BYTE_ORDER == X_LITTLE_ENDIAN) 294 pmap->pad2 = 0; 295#endif 296#endif 297 pmap->red = (EntryPtr)((char *)pmap + sizeof(ColormapRec)); 298 sizebytes = size * sizeof(Entry); 299 pmap->clientPixelsRed = (Pixel **)((char *)pmap->red + sizebytes); 300 pmap->numPixelsRed = (int *)((char *)pmap->clientPixelsRed + 301 (MAXCLIENTS * sizeof(Pixel *))); 302 pmap->mid = mid; 303 pmap->flags = 0; /* start out with all flags clear */ 304 if(mid == pScreen->defColormap) 305 pmap->flags |= IsDefault; 306 pmap->pScreen = pScreen; 307 pmap->pVisual = pVisual; 308 pmap->class = class; 309 if ((class | DynamicClass) == DirectColor) 310 size = NUMRED(pVisual); 311 pmap->freeRed = size; 312 memset((char *) pmap->red, 0, (int)sizebytes); 313 memset((char *) pmap->numPixelsRed, 0, MAXCLIENTS * sizeof(int)); 314 for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; --pptr >= pmap->clientPixelsRed; ) 315 *pptr = (Pixel *)NULL; 316 if (alloc == AllocAll) 317 { 318 if (class & DynamicClass) 319 pmap->flags |= AllAllocated; 320 for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--) 321 pent->refcnt = AllocPrivate; 322 pmap->freeRed = 0; 323 ppix = malloc(size * sizeof(Pixel)); 324 if (!ppix) 325 { 326 free(pmap); 327 return BadAlloc; 328 } 329 pmap->clientPixelsRed[client] = ppix; 330 for(i = 0; i < size; i++) 331 ppix[i] = i; 332 pmap->numPixelsRed[client] = size; 333 } 334 335 if ((class | DynamicClass) == DirectColor) 336 { 337 pmap->freeGreen = NUMGREEN(pVisual); 338 pmap->green = (EntryPtr)((char *)pmap->numPixelsRed + 339 (MAXCLIENTS * sizeof(int))); 340 pmap->clientPixelsGreen = (Pixel **)((char *)pmap->green + sizebytes); 341 pmap->numPixelsGreen = (int *)((char *)pmap->clientPixelsGreen + 342 (MAXCLIENTS * sizeof(Pixel *))); 343 pmap->freeBlue = NUMBLUE(pVisual); 344 pmap->blue = (EntryPtr)((char *)pmap->numPixelsGreen + 345 (MAXCLIENTS * sizeof(int))); 346 pmap->clientPixelsBlue = (Pixel **)((char *)pmap->blue + sizebytes); 347 pmap->numPixelsBlue = (int *)((char *)pmap->clientPixelsBlue + 348 (MAXCLIENTS * sizeof(Pixel *))); 349 350 memset((char *) pmap->green, 0, (int)sizebytes); 351 memset((char *) pmap->blue, 0, (int)sizebytes); 352 353 memmove((char *) pmap->clientPixelsGreen, 354 (char *) pmap->clientPixelsRed, 355 MAXCLIENTS * sizeof(Pixel *)); 356 memmove((char *) pmap->clientPixelsBlue, 357 (char *) pmap->clientPixelsRed, 358 MAXCLIENTS * sizeof(Pixel *)); 359 memset((char *) pmap->numPixelsGreen, 0, MAXCLIENTS * sizeof(int)); 360 memset((char *) pmap->numPixelsBlue, 0, MAXCLIENTS * sizeof(int)); 361 362 /* If every cell is allocated, mark its refcnt */ 363 if (alloc == AllocAll) 364 { 365 size = pmap->freeGreen; 366 for(pent = &pmap->green[size-1]; pent >= pmap->green; pent--) 367 pent->refcnt = AllocPrivate; 368 pmap->freeGreen = 0; 369 ppix = malloc(size * sizeof(Pixel)); 370 if (!ppix) 371 { 372 free(pmap->clientPixelsRed[client]); 373 free(pmap); 374 return BadAlloc; 375 } 376 pmap->clientPixelsGreen[client] = ppix; 377 for(i = 0; i < size; i++) 378 ppix[i] = i; 379 pmap->numPixelsGreen[client] = size; 380 381 size = pmap->freeBlue; 382 for(pent = &pmap->blue[size-1]; pent >= pmap->blue; pent--) 383 pent->refcnt = AllocPrivate; 384 pmap->freeBlue = 0; 385 ppix = malloc(size * sizeof(Pixel)); 386 if (!ppix) 387 { 388 free(pmap->clientPixelsGreen[client]); 389 free(pmap->clientPixelsRed[client]); 390 free(pmap); 391 return BadAlloc; 392 } 393 pmap->clientPixelsBlue[client] = ppix; 394 for(i = 0; i < size; i++) 395 ppix[i] = i; 396 pmap->numPixelsBlue[client] = size; 397 } 398 } 399 pmap->flags |= BeingCreated; 400 401 if (!AddResource(mid, RT_COLORMAP, (pointer)pmap)) 402 return BadAlloc; 403 404 /* 405 * Security creation/labeling check 406 */ 407 i = XaceHook(XACE_RESOURCE_ACCESS, clients[client], mid, RT_COLORMAP, 408 pmap, RT_NONE, NULL, DixCreateAccess); 409 if (i != Success) { 410 FreeResource(mid, RT_NONE); 411 return i; 412 } 413 414 /* If the device wants a chance to initialize the colormap in any way, 415 * this is it. In specific, if this is a Static colormap, this is the 416 * time to fill in the colormap's values */ 417 if (!(*pScreen->CreateColormap)(pmap)) 418 { 419 FreeResource (mid, RT_NONE); 420 return BadAlloc; 421 } 422 pmap->flags &= ~BeingCreated; 423 *ppcmap = pmap; 424 return Success; 425} 426 427/** 428 * 429 * \param value must conform to DeleteType 430 */ 431int 432FreeColormap (pointer value, XID mid) 433{ 434 int i; 435 EntryPtr pent; 436 ColormapPtr pmap = (ColormapPtr)value; 437 438 if(CLIENT_ID(mid) != SERVER_ID) 439 { 440 (*pmap->pScreen->UninstallColormap) (pmap); 441 WalkTree(pmap->pScreen, (VisitWindowProcPtr)TellNoMap, (pointer) &mid); 442 } 443 444 /* This is the device's chance to undo anything it needs to, especially 445 * to free any storage it allocated */ 446 (*pmap->pScreen->DestroyColormap)(pmap); 447 448 if(pmap->clientPixelsRed) 449 { 450 for(i = 0; i < MAXCLIENTS; i++) 451 free(pmap->clientPixelsRed[i]); 452 } 453 454 if ((pmap->class == PseudoColor) || (pmap->class == GrayScale)) 455 { 456 for(pent = &pmap->red[pmap->pVisual->ColormapEntries - 1]; 457 pent >= pmap->red; 458 pent--) 459 { 460 if(pent->fShared) 461 { 462 if (--pent->co.shco.red->refcnt == 0) 463 free(pent->co.shco.red); 464 if (--pent->co.shco.green->refcnt == 0) 465 free(pent->co.shco.green); 466 if (--pent->co.shco.blue->refcnt == 0) 467 free(pent->co.shco.blue); 468 } 469 } 470 } 471 if((pmap->class | DynamicClass) == DirectColor) 472 { 473 for(i = 0; i < MAXCLIENTS; i++) 474 { 475 free(pmap->clientPixelsGreen[i]); 476 free(pmap->clientPixelsBlue[i]); 477 } 478 } 479 480 if (pmap->flags & IsDefault) { 481 dixFreePrivates(pmap->devPrivates, PRIVATE_COLORMAP); 482 free(pmap); 483 } else 484 dixFreeObjectWithPrivates(pmap, PRIVATE_COLORMAP); 485 return Success; 486} 487 488/* Tell window that pmid has disappeared */ 489static int 490TellNoMap (WindowPtr pwin, Colormap *pmid) 491{ 492 xEvent xE; 493 494 if (wColormap(pwin) == *pmid) 495 { 496 /* This should be call to DeliverEvent */ 497 xE.u.u.type = ColormapNotify; 498 xE.u.colormap.window = pwin->drawable.id; 499 xE.u.colormap.colormap = None; 500 xE.u.colormap.new = TRUE; 501 xE.u.colormap.state = ColormapUninstalled; 502#ifdef PANORAMIX 503 if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum) 504#endif 505 DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); 506 if (pwin->optional) { 507 pwin->optional->colormap = None; 508 CheckWindowOptionalNeed (pwin); 509 } 510 } 511 512 return WT_WALKCHILDREN; 513} 514 515/* Tell window that pmid got uninstalled */ 516int 517TellLostMap (WindowPtr pwin, pointer value) 518{ 519 Colormap *pmid = (Colormap *)value; 520 xEvent xE; 521 522#ifdef PANORAMIX 523 if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) 524 return WT_STOPWALKING; 525#endif 526 if (wColormap(pwin) == *pmid) 527 { 528 /* This should be call to DeliverEvent */ 529 xE.u.u.type = ColormapNotify; 530 xE.u.colormap.window = pwin->drawable.id; 531 xE.u.colormap.colormap = *pmid; 532 xE.u.colormap.new = FALSE; 533 xE.u.colormap.state = ColormapUninstalled; 534 DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); 535 } 536 537 return WT_WALKCHILDREN; 538} 539 540/* Tell window that pmid got installed */ 541int 542TellGainedMap (WindowPtr pwin, pointer value) 543{ 544 Colormap *pmid = (Colormap *)value; 545 xEvent xE; 546 547#ifdef PANORAMIX 548 if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) 549 return WT_STOPWALKING; 550#endif 551 if (wColormap (pwin) == *pmid) 552 { 553 /* This should be call to DeliverEvent */ 554 xE.u.u.type = ColormapNotify; 555 xE.u.colormap.window = pwin->drawable.id; 556 xE.u.colormap.colormap = *pmid; 557 xE.u.colormap.new = FALSE; 558 xE.u.colormap.state = ColormapInstalled; 559 DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); 560 } 561 562 return WT_WALKCHILDREN; 563} 564 565 566int 567CopyColormapAndFree (Colormap mid, ColormapPtr pSrc, int client) 568{ 569 ColormapPtr pmap = (ColormapPtr) NULL; 570 int result, alloc, size; 571 Colormap midSrc; 572 ScreenPtr pScreen; 573 VisualPtr pVisual; 574 575 pScreen = pSrc->pScreen; 576 pVisual = pSrc->pVisual; 577 midSrc = pSrc->mid; 578 alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ? 579 AllocAll : AllocNone; 580 size = pVisual->ColormapEntries; 581 582 /* If the create returns non-0, it failed */ 583 result = CreateColormap (mid, pScreen, pVisual, &pmap, alloc, client); 584 if(result != Success) 585 return result; 586 if(alloc == AllocAll) 587 { 588 memmove((char *)pmap->red, (char *)pSrc->red, size * sizeof(Entry)); 589 if((pmap->class | DynamicClass) == DirectColor) 590 { 591 memmove((char *)pmap->green, (char *)pSrc->green, size * sizeof(Entry)); 592 memmove((char *)pmap->blue, (char *)pSrc->blue, size * sizeof(Entry)); 593 } 594 pSrc->flags &= ~AllAllocated; 595 FreePixels(pSrc, client); 596 UpdateColors(pmap); 597 return Success; 598 } 599 600 CopyFree(REDMAP, client, pSrc, pmap); 601 if ((pmap->class | DynamicClass) == DirectColor) 602 { 603 CopyFree(GREENMAP, client, pSrc, pmap); 604 CopyFree(BLUEMAP, client, pSrc, pmap); 605 } 606 if (pmap->class & DynamicClass) 607 UpdateColors(pmap); 608 /* XXX should worry about removing any RT_CMAPENTRY resource */ 609 return Success; 610} 611 612/* Helper routine for freeing large numbers of cells from a map */ 613static void 614CopyFree (int channel, int client, ColormapPtr pmapSrc, ColormapPtr pmapDst) 615{ 616 int z, npix; 617 EntryPtr pentSrcFirst, pentDstFirst; 618 EntryPtr pentSrc, pentDst; 619 Pixel *ppix; 620 int nalloc; 621 622 switch(channel) 623 { 624 default: /* so compiler can see that everything gets initialized */ 625 case REDMAP: 626 ppix = (pmapSrc->clientPixelsRed)[client]; 627 npix = (pmapSrc->numPixelsRed)[client]; 628 pentSrcFirst = pmapSrc->red; 629 pentDstFirst = pmapDst->red; 630 break; 631 case GREENMAP: 632 ppix = (pmapSrc->clientPixelsGreen)[client]; 633 npix = (pmapSrc->numPixelsGreen)[client]; 634 pentSrcFirst = pmapSrc->green; 635 pentDstFirst = pmapDst->green; 636 break; 637 case BLUEMAP: 638 ppix = (pmapSrc->clientPixelsBlue)[client]; 639 npix = (pmapSrc->numPixelsBlue)[client]; 640 pentSrcFirst = pmapSrc->blue; 641 pentDstFirst = pmapDst->blue; 642 break; 643 } 644 nalloc = 0; 645 if (pmapSrc->class & DynamicClass) 646 { 647 for(z = npix; --z >= 0; ppix++) 648 { 649 /* Copy entries */ 650 pentSrc = pentSrcFirst + *ppix; 651 pentDst = pentDstFirst + *ppix; 652 if (pentDst->refcnt > 0) 653 { 654 pentDst->refcnt++; 655 } 656 else 657 { 658 *pentDst = *pentSrc; 659 nalloc++; 660 if (pentSrc->refcnt > 0) 661 pentDst->refcnt = 1; 662 else 663 pentSrc->fShared = FALSE; 664 } 665 FreeCell(pmapSrc, *ppix, channel); 666 } 667 } 668 669 /* Note that FreeCell has already fixed pmapSrc->free{Color} */ 670 switch(channel) 671 { 672 case REDMAP: 673 pmapDst->freeRed -= nalloc; 674 (pmapDst->clientPixelsRed)[client] = 675 (pmapSrc->clientPixelsRed)[client]; 676 (pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL; 677 (pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client]; 678 (pmapSrc->numPixelsRed)[client] = 0; 679 break; 680 case GREENMAP: 681 pmapDst->freeGreen -= nalloc; 682 (pmapDst->clientPixelsGreen)[client] = 683 (pmapSrc->clientPixelsGreen)[client]; 684 (pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL; 685 (pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client]; 686 (pmapSrc->numPixelsGreen)[client] = 0; 687 break; 688 case BLUEMAP: 689 pmapDst->freeBlue -= nalloc; 690 pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client]; 691 pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL; 692 pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client]; 693 pmapSrc->numPixelsBlue[client] = 0; 694 break; 695 } 696} 697 698/* Free the ith entry in a color map. Must handle freeing of 699 * colors allocated through AllocColorPlanes */ 700static void 701FreeCell (ColormapPtr pmap, Pixel i, int channel) 702{ 703 EntryPtr pent; 704 int *pCount; 705 706 707 switch (channel) 708 { 709 default: /* so compiler can see that everything gets initialized */ 710 case PSEUDOMAP: 711 case REDMAP: 712 pent = (EntryPtr) &pmap->red[i]; 713 pCount = &pmap->freeRed; 714 break; 715 case GREENMAP: 716 pent = (EntryPtr) &pmap->green[i]; 717 pCount = &pmap->freeGreen; 718 break; 719 case BLUEMAP: 720 pent = (EntryPtr) &pmap->blue[i]; 721 pCount = &pmap->freeBlue; 722 break; 723 } 724 /* If it's not privately allocated and it's not time to free it, just 725 * decrement the count */ 726 if (pent->refcnt > 1) 727 pent->refcnt--; 728 else 729 { 730 /* If the color type is shared, find the sharedcolor. If decremented 731 * refcnt is 0, free the shared cell. */ 732 if (pent->fShared) 733 { 734 if(--pent->co.shco.red->refcnt == 0) 735 free(pent->co.shco.red); 736 if(--pent->co.shco.green->refcnt == 0) 737 free(pent->co.shco.green); 738 if(--pent->co.shco.blue->refcnt == 0) 739 free(pent->co.shco.blue); 740 pent->fShared = FALSE; 741 } 742 pent->refcnt = 0; 743 *pCount += 1; 744 } 745} 746 747static void 748UpdateColors (ColormapPtr pmap) 749{ 750 xColorItem *defs; 751 xColorItem *pdef; 752 EntryPtr pent; 753 VisualPtr pVisual; 754 int i, n, size; 755 756 pVisual = pmap->pVisual; 757 size = pVisual->ColormapEntries; 758 defs = malloc(size * sizeof(xColorItem)); 759 if (!defs) 760 return; 761 n = 0; 762 pdef = defs; 763 if (pmap->class == DirectColor) 764 { 765 for (i = 0; i < size; i++) 766 { 767 if (!pmap->red[i].refcnt && 768 !pmap->green[i].refcnt && 769 !pmap->blue[i].refcnt) 770 continue; 771 pdef->pixel = ((Pixel)i << pVisual->offsetRed) | 772 ((Pixel)i << pVisual->offsetGreen) | 773 ((Pixel)i << pVisual->offsetBlue); 774 pdef->red = pmap->red[i].co.local.red; 775 pdef->green = pmap->green[i].co.local.green; 776 pdef->blue = pmap->blue[i].co.local.blue; 777 pdef->flags = DoRed|DoGreen|DoBlue; 778 pdef++; 779 n++; 780 } 781 } 782 else 783 { 784 for (i = 0, pent = pmap->red; i < size; i++, pent++) 785 { 786 if (!pent->refcnt) 787 continue; 788 pdef->pixel = i; 789 if(pent->fShared) 790 { 791 pdef->red = pent->co.shco.red->color; 792 pdef->green = pent->co.shco.green->color; 793 pdef->blue = pent->co.shco.blue->color; 794 } 795 else 796 { 797 pdef->red = pent->co.local.red; 798 pdef->green = pent->co.local.green; 799 pdef->blue = pent->co.local.blue; 800 } 801 pdef->flags = DoRed|DoGreen|DoBlue; 802 pdef++; 803 n++; 804 } 805 } 806 if (n) 807 (*pmap->pScreen->StoreColors)(pmap, n, defs); 808 free(defs); 809} 810 811/* Get a read-only color from a ColorMap (probably slow for large maps) 812 * Returns by changing the value in pred, pgreen, pblue and pPix 813 */ 814int 815AllocColor (ColormapPtr pmap, 816 unsigned short *pred, unsigned short *pgreen, unsigned short *pblue, 817 Pixel *pPix, int client) 818{ 819 Pixel pixR, pixG, pixB; 820 int entries; 821 xrgb rgb; 822 int class; 823 VisualPtr pVisual; 824 int npix; 825 Pixel *ppix; 826 827 pVisual = pmap->pVisual; 828 (*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual); 829 rgb.red = *pred; 830 rgb.green = *pgreen; 831 rgb.blue = *pblue; 832 class = pmap->class; 833 entries = pVisual->ColormapEntries; 834 835 /* If the colormap is being created, then we want to be able to change 836 * the colormap, even if it's a static type. Otherwise, we'd never be 837 * able to initialize static colormaps 838 */ 839 if(pmap->flags & BeingCreated) 840 class |= DynamicClass; 841 842 /* If this is one of the static storage classes, and we're not initializing 843 * it, the best we can do is to find the closest color entry to the 844 * requested one and return that. 845 */ 846 switch (class) { 847 case StaticColor: 848 case StaticGray: 849 /* Look up all three components in the same pmap */ 850 *pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); 851 *pred = pmap->red[pixR].co.local.red; 852 *pgreen = pmap->red[pixR].co.local.green; 853 *pblue = pmap->red[pixR].co.local.blue; 854 npix = pmap->numPixelsRed[client]; 855 ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], 856 (npix + 1) * sizeof(Pixel)); 857 if (!ppix) 858 return BadAlloc; 859 ppix[npix] = pixR; 860 pmap->clientPixelsRed[client] = ppix; 861 pmap->numPixelsRed[client]++; 862 break; 863 864 case TrueColor: 865 /* Look up each component in its own map, then OR them together */ 866 pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); 867 pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); 868 pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); 869 *pPix = (pixR << pVisual->offsetRed) | 870 (pixG << pVisual->offsetGreen) | 871 (pixB << pVisual->offsetBlue) | 872 ALPHAMASK(pVisual); 873 874 *pred = pmap->red[pixR].co.local.red; 875 *pgreen = pmap->green[pixG].co.local.green; 876 *pblue = pmap->blue[pixB].co.local.blue; 877 npix = pmap->numPixelsRed[client]; 878 ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], 879 (npix + 1) * sizeof(Pixel)); 880 if (!ppix) 881 return BadAlloc; 882 ppix[npix] = pixR; 883 pmap->clientPixelsRed[client] = ppix; 884 npix = pmap->numPixelsGreen[client]; 885 ppix = (Pixel *) realloc(pmap->clientPixelsGreen[client], 886 (npix + 1) * sizeof(Pixel)); 887 if (!ppix) 888 return BadAlloc; 889 ppix[npix] = pixG; 890 pmap->clientPixelsGreen[client] = ppix; 891 npix = pmap->numPixelsBlue[client]; 892 ppix = (Pixel *) realloc(pmap->clientPixelsBlue[client], 893 (npix + 1) * sizeof(Pixel)); 894 if (!ppix) 895 return BadAlloc; 896 ppix[npix] = pixB; 897 pmap->clientPixelsBlue[client] = ppix; 898 pmap->numPixelsRed[client]++; 899 pmap->numPixelsGreen[client]++; 900 pmap->numPixelsBlue[client]++; 901 break; 902 903 case GrayScale: 904 case PseudoColor: 905 if (pmap->mid != pmap->pScreen->defColormap && 906 pmap->pVisual->vid == pmap->pScreen->rootVisual) 907 { 908 ColormapPtr prootmap; 909 dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, 910 RT_COLORMAP, clients[client], DixReadAccess); 911 912 if (pmap->class == prootmap->class) 913 FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb, 914 pPix, PSEUDOMAP, AllComp); 915 } 916 if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP, 917 client, AllComp) != Success) 918 return BadAlloc; 919 break; 920 921 case DirectColor: 922 if (pmap->mid != pmap->pScreen->defColormap && 923 pmap->pVisual->vid == pmap->pScreen->rootVisual) 924 { 925 ColormapPtr prootmap; 926 dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, 927 RT_COLORMAP, clients[client], DixReadAccess); 928 929 if (pmap->class == prootmap->class) 930 { 931 pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; 932 FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb, 933 &pixR, REDMAP, RedComp); 934 pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; 935 FindColorInRootCmap (prootmap, prootmap->green, entries, &rgb, 936 &pixG, GREENMAP, GreenComp); 937 pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; 938 FindColorInRootCmap (prootmap, prootmap->blue, entries, &rgb, 939 &pixB, BLUEMAP, BlueComp); 940 *pPix = pixR | pixG | pixB; 941 } 942 } 943 944 pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; 945 if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, 946 client, RedComp) != Success) 947 return BadAlloc; 948 pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; 949 if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, 950 GREENMAP, client, GreenComp) != Success) 951 { 952 (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0); 953 return BadAlloc; 954 } 955 pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; 956 if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, 957 client, BlueComp) != Success) 958 { 959 (void)FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel)0); 960 (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0); 961 return BadAlloc; 962 } 963 *pPix = pixR | pixG | pixB | ALPHAMASK(pVisual); 964 965 break; 966 } 967 968 /* if this is the client's first pixel in this colormap, tell the 969 * resource manager that the client has pixels in this colormap which 970 * should be freed when the client dies */ 971 if ((pmap->numPixelsRed[client] == 1) && 972 (CLIENT_ID(pmap->mid) != client) && 973 !(pmap->flags & BeingCreated)) 974 { 975 colorResource *pcr; 976 977 pcr = malloc(sizeof(colorResource)); 978 if (!pcr) 979 { 980 (void)FreeColors(pmap, client, 1, pPix, (Pixel)0); 981 return BadAlloc; 982 } 983 pcr->mid = pmap->mid; 984 pcr->client = client; 985 if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) 986 return BadAlloc; 987 } 988 return Success; 989} 990 991/* 992 * FakeAllocColor -- fake an AllocColor request by 993 * returning a free pixel if availible, otherwise returning 994 * the closest matching pixel. This is used by the mi 995 * software sprite code to recolor cursors. A nice side-effect 996 * is that this routine will never return failure. 997 */ 998 999void 1000FakeAllocColor (ColormapPtr pmap, xColorItem *item) 1001{ 1002 Pixel pixR, pixG, pixB; 1003 Pixel temp; 1004 int entries; 1005 xrgb rgb; 1006 int class; 1007 VisualPtr pVisual; 1008 1009 pVisual = pmap->pVisual; 1010 rgb.red = item->red; 1011 rgb.green = item->green; 1012 rgb.blue = item->blue; 1013 (*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual); 1014 class = pmap->class; 1015 entries = pVisual->ColormapEntries; 1016 1017 switch (class) { 1018 case GrayScale: 1019 case PseudoColor: 1020 temp = 0; 1021 item->pixel = 0; 1022 if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP, 1023 -1, AllComp) == Success) { 1024 item->pixel = temp; 1025 break; 1026 } 1027 /* fall through ... */ 1028 case StaticColor: 1029 case StaticGray: 1030 item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); 1031 break; 1032 1033 case DirectColor: 1034 /* Look up each component in its own map, then OR them together */ 1035 pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed; 1036 pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen; 1037 pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue; 1038 if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, 1039 -1, RedComp) != Success) 1040 pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP) 1041 << pVisual->offsetRed; 1042 if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, 1043 GREENMAP, -1, GreenComp) != Success) 1044 pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, 1045 GREENMAP) << pVisual->offsetGreen; 1046 if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, 1047 -1, BlueComp) != Success) 1048 pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP) 1049 << pVisual->offsetBlue; 1050 item->pixel = pixR | pixG | pixB; 1051 break; 1052 1053 case TrueColor: 1054 /* Look up each component in its own map, then OR them together */ 1055 pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); 1056 pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); 1057 pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); 1058 item->pixel = (pixR << pVisual->offsetRed) | 1059 (pixG << pVisual->offsetGreen) | 1060 (pixB << pVisual->offsetBlue); 1061 break; 1062 } 1063} 1064 1065/* free a pixel value obtained from FakeAllocColor */ 1066void 1067FakeFreeColor(ColormapPtr pmap, Pixel pixel) 1068{ 1069 VisualPtr pVisual; 1070 Pixel pixR, pixG, pixB; 1071 1072 switch (pmap->class) { 1073 case GrayScale: 1074 case PseudoColor: 1075 if (pmap->red[pixel].refcnt == AllocTemporary) 1076 pmap->red[pixel].refcnt = 0; 1077 break; 1078 case DirectColor: 1079 pVisual = pmap->pVisual; 1080 pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed; 1081 pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; 1082 pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; 1083 if (pmap->red[pixR].refcnt == AllocTemporary) 1084 pmap->red[pixR].refcnt = 0; 1085 if (pmap->green[pixG].refcnt == AllocTemporary) 1086 pmap->green[pixG].refcnt = 0; 1087 if (pmap->blue[pixB].refcnt == AllocTemporary) 1088 pmap->blue[pixB].refcnt = 0; 1089 break; 1090 } 1091} 1092 1093typedef unsigned short BigNumUpper; 1094typedef unsigned long BigNumLower; 1095 1096#define BIGNUMLOWERBITS 24 1097#define BIGNUMUPPERBITS 16 1098#define BIGNUMLOWER (1 << BIGNUMLOWERBITS) 1099#define BIGNUMUPPER (1 << BIGNUMUPPERBITS) 1100#define UPPERPART(i) ((i) >> BIGNUMLOWERBITS) 1101#define LOWERPART(i) ((i) & (BIGNUMLOWER - 1)) 1102 1103typedef struct _bignum { 1104 BigNumUpper upper; 1105 BigNumLower lower; 1106} BigNumRec, *BigNumPtr; 1107 1108#define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\ 1109 ((x)->upper == (y)->upper && (x)->lower > (y)->lower)) 1110 1111#define UnsignedToBigNum(u,r) (((r)->upper = UPPERPART(u)), \ 1112 ((r)->lower = LOWERPART(u))) 1113 1114#define MaxBigNum(r) (((r)->upper = BIGNUMUPPER-1), \ 1115 ((r)->lower = BIGNUMLOWER-1)) 1116 1117static void 1118BigNumAdd (BigNumPtr x, BigNumPtr y, BigNumPtr r) 1119{ 1120 BigNumLower lower, carry = 0; 1121 1122 lower = x->lower + y->lower; 1123 if (lower >= BIGNUMLOWER) { 1124 lower -= BIGNUMLOWER; 1125 carry = 1; 1126 } 1127 r->lower = lower; 1128 r->upper = x->upper + y->upper + carry; 1129} 1130 1131static Pixel 1132FindBestPixel(EntryPtr pentFirst, int size, xrgb *prgb, int channel) 1133{ 1134 EntryPtr pent; 1135 Pixel pixel, final; 1136 long dr, dg, db; 1137 unsigned long sq; 1138 BigNumRec minval, sum, temp; 1139 1140 final = 0; 1141 MaxBigNum(&minval); 1142 /* look for the minimal difference */ 1143 for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++) 1144 { 1145 dr = dg = db = 0; 1146 switch(channel) 1147 { 1148 case PSEUDOMAP: 1149 dg = (long) pent->co.local.green - prgb->green; 1150 db = (long) pent->co.local.blue - prgb->blue; 1151 case REDMAP: 1152 dr = (long) pent->co.local.red - prgb->red; 1153 break; 1154 case GREENMAP: 1155 dg = (long) pent->co.local.green - prgb->green; 1156 break; 1157 case BLUEMAP: 1158 db = (long) pent->co.local.blue - prgb->blue; 1159 break; 1160 } 1161 sq = dr * dr; 1162 UnsignedToBigNum (sq, &sum); 1163 sq = dg * dg; 1164 UnsignedToBigNum (sq, &temp); 1165 BigNumAdd (&sum, &temp, &sum); 1166 sq = db * db; 1167 UnsignedToBigNum (sq, &temp); 1168 BigNumAdd (&sum, &temp, &sum); 1169 if (BigNumGreater (&minval, &sum)) 1170 { 1171 final = pixel; 1172 minval = sum; 1173 } 1174 } 1175 return final; 1176} 1177 1178static void 1179FindColorInRootCmap (ColormapPtr pmap, EntryPtr pentFirst, int size, 1180 xrgb *prgb, Pixel *pPixel, int channel, 1181 ColorCompareProcPtr comp) 1182{ 1183 EntryPtr pent; 1184 Pixel pixel; 1185 int count; 1186 1187 if ((pixel = *pPixel) >= size) 1188 pixel = 0; 1189 for (pent = pentFirst + pixel, count = size; --count >= 0; pent++, pixel++) 1190 { 1191 if (pent->refcnt > 0 && (*comp) (pent, prgb)) 1192 { 1193 switch (channel) 1194 { 1195 case REDMAP: 1196 pixel <<= pmap->pVisual->offsetRed; 1197 break; 1198 case GREENMAP: 1199 pixel <<= pmap->pVisual->offsetGreen; 1200 break; 1201 case BLUEMAP: 1202 pixel <<= pmap->pVisual->offsetBlue; 1203 break; 1204 default: /* PSEUDOMAP */ 1205 break; 1206 } 1207 *pPixel = pixel; 1208 } 1209 } 1210} 1211 1212/* Tries to find a color in pmap that exactly matches the one requested in prgb 1213 * if it can't it allocates one. 1214 * Starts looking at pentFirst + *pPixel, so if you want a specific pixel, 1215 * load *pPixel with that value, otherwise set it to 0 1216 */ 1217int 1218FindColor (ColormapPtr pmap, EntryPtr pentFirst, int size, xrgb *prgb, 1219 Pixel *pPixel, int channel, int client, 1220 ColorCompareProcPtr comp) 1221{ 1222 EntryPtr pent; 1223 Bool foundFree; 1224 Pixel pixel, Free = 0; 1225 int npix, count, *nump = NULL; 1226 Pixel **pixp = NULL, *ppix; 1227 xColorItem def; 1228 1229 foundFree = FALSE; 1230 1231 if((pixel = *pPixel) >= size) 1232 pixel = 0; 1233 /* see if there is a match, and also look for a free entry */ 1234 for (pent = pentFirst + pixel, count = size; --count >= 0; ) 1235 { 1236 if (pent->refcnt > 0) 1237 { 1238 if ((*comp) (pent, prgb)) 1239 { 1240 if (client >= 0) 1241 pent->refcnt++; 1242 *pPixel = pixel; 1243 switch(channel) 1244 { 1245 case REDMAP: 1246 *pPixel <<= pmap->pVisual->offsetRed; 1247 case PSEUDOMAP: 1248 break; 1249 case GREENMAP: 1250 *pPixel <<= pmap->pVisual->offsetGreen; 1251 break; 1252 case BLUEMAP: 1253 *pPixel <<= pmap->pVisual->offsetBlue; 1254 break; 1255 } 1256 goto gotit; 1257 } 1258 } 1259 else if (!foundFree && pent->refcnt == 0) 1260 { 1261 Free = pixel; 1262 foundFree = TRUE; 1263 /* If we're initializing the colormap, then we are looking for 1264 * the first free cell we can find, not to minimize the number 1265 * of entries we use. So don't look any further. */ 1266 if(pmap->flags & BeingCreated) 1267 break; 1268 } 1269 pixel++; 1270 if(pixel >= size) 1271 { 1272 pent = pentFirst; 1273 pixel = 0; 1274 } 1275 else 1276 pent++; 1277 } 1278 1279 /* If we got here, we didn't find a match. If we also didn't find 1280 * a free entry, we're out of luck. Otherwise, we'll usurp a free 1281 * entry and fill it in */ 1282 if (!foundFree) 1283 return BadAlloc; 1284 pent = pentFirst + Free; 1285 pent->fShared = FALSE; 1286 pent->refcnt = (client >= 0) ? 1 : AllocTemporary; 1287 1288 switch (channel) 1289 { 1290 case PSEUDOMAP: 1291 pent->co.local.red = prgb->red; 1292 pent->co.local.green = prgb->green; 1293 pent->co.local.blue = prgb->blue; 1294 def.red = prgb->red; 1295 def.green = prgb->green; 1296 def.blue = prgb->blue; 1297 def.flags = (DoRed|DoGreen|DoBlue); 1298 if (client >= 0) 1299 pmap->freeRed--; 1300 def.pixel = Free; 1301 break; 1302 1303 case REDMAP: 1304 pent->co.local.red = prgb->red; 1305 def.red = prgb->red; 1306 def.green = pmap->green[0].co.local.green; 1307 def.blue = pmap->blue[0].co.local.blue; 1308 def.flags = DoRed; 1309 if (client >= 0) 1310 pmap->freeRed--; 1311 def.pixel = Free << pmap->pVisual->offsetRed; 1312 break; 1313 1314 case GREENMAP: 1315 pent->co.local.green = prgb->green; 1316 def.red = pmap->red[0].co.local.red; 1317 def.green = prgb->green; 1318 def.blue = pmap->blue[0].co.local.blue; 1319 def.flags = DoGreen; 1320 if (client >= 0) 1321 pmap->freeGreen--; 1322 def.pixel = Free << pmap->pVisual->offsetGreen; 1323 break; 1324 1325 case BLUEMAP: 1326 pent->co.local.blue = prgb->blue; 1327 def.red = pmap->red[0].co.local.red; 1328 def.green = pmap->green[0].co.local.green; 1329 def.blue = prgb->blue; 1330 def.flags = DoBlue; 1331 if (client >= 0) 1332 pmap->freeBlue--; 1333 def.pixel = Free << pmap->pVisual->offsetBlue; 1334 break; 1335 } 1336 (*pmap->pScreen->StoreColors) (pmap, 1, &def); 1337 pixel = Free; 1338 *pPixel = def.pixel; 1339 1340gotit: 1341 if (pmap->flags & BeingCreated || client == -1) 1342 return Success; 1343 /* Now remember the pixel, for freeing later */ 1344 switch (channel) 1345 { 1346 case PSEUDOMAP: 1347 case REDMAP: 1348 nump = pmap->numPixelsRed; 1349 pixp = pmap->clientPixelsRed; 1350 break; 1351 1352 case GREENMAP: 1353 nump = pmap->numPixelsGreen; 1354 pixp = pmap->clientPixelsGreen; 1355 break; 1356 1357 case BLUEMAP: 1358 nump = pmap->numPixelsBlue; 1359 pixp = pmap->clientPixelsBlue; 1360 break; 1361 } 1362 npix = nump[client]; 1363 ppix = (Pixel *) realloc(pixp[client], (npix + 1) * sizeof(Pixel)); 1364 if (!ppix) 1365 { 1366 pent->refcnt--; 1367 if (!pent->fShared) 1368 switch (channel) 1369 { 1370 case PSEUDOMAP: 1371 case REDMAP: 1372 pmap->freeRed++; 1373 break; 1374 case GREENMAP: 1375 pmap->freeGreen++; 1376 break; 1377 case BLUEMAP: 1378 pmap->freeBlue++; 1379 break; 1380 } 1381 return BadAlloc; 1382 } 1383 ppix[npix] = pixel; 1384 pixp[client] = ppix; 1385 nump[client]++; 1386 1387 return Success; 1388} 1389 1390/* Comparison functions -- passed to FindColor to determine if an 1391 * entry is already the color we're looking for or not */ 1392static int 1393AllComp (EntryPtr pent, xrgb *prgb) 1394{ 1395 if((pent->co.local.red == prgb->red) && 1396 (pent->co.local.green == prgb->green) && 1397 (pent->co.local.blue == prgb->blue) ) 1398 return 1; 1399 return 0; 1400} 1401 1402static int 1403RedComp (EntryPtr pent, xrgb *prgb) 1404{ 1405 if (pent->co.local.red == prgb->red) 1406 return 1; 1407 return 0; 1408} 1409 1410static int 1411GreenComp (EntryPtr pent, xrgb *prgb) 1412{ 1413 if (pent->co.local.green == prgb->green) 1414 return 1; 1415 return 0; 1416} 1417 1418static int 1419BlueComp (EntryPtr pent, xrgb *prgb) 1420{ 1421 if (pent->co.local.blue == prgb->blue) 1422 return 1; 1423 return 0; 1424} 1425 1426 1427/* Read the color value of a cell */ 1428 1429int 1430QueryColors (ColormapPtr pmap, int count, Pixel *ppixIn, xrgb *prgbList, ClientPtr client) 1431{ 1432 Pixel *ppix, pixel; 1433 xrgb *prgb; 1434 VisualPtr pVisual; 1435 EntryPtr pent; 1436 Pixel i; 1437 int errVal = Success; 1438 1439 pVisual = pmap->pVisual; 1440 if ((pmap->class | DynamicClass) == DirectColor) 1441 { 1442 int numred, numgreen, numblue; 1443 Pixel rgbbad; 1444 1445 numred = NUMRED(pVisual); 1446 numgreen = NUMGREEN(pVisual); 1447 numblue = NUMBLUE(pVisual); 1448 rgbbad = ~RGBMASK(pVisual); 1449 for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) 1450 { 1451 pixel = *ppix; 1452 if (pixel & rgbbad) { 1453 client->errorValue = pixel; 1454 errVal = BadValue; 1455 continue; 1456 } 1457 i = (pixel & pVisual->redMask) >> pVisual->offsetRed; 1458 if (i >= numred) 1459 { 1460 client->errorValue = pixel; 1461 errVal = BadValue; 1462 continue; 1463 } 1464 prgb->red = pmap->red[i].co.local.red; 1465 i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; 1466 if (i >= numgreen) 1467 { 1468 client->errorValue = pixel; 1469 errVal = BadValue; 1470 continue; 1471 } 1472 prgb->green = pmap->green[i].co.local.green; 1473 i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; 1474 if (i >= numblue) 1475 { 1476 client->errorValue = pixel; 1477 errVal = BadValue; 1478 continue; 1479 } 1480 prgb->blue = pmap->blue[i].co.local.blue; 1481 } 1482 } 1483 else 1484 { 1485 for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) 1486 { 1487 pixel = *ppix; 1488 if (pixel >= pVisual->ColormapEntries) 1489 { 1490 client->errorValue = pixel; 1491 errVal = BadValue; 1492 } 1493 else 1494 { 1495 pent = (EntryPtr)&pmap->red[pixel]; 1496 if (pent->fShared) 1497 { 1498 prgb->red = pent->co.shco.red->color; 1499 prgb->green = pent->co.shco.green->color; 1500 prgb->blue = pent->co.shco.blue->color; 1501 } 1502 else 1503 { 1504 prgb->red = pent->co.local.red; 1505 prgb->green = pent->co.local.green; 1506 prgb->blue = pent->co.local.blue; 1507 } 1508 } 1509 } 1510 } 1511 return errVal; 1512} 1513 1514static void 1515FreePixels(ColormapPtr pmap, int client) 1516{ 1517 Pixel *ppix, *ppixStart; 1518 int n; 1519 int class; 1520 1521 class = pmap->class; 1522 ppixStart = pmap->clientPixelsRed[client]; 1523 if (class & DynamicClass) 1524 { 1525 n = pmap->numPixelsRed[client]; 1526 for (ppix = ppixStart; --n >= 0; ) 1527 { 1528 FreeCell(pmap, *ppix, REDMAP); 1529 ppix++; 1530 } 1531 } 1532 1533 free(ppixStart); 1534 pmap->clientPixelsRed[client] = (Pixel *) NULL; 1535 pmap->numPixelsRed[client] = 0; 1536 if ((class | DynamicClass) == DirectColor) 1537 { 1538 ppixStart = pmap->clientPixelsGreen[client]; 1539 if (class & DynamicClass) 1540 for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;) 1541 FreeCell(pmap, *ppix++, GREENMAP); 1542 free(ppixStart); 1543 pmap->clientPixelsGreen[client] = (Pixel *) NULL; 1544 pmap->numPixelsGreen[client] = 0; 1545 1546 ppixStart = pmap->clientPixelsBlue[client]; 1547 if (class & DynamicClass) 1548 for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0; ) 1549 FreeCell(pmap, *ppix++, BLUEMAP); 1550 free(ppixStart); 1551 pmap->clientPixelsBlue[client] = (Pixel *) NULL; 1552 pmap->numPixelsBlue[client] = 0; 1553 } 1554} 1555 1556/** 1557 * Frees all of a client's colors and cells. 1558 * 1559 * \param value must conform to DeleteType 1560 * \unused fakeid 1561 */ 1562int 1563FreeClientPixels (pointer value, XID fakeid) 1564{ 1565 pointer pmap; 1566 colorResource *pcr = value; 1567 int rc; 1568 1569 rc = dixLookupResourceByType(&pmap, pcr->mid, RT_COLORMAP, serverClient, 1570 DixRemoveAccess); 1571 if (rc == Success) 1572 FreePixels((ColormapPtr)pmap, pcr->client); 1573 free(pcr); 1574 return Success; 1575} 1576 1577int 1578AllocColorCells (int client, ColormapPtr pmap, int colors, int planes, 1579 Bool contig, Pixel *ppix, Pixel *masks) 1580{ 1581 Pixel rmask, gmask, bmask, *ppixFirst, r, g, b; 1582 int n, class; 1583 int ok; 1584 int oldcount; 1585 colorResource *pcr = (colorResource *)NULL; 1586 1587 class = pmap->class; 1588 if (!(class & DynamicClass)) 1589 return BadAlloc; /* Shouldn't try on this type */ 1590 oldcount = pmap->numPixelsRed[client]; 1591 if (pmap->class == DirectColor) 1592 oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; 1593 if (!oldcount && (CLIENT_ID(pmap->mid) != client)) 1594 { 1595 pcr = malloc(sizeof(colorResource)); 1596 if (!pcr) 1597 return BadAlloc; 1598 } 1599 1600 if (pmap->class == DirectColor) 1601 { 1602 ok = AllocDirect (client, pmap, colors, planes, planes, planes, 1603 contig, ppix, &rmask, &gmask, &bmask); 1604 if(ok == Success) 1605 { 1606 for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b) 1607 { 1608 while(!(rmask & r)) 1609 r += r; 1610 while(!(gmask & g)) 1611 g += g; 1612 while(!(bmask & b)) 1613 b += b; 1614 *masks++ = r | g | b; 1615 } 1616 } 1617 } 1618 else 1619 { 1620 ok = AllocPseudo (client, pmap, colors, planes, contig, ppix, &rmask, 1621 &ppixFirst); 1622 if(ok == Success) 1623 { 1624 for (r = 1, n = planes; --n >= 0; r += r) 1625 { 1626 while(!(rmask & r)) 1627 r += r; 1628 *masks++ = r; 1629 } 1630 } 1631 } 1632 1633 /* if this is the client's first pixels in this colormap, tell the 1634 * resource manager that the client has pixels in this colormap which 1635 * should be freed when the client dies */ 1636 if ((ok == Success) && pcr) 1637 { 1638 pcr->mid = pmap->mid; 1639 pcr->client = client; 1640 if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) 1641 ok = BadAlloc; 1642 } else free(pcr); 1643 1644 return ok; 1645} 1646 1647 1648int 1649AllocColorPlanes (int client, ColormapPtr pmap, int colors, 1650 int r, int g, int b, Bool contig, Pixel *pixels, 1651 Pixel *prmask, Pixel *pgmask, Pixel *pbmask) 1652{ 1653 int ok; 1654 Pixel mask, *ppixFirst; 1655 Pixel shift; 1656 int i; 1657 int class; 1658 int oldcount; 1659 colorResource *pcr = (colorResource *)NULL; 1660 1661 class = pmap->class; 1662 if (!(class & DynamicClass)) 1663 return BadAlloc; /* Shouldn't try on this type */ 1664 oldcount = pmap->numPixelsRed[client]; 1665 if (class == DirectColor) 1666 oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; 1667 if (!oldcount && (CLIENT_ID(pmap->mid) != client)) 1668 { 1669 pcr = malloc(sizeof(colorResource)); 1670 if (!pcr) 1671 return BadAlloc; 1672 } 1673 1674 if (class == DirectColor) 1675 { 1676 ok = AllocDirect (client, pmap, colors, r, g, b, contig, pixels, 1677 prmask, pgmask, pbmask); 1678 } 1679 else 1680 { 1681 /* Allocate the proper pixels */ 1682 /* XXX This is sort of bad, because of contig is set, we force all 1683 * r + g + b bits to be contiguous. Should only force contiguity 1684 * per mask 1685 */ 1686 ok = AllocPseudo (client, pmap, colors, r + g + b, contig, pixels, 1687 &mask, &ppixFirst); 1688 1689 if(ok == Success) 1690 { 1691 /* now split that mask into three */ 1692 *prmask = *pgmask = *pbmask = 0; 1693 shift = 1; 1694 for (i = r; --i >= 0; shift += shift) 1695 { 1696 while (!(mask & shift)) 1697 shift += shift; 1698 *prmask |= shift; 1699 } 1700 for (i = g; --i >= 0; shift += shift) 1701 { 1702 while (!(mask & shift)) 1703 shift += shift; 1704 *pgmask |= shift; 1705 } 1706 for (i = b; --i >= 0; shift += shift) 1707 { 1708 while (!(mask & shift)) 1709 shift += shift; 1710 *pbmask |= shift; 1711 } 1712 1713 /* set up the shared color cells */ 1714 if (!AllocShared(pmap, pixels, colors, r, g, b, 1715 *prmask, *pgmask, *pbmask, ppixFirst)) 1716 { 1717 (void)FreeColors(pmap, client, colors, pixels, mask); 1718 ok = BadAlloc; 1719 } 1720 } 1721 } 1722 1723 /* if this is the client's first pixels in this colormap, tell the 1724 * resource manager that the client has pixels in this colormap which 1725 * should be freed when the client dies */ 1726 if ((ok == Success) && pcr) 1727 { 1728 pcr->mid = pmap->mid; 1729 pcr->client = client; 1730 if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) 1731 ok = BadAlloc; 1732 } else free(pcr); 1733 1734 return ok; 1735} 1736 1737static int 1738AllocDirect (int client, ColormapPtr pmap, int c, int r, int g, int b, Bool contig, 1739 Pixel *pixels, Pixel *prmask, Pixel *pgmask, Pixel *pbmask) 1740{ 1741 Pixel *ppixRed, *ppixGreen, *ppixBlue; 1742 Pixel *ppix, *pDst, *p; 1743 int npix, npixR, npixG, npixB; 1744 Bool okR, okG, okB; 1745 Pixel *rpix = 0, *gpix = 0, *bpix = 0; 1746 1747 npixR = c << r; 1748 npixG = c << g; 1749 npixB = c << b; 1750 if ((r >= 32) || (g >= 32) || (b >= 32) || 1751 (npixR > pmap->freeRed) || (npixR < c) || 1752 (npixG > pmap->freeGreen) || (npixG < c) || 1753 (npixB > pmap->freeBlue) || (npixB < c)) 1754 return BadAlloc; 1755 1756 /* start out with empty pixels */ 1757 for(p = pixels; p < pixels + c; p++) 1758 *p = 0; 1759 1760 ppixRed = malloc(npixR * sizeof(Pixel)); 1761 ppixGreen = malloc(npixG * sizeof(Pixel)); 1762 ppixBlue = malloc(npixB * sizeof(Pixel)); 1763 if (!ppixRed || !ppixGreen || !ppixBlue) 1764 { 1765 free(ppixBlue); 1766 free(ppixGreen); 1767 free(ppixRed); 1768 return BadAlloc; 1769 } 1770 1771 okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask); 1772 okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask); 1773 okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask); 1774 1775 if (okR && okG && okB) 1776 { 1777 rpix = (Pixel *) realloc(pmap->clientPixelsRed[client], 1778 (pmap->numPixelsRed[client] + (c << r)) * 1779 sizeof(Pixel)); 1780 if (rpix) 1781 pmap->clientPixelsRed[client] = rpix; 1782 gpix = (Pixel *) realloc(pmap->clientPixelsGreen[client], 1783 (pmap->numPixelsGreen[client] + (c << g)) * 1784 sizeof(Pixel)); 1785 if (gpix) 1786 pmap->clientPixelsGreen[client] = gpix; 1787 bpix = (Pixel *) realloc(pmap->clientPixelsBlue[client], 1788 (pmap->numPixelsBlue[client] + (c << b)) * 1789 sizeof(Pixel)); 1790 if (bpix) 1791 pmap->clientPixelsBlue[client] = bpix; 1792 } 1793 1794 if (!okR || !okG || !okB || !rpix || !gpix || !bpix) 1795 { 1796 if (okR) 1797 for(ppix = ppixRed, npix = npixR; --npix >= 0; ppix++) 1798 pmap->red[*ppix].refcnt = 0; 1799 if (okG) 1800 for(ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++) 1801 pmap->green[*ppix].refcnt = 0; 1802 if (okB) 1803 for(ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++) 1804 pmap->blue[*ppix].refcnt = 0; 1805 free(ppixBlue); 1806 free(ppixGreen); 1807 free(ppixRed); 1808 return BadAlloc; 1809 } 1810 1811 *prmask <<= pmap->pVisual->offsetRed; 1812 *pgmask <<= pmap->pVisual->offsetGreen; 1813 *pbmask <<= pmap->pVisual->offsetBlue; 1814 1815 ppix = rpix + pmap->numPixelsRed[client]; 1816 for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++) 1817 { 1818 *ppix++ = *p; 1819 if(p < ppixRed + c) 1820 *pDst++ |= *p << pmap->pVisual->offsetRed; 1821 } 1822 pmap->numPixelsRed[client] += npixR; 1823 pmap->freeRed -= npixR; 1824 1825 ppix = gpix + pmap->numPixelsGreen[client]; 1826 for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++) 1827 { 1828 *ppix++ = *p; 1829 if(p < ppixGreen + c) 1830 *pDst++ |= *p << pmap->pVisual->offsetGreen; 1831 } 1832 pmap->numPixelsGreen[client] += npixG; 1833 pmap->freeGreen -= npixG; 1834 1835 ppix = bpix + pmap->numPixelsBlue[client]; 1836 for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++) 1837 { 1838 *ppix++ = *p; 1839 if(p < ppixBlue + c) 1840 *pDst++ |= *p << pmap->pVisual->offsetBlue; 1841 } 1842 pmap->numPixelsBlue[client] += npixB; 1843 pmap->freeBlue -= npixB; 1844 1845 1846 for (pDst = pixels; pDst < pixels + c; pDst++) 1847 *pDst |= ALPHAMASK(pmap->pVisual); 1848 1849 free(ppixBlue); 1850 free(ppixGreen); 1851 free(ppixRed); 1852 1853 return Success; 1854} 1855 1856static int 1857AllocPseudo (int client, ColormapPtr pmap, int c, int r, Bool contig, 1858 Pixel *pixels, Pixel *pmask, Pixel **pppixFirst) 1859{ 1860 Pixel *ppix, *p, *pDst, *ppixTemp; 1861 int npix; 1862 Bool ok; 1863 1864 npix = c << r; 1865 if ((r >= 32) || (npix > pmap->freeRed) || (npix < c)) 1866 return BadAlloc; 1867 if(!(ppixTemp = malloc(npix * sizeof(Pixel)))) 1868 return BadAlloc; 1869 ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask); 1870 1871 if (ok) 1872 { 1873 1874 /* all the allocated pixels are added to the client pixel list, 1875 * but only the unique ones are returned to the client */ 1876 ppix = (Pixel *)realloc(pmap->clientPixelsRed[client], 1877 (pmap->numPixelsRed[client] + npix) * sizeof(Pixel)); 1878 if (!ppix) 1879 { 1880 for (p = ppixTemp; p < ppixTemp + npix; p++) 1881 pmap->red[*p].refcnt = 0; 1882 free(ppixTemp); 1883 return BadAlloc; 1884 } 1885 pmap->clientPixelsRed[client] = ppix; 1886 ppix += pmap->numPixelsRed[client]; 1887 *pppixFirst = ppix; 1888 pDst = pixels; 1889 for (p = ppixTemp; p < ppixTemp + npix; p++) 1890 { 1891 *ppix++ = *p; 1892 if(p < ppixTemp + c) 1893 *pDst++ = *p; 1894 } 1895 pmap->numPixelsRed[client] += npix; 1896 pmap->freeRed -= npix; 1897 } 1898 free(ppixTemp); 1899 return ok ? Success : BadAlloc; 1900} 1901 1902/* Allocates count << planes pixels from colormap pmap for client. If 1903 * contig, then the plane mask is made of consecutive bits. Returns 1904 * all count << pixels in the array pixels. The first count of those 1905 * pixels are the unique pixels. *pMask has the mask to Or with the 1906 * unique pixels to get the rest of them. 1907 * 1908 * Returns True iff all pixels could be allocated 1909 * All cells allocated will have refcnt set to AllocPrivate and shared to FALSE 1910 * (see AllocShared for why we care) 1911 */ 1912static Bool 1913AllocCP (ColormapPtr pmap, EntryPtr pentFirst, int count, int planes, 1914 Bool contig, Pixel *pixels, Pixel *pMask) 1915{ 1916 EntryPtr ent; 1917 Pixel pixel, base, entries, maxp, save; 1918 int dplanes, found; 1919 Pixel *ppix; 1920 Pixel mask; 1921 Pixel finalmask; 1922 1923 dplanes = pmap->pVisual->nplanes; 1924 1925 /* Easy case. Allocate pixels only */ 1926 if (planes == 0) 1927 { 1928 /* allocate writable entries */ 1929 ppix = pixels; 1930 ent = pentFirst; 1931 pixel = 0; 1932 while (--count >= 0) 1933 { 1934 /* Just find count unallocated cells */ 1935 while (ent->refcnt) 1936 { 1937 ent++; 1938 pixel++; 1939 } 1940 ent->refcnt = AllocPrivate; 1941 *ppix++ = pixel; 1942 ent->fShared = FALSE; 1943 } 1944 *pMask = 0; 1945 return TRUE; 1946 } 1947 else if (planes > dplanes) 1948 { 1949 return FALSE; 1950 } 1951 1952 /* General case count pixels * 2 ^ planes cells to be allocated */ 1953 1954 /* make room for new pixels */ 1955 ent = pentFirst; 1956 1957 /* first try for contiguous planes, since it's fastest */ 1958 for (mask = (((Pixel)1) << planes) - 1, base = 1, dplanes -= (planes - 1); 1959 --dplanes >= 0; 1960 mask += mask, base += base) 1961 { 1962 ppix = pixels; 1963 found = 0; 1964 pixel = 0; 1965 entries = pmap->pVisual->ColormapEntries - mask; 1966 while (pixel < entries) 1967 { 1968 save = pixel; 1969 maxp = pixel + mask + base; 1970 /* check if all are free */ 1971 while (pixel != maxp && ent[pixel].refcnt == 0) 1972 pixel += base; 1973 if (pixel == maxp) 1974 { 1975 /* this one works */ 1976 *ppix++ = save; 1977 found++; 1978 if (found == count) 1979 { 1980 /* found enough, allocate them all */ 1981 while (--count >= 0) 1982 { 1983 pixel = pixels[count]; 1984 maxp = pixel + mask; 1985 while (1) 1986 { 1987 ent[pixel].refcnt = AllocPrivate; 1988 ent[pixel].fShared = FALSE; 1989 if (pixel == maxp) 1990 break; 1991 pixel += base; 1992 *ppix++ = pixel; 1993 } 1994 } 1995 *pMask = mask; 1996 return TRUE; 1997 } 1998 } 1999 pixel = save + 1; 2000 if (pixel & mask) 2001 pixel += mask; 2002 } 2003 } 2004 2005 dplanes = pmap->pVisual->nplanes; 2006 if (contig || planes == 1 || dplanes < 3) 2007 return FALSE; 2008 2009 /* this will be very slow for large maps, need a better algorithm */ 2010 2011 /* 2012 we can generate the smallest and largest numbers that fits in dplanes 2013 bits and contain exactly planes bits set as follows. First, we need to 2014 check that it is possible to generate such a mask at all. 2015 (Non-contiguous masks need one more bit than contiguous masks). Then 2016 the smallest such mask consists of the rightmost planes-1 bits set, then 2017 a zero, then a one in position planes + 1. The formula is 2018 (3 << (planes-1)) -1 2019 The largest such masks consists of the leftmost planes-1 bits set, then 2020 a zero, then a one bit in position dplanes-planes-1. If dplanes is 2021 smaller than 32 (the number of bits in a word) then the formula is: 2022 (1<<dplanes) - (1<<(dplanes-planes+1) + (1<<dplanes-planes-1) 2023 If dplanes = 32, then we can't calculate (1<<dplanes) and we have 2024 to use: 2025 ( (1<<(planes-1)) - 1) << (dplanes-planes+1) + (1<<(dplanes-planes-1)) 2026 2027 << Thank you, Loretta>>> 2028 2029 */ 2030 2031 finalmask = 2032 (((((Pixel)1)<<(planes-1)) - 1) << (dplanes-planes+1)) + 2033 (((Pixel)1)<<(dplanes-planes-1)); 2034 for (mask = (((Pixel)3) << (planes -1)) - 1; mask <= finalmask; mask++) 2035 { 2036 /* next 3 magic statements count number of ones (HAKMEM #169) */ 2037 pixel = (mask >> 1) & 033333333333; 2038 pixel = mask - pixel - ((pixel >> 1) & 033333333333); 2039 if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes) 2040 continue; 2041 ppix = pixels; 2042 found = 0; 2043 entries = pmap->pVisual->ColormapEntries - mask; 2044 base = lowbit (mask); 2045 for (pixel = 0; pixel < entries; pixel++) 2046 { 2047 if (pixel & mask) 2048 continue; 2049 maxp = 0; 2050 /* check if all are free */ 2051 while (ent[pixel + maxp].refcnt == 0) 2052 { 2053 GetNextBitsOrBreak(maxp, mask, base); 2054 } 2055 if ((maxp < mask) || (ent[pixel + mask].refcnt != 0)) 2056 continue; 2057 /* this one works */ 2058 *ppix++ = pixel; 2059 found++; 2060 if (found < count) 2061 continue; 2062 /* found enough, allocate them all */ 2063 while (--count >= 0) 2064 { 2065 pixel = (pixels)[count]; 2066 maxp = 0; 2067 while (1) 2068 { 2069 ent[pixel + maxp].refcnt = AllocPrivate; 2070 ent[pixel + maxp].fShared = FALSE; 2071 GetNextBitsOrBreak(maxp, mask, base); 2072 *ppix++ = pixel + maxp; 2073 } 2074 } 2075 2076 *pMask = mask; 2077 return TRUE; 2078 } 2079 } 2080 return FALSE; 2081} 2082 2083/** 2084 * 2085 * \param ppixFirst First of the client's new pixels 2086 */ 2087static Bool 2088AllocShared (ColormapPtr pmap, Pixel *ppix, int c, int r, int g, int b, 2089 Pixel rmask, Pixel gmask, Pixel bmask, Pixel *ppixFirst) 2090{ 2091 Pixel *pptr, *cptr; 2092 int npix, z, npixClientNew, npixShared; 2093 Pixel basemask, base, bits, common; 2094 SHAREDCOLOR *pshared, **ppshared, **psharedList; 2095 2096 npixClientNew = c << (r + g + b); 2097 npixShared = (c << r) + (c << g) + (c << b); 2098 psharedList = malloc(npixShared * sizeof(SHAREDCOLOR *)); 2099 if (!psharedList) 2100 return FALSE; 2101 ppshared = psharedList; 2102 for (z = npixShared; --z >= 0; ) 2103 { 2104 if (!(ppshared[z] = malloc(sizeof(SHAREDCOLOR)))) 2105 { 2106 for (z++ ; z < npixShared; z++) 2107 free(ppshared[z]); 2108 free(psharedList); 2109 return FALSE; 2110 } 2111 } 2112 for(pptr = ppix, npix = c; --npix >= 0; pptr++) 2113 { 2114 basemask = ~(gmask | bmask); 2115 common = *pptr & basemask; 2116 if (rmask) 2117 { 2118 bits = 0; 2119 base = lowbit (rmask); 2120 while(1) 2121 { 2122 pshared = *ppshared++; 2123 pshared->refcnt = 1 << (g + b); 2124 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) 2125 { 2126 if ((*cptr & basemask) == (common | bits)) 2127 { 2128 pmap->red[*cptr].fShared = TRUE; 2129 pmap->red[*cptr].co.shco.red = pshared; 2130 } 2131 } 2132 GetNextBitsOrBreak(bits, rmask, base); 2133 } 2134 } 2135 else 2136 { 2137 pshared = *ppshared++; 2138 pshared->refcnt = 1 << (g + b); 2139 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) 2140 { 2141 if ((*cptr & basemask) == common) 2142 { 2143 pmap->red[*cptr].fShared = TRUE; 2144 pmap->red[*cptr].co.shco.red = pshared; 2145 } 2146 } 2147 } 2148 basemask = ~(rmask | bmask); 2149 common = *pptr & basemask; 2150 if (gmask) 2151 { 2152 bits = 0; 2153 base = lowbit (gmask); 2154 while(1) 2155 { 2156 pshared = *ppshared++; 2157 pshared->refcnt = 1 << (r + b); 2158 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) 2159 { 2160 if ((*cptr & basemask) == (common | bits)) 2161 { 2162 pmap->red[*cptr].co.shco.green = pshared; 2163 } 2164 } 2165 GetNextBitsOrBreak(bits, gmask, base); 2166 } 2167 } 2168 else 2169 { 2170 pshared = *ppshared++; 2171 pshared->refcnt = 1 << (g + b); 2172 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) 2173 { 2174 if ((*cptr & basemask) == common) 2175 { 2176 pmap->red[*cptr].co.shco.green = pshared; 2177 } 2178 } 2179 } 2180 basemask = ~(rmask | gmask); 2181 common = *pptr & basemask; 2182 if (bmask) 2183 { 2184 bits = 0; 2185 base = lowbit (bmask); 2186 while(1) 2187 { 2188 pshared = *ppshared++; 2189 pshared->refcnt = 1 << (r + g); 2190 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) 2191 { 2192 if ((*cptr & basemask) == (common | bits)) 2193 { 2194 pmap->red[*cptr].co.shco.blue = pshared; 2195 } 2196 } 2197 GetNextBitsOrBreak(bits, bmask, base); 2198 } 2199 } 2200 else 2201 { 2202 pshared = *ppshared++; 2203 pshared->refcnt = 1 << (g + b); 2204 for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) 2205 { 2206 if ((*cptr & basemask) == common) 2207 { 2208 pmap->red[*cptr].co.shco.blue = pshared; 2209 } 2210 } 2211 } 2212 } 2213 free(psharedList); 2214 return TRUE; 2215} 2216 2217 2218/** FreeColors 2219 * Free colors and/or cells (probably slow for large numbers) 2220 */ 2221int 2222FreeColors (ColormapPtr pmap, int client, int count, Pixel *pixels, Pixel mask) 2223{ 2224 int rval, result, class; 2225 Pixel rmask; 2226 2227 class = pmap->class; 2228 if (pmap->flags & AllAllocated) 2229 return BadAccess; 2230 if ((class | DynamicClass) == DirectColor) 2231 { 2232 rmask = mask & RGBMASK(pmap->pVisual); 2233 result = FreeCo(pmap, client, REDMAP, count, pixels, 2234 mask & pmap->pVisual->redMask); 2235 /* If any of the three calls fails, we must report that, if more 2236 * than one fails, it's ok that we report the last one */ 2237 rval = FreeCo(pmap, client, GREENMAP, count, pixels, 2238 mask & pmap->pVisual->greenMask); 2239 if(rval != Success) 2240 result = rval; 2241 rval = FreeCo(pmap, client, BLUEMAP, count, pixels, 2242 mask & pmap->pVisual->blueMask); 2243 if(rval != Success) 2244 result = rval; 2245 } 2246 else 2247 { 2248 rmask = mask & ((((Pixel)1) << pmap->pVisual->nplanes) - 1); 2249 result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask); 2250 } 2251 if ((mask != rmask) && count) 2252 { 2253 clients[client]->errorValue = *pixels | mask; 2254 result = BadValue; 2255 } 2256 /* XXX should worry about removing any RT_CMAPENTRY resource */ 2257 return result; 2258} 2259 2260/** 2261 * Helper for FreeColors -- frees all combinations of *newpixels and mask bits 2262 * which the client has allocated in channel colormap cells of pmap. 2263 * doesn't change newpixels if it doesn't need to 2264 * 2265 * \param pmap which colormap head 2266 * \param color which sub-map, eg, RED, BLUE, PSEUDO 2267 * \param npixIn number of pixels passed in 2268 * \param ppixIn number of base pixels 2269 * \param mask mask client gave us 2270 */ 2271static int 2272FreeCo (ColormapPtr pmap, int client, int color, int npixIn, Pixel *ppixIn, Pixel mask) 2273{ 2274 Pixel *ppixClient, pixTest; 2275 int npixClient, npixNew, npix; 2276 Pixel bits, base, cmask, rgbbad; 2277 Pixel *pptr, *cptr; 2278 int n, zapped; 2279 int errVal = Success; 2280 int offset, numents; 2281 2282 if (npixIn == 0) 2283 return errVal; 2284 bits = 0; 2285 zapped = 0; 2286 base = lowbit (mask); 2287 2288 switch(color) 2289 { 2290 case REDMAP: 2291 cmask = pmap->pVisual->redMask; 2292 rgbbad = ~RGBMASK(pmap->pVisual); 2293 offset = pmap->pVisual->offsetRed; 2294 numents = (cmask >> offset) + 1; 2295 ppixClient = pmap->clientPixelsRed[client]; 2296 npixClient = pmap->numPixelsRed[client]; 2297 break; 2298 case GREENMAP: 2299 cmask = pmap->pVisual->greenMask; 2300 rgbbad = ~RGBMASK(pmap->pVisual); 2301 offset = pmap->pVisual->offsetGreen; 2302 numents = (cmask >> offset) + 1; 2303 ppixClient = pmap->clientPixelsGreen[client]; 2304 npixClient = pmap->numPixelsGreen[client]; 2305 break; 2306 case BLUEMAP: 2307 cmask = pmap->pVisual->blueMask; 2308 rgbbad = ~RGBMASK(pmap->pVisual); 2309 offset = pmap->pVisual->offsetBlue; 2310 numents = (cmask >> offset) + 1; 2311 ppixClient = pmap->clientPixelsBlue[client]; 2312 npixClient = pmap->numPixelsBlue[client]; 2313 break; 2314 default: /* so compiler can see that everything gets initialized */ 2315 case PSEUDOMAP: 2316 cmask = ~((Pixel)0); 2317 rgbbad = 0; 2318 offset = 0; 2319 numents = pmap->pVisual->ColormapEntries; 2320 ppixClient = pmap->clientPixelsRed[client]; 2321 npixClient = pmap->numPixelsRed[client]; 2322 break; 2323 } 2324 2325 2326 /* zap all pixels which match */ 2327 while (1) 2328 { 2329 /* go through pixel list */ 2330 for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++) 2331 { 2332 pixTest = ((*pptr | bits) & cmask) >> offset; 2333 if ((pixTest >= numents) || (*pptr & rgbbad)) 2334 { 2335 clients[client]->errorValue = *pptr | bits; 2336 errVal = BadValue; 2337 continue; 2338 } 2339 2340 /* find match in client list */ 2341 for (cptr = ppixClient, npix = npixClient; 2342 --npix >= 0 && *cptr != pixTest; 2343 cptr++) ; 2344 2345 if (npix >= 0) 2346 { 2347 if (pmap->class & DynamicClass) 2348 { 2349 FreeCell(pmap, pixTest, color); 2350 } 2351 *cptr = ~((Pixel)0); 2352 zapped++; 2353 } 2354 else 2355 errVal = BadAccess; 2356 } 2357 /* generate next bits value */ 2358 GetNextBitsOrBreak(bits, mask, base); 2359 } 2360 2361 /* delete freed pixels from client pixel list */ 2362 if (zapped) 2363 { 2364 npixNew = npixClient - zapped; 2365 if (npixNew) 2366 { 2367 /* Since the list can only get smaller, we can do a copy in 2368 * place and then realloc to a smaller size */ 2369 pptr = cptr = ppixClient; 2370 2371 /* If we have all the new pixels, we don't have to examine the 2372 * rest of the old ones */ 2373 for(npix = 0; npix < npixNew; cptr++) 2374 { 2375 if (*cptr != ~((Pixel)0)) 2376 { 2377 *pptr++ = *cptr; 2378 npix++; 2379 } 2380 } 2381 pptr = (Pixel *)realloc(ppixClient, npixNew * sizeof(Pixel)); 2382 if (pptr) 2383 ppixClient = pptr; 2384 npixClient = npixNew; 2385 } 2386 else 2387 { 2388 npixClient = 0; 2389 free(ppixClient); 2390 ppixClient = (Pixel *)NULL; 2391 } 2392 switch(color) 2393 { 2394 case PSEUDOMAP: 2395 case REDMAP: 2396 pmap->clientPixelsRed[client] = ppixClient; 2397 pmap->numPixelsRed[client] = npixClient; 2398 break; 2399 case GREENMAP: 2400 pmap->clientPixelsGreen[client] = ppixClient; 2401 pmap->numPixelsGreen[client] = npixClient; 2402 break; 2403 case BLUEMAP: 2404 pmap->clientPixelsBlue[client] = ppixClient; 2405 pmap->numPixelsBlue[client] = npixClient; 2406 break; 2407 } 2408 } 2409 return errVal; 2410} 2411 2412 2413 2414/* Redefine color values */ 2415int 2416StoreColors (ColormapPtr pmap, int count, xColorItem *defs, ClientPtr client) 2417{ 2418 Pixel pix; 2419 xColorItem *pdef; 2420 EntryPtr pent, pentT, pentLast; 2421 VisualPtr pVisual; 2422 SHAREDCOLOR *pred, *pgreen, *pblue; 2423 int n, ChgRed, ChgGreen, ChgBlue, idef; 2424 int class, errVal = Success; 2425 int ok; 2426 2427 2428 class = pmap->class; 2429 if(!(class & DynamicClass) && !(pmap->flags & BeingCreated)) 2430 { 2431 return BadAccess; 2432 } 2433 pVisual = pmap->pVisual; 2434 2435 idef = 0; 2436 if((class | DynamicClass) == DirectColor) 2437 { 2438 int numred, numgreen, numblue; 2439 Pixel rgbbad; 2440 2441 numred = NUMRED(pVisual); 2442 numgreen = NUMGREEN(pVisual); 2443 numblue = NUMBLUE(pVisual); 2444 rgbbad = ~RGBMASK(pVisual); 2445 for (pdef = defs, n = 0; n < count; pdef++, n++) 2446 { 2447 ok = TRUE; 2448 (*pmap->pScreen->ResolveColor) 2449 (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); 2450 2451 if (pdef->pixel & rgbbad) 2452 { 2453 errVal = BadValue; 2454 client->errorValue = pdef->pixel; 2455 continue; 2456 } 2457 pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed; 2458 if (pix >= numred) 2459 { 2460 errVal = BadValue; 2461 ok = FALSE; 2462 } 2463 else if (pmap->red[pix].refcnt != AllocPrivate) 2464 { 2465 errVal = BadAccess; 2466 ok = FALSE; 2467 } 2468 else if (pdef->flags & DoRed) 2469 { 2470 pmap->red[pix].co.local.red = pdef->red; 2471 } 2472 else 2473 { 2474 pdef->red = pmap->red[pix].co.local.red; 2475 } 2476 2477 pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen; 2478 if (pix >= numgreen) 2479 { 2480 errVal = BadValue; 2481 ok = FALSE; 2482 } 2483 else if (pmap->green[pix].refcnt != AllocPrivate) 2484 { 2485 errVal = BadAccess; 2486 ok = FALSE; 2487 } 2488 else if (pdef->flags & DoGreen) 2489 { 2490 pmap->green[pix].co.local.green = pdef->green; 2491 } 2492 else 2493 { 2494 pdef->green = pmap->green[pix].co.local.green; 2495 } 2496 2497 pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue; 2498 if (pix >= numblue) 2499 { 2500 errVal = BadValue; 2501 ok = FALSE; 2502 } 2503 else if (pmap->blue[pix].refcnt != AllocPrivate) 2504 { 2505 errVal = BadAccess; 2506 ok = FALSE; 2507 } 2508 else if (pdef->flags & DoBlue) 2509 { 2510 pmap->blue[pix].co.local.blue = pdef->blue; 2511 } 2512 else 2513 { 2514 pdef->blue = pmap->blue[pix].co.local.blue; 2515 } 2516 /* If this is an o.k. entry, then it gets added to the list 2517 * to be sent to the hardware. If not, skip it. Once we've 2518 * skipped one, we have to copy all the others. 2519 */ 2520 if(ok) 2521 { 2522 if(idef != n) 2523 defs[idef] = defs[n]; 2524 idef++; 2525 } else 2526 client->errorValue = pdef->pixel; 2527 } 2528 } 2529 else 2530 { 2531 for (pdef = defs, n = 0; n < count; pdef++, n++) 2532 { 2533 2534 ok = TRUE; 2535 if (pdef->pixel >= pVisual->ColormapEntries) 2536 { 2537 client->errorValue = pdef->pixel; 2538 errVal = BadValue; 2539 ok = FALSE; 2540 } 2541 else if (pmap->red[pdef->pixel].refcnt != AllocPrivate) 2542 { 2543 errVal = BadAccess; 2544 ok = FALSE; 2545 } 2546 2547 /* If this is an o.k. entry, then it gets added to the list 2548 * to be sent to the hardware. If not, skip it. Once we've 2549 * skipped one, we have to copy all the others. 2550 */ 2551 if(ok) 2552 { 2553 if(idef != n) 2554 defs[idef] = defs[n]; 2555 idef++; 2556 } 2557 else 2558 continue; 2559 2560 (*pmap->pScreen->ResolveColor) 2561 (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); 2562 2563 pent = &pmap->red[pdef->pixel]; 2564 2565 if(pdef->flags & DoRed) 2566 { 2567 if(pent->fShared) 2568 { 2569 pent->co.shco.red->color = pdef->red; 2570 if (pent->co.shco.red->refcnt > 1) 2571 ok = FALSE; 2572 } 2573 else 2574 pent->co.local.red = pdef->red; 2575 } 2576 else 2577 { 2578 if(pent->fShared) 2579 pdef->red = pent->co.shco.red->color; 2580 else 2581 pdef->red = pent->co.local.red; 2582 } 2583 if(pdef->flags & DoGreen) 2584 { 2585 if(pent->fShared) 2586 { 2587 pent->co.shco.green->color = pdef->green; 2588 if (pent->co.shco.green->refcnt > 1) 2589 ok = FALSE; 2590 } 2591 else 2592 pent->co.local.green = pdef->green; 2593 } 2594 else 2595 { 2596 if(pent->fShared) 2597 pdef->green = pent->co.shco.green->color; 2598 else 2599 pdef->green = pent->co.local.green; 2600 } 2601 if(pdef->flags & DoBlue) 2602 { 2603 if(pent->fShared) 2604 { 2605 pent->co.shco.blue->color = pdef->blue; 2606 if (pent->co.shco.blue->refcnt > 1) 2607 ok = FALSE; 2608 } 2609 else 2610 pent->co.local.blue = pdef->blue; 2611 } 2612 else 2613 { 2614 if(pent->fShared) 2615 pdef->blue = pent->co.shco.blue->color; 2616 else 2617 pdef->blue = pent->co.local.blue; 2618 } 2619 2620 if(!ok) 2621 { 2622 /* have to run through the colormap and change anybody who 2623 * shares this value */ 2624 pred = pent->co.shco.red; 2625 pgreen = pent->co.shco.green; 2626 pblue = pent->co.shco.blue; 2627 ChgRed = pdef->flags & DoRed; 2628 ChgGreen = pdef->flags & DoGreen; 2629 ChgBlue = pdef->flags & DoBlue; 2630 pentLast = pmap->red + pVisual->ColormapEntries; 2631 2632 for(pentT = pmap->red; pentT < pentLast; pentT++) 2633 { 2634 if(pentT->fShared && (pentT != pent)) 2635 { 2636 xColorItem defChg; 2637 2638 /* There are, alas, devices in this world too dumb 2639 * to read their own hardware colormaps. Sick, but 2640 * true. So we're going to be really nice and load 2641 * the xColorItem with the proper value for all the 2642 * fields. We will only set the flags for those 2643 * fields that actually change. Smart devices can 2644 * arrange to change only those fields. Dumb devices 2645 * can rest assured that we have provided for them, 2646 * and can change all three fields */ 2647 2648 defChg.flags = 0; 2649 if(ChgRed && pentT->co.shco.red == pred) 2650 { 2651 defChg.flags |= DoRed; 2652 } 2653 if(ChgGreen && pentT->co.shco.green == pgreen) 2654 { 2655 defChg.flags |= DoGreen; 2656 } 2657 if(ChgBlue && pentT->co.shco.blue == pblue) 2658 { 2659 defChg.flags |= DoBlue; 2660 } 2661 if(defChg.flags != 0) 2662 { 2663 defChg.pixel = pentT - pmap->red; 2664 defChg.red = pentT->co.shco.red->color; 2665 defChg.green = pentT->co.shco.green->color; 2666 defChg.blue = pentT->co.shco.blue->color; 2667 (*pmap->pScreen->StoreColors) (pmap, 1, &defChg); 2668 } 2669 } 2670 } 2671 2672 } 2673 } 2674 } 2675 /* Note that we use idef, the count of acceptable entries, and not 2676 * count, the count of proposed entries */ 2677 if (idef != 0) 2678 ( *pmap->pScreen->StoreColors) (pmap, idef, defs); 2679 return errVal; 2680} 2681 2682int 2683IsMapInstalled(Colormap map, WindowPtr pWin) 2684{ 2685 Colormap *pmaps; 2686 int imap, nummaps, found; 2687 2688 pmaps = malloc(pWin->drawable.pScreen->maxInstalledCmaps*sizeof(Colormap)); 2689 if(!pmaps) 2690 return FALSE; 2691 nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps) 2692 (pWin->drawable.pScreen, pmaps); 2693 found = FALSE; 2694 for(imap = 0; imap < nummaps; imap++) 2695 { 2696 if(pmaps[imap] == map) 2697 { 2698 found = TRUE; 2699 break; 2700 } 2701 } 2702 free(pmaps); 2703 return found; 2704} 2705 2706struct colormap_lookup_data { 2707 ScreenPtr pScreen; 2708 VisualPtr visuals; 2709}; 2710 2711static void _colormap_find_resource(pointer value, XID id, 2712 pointer cdata) 2713{ 2714 struct colormap_lookup_data *cmap_data = cdata; 2715 VisualPtr visuals = cmap_data->visuals; 2716 ScreenPtr pScreen = cmap_data->pScreen; 2717 ColormapPtr cmap = value; 2718 int j; 2719 2720 if (pScreen != cmap->pScreen) 2721 return; 2722 2723 j = cmap->pVisual - pScreen->visuals; 2724 cmap->pVisual = &visuals[j]; 2725} 2726 2727/* something has realloced the visuals, instead of breaking 2728 ABI fix it up here - glx and compsite did this wrong */ 2729Bool 2730ResizeVisualArray(ScreenPtr pScreen, int new_visual_count, 2731 DepthPtr depth) 2732{ 2733 struct colormap_lookup_data cdata; 2734 int numVisuals; 2735 VisualPtr visuals; 2736 XID *vids, vid; 2737 int first_new_vid, first_new_visual, i; 2738 2739 first_new_vid = depth->numVids; 2740 first_new_visual = pScreen->numVisuals; 2741 2742 vids = realloc(depth->vids, (depth->numVids + new_visual_count) * sizeof(XID)); 2743 if (!vids) 2744 return FALSE; 2745 2746 /* its realloced now no going back if we fail the next one */ 2747 depth->vids = vids; 2748 2749 numVisuals = pScreen->numVisuals + new_visual_count; 2750 visuals = realloc(pScreen->visuals, numVisuals * sizeof(VisualRec)); 2751 if (!visuals) { 2752 return FALSE; 2753 } 2754 2755 cdata.visuals = visuals; 2756 cdata.pScreen = pScreen; 2757 FindClientResourcesByType(serverClient, RT_COLORMAP, _colormap_find_resource, &cdata); 2758 2759 pScreen->visuals = visuals; 2760 2761 for (i = 0; i < new_visual_count; i++) { 2762 vid = FakeClientID(0); 2763 pScreen->visuals[first_new_visual + i].vid = vid; 2764 vids[first_new_vid + i] = vid; 2765 } 2766 2767 depth->numVids += new_visual_count; 2768 pScreen->numVisuals += new_visual_count; 2769 2770 return TRUE; 2771} 2772