1 /*
2 *
3 * Copyright © 1999 Keith Packard
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 Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Keith Packard makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
27
28 #include "scrnintstr.h"
29 #include "gcstruct.h"
30 #include "pixmapstr.h"
31 #include "windowstr.h"
32 #include "mi.h"
33 #include "picturestr.h"
34 #include "mipict.h"
35
36 int
miCreatePicture(PicturePtr pPicture)37 miCreatePicture(PicturePtr pPicture)
38 {
39 return Success;
40 }
41
42 void
miDestroyPicture(PicturePtr pPicture)43 miDestroyPicture(PicturePtr pPicture)
44 {
45 if (pPicture->freeCompClip)
46 RegionDestroy(pPicture->pCompositeClip);
47 }
48
49 static void
miDestroyPictureClip(PicturePtr pPicture)50 miDestroyPictureClip(PicturePtr pPicture)
51 {
52 if (pPicture->clientClip)
53 RegionDestroy(pPicture->clientClip);
54 pPicture->clientClip = NULL;
55 }
56
57 static int
miChangePictureClip(PicturePtr pPicture,int type,void * value,int n)58 miChangePictureClip(PicturePtr pPicture, int type, void *value, int n)
59 {
60 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
61 PictureScreenPtr ps = GetPictureScreen(pScreen);
62 RegionPtr clientClip;
63
64 switch (type) {
65 case CT_PIXMAP:
66 /* convert the pixmap to a region */
67 clientClip = BitmapToRegion(pScreen, (PixmapPtr) value);
68 if (!clientClip)
69 return BadAlloc;
70 (*pScreen->DestroyPixmap) ((PixmapPtr) value);
71 break;
72 case CT_REGION:
73 clientClip = value;
74 break;
75 case CT_NONE:
76 clientClip = 0;
77 break;
78 default:
79 clientClip = RegionFromRects(n, (xRectangle *) value, type);
80 if (!clientClip)
81 return BadAlloc;
82 free(value);
83 break;
84 }
85 (*ps->DestroyPictureClip) (pPicture);
86 pPicture->clientClip = clientClip;
87 pPicture->stateChanges |= CPClipMask;
88 return Success;
89 }
90
91 static void
miChangePicture(PicturePtr pPicture,Mask mask)92 miChangePicture(PicturePtr pPicture, Mask mask)
93 {
94 return;
95 }
96
97 static void
miValidatePicture(PicturePtr pPicture,Mask mask)98 miValidatePicture(PicturePtr pPicture, Mask mask)
99 {
100 DrawablePtr pDrawable = pPicture->pDrawable;
101
102 if ((mask & (CPClipXOrigin | CPClipYOrigin | CPClipMask | CPSubwindowMode))
103 || (pDrawable->serialNumber !=
104 (pPicture->serialNumber & DRAWABLE_SERIAL_BITS))) {
105 if (pDrawable->type == DRAWABLE_WINDOW) {
106 WindowPtr pWin = (WindowPtr) pDrawable;
107 RegionPtr pregWin;
108 Bool freeTmpClip, freeCompClip;
109
110 if (pPicture->subWindowMode == IncludeInferiors) {
111 pregWin = NotClippedByChildren(pWin);
112 freeTmpClip = TRUE;
113 }
114 else {
115 pregWin = &pWin->clipList;
116 freeTmpClip = FALSE;
117 }
118 freeCompClip = pPicture->freeCompClip;
119
120 /*
121 * if there is no client clip, we can get by with just keeping the
122 * pointer we got, and remembering whether or not should destroy
123 * (or maybe re-use) it later. this way, we avoid unnecessary
124 * copying of regions. (this wins especially if many clients clip
125 * by children and have no client clip.)
126 */
127 if (!pPicture->clientClip) {
128 if (freeCompClip)
129 RegionDestroy(pPicture->pCompositeClip);
130 pPicture->pCompositeClip = pregWin;
131 pPicture->freeCompClip = freeTmpClip;
132 }
133 else {
134 /*
135 * we need one 'real' region to put into the composite clip. if
136 * pregWin the current composite clip are real, we can get rid of
137 * one. if pregWin is real and the current composite clip isn't,
138 * use pregWin for the composite clip. if the current composite
139 * clip is real and pregWin isn't, use the current composite
140 * clip. if neither is real, create a new region.
141 */
142
143 RegionTranslate(pPicture->clientClip,
144 pDrawable->x + pPicture->clipOrigin.x,
145 pDrawable->y + pPicture->clipOrigin.y);
146
147 if (freeCompClip) {
148 RegionIntersect(pPicture->pCompositeClip,
149 pregWin, pPicture->clientClip);
150 if (freeTmpClip)
151 RegionDestroy(pregWin);
152 }
153 else if (freeTmpClip) {
154 RegionIntersect(pregWin, pregWin, pPicture->clientClip);
155 pPicture->pCompositeClip = pregWin;
156 }
157 else {
158 pPicture->pCompositeClip = RegionCreate(NullBox, 0);
159 RegionIntersect(pPicture->pCompositeClip,
160 pregWin, pPicture->clientClip);
161 }
162 pPicture->freeCompClip = TRUE;
163 RegionTranslate(pPicture->clientClip,
164 -(pDrawable->x + pPicture->clipOrigin.x),
165 -(pDrawable->y + pPicture->clipOrigin.y));
166 }
167 } /* end of composite clip for a window */
168 else {
169 BoxRec pixbounds;
170
171 /* XXX should we translate by drawable.x/y here ? */
172 /* If you want pixmaps in offscreen memory, yes */
173 pixbounds.x1 = pDrawable->x;
174 pixbounds.y1 = pDrawable->y;
175 pixbounds.x2 = pDrawable->x + pDrawable->width;
176 pixbounds.y2 = pDrawable->y + pDrawable->height;
177
178 if (pPicture->freeCompClip) {
179 RegionReset(pPicture->pCompositeClip, &pixbounds);
180 }
181 else {
182 pPicture->freeCompClip = TRUE;
183 pPicture->pCompositeClip = RegionCreate(&pixbounds, 1);
184 }
185
186 if (pPicture->clientClip) {
187 if (pDrawable->x || pDrawable->y) {
188 RegionTranslate(pPicture->clientClip,
189 pDrawable->x + pPicture->clipOrigin.x,
190 pDrawable->y + pPicture->clipOrigin.y);
191 RegionIntersect(pPicture->pCompositeClip,
192 pPicture->pCompositeClip,
193 pPicture->clientClip);
194 RegionTranslate(pPicture->clientClip,
195 -(pDrawable->x + pPicture->clipOrigin.x),
196 -(pDrawable->y + pPicture->clipOrigin.y));
197 }
198 else {
199 RegionTranslate(pPicture->pCompositeClip,
200 -pPicture->clipOrigin.x,
201 -pPicture->clipOrigin.y);
202 RegionIntersect(pPicture->pCompositeClip,
203 pPicture->pCompositeClip,
204 pPicture->clientClip);
205 RegionTranslate(pPicture->pCompositeClip,
206 pPicture->clipOrigin.x,
207 pPicture->clipOrigin.y);
208 }
209 }
210 } /* end of composite clip for pixmap */
211 }
212 }
213
214 static int
miChangePictureTransform(PicturePtr pPicture,PictTransform * transform)215 miChangePictureTransform(PicturePtr pPicture, PictTransform * transform)
216 {
217 return Success;
218 }
219
220 static int
miChangePictureFilter(PicturePtr pPicture,int filter,xFixed * params,int nparams)221 miChangePictureFilter(PicturePtr pPicture,
222 int filter, xFixed * params, int nparams)
223 {
224 return Success;
225 }
226
227 #define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v))
228
229 static inline pixman_bool_t
miClipPictureReg(pixman_region16_t * pRegion,pixman_region16_t * pClip,int dx,int dy)230 miClipPictureReg(pixman_region16_t * pRegion,
231 pixman_region16_t * pClip, int dx, int dy)
232 {
233 if (pixman_region_n_rects(pRegion) == 1 &&
234 pixman_region_n_rects(pClip) == 1) {
235 pixman_box16_t *pRbox = pixman_region_rectangles(pRegion, NULL);
236 pixman_box16_t *pCbox = pixman_region_rectangles(pClip, NULL);
237 int v;
238
239 if (pRbox->x1 < (v = pCbox->x1 + dx))
240 pRbox->x1 = BOUND(v);
241 if (pRbox->x2 > (v = pCbox->x2 + dx))
242 pRbox->x2 = BOUND(v);
243 if (pRbox->y1 < (v = pCbox->y1 + dy))
244 pRbox->y1 = BOUND(v);
245 if (pRbox->y2 > (v = pCbox->y2 + dy))
246 pRbox->y2 = BOUND(v);
247 if (pRbox->x1 >= pRbox->x2 || pRbox->y1 >= pRbox->y2) {
248 pixman_region_init(pRegion);
249 }
250 }
251 else if (!pixman_region_not_empty(pClip))
252 return FALSE;
253 else {
254 if (dx || dy)
255 pixman_region_translate(pRegion, -dx, -dy);
256 if (!pixman_region_intersect(pRegion, pRegion, pClip))
257 return FALSE;
258 if (dx || dy)
259 pixman_region_translate(pRegion, dx, dy);
260 }
261 return pixman_region_not_empty(pRegion);
262 }
263
264 static inline Bool
miClipPictureSrc(RegionPtr pRegion,PicturePtr pPicture,int dx,int dy)265 miClipPictureSrc(RegionPtr pRegion, PicturePtr pPicture, int dx, int dy)
266 {
267 if (pPicture->clientClip) {
268 Bool result;
269
270 pixman_region_translate(pPicture->clientClip,
271 pPicture->clipOrigin.x + dx,
272 pPicture->clipOrigin.y + dy);
273
274 result = RegionIntersect(pRegion, pRegion, pPicture->clientClip);
275
276 pixman_region_translate(pPicture->clientClip,
277 -(pPicture->clipOrigin.x + dx),
278 -(pPicture->clipOrigin.y + dy));
279
280 if (!result)
281 return FALSE;
282 }
283 return TRUE;
284 }
285
286 static void
SourceValidateOnePicture(PicturePtr pPicture)287 SourceValidateOnePicture(PicturePtr pPicture)
288 {
289 DrawablePtr pDrawable = pPicture->pDrawable;
290 ScreenPtr pScreen;
291
292 if (!pDrawable)
293 return;
294
295 pScreen = pDrawable->pScreen;
296
297 pScreen->SourceValidate(pDrawable, 0, 0, pDrawable->width,
298 pDrawable->height, pPicture->subWindowMode);
299 }
300
301 void
miCompositeSourceValidate(PicturePtr pPicture)302 miCompositeSourceValidate(PicturePtr pPicture)
303 {
304 SourceValidateOnePicture(pPicture);
305 if (pPicture->alphaMap)
306 SourceValidateOnePicture(pPicture->alphaMap);
307 }
308
309 /*
310 * returns FALSE if the final region is empty. Indistinguishable from
311 * an allocation failure, but rendering ignores those anyways.
312 */
313
314 Bool
miComputeCompositeRegion(RegionPtr pRegion,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)315 miComputeCompositeRegion(RegionPtr pRegion,
316 PicturePtr pSrc,
317 PicturePtr pMask,
318 PicturePtr pDst,
319 INT16 xSrc,
320 INT16 ySrc,
321 INT16 xMask,
322 INT16 yMask,
323 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
324 {
325
326 int v;
327
328 pRegion->extents.x1 = xDst;
329 v = xDst + width;
330 pRegion->extents.x2 = BOUND(v);
331 pRegion->extents.y1 = yDst;
332 v = yDst + height;
333 pRegion->extents.y2 = BOUND(v);
334 pRegion->data = 0;
335 /* Check for empty operation */
336 if (pRegion->extents.x1 >= pRegion->extents.x2 ||
337 pRegion->extents.y1 >= pRegion->extents.y2) {
338 pixman_region_init(pRegion);
339 return FALSE;
340 }
341 /* clip against dst */
342 if (!miClipPictureReg(pRegion, pDst->pCompositeClip, 0, 0)) {
343 pixman_region_fini(pRegion);
344 return FALSE;
345 }
346 if (pDst->alphaMap) {
347 if (!miClipPictureReg(pRegion, pDst->alphaMap->pCompositeClip,
348 -pDst->alphaOrigin.x, -pDst->alphaOrigin.y)) {
349 pixman_region_fini(pRegion);
350 return FALSE;
351 }
352 }
353 /* clip against src */
354 if (!miClipPictureSrc(pRegion, pSrc, xDst - xSrc, yDst - ySrc)) {
355 pixman_region_fini(pRegion);
356 return FALSE;
357 }
358 if (pSrc->alphaMap) {
359 if (!miClipPictureSrc(pRegion, pSrc->alphaMap,
360 xDst - (xSrc - pSrc->alphaOrigin.x),
361 yDst - (ySrc - pSrc->alphaOrigin.y))) {
362 pixman_region_fini(pRegion);
363 return FALSE;
364 }
365 }
366 /* clip against mask */
367 if (pMask) {
368 if (!miClipPictureSrc(pRegion, pMask, xDst - xMask, yDst - yMask)) {
369 pixman_region_fini(pRegion);
370 return FALSE;
371 }
372 if (pMask->alphaMap) {
373 if (!miClipPictureSrc(pRegion, pMask->alphaMap,
374 xDst - (xMask - pMask->alphaOrigin.x),
375 yDst - (yMask - pMask->alphaOrigin.y))) {
376 pixman_region_fini(pRegion);
377 return FALSE;
378 }
379 }
380 }
381
382 miCompositeSourceValidate(pSrc);
383 if (pMask)
384 miCompositeSourceValidate(pMask);
385
386 return TRUE;
387 }
388
389 void
miRenderColorToPixel(PictFormatPtr format,xRenderColor * color,CARD32 * pixel)390 miRenderColorToPixel(PictFormatPtr format, xRenderColor * color, CARD32 *pixel)
391 {
392 CARD32 r, g, b, a;
393 miIndexedPtr pIndexed;
394
395 switch (format->type) {
396 case PictTypeDirect:
397 r = color->red >> (16 - Ones(format->direct.redMask));
398 g = color->green >> (16 - Ones(format->direct.greenMask));
399 b = color->blue >> (16 - Ones(format->direct.blueMask));
400 a = color->alpha >> (16 - Ones(format->direct.alphaMask));
401 r = r << format->direct.red;
402 g = g << format->direct.green;
403 b = b << format->direct.blue;
404 a = a << format->direct.alpha;
405 *pixel = r | g | b | a;
406 break;
407 case PictTypeIndexed:
408 pIndexed = (miIndexedPtr) (format->index.devPrivate);
409 if (pIndexed->color) {
410 r = color->red >> 11;
411 g = color->green >> 11;
412 b = color->blue >> 11;
413 *pixel = miIndexToEnt15(pIndexed, (r << 10) | (g << 5) | b);
414 }
415 else {
416 r = color->red >> 8;
417 g = color->green >> 8;
418 b = color->blue >> 8;
419 *pixel = miIndexToEntY24(pIndexed, (r << 16) | (g << 8) | b);
420 }
421 break;
422 }
423 }
424
425 static CARD16
miFillColor(CARD32 pixel,int bits)426 miFillColor(CARD32 pixel, int bits)
427 {
428 while (bits < 16) {
429 pixel |= pixel << bits;
430 bits <<= 1;
431 }
432 return (CARD16) pixel;
433 }
434
435 Bool
miIsSolidAlpha(PicturePtr pSrc)436 miIsSolidAlpha(PicturePtr pSrc)
437 {
438 ScreenPtr pScreen;
439 char line[1];
440
441 if (!pSrc->pDrawable)
442 return FALSE;
443
444 pScreen = pSrc->pDrawable->pScreen;
445
446 /* Alpha-only */
447 if (PICT_FORMAT_TYPE(pSrc->format) != PICT_TYPE_A)
448 return FALSE;
449 /* repeat */
450 if (!pSrc->repeat)
451 return FALSE;
452 /* 1x1 */
453 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1)
454 return FALSE;
455 line[0] = 1;
456 (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line);
457 switch (pSrc->pDrawable->bitsPerPixel) {
458 case 1:
459 return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80;
460 case 4:
461 return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0;
462 case 8:
463 return (CARD8) line[0] == 0xff;
464 default:
465 return FALSE;
466 }
467 }
468
469 void
miRenderPixelToColor(PictFormatPtr format,CARD32 pixel,xRenderColor * color)470 miRenderPixelToColor(PictFormatPtr format, CARD32 pixel, xRenderColor * color)
471 {
472 CARD32 r, g, b, a;
473 miIndexedPtr pIndexed;
474
475 switch (format->type) {
476 case PictTypeDirect:
477 r = (pixel >> format->direct.red) & format->direct.redMask;
478 g = (pixel >> format->direct.green) & format->direct.greenMask;
479 b = (pixel >> format->direct.blue) & format->direct.blueMask;
480 a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
481 color->red = miFillColor(r, Ones(format->direct.redMask));
482 color->green = miFillColor(g, Ones(format->direct.greenMask));
483 color->blue = miFillColor(b, Ones(format->direct.blueMask));
484 color->alpha = miFillColor(a, Ones(format->direct.alphaMask));
485 break;
486 case PictTypeIndexed:
487 pIndexed = (miIndexedPtr) (format->index.devPrivate);
488 pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED - 1)];
489 r = (pixel >> 16) & 0xff;
490 g = (pixel >> 8) & 0xff;
491 b = (pixel) & 0xff;
492 color->red = miFillColor(r, 8);
493 color->green = miFillColor(g, 8);
494 color->blue = miFillColor(b, 8);
495 color->alpha = 0xffff;
496 break;
497 }
498 }
499
500 static void
miTriStrip(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int npoints,xPointFixed * points)501 miTriStrip(CARD8 op,
502 PicturePtr pSrc,
503 PicturePtr pDst,
504 PictFormatPtr maskFormat,
505 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
506 {
507 xTriangle *tris, *tri;
508 int ntri;
509
510 ntri = npoints - 2;
511 tris = xallocarray(ntri, sizeof(xTriangle));
512 if (!tris)
513 return;
514
515 for (tri = tris; npoints >= 3; npoints--, points++, tri++) {
516 tri->p1 = points[0];
517 tri->p2 = points[1];
518 tri->p3 = points[2];
519 }
520 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris);
521 free(tris);
522 }
523
524 static void
miTriFan(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int npoints,xPointFixed * points)525 miTriFan(CARD8 op,
526 PicturePtr pSrc,
527 PicturePtr pDst,
528 PictFormatPtr maskFormat,
529 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
530 {
531 xTriangle *tris, *tri;
532 xPointFixed *first;
533 int ntri;
534
535 ntri = npoints - 2;
536 tris = xallocarray(ntri, sizeof(xTriangle));
537 if (!tris)
538 return;
539
540 first = points++;
541 for (tri = tris; npoints >= 3; npoints--, points++, tri++) {
542 tri->p1 = *first;
543 tri->p2 = points[0];
544 tri->p3 = points[1];
545 }
546 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris);
547 free(tris);
548 }
549
550 Bool
miPictureInit(ScreenPtr pScreen,PictFormatPtr formats,int nformats)551 miPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
552 {
553 PictureScreenPtr ps;
554
555 if (!PictureInit(pScreen, formats, nformats))
556 return FALSE;
557 ps = GetPictureScreen(pScreen);
558 ps->CreatePicture = miCreatePicture;
559 ps->DestroyPicture = miDestroyPicture;
560 ps->ChangePictureClip = miChangePictureClip;
561 ps->DestroyPictureClip = miDestroyPictureClip;
562 ps->ChangePicture = miChangePicture;
563 ps->ValidatePicture = miValidatePicture;
564 ps->InitIndexed = miInitIndexed;
565 ps->CloseIndexed = miCloseIndexed;
566 ps->UpdateIndexed = miUpdateIndexed;
567 ps->ChangePictureTransform = miChangePictureTransform;
568 ps->ChangePictureFilter = miChangePictureFilter;
569 ps->RealizeGlyph = miRealizeGlyph;
570 ps->UnrealizeGlyph = miUnrealizeGlyph;
571
572 /* MI rendering routines */
573 ps->Composite = 0; /* requires DDX support */
574 ps->Glyphs = miGlyphs;
575 ps->CompositeRects = miCompositeRects;
576 ps->Trapezoids = 0;
577 ps->Triangles = 0;
578
579 ps->RasterizeTrapezoid = 0; /* requires DDX support */
580 ps->AddTraps = 0; /* requires DDX support */
581 ps->AddTriangles = 0; /* requires DDX support */
582
583 ps->TriStrip = miTriStrip; /* converts call to CompositeTriangles */
584 ps->TriFan = miTriFan;
585
586 return TRUE;
587 }
588