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 if (pScreen->SourceValidate) {
298 pScreen->SourceValidate(pDrawable, 0, 0, pDrawable->width,
299 pDrawable->height, pPicture->subWindowMode);
300 }
301 }
302
303 void
miCompositeSourceValidate(PicturePtr pPicture)304 miCompositeSourceValidate(PicturePtr pPicture)
305 {
306 SourceValidateOnePicture(pPicture);
307 if (pPicture->alphaMap)
308 SourceValidateOnePicture(pPicture->alphaMap);
309 }
310
311 /*
312 * returns FALSE if the final region is empty. Indistinguishable from
313 * an allocation failure, but rendering ignores those anyways.
314 */
315
316 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)317 miComputeCompositeRegion(RegionPtr pRegion,
318 PicturePtr pSrc,
319 PicturePtr pMask,
320 PicturePtr pDst,
321 INT16 xSrc,
322 INT16 ySrc,
323 INT16 xMask,
324 INT16 yMask,
325 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
326 {
327
328 int v;
329
330 pRegion->extents.x1 = xDst;
331 v = xDst + width;
332 pRegion->extents.x2 = BOUND(v);
333 pRegion->extents.y1 = yDst;
334 v = yDst + height;
335 pRegion->extents.y2 = BOUND(v);
336 pRegion->data = 0;
337 /* Check for empty operation */
338 if (pRegion->extents.x1 >= pRegion->extents.x2 ||
339 pRegion->extents.y1 >= pRegion->extents.y2) {
340 pixman_region_init(pRegion);
341 return FALSE;
342 }
343 /* clip against dst */
344 if (!miClipPictureReg(pRegion, pDst->pCompositeClip, 0, 0)) {
345 pixman_region_fini(pRegion);
346 return FALSE;
347 }
348 if (pDst->alphaMap) {
349 if (!miClipPictureReg(pRegion, pDst->alphaMap->pCompositeClip,
350 -pDst->alphaOrigin.x, -pDst->alphaOrigin.y)) {
351 pixman_region_fini(pRegion);
352 return FALSE;
353 }
354 }
355 /* clip against src */
356 if (!miClipPictureSrc(pRegion, pSrc, xDst - xSrc, yDst - ySrc)) {
357 pixman_region_fini(pRegion);
358 return FALSE;
359 }
360 if (pSrc->alphaMap) {
361 if (!miClipPictureSrc(pRegion, pSrc->alphaMap,
362 xDst - (xSrc - pSrc->alphaOrigin.x),
363 yDst - (ySrc - pSrc->alphaOrigin.y))) {
364 pixman_region_fini(pRegion);
365 return FALSE;
366 }
367 }
368 /* clip against mask */
369 if (pMask) {
370 if (!miClipPictureSrc(pRegion, pMask, xDst - xMask, yDst - yMask)) {
371 pixman_region_fini(pRegion);
372 return FALSE;
373 }
374 if (pMask->alphaMap) {
375 if (!miClipPictureSrc(pRegion, pMask->alphaMap,
376 xDst - (xMask - pMask->alphaOrigin.x),
377 yDst - (yMask - pMask->alphaOrigin.y))) {
378 pixman_region_fini(pRegion);
379 return FALSE;
380 }
381 }
382 }
383
384 miCompositeSourceValidate(pSrc);
385 if (pMask)
386 miCompositeSourceValidate(pMask);
387
388 return TRUE;
389 }
390
391 void
miRenderColorToPixel(PictFormatPtr format,xRenderColor * color,CARD32 * pixel)392 miRenderColorToPixel(PictFormatPtr format, xRenderColor * color, CARD32 *pixel)
393 {
394 CARD32 r, g, b, a;
395 miIndexedPtr pIndexed;
396
397 switch (format->type) {
398 case PictTypeDirect:
399 r = color->red >> (16 - Ones(format->direct.redMask));
400 g = color->green >> (16 - Ones(format->direct.greenMask));
401 b = color->blue >> (16 - Ones(format->direct.blueMask));
402 a = color->alpha >> (16 - Ones(format->direct.alphaMask));
403 r = r << format->direct.red;
404 g = g << format->direct.green;
405 b = b << format->direct.blue;
406 a = a << format->direct.alpha;
407 *pixel = r | g | b | a;
408 break;
409 case PictTypeIndexed:
410 pIndexed = (miIndexedPtr) (format->index.devPrivate);
411 if (pIndexed->color) {
412 r = color->red >> 11;
413 g = color->green >> 11;
414 b = color->blue >> 11;
415 *pixel = miIndexToEnt15(pIndexed, (r << 10) | (g << 5) | b);
416 }
417 else {
418 r = color->red >> 8;
419 g = color->green >> 8;
420 b = color->blue >> 8;
421 *pixel = miIndexToEntY24(pIndexed, (r << 16) | (g << 8) | b);
422 }
423 break;
424 }
425 }
426
427 static CARD16
miFillColor(CARD32 pixel,int bits)428 miFillColor(CARD32 pixel, int bits)
429 {
430 while (bits < 16) {
431 pixel |= pixel << bits;
432 bits <<= 1;
433 }
434 return (CARD16) pixel;
435 }
436
437 Bool
miIsSolidAlpha(PicturePtr pSrc)438 miIsSolidAlpha(PicturePtr pSrc)
439 {
440 ScreenPtr pScreen;
441 char line[1];
442
443 if (!pSrc->pDrawable)
444 return FALSE;
445
446 pScreen = pSrc->pDrawable->pScreen;
447
448 /* Alpha-only */
449 if (PICT_FORMAT_TYPE(pSrc->format) != PICT_TYPE_A)
450 return FALSE;
451 /* repeat */
452 if (!pSrc->repeat)
453 return FALSE;
454 /* 1x1 */
455 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1)
456 return FALSE;
457 line[0] = 1;
458 (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line);
459 switch (pSrc->pDrawable->bitsPerPixel) {
460 case 1:
461 return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80;
462 case 4:
463 return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0;
464 case 8:
465 return (CARD8) line[0] == 0xff;
466 default:
467 return FALSE;
468 }
469 }
470
471 void
miRenderPixelToColor(PictFormatPtr format,CARD32 pixel,xRenderColor * color)472 miRenderPixelToColor(PictFormatPtr format, CARD32 pixel, xRenderColor * color)
473 {
474 CARD32 r, g, b, a;
475 miIndexedPtr pIndexed;
476
477 switch (format->type) {
478 case PictTypeDirect:
479 r = (pixel >> format->direct.red) & format->direct.redMask;
480 g = (pixel >> format->direct.green) & format->direct.greenMask;
481 b = (pixel >> format->direct.blue) & format->direct.blueMask;
482 a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
483 color->red = miFillColor(r, Ones(format->direct.redMask));
484 color->green = miFillColor(g, Ones(format->direct.greenMask));
485 color->blue = miFillColor(b, Ones(format->direct.blueMask));
486 color->alpha = miFillColor(a, Ones(format->direct.alphaMask));
487 break;
488 case PictTypeIndexed:
489 pIndexed = (miIndexedPtr) (format->index.devPrivate);
490 pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED - 1)];
491 r = (pixel >> 16) & 0xff;
492 g = (pixel >> 8) & 0xff;
493 b = (pixel) & 0xff;
494 color->red = miFillColor(r, 8);
495 color->green = miFillColor(g, 8);
496 color->blue = miFillColor(b, 8);
497 color->alpha = 0xffff;
498 break;
499 }
500 }
501
502 static void
miTriStrip(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int npoints,xPointFixed * points)503 miTriStrip(CARD8 op,
504 PicturePtr pSrc,
505 PicturePtr pDst,
506 PictFormatPtr maskFormat,
507 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
508 {
509 xTriangle *tris, *tri;
510 int ntri;
511
512 ntri = npoints - 2;
513 tris = xallocarray(ntri, sizeof(xTriangle));
514 if (!tris)
515 return;
516
517 for (tri = tris; npoints >= 3; npoints--, points++, tri++) {
518 tri->p1 = points[0];
519 tri->p2 = points[1];
520 tri->p3 = points[2];
521 }
522 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris);
523 free(tris);
524 }
525
526 static void
miTriFan(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int npoints,xPointFixed * points)527 miTriFan(CARD8 op,
528 PicturePtr pSrc,
529 PicturePtr pDst,
530 PictFormatPtr maskFormat,
531 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
532 {
533 xTriangle *tris, *tri;
534 xPointFixed *first;
535 int ntri;
536
537 ntri = npoints - 2;
538 tris = xallocarray(ntri, sizeof(xTriangle));
539 if (!tris)
540 return;
541
542 first = points++;
543 for (tri = tris; npoints >= 3; npoints--, points++, tri++) {
544 tri->p1 = *first;
545 tri->p2 = points[0];
546 tri->p3 = points[1];
547 }
548 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris);
549 free(tris);
550 }
551
552 Bool
miPictureInit(ScreenPtr pScreen,PictFormatPtr formats,int nformats)553 miPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
554 {
555 PictureScreenPtr ps;
556
557 if (!PictureInit(pScreen, formats, nformats))
558 return FALSE;
559 ps = GetPictureScreen(pScreen);
560 ps->CreatePicture = miCreatePicture;
561 ps->DestroyPicture = miDestroyPicture;
562 ps->ChangePictureClip = miChangePictureClip;
563 ps->DestroyPictureClip = miDestroyPictureClip;
564 ps->ChangePicture = miChangePicture;
565 ps->ValidatePicture = miValidatePicture;
566 ps->InitIndexed = miInitIndexed;
567 ps->CloseIndexed = miCloseIndexed;
568 ps->UpdateIndexed = miUpdateIndexed;
569 ps->ChangePictureTransform = miChangePictureTransform;
570 ps->ChangePictureFilter = miChangePictureFilter;
571 ps->RealizeGlyph = miRealizeGlyph;
572 ps->UnrealizeGlyph = miUnrealizeGlyph;
573
574 /* MI rendering routines */
575 ps->Composite = 0; /* requires DDX support */
576 ps->Glyphs = miGlyphs;
577 ps->CompositeRects = miCompositeRects;
578 ps->Trapezoids = 0;
579 ps->Triangles = 0;
580
581 ps->RasterizeTrapezoid = 0; /* requires DDX support */
582 ps->AddTraps = 0; /* requires DDX support */
583 ps->AddTriangles = 0; /* requires DDX support */
584
585 ps->TriStrip = miTriStrip; /* converts call to CompositeTriangles */
586 ps->TriFan = miTriFan;
587
588 return TRUE;
589 }
590