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