xref: /OK3568_Linux_fs/external/xserver/render/mipict.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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