/* * Copyright © 2000 SuSE, Inc. * * 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 SuSE not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. SuSE makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * 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. * * Author: Keith Packard, SuSE, Inc. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include "misc.h" #include "screenint.h" #include "drv_scrnintstr.h" #include "drv_picturestr.h" #include "drv_pixmapstr.h" #include "drv_gcstruct.h" #define NEXT_VAL(_type) (vlist ? (_type) *vlist++ : (_type) ulist++->val) #define NEXT_PTR(_type) ((_type) ulist++->ptr) DevPrivateKeyRec DrvPictureScreenPrivateKeyRec; int DrvChangePicture (DrvPicturePtr pPicture, Mask vmask, int *vlist, DevUnion *ulist) { DrvScreenPtr pScreen = pPicture->pPixmap ? pPicture->pPixmap->pDrvScreen : 0; DrvPictureScreenPtr ps = pScreen ? DrvGetPictureScreen(pScreen) : 0; BITS32 index2; int error = 0; BITS32 maskQ; maskQ = vmask; while (vmask && !error) { index2 = (BITS32) lowbit (vmask); vmask &= ~index2; pPicture->stateChanges |= index2; switch (index2) { case CPRepeat: { unsigned int newr; newr = NEXT_VAL(unsigned int); if (newr <= RepeatReflect) { pPicture->repeat = (newr != RepeatNone); pPicture->repeatType = newr; } else { error = BadValue; } } break; case CPAlphaMap: #if 0 { DrvPicturePtr pAlpha; if (vlist) { Picture pid = NEXT_VAL(Picture); if (pid == None) pAlpha = 0; else { error = dixLookupResourceByType((pointer *)&pAlpha, pid, PictureType, client, DixReadAccess); if (error != Success) { client->errorValue = pid; break; } if (pAlpha->pDrawable == NULL || pAlpha->pDrawable->type != DRAWABLE_PIXMAP) { client->errorValue = pid; error = BadMatch; break; } } } else pAlpha = NEXT_PTR(PicturePtr); if (!error) { if (pAlpha && pAlpha->pDrawable->type == DRAWABLE_PIXMAP) pAlpha->refcnt++; if (pPicture->alphaMap) DrvFreePicture ((pointer) pPicture->alphaMap); pPicture->alphaMap = pAlpha; } } break; case CPAlphaXOrigin: pPicture->alphaOrigin.x = NEXT_VAL(INT16); break; case CPAlphaYOrigin: pPicture->alphaOrigin.y = NEXT_VAL(INT16); break; case CPClipXOrigin: pPicture->clipOrigin.x = NEXT_VAL(INT16); break; case CPClipYOrigin: pPicture->clipOrigin.y = NEXT_VAL(INT16); break; #endif case CPClipMask: { Pixmap pid; DrvPixmapPtr pPixmap; int clipType; if (!pScreen) return BadDrawable; if (vlist) { pid = NEXT_VAL(Pixmap); if (pid == None) { clipType = CT_NONE; pPixmap = NullDrvPixmap; } else { #if 0 clipType = CT_PIXMAP; error = dixLookupResourceByType((pointer *)&pPixmap, pid, RT_PIXMAP, client, DixReadAccess); if (error != Success) { client->errorValue = pid; break; } #endif } } else { pPixmap = NEXT_PTR(DrvPixmapPtr); if (pPixmap) clipType = CT_PIXMAP; else clipType = CT_NONE; } if (pPixmap) { if ((pPixmap->depth != 1) || (pPixmap->pDrvScreen != pScreen)) { error = BadMatch; break; } else { clipType = CT_PIXMAP; pPixmap->refcnt++; } } // error = (*ps->ChangePictureClip)(pPicture, clipType, // (pointer)pPixmap, 0); break; } break; #if 0 case CPPolyEdge: { unsigned int newe; newe = NEXT_VAL(unsigned int); if (newe == PolyEdgeSharp || newe == PolyEdgeSmooth) pPicture->polyEdge = newe; else { error = BadValue; } } break; case CPPolyMode: { unsigned int newm; newm = NEXT_VAL(unsigned int); if (newm == PolyModePrecise || newm == PolyModeImprecise) pPicture->polyMode = newm; else { client->errorValue = newm; error = BadValue; } } break; #endif case CPDither: (void) NEXT_VAL(Atom); /* unimplemented */ break; case CPComponentAlpha: { unsigned int newca; newca = NEXT_VAL (unsigned int); if (newca <= xTrue) pPicture->componentAlpha = newca; else { error = BadValue; } } break; default: error = BadValue; break; } } // if (ps) // (*ps->ChangePicture) (pPicture, maskQ); return error; } int DrvFreePicture (pointer value) { DrvPicturePtr pPicture = (DrvPicturePtr) value; if (--pPicture->refcnt == 0) { free(pPicture->transform); if (pPicture->pSourcePict) { if (pPicture->pSourcePict->type != SourcePictTypeSolidFill) free(pPicture->pSourcePict->linear.stops); free(pPicture->pSourcePict); } if (pPicture->pPixmap) { DrvScreenPtr pScreen = pPicture->pPixmap->pDrvScreen; DrvPictureScreenPtr ps = DrvGetPictureScreen(pScreen); if (pPicture->alphaMap) DrvFreePicture ((pointer) pPicture->alphaMap); // (*ps->gpu.DestroyPicture) (pPicture); // (*ps->DestroyPictureClip) (pPicture); (*pScreen->DestroyPixmap) (pPicture->pPixmap); } dixFreeObjectWithPrivates(pPicture, PRIVATE_DRV_PICTURE); } return Success; } static void SetDrvPictureToDefaults (DrvPicturePtr pPicture) { pPicture->refcnt = 1; pPicture->repeat = 0; pPicture->polyEdge = PolyEdgeSharp; pPicture->polyMode = PolyModePrecise; pPicture->freeCompClip = FALSE; pPicture->clientClipType = CT_NONE; pPicture->componentAlpha = FALSE; pPicture->repeatType = RepeatNone; pPicture->alphaMap = 0; pPicture->alphaOrigin.x = 0; pPicture->alphaOrigin.y = 0; // pPicture->clipOrigin.x = 0; // pPicture->clipOrigin.y = 0; // pPicture->clientClip = 0; pPicture->transform = 0; pPicture->filter = PictureGetFilterId (FilterNearest, -1, TRUE); pPicture->filter_params = 0; pPicture->filter_nparams = 0; pPicture->stateChanges = -1; pPicture->pSourcePict = 0; } DrvPicturePtr DrvCreatePicture (DrvPixmapPtr pPixmap, PictFormatPtr pFormat, Mask vmask, int *vlist) { DrvPicturePtr pPicture; int error = Success; pPicture = dixAllocateObjectWithPrivates(DrvPictureRec, PRIVATE_DRV_PICTURE); if (!pPicture) { return 0; } pPicture->pPixmap = pPixmap; pPicture->pFormat = pFormat; if (pFormat) { pPicture->format = pFormat->format; if (pPixmap) pPicture->format |= (pPixmap->bitsPerPixel << 24); } if (pPixmap) ++pPixmap->refcnt; pPicture->pNext = 0; SetDrvPictureToDefaults (pPicture); if (vmask) error = DrvChangePicture (pPicture, vmask, vlist,0); // else // ero // if (*error == Success) // *error = (*ps->CreatePicture) (pPicture); out: if (error != Success) { DrvFreePicture (pPicture); pPicture = 0; } return pPicture; } void DrvValidatePicture (DrvPicturePtr pPicture) { DrvPixmapPtr pDrawable = pPicture->pPixmap; BoxRec pixbounds; if (!pDrawable) return; /* XXX should we translate by drawable.x/y here ? */ /* If you want pixmaps in offscreen memory, yes */ pixbounds.x1 = 0; pixbounds.y1 = 0; pixbounds.x2 = pDrawable->width; pixbounds.y2 = pDrawable->height; if (pPicture->freeCompClip) { RegionReset(pPicture->pCompositeClip, &pixbounds); } else { pPicture->freeCompClip = TRUE; pPicture->pCompositeClip = RegionCreate(&pixbounds, 1); } } void DrvCompositePicture (CARD8 op, DrvPicturePtr pSrc, DrvPicturePtr pMask, DrvPicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { DrvPictureScreenPtr ps = DrvGetPictureScreen(pDst->pPixmap->pDrvScreen); DrvValidatePicture (pSrc); if (pMask) DrvValidatePicture (pMask); DrvValidatePicture (pDst); (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); } #define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) static void GlyphExtents (int nlist, GlyphListPtr list, GlyphPtr *glyphs, BoxPtr extents) { int x1, x2, y1, y2; int n; GlyphPtr glyph; int x, y; x = 0; y = 0; extents->x1 = MAXSHORT; extents->x2 = MINSHORT; extents->y1 = MAXSHORT; extents->y2 = MINSHORT; while (nlist--) { x += list->xOff; y += list->yOff; n = list->len; list++; while (n--) { glyph = *glyphs++; x1 = x - glyph->info.x; if (x1 < MINSHORT) x1 = MINSHORT; y1 = y - glyph->info.y; if (y1 < MINSHORT) y1 = MINSHORT; x2 = x1 + glyph->info.width; if (x2 > MAXSHORT) x2 = MAXSHORT; y2 = y1 + glyph->info.height; if (y2 > MAXSHORT) y2 = MAXSHORT; if (x1 < extents->x1) extents->x1 = x1; if (x2 > extents->x2) extents->x2 = x2; if (y1 < extents->y1) extents->y1 = y1; if (y2 > extents->y2) extents->y2 = y2; x += glyph->info.xOff; y += glyph->info.yOff; } } } void DrvGlyphs (CARD8 op, DrvPicturePtr pSrc, DrvPicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs, int gp_index) { DrvPicturePtr pPicture; DrvPixmapPtr pMaskPixmap = 0; DrvPicturePtr pMask; DrvScreenPtr pScreen = pDst->pPixmap->pDrvScreen; int width = 0, height = 0; int x, y; int xDst = list->xOff, yDst = list->yOff; int n; GlyphPtr glyph; int error; BoxRec extents = {0, 0, 0, 0}; CARD32 component_alpha; if (maskFormat) { DrvGCPtr pGC; xRectangle rect; GlyphExtents (nlist, list, glyphs, &extents); if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) return; width = extents.x2 - extents.x1; height = extents.y2 - extents.y1; pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, maskFormat->depth, CREATE_PIXMAP_USAGE_SCRATCH, NULL); if (!pMaskPixmap) return; component_alpha = NeedsComponent(maskFormat->format); pMask = DrvCreatePicture (pMaskPixmap, maskFormat, CPComponentAlpha, &component_alpha); if (!pMask) { (*pScreen->DestroyPixmap) (pMaskPixmap); return; } pGC = DrvGetScratchGC (pMaskPixmap->depth, pScreen); DrvValidateGC (pMaskPixmap, pGC); rect.x = 0; rect.y = 0; rect.width = width; rect.height = height; (*pGC->ops->PolyFillRect) (pMaskPixmap, pGC, 1, &rect); DrvFreeScratchGC (pGC); x = -extents.x1; y = -extents.y1; } else { pMask = pDst; x = 0; y = 0; } while (nlist--) { x += list->xOff; y += list->yOff; n = list->len; while (n--) { glyph = *glyphs++; //TODO pPicture = (GlyphPicture (glyph)[pScreen->myNum])->gpu[gp_index]; if (pPicture) { if (maskFormat) { DrvCompositePicture (PictOpAdd, pPicture, None, pMask, 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y, glyph->info.width, glyph->info.height); } else { DrvCompositePicture (op, pSrc, pPicture, pDst, xSrc + (x - glyph->info.x) - xDst, ySrc + (y - glyph->info.y) - yDst, 0, 0, x - glyph->info.x, y - glyph->info.y, glyph->info.width, glyph->info.height); } } x += glyph->info.xOff; y += glyph->info.yOff; } list++; } if (maskFormat) { x = extents.x1; y = extents.y1; DrvCompositePicture (op, pSrc, pMask, pDst, xSrc + x - xDst, ySrc + y - yDst, 0, 0, x, y, width, height); DrvFreePicture ((pointer) pMask); (*pScreen->DestroyPixmap) (pMaskPixmap); } } #define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) static inline pixman_bool_t drvClipPictureReg (pixman_region16_t * pRegion, pixman_region16_t * pClip, int dx, int dy) { if (pixman_region_n_rects(pRegion) == 1 && pixman_region_n_rects(pClip) == 1) { pixman_box16_t * pRbox = pixman_region_rectangles(pRegion, NULL); pixman_box16_t * pCbox = pixman_region_rectangles(pClip, NULL); 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) { pixman_region_init (pRegion); } } else if (!pixman_region_not_empty (pClip)) return FALSE; else { if (dx || dy) pixman_region_translate (pRegion, -dx, -dy); if (!pixman_region_intersect (pRegion, pRegion, pClip)) return FALSE; if (dx || dy) pixman_region_translate(pRegion, dx, dy); } return pixman_region_not_empty(pRegion); } static __inline Bool drvClipPictureSrc (RegionPtr pRegion, DrvPicturePtr pPicture, int dx, int dy) { #if 0 if (pPicture->clientClipType != CT_NONE) { Bool result; pixman_region_translate ( pPicture->clientClip, pPicture->clipOrigin.x + dx, pPicture->clipOrigin.y + dy); result = RegionIntersect(pRegion, pRegion, pPicture->clientClip); pixman_region_translate ( pPicture->clientClip, - (pPicture->clipOrigin.x + dx), - (pPicture->clipOrigin.y + dy)); if (!result) return FALSE; } #endif return TRUE; } /* * returns FALSE if the final region is empty. Indistinguishable from * an allocation failure, but rendering ignores those anyways. */ Bool drvComputeCompositeRegion (RegionPtr pRegion, DrvPicturePtr pSrc, DrvPicturePtr pMask, DrvPicturePtr 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) { pixman_region_init (pRegion); return FALSE; } /* clip against dst */ if (!drvClipPictureReg (pRegion, pDst->pCompositeClip, 0, 0)) { pixman_region_fini (pRegion); ErrorF("failed in clip against dst\n"); return FALSE; } if (pDst->alphaMap) { if (!drvClipPictureReg (pRegion, pDst->alphaMap->pCompositeClip, -pDst->alphaOrigin.x, -pDst->alphaOrigin.y)) { pixman_region_fini (pRegion); ErrorF("failed in clip against alpha map\n"); return FALSE; } } /* clip against src */ if (!drvClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc)) { pixman_region_fini (pRegion); ErrorF("failed in clip against src \n"); return FALSE; } if (pSrc->alphaMap) { if (!drvClipPictureSrc (pRegion, pSrc->alphaMap, xDst - (xSrc - pSrc->alphaOrigin.x), yDst - (ySrc - pSrc->alphaOrigin.y))) { pixman_region_fini (pRegion); ErrorF("failed in clip against src am \n"); return FALSE; } } /* clip against mask */ if (pMask) { if (!drvClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask)) { ErrorF("failed in clip against mask \n"); pixman_region_fini (pRegion); return FALSE; } if (pMask->alphaMap) { if (!drvClipPictureSrc (pRegion, pMask->alphaMap, xDst - (xMask - pMask->alphaOrigin.x), yDst - (yMask - pMask->alphaOrigin.y))) { ErrorF("failed in clip against mask am\n"); pixman_region_fini (pRegion); return FALSE; } } } return TRUE; } Bool drvPictureInit(DrvScreenPtr pScreen) { DrvPictureScreenPtr dps; if (!dixRegisterPrivateKey(&DrvPictureScreenPrivateKeyRec, PRIVATE_DRV_SCREEN, 0)) return FALSE; dps = (DrvPictureScreenPtr) malloc(sizeof (DrvPictureScreenRec)); if (!dps) { return FALSE; } DrvSetPictureScreen(pScreen, dps); return TRUE; }