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