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