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