Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | ||
45 | DevPrivateKeyRec PictureScreenPrivateKeyRec; | |
46 | DevPrivateKeyRec PictureWindowPrivateKeyRec; | |
47 | static int PictureGeneration; | |
48 | RESTYPE PictureType; | |
49 | RESTYPE PictFormatType; | |
50 | RESTYPE GlyphSetType; | |
51 | int PictureCmapPolicy = PictureCmapPolicyDefault; | |
52 | ||
53 | PictFormatPtr | |
54 | PictureWindowFormat(WindowPtr pWindow) | |
55 | { | |
56 | ScreenPtr pScreen = pWindow->drawable.pScreen; | |
57 | return PictureMatchVisual(pScreen, pWindow->drawable.depth, | |
58 | WindowGetVisual(pWindow)); | |
59 | } | |
60 | ||
61 | Bool | |
62 | PictureDestroyWindow(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 | ||
82 | Bool | |
83 | PictureCloseScreen(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 | ||
102 | void | |
103 | PictureStoreColors(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 | ||
128 | static int | |
129 | visualDepth(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 | ||
143 | typedef struct _formatInit { | |
144 | CARD32 format; | |
145 | CARD8 depth; | |
146 | } FormatInitRec, *FormatInitPtr; | |
147 | ||
148 | static int | |
149 | addFormat(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 | ||
163 | PictFormatPtr | |
164 | PictureCreateDefaultFormats(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 | ||
425 | static VisualPtr | |
426 | PictureFindVisual(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 | ||
439 | Bool | |
440 | PictureInitIndexedFormat(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 | ||
465 | static Bool | |
466 | PictureInitIndexedFormats(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 | ||
482 | Bool | |
483 | PictureFinishInit(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 | ||
496 | Bool | |
497 | PictureSetSubpixelOrder(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 | ||
508 | int | |
509 | PictureGetSubpixelOrder(ScreenPtr pScreen) | |
510 | { | |
511 | PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); | |
512 | ||
513 | if (!ps) | |
514 | return SubPixelUnknown; | |
515 | return ps->subpixel; | |
516 | } | |
517 | ||
518 | PictFormatPtr | |
519 | PictureMatchVisual(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 | ||
566 | PictFormatPtr | |
567 | PictureMatchFormat(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 | ||
585 | int | |
586 | PictureParseCmapPolicy(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 */ | |
603 | static void | |
604 | GetPictureBytes(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 | ||
625 | Bool | |
626 | PictureInit(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 | ||
724 | void | |
725 | SetPictureToDefaults(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 | ||
757 | PicturePtr | |
758 | CreatePicture(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 | ||
809 | static CARD32 | |
810 | xRenderColorToCard32(xRenderColor c) | |
811 | { | |
812 | return | |
813 | (c.alpha >> 8 << 24) | | |
814 | (c.red >> 8 << 16) | (c.green & 0xff00) | (c.blue >> 8); | |
815 | } | |
816 | ||
817 | static void | |
818 | initGradient(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 | ||
852 | static PicturePtr | |
853 | createSourcePicture(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 | ||
867 | PicturePtr | |
868 | CreateSolidPicture(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 | ||
890 | PicturePtr | |
891 | CreateLinearGradientPicture(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 | ||
928 | PicturePtr | |
929 | CreateRadialGradientPicture(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 | ||
973 | PicturePtr | |
974 | CreateConicalGradientPicture(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 | ||
1015 | int | |
1016 | ChangePicture(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 | ||
1230 | int | |
1231 | SetPictureClipRects(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 | ||
1253 | int | |
1254 | SetPictureClipRegion(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 | ||
1289 | static Bool | |
1290 | transformIsIdentity(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 | ||
1302 | int | |
1303 | SetPictureTransform(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 | ||
1335 | void | |
1336 | CopyPicture(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 | ||
1416 | static void | |
1417 | ValidateOnePicture(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 | ||
1429 | void | |
1430 | ValidatePicture(PicturePtr pPicture) | |
1431 | { | |
1432 | ValidateOnePicture(pPicture); | |
1433 | if (pPicture->alphaMap) | |
1434 | ValidateOnePicture(pPicture->alphaMap); | |
1435 | } | |
1436 | ||
1437 | int | |
1438 | FreePicture(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 | ||
1482 | int | |
1483 | FreePictFormat(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 | */ | |
1494 | static CARD8 | |
1495 | ReduceCompositeOp(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 | ||
1589 | void | |
1590 | CompositePicture(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 | ||
1618 | void | |
1619 | CompositeRects(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 | ||
1629 | void | |
1630 | CompositeTrapezoids(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 | ||
1643 | void | |
1644 | CompositeTriangles(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 | ||
1659 | void | |
1660 | CompositeTriStrip(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 | ||
1676 | void | |
1677 | CompositeTriFan(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 | ||
1693 | void | |
1694 | AddTraps(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 | } |