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