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