1/*
2 *
3 * Copyright © 2000 SuSE, Inc.
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, and that the name of SuSE not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission.  SuSE makes no representations about the
12 * suitability of this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 *
15 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Author:  Keith Packard, SuSE, Inc.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28#include "Xrenderint.h"
29#include <limits.h>
30
31XRenderExtInfo XRenderExtensionInfo;
32char XRenderExtensionName[] = RENDER_NAME;
33
34static int XRenderCloseDisplay (Display *dpy, XExtCodes *codes);
35
36/*
37 * XRenderExtFindDisplay - look for a display in this extension; keeps a
38 * cache of the most-recently used for efficiency. (Replaces
39 * XextFindDisplay.)
40 */
41static XRenderExtDisplayInfo *
42XRenderExtFindDisplay (XRenderExtInfo *extinfo,
43                       Display        *dpy)
44{
45    XRenderExtDisplayInfo *dpyinfo;
46
47    /*
48     * see if this was the most recently accessed display
49     */
50    if ((dpyinfo = extinfo->cur) && dpyinfo->display == dpy)
51        return dpyinfo;
52
53    /*
54     * look for display in list
55     */
56    _XLockMutex(_Xglobal_lock);
57    for (dpyinfo = extinfo->head; dpyinfo; dpyinfo = dpyinfo->next) {
58        if (dpyinfo->display == dpy) {
59            extinfo->cur = dpyinfo;     /* cache most recently used */
60            _XUnlockMutex(_Xglobal_lock);
61            return dpyinfo;
62        }
63    }
64    _XUnlockMutex(_Xglobal_lock);
65
66    return NULL;
67}
68
69/*
70 * If the server is missing support for any of the required depths on
71 * any screen, tell the application that Render is not present.
72 */
73
74#define DEPTH_MASK(d)	(1U << ((d) - 1))
75
76/*
77 * Render requires support for depth 1, 4, 8, 24 and 32 pixmaps
78 */
79
80#define REQUIRED_DEPTHS	(DEPTH_MASK(1) | \
81			 DEPTH_MASK(4) | \
82			 DEPTH_MASK(8) | \
83			 DEPTH_MASK(24) | \
84			 DEPTH_MASK(32))
85
86typedef struct _DepthCheckRec {
87    struct _DepthCheckRec *next;
88    Display *dpy;
89    CARD32  missing;
90    unsigned long serial;
91} DepthCheckRec, *DepthCheckPtr;
92
93static DepthCheckPtr	depthChecks;
94
95static int
96XRenderDepthCheckErrorHandler (Display *dpy, XErrorEvent *evt)
97{
98    if (evt->request_code == X_CreatePixmap && evt->error_code == BadValue)
99    {
100	DepthCheckPtr	d;
101
102	_XLockMutex(_Xglobal_lock);
103	for (d = depthChecks; d; d = d->next)
104	{
105	    if (d->dpy == dpy)
106	    {
107		if ((long) (evt->serial - d->serial) >= 0)
108		    d->missing |= DEPTH_MASK(evt->resourceid);
109		break;
110	    }
111        }
112	_XUnlockMutex (_Xglobal_lock);
113    }
114    return 0;
115}
116
117static Bool
118XRenderHasDepths (Display *dpy)
119{
120    int	s;
121
122    for (s = 0; s < ScreenCount (dpy); s++)
123    {
124	CARD32		    depths = 0;
125	CARD32		    missing;
126	Screen		    *scr = ScreenOfDisplay (dpy, s);
127	int		    d;
128
129	for (d = 0; d < scr->ndepths; d++)
130	    depths |= DEPTH_MASK(scr->depths[d].depth);
131	missing = ~depths & REQUIRED_DEPTHS;
132	if (missing)
133	{
134	    DepthCheckRec   dc, **dp;
135	    XErrorHandler   previousHandler;
136
137	    /*
138	     * Ok, this is ugly.  It should be sufficient at this
139	     * point to just return False, but Xinerama is broken at
140	     * this point and only advertises depths which have an
141	     * associated visual.  Of course, the other depths still
142	     * work, but the only way to find out is to try them.
143	     */
144	    dc.dpy = dpy;
145	    dc.missing = 0;
146	    dc.serial = XNextRequest (dpy);
147	    _XLockMutex(_Xglobal_lock);
148	    dc.next = depthChecks;
149	    depthChecks = &dc;
150	    _XUnlockMutex (_Xglobal_lock);
151	    /*
152	     * I suspect this is not really thread safe, but Xlib doesn't
153	     * provide a lot of options here
154	     */
155	    previousHandler = XSetErrorHandler (XRenderDepthCheckErrorHandler);
156	    /*
157	     * Try each missing depth and see if pixmap creation succeeds
158	     */
159	    for (d = 1; d <= 32; d++)
160		/* don't check depth 1 == Xcursor recurses... */
161		if ((missing & DEPTH_MASK(d)) && d != 1)
162		{
163		    Pixmap  p;
164		    p = XCreatePixmap (dpy, RootWindow (dpy, s), 1, 1, (unsigned) d);
165		    XFreePixmap (dpy, p);
166		}
167	    XSync (dpy, False);
168	    XSetErrorHandler (previousHandler);
169	    /*
170	     * Unhook from the list of depth check records
171	     */
172	    _XLockMutex(_Xglobal_lock);
173	    for (dp = &depthChecks; *dp; dp = &(*dp)->next)
174	    {
175		if (*dp == &dc)
176		{
177		    *dp = dc.next;
178		    break;
179		}
180	    }
181	    _XUnlockMutex (_Xglobal_lock);
182	    if (dc.missing)
183		return False;
184	}
185    }
186    return True;
187}
188
189/*
190 * XRenderExtAddDisplay - add a display to this extension. (Replaces
191 * XextAddDisplay)
192 */
193static XRenderExtDisplayInfo *
194XRenderExtAddDisplay (XRenderExtInfo *extinfo,
195                      Display        *dpy,
196                      char           *ext_name)
197{
198    XRenderExtDisplayInfo *dpyinfo;
199
200    dpyinfo = Xmalloc (sizeof (XRenderExtDisplayInfo));
201    if (!dpyinfo) return NULL;
202    dpyinfo->display = dpy;
203    dpyinfo->info = NULL;
204
205    if (XRenderHasDepths (dpy))
206	dpyinfo->codes = XInitExtension (dpy, ext_name);
207    else
208	dpyinfo->codes = NULL;
209
210    /*
211     * if the server has the extension, then we can initialize the
212     * appropriate function vectors
213     */
214    if (dpyinfo->codes) {
215        XESetCloseDisplay (dpy, dpyinfo->codes->extension,
216                           XRenderCloseDisplay);
217    } else {
218	/* The server doesn't have this extension.
219	 * Use a private Xlib-internal extension to hang the close_display
220	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
221	 * (XBUG 7955)
222	 */
223	XExtCodes *codes = XAddExtension(dpy);
224	if (!codes) {
225	    XFree(dpyinfo);
226	    return NULL;
227	}
228        XESetCloseDisplay (dpy, codes->extension, XRenderCloseDisplay);
229    }
230
231    /*
232     * now, chain it onto the list
233     */
234    _XLockMutex(_Xglobal_lock);
235    dpyinfo->next = extinfo->head;
236    extinfo->head = dpyinfo;
237    extinfo->cur = dpyinfo;
238    extinfo->ndisplays++;
239    _XUnlockMutex(_Xglobal_lock);
240    return dpyinfo;
241}
242
243
244/*
245 * XRenderExtRemoveDisplay - remove the indicated display from the
246 * extension object. (Replaces XextRemoveDisplay.)
247 */
248static int
249XRenderExtRemoveDisplay (XRenderExtInfo *extinfo, Display *dpy)
250{
251    XRenderExtDisplayInfo *dpyinfo, *prev;
252
253    /*
254     * locate this display and its back link so that it can be removed
255     */
256    _XLockMutex(_Xglobal_lock);
257    prev = NULL;
258    for (dpyinfo = extinfo->head; dpyinfo; dpyinfo = dpyinfo->next) {
259	if (dpyinfo->display == dpy) break;
260	prev = dpyinfo;
261    }
262    if (!dpyinfo) {
263	_XUnlockMutex(_Xglobal_lock);
264	return 0;		/* hmm, actually an error */
265    }
266
267    /*
268     * remove the display from the list; handles going to zero
269     */
270    if (prev)
271	prev->next = dpyinfo->next;
272    else
273	extinfo->head = dpyinfo->next;
274
275    extinfo->ndisplays--;
276    if (dpyinfo == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
277    _XUnlockMutex(_Xglobal_lock);
278
279    Xfree (dpyinfo);
280    return 1;
281}
282
283
284
285XRenderExtDisplayInfo *
286XRenderFindDisplay (Display *dpy)
287{
288    XRenderExtDisplayInfo *dpyinfo;
289
290    dpyinfo = XRenderExtFindDisplay (&XRenderExtensionInfo, dpy);
291    if (!dpyinfo)
292	dpyinfo = XRenderExtAddDisplay (&XRenderExtensionInfo, dpy,
293                                        XRenderExtensionName);
294    return dpyinfo;
295}
296
297static void
298XRenderFreeXRenderInfo (XRenderInfo *xri)
299{
300    Xfree(xri->format);
301    Xfree(xri->screen);
302    Xfree(xri->depth);
303    Xfree(xri->visual);
304    Xfree(xri);
305}
306
307static int
308XRenderCloseDisplay (Display *dpy, XExtCodes *codes _X_UNUSED)
309{
310    XRenderExtDisplayInfo *info = XRenderFindDisplay (dpy);
311    if (info && info->info) XRenderFreeXRenderInfo (info->info);
312
313    return XRenderExtRemoveDisplay (&XRenderExtensionInfo, dpy);
314}
315
316/****************************************************************************
317 *                                                                          *
318 *			    Render public interfaces                        *
319 *                                                                          *
320 ****************************************************************************/
321
322Bool XRenderQueryExtension (Display *dpy, int *event_basep, int *error_basep)
323{
324    XRenderExtDisplayInfo *info = XRenderFindDisplay (dpy);
325
326    if (RenderHasExtension(info)) {
327	*event_basep = info->codes->first_event;
328	*error_basep = info->codes->first_error;
329	return True;
330    } else {
331	return False;
332    }
333}
334
335
336Status XRenderQueryVersion (Display *dpy,
337			    int	    *major_versionp,
338			    int	    *minor_versionp)
339{
340    XRenderExtDisplayInfo *info = XRenderFindDisplay (dpy);
341    XRenderInfo	    *xri;
342
343    if (!RenderHasExtension (info))
344	return 0;
345
346    if (!XRenderQueryFormats (dpy))
347	return 0;
348
349    xri = info->info;
350    *major_versionp = xri->major_version;
351    *minor_versionp = xri->minor_version;
352    return 1;
353}
354
355static XRenderPictFormat *
356_XRenderFindFormat (XRenderInfo *xri, PictFormat format)
357{
358    int	nf;
359
360    for (nf = 0; nf < xri->nformat; nf++)
361	if (xri->format[nf].id == format)
362	    return &xri->format[nf];
363    return NULL;
364}
365
366static Visual *
367_XRenderFindVisual (Display *dpy, VisualID vid)
368{
369    return _XVIDtoVisual (dpy, vid);
370}
371
372typedef struct _renderVersionState {
373    unsigned long   version_seq;
374    Bool	    error;
375    int		    major_version;
376    int		    minor_version;
377
378} _XrenderVersionState;
379
380static Bool
381_XRenderVersionHandler (Display	    *dpy,
382			xReply	    *rep,
383			char	    *buf,
384			int	    len,
385			XPointer    data)
386{
387    xRenderQueryVersionReply	replbuf;
388    xRenderQueryVersionReply	*repl;
389    _XrenderVersionState	*state = (_XrenderVersionState *) data;
390
391    if (dpy->last_request_read != state->version_seq)
392	return False;
393    if (rep->generic.type == X_Error)
394    {
395	state->error = True;
396	return False;
397    }
398    repl = (xRenderQueryVersionReply *)
399	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
400		     (SIZEOF(xRenderQueryVersionReply) - SIZEOF(xReply)) >> 2,
401			True);
402    state->major_version = (int) repl->majorVersion;
403    state->minor_version = (int) repl->minorVersion;
404    return True;
405}
406
407Status
408XRenderQueryFormats (Display *dpy)
409{
410    XRenderExtDisplayInfo	*info = XRenderFindDisplay (dpy);
411    _XAsyncHandler		async;
412    _XrenderVersionState	async_state;
413    xRenderQueryVersionReq	*vreq;
414    xRenderQueryPictFormatsReply rep;
415    xRenderQueryPictFormatsReq  *req;
416    XRenderInfo			*xri;
417    XRenderPictFormat		*format;
418    XRenderScreen		*screen;
419    XRenderDepth		*depth;
420    XRenderVisual		*visual;
421    xPictFormInfo		*xFormat;
422    xPictScreen			*xScreen;
423    xPictDepth			*xPDepth;
424    xPictVisual			*xVisual;
425    CARD32			*xSubpixel;
426    void			*xData;
427    int				ns, nd;
428    unsigned			nf;
429    unsigned long		rlength;
430    unsigned long		nbytes;
431
432    RenderCheckExtension (dpy, info, 0);
433    LockDisplay (dpy);
434    if (info->info)
435    {
436	UnlockDisplay (dpy);
437	return 1;
438    }
439    GetReq (RenderQueryVersion, vreq);
440    vreq->reqType = (CARD8) info->codes->major_opcode;
441    vreq->renderReqType = X_RenderQueryVersion;
442    vreq->majorVersion = RENDER_MAJOR;
443    vreq->minorVersion = RENDER_MINOR;
444
445    async_state.version_seq = dpy->request;
446    async_state.error = False;
447    async.next = dpy->async_handlers;
448    async.handler = _XRenderVersionHandler;
449    async.data = (XPointer) &async_state;
450    dpy->async_handlers = &async;
451
452    GetReq (RenderQueryPictFormats, req);
453    req->reqType = (CARD8) info->codes->major_opcode;
454    req->renderReqType = X_RenderQueryPictFormats;
455
456    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
457    {
458	DeqAsyncHandler (dpy, &async);
459	UnlockDisplay (dpy);
460	SyncHandle ();
461	return 0;
462    }
463    DeqAsyncHandler (dpy, &async);
464    if (async_state.error)
465    {
466	UnlockDisplay(dpy);
467	SyncHandle();
468	return 0;
469    }
470    /*
471     * Check for the lack of sub-pixel data
472     */
473    if (async_state.major_version == 0 && async_state.minor_version < 6)
474	rep.numSubpixel = 0;
475
476    if ((rep.numFormats < ((INT_MAX / 4) / sizeof (XRenderPictFormat))) &&
477	(rep.numScreens < ((INT_MAX / 4) / sizeof (XRenderScreen))) &&
478	(rep.numDepths  < ((INT_MAX / 4) / sizeof (XRenderDepth))) &&
479	(rep.numVisuals < ((INT_MAX / 4) / sizeof (XRenderVisual))) &&
480	(rep.numSubpixel < ((INT_MAX / 4) / 4)) &&
481	(rep.length < (INT_MAX >> 2)) ) {
482        /* Zero-initialize so that pointers are NULL if there is a failure. */
483	xri = Xcalloc (1, sizeof (XRenderInfo));
484	rlength = ((rep.numFormats * sizeof (xPictFormInfo)) +
485		   (rep.numScreens * sizeof (xPictScreen)) +
486		   (rep.numDepths * sizeof (xPictDepth)) +
487		   (rep.numVisuals * sizeof (xPictVisual)) +
488		   (rep.numSubpixel * 4));
489	xData = Xmalloc (rlength);
490	nbytes = (unsigned long) rep.length << 2;
491    } else {
492	xri = NULL;
493	xData = NULL;
494	rlength = nbytes = 0;
495    }
496
497    if (!xri || !xData || nbytes < rlength)
498    {
499	if (xri) Xfree (xri);
500	if (xData) Xfree (xData);
501	_XEatDataWords (dpy, rep.length);
502	UnlockDisplay (dpy);
503	SyncHandle ();
504	return 0;
505    }
506    xri->major_version = async_state.major_version;
507    xri->minor_version = async_state.minor_version;
508    xri->format = Xcalloc(rep.numFormats, sizeof(XRenderPictFormat));
509    xri->nformat = (int) rep.numFormats;
510    xri->screen = Xcalloc(rep.numScreens, sizeof(XRenderScreen));
511    xri->nscreen = (int) rep.numScreens;
512    xri->depth = Xcalloc(rep.numDepths, sizeof(XRenderDepth));
513    xri->ndepth = (int) rep.numDepths;
514    xri->visual = Xcalloc(rep.numVisuals, sizeof(XRenderVisual));
515    xri->nvisual = (int) rep.numVisuals;
516    if (!xri->format || !xri->screen || !xri->depth || !xri->visual)
517    {
518	XRenderFreeXRenderInfo(xri);
519	Xfree (xData);
520	_XEatDataWords (dpy, rep.length);
521	UnlockDisplay (dpy);
522	SyncHandle ();
523	return 0;
524    }
525    _XRead (dpy, (char *) xData, (long) rlength);
526    format = xri->format;
527    xFormat = (xPictFormInfo *) xData;
528    for (nf = 0; nf < rep.numFormats; nf++)
529    {
530	format->id = xFormat->id;
531	format->type = xFormat->type;
532	format->depth = xFormat->depth;
533	format->direct.red       = (short) xFormat->direct.red;
534	format->direct.redMask   = (short) xFormat->direct.redMask;
535	format->direct.green     = (short) xFormat->direct.green;
536	format->direct.greenMask = (short) xFormat->direct.greenMask;
537	format->direct.blue      = (short) xFormat->direct.blue;
538	format->direct.blueMask  = (short) xFormat->direct.blueMask;
539	format->direct.alpha     = (short) xFormat->direct.alpha;
540	format->direct.alphaMask = (short) xFormat->direct.alphaMask;
541	format->colormap = xFormat->colormap;
542	format++;
543	xFormat++;
544    }
545    xScreen = (xPictScreen *) xFormat;
546    screen = xri->screen;
547    depth = xri->depth;
548    visual = xri->visual;
549    for (ns = 0; ns < xri->nscreen; ns++)
550    {
551	screen->depths = depth;
552	screen->ndepths = (int) xScreen->nDepth;
553	screen->fallback = _XRenderFindFormat (xri, xScreen->fallback);
554	screen->subpixel = SubPixelUnknown;
555	xPDepth = (xPictDepth *) (xScreen + 1);
556	if (screen->ndepths > rep.numDepths) {
557	    XRenderFreeXRenderInfo(xri);
558	    Xfree (xData);
559	    _XEatDataWords (dpy, rep.length);
560	    UnlockDisplay (dpy);
561	    SyncHandle ();
562	    return 0;
563	}
564	rep.numDepths -= (CARD32) screen->ndepths;
565	for (nd = 0; nd < screen->ndepths; nd++)
566	{
567	    int nv;
568
569	    depth->depth = xPDepth->depth;
570	    depth->nvisuals = xPDepth->nPictVisuals;
571	    depth->visuals = visual;
572	    xVisual = (xPictVisual *) (xPDepth + 1);
573	    if (depth->nvisuals > rep.numVisuals) {
574		XRenderFreeXRenderInfo (xri);
575		Xfree (xData);
576		_XEatDataWords (dpy, rep.length);
577		UnlockDisplay (dpy);
578		SyncHandle ();
579		return 0;
580	    }
581	    rep.numVisuals -= (CARD32) depth->nvisuals;
582	    for (nv = 0; nv < depth->nvisuals; nv++)
583	    {
584		visual->visual = _XRenderFindVisual (dpy, xVisual->visual);
585		visual->format = _XRenderFindFormat (xri, xVisual->format);
586		visual++;
587		xVisual++;
588	    }
589	    depth++;
590	    xPDepth = (xPictDepth *) xVisual;
591	}
592	screen++;
593	xScreen = (xPictScreen *) xPDepth;
594    }
595    xSubpixel = (CARD32 *) xScreen;
596    screen = xri->screen;
597    for (ns = 0; ns < rep.numSubpixel; ns++)
598    {
599	screen->subpixel = (int) *xSubpixel;
600	xSubpixel++;
601	screen++;
602    }
603    info->info = xri;
604    /*
605     * Skip any extra data
606     */
607    if (nbytes > rlength)
608	_XEatData (dpy, (unsigned long) (nbytes - rlength));
609
610    UnlockDisplay (dpy);
611    SyncHandle ();
612    Xfree (xData);
613    return 1;
614}
615
616int
617XRenderQuerySubpixelOrder (Display *dpy, int screen)
618{
619    XRenderExtDisplayInfo *info = XRenderFindDisplay (dpy);
620    XRenderInfo	    *xri;
621
622    if (!RenderHasExtension (info))
623	return SubPixelUnknown;
624
625    if (!XRenderQueryFormats (dpy))
626	return SubPixelUnknown;
627
628    xri = info->info;
629    return xri->screen[screen].subpixel;
630}
631
632Bool
633XRenderSetSubpixelOrder (Display *dpy, int screen, int subpixel)
634{
635    XRenderExtDisplayInfo *info = XRenderFindDisplay (dpy);
636    XRenderInfo	    *xri;
637
638    if (!RenderHasExtension (info))
639	return False;
640
641    if (!XRenderQueryFormats (dpy))
642	return False;
643
644    xri = info->info;
645    xri->screen[screen].subpixel = subpixel;
646    return True;
647}
648
649XRenderPictFormat *
650XRenderFindVisualFormat (Display *dpy, _Xconst Visual *visual)
651{
652    XRenderExtDisplayInfo *info = XRenderFindDisplay (dpy);
653    int		    nv;
654    XRenderInfo	    *xri;
655    XRenderVisual   *xrv;
656
657    RenderCheckExtension (dpy, info, NULL);
658    if (!XRenderQueryFormats (dpy))
659        return NULL;
660    xri = info->info;
661    for (nv = 0, xrv = xri->visual; nv < xri->nvisual; nv++, xrv++)
662	if (xrv->visual == visual)
663	    return xrv->format;
664    return NULL;
665}
666
667XRenderPictFormat *
668XRenderFindFormat (Display		*dpy,
669		   unsigned long	mask,
670		   _Xconst XRenderPictFormat	*template,
671		   int			count)
672{
673    XRenderExtDisplayInfo *info = XRenderFindDisplay (dpy);
674    int		    nf;
675    XRenderInfo     *xri;
676
677    RenderCheckExtension (dpy, info, NULL);
678    if (!XRenderQueryFormats (dpy))
679	return NULL;
680    xri = info->info;
681    for (nf = 0; nf < xri->nformat; nf++)
682    {
683	if (mask & PictFormatID)
684	    if (template->id != xri->format[nf].id)
685		continue;
686	if (mask & PictFormatType)
687	if (template->type != xri->format[nf].type)
688		continue;
689	if (mask & PictFormatDepth)
690	    if (template->depth != xri->format[nf].depth)
691		continue;
692	if (mask & PictFormatRed)
693	    if (template->direct.red != xri->format[nf].direct.red)
694		continue;
695	if (mask & PictFormatRedMask)
696	    if (template->direct.redMask != xri->format[nf].direct.redMask)
697		continue;
698	if (mask & PictFormatGreen)
699	    if (template->direct.green != xri->format[nf].direct.green)
700		continue;
701	if (mask & PictFormatGreenMask)
702	    if (template->direct.greenMask != xri->format[nf].direct.greenMask)
703		continue;
704	if (mask & PictFormatBlue)
705	    if (template->direct.blue != xri->format[nf].direct.blue)
706		continue;
707	if (mask & PictFormatBlueMask)
708	    if (template->direct.blueMask != xri->format[nf].direct.blueMask)
709		continue;
710	if (mask & PictFormatAlpha)
711	    if (template->direct.alpha != xri->format[nf].direct.alpha)
712		continue;
713	if (mask & PictFormatAlphaMask)
714	    if (template->direct.alphaMask != xri->format[nf].direct.alphaMask)
715		continue;
716	if (mask & PictFormatColormap)
717	    if (template->colormap != xri->format[nf].colormap)
718		continue;
719	if (count-- == 0)
720	    return &xri->format[nf];
721    }
722    return NULL;
723}
724
725XRenderPictFormat *
726XRenderFindStandardFormat (Display  *dpy,
727			   int	    format)
728{
729    static struct {
730	XRenderPictFormat   templ;
731	unsigned long	    mask;
732    } standardFormats[PictStandardNUM] = {
733	/* PictStandardARGB32 */
734	{
735	    {
736		0,			    /* id */
737		PictTypeDirect,		    /* type */
738		32,			    /* depth */
739		{			    /* direct */
740		    16,			    /* direct.red */
741		    0xff,		    /* direct.redMask */
742		    8,			    /* direct.green */
743		    0xff,		    /* direct.greenMask */
744		    0,			    /* direct.blue */
745		    0xff,		    /* direct.blueMask */
746		    24,			    /* direct.alpha */
747		    0xff,		    /* direct.alphaMask */
748		},
749		0,			    /* colormap */
750	    },
751	    PictFormatType |
752	    PictFormatDepth |
753	    PictFormatRed |
754	    PictFormatRedMask |
755	    PictFormatGreen |
756	    PictFormatGreenMask |
757	    PictFormatBlue |
758	    PictFormatBlueMask |
759	    PictFormatAlpha |
760	    PictFormatAlphaMask,
761	},
762	/* PictStandardRGB24 */
763	{
764	    {
765		0,			    /* id */
766		PictTypeDirect,		    /* type */
767		24,			    /* depth */
768		{			    /* direct */
769		    16,			    /* direct.red */
770		    0xff,		    /* direct.redMask */
771		    8,			    /* direct.green */
772		    0xff,		    /* direct.greenMask */
773		    0,			    /* direct.blue */
774		    0xff,		    /* direct.blueMask */
775		    0,			    /* direct.alpha */
776		    0x00,		    /* direct.alphaMask */
777		},
778		0,			    /* colormap */
779	    },
780	    PictFormatType |
781	    PictFormatDepth |
782	    PictFormatRed |
783	    PictFormatRedMask |
784	    PictFormatGreen |
785	    PictFormatGreenMask |
786	    PictFormatBlue |
787	    PictFormatBlueMask |
788	    PictFormatAlphaMask,
789	},
790	/* PictStandardA8 */
791	{
792	    {
793		0,			    /* id */
794		PictTypeDirect,		    /* type */
795		8,			    /* depth */
796		{			    /* direct */
797		    0,			    /* direct.red */
798		    0x00,		    /* direct.redMask */
799		    0,			    /* direct.green */
800		    0x00,		    /* direct.greenMask */
801		    0,			    /* direct.blue */
802		    0x00,		    /* direct.blueMask */
803		    0,			    /* direct.alpha */
804		    0xff,		    /* direct.alphaMask */
805		},
806		0,			    /* colormap */
807	    },
808	    PictFormatType |
809	    PictFormatDepth |
810	    PictFormatRedMask |
811	    PictFormatGreenMask |
812	    PictFormatBlueMask |
813	    PictFormatAlpha |
814	    PictFormatAlphaMask,
815	},
816	/* PictStandardA4 */
817	{
818	    {
819		0,			    /* id */
820		PictTypeDirect,		    /* type */
821		4,			    /* depth */
822		{			    /* direct */
823		    0,			    /* direct.red */
824		    0x00,		    /* direct.redMask */
825		    0,			    /* direct.green */
826		    0x00,		    /* direct.greenMask */
827		    0,			    /* direct.blue */
828		    0x00,		    /* direct.blueMask */
829		    0,			    /* direct.alpha */
830		    0x0f,		    /* direct.alphaMask */
831		},
832		0,			    /* colormap */
833	    },
834	    PictFormatType |
835	    PictFormatDepth |
836	    PictFormatRedMask |
837	    PictFormatGreenMask |
838	    PictFormatBlueMask |
839	    PictFormatAlpha |
840	    PictFormatAlphaMask,
841	},
842	/* PictStandardA1 */
843	{
844	    {
845		0,			    /* id */
846		PictTypeDirect,		    /* type */
847		1,			    /* depth */
848		{			    /* direct */
849		    0,			    /* direct.red */
850		    0x00,		    /* direct.redMask */
851		    0,			    /* direct.green */
852		    0x00,		    /* direct.greenMask */
853		    0,			    /* direct.blue */
854		    0x00,		    /* direct.blueMask */
855		    0,			    /* direct.alpha */
856		    0x01,		    /* direct.alphaMask */
857		},
858		0,			    /* colormap */
859	    },
860	    PictFormatType |
861	    PictFormatDepth |
862	    PictFormatRedMask |
863	    PictFormatGreenMask |
864	    PictFormatBlueMask |
865	    PictFormatAlpha |
866	    PictFormatAlphaMask,
867	},
868    };
869
870    if (0 <= format && format < PictStandardNUM)
871	return XRenderFindFormat (dpy,
872				  standardFormats[format].mask,
873				  &standardFormats[format].templ,
874				  0);
875    return NULL;
876}
877
878XIndexValue *
879XRenderQueryPictIndexValues(Display			*dpy,
880			    _Xconst XRenderPictFormat	*format,
881			    int				*num)
882{
883    XRenderExtDisplayInfo		*info = XRenderFindDisplay (dpy);
884    xRenderQueryPictIndexValuesReq	*req;
885    xRenderQueryPictIndexValuesReply	rep;
886    XIndexValue				*values;
887    unsigned int			nbytes, nread, i;
888
889    RenderCheckExtension (dpy, info, NULL);
890
891    LockDisplay (dpy);
892    GetReq (RenderQueryPictIndexValues, req);
893    req->reqType       = (CARD8) info->codes->major_opcode;
894    req->renderReqType = X_RenderQueryPictIndexValues;
895    req->format        = (CARD32) format->id;
896    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
897    {
898	UnlockDisplay (dpy);
899	SyncHandle ();
900	return NULL;
901    }
902
903    if ((rep.length < (INT_MAX >> 2)) &&
904	(rep.numIndexValues < (INT_MAX / sizeof (XIndexValue)))) {
905	unsigned int rlength;
906	/* request data length */
907	nbytes = rep.length << 2;
908	/* bytes of actual data in the request */
909	nread = rep.numIndexValues * SIZEOF (xIndexValue);
910	/* size of array returned to application */
911	rlength = (unsigned) ((unsigned long) rep.numIndexValues * sizeof (XIndexValue));
912
913	/* allocate returned data */
914	values = Xmalloc (rlength);
915    } else {
916	nbytes = nread = 0;
917	values = NULL;
918    }
919
920    if (!values)
921    {
922	_XEatDataWords (dpy, rep.length);
923	UnlockDisplay (dpy);
924	SyncHandle ();
925	return NULL;
926    }
927
928    /* read the values one at a time and convert */
929    *num = (int) rep.numIndexValues;
930    for (i = 0; i < rep.numIndexValues; i++)
931    {
932	xIndexValue value;
933
934	_XRead (dpy, (char *) &value, SIZEOF (xIndexValue));
935	values[i].pixel = value.pixel;
936	values[i].red = value.red;
937	values[i].green = value.green;
938	values[i].blue = value.blue;
939	values[i].alpha = value.alpha;
940    }
941    /* skip any padding */
942    if(nbytes > nread)
943    {
944	_XEatData (dpy, (unsigned long) (nbytes - nread));
945    }
946    UnlockDisplay (dpy);
947    SyncHandle ();
948    return values;
949}
950