1 /*
2  * Copyright (c) 1987, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /*
25  * This is based on cfbcmap.c.  The functions here are useful independently
26  * of cfb, which is the reason for including them here.  How "mi" these
27  * are may be debatable.
28  */
29 
30 #ifdef HAVE_DIX_CONFIG_H
31 #include <dix-config.h>
32 #endif
33 
34 #include <X11/X.h>
35 #include <X11/Xproto.h>
36 #include "scrnintstr.h"
37 #include "colormapst.h"
38 #include "resource.h"
39 #include "globals.h"
40 #include "micmap.h"
41 
42 DevPrivateKeyRec micmapScrPrivateKeyRec;
43 
44 int
miListInstalledColormaps(ScreenPtr pScreen,Colormap * pmaps)45 miListInstalledColormaps(ScreenPtr pScreen, Colormap * pmaps)
46 {
47     if (GetInstalledmiColormap(pScreen)) {
48         *pmaps = GetInstalledmiColormap(pScreen)->mid;
49         return 1;
50     }
51     return 0;
52 }
53 
54 void
miInstallColormap(ColormapPtr pmap)55 miInstallColormap(ColormapPtr pmap)
56 {
57     ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen);
58 
59     if (pmap != oldpmap) {
60         /* Uninstall pInstalledMap. No hardware changes required, just
61          * notify all interested parties. */
62         if (oldpmap != (ColormapPtr) None)
63             WalkTree(pmap->pScreen, TellLostMap, (char *) &oldpmap->mid);
64         /* Install pmap */
65         SetInstalledmiColormap(pmap->pScreen, pmap);
66         WalkTree(pmap->pScreen, TellGainedMap, (char *) &pmap->mid);
67 
68     }
69 }
70 
71 void
miUninstallColormap(ColormapPtr pmap)72 miUninstallColormap(ColormapPtr pmap)
73 {
74     ColormapPtr curpmap = GetInstalledmiColormap(pmap->pScreen);
75 
76     if (pmap == curpmap) {
77         if (pmap->mid != pmap->pScreen->defColormap) {
78             dixLookupResourceByType((void **) &curpmap,
79                                     pmap->pScreen->defColormap,
80                                     RT_COLORMAP, serverClient, DixUseAccess);
81             (*pmap->pScreen->InstallColormap) (curpmap);
82         }
83     }
84 }
85 
86 void
miResolveColor(unsigned short * pred,unsigned short * pgreen,unsigned short * pblue,VisualPtr pVisual)87 miResolveColor(unsigned short *pred, unsigned short *pgreen,
88                unsigned short *pblue, VisualPtr pVisual)
89 {
90     int shift = 16 - pVisual->bitsPerRGBValue;
91     unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1;
92 
93     if ((pVisual->class | DynamicClass) == GrayScale) {
94         /* rescale to gray then rgb bits */
95         *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100;
96         *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim;
97     }
98     else {
99         /* rescale to rgb bits */
100         *pred = ((*pred >> shift) * 65535) / lim;
101         *pgreen = ((*pgreen >> shift) * 65535) / lim;
102         *pblue = ((*pblue >> shift) * 65535) / lim;
103     }
104 }
105 
106 Bool
miInitializeColormap(ColormapPtr pmap)107 miInitializeColormap(ColormapPtr pmap)
108 {
109     unsigned i;
110     VisualPtr pVisual;
111     unsigned lim, maxent, shift;
112 
113     pVisual = pmap->pVisual;
114     lim = (1 << pVisual->bitsPerRGBValue) - 1;
115     shift = 16 - pVisual->bitsPerRGBValue;
116     maxent = pVisual->ColormapEntries - 1;
117     if (pVisual->class == TrueColor) {
118         unsigned limr, limg, limb;
119 
120         limr = pVisual->redMask >> pVisual->offsetRed;
121         limg = pVisual->greenMask >> pVisual->offsetGreen;
122         limb = pVisual->blueMask >> pVisual->offsetBlue;
123         for (i = 0; i <= maxent; i++) {
124             /* rescale to [0..65535] then rgb bits */
125             pmap->red[i].co.local.red =
126                 ((((i * 65535) / limr) >> shift) * 65535) / lim;
127             pmap->green[i].co.local.green =
128                 ((((i * 65535) / limg) >> shift) * 65535) / lim;
129             pmap->blue[i].co.local.blue =
130                 ((((i * 65535) / limb) >> shift) * 65535) / lim;
131         }
132     }
133     else if (pVisual->class == StaticColor) {
134         unsigned limr, limg, limb;
135 
136         limr = pVisual->redMask >> pVisual->offsetRed;
137         limg = pVisual->greenMask >> pVisual->offsetGreen;
138         limb = pVisual->blueMask >> pVisual->offsetBlue;
139         for (i = 0; i <= maxent; i++) {
140             /* rescale to [0..65535] then rgb bits */
141             pmap->red[i].co.local.red =
142                 ((((((i & pVisual->redMask) >> pVisual->offsetRed)
143                     * 65535) / limr) >> shift) * 65535) / lim;
144             pmap->red[i].co.local.green =
145                 ((((((i & pVisual->greenMask) >> pVisual->offsetGreen)
146                     * 65535) / limg) >> shift) * 65535) / lim;
147             pmap->red[i].co.local.blue =
148                 ((((((i & pVisual->blueMask) >> pVisual->offsetBlue)
149                     * 65535) / limb) >> shift) * 65535) / lim;
150         }
151     }
152     else if (pVisual->class == StaticGray) {
153         for (i = 0; i <= maxent; i++) {
154             /* rescale to [0..65535] then rgb bits */
155             pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift)
156                                          * 65535) / lim;
157             pmap->red[i].co.local.green = pmap->red[i].co.local.red;
158             pmap->red[i].co.local.blue = pmap->red[i].co.local.red;
159         }
160     }
161     return TRUE;
162 }
163 
164 /* When simulating DirectColor on PseudoColor hardware, multiple
165    entries of the colormap must be updated
166  */
167 
168 #define AddElement(mask) { \
169     pixel = red | green | blue; \
170     for (i = 0; i < nresult; i++) \
171   	if (outdefs[i].pixel == pixel) \
172     	    break; \
173     if (i == nresult) \
174     { \
175    	nresult++; \
176 	outdefs[i].pixel = pixel; \
177 	outdefs[i].flags = 0; \
178     } \
179     outdefs[i].flags |= (mask); \
180     outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \
181     outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \
182     outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \
183 }
184 
185 int
miExpandDirectColors(ColormapPtr pmap,int ndef,xColorItem * indefs,xColorItem * outdefs)186 miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem * indefs,
187                      xColorItem * outdefs)
188 {
189     int red, green, blue;
190     int maxred, maxgreen, maxblue;
191     int stepred, stepgreen, stepblue;
192     VisualPtr pVisual;
193     int pixel;
194     int nresult;
195     int i;
196 
197     pVisual = pmap->pVisual;
198 
199     stepred = 1 << pVisual->offsetRed;
200     stepgreen = 1 << pVisual->offsetGreen;
201     stepblue = 1 << pVisual->offsetBlue;
202     maxred = pVisual->redMask;
203     maxgreen = pVisual->greenMask;
204     maxblue = pVisual->blueMask;
205     nresult = 0;
206     for (; ndef--; indefs++) {
207         if (indefs->flags & DoRed) {
208             red = indefs->pixel & pVisual->redMask;
209             for (green = 0; green <= maxgreen; green += stepgreen) {
210                 for (blue = 0; blue <= maxblue; blue += stepblue) {
211                     AddElement(DoRed)
212                 }
213             }
214         }
215         if (indefs->flags & DoGreen) {
216             green = indefs->pixel & pVisual->greenMask;
217             for (red = 0; red <= maxred; red += stepred) {
218                 for (blue = 0; blue <= maxblue; blue += stepblue) {
219                     AddElement(DoGreen)
220                 }
221             }
222         }
223         if (indefs->flags & DoBlue) {
224             blue = indefs->pixel & pVisual->blueMask;
225             for (red = 0; red <= maxred; red += stepred) {
226                 for (green = 0; green <= maxgreen; green += stepgreen) {
227                     AddElement(DoBlue)
228                 }
229             }
230         }
231     }
232     return nresult;
233 }
234 
235 Bool
miCreateDefColormap(ScreenPtr pScreen)236 miCreateDefColormap(ScreenPtr pScreen)
237 {
238     unsigned short zero = 0, ones = 0xFFFF;
239     Pixel wp, bp;
240     VisualPtr pVisual;
241     ColormapPtr cmap;
242     int alloctype;
243 
244     if (!dixRegisterPrivateKey(&micmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
245         return FALSE;
246 
247     for (pVisual = pScreen->visuals;
248          pVisual->vid != pScreen->rootVisual; pVisual++);
249 
250     if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass))
251         alloctype = AllocNone;
252     else
253         alloctype = AllocAll;
254 
255     if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap,
256                        alloctype, 0) != Success)
257         return FALSE;
258 
259     if (pScreen->rootDepth > 1) {
260         wp = pScreen->whitePixel;
261         bp = pScreen->blackPixel;
262         if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) !=
263              Success) ||
264             (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != Success))
265             return FALSE;
266         pScreen->whitePixel = wp;
267         pScreen->blackPixel = bp;
268     }
269 
270     (*pScreen->InstallColormap) (cmap);
271     return TRUE;
272 }
273 
274 /*
275  * Default true color bitmasks, should be overridden by
276  * driver
277  */
278 
279 #define _RZ(d) ((d + 2) / 3)
280 #define _RS(d) 0
281 #define _RM(d) ((1U << _RZ(d)) - 1)
282 #define _GZ(d) ((d - _RZ(d) + 1) / 2)
283 #define _GS(d) _RZ(d)
284 #define _GM(d) (((1U << _GZ(d)) - 1) << _GS(d))
285 #define _BZ(d) (d - _RZ(d) - _GZ(d))
286 #define _BS(d) (_RZ(d) + _GZ(d))
287 #define _BM(d) (((1U << _BZ(d)) - 1) << _BS(d))
288 #define _CE(d) (1U << _RZ(d))
289 
290 typedef struct _miVisuals {
291     struct _miVisuals *next;
292     int depth;
293     int bitsPerRGB;
294     int visuals;
295     int count;
296     int preferredCVC;
297     Pixel redMask, greenMask, blueMask;
298 } miVisualsRec, *miVisualsPtr;
299 
300 static int miVisualPriority[] = {
301     PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray
302 };
303 
304 #define NUM_PRIORITY	6
305 
306 static miVisualsPtr miVisuals;
307 
308 void
miClearVisualTypes(void)309 miClearVisualTypes(void)
310 {
311     miVisualsPtr v;
312 
313     while ((v = miVisuals)) {
314         miVisuals = v->next;
315         free(v);
316     }
317 }
318 
319 Bool
miSetVisualTypesAndMasks(int depth,int visuals,int bitsPerRGB,int preferredCVC,Pixel redMask,Pixel greenMask,Pixel blueMask)320 miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
321                          int preferredCVC,
322                          Pixel redMask, Pixel greenMask, Pixel blueMask)
323 {
324     miVisualsPtr new, *prev, v;
325     int count;
326 
327     new = malloc(sizeof *new);
328     if (!new)
329         return FALSE;
330     if (!redMask || !greenMask || !blueMask) {
331         redMask = _RM(depth);
332         greenMask = _GM(depth);
333         blueMask = _BM(depth);
334     }
335     new->next = 0;
336     new->depth = depth;
337     new->visuals = visuals;
338     new->bitsPerRGB = bitsPerRGB;
339     new->preferredCVC = preferredCVC;
340     new->redMask = redMask;
341     new->greenMask = greenMask;
342     new->blueMask = blueMask;
343     count = (visuals >> 1) & 033333333333;
344     count = visuals - count - ((count >> 1) & 033333333333);
345     count = (((count + (count >> 3)) & 030707070707) % 077);    /* HAKMEM 169 */
346     new->count = count;
347     for (prev = &miVisuals; (v = *prev); prev = &v->next);
348     *prev = new;
349     return TRUE;
350 }
351 
352 Bool
miSetVisualTypes(int depth,int visuals,int bitsPerRGB,int preferredCVC)353 miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC)
354 {
355     return miSetVisualTypesAndMasks(depth, visuals, bitsPerRGB,
356                                     preferredCVC, 0, 0, 0);
357 }
358 
359 int
miGetDefaultVisualMask(int depth)360 miGetDefaultVisualMask(int depth)
361 {
362     if (depth > MAX_PSEUDO_DEPTH)
363         return LARGE_VISUALS;
364     else if (depth >= MIN_TRUE_DEPTH)
365         return ALL_VISUALS;
366     else if (depth == 1)
367         return StaticGrayMask;
368     else
369         return SMALL_VISUALS;
370 }
371 
372 static Bool
miVisualTypesSet(int depth)373 miVisualTypesSet(int depth)
374 {
375     miVisualsPtr visuals;
376 
377     for (visuals = miVisuals; visuals; visuals = visuals->next)
378         if (visuals->depth == depth)
379             return TRUE;
380     return FALSE;
381 }
382 
383 Bool
miSetPixmapDepths(void)384 miSetPixmapDepths(void)
385 {
386     int d, f;
387 
388     /* Add any unlisted depths from the pixmap formats */
389     for (f = 0; f < screenInfo.numPixmapFormats; f++) {
390         d = screenInfo.formats[f].depth;
391         if (!miVisualTypesSet(d)) {
392             if (!miSetVisualTypes(d, 0, 0, -1))
393                 return FALSE;
394         }
395     }
396     return TRUE;
397 }
398 
399 /*
400  * Distance to least significant one bit
401  */
402 static int
maskShift(Pixel p)403 maskShift(Pixel p)
404 {
405     int s;
406 
407     if (!p)
408         return 0;
409     s = 0;
410     while (!(p & 1)) {
411         s++;
412         p >>= 1;
413     }
414     return s;
415 }
416 
417 /*
418  * Given a list of formats for a screen, create a list
419  * of visuals and depths for the screen which correspond to
420  * the set which can be used with this version of cfb.
421  */
422 
423 Bool
miInitVisuals(VisualPtr * visualp,DepthPtr * depthp,int * nvisualp,int * ndepthp,int * rootDepthp,VisualID * defaultVisp,unsigned long sizes,int bitsPerRGB,int preferredVis)424 miInitVisuals(VisualPtr * visualp, DepthPtr * depthp, int *nvisualp,
425               int *ndepthp, int *rootDepthp, VisualID * defaultVisp,
426               unsigned long sizes, int bitsPerRGB, int preferredVis)
427 {
428     int i, j = 0, k;
429     VisualPtr visual;
430     DepthPtr depth;
431     VisualID *vid;
432     int d, b;
433     int f;
434     int ndepth, nvisual;
435     int nvtype;
436     int vtype;
437     miVisualsPtr visuals, nextVisuals;
438     int *preferredCVCs, *prefp;
439     int first_depth;
440 
441     /* none specified, we'll guess from pixmap formats */
442     if (!miVisuals) {
443         for (f = 0; f < screenInfo.numPixmapFormats; f++) {
444             d = screenInfo.formats[f].depth;
445             b = screenInfo.formats[f].bitsPerPixel;
446             if (sizes & (1 << (b - 1)))
447                 vtype = miGetDefaultVisualMask(d);
448             else
449                 vtype = 0;
450             if (!miSetVisualTypes(d, vtype, bitsPerRGB, -1))
451                 return FALSE;
452         }
453     }
454     nvisual = 0;
455     ndepth = 0;
456     for (visuals = miVisuals; visuals; visuals = nextVisuals) {
457         nextVisuals = visuals->next;
458         ndepth++;
459         nvisual += visuals->count;
460     }
461     depth = xallocarray(ndepth, sizeof(DepthRec));
462     visual = xallocarray(nvisual, sizeof(VisualRec));
463     preferredCVCs = xallocarray(ndepth, sizeof(int));
464     if (!depth || !visual || !preferredCVCs) {
465         free(depth);
466         free(visual);
467         free(preferredCVCs);
468         return FALSE;
469     }
470     *depthp = depth;
471     *visualp = visual;
472     *ndepthp = ndepth;
473     *nvisualp = nvisual;
474     prefp = preferredCVCs;
475     for (visuals = miVisuals; visuals; visuals = nextVisuals) {
476         nextVisuals = visuals->next;
477         d = visuals->depth;
478         vtype = visuals->visuals;
479         nvtype = visuals->count;
480         *prefp = visuals->preferredCVC;
481         prefp++;
482         vid = NULL;
483         if (nvtype) {
484             vid = xallocarray(nvtype, sizeof(VisualID));
485             if (!vid) {
486                 free(depth);
487                 free(visual);
488                 free(preferredCVCs);
489                 return FALSE;
490             }
491         }
492         depth->depth = d;
493         depth->numVids = nvtype;
494         depth->vids = vid;
495         depth++;
496         for (i = 0; i < NUM_PRIORITY; i++) {
497             if (!(vtype & (1 << miVisualPriority[i])))
498                 continue;
499             visual->class = miVisualPriority[i];
500             visual->bitsPerRGBValue = visuals->bitsPerRGB;
501             visual->ColormapEntries = 1 << d;
502             visual->nplanes = d;
503             visual->vid = *vid = FakeClientID(0);
504             switch (visual->class) {
505             case PseudoColor:
506             case GrayScale:
507             case StaticGray:
508                 visual->redMask = 0;
509                 visual->greenMask = 0;
510                 visual->blueMask = 0;
511                 visual->offsetRed = 0;
512                 visual->offsetGreen = 0;
513                 visual->offsetBlue = 0;
514                 break;
515             case DirectColor:
516             case TrueColor:
517                 visual->ColormapEntries = _CE(d);
518                 /* fall through */
519             case StaticColor:
520                 visual->redMask = visuals->redMask;
521                 visual->greenMask = visuals->greenMask;
522                 visual->blueMask = visuals->blueMask;
523                 visual->offsetRed = maskShift(visuals->redMask);
524                 visual->offsetGreen = maskShift(visuals->greenMask);
525                 visual->offsetBlue = maskShift(visuals->blueMask);
526             }
527             vid++;
528             visual++;
529         }
530         free(visuals);
531     }
532     miVisuals = NULL;
533     visual = *visualp;
534     depth = *depthp;
535 
536     /*
537      * if we did not supplyied by a preferred visual class
538      * check if there is a preferred class in one of the depth
539      * structures - if there is, we want to start looking for the
540      * default visual/depth from that depth.
541      */
542     first_depth = 0;
543     if (preferredVis < 0 && defaultColorVisualClass < 0) {
544         for (i = 0; i < ndepth; i++) {
545             if (preferredCVCs[i] >= 0) {
546                 first_depth = i;
547                 break;
548             }
549         }
550     }
551 
552     for (i = first_depth; i < ndepth; i++) {
553         int prefColorVisualClass = -1;
554 
555         if (defaultColorVisualClass >= 0)
556             prefColorVisualClass = defaultColorVisualClass;
557         else if (preferredVis >= 0)
558             prefColorVisualClass = preferredVis;
559         else if (preferredCVCs[i] >= 0)
560             prefColorVisualClass = preferredCVCs[i];
561 
562         if (*rootDepthp && *rootDepthp != depth[i].depth)
563             continue;
564 
565         for (j = 0; j < depth[i].numVids; j++) {
566             for (k = 0; k < nvisual; k++)
567                 if (visual[k].vid == depth[i].vids[j])
568                     break;
569             if (k == nvisual)
570                 continue;
571             if (prefColorVisualClass < 0 ||
572                 visual[k].class == prefColorVisualClass)
573                 break;
574         }
575         if (j != depth[i].numVids)
576             break;
577     }
578     if (i == ndepth) {
579         i = 0;
580         j = 0;
581     }
582     *rootDepthp = depth[i].depth;
583     *defaultVisp = depth[i].vids[j];
584     free(preferredCVCs);
585 
586     return TRUE;
587 }
588