/* * $XFree86: xc/programs/Xserver/render/mipict.c,v 1.15tsi Exp $ * * Copyright © 1999 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_DIX_CONFIG_H #include <dix-config.h> #endif #include "scrnintstr.h" #include "gcstruct.h" #include "pixmapstr.h" #include "windowstr.h" #include "mi.h" #include "picturestr.h" #include "mipict.h" #ifndef __GNUC__ #define __inline #endif int miCreatePicture (PicturePtr pPicture) { return Success; } void miDestroyPicture (PicturePtr pPicture) { if (pPicture->freeCompClip) REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->pCompositeClip); } void miDestroyPictureClip (PicturePtr pPicture) { switch (pPicture->clientClipType) { case CT_NONE: return; case CT_PIXMAP: (*pPicture->pDrawable->pScreen->DestroyPixmap) ((PixmapPtr) (pPicture->clientClip)); break; default: /* * we know we'll never have a list of rectangles, since ChangeClip * immediately turns them into a region */ REGION_DESTROY(pPicture->pDrawable->pScreen, pPicture->clientClip); break; } pPicture->clientClip = NULL; pPicture->clientClipType = CT_NONE; } int miChangePictureClip (PicturePtr pPicture, int type, void * value, int n) { ScreenPtr pScreen = pPicture->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); void * clientClip; int clientClipType; switch (type) { case CT_PIXMAP: /* convert the pixmap to a region */ clientClip = (void *) BITMAP_TO_REGION(pScreen, (PixmapPtr) value); if (!clientClip) return BadAlloc; clientClipType = CT_REGION; (*pScreen->DestroyPixmap) ((PixmapPtr) value); break; case CT_REGION: clientClip = value; clientClipType = CT_REGION; break; case CT_NONE: clientClip = 0; clientClipType = CT_NONE; break; default: clientClip = (void *) RECTS_TO_REGION(pScreen, n, (xRectangle *) value, type); if (!clientClip) return BadAlloc; clientClipType = CT_REGION; xfree(value); break; } (*ps->DestroyPictureClip) (pPicture); pPicture->clientClip = clientClip; pPicture->clientClipType = clientClipType; pPicture->stateChanges |= CPClipMask; return Success; } void miChangePicture (PicturePtr pPicture, Mask mask) { return; } void miValidatePicture (PicturePtr pPicture, Mask mask) { DrawablePtr pDrawable = pPicture->pDrawable; ScreenPtr pScreen = pDrawable->pScreen; if ((mask & (CPClipXOrigin|CPClipYOrigin|CPClipMask|CPSubwindowMode)) || (pDrawable->serialNumber != (pPicture->serialNumber & DRAWABLE_SERIAL_BITS))) { if (pDrawable->type == DRAWABLE_WINDOW) { WindowPtr pWin = (WindowPtr) pDrawable; RegionPtr pregWin; Bool freeTmpClip, freeCompClip; if (pPicture->subWindowMode == IncludeInferiors) { pregWin = NotClippedByChildren(pWin); freeTmpClip = TRUE; } else { pregWin = &pWin->clipList; freeTmpClip = FALSE; } freeCompClip = pPicture->freeCompClip; /* * if there is no client clip, we can get by with just keeping the * pointer we got, and remembering whether or not should destroy * (or maybe re-use) it later. this way, we avoid unnecessary * copying of regions. (this wins especially if many clients clip * by children and have no client clip.) */ if (pPicture->clientClipType == CT_NONE) { if (freeCompClip) REGION_DESTROY(pScreen, pPicture->pCompositeClip); pPicture->pCompositeClip = pregWin; pPicture->freeCompClip = freeTmpClip; } else { /* * we need one 'real' region to put into the composite clip. if * pregWin the current composite clip are real, we can get rid of * one. if pregWin is real and the current composite clip isn't, * use pregWin for the composite clip. if the current composite * clip is real and pregWin isn't, use the current composite * clip. if neither is real, create a new region. */ REGION_TRANSLATE(pScreen, pPicture->clientClip, pDrawable->x + pPicture->clipOrigin.x, pDrawable->y + pPicture->clipOrigin.y); if (freeCompClip) { REGION_INTERSECT(pScreen, pPicture->pCompositeClip, pregWin, pPicture->clientClip); if (freeTmpClip) REGION_DESTROY(pScreen, pregWin); } else if (freeTmpClip) { REGION_INTERSECT(pScreen, pregWin, pregWin, pPicture->clientClip); pPicture->pCompositeClip = pregWin; } else { pPicture->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); REGION_INTERSECT(pScreen, pPicture->pCompositeClip, pregWin, pPicture->clientClip); } pPicture->freeCompClip = TRUE; REGION_TRANSLATE(pScreen, pPicture->clientClip, -(pDrawable->x + pPicture->clipOrigin.x), -(pDrawable->y + pPicture->clipOrigin.y)); } } /* end of composite clip for a window */ else { BoxRec pixbounds; /* XXX should we translate by drawable.x/y here ? */ /* If you want pixmaps in offscreen memory, yes */ pixbounds.x1 = pDrawable->x; pixbounds.y1 = pDrawable->y; pixbounds.x2 = pDrawable->x + pDrawable->width; pixbounds.y2 = pDrawable->y + pDrawable->height; if (pPicture->freeCompClip) { REGION_RESET(pScreen, pPicture->pCompositeClip, &pixbounds); } else { pPicture->freeCompClip = TRUE; pPicture->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1); } if (pPicture->clientClipType == CT_REGION) { if(pDrawable->x || pDrawable->y) { REGION_TRANSLATE(pScreen, pPicture->clientClip, pDrawable->x + pPicture->clipOrigin.x, pDrawable->y + pPicture->clipOrigin.y); REGION_INTERSECT(pScreen, pPicture->pCompositeClip, pPicture->pCompositeClip, pPicture->clientClip); REGION_TRANSLATE(pScreen, pPicture->clientClip, -(pDrawable->x + pPicture->clipOrigin.x), -(pDrawable->y + pPicture->clipOrigin.y)); } else { REGION_TRANSLATE(pScreen, pPicture->pCompositeClip, -pPicture->clipOrigin.x, -pPicture->clipOrigin.y); REGION_INTERSECT(pScreen, pPicture->pCompositeClip, pPicture->pCompositeClip, pPicture->clientClip); REGION_TRANSLATE(pScreen, pPicture->pCompositeClip, pPicture->clipOrigin.x, pPicture->clipOrigin.y); } } } /* end of composite clip for pixmap */ } } int miChangePictureTransform (PicturePtr pPicture, PictTransform *transform) { return Success; } int miChangePictureFilter (PicturePtr pPicture, int filter, xFixed *params, int nparams) { return Success; } #define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) static __inline Bool miClipPictureReg (RegionPtr pRegion, RegionPtr pClip, int dx, int dy) { if (REGION_NUM_RECTS(pRegion) == 1 && REGION_NUM_RECTS(pClip) == 1) { BoxPtr pRbox = REGION_RECTS(pRegion); BoxPtr pCbox = REGION_RECTS(pClip); int v; if (pRbox->x1 < (v = pCbox->x1 + dx)) pRbox->x1 = BOUND(v); if (pRbox->x2 > (v = pCbox->x2 + dx)) pRbox->x2 = BOUND(v); if (pRbox->y1 < (v = pCbox->y1 + dy)) pRbox->y1 = BOUND(v); if (pRbox->y2 > (v = pCbox->y2 + dy)) pRbox->y2 = BOUND(v); if (pRbox->x1 >= pRbox->x2 || pRbox->y1 >= pRbox->y2) { REGION_EMPTY(pScreen, pRegion); } } else if (!REGION_NOTEMPTY (pScreen, pClip)) return FALSE; else { if (dx || dy) REGION_TRANSLATE(pScreen, pRegion, -dx, -dy); if (!REGION_INTERSECT (pScreen, pRegion, pRegion, pClip)) return FALSE; if (dx || dy) REGION_TRANSLATE(pScreen, pRegion, dx, dy); } return REGION_NOTEMPTY(pScreen, pRegion); } static __inline Bool miClipPictureSrc (RegionPtr pRegion, PicturePtr pPicture, int dx, int dy) { /* XXX what to do with clipping from transformed pictures? */ if (pPicture->transform || !pPicture->pDrawable) return TRUE; if (pPicture->repeat) { if (pPicture->clientClipType != CT_NONE) { REGION_TRANSLATE(pScreen, pRegion, dx - pPicture->clipOrigin.x, dy - pPicture->clipOrigin.y); if (!REGION_INTERSECT (pScreen, pRegion, pRegion, (RegionPtr) pPicture->clientClip)) return FALSE; REGION_TRANSLATE(pScreen, pRegion, - (dx - pPicture->clipOrigin.x), - (dy - pPicture->clipOrigin.y)); } return TRUE; } else { return miClipPictureReg (pRegion, pPicture->pCompositeClip, dx, dy); } } static void miCompositeSourceValidate (PicturePtr pPicture, INT16 x, INT16 y, CARD16 width, CARD16 height) { DrawablePtr pDrawable = pPicture->pDrawable; ScreenPtr pScreen; if (!pDrawable) return; pScreen = pDrawable->pScreen; if (pScreen->SourceValidate) { x -= pPicture->pDrawable->x; y -= pPicture->pDrawable->y; if (pPicture->transform) { xPoint points[4]; int i; int xmin, ymin, xmax, ymax; #define VectorSet(i,_x,_y) { points[i].x = _x; points[i].y = _y; } VectorSet (0, x, y); VectorSet (1, x + width, y); VectorSet (2, x, y + height); VectorSet (3, x + width, y + height); xmin = ymin = 32767; xmax = ymax = -32737; for (i = 0; i < 4; i++) { PictVector t; t.vector[0] = IntToxFixed (points[i].x); t.vector[1] = IntToxFixed (points[i].y); t.vector[2] = xFixed1; if (PictureTransformPoint (pPicture->transform, &t)) { int tx = xFixedToInt (t.vector[0]); int ty = xFixedToInt (t.vector[1]); if (tx < xmin) xmin = tx; if (tx > xmax) xmax = tx; if (ty < ymin) ymin = ty; if (ty > ymax) ymax = ty; } } x = xmin; y = ymin; width = xmax - xmin; height = ymax - ymin; } (*pScreen->SourceValidate) (pDrawable, x, y, width, height); } } /* * returns FALSE if the final region is empty. Indistinguishable from * an allocation failure, but rendering ignores those anyways. */ 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) { int v; pRegion->extents.x1 = xDst; v = xDst + width; pRegion->extents.x2 = BOUND(v); pRegion->extents.y1 = yDst; v = yDst + height; pRegion->extents.y2 = BOUND(v); pRegion->data = 0; /* Check for empty operation */ if (pRegion->extents.x1 >= pRegion->extents.x2 || pRegion->extents.y1 >= pRegion->extents.y2) { REGION_EMPTY (pDst->pDrawable->pScreen, pRegion); return FALSE; } /* clip against dst */ if (!miClipPictureReg (pRegion, pDst->pCompositeClip, 0, 0)) { REGION_UNINIT (pScreen, pRegion); return FALSE; } if (pDst->alphaMap) { if (!miClipPictureReg (pRegion, pDst->alphaMap->pCompositeClip, -pDst->alphaOrigin.x, -pDst->alphaOrigin.y)) { REGION_UNINIT (pScreen, pRegion); return FALSE; } } /* clip against src */ if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc)) { REGION_UNINIT (pScreen, pRegion); return FALSE; } if (pSrc->alphaMap) { if (!miClipPictureSrc (pRegion, pSrc->alphaMap, xDst - (xSrc + pSrc->alphaOrigin.x), yDst - (ySrc + pSrc->alphaOrigin.y))) { REGION_UNINIT (pScreen, pRegion); return FALSE; } } /* clip against mask */ if (pMask) { if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask)) { REGION_UNINIT (pScreen, pRegion); return FALSE; } if (pMask->alphaMap) { if (!miClipPictureSrc (pRegion, pMask->alphaMap, xDst - (xMask + pMask->alphaOrigin.x), yDst - (yMask + pMask->alphaOrigin.y))) { REGION_UNINIT (pScreen, pRegion); return FALSE; } } } miCompositeSourceValidate (pSrc, xSrc, ySrc, width, height); if (pMask) miCompositeSourceValidate (pMask, xMask, yMask, width, height); return TRUE; } void miRenderColorToPixel (PictFormatPtr format, xRenderColor *color, CARD32 *pixel) { CARD32 r, g, b, a; miIndexedPtr pIndexed; switch (format->type) { case PictTypeDirect: r = color->red >> (16 - Ones (format->direct.redMask)); g = color->green >> (16 - Ones (format->direct.greenMask)); b = color->blue >> (16 - Ones (format->direct.blueMask)); a = color->alpha >> (16 - Ones (format->direct.alphaMask)); r = r << format->direct.red; g = g << format->direct.green; b = b << format->direct.blue; a = a << format->direct.alpha; *pixel = r|g|b|a; break; case PictTypeIndexed: pIndexed = (miIndexedPtr) (format->index.devPrivate); if (pIndexed->color) { r = color->red >> 11; g = color->green >> 11; b = color->blue >> 11; *pixel = miIndexToEnt15 (pIndexed, (r << 10) | (g << 5) | b); } else { r = color->red >> 8; g = color->green >> 8; b = color->blue >> 8; *pixel = miIndexToEntY24 (pIndexed, (r << 16) | (g << 8) | b); } break; } } static CARD16 miFillColor (CARD32 pixel, int bits) { while (bits < 16) { pixel |= pixel << bits; bits <<= 1; } return (CARD16) pixel; } Bool miIsSolidAlpha (PicturePtr pSrc) { ScreenPtr pScreen; char line[1]; if (!pSrc->pDrawable) return FALSE; pScreen = pSrc->pDrawable->pScreen; /* Alpha-only */ if (PICT_FORMAT_TYPE (pSrc->format) != PICT_TYPE_A) return FALSE; /* repeat */ if (!pSrc->repeat) return FALSE; /* 1x1 */ if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) return FALSE; line[0] = 1; (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line); switch (pSrc->pDrawable->bitsPerPixel) { case 1: return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80; case 4: return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0; case 8: return (CARD8) line[0] == 0xff; default: return FALSE; } } void miRenderPixelToColor (PictFormatPtr format, CARD32 pixel, xRenderColor *color) { CARD32 r, g, b, a; miIndexedPtr pIndexed; switch (format->type) { case PictTypeDirect: r = (pixel >> format->direct.red) & format->direct.redMask; g = (pixel >> format->direct.green) & format->direct.greenMask; b = (pixel >> format->direct.blue) & format->direct.blueMask; a = (pixel >> format->direct.alpha) & format->direct.alphaMask; color->red = miFillColor (r, Ones (format->direct.redMask)); color->green = miFillColor (g, Ones (format->direct.greenMask)); color->blue = miFillColor (b, Ones (format->direct.blueMask)); color->alpha = miFillColor (a, Ones (format->direct.alphaMask)); break; case PictTypeIndexed: pIndexed = (miIndexedPtr) (format->index.devPrivate); pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED-1)]; r = (pixel >> 16) & 0xff; g = (pixel >> 8) & 0xff; b = (pixel ) & 0xff; color->red = miFillColor (r, 8); color->green = miFillColor (g, 8); color->blue = miFillColor (b, 8); color->alpha = 0xffff; break; } } Bool miPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) { PictureScreenPtr ps; if (!PictureInit (pScreen, formats, nformats)) return FALSE; ps = GetPictureScreen(pScreen); ps->CreatePicture = miCreatePicture; ps->DestroyPicture = miDestroyPicture; ps->ChangePictureClip = miChangePictureClip; ps->DestroyPictureClip = miDestroyPictureClip; ps->ChangePicture = miChangePicture; ps->ValidatePicture = miValidatePicture; ps->InitIndexed = miInitIndexed; ps->CloseIndexed = miCloseIndexed; ps->UpdateIndexed = miUpdateIndexed; ps->ChangePictureTransform = miChangePictureTransform; ps->ChangePictureFilter = miChangePictureFilter; /* MI rendering routines */ ps->Composite = 0; /* requires DDX support */ ps->Glyphs = miGlyphs; ps->CompositeRects = miCompositeRects; ps->Trapezoids = miTrapezoids; ps->Triangles = miTriangles; ps->TriStrip = miTriStrip; ps->TriFan = miTriFan; ps->RasterizeTrapezoid = 0; /* requires DDX support */ ps->AddTraps = 0; /* requires DDX support */ ps->AddTriangles = 0; /* requires DDX support */ return TRUE; }