3 * Copyright © 1999 Keith Packard
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.
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.
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
28 #include "scrnintstr.h"
30 #include "pixmapstr.h"
31 #include "windowstr.h"
33 #include "picturestr.h"
37 miCreatePicture(PicturePtr pPicture
)
43 miDestroyPicture(PicturePtr pPicture
)
45 if (pPicture
->freeCompClip
)
46 RegionDestroy(pPicture
->pCompositeClip
);
50 miDestroyPictureClip(PicturePtr pPicture
)
52 switch (pPicture
->clientClipType
) {
56 (*pPicture
->pDrawable
->pScreen
->
57 DestroyPixmap
) ((PixmapPtr
) (pPicture
->clientClip
));
61 * we know we'll never have a list of rectangles, since ChangeClip
62 * immediately turns them into a region
64 RegionDestroy(pPicture
->clientClip
);
67 pPicture
->clientClip
= NULL
;
68 pPicture
->clientClipType
= CT_NONE
;
72 miChangePictureClip(PicturePtr pPicture
, int type
, pointer value
, int n
)
74 ScreenPtr pScreen
= pPicture
->pDrawable
->pScreen
;
75 PictureScreenPtr ps
= GetPictureScreen(pScreen
);
81 /* convert the pixmap to a region */
82 clientClip
= (pointer
) BitmapToRegion(pScreen
, (PixmapPtr
) value
);
85 clientClipType
= CT_REGION
;
86 (*pScreen
->DestroyPixmap
) ((PixmapPtr
) value
);
90 clientClipType
= CT_REGION
;
94 clientClipType
= CT_NONE
;
97 clientClip
= (pointer
) RegionFromRects(n
, (xRectangle
*) value
, type
);
100 clientClipType
= CT_REGION
;
104 (*ps
->DestroyPictureClip
) (pPicture
);
105 pPicture
->clientClip
= clientClip
;
106 pPicture
->clientClipType
= clientClipType
;
107 pPicture
->stateChanges
|= CPClipMask
;
112 miChangePicture(PicturePtr pPicture
, Mask mask
)
118 miValidatePicture(PicturePtr pPicture
, Mask mask
)
120 DrawablePtr pDrawable
= pPicture
->pDrawable
;
122 if ((mask
& (CPClipXOrigin
| CPClipYOrigin
| CPClipMask
| CPSubwindowMode
))
123 || (pDrawable
->serialNumber
!=
124 (pPicture
->serialNumber
& DRAWABLE_SERIAL_BITS
))) {
125 if (pDrawable
->type
== DRAWABLE_WINDOW
) {
126 WindowPtr pWin
= (WindowPtr
) pDrawable
;
128 Bool freeTmpClip
, freeCompClip
;
130 if (pPicture
->subWindowMode
== IncludeInferiors
) {
131 pregWin
= NotClippedByChildren(pWin
);
135 pregWin
= &pWin
->clipList
;
138 freeCompClip
= pPicture
->freeCompClip
;
141 * if there is no client clip, we can get by with just keeping the
142 * pointer we got, and remembering whether or not should destroy
143 * (or maybe re-use) it later. this way, we avoid unnecessary
144 * copying of regions. (this wins especially if many clients clip
145 * by children and have no client clip.)
147 if (pPicture
->clientClipType
== CT_NONE
) {
149 RegionDestroy(pPicture
->pCompositeClip
);
150 pPicture
->pCompositeClip
= pregWin
;
151 pPicture
->freeCompClip
= freeTmpClip
;
155 * we need one 'real' region to put into the composite clip. if
156 * pregWin the current composite clip are real, we can get rid of
157 * one. if pregWin is real and the current composite clip isn't,
158 * use pregWin for the composite clip. if the current composite
159 * clip is real and pregWin isn't, use the current composite
160 * clip. if neither is real, create a new region.
163 RegionTranslate(pPicture
->clientClip
,
164 pDrawable
->x
+ pPicture
->clipOrigin
.x
,
165 pDrawable
->y
+ pPicture
->clipOrigin
.y
);
168 RegionIntersect(pPicture
->pCompositeClip
,
169 pregWin
, pPicture
->clientClip
);
171 RegionDestroy(pregWin
);
173 else if (freeTmpClip
) {
174 RegionIntersect(pregWin
, pregWin
, pPicture
->clientClip
);
175 pPicture
->pCompositeClip
= pregWin
;
178 pPicture
->pCompositeClip
= RegionCreate(NullBox
, 0);
179 RegionIntersect(pPicture
->pCompositeClip
,
180 pregWin
, pPicture
->clientClip
);
182 pPicture
->freeCompClip
= TRUE
;
183 RegionTranslate(pPicture
->clientClip
,
184 -(pDrawable
->x
+ pPicture
->clipOrigin
.x
),
185 -(pDrawable
->y
+ pPicture
->clipOrigin
.y
));
187 } /* end of composite clip for a window */
191 /* XXX should we translate by drawable.x/y here ? */
192 /* If you want pixmaps in offscreen memory, yes */
193 pixbounds
.x1
= pDrawable
->x
;
194 pixbounds
.y1
= pDrawable
->y
;
195 pixbounds
.x2
= pDrawable
->x
+ pDrawable
->width
;
196 pixbounds
.y2
= pDrawable
->y
+ pDrawable
->height
;
198 if (pPicture
->freeCompClip
) {
199 RegionReset(pPicture
->pCompositeClip
, &pixbounds
);
202 pPicture
->freeCompClip
= TRUE
;
203 pPicture
->pCompositeClip
= RegionCreate(&pixbounds
, 1);
206 if (pPicture
->clientClipType
== CT_REGION
) {
207 if (pDrawable
->x
|| pDrawable
->y
) {
208 RegionTranslate(pPicture
->clientClip
,
209 pDrawable
->x
+ pPicture
->clipOrigin
.x
,
210 pDrawable
->y
+ pPicture
->clipOrigin
.y
);
211 RegionIntersect(pPicture
->pCompositeClip
,
212 pPicture
->pCompositeClip
,
213 pPicture
->clientClip
);
214 RegionTranslate(pPicture
->clientClip
,
215 -(pDrawable
->x
+ pPicture
->clipOrigin
.x
),
216 -(pDrawable
->y
+ pPicture
->clipOrigin
.y
));
219 RegionTranslate(pPicture
->pCompositeClip
,
220 -pPicture
->clipOrigin
.x
,
221 -pPicture
->clipOrigin
.y
);
222 RegionIntersect(pPicture
->pCompositeClip
,
223 pPicture
->pCompositeClip
,
224 pPicture
->clientClip
);
225 RegionTranslate(pPicture
->pCompositeClip
,
226 pPicture
->clipOrigin
.x
,
227 pPicture
->clipOrigin
.y
);
230 } /* end of composite clip for pixmap */
235 miChangePictureTransform(PicturePtr pPicture
, PictTransform
* transform
)
241 miChangePictureFilter(PicturePtr pPicture
,
242 int filter
, xFixed
* params
, int nparams
)
247 #define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v))
249 static inline pixman_bool_t
250 miClipPictureReg(pixman_region16_t
* pRegion
,
251 pixman_region16_t
* pClip
, int dx
, int dy
)
253 if (pixman_region_n_rects(pRegion
) == 1 &&
254 pixman_region_n_rects(pClip
) == 1) {
255 pixman_box16_t
*pRbox
= pixman_region_rectangles(pRegion
, NULL
);
256 pixman_box16_t
*pCbox
= pixman_region_rectangles(pClip
, NULL
);
259 if (pRbox
->x1
< (v
= pCbox
->x1
+ dx
))
260 pRbox
->x1
= BOUND(v
);
261 if (pRbox
->x2
> (v
= pCbox
->x2
+ dx
))
262 pRbox
->x2
= BOUND(v
);
263 if (pRbox
->y1
< (v
= pCbox
->y1
+ dy
))
264 pRbox
->y1
= BOUND(v
);
265 if (pRbox
->y2
> (v
= pCbox
->y2
+ dy
))
266 pRbox
->y2
= BOUND(v
);
267 if (pRbox
->x1
>= pRbox
->x2
|| pRbox
->y1
>= pRbox
->y2
) {
268 pixman_region_init(pRegion
);
271 else if (!pixman_region_not_empty(pClip
))
275 pixman_region_translate(pRegion
, -dx
, -dy
);
276 if (!pixman_region_intersect(pRegion
, pRegion
, pClip
))
279 pixman_region_translate(pRegion
, dx
, dy
);
281 return pixman_region_not_empty(pRegion
);
285 miClipPictureSrc(RegionPtr pRegion
, PicturePtr pPicture
, int dx
, int dy
)
287 if (pPicture
->clientClipType
!= CT_NONE
) {
290 pixman_region_translate(pPicture
->clientClip
,
291 pPicture
->clipOrigin
.x
+ dx
,
292 pPicture
->clipOrigin
.y
+ dy
);
294 result
= RegionIntersect(pRegion
, pRegion
, pPicture
->clientClip
);
296 pixman_region_translate(pPicture
->clientClip
,
297 -(pPicture
->clipOrigin
.x
+ dx
),
298 -(pPicture
->clipOrigin
.y
+ dy
));
307 SourceValidateOnePicture(PicturePtr pPicture
)
309 DrawablePtr pDrawable
= pPicture
->pDrawable
;
315 pScreen
= pDrawable
->pScreen
;
317 if (pScreen
->SourceValidate
) {
318 pScreen
->SourceValidate(pDrawable
, 0, 0, pDrawable
->width
,
319 pDrawable
->height
, pPicture
->subWindowMode
);
324 miCompositeSourceValidate(PicturePtr pPicture
)
326 SourceValidateOnePicture(pPicture
);
327 if (pPicture
->alphaMap
)
328 SourceValidateOnePicture(pPicture
->alphaMap
);
332 * returns FALSE if the final region is empty. Indistinguishable from
333 * an allocation failure, but rendering ignores those anyways.
337 miComputeCompositeRegion(RegionPtr pRegion
,
345 INT16 xDst
, INT16 yDst
, CARD16 width
, CARD16 height
)
350 pRegion
->extents
.x1
= xDst
;
352 pRegion
->extents
.x2
= BOUND(v
);
353 pRegion
->extents
.y1
= yDst
;
355 pRegion
->extents
.y2
= BOUND(v
);
357 /* Check for empty operation */
358 if (pRegion
->extents
.x1
>= pRegion
->extents
.x2
||
359 pRegion
->extents
.y1
>= pRegion
->extents
.y2
) {
360 pixman_region_init(pRegion
);
363 /* clip against dst */
364 if (!miClipPictureReg(pRegion
, pDst
->pCompositeClip
, 0, 0)) {
365 pixman_region_fini(pRegion
);
368 if (pDst
->alphaMap
) {
369 if (!miClipPictureReg(pRegion
, pDst
->alphaMap
->pCompositeClip
,
370 -pDst
->alphaOrigin
.x
, -pDst
->alphaOrigin
.y
)) {
371 pixman_region_fini(pRegion
);
375 /* clip against src */
376 if (!miClipPictureSrc(pRegion
, pSrc
, xDst
- xSrc
, yDst
- ySrc
)) {
377 pixman_region_fini(pRegion
);
380 if (pSrc
->alphaMap
) {
381 if (!miClipPictureSrc(pRegion
, pSrc
->alphaMap
,
382 xDst
- (xSrc
- pSrc
->alphaOrigin
.x
),
383 yDst
- (ySrc
- pSrc
->alphaOrigin
.y
))) {
384 pixman_region_fini(pRegion
);
388 /* clip against mask */
390 if (!miClipPictureSrc(pRegion
, pMask
, xDst
- xMask
, yDst
- yMask
)) {
391 pixman_region_fini(pRegion
);
394 if (pMask
->alphaMap
) {
395 if (!miClipPictureSrc(pRegion
, pMask
->alphaMap
,
396 xDst
- (xMask
- pMask
->alphaOrigin
.x
),
397 yDst
- (yMask
- pMask
->alphaOrigin
.y
))) {
398 pixman_region_fini(pRegion
);
404 miCompositeSourceValidate(pSrc
);
406 miCompositeSourceValidate(pMask
);
412 miRenderColorToPixel(PictFormatPtr format
, xRenderColor
* color
, CARD32
*pixel
)
415 miIndexedPtr pIndexed
;
417 switch (format
->type
) {
419 r
= color
->red
>> (16 - Ones(format
->direct
.redMask
));
420 g
= color
->green
>> (16 - Ones(format
->direct
.greenMask
));
421 b
= color
->blue
>> (16 - Ones(format
->direct
.blueMask
));
422 a
= color
->alpha
>> (16 - Ones(format
->direct
.alphaMask
));
423 r
= r
<< format
->direct
.red
;
424 g
= g
<< format
->direct
.green
;
425 b
= b
<< format
->direct
.blue
;
426 a
= a
<< format
->direct
.alpha
;
427 *pixel
= r
| g
| b
| a
;
429 case PictTypeIndexed
:
430 pIndexed
= (miIndexedPtr
) (format
->index
.devPrivate
);
431 if (pIndexed
->color
) {
432 r
= color
->red
>> 11;
433 g
= color
->green
>> 11;
434 b
= color
->blue
>> 11;
435 *pixel
= miIndexToEnt15(pIndexed
, (r
<< 10) | (g
<< 5) | b
);
439 g
= color
->green
>> 8;
440 b
= color
->blue
>> 8;
441 *pixel
= miIndexToEntY24(pIndexed
, (r
<< 16) | (g
<< 8) | b
);
448 miFillColor(CARD32 pixel
, int bits
)
451 pixel
|= pixel
<< bits
;
454 return (CARD16
) pixel
;
458 miIsSolidAlpha(PicturePtr pSrc
)
463 if (!pSrc
->pDrawable
)
466 pScreen
= pSrc
->pDrawable
->pScreen
;
469 if (PICT_FORMAT_TYPE(pSrc
->format
) != PICT_TYPE_A
)
475 if (pSrc
->pDrawable
->width
!= 1 || pSrc
->pDrawable
->height
!= 1)
478 (*pScreen
->GetImage
) (pSrc
->pDrawable
, 0, 0, 1, 1, ZPixmap
, ~0L, line
);
479 switch (pSrc
->pDrawable
->bitsPerPixel
) {
481 return (CARD8
) line
[0] == 1 || (CARD8
) line
[0] == 0x80;
483 return (CARD8
) line
[0] == 0xf || (CARD8
) line
[0] == 0xf0;
485 return (CARD8
) line
[0] == 0xff;
492 miRenderPixelToColor(PictFormatPtr format
, CARD32 pixel
, xRenderColor
* color
)
495 miIndexedPtr pIndexed
;
497 switch (format
->type
) {
499 r
= (pixel
>> format
->direct
.red
) & format
->direct
.redMask
;
500 g
= (pixel
>> format
->direct
.green
) & format
->direct
.greenMask
;
501 b
= (pixel
>> format
->direct
.blue
) & format
->direct
.blueMask
;
502 a
= (pixel
>> format
->direct
.alpha
) & format
->direct
.alphaMask
;
503 color
->red
= miFillColor(r
, Ones(format
->direct
.redMask
));
504 color
->green
= miFillColor(g
, Ones(format
->direct
.greenMask
));
505 color
->blue
= miFillColor(b
, Ones(format
->direct
.blueMask
));
506 color
->alpha
= miFillColor(a
, Ones(format
->direct
.alphaMask
));
508 case PictTypeIndexed
:
509 pIndexed
= (miIndexedPtr
) (format
->index
.devPrivate
);
510 pixel
= pIndexed
->rgba
[pixel
& (MI_MAX_INDEXED
- 1)];
511 r
= (pixel
>> 16) & 0xff;
512 g
= (pixel
>> 8) & 0xff;
514 color
->red
= miFillColor(r
, 8);
515 color
->green
= miFillColor(g
, 8);
516 color
->blue
= miFillColor(b
, 8);
517 color
->alpha
= 0xffff;
526 PictFormatPtr maskFormat
,
527 INT16 xSrc
, INT16 ySrc
, int npoints
, xPointFixed
* points
)
529 xTriangle
*tris
, *tri
;
533 tris
= malloc(ntri
* sizeof(xTriangle
));
537 for (tri
= tris
; npoints
>= 3; npoints
--, points
++, tri
++) {
542 CompositeTriangles(op
, pSrc
, pDst
, maskFormat
, xSrc
, ySrc
, ntri
, tris
);
550 PictFormatPtr maskFormat
,
551 INT16 xSrc
, INT16 ySrc
, int npoints
, xPointFixed
* points
)
553 xTriangle
*tris
, *tri
;
558 tris
= malloc(ntri
* sizeof(xTriangle
));
563 for (tri
= tris
; npoints
>= 3; npoints
--, points
++, tri
++) {
568 CompositeTriangles(op
, pSrc
, pDst
, maskFormat
, xSrc
, ySrc
, ntri
, tris
);
573 miPictureInit(ScreenPtr pScreen
, PictFormatPtr formats
, int nformats
)
577 if (!PictureInit(pScreen
, formats
, nformats
))
579 ps
= GetPictureScreen(pScreen
);
580 ps
->CreatePicture
= miCreatePicture
;
581 ps
->DestroyPicture
= miDestroyPicture
;
582 ps
->ChangePictureClip
= miChangePictureClip
;
583 ps
->DestroyPictureClip
= miDestroyPictureClip
;
584 ps
->ChangePicture
= miChangePicture
;
585 ps
->ValidatePicture
= miValidatePicture
;
586 ps
->InitIndexed
= miInitIndexed
;
587 ps
->CloseIndexed
= miCloseIndexed
;
588 ps
->UpdateIndexed
= miUpdateIndexed
;
589 ps
->ChangePictureTransform
= miChangePictureTransform
;
590 ps
->ChangePictureFilter
= miChangePictureFilter
;
591 ps
->RealizeGlyph
= miRealizeGlyph
;
592 ps
->UnrealizeGlyph
= miUnrealizeGlyph
;
594 /* MI rendering routines */
595 ps
->Composite
= 0; /* requires DDX support */
596 ps
->Glyphs
= miGlyphs
;
597 ps
->CompositeRects
= miCompositeRects
;
601 ps
->RasterizeTrapezoid
= 0; /* requires DDX support */
602 ps
->AddTraps
= 0; /* requires DDX support */
603 ps
->AddTriangles
= 0; /* requires DDX support */
605 ps
->TriStrip
= miTriStrip
; /* converts call to CompositeTriangles */
606 ps
->TriFan
= miTriFan
;