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