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