picture.c revision 35c4bbdf
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_DIX_CONFIG_H
26#include <dix-config.h>
27#endif
28
29#include "misc.h"
30#include "scrnintstr.h"
31#include "os.h"
32#include "regionstr.h"
33#include "validate.h"
34#include "windowstr.h"
35#include "input.h"
36#include "resource.h"
37#include "colormapst.h"
38#include "cursorstr.h"
39#include "dixstruct.h"
40#include "gcstruct.h"
41#include "servermd.h"
42#include "picturestr.h"
43#include "xace.h"
44#ifdef PANORAMIX
45#include "panoramiXsrv.h"
46#endif
47
48DevPrivateKeyRec PictureScreenPrivateKeyRec;
49DevPrivateKeyRec PictureWindowPrivateKeyRec;
50static int PictureGeneration;
51RESTYPE PictureType;
52RESTYPE PictFormatType;
53RESTYPE GlyphSetType;
54int PictureCmapPolicy = PictureCmapPolicyDefault;
55
56PictFormatPtr
57PictureWindowFormat(WindowPtr pWindow)
58{
59    ScreenPtr pScreen = pWindow->drawable.pScreen;
60    return PictureMatchVisual(pScreen, pWindow->drawable.depth,
61                              WindowGetVisual(pWindow));
62}
63
64static Bool
65PictureDestroyWindow(WindowPtr pWindow)
66{
67    ScreenPtr pScreen = pWindow->drawable.pScreen;
68    PicturePtr pPicture;
69    PictureScreenPtr ps = GetPictureScreen(pScreen);
70    Bool ret;
71
72    while ((pPicture = GetPictureWindow(pWindow))) {
73        SetPictureWindow(pWindow, pPicture->pNext);
74        if (pPicture->id)
75            FreeResource(pPicture->id, PictureType);
76        FreePicture((void *) pPicture, pPicture->id);
77    }
78    pScreen->DestroyWindow = ps->DestroyWindow;
79    ret = (*pScreen->DestroyWindow) (pWindow);
80    ps->DestroyWindow = pScreen->DestroyWindow;
81    pScreen->DestroyWindow = PictureDestroyWindow;
82    return ret;
83}
84
85static Bool
86PictureCloseScreen(ScreenPtr pScreen)
87{
88    PictureScreenPtr ps = GetPictureScreen(pScreen);
89    Bool ret;
90    int n;
91
92    pScreen->CloseScreen = ps->CloseScreen;
93    ret = (*pScreen->CloseScreen) (pScreen);
94    PictureResetFilters(pScreen);
95    for (n = 0; n < ps->nformats; n++)
96        if (ps->formats[n].type == PictTypeIndexed)
97            (*ps->CloseIndexed) (pScreen, &ps->formats[n]);
98    GlyphUninit(pScreen);
99    SetPictureScreen(pScreen, 0);
100    free(ps->formats);
101    free(ps);
102    return ret;
103}
104
105static void
106PictureStoreColors(ColormapPtr pColormap, int ndef, xColorItem * pdef)
107{
108    ScreenPtr pScreen = pColormap->pScreen;
109    PictureScreenPtr ps = GetPictureScreen(pScreen);
110
111    pScreen->StoreColors = ps->StoreColors;
112    (*pScreen->StoreColors) (pColormap, ndef, pdef);
113    ps->StoreColors = pScreen->StoreColors;
114    pScreen->StoreColors = PictureStoreColors;
115
116    if (pColormap->class == PseudoColor || pColormap->class == GrayScale) {
117        PictFormatPtr format = ps->formats;
118        int nformats = ps->nformats;
119
120        while (nformats--) {
121            if (format->type == PictTypeIndexed &&
122                format->index.pColormap == pColormap) {
123                (*ps->UpdateIndexed) (pScreen, format, ndef, pdef);
124                break;
125            }
126            format++;
127        }
128    }
129}
130
131static int
132visualDepth(ScreenPtr pScreen, VisualPtr pVisual)
133{
134    int d, v;
135    DepthPtr pDepth;
136
137    for (d = 0; d < pScreen->numDepths; d++) {
138        pDepth = &pScreen->allowedDepths[d];
139        for (v = 0; v < pDepth->numVids; v++)
140            if (pDepth->vids[v] == pVisual->vid)
141                return pDepth->depth;
142    }
143    return 0;
144}
145
146typedef struct _formatInit {
147    CARD32 format;
148    CARD8 depth;
149} FormatInitRec, *FormatInitPtr;
150
151static int
152addFormat(FormatInitRec formats[256], int nformat, CARD32 format, CARD8 depth)
153{
154    int n;
155
156    for (n = 0; n < nformat; n++)
157        if (formats[n].format == format && formats[n].depth == depth)
158            return nformat;
159    formats[nformat].format = format;
160    formats[nformat].depth = depth;
161    return ++nformat;
162}
163
164#define Mask(n) ((1 << (n)) - 1)
165
166static PictFormatPtr
167PictureCreateDefaultFormats(ScreenPtr pScreen, int *nformatp)
168{
169    int nformats, f;
170    PictFormatPtr pFormats;
171    FormatInitRec formats[1024];
172    CARD32 format;
173    CARD8 depth;
174    VisualPtr pVisual;
175    int v;
176    int bpp;
177    int type;
178    int r, g, b;
179    int d;
180    DepthPtr pDepth;
181
182    nformats = 0;
183    /* formats required by protocol */
184    formats[nformats].format = PICT_a1;
185    formats[nformats].depth = 1;
186    nformats++;
187    formats[nformats].format = PICT_FORMAT(BitsPerPixel(8),
188                                           PICT_TYPE_A, 8, 0, 0, 0);
189    formats[nformats].depth = 8;
190    nformats++;
191    formats[nformats].format = PICT_FORMAT(BitsPerPixel(4),
192                                           PICT_TYPE_A, 4, 0, 0, 0);
193    formats[nformats].depth = 4;
194    nformats++;
195    formats[nformats].format = PICT_a8r8g8b8;
196    formats[nformats].depth = 32;
197    nformats++;
198    formats[nformats].format = PICT_x8r8g8b8;
199    formats[nformats].depth = 32;
200    nformats++;
201    formats[nformats].format = PICT_b8g8r8a8;
202    formats[nformats].depth = 32;
203    nformats++;
204    formats[nformats].format = PICT_b8g8r8x8;
205    formats[nformats].depth = 32;
206    nformats++;
207
208    /* now look through the depths and visuals adding other formats */
209    for (v = 0; v < pScreen->numVisuals; v++) {
210        pVisual = &pScreen->visuals[v];
211        depth = visualDepth(pScreen, pVisual);
212        if (!depth)
213            continue;
214        bpp = BitsPerPixel(depth);
215        switch (pVisual->class) {
216        case DirectColor:
217        case TrueColor:
218            r = Ones(pVisual->redMask);
219            g = Ones(pVisual->greenMask);
220            b = Ones(pVisual->blueMask);
221            type = PICT_TYPE_OTHER;
222            /*
223             * Current rendering code supports only three direct formats,
224             * fields must be packed together at the bottom of the pixel
225             */
226            if (pVisual->offsetBlue == 0 &&
227                pVisual->offsetGreen == b && pVisual->offsetRed == b + g) {
228                type = PICT_TYPE_ARGB;
229            }
230            else if (pVisual->offsetRed == 0 &&
231                     pVisual->offsetGreen == r &&
232                     pVisual->offsetBlue == r + g) {
233                type = PICT_TYPE_ABGR;
234            }
235            else if (pVisual->offsetRed == pVisual->offsetGreen - r &&
236                     pVisual->offsetGreen == pVisual->offsetBlue - g &&
237                     pVisual->offsetBlue == bpp - b) {
238                type = PICT_TYPE_BGRA;
239            }
240            if (type != PICT_TYPE_OTHER) {
241                format = PICT_FORMAT(bpp, type, 0, r, g, b);
242                nformats = addFormat(formats, nformats, format, depth);
243            }
244            break;
245        case StaticColor:
246        case PseudoColor:
247            format = PICT_VISFORMAT(bpp, PICT_TYPE_COLOR, v);
248            nformats = addFormat(formats, nformats, format, depth);
249            break;
250        case StaticGray:
251        case GrayScale:
252            format = PICT_VISFORMAT(bpp, PICT_TYPE_GRAY, v);
253            nformats = addFormat(formats, nformats, format, depth);
254            break;
255        }
256    }
257    /*
258     * Walk supported depths and add useful Direct formats
259     */
260    for (d = 0; d < pScreen->numDepths; d++) {
261        pDepth = &pScreen->allowedDepths[d];
262        bpp = BitsPerPixel(pDepth->depth);
263        format = 0;
264        switch (bpp) {
265        case 16:
266            /* depth 12 formats */
267            if (pDepth->depth >= 12) {
268                nformats = addFormat(formats, nformats,
269                                     PICT_x4r4g4b4, pDepth->depth);
270                nformats = addFormat(formats, nformats,
271                                     PICT_x4b4g4r4, pDepth->depth);
272            }
273            /* depth 15 formats */
274            if (pDepth->depth >= 15) {
275                nformats = addFormat(formats, nformats,
276                                     PICT_x1r5g5b5, pDepth->depth);
277                nformats = addFormat(formats, nformats,
278                                     PICT_x1b5g5r5, pDepth->depth);
279            }
280            /* depth 16 formats */
281            if (pDepth->depth >= 16) {
282                nformats = addFormat(formats, nformats,
283                                     PICT_a1r5g5b5, pDepth->depth);
284                nformats = addFormat(formats, nformats,
285                                     PICT_a1b5g5r5, pDepth->depth);
286                nformats = addFormat(formats, nformats,
287                                     PICT_r5g6b5, pDepth->depth);
288                nformats = addFormat(formats, nformats,
289                                     PICT_b5g6r5, pDepth->depth);
290                nformats = addFormat(formats, nformats,
291                                     PICT_a4r4g4b4, pDepth->depth);
292                nformats = addFormat(formats, nformats,
293                                     PICT_a4b4g4r4, pDepth->depth);
294            }
295            break;
296        case 24:
297            if (pDepth->depth >= 24) {
298                nformats = addFormat(formats, nformats,
299                                     PICT_r8g8b8, pDepth->depth);
300                nformats = addFormat(formats, nformats,
301                                     PICT_b8g8r8, pDepth->depth);
302            }
303            break;
304        case 32:
305            if (pDepth->depth >= 24) {
306                nformats = addFormat(formats, nformats,
307                                     PICT_x8r8g8b8, pDepth->depth);
308                nformats = addFormat(formats, nformats,
309                                     PICT_x8b8g8r8, pDepth->depth);
310            }
311            if (pDepth->depth >= 30) {
312                nformats = addFormat(formats, nformats,
313                                     PICT_a2r10g10b10, pDepth->depth);
314                nformats = addFormat(formats, nformats,
315                                     PICT_x2r10g10b10, pDepth->depth);
316                nformats = addFormat(formats, nformats,
317                                     PICT_a2b10g10r10, pDepth->depth);
318                nformats = addFormat(formats, nformats,
319                                     PICT_x2b10g10r10, pDepth->depth);
320            }
321            break;
322        }
323    }
324
325    pFormats = calloc(nformats, sizeof(PictFormatRec));
326    if (!pFormats)
327        return 0;
328    for (f = 0; f < nformats; f++) {
329        pFormats[f].id = FakeClientID(0);
330        pFormats[f].depth = formats[f].depth;
331        format = formats[f].format;
332        pFormats[f].format = format;
333        switch (PICT_FORMAT_TYPE(format)) {
334        case PICT_TYPE_ARGB:
335            pFormats[f].type = PictTypeDirect;
336
337            pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
338
339            if (pFormats[f].direct.alphaMask)
340                pFormats[f].direct.alpha = (PICT_FORMAT_R(format) +
341                                            PICT_FORMAT_G(format) +
342                                            PICT_FORMAT_B(format));
343
344            pFormats[f].direct.redMask = Mask (PICT_FORMAT_R(format));
345
346            pFormats[f].direct.red = (PICT_FORMAT_G(format) +
347                                      PICT_FORMAT_B(format));
348
349            pFormats[f].direct.greenMask = Mask (PICT_FORMAT_G(format));
350
351            pFormats[f].direct.green = PICT_FORMAT_B(format);
352
353            pFormats[f].direct.blueMask = Mask (PICT_FORMAT_B(format));
354
355            pFormats[f].direct.blue = 0;
356            break;
357
358        case PICT_TYPE_ABGR:
359            pFormats[f].type = PictTypeDirect;
360
361            pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
362
363            if (pFormats[f].direct.alphaMask)
364                pFormats[f].direct.alpha = (PICT_FORMAT_B(format) +
365                                            PICT_FORMAT_G(format) +
366                                            PICT_FORMAT_R(format));
367
368            pFormats[f].direct.blueMask = Mask (PICT_FORMAT_B(format));
369
370            pFormats[f].direct.blue = (PICT_FORMAT_G(format) +
371                                       PICT_FORMAT_R(format));
372
373            pFormats[f].direct.greenMask = Mask (PICT_FORMAT_G(format));
374
375            pFormats[f].direct.green = PICT_FORMAT_R(format);
376
377            pFormats[f].direct.redMask = Mask (PICT_FORMAT_R(format));
378
379            pFormats[f].direct.red = 0;
380            break;
381
382        case PICT_TYPE_BGRA:
383            pFormats[f].type = PictTypeDirect;
384
385            pFormats[f].direct.blueMask = Mask (PICT_FORMAT_B(format));
386
387            pFormats[f].direct.blue =
388                (PICT_FORMAT_BPP(format) - PICT_FORMAT_B(format));
389
390            pFormats[f].direct.greenMask = Mask (PICT_FORMAT_G(format));
391
392            pFormats[f].direct.green =
393                (PICT_FORMAT_BPP(format) - PICT_FORMAT_B(format) -
394                 PICT_FORMAT_G(format));
395
396            pFormats[f].direct.redMask = Mask (PICT_FORMAT_R(format));
397
398            pFormats[f].direct.red =
399                (PICT_FORMAT_BPP(format) - PICT_FORMAT_B(format) -
400                 PICT_FORMAT_G(format) - PICT_FORMAT_R(format));
401
402            pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
403
404            pFormats[f].direct.alpha = 0;
405            break;
406
407        case PICT_TYPE_A:
408            pFormats[f].type = PictTypeDirect;
409
410            pFormats[f].direct.alpha = 0;
411            pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
412
413            /* remaining fields already set to zero */
414            break;
415
416        case PICT_TYPE_COLOR:
417        case PICT_TYPE_GRAY:
418            pFormats[f].type = PictTypeIndexed;
419            pFormats[f].index.vid =
420                pScreen->visuals[PICT_FORMAT_VIS(format)].vid;
421            break;
422        }
423    }
424    *nformatp = nformats;
425    return pFormats;
426}
427
428static VisualPtr
429PictureFindVisual(ScreenPtr pScreen, VisualID visual)
430{
431    int i;
432    VisualPtr pVisual;
433
434    for (i = 0, pVisual = pScreen->visuals;
435         i < pScreen->numVisuals; i++, pVisual++) {
436        if (pVisual->vid == visual)
437            return pVisual;
438    }
439    return 0;
440}
441
442static Bool
443PictureInitIndexedFormat(ScreenPtr pScreen, PictFormatPtr format)
444{
445    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
446
447    if (format->type != PictTypeIndexed || format->index.pColormap)
448        return TRUE;
449
450    if (format->index.vid == pScreen->rootVisual) {
451        dixLookupResourceByType((void **) &format->index.pColormap,
452                                pScreen->defColormap, RT_COLORMAP,
453                                serverClient, DixGetAttrAccess);
454    }
455    else {
456        VisualPtr pVisual = PictureFindVisual(pScreen, format->index.vid);
457
458        if (CreateColormap(FakeClientID(0), pScreen, pVisual,
459                           &format->index.pColormap, AllocNone, 0)
460            != Success)
461            return FALSE;
462    }
463    if (!ps->InitIndexed(pScreen, format))
464        return FALSE;
465    return TRUE;
466}
467
468static Bool
469PictureInitIndexedFormats(ScreenPtr pScreen)
470{
471    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
472    PictFormatPtr format;
473    int nformat;
474
475    if (!ps)
476        return FALSE;
477    format = ps->formats;
478    nformat = ps->nformats;
479    while (nformat--)
480        if (!PictureInitIndexedFormat(pScreen, format++))
481            return FALSE;
482    return TRUE;
483}
484
485Bool
486PictureFinishInit(void)
487{
488    int s;
489
490    for (s = 0; s < screenInfo.numScreens; s++) {
491        if (!PictureInitIndexedFormats(screenInfo.screens[s]))
492            return FALSE;
493        (void) AnimCurInit(screenInfo.screens[s]);
494    }
495
496    return TRUE;
497}
498
499Bool
500PictureSetSubpixelOrder(ScreenPtr pScreen, int subpixel)
501{
502    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
503
504    if (!ps)
505        return FALSE;
506    ps->subpixel = subpixel;
507    return TRUE;
508
509}
510
511int
512PictureGetSubpixelOrder(ScreenPtr pScreen)
513{
514    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
515
516    if (!ps)
517        return SubPixelUnknown;
518    return ps->subpixel;
519}
520
521PictFormatPtr
522PictureMatchVisual(ScreenPtr pScreen, int depth, VisualPtr pVisual)
523{
524    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
525    PictFormatPtr format;
526    int nformat;
527    int type;
528
529    if (!ps)
530        return 0;
531    format = ps->formats;
532    nformat = ps->nformats;
533    switch (pVisual->class) {
534    case StaticGray:
535    case GrayScale:
536    case StaticColor:
537    case PseudoColor:
538        type = PictTypeIndexed;
539        break;
540    case TrueColor:
541    case DirectColor:
542        type = PictTypeDirect;
543        break;
544    default:
545        return 0;
546    }
547    while (nformat--) {
548        if (format->depth == depth && format->type == type) {
549            if (type == PictTypeIndexed) {
550                if (format->index.vid == pVisual->vid)
551                    return format;
552            }
553            else {
554                if (format->direct.redMask << format->direct.red ==
555                    pVisual->redMask &&
556                    format->direct.greenMask << format->direct.green ==
557                    pVisual->greenMask &&
558                    format->direct.blueMask << format->direct.blue ==
559                    pVisual->blueMask) {
560                    return format;
561                }
562            }
563        }
564        format++;
565    }
566    return 0;
567}
568
569PictFormatPtr
570PictureMatchFormat(ScreenPtr pScreen, int depth, CARD32 f)
571{
572    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
573    PictFormatPtr format;
574    int nformat;
575
576    if (!ps)
577        return 0;
578    format = ps->formats;
579    nformat = ps->nformats;
580    while (nformat--) {
581        if (format->depth == depth && format->format == (f & 0xffffff))
582            return format;
583        format++;
584    }
585    return 0;
586}
587
588int
589PictureParseCmapPolicy(const char *name)
590{
591    if (strcmp(name, "default") == 0)
592        return PictureCmapPolicyDefault;
593    else if (strcmp(name, "mono") == 0)
594        return PictureCmapPolicyMono;
595    else if (strcmp(name, "gray") == 0)
596        return PictureCmapPolicyGray;
597    else if (strcmp(name, "color") == 0)
598        return PictureCmapPolicyColor;
599    else if (strcmp(name, "all") == 0)
600        return PictureCmapPolicyAll;
601    else
602        return PictureCmapPolicyInvalid;
603}
604
605/** @see GetDefaultBytes */
606static void
607GetPictureBytes(void *value, XID id, ResourceSizePtr size)
608{
609    PicturePtr picture = value;
610
611    /* Currently only pixmap bytes are reported to clients. */
612    size->resourceSize = 0;
613
614    size->refCnt = picture->refcnt;
615
616    /* Calculate pixmap reference sizes. */
617    size->pixmapRefSize = 0;
618    if (picture->pDrawable && (picture->pDrawable->type == DRAWABLE_PIXMAP))
619    {
620        SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
621        ResourceSizeRec pixmapSize = { 0, 0, 0 };
622        PixmapPtr pixmap = (PixmapPtr)picture->pDrawable;
623        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
624        size->pixmapRefSize += pixmapSize.pixmapRefSize;
625    }
626}
627
628static int
629FreePictFormat(void *pPictFormat, XID pid)
630{
631    return Success;
632}
633
634Bool
635PictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
636{
637    PictureScreenPtr ps;
638    int n;
639    CARD32 type, a, r, g, b;
640
641    if (PictureGeneration != serverGeneration) {
642        PictureType = CreateNewResourceType(FreePicture, "PICTURE");
643        if (!PictureType)
644            return FALSE;
645        SetResourceTypeSizeFunc(PictureType, GetPictureBytes);
646        PictFormatType = CreateNewResourceType(FreePictFormat, "PICTFORMAT");
647        if (!PictFormatType)
648            return FALSE;
649        GlyphSetType = CreateNewResourceType(FreeGlyphSet, "GLYPHSET");
650        if (!GlyphSetType)
651            return FALSE;
652        PictureGeneration = serverGeneration;
653    }
654    if (!dixRegisterPrivateKey(&PictureScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
655        return FALSE;
656
657    if (!dixRegisterPrivateKey(&PictureWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
658        return FALSE;
659
660    if (!formats) {
661        formats = PictureCreateDefaultFormats(pScreen, &nformats);
662        if (!formats)
663            return FALSE;
664    }
665    for (n = 0; n < nformats; n++) {
666        if (!AddResource
667            (formats[n].id, PictFormatType, (void *) (formats + n))) {
668            int i;
669            for (i = 0; i < n; i++)
670                FreeResource(formats[i].id, RT_NONE);
671            free(formats);
672            return FALSE;
673        }
674        if (formats[n].type == PictTypeIndexed) {
675            VisualPtr pVisual =
676                PictureFindVisual(pScreen, formats[n].index.vid);
677            if ((pVisual->class | DynamicClass) == PseudoColor)
678                type = PICT_TYPE_COLOR;
679            else
680                type = PICT_TYPE_GRAY;
681            a = r = g = b = 0;
682        }
683        else {
684            if ((formats[n].direct.redMask |
685                 formats[n].direct.blueMask | formats[n].direct.greenMask) == 0)
686                type = PICT_TYPE_A;
687            else if (formats[n].direct.red > formats[n].direct.blue)
688                type = PICT_TYPE_ARGB;
689            else if (formats[n].direct.red == 0)
690                type = PICT_TYPE_ABGR;
691            else
692                type = PICT_TYPE_BGRA;
693            a = Ones(formats[n].direct.alphaMask);
694            r = Ones(formats[n].direct.redMask);
695            g = Ones(formats[n].direct.greenMask);
696            b = Ones(formats[n].direct.blueMask);
697        }
698        formats[n].format = PICT_FORMAT(0, type, a, r, g, b);
699    }
700    ps = (PictureScreenPtr) malloc(sizeof(PictureScreenRec));
701    if (!ps) {
702        free(formats);
703        return FALSE;
704    }
705    SetPictureScreen(pScreen, ps);
706
707    ps->formats = formats;
708    ps->fallback = formats;
709    ps->nformats = nformats;
710
711    ps->filters = 0;
712    ps->nfilters = 0;
713    ps->filterAliases = 0;
714    ps->nfilterAliases = 0;
715
716    ps->subpixel = SubPixelUnknown;
717
718    ps->CloseScreen = pScreen->CloseScreen;
719    ps->DestroyWindow = pScreen->DestroyWindow;
720    ps->StoreColors = pScreen->StoreColors;
721    pScreen->DestroyWindow = PictureDestroyWindow;
722    pScreen->CloseScreen = PictureCloseScreen;
723    pScreen->StoreColors = PictureStoreColors;
724
725    if (!PictureSetDefaultFilters(pScreen)) {
726        PictureResetFilters(pScreen);
727        SetPictureScreen(pScreen, 0);
728        free(formats);
729        free(ps);
730        return FALSE;
731    }
732
733    return TRUE;
734}
735
736static void
737SetPictureToDefaults(PicturePtr pPicture)
738{
739    pPicture->refcnt = 1;
740    pPicture->repeat = 0;
741    pPicture->graphicsExposures = FALSE;
742    pPicture->subWindowMode = ClipByChildren;
743    pPicture->polyEdge = PolyEdgeSharp;
744    pPicture->polyMode = PolyModePrecise;
745    pPicture->freeCompClip = FALSE;
746    pPicture->componentAlpha = FALSE;
747    pPicture->repeatType = RepeatNone;
748
749    pPicture->alphaMap = 0;
750    pPicture->alphaOrigin.x = 0;
751    pPicture->alphaOrigin.y = 0;
752
753    pPicture->clipOrigin.x = 0;
754    pPicture->clipOrigin.y = 0;
755    pPicture->clientClip = 0;
756
757    pPicture->transform = 0;
758
759    pPicture->filter = PictureGetFilterId(FilterNearest, -1, TRUE);
760    pPicture->filter_params = 0;
761    pPicture->filter_nparams = 0;
762
763    pPicture->serialNumber = GC_CHANGE_SERIAL_BIT;
764    pPicture->stateChanges = -1;
765    pPicture->pSourcePict = 0;
766}
767
768PicturePtr
769CreatePicture(Picture pid,
770              DrawablePtr pDrawable,
771              PictFormatPtr pFormat,
772              Mask vmask, XID *vlist, ClientPtr client, int *error)
773{
774    PicturePtr pPicture;
775    PictureScreenPtr ps = GetPictureScreen(pDrawable->pScreen);
776
777    pPicture = dixAllocateScreenObjectWithPrivates(pDrawable->pScreen,
778                                                   PictureRec, PRIVATE_PICTURE);
779    if (!pPicture) {
780        *error = BadAlloc;
781        return 0;
782    }
783
784    pPicture->id = pid;
785    pPicture->pDrawable = pDrawable;
786    pPicture->pFormat = pFormat;
787    pPicture->format = pFormat->format | (pDrawable->bitsPerPixel << 24);
788
789    /* security creation/labeling check */
790    *error = XaceHook(XACE_RESOURCE_ACCESS, client, pid, PictureType, pPicture,
791                      RT_PIXMAP, pDrawable, DixCreateAccess | DixSetAttrAccess);
792    if (*error != Success)
793        goto out;
794
795    if (pDrawable->type == DRAWABLE_PIXMAP) {
796        ++((PixmapPtr) pDrawable)->refcnt;
797        pPicture->pNext = 0;
798    }
799    else {
800        pPicture->pNext = GetPictureWindow(((WindowPtr) pDrawable));
801        SetPictureWindow(((WindowPtr) pDrawable), pPicture);
802    }
803
804    SetPictureToDefaults(pPicture);
805
806    if (vmask)
807        *error = ChangePicture(pPicture, vmask, vlist, 0, client);
808    else
809        *error = Success;
810    if (*error == Success)
811        *error = (*ps->CreatePicture) (pPicture);
812 out:
813    if (*error != Success) {
814        FreePicture(pPicture, (XID) 0);
815        pPicture = 0;
816    }
817    return pPicture;
818}
819
820static CARD32
821xRenderColorToCard32(xRenderColor c)
822{
823    return
824        (c.alpha >> 8 << 24) |
825        (c.red >> 8 << 16) | (c.green & 0xff00) | (c.blue >> 8);
826}
827
828static void
829initGradient(SourcePictPtr pGradient, int stopCount,
830             xFixed * stopPoints, xRenderColor * stopColors, int *error)
831{
832    int i;
833    xFixed dpos;
834
835    if (stopCount <= 0) {
836        *error = BadValue;
837        return;
838    }
839
840    dpos = -1;
841    for (i = 0; i < stopCount; ++i) {
842        if (stopPoints[i] < dpos || stopPoints[i] > (1 << 16)) {
843            *error = BadValue;
844            return;
845        }
846        dpos = stopPoints[i];
847    }
848
849    pGradient->gradient.stops = xallocarray(stopCount, sizeof(PictGradientStop));
850    if (!pGradient->gradient.stops) {
851        *error = BadAlloc;
852        return;
853    }
854
855    pGradient->gradient.nstops = stopCount;
856
857    for (i = 0; i < stopCount; ++i) {
858        pGradient->gradient.stops[i].x = stopPoints[i];
859        pGradient->gradient.stops[i].color = stopColors[i];
860    }
861}
862
863static PicturePtr
864createSourcePicture(void)
865{
866    PicturePtr pPicture;
867
868    pPicture = dixAllocateScreenObjectWithPrivates(NULL, PictureRec,
869                                                   PRIVATE_PICTURE);
870    if (!pPicture)
871	return 0;
872
873    pPicture->pDrawable = 0;
874    pPicture->pFormat = 0;
875    pPicture->pNext = 0;
876    pPicture->format = PICT_a8r8g8b8;
877
878    SetPictureToDefaults(pPicture);
879    return pPicture;
880}
881
882PicturePtr
883CreateSolidPicture(Picture pid, xRenderColor * color, int *error)
884{
885    PicturePtr pPicture;
886
887    pPicture = createSourcePicture();
888    if (!pPicture) {
889        *error = BadAlloc;
890        return 0;
891    }
892
893    pPicture->id = pid;
894    pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictSolidFill));
895    if (!pPicture->pSourcePict) {
896        *error = BadAlloc;
897        free(pPicture);
898        return 0;
899    }
900    pPicture->pSourcePict->type = SourcePictTypeSolidFill;
901    pPicture->pSourcePict->solidFill.color = xRenderColorToCard32(*color);
902    return pPicture;
903}
904
905PicturePtr
906CreateLinearGradientPicture(Picture pid, xPointFixed * p1, xPointFixed * p2,
907                            int nStops, xFixed * stops, xRenderColor * colors,
908                            int *error)
909{
910    PicturePtr pPicture;
911
912    if (nStops < 1) {
913        *error = BadValue;
914        return 0;
915    }
916
917    pPicture = createSourcePicture();
918    if (!pPicture) {
919        *error = BadAlloc;
920        return 0;
921    }
922
923    pPicture->id = pid;
924    pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictLinearGradient));
925    if (!pPicture->pSourcePict) {
926        *error = BadAlloc;
927        free(pPicture);
928        return 0;
929    }
930
931    pPicture->pSourcePict->linear.type = SourcePictTypeLinear;
932    pPicture->pSourcePict->linear.p1 = *p1;
933    pPicture->pSourcePict->linear.p2 = *p2;
934
935    initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
936    if (*error) {
937        free(pPicture);
938        return 0;
939    }
940    return pPicture;
941}
942
943PicturePtr
944CreateRadialGradientPicture(Picture pid, xPointFixed * inner,
945                            xPointFixed * outer, xFixed innerRadius,
946                            xFixed outerRadius, int nStops, xFixed * stops,
947                            xRenderColor * colors, int *error)
948{
949    PicturePtr pPicture;
950    PictRadialGradient *radial;
951
952    if (nStops < 1) {
953        *error = BadValue;
954        return 0;
955    }
956
957    pPicture = createSourcePicture();
958    if (!pPicture) {
959        *error = BadAlloc;
960        return 0;
961    }
962
963    pPicture->id = pid;
964    pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictRadialGradient));
965    if (!pPicture->pSourcePict) {
966        *error = BadAlloc;
967        free(pPicture);
968        return 0;
969    }
970    radial = &pPicture->pSourcePict->radial;
971
972    radial->type = SourcePictTypeRadial;
973    radial->c1.x = inner->x;
974    radial->c1.y = inner->y;
975    radial->c1.radius = innerRadius;
976    radial->c2.x = outer->x;
977    radial->c2.y = outer->y;
978    radial->c2.radius = outerRadius;
979
980    initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
981    if (*error) {
982        free(pPicture);
983        return 0;
984    }
985    return pPicture;
986}
987
988PicturePtr
989CreateConicalGradientPicture(Picture pid, xPointFixed * center, xFixed angle,
990                             int nStops, xFixed * stops, xRenderColor * colors,
991                             int *error)
992{
993    PicturePtr pPicture;
994
995    if (nStops < 1) {
996        *error = BadValue;
997        return 0;
998    }
999
1000    pPicture = createSourcePicture();
1001    if (!pPicture) {
1002        *error = BadAlloc;
1003        return 0;
1004    }
1005
1006    pPicture->id = pid;
1007    pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictConicalGradient));
1008    if (!pPicture->pSourcePict) {
1009        *error = BadAlloc;
1010        free(pPicture);
1011        return 0;
1012    }
1013
1014    pPicture->pSourcePict->conical.type = SourcePictTypeConical;
1015    pPicture->pSourcePict->conical.center = *center;
1016    pPicture->pSourcePict->conical.angle = angle;
1017
1018    initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
1019    if (*error) {
1020        free(pPicture);
1021        return 0;
1022    }
1023    return pPicture;
1024}
1025
1026static int
1027cpAlphaMap(void **result, XID id, ScreenPtr screen, ClientPtr client, Mask mode)
1028{
1029#ifdef PANORAMIX
1030    if (!noPanoramiXExtension) {
1031        PanoramiXRes *res;
1032        int err = dixLookupResourceByType((void **)&res, id, XRT_PICTURE,
1033                                          client, mode);
1034        if (err != Success)
1035            return err;
1036        id = res->info[screen->myNum].id;
1037    }
1038#endif
1039    return dixLookupResourceByType(result, id, PictureType, client, mode);
1040}
1041
1042static int
1043cpClipMask(void **result, XID id, ScreenPtr screen, ClientPtr client, Mask mode)
1044{
1045#ifdef PANORAMIX
1046    if (!noPanoramiXExtension) {
1047        PanoramiXRes *res;
1048        int err = dixLookupResourceByType((void **)&res, id, XRT_PIXMAP,
1049                                          client, mode);
1050        if (err != Success)
1051            return err;
1052        id = res->info[screen->myNum].id;
1053    }
1054#endif
1055    return dixLookupResourceByType(result, id, RT_PIXMAP, client, mode);
1056}
1057
1058#define NEXT_VAL(_type) (vlist ? (_type) *vlist++ : (_type) ulist++->val)
1059
1060#define NEXT_PTR(_type) ((_type) ulist++->ptr)
1061
1062int
1063ChangePicture(PicturePtr pPicture,
1064              Mask vmask, XID *vlist, DevUnion *ulist, ClientPtr client)
1065{
1066    ScreenPtr pScreen = pPicture->pDrawable ? pPicture->pDrawable->pScreen : 0;
1067    PictureScreenPtr ps = pScreen ? GetPictureScreen(pScreen) : 0;
1068    BITS32 index2;
1069    int error = 0;
1070    BITS32 maskQ;
1071
1072    pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
1073    maskQ = vmask;
1074    while (vmask && !error) {
1075        index2 = (BITS32) lowbit(vmask);
1076        vmask &= ~index2;
1077        pPicture->stateChanges |= index2;
1078        switch (index2) {
1079        case CPRepeat:
1080        {
1081            unsigned int newr;
1082            newr = NEXT_VAL(unsigned int);
1083
1084            if (newr <= RepeatReflect) {
1085                pPicture->repeat = (newr != RepeatNone);
1086                pPicture->repeatType = newr;
1087            }
1088            else {
1089                client->errorValue = newr;
1090                error = BadValue;
1091            }
1092        }
1093            break;
1094        case CPAlphaMap:
1095        {
1096            PicturePtr pAlpha;
1097
1098            if (vlist) {
1099                Picture pid = NEXT_VAL(Picture);
1100
1101                if (pid == None)
1102                    pAlpha = 0;
1103                else {
1104                    error = cpAlphaMap((void **) &pAlpha, pid, pScreen,
1105                                       client, DixReadAccess);
1106                    if (error != Success) {
1107                        client->errorValue = pid;
1108                        break;
1109                    }
1110                    if (pAlpha->pDrawable == NULL ||
1111                        pAlpha->pDrawable->type != DRAWABLE_PIXMAP) {
1112                        client->errorValue = pid;
1113                        error = BadMatch;
1114                        break;
1115                    }
1116                }
1117            }
1118            else
1119                pAlpha = NEXT_PTR(PicturePtr);
1120            if (!error) {
1121                if (pAlpha && pAlpha->pDrawable->type == DRAWABLE_PIXMAP)
1122                    pAlpha->refcnt++;
1123                if (pPicture->alphaMap)
1124                    FreePicture((void *) pPicture->alphaMap, (XID) 0);
1125                pPicture->alphaMap = pAlpha;
1126            }
1127        }
1128            break;
1129        case CPAlphaXOrigin:
1130            pPicture->alphaOrigin.x = NEXT_VAL(INT16);
1131
1132            break;
1133        case CPAlphaYOrigin:
1134            pPicture->alphaOrigin.y = NEXT_VAL(INT16);
1135
1136            break;
1137        case CPClipXOrigin:
1138            pPicture->clipOrigin.x = NEXT_VAL(INT16);
1139
1140            break;
1141        case CPClipYOrigin:
1142            pPicture->clipOrigin.y = NEXT_VAL(INT16);
1143
1144            break;
1145        case CPClipMask:
1146        {
1147            Pixmap pid;
1148            PixmapPtr pPixmap;
1149            int clipType;
1150
1151            if (!pScreen)
1152                return BadDrawable;
1153
1154            if (vlist) {
1155                pid = NEXT_VAL(Pixmap);
1156                if (pid == None) {
1157                    clipType = CT_NONE;
1158                    pPixmap = NullPixmap;
1159                }
1160                else {
1161                    clipType = CT_PIXMAP;
1162                    error = cpClipMask((void **) &pPixmap, pid, pScreen,
1163                                       client, DixReadAccess);
1164                    if (error != Success) {
1165                        client->errorValue = pid;
1166                        break;
1167                    }
1168                }
1169            }
1170            else {
1171                pPixmap = NEXT_PTR(PixmapPtr);
1172
1173                if (pPixmap)
1174                    clipType = CT_PIXMAP;
1175                else
1176                    clipType = CT_NONE;
1177            }
1178
1179            if (pPixmap) {
1180                if ((pPixmap->drawable.depth != 1) ||
1181                    (pPixmap->drawable.pScreen != pScreen)) {
1182                    error = BadMatch;
1183                    break;
1184                }
1185                else {
1186                    clipType = CT_PIXMAP;
1187                    pPixmap->refcnt++;
1188                }
1189            }
1190            error = (*ps->ChangePictureClip) (pPicture, clipType,
1191                                              (void *) pPixmap, 0);
1192            break;
1193        }
1194        case CPGraphicsExposure:
1195        {
1196            unsigned int newe;
1197            newe = NEXT_VAL(unsigned int);
1198
1199            if (newe <= xTrue)
1200                pPicture->graphicsExposures = newe;
1201            else {
1202                client->errorValue = newe;
1203                error = BadValue;
1204            }
1205        }
1206            break;
1207        case CPSubwindowMode:
1208        {
1209            unsigned int news;
1210            news = NEXT_VAL(unsigned int);
1211
1212            if (news == ClipByChildren || news == IncludeInferiors)
1213                pPicture->subWindowMode = news;
1214            else {
1215                client->errorValue = news;
1216                error = BadValue;
1217            }
1218        }
1219            break;
1220        case CPPolyEdge:
1221        {
1222            unsigned int newe;
1223            newe = NEXT_VAL(unsigned int);
1224
1225            if (newe == PolyEdgeSharp || newe == PolyEdgeSmooth)
1226                pPicture->polyEdge = newe;
1227            else {
1228                client->errorValue = newe;
1229                error = BadValue;
1230            }
1231        }
1232            break;
1233        case CPPolyMode:
1234        {
1235            unsigned int newm;
1236            newm = NEXT_VAL(unsigned int);
1237
1238            if (newm == PolyModePrecise || newm == PolyModeImprecise)
1239                pPicture->polyMode = newm;
1240            else {
1241                client->errorValue = newm;
1242                error = BadValue;
1243            }
1244        }
1245            break;
1246        case CPDither:
1247            (void) NEXT_VAL(Atom);      /* unimplemented */
1248
1249            break;
1250        case CPComponentAlpha:
1251        {
1252            unsigned int newca;
1253
1254            newca = NEXT_VAL(unsigned int);
1255
1256            if (newca <= xTrue)
1257                pPicture->componentAlpha = newca;
1258            else {
1259                client->errorValue = newca;
1260                error = BadValue;
1261            }
1262        }
1263            break;
1264        default:
1265            client->errorValue = maskQ;
1266            error = BadValue;
1267            break;
1268        }
1269    }
1270    if (ps)
1271        (*ps->ChangePicture) (pPicture, maskQ);
1272    return error;
1273}
1274
1275int
1276SetPictureClipRects(PicturePtr pPicture,
1277                    int xOrigin, int yOrigin, int nRect, xRectangle *rects)
1278{
1279    ScreenPtr pScreen = pPicture->pDrawable->pScreen;
1280    PictureScreenPtr ps = GetPictureScreen(pScreen);
1281    RegionPtr clientClip;
1282    int result;
1283
1284    clientClip = RegionFromRects(nRect, rects, CT_UNSORTED);
1285    if (!clientClip)
1286        return BadAlloc;
1287    result = (*ps->ChangePictureClip) (pPicture, CT_REGION,
1288                                       (void *) clientClip, 0);
1289    if (result == Success) {
1290        pPicture->clipOrigin.x = xOrigin;
1291        pPicture->clipOrigin.y = yOrigin;
1292        pPicture->stateChanges |= CPClipXOrigin | CPClipYOrigin | CPClipMask;
1293        pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
1294    }
1295    return result;
1296}
1297
1298int
1299SetPictureClipRegion(PicturePtr pPicture,
1300                     int xOrigin, int yOrigin, RegionPtr pRegion)
1301{
1302    ScreenPtr pScreen = pPicture->pDrawable->pScreen;
1303    PictureScreenPtr ps = GetPictureScreen(pScreen);
1304    RegionPtr clientClip;
1305    int result;
1306    int type;
1307
1308    if (pRegion) {
1309        type = CT_REGION;
1310        clientClip = RegionCreate(RegionExtents(pRegion),
1311                                  RegionNumRects(pRegion));
1312        if (!clientClip)
1313            return BadAlloc;
1314        if (!RegionCopy(clientClip, pRegion)) {
1315            RegionDestroy(clientClip);
1316            return BadAlloc;
1317        }
1318    }
1319    else {
1320        type = CT_NONE;
1321        clientClip = 0;
1322    }
1323
1324    result = (*ps->ChangePictureClip) (pPicture, type, (void *) clientClip, 0);
1325    if (result == Success) {
1326        pPicture->clipOrigin.x = xOrigin;
1327        pPicture->clipOrigin.y = yOrigin;
1328        pPicture->stateChanges |= CPClipXOrigin | CPClipYOrigin | CPClipMask;
1329        pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
1330    }
1331    return result;
1332}
1333
1334static Bool
1335transformIsIdentity(PictTransform * t)
1336{
1337    return ((t->matrix[0][0] == t->matrix[1][1]) &&
1338            (t->matrix[0][0] == t->matrix[2][2]) &&
1339            (t->matrix[0][0] != 0) &&
1340            (t->matrix[0][1] == 0) &&
1341            (t->matrix[0][2] == 0) &&
1342            (t->matrix[1][0] == 0) &&
1343            (t->matrix[1][2] == 0) &&
1344            (t->matrix[2][0] == 0) && (t->matrix[2][1] == 0));
1345}
1346
1347int
1348SetPictureTransform(PicturePtr pPicture, PictTransform * transform)
1349{
1350    if (transform && transformIsIdentity(transform))
1351        transform = 0;
1352
1353    if (transform) {
1354        if (!pPicture->transform) {
1355            pPicture->transform =
1356                (PictTransform *) malloc(sizeof(PictTransform));
1357            if (!pPicture->transform)
1358                return BadAlloc;
1359        }
1360        *pPicture->transform = *transform;
1361    }
1362    else {
1363        free(pPicture->transform);
1364        pPicture->transform = NULL;
1365    }
1366    pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
1367
1368    if (pPicture->pDrawable != NULL) {
1369        int result;
1370        PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
1371
1372        result = (*ps->ChangePictureTransform) (pPicture, transform);
1373
1374        return result;
1375    }
1376
1377    return Success;
1378}
1379
1380static void
1381ValidateOnePicture(PicturePtr pPicture)
1382{
1383    if (pPicture->pDrawable &&
1384        pPicture->serialNumber != pPicture->pDrawable->serialNumber) {
1385        PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
1386
1387        (*ps->ValidatePicture) (pPicture, pPicture->stateChanges);
1388        pPicture->stateChanges = 0;
1389        pPicture->serialNumber = pPicture->pDrawable->serialNumber;
1390    }
1391}
1392
1393void
1394ValidatePicture(PicturePtr pPicture)
1395{
1396    ValidateOnePicture(pPicture);
1397    if (pPicture->alphaMap)
1398        ValidateOnePicture(pPicture->alphaMap);
1399}
1400
1401int
1402FreePicture(void *value, XID pid)
1403{
1404    PicturePtr pPicture = (PicturePtr) value;
1405
1406    if (--pPicture->refcnt == 0) {
1407        free(pPicture->transform);
1408        free(pPicture->filter_params);
1409
1410        if (pPicture->pSourcePict) {
1411            if (pPicture->pSourcePict->type != SourcePictTypeSolidFill)
1412                free(pPicture->pSourcePict->linear.stops);
1413
1414            free(pPicture->pSourcePict);
1415        }
1416
1417        if (pPicture->pDrawable) {
1418            ScreenPtr pScreen = pPicture->pDrawable->pScreen;
1419            PictureScreenPtr ps = GetPictureScreen(pScreen);
1420
1421            if (pPicture->alphaMap)
1422                FreePicture((void *) pPicture->alphaMap, (XID) 0);
1423            (*ps->DestroyPicture) (pPicture);
1424            (*ps->DestroyPictureClip) (pPicture);
1425            if (pPicture->pDrawable->type == DRAWABLE_WINDOW) {
1426                WindowPtr pWindow = (WindowPtr) pPicture->pDrawable;
1427                PicturePtr *pPrev;
1428
1429                for (pPrev = (PicturePtr *) dixLookupPrivateAddr
1430                     (&pWindow->devPrivates, PictureWindowPrivateKey);
1431                     *pPrev; pPrev = &(*pPrev)->pNext) {
1432                    if (*pPrev == pPicture) {
1433                        *pPrev = pPicture->pNext;
1434                        break;
1435                    }
1436                }
1437            }
1438            else if (pPicture->pDrawable->type == DRAWABLE_PIXMAP) {
1439                (*pScreen->DestroyPixmap) ((PixmapPtr) pPicture->pDrawable);
1440            }
1441        }
1442        dixFreeObjectWithPrivates(pPicture, PRIVATE_PICTURE);
1443    }
1444    return Success;
1445}
1446
1447/**
1448 * ReduceCompositeOp is used to choose simpler ops for cases where alpha
1449 * channels are always one and so math on the alpha channel per pixel becomes
1450 * unnecessary.  It may also avoid destination reads sometimes if apps aren't
1451 * being careful to avoid these cases.
1452 */
1453static CARD8
1454ReduceCompositeOp(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
1455                  INT16 xSrc, INT16 ySrc, CARD16 width, CARD16 height)
1456{
1457    Bool no_src_alpha, no_dst_alpha;
1458
1459    /* Sampling off the edge of a RepeatNone picture introduces alpha
1460     * even if the picture itself doesn't have alpha. We don't try to
1461     * detect every case where we don't sample off the edge, just the
1462     * simplest case where there is no transform on the source
1463     * picture.
1464     */
1465    no_src_alpha = PICT_FORMAT_COLOR(pSrc->format) &&
1466        PICT_FORMAT_A(pSrc->format) == 0 &&
1467        (pSrc->repeatType != RepeatNone ||
1468         (!pSrc->transform &&
1469          xSrc >= 0 && ySrc >= 0 &&
1470          xSrc + width <= pSrc->pDrawable->width &&
1471          ySrc + height <= pSrc->pDrawable->height)) &&
1472        pSrc->alphaMap == NULL && pMask == NULL;
1473    no_dst_alpha = PICT_FORMAT_COLOR(pDst->format) &&
1474        PICT_FORMAT_A(pDst->format) == 0 && pDst->alphaMap == NULL;
1475
1476    /* TODO, maybe: Conjoint and Disjoint op reductions? */
1477
1478    /* Deal with simplifications where the source alpha is always 1. */
1479    if (no_src_alpha) {
1480        switch (op) {
1481        case PictOpOver:
1482            op = PictOpSrc;
1483            break;
1484        case PictOpInReverse:
1485            op = PictOpDst;
1486            break;
1487        case PictOpOutReverse:
1488            op = PictOpClear;
1489            break;
1490        case PictOpAtop:
1491            op = PictOpIn;
1492            break;
1493        case PictOpAtopReverse:
1494            op = PictOpOverReverse;
1495            break;
1496        case PictOpXor:
1497            op = PictOpOut;
1498            break;
1499        default:
1500            break;
1501        }
1502    }
1503
1504    /* Deal with simplifications when the destination alpha is always 1 */
1505    if (no_dst_alpha) {
1506        switch (op) {
1507        case PictOpOverReverse:
1508            op = PictOpDst;
1509            break;
1510        case PictOpIn:
1511            op = PictOpSrc;
1512            break;
1513        case PictOpOut:
1514            op = PictOpClear;
1515            break;
1516        case PictOpAtop:
1517            op = PictOpOver;
1518            break;
1519        case PictOpXor:
1520            op = PictOpOutReverse;
1521            break;
1522        default:
1523            break;
1524        }
1525    }
1526
1527    /* Reduce some con/disjoint ops to the basic names. */
1528    switch (op) {
1529    case PictOpDisjointClear:
1530    case PictOpConjointClear:
1531        op = PictOpClear;
1532        break;
1533    case PictOpDisjointSrc:
1534    case PictOpConjointSrc:
1535        op = PictOpSrc;
1536        break;
1537    case PictOpDisjointDst:
1538    case PictOpConjointDst:
1539        op = PictOpDst;
1540        break;
1541    default:
1542        break;
1543    }
1544
1545    return op;
1546}
1547
1548void
1549CompositePicture(CARD8 op,
1550                 PicturePtr pSrc,
1551                 PicturePtr pMask,
1552                 PicturePtr pDst,
1553                 INT16 xSrc,
1554                 INT16 ySrc,
1555                 INT16 xMask,
1556                 INT16 yMask,
1557                 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
1558{
1559    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
1560
1561    ValidatePicture(pSrc);
1562    if (pMask)
1563        ValidatePicture(pMask);
1564    ValidatePicture(pDst);
1565
1566    op = ReduceCompositeOp(op, pSrc, pMask, pDst, xSrc, ySrc, width, height);
1567    if (op == PictOpDst)
1568        return;
1569
1570    (*ps->Composite) (op,
1571                      pSrc,
1572                      pMask,
1573                      pDst,
1574                      xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
1575}
1576
1577void
1578CompositeRects(CARD8 op,
1579               PicturePtr pDst,
1580               xRenderColor * color, int nRect, xRectangle *rects)
1581{
1582    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
1583
1584    ValidatePicture(pDst);
1585    (*ps->CompositeRects) (op, pDst, color, nRect, rects);
1586}
1587
1588void
1589CompositeTrapezoids(CARD8 op,
1590                    PicturePtr pSrc,
1591                    PicturePtr pDst,
1592                    PictFormatPtr maskFormat,
1593                    INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid * traps)
1594{
1595    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
1596
1597    ValidatePicture(pSrc);
1598    ValidatePicture(pDst);
1599    (*ps->Trapezoids) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, traps);
1600}
1601
1602void
1603CompositeTriangles(CARD8 op,
1604                   PicturePtr pSrc,
1605                   PicturePtr pDst,
1606                   PictFormatPtr maskFormat,
1607                   INT16 xSrc,
1608                   INT16 ySrc, int ntriangles, xTriangle * triangles)
1609{
1610    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
1611
1612    ValidatePicture(pSrc);
1613    ValidatePicture(pDst);
1614    (*ps->Triangles) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntriangles,
1615                      triangles);
1616}
1617
1618void
1619CompositeTriStrip(CARD8 op,
1620                  PicturePtr pSrc,
1621                  PicturePtr pDst,
1622                  PictFormatPtr maskFormat,
1623                  INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
1624{
1625    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
1626
1627    if (npoints < 3)
1628        return;
1629
1630    ValidatePicture(pSrc);
1631    ValidatePicture(pDst);
1632    (*ps->TriStrip) (op, pSrc, pDst, maskFormat, xSrc, ySrc, npoints, points);
1633}
1634
1635void
1636CompositeTriFan(CARD8 op,
1637                PicturePtr pSrc,
1638                PicturePtr pDst,
1639                PictFormatPtr maskFormat,
1640                INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
1641{
1642    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
1643
1644    if (npoints < 3)
1645        return;
1646
1647    ValidatePicture(pSrc);
1648    ValidatePicture(pDst);
1649    (*ps->TriFan) (op, pSrc, pDst, maskFormat, xSrc, ySrc, npoints, points);
1650}
1651
1652void
1653AddTraps(PicturePtr pPicture, INT16 xOff, INT16 yOff, int ntrap, xTrap * traps)
1654{
1655    PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
1656
1657    ValidatePicture(pPicture);
1658    (*ps->AddTraps) (pPicture, xOff, yOff, ntrap, traps);
1659}
1660