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