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
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <X11/X.h>
36#include <X11/Xproto.h>
37#include "scrnintstr.h"
38#include "colormapst.h"
39#include "resource.h"
40#include "globals.h"
41#include "micmap.h"
42
43DevPrivateKeyRec micmapScrPrivateKeyRec;
44
45int
46miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
47{
48    if (GetInstalledmiColormap(pScreen)) {
49	*pmaps = GetInstalledmiColormap(pScreen)->mid;
50	return 1;
51    }
52    return 0;
53}
54
55void
56miInstallColormap(ColormapPtr pmap)
57{
58    ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen);
59
60    if(pmap != oldpmap)
61    {
62	/* Uninstall pInstalledMap. No hardware changes required, just
63	 * notify all interested parties. */
64	if(oldpmap != (ColormapPtr)None)
65	    WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
66	/* Install pmap */
67	SetInstalledmiColormap(pmap->pScreen, pmap);
68	WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
69
70    }
71}
72
73void
74miUninstallColormap(ColormapPtr pmap)
75{
76    ColormapPtr curpmap = GetInstalledmiColormap(pmap->pScreen);
77
78    if(pmap == curpmap)
79    {
80	if (pmap->mid != pmap->pScreen->defColormap)
81	{
82	    dixLookupResourceByType((pointer *)&curpmap,
83				    pmap->pScreen->defColormap,
84				    RT_COLORMAP, serverClient,
85				    DixUseAccess);
86	    (*pmap->pScreen->InstallColormap)(curpmap);
87	}
88    }
89}
90
91void
92miResolveColor(unsigned short *pred, unsigned short *pgreen,
93		unsigned short *pblue, VisualPtr pVisual)
94{
95    int shift = 16 - pVisual->bitsPerRGBValue;
96    unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1;
97
98    if ((pVisual->class | DynamicClass) == GrayScale)
99    {
100	/* rescale to gray then rgb bits */
101	*pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100;
102	*pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim;
103    }
104    else
105    {
106	/* rescale to rgb bits */
107	*pred = ((*pred >> shift) * 65535) / lim;
108	*pgreen = ((*pgreen >> shift) * 65535) / lim;
109	*pblue = ((*pblue >> shift) * 65535) / lim;
110    }
111}
112
113Bool
114miInitializeColormap(ColormapPtr pmap)
115{
116    unsigned i;
117    VisualPtr pVisual;
118    unsigned lim, maxent, shift;
119
120    pVisual = pmap->pVisual;
121    lim = (1 << pVisual->bitsPerRGBValue) - 1;
122    shift = 16 - pVisual->bitsPerRGBValue;
123    maxent = pVisual->ColormapEntries - 1;
124    if (pVisual->class == TrueColor)
125    {
126	unsigned limr, limg, limb;
127
128	limr = pVisual->redMask >> pVisual->offsetRed;
129	limg = pVisual->greenMask >> pVisual->offsetGreen;
130	limb = pVisual->blueMask >> pVisual->offsetBlue;
131	for(i = 0; i <= maxent; i++)
132	{
133	    /* rescale to [0..65535] then rgb bits */
134	    pmap->red[i].co.local.red =
135		((((i * 65535) / limr) >> shift) * 65535) / lim;
136	    pmap->green[i].co.local.green =
137		((((i * 65535) / limg) >> shift) * 65535) / lim;
138	    pmap->blue[i].co.local.blue =
139		((((i * 65535) / limb) >> shift) * 65535) / lim;
140	}
141    }
142    else if (pVisual->class == StaticColor)
143    {
144	unsigned limr, limg, limb;
145
146	limr = pVisual->redMask >> pVisual->offsetRed;
147	limg = pVisual->greenMask >> pVisual->offsetGreen;
148	limb = pVisual->blueMask >> pVisual->offsetBlue;
149	for(i = 0; i <= maxent; i++)
150	{
151	    /* rescale to [0..65535] then rgb bits */
152	    pmap->red[i].co.local.red =
153		((((((i & pVisual->redMask) >> pVisual->offsetRed)
154		    * 65535) / limr) >> shift) * 65535) / lim;
155	    pmap->red[i].co.local.green =
156		((((((i & pVisual->greenMask) >> pVisual->offsetGreen)
157		    * 65535) / limg) >> shift) * 65535) / lim;
158	    pmap->red[i].co.local.blue =
159		((((((i & pVisual->blueMask) >> pVisual->offsetBlue)
160		    * 65535) / limb) >> shift) * 65535) / lim;
161	}
162    }
163    else if (pVisual->class == StaticGray)
164    {
165	for(i = 0; i <= maxent; i++)
166	{
167	    /* rescale to [0..65535] then rgb bits */
168	    pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift)
169					 * 65535) / lim;
170	    pmap->red[i].co.local.green = pmap->red[i].co.local.red;
171	    pmap->red[i].co.local.blue = pmap->red[i].co.local.red;
172	}
173    }
174    return TRUE;
175}
176
177/* When simulating DirectColor on PseudoColor hardware, multiple
178   entries of the colormap must be updated
179 */
180
181#define AddElement(mask) { \
182    pixel = red | green | blue; \
183    for (i = 0; i < nresult; i++) \
184  	if (outdefs[i].pixel == pixel) \
185    	    break; \
186    if (i == nresult) \
187    { \
188   	nresult++; \
189	outdefs[i].pixel = pixel; \
190	outdefs[i].flags = 0; \
191    } \
192    outdefs[i].flags |= (mask); \
193    outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \
194    outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \
195    outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \
196}
197
198int
199miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs,
200			xColorItem *outdefs)
201{
202    int	        red, green, blue;
203    int	        maxred, maxgreen, maxblue;
204    int	        stepred, stepgreen, stepblue;
205    VisualPtr   pVisual;
206    int         pixel;
207    int         nresult;
208    int         i;
209
210    pVisual = pmap->pVisual;
211
212    stepred = 1 << pVisual->offsetRed;
213    stepgreen = 1 << pVisual->offsetGreen;
214    stepblue = 1 << pVisual->offsetBlue;
215    maxred = pVisual->redMask;
216    maxgreen = pVisual->greenMask;
217    maxblue = pVisual->blueMask;
218    nresult = 0;
219    for (;ndef--; indefs++)
220    {
221	if (indefs->flags & DoRed)
222	{
223	    red = indefs->pixel & pVisual->redMask;
224    	    for (green = 0; green <= maxgreen; green += stepgreen)
225    	    {
226	    	for (blue = 0; blue <= maxblue; blue += stepblue)
227	    	{
228		    AddElement (DoRed)
229	    	}
230    	    }
231	}
232	if (indefs->flags & DoGreen)
233	{
234	    green = indefs->pixel & pVisual->greenMask;
235    	    for (red = 0; red <= maxred; red += stepred)
236    	    {
237	    	for (blue = 0; blue <= maxblue; blue += stepblue)
238	    	{
239		    AddElement (DoGreen)
240	    	}
241    	    }
242	}
243	if (indefs->flags & DoBlue)
244	{
245	    blue = indefs->pixel & pVisual->blueMask;
246    	    for (red = 0; red <= maxred; red += stepred)
247    	    {
248	    	for (green = 0; green <= maxgreen; green += stepgreen)
249	    	{
250		    AddElement (DoBlue)
251	    	}
252    	    }
253	}
254    }
255    return nresult;
256}
257
258Bool
259miCreateDefColormap(ScreenPtr pScreen)
260{
261/*
262 * In the following sources PC X server vendors may want to delete
263 * "_not_tog" from "#ifdef WIN32_not_tog"
264 */
265#ifdef WIN32_not_tog
266    /*
267     * these are the MS-Windows desktop colors, adjusted for X's 16-bit
268     * color specifications.
269     */
270    static xColorItem citems[] = {
271	{   0,      0,      0,      0, 0, 0 },
272	{   1, 0x8000,      0,      0, 0, 0 },
273	{   2,      0, 0x8000,      0, 0, 0 },
274	{   3, 0x8000, 0x8000,      0, 0, 0 },
275	{   4,      0,      0, 0x8000, 0, 0 },
276	{   5, 0x8000,      0, 0x8000, 0, 0 },
277	{   6,      0, 0x8000, 0x8000, 0, 0 },
278	{   7, 0xc000, 0xc000, 0xc000, 0, 0 },
279	{   8, 0xc000, 0xdc00, 0xc000, 0, 0 },
280	{   9, 0xa600, 0xca00, 0xf000, 0, 0 },
281	{ 246, 0xff00, 0xfb00, 0xf000, 0, 0 },
282	{ 247, 0xa000, 0xa000, 0xa400, 0, 0 },
283	{ 248, 0x8000, 0x8000, 0x8000, 0, 0 },
284	{ 249, 0xff00,      0,      0, 0, 0 },
285	{ 250,      0, 0xff00,      0, 0, 0 },
286	{ 251, 0xff00, 0xff00,      0, 0, 0 },
287	{ 252,      0,      0, 0xff00, 0, 0 },
288	{ 253, 0xff00,      0, 0xff00, 0, 0 },
289	{ 254,      0, 0xff00, 0xff00, 0, 0 },
290	{ 255, 0xff00, 0xff00, 0xff00, 0, 0 }
291    };
292#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0]
293    int i;
294#else
295    unsigned short	zero = 0, ones = 0xFFFF;
296#endif
297    Pixel wp, bp;
298    VisualPtr	pVisual;
299    ColormapPtr	cmap;
300    int alloctype;
301
302    if (!dixRegisterPrivateKey(&micmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
303	return FALSE;
304
305    for (pVisual = pScreen->visuals;
306	 pVisual->vid != pScreen->rootVisual;
307	 pVisual++)
308	;
309
310    if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass))
311	alloctype = AllocNone;
312    else
313	alloctype = AllocAll;
314
315    if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap,
316		       alloctype, 0) != Success)
317	return FALSE;
318
319    if (pScreen->rootDepth > 1) {
320	wp = pScreen->whitePixel;
321	bp = pScreen->blackPixel;
322#ifdef WIN32_not_tog
323	for (i = 0; i < NUM_DESKTOP_COLORS; i++) {
324	    if (AllocColor (cmap,
325			    &citems[i].red, &citems[i].green, &citems[i].blue,
326			    &citems[i].pixel, 0) != Success)
327		return FALSE;
328	}
329#else
330	if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) !=
331       	       Success) ||
332	    (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) !=
333       	       Success))
334    	    return FALSE;
335	pScreen->whitePixel = wp;
336	pScreen->blackPixel = bp;
337#endif
338    }
339
340    (*pScreen->InstallColormap)(cmap);
341    return TRUE;
342}
343
344/*
345 * Default true color bitmasks, should be overridden by
346 * driver
347 */
348
349#define _RZ(d) ((d + 2) / 3)
350#define _RS(d) 0
351#define _RM(d) ((1 << _RZ(d)) - 1)
352#define _GZ(d) ((d - _RZ(d) + 1) / 2)
353#define _GS(d) _RZ(d)
354#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d))
355#define _BZ(d) (d - _RZ(d) - _GZ(d))
356#define _BS(d) (_RZ(d) + _GZ(d))
357#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d))
358#define _CE(d) (1 << _RZ(d))
359
360typedef struct _miVisuals {
361    struct _miVisuals	*next;
362    int			depth;
363    int			bitsPerRGB;
364    int			visuals;
365    int			count;
366    int			preferredCVC;
367    Pixel		redMask, greenMask, blueMask;
368} miVisualsRec, *miVisualsPtr;
369
370static int  miVisualPriority[] = {
371    PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray
372};
373
374#define NUM_PRIORITY	6
375
376static miVisualsPtr	miVisuals;
377
378void
379miClearVisualTypes(void)
380{
381    miVisualsPtr v;
382
383    while ((v = miVisuals)) {
384	miVisuals = v->next;
385	free(v);
386    }
387}
388
389
390Bool
391miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
392			 int preferredCVC,
393			 Pixel redMask, Pixel greenMask, Pixel blueMask)
394{
395    miVisualsPtr   new, *prev, v;
396    int		    count;
397
398    new = malloc(sizeof *new);
399    if (!new)
400	return FALSE;
401    if (!redMask || !greenMask || !blueMask)
402    {
403	redMask = _RM(depth);
404	greenMask = _GM(depth);
405	blueMask = _BM(depth);
406    }
407    new->next = 0;
408    new->depth = depth;
409    new->visuals = visuals;
410    new->bitsPerRGB = bitsPerRGB;
411    new->preferredCVC = preferredCVC;
412    new->redMask = redMask;
413    new->greenMask = greenMask;
414    new->blueMask = blueMask;
415    count = (visuals >> 1) & 033333333333;
416    count = visuals - count - ((count >> 1) & 033333333333);
417    count = (((count + (count >> 3)) & 030707070707) % 077);	/* HAKMEM 169 */
418    new->count = count;
419    for (prev = &miVisuals; (v = *prev); prev = &v->next);
420    *prev = new;
421    return TRUE;
422}
423
424Bool
425miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC)
426{
427    return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB,
428				     preferredCVC, 0, 0, 0);
429}
430
431int
432miGetDefaultVisualMask(int depth)
433{
434    if (depth > MAX_PSEUDO_DEPTH)
435	return LARGE_VISUALS;
436    else if (depth >= MIN_TRUE_DEPTH)
437	return ALL_VISUALS;
438    else if (depth == 1)
439	return StaticGrayMask;
440    else
441	return SMALL_VISUALS;
442}
443
444static Bool
445miVisualTypesSet (int depth)
446{
447    miVisualsPtr    visuals;
448
449    for (visuals = miVisuals; visuals; visuals = visuals->next)
450	if (visuals->depth == depth)
451	    return TRUE;
452    return FALSE;
453}
454
455Bool
456miSetPixmapDepths (void)
457{
458    int	d, f;
459
460    /* Add any unlisted depths from the pixmap formats */
461    for (f = 0; f < screenInfo.numPixmapFormats; f++)
462    {
463	d = screenInfo.formats[f].depth;
464	if (!miVisualTypesSet (d))
465	{
466	    if (!miSetVisualTypes (d, 0, 0, -1))
467		return FALSE;
468	}
469    }
470    return TRUE;
471}
472
473/*
474 * Distance to least significant one bit
475 */
476static int
477maskShift (Pixel p)
478{
479    int	s;
480
481    if (!p) return 0;
482    s = 0;
483    while (!(p & 1))
484    {
485	s++;
486	p >>= 1;
487    }
488    return s;
489}
490
491/*
492 * Given a list of formats for a screen, create a list
493 * of visuals and depths for the screen which corespond to
494 * the set which can be used with this version of cfb.
495 */
496
497Bool
498miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
499		int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
500		unsigned long sizes, int bitsPerRGB, int preferredVis)
501
502{
503    int		i, j = 0, k;
504    VisualPtr	visual;
505    DepthPtr	depth;
506    VisualID	*vid;
507    int		d, b;
508    int		f;
509    int		ndepth, nvisual;
510    int		nvtype;
511    int		vtype;
512    miVisualsPtr   visuals, nextVisuals;
513    int		*preferredCVCs, *prefp;
514    int		first_depth;
515
516    /* none specified, we'll guess from pixmap formats */
517    if (!miVisuals)
518    {
519    	for (f = 0; f < screenInfo.numPixmapFormats; f++)
520    	{
521	    d = screenInfo.formats[f].depth;
522	    b = screenInfo.formats[f].bitsPerPixel;
523	    if (sizes & (1 << (b - 1)))
524		vtype = miGetDefaultVisualMask(d);
525	    else
526		vtype = 0;
527	    if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1))
528		return FALSE;
529    	}
530    }
531    nvisual = 0;
532    ndepth = 0;
533    for (visuals = miVisuals; visuals; visuals = nextVisuals)
534    {
535	nextVisuals = visuals->next;
536	ndepth++;
537	nvisual += visuals->count;
538    }
539    depth = malloc(ndepth * sizeof (DepthRec));
540    visual = malloc(nvisual * sizeof (VisualRec));
541    preferredCVCs = malloc(ndepth * sizeof(int));
542    if (!depth || !visual || !preferredCVCs)
543    {
544	free(depth);
545	free(visual);
546	free(preferredCVCs);
547	return FALSE;
548    }
549    *depthp = depth;
550    *visualp = visual;
551    *ndepthp = ndepth;
552    *nvisualp = nvisual;
553    prefp = preferredCVCs;
554    for (visuals = miVisuals; visuals; visuals = nextVisuals)
555    {
556	nextVisuals = visuals->next;
557	d = visuals->depth;
558	vtype = visuals->visuals;
559	nvtype = visuals->count;
560	*prefp = visuals->preferredCVC;
561	prefp++;
562	vid = NULL;
563	if (nvtype)
564	{
565	    vid = malloc(nvtype * sizeof (VisualID));
566	    if (!vid) {
567	        free(depth);
568	        free(visual);
569		free(preferredCVCs);
570		return FALSE;
571	    }
572	}
573	depth->depth = d;
574	depth->numVids = nvtype;
575	depth->vids = vid;
576	depth++;
577	for (i = 0; i < NUM_PRIORITY; i++) {
578	    if (! (vtype & (1 << miVisualPriority[i])))
579		continue;
580	    visual->class = miVisualPriority[i];
581	    visual->bitsPerRGBValue = visuals->bitsPerRGB;
582	    visual->ColormapEntries = 1 << d;
583	    visual->nplanes = d;
584	    visual->vid = *vid = FakeClientID (0);
585	    switch (visual->class) {
586	    case PseudoColor:
587	    case GrayScale:
588	    case StaticGray:
589		visual->redMask = 0;
590		visual->greenMask =  0;
591		visual->blueMask =  0;
592		visual->offsetRed  =  0;
593		visual->offsetGreen = 0;
594		visual->offsetBlue =  0;
595		break;
596	    case DirectColor:
597	    case TrueColor:
598		visual->ColormapEntries = _CE(d);
599		/* fall through */
600	    case StaticColor:
601		visual->redMask =  visuals->redMask;
602		visual->greenMask =  visuals->greenMask;
603		visual->blueMask =  visuals->blueMask;
604		visual->offsetRed  =  maskShift (visuals->redMask);
605		visual->offsetGreen = maskShift (visuals->greenMask);
606		visual->offsetBlue =  maskShift (visuals->blueMask);
607	    }
608	    vid++;
609	    visual++;
610	}
611	free(visuals);
612    }
613    miVisuals = NULL;
614    visual = *visualp;
615    depth = *depthp;
616
617    /*
618     * if we did not supplyied by a preferred visual class
619     * check if there is a preferred class in one of the depth
620     * structures - if there is, we want to start looking for the
621     * default visual/depth from that depth.
622     */
623    first_depth = 0;
624    if (preferredVis < 0 && defaultColorVisualClass < 0 ) {
625       for (i = 0; i < ndepth; i++) {
626	  if (preferredCVCs[i] >= 0) {
627	     first_depth = i;
628	     break;
629	  }
630       }
631    }
632
633    for (i = first_depth; i < ndepth; i++)
634    {
635	int prefColorVisualClass = -1;
636
637	if (defaultColorVisualClass >= 0)
638	    prefColorVisualClass = defaultColorVisualClass;
639	else if (preferredVis >= 0)
640	    prefColorVisualClass = preferredVis;
641	else if (preferredCVCs[i] >= 0)
642	    prefColorVisualClass = preferredCVCs[i];
643
644	if (*rootDepthp && *rootDepthp != depth[i].depth)
645	    continue;
646
647	for (j = 0; j < depth[i].numVids; j++)
648	{
649	    for (k = 0; k < nvisual; k++)
650		if (visual[k].vid == depth[i].vids[j])
651		    break;
652	    if (k == nvisual)
653		continue;
654	    if (prefColorVisualClass < 0 ||
655		visual[k].class == prefColorVisualClass)
656		break;
657	}
658	if (j != depth[i].numVids)
659	    break;
660    }
661    if (i == ndepth) {
662	i = 0;
663	j = 0;
664    }
665    *rootDepthp = depth[i].depth;
666    *defaultVisp = depth[i].vids[j];
667    free(preferredCVCs);
668
669    return TRUE;
670}
671