/* * * Copyright © 2003 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 #endif #include #include #include "scrnintstr.h" #include "windowstr.h" #include #include "dixfontstr.h" #include #include "mi.h" #include "regionstr.h" #include "globals.h" #include "gcstruct.h" #include "damage.h" #include "damagestr.h" #define wrap(priv, real, mem, func) {\ priv->mem = real->mem; \ real->mem = func; \ } #define unwrap(priv, real, mem) {\ real->mem = priv->mem; \ } #define BOX_SAME(a,b) \ ((a)->x1 == (b)->x1 && \ (a)->y1 == (b)->y1 && \ (a)->x2 == (b)->x2 && \ (a)->y2 == (b)->y2) #define DAMAGE_VALIDATE_ENABLE 0 #define DAMAGE_DEBUG_ENABLE 0 #if DAMAGE_DEBUG_ENABLE #define DAMAGE_DEBUG(x) ErrorF x #else #define DAMAGE_DEBUG(x) #endif #define getPixmapDamageRef(pPixmap) \ ((DamagePtr *) &(pPixmap->devPrivates[damagePixPrivateIndex].ptr)) #define pixmapDamage(pPixmap) damagePixPriv(pPixmap) static DamagePtr * getDrawableDamageRef(DrawablePtr pDrawable) { PixmapPtr pPixmap; if (pDrawable->type == DRAWABLE_WINDOW) { ScreenPtr pScreen = pDrawable->pScreen; pPixmap = 0; if (pScreen->GetWindowPixmap #ifdef ROOTLESS_WORKAROUND && ((WindowPtr) pDrawable)->viewable #endif ) pPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) pDrawable); if (!pPixmap) { damageScrPriv(pScreen); return &pScrPriv->pScreenDamage; } } else pPixmap = (PixmapPtr) pDrawable; return getPixmapDamageRef(pPixmap); } #define getDrawableDamage(pDrawable) (*getDrawableDamageRef (pDrawable)) #define getWindowDamage(pWin) getDrawableDamage(&(pWin)->drawable) #define drawableDamage(pDrawable) \ DamagePtr pDamage = getDrawableDamage(pDrawable) #define windowDamage(pWin) drawableDamage(&(pWin)->drawable) #define winDamageRef(pWindow) \ DamagePtr *pPrev = (DamagePtr *) \ &(pWindow->devPrivates[damageWinPrivateIndex].ptr) static void DamageReportDamage(DamagePtr pDamage, RegionPtr pDamageRegion) { BoxRec tmpBox; RegionRec tmpRegion; Bool was_empty; switch (pDamage->damageLevel) { case DamageReportRawRegion: (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure); break; case DamageReportDeltaRegion: REGION_NULL(&tmpRegion); REGION_SUBTRACT(&tmpRegion, pDamageRegion, &pDamage->damage); if (REGION_NOTEMPTY(&tmpRegion)) { REGION_UNION(&pDamage->damage, &pDamage->damage, pDamageRegion); (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure); } REGION_UNINIT(&tmpRegion); break; case DamageReportBoundingBox: tmpBox = *REGION_EXTENTS(&pDamage->damage); REGION_UNION(&pDamage->damage, &pDamage->damage, pDamageRegion); if (!BOX_SAME(&tmpBox, REGION_EXTENTS(&pDamage->damage))) { (*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure); } break; case DamageReportNonEmpty: was_empty = !REGION_NOTEMPTY(&pDamage->damage); REGION_UNION(&pDamage->damage, &pDamage->damage, pDamageRegion); if (was_empty && REGION_NOTEMPTY(&pDamage->damage)) { (*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure); } break; case DamageReportNone: REGION_UNION(&pDamage->damage, &pDamage->damage, pDamageRegion); break; } } #if DAMAGE_DEBUG_ENABLE static void _damageDamageRegion(DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode, const char *where) #define damageDamageRegion(d,r,c,m) _damageDamageRegion(d,r,c,m,__FUNCTION__) #else static void damageDamageRegion(DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode) #endif { ScreenPtr pScreen = pDrawable->pScreen; damageScrPriv(pScreen); drawableDamage(pDrawable); DamagePtr pNext; RegionRec clippedRec; RegionPtr pDamageRegion; RegionRec pixClip; int draw_x, draw_y; /* short circuit for empty regions */ if (!REGION_NOTEMPTY(pRegion)) return; if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) (pDrawable))->backingStore == NotUseful) { if (subWindowMode == ClipByChildren) { REGION_INTERSECT(pRegion, pRegion, &((WindowPtr) (pDrawable))->clipList); } else if (subWindowMode == IncludeInferiors) { RegionPtr pTempRegion = NotClippedByChildren((WindowPtr) (pDrawable)); REGION_INTERSECT(pRegion, pRegion, pTempRegion); REGION_DESTROY(pTempRegion); } /* If subWindowMode is set to an invalid value, don't perform * any drawable-based clipping. */ } REGION_NULL(&clippedRec); for (; pDamage; pDamage = pNext) { pNext = pDamage->pNext; /* * Check for internal damage and don't send events */ if (pScrPriv->internalLevel > 0 && !pDamage->isInternal) { DAMAGE_DEBUG(("non internal damage, skipping at %d\n", pScrPriv->internalLevel)); continue; } /* * Check for unrealized windows */ if (pDamage->pDrawable->type == DRAWABLE_WINDOW && !((WindowPtr) (pDamage->pDrawable))->realized) { #if 0 DAMAGE_DEBUG(("damage while window unrealized\n")); #endif continue; } draw_x = pDamage->pDrawable->x; draw_y = pDamage->pDrawable->y; /* * Clip against border or pixmap bounds */ pDamageRegion = pRegion; if (clip || pDamage->pDrawable != pDrawable) { pDamageRegion = &clippedRec; if (pDamage->pDrawable->type == DRAWABLE_WINDOW) { REGION_INTERSECT(pDamageRegion, pRegion, &((WindowPtr) (pDamage->pDrawable))-> borderClip); } else { BoxRec box; box.x1 = draw_x; box.y1 = draw_y; box.x2 = draw_x + pDamage->pDrawable->width; box.y2 = draw_y + pDamage->pDrawable->height; REGION_INIT(&pixClip, &box, 1); REGION_INTERSECT(pDamageRegion, pRegion, &pixClip); REGION_UNINIT(&pixClip); } /* * Short circuit empty results */ if (!REGION_NOTEMPTY(pDamageRegion)) continue; } DAMAGE_DEBUG(("%s %d x %d +%d +%d (target 0x%lx monitor 0x%lx)\n", where, pDamageRegion->extents.x2 - pDamageRegion->extents.x1, pDamageRegion->extents.y2 - pDamageRegion->extents.y1, pDamageRegion->extents.x1, pDamageRegion->extents.y1, pDrawable->id, pDamage->pDrawable->id)); /* * Move region to target coordinate space */ if (draw_x || draw_y) REGION_TRANSLATE(pDamageRegion, -draw_x, -draw_y); /* If the damage rec has been flagged to report damage after the op has * completed, then union it into the delayed damage region, which will * be used for reporting after calling down, and skip the reporting */ if (!pDamage->reportAfter) { DamageReportDamage(pDamage, pDamageRegion); } else { REGION_UNION(&pDamage->pendingDamage, &pDamage->pendingDamage, pDamageRegion); } /* * translate original region back */ if (pDamageRegion == pRegion && (draw_x || draw_y)) REGION_TRANSLATE(pDamageRegion, draw_x, draw_y); } REGION_UNINIT(&clippedRec); } static void damageReportPostOp(DrawablePtr pDrawable) { drawableDamage(pDrawable); for (; pDamage != NULL; pDamage = pDamage->pNext) { if (pDamage->reportAfter) { DamageReportDamage(pDamage, &pDamage->pendingDamage); REGION_EMPTY(&pDamage->pendingDamage); } } } #if DAMAGE_DEBUG_ENABLE #define damageDamageBox(d,b,m) _damageDamageBox(d,b,m,__FUNCTION__) static void _damageDamageBox(DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode, const char *where) #else static void damageDamageBox(DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode) #endif { RegionRec region; REGION_INIT(®ion, pBox, 1); #if DAMAGE_DEBUG_ENABLE _damageDamageRegion(pDrawable, ®ion, TRUE, subWindowMode, where); #else damageDamageRegion(pDrawable, ®ion, TRUE, subWindowMode); #endif REGION_UNINIT(®ion); } static void damageValidateGC(GCPtr, unsigned long, DrawablePtr); static void damageChangeGC(GCPtr, unsigned long); static void damageCopyGC(GCPtr, unsigned long, GCPtr); static void damageDestroyGC(GCPtr); static void damageChangeClip(GCPtr, int, pointer, int); static void damageDestroyClip(GCPtr); static void damageCopyClip(GCPtr, GCPtr); static const GCFuncs damageGCFuncs = { damageValidateGC, damageChangeGC, damageCopyGC, damageDestroyGC, damageChangeClip, damageDestroyClip, damageCopyClip }; static GCOps damageGCOps; static Bool damageCreateGC(GCPtr pGC) { ScreenPtr pScreen = pGC->pScreen; damageScrPriv(pScreen); damageGCPriv(pGC); Bool ret; pGC->pCompositeClip = 0; unwrap(pScrPriv, pScreen, CreateGC); if ((ret = (*pScreen->CreateGC) (pGC))) { pGCPriv->ops = NULL; pGCPriv->funcs = pGC->funcs; pGC->funcs = &damageGCFuncs; } wrap(pScrPriv, pScreen, CreateGC, damageCreateGC); return ret; } #ifdef NOTUSED static void damageWrapGC(GCPtr pGC) { damageGCPriv(pGC); pGCPriv->ops = NULL; pGCPriv->funcs = pGC->funcs; pGC->funcs = &damageGCFuncs; } static void damageUnwrapGC(GCPtr pGC) { damageGCPriv(pGC); pGC->funcs = pGCPriv->funcs; if (pGCPriv->ops) pGC->ops = pGCPriv->ops; } #endif #define DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable) \ damageGCPriv(pGC); \ const GCFuncs *oldFuncs = pGC->funcs; \ unwrap(pGCPriv, pGC, funcs); \ unwrap(pGCPriv, pGC, ops); \ #define DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable) \ wrap(pGCPriv, pGC, funcs, oldFuncs); \ wrap(pGCPriv, pGC, ops, &damageGCOps) #define DAMAGE_GC_FUNC_PROLOGUE(pGC) \ damageGCPriv(pGC); \ unwrap(pGCPriv, pGC, funcs); \ if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops) #define DAMAGE_GC_FUNC_EPILOGUE(pGC) \ wrap(pGCPriv, pGC, funcs, &damageGCFuncs); \ if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &damageGCOps) static void damageValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { DAMAGE_GC_FUNC_PROLOGUE(pGC); (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); pGCPriv->ops = pGC->ops; /* just so it's not NULL */ DAMAGE_GC_FUNC_EPILOGUE(pGC); } static void damageDestroyGC(GCPtr pGC) { DAMAGE_GC_FUNC_PROLOGUE(pGC); (*pGC->funcs->DestroyGC) (pGC); DAMAGE_GC_FUNC_EPILOGUE(pGC); } static void damageChangeGC(GCPtr pGC, unsigned long mask) { DAMAGE_GC_FUNC_PROLOGUE(pGC); (*pGC->funcs->ChangeGC) (pGC, mask); DAMAGE_GC_FUNC_EPILOGUE(pGC); } static void damageCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) { DAMAGE_GC_FUNC_PROLOGUE(pGCDst); (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); DAMAGE_GC_FUNC_EPILOGUE(pGCDst); } static void damageChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) { DAMAGE_GC_FUNC_PROLOGUE(pGC); (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); DAMAGE_GC_FUNC_EPILOGUE(pGC); } static void damageCopyClip(GCPtr pgcDst, GCPtr pgcSrc) { DAMAGE_GC_FUNC_PROLOGUE(pgcDst); (*pgcDst->funcs->CopyClip) (pgcDst, pgcSrc); DAMAGE_GC_FUNC_EPILOGUE(pgcDst); } static void damageDestroyClip(GCPtr pGC) { DAMAGE_GC_FUNC_PROLOGUE(pGC); (*pGC->funcs->DestroyClip) (pGC); DAMAGE_GC_FUNC_EPILOGUE(pGC); } #define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) { \ BoxPtr extents = &pGC->pCompositeClip->extents;\ if(box.x1 < extents->x1) box.x1 = extents->x1; \ if(box.x2 > extents->x2) box.x2 = extents->x2; \ if(box.y1 < extents->y1) box.y1 = extents->y1; \ if(box.y2 > extents->y2) box.y2 = extents->y2; \ } #define TRANSLATE_BOX(box, pDrawable) { \ box.x1 += pDrawable->x; \ box.x2 += pDrawable->x; \ box.y1 += pDrawable->y; \ box.y2 += pDrawable->y; \ } #define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) { \ TRANSLATE_BOX(box, pDrawable); \ TRIM_BOX(box, pGC); \ } #define BOX_NOT_EMPTY(box) \ (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) #define checkGCDamage(d,g) (getDrawableDamage(d) && \ (!g->pCompositeClip ||\ REGION_NOTEMPTY(\ g->pCompositeClip))) #define TRIM_PICTURE_BOX(box, pDst) { \ BoxPtr extents = &pDst->pCompositeClip->extents;\ if(box.x1 < extents->x1) box.x1 = extents->x1; \ if(box.x2 > extents->x2) box.x2 = extents->x2; \ if(box.y1 < extents->y1) box.y1 = extents->y1; \ if(box.y2 > extents->y2) box.y2 = extents->y2; \ } #define checkPictureDamage(p) (getDrawableDamage(p->pDrawable) && \ REGION_NOTEMPTY(p->pCompositeClip)) static void damageComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); damageScrPriv(pScreen); if (checkPictureDamage(pDst)) { BoxRec box; box.x1 = xDst + pDst->pDrawable->x; box.y1 = yDst + pDst->pDrawable->y; box.x2 = box.x1 + width; box.y2 = box.y1 + height; TRIM_PICTURE_BOX(box, pDst); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDst->pDrawable, &box, pDst->subWindowMode); } unwrap(pScrPriv, ps, Composite); (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); damageReportPostOp(pDst->pDrawable); wrap(pScrPriv, ps, Composite, damageComposite); } static void damageGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) { ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); damageScrPriv(pScreen); if (checkPictureDamage(pDst)) { int nlistTmp = nlist; GlyphListPtr listTmp = list; GlyphPtr *glyphsTmp = glyphs; int x, y; int n; GlyphPtr glyph; BoxRec box; int x1, y1, x2, y2; box.x1 = 32767; box.y1 = 32767; box.x2 = -32767; box.y2 = -32767; x = pDst->pDrawable->x; y = pDst->pDrawable->y; while (nlistTmp--) { x += listTmp->xOff; y += listTmp->yOff; n = listTmp->len; while (n--) { glyph = *glyphsTmp++; x1 = x - glyph->info.x; y1 = y - glyph->info.y; x2 = x1 + glyph->info.width; y2 = y1 + glyph->info.height; if (x1 < box.x1) box.x1 = x1; if (y1 < box.y1) box.y1 = y1; if (x2 > box.x2) box.x2 = x2; if (y2 > box.y2) box.y2 = y2; x += glyph->info.xOff; y += glyph->info.yOff; } listTmp++; } TRIM_PICTURE_BOX(box, pDst); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDst->pDrawable, &box, pDst->subWindowMode); } unwrap(pScrPriv, ps, Glyphs); (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); damageReportPostOp(pDst->pDrawable); wrap(pScrPriv, ps, Glyphs, damageGlyphs); } /**********************************************************/ static void damageFillSpans(DrawablePtr pDrawable, GC * pGC, int npt, DDXPointPtr ppt, int *pwidth, int fSorted) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (npt && checkGCDamage(pDrawable, pGC)) { int nptTmp = npt; DDXPointPtr pptTmp = ppt; int *pwidthTmp = pwidth; BoxRec box; box.x1 = pptTmp->x; box.x2 = box.x1 + *pwidthTmp; box.y2 = box.y1 = pptTmp->y; while (--nptTmp) { pptTmp++; pwidthTmp++; if (box.x1 > pptTmp->x) box.x1 = pptTmp->x; if (box.x2 < (pptTmp->x + *pwidthTmp)) box.x2 = pptTmp->x + *pwidthTmp; if (box.y1 > pptTmp->y) box.y1 = pptTmp->y; else if (box.y2 < pptTmp->y) box.y2 = pptTmp->y; } box.y2++; if (!pGC->miTranslate) { TRANSLATE_BOX(box, pDrawable); } TRIM_BOX(box, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->FillSpans) (pDrawable, pGC, npt, ppt, pwidth, fSorted); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damageSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *pcharsrc, DDXPointPtr ppt, int *pwidth, int npt, int fSorted) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (npt && checkGCDamage(pDrawable, pGC)) { DDXPointPtr pptTmp = ppt; int *pwidthTmp = pwidth; int nptTmp = npt; BoxRec box; box.x1 = pptTmp->x; box.x2 = box.x1 + *pwidthTmp; box.y2 = box.y1 = pptTmp->y; while (--nptTmp) { pptTmp++; pwidthTmp++; if (box.x1 > pptTmp->x) box.x1 = pptTmp->x; if (box.x2 < (pptTmp->x + *pwidthTmp)) box.x2 = pptTmp->x + *pwidthTmp; if (box.y1 > pptTmp->y) box.y1 = pptTmp->y; else if (box.y2 < pptTmp->y) box.y2 = pptTmp->y; } box.y2++; if (!pGC->miTranslate) { TRANSLATE_BOX(box, pDrawable); } TRIM_BOX(box, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->SetSpans) (pDrawable, pGC, pcharsrc, ppt, pwidth, npt, fSorted); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *pImage) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage(pDrawable, pGC)) { BoxRec box; box.x1 = x + pDrawable->x; box.x2 = box.x1 + w; box.y1 = y + pDrawable->y; box.y2 = box.y1 + h; TRIM_BOX(box, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, pImage); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static RegionPtr damageCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GC * pGC, int srcx, int srcy, int width, int height, int dstx, int dsty) { RegionPtr ret; DAMAGE_GC_OP_PROLOGUE(pGC, pDst); /* The driver will only call SourceValidate() when pSrc != pDst, * but the software sprite (misprite.c) always need to know when a * drawable is copied so it can remove the sprite. See #1030. */ if ((pSrc == pDst) && pSrc->pScreen->SourceValidate && pSrc->type == DRAWABLE_WINDOW && ((WindowPtr) pSrc)->viewable) { (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height); } if (checkGCDamage(pDst, pGC)) { BoxRec box; box.x1 = dstx + pDst->x; box.x2 = box.x1 + width; box.y1 = dsty + pDst->y; box.y2 = box.y1 + height; TRIM_BOX(box, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDst, &box, pGC->subWindowMode); } ret = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, width, height, dstx, dsty); damageReportPostOp(pDst); DAMAGE_GC_OP_EPILOGUE(pGC, pDst); return ret; } static RegionPtr damageCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int width, int height, int dstx, int dsty, unsigned long bitPlane) { RegionPtr ret; DAMAGE_GC_OP_PROLOGUE(pGC, pDst); /* The driver will only call SourceValidate() when pSrc != pDst, * but the software sprite (misprite.c) always need to know when a * drawable is copied so it can remove the sprite. See #1030. */ if ((pSrc == pDst) && pSrc->pScreen->SourceValidate && pSrc->type == DRAWABLE_WINDOW && ((WindowPtr) pSrc)->viewable) { (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height); } if (checkGCDamage(pDst, pGC)) { BoxRec box; box.x1 = dstx + pDst->x; box.x2 = box.x1 + width; box.y1 = dsty + pDst->y; box.y2 = box.y1 + height; TRIM_BOX(box, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDst, &box, pGC->subWindowMode); } ret = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); damageReportPostOp(pDst); DAMAGE_GC_OP_EPILOGUE(pGC, pDst); return ret; } static void damagePolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, xPoint * ppt) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (npt && checkGCDamage(pDrawable, pGC)) { BoxRec box; int nptTmp = npt; xPoint *pptTmp = ppt; box.x2 = box.x1 = pptTmp->x; box.y2 = box.y1 = pptTmp->y; /* this could be slow if the points were spread out */ while (--nptTmp) { pptTmp++; if (box.x1 > pptTmp->x) box.x1 = pptTmp->x; else if (box.x2 < pptTmp->x) box.x2 = pptTmp->x; if (box.y1 > pptTmp->y) box.y1 = pptTmp->y; else if (box.y2 < pptTmp->y) box.y2 = pptTmp->y; } box.x2++; box.y2++; TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, ppt); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (npt && checkGCDamage(pDrawable, pGC)) { int nptTmp = npt; DDXPointPtr pptTmp = ppt; BoxRec box; int extra = pGC->lineWidth >> 1; box.x2 = box.x1 = pptTmp->x; box.y2 = box.y1 = pptTmp->y; if (nptTmp > 1) { if (pGC->joinStyle == JoinMiter) extra = 6 * pGC->lineWidth; else if (pGC->capStyle == CapProjecting) extra = pGC->lineWidth; } if (mode == CoordModePrevious) { int x = box.x1; int y = box.y1; while (--nptTmp) { pptTmp++; x += pptTmp->x; y += pptTmp->y; if (box.x1 > x) box.x1 = x; else if (box.x2 < x) box.x2 = x; if (box.y1 > y) box.y1 = y; else if (box.y2 < y) box.y2 = y; } } else { while (--nptTmp) { pptTmp++; if (box.x1 > pptTmp->x) box.x1 = pptTmp->x; else if (box.x2 < pptTmp->x) box.x2 = pptTmp->x; if (box.y1 > pptTmp->y) box.y1 = pptTmp->y; else if (box.y2 < pptTmp->y) box.y2 = pptTmp->y; } } box.x2++; box.y2++; if (extra) { box.x1 -= extra; box.x2 += extra; box.y1 -= extra; box.y2 += extra; } TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppt); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePolySegment(DrawablePtr pDrawable, GCPtr pGC, int nSeg, xSegment * pSeg) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (nSeg && checkGCDamage(pDrawable, pGC)) { BoxRec box; int extra = pGC->lineWidth; int nsegTmp = nSeg; xSegment *pSegTmp = pSeg; if (pGC->capStyle != CapProjecting) extra >>= 1; if (pSegTmp->x2 > pSegTmp->x1) { box.x1 = pSegTmp->x1; box.x2 = pSegTmp->x2; } else { box.x2 = pSegTmp->x1; box.x1 = pSegTmp->x2; } if (pSegTmp->y2 > pSegTmp->y1) { box.y1 = pSegTmp->y1; box.y2 = pSegTmp->y2; } else { box.y2 = pSegTmp->y1; box.y1 = pSegTmp->y2; } while (--nsegTmp) { pSegTmp++; if (pSegTmp->x2 > pSegTmp->x1) { if (pSegTmp->x1 < box.x1) box.x1 = pSegTmp->x1; if (pSegTmp->x2 > box.x2) box.x2 = pSegTmp->x2; } else { if (pSegTmp->x2 < box.x1) box.x1 = pSegTmp->x2; if (pSegTmp->x1 > box.x2) box.x2 = pSegTmp->x1; } if (pSegTmp->y2 > pSegTmp->y1) { if (pSegTmp->y1 < box.y1) box.y1 = pSegTmp->y1; if (pSegTmp->y2 > box.y2) box.y2 = pSegTmp->y2; } else { if (pSegTmp->y2 < box.y1) box.y1 = pSegTmp->y2; if (pSegTmp->y1 > box.y2) box.y2 = pSegTmp->y1; } } box.x2++; box.y2++; if (extra) { box.x1 -= extra; box.x2 += extra; box.y1 -= extra; box.y2 += extra; } TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->PolySegment) (pDrawable, pGC, nSeg, pSeg); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nRects, xRectangle *pRects) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (nRects && checkGCDamage(pDrawable, pGC)) { BoxRec box; int offset1, offset2, offset3; int nRectsTmp = nRects; xRectangle *pRectsTmp = pRects; offset2 = pGC->lineWidth; if (!offset2) offset2 = 1; offset1 = offset2 >> 1; offset3 = offset2 - offset1; while (nRectsTmp--) { box.x1 = pRectsTmp->x - offset1; box.y1 = pRectsTmp->y - offset1; box.x2 = box.x1 + pRectsTmp->width + offset2; box.y2 = box.y1 + offset2; TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); box.x1 = pRectsTmp->x - offset1; box.y1 = pRectsTmp->y + offset3; box.x2 = box.x1 + offset2; box.y2 = box.y1 + pRectsTmp->height - offset2; TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); box.x1 = pRectsTmp->x + pRectsTmp->width - offset1; box.y1 = pRectsTmp->y + offset3; box.x2 = box.x1 + offset2; box.y2 = box.y1 + pRectsTmp->height - offset2; TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); box.x1 = pRectsTmp->x - offset1; box.y1 = pRectsTmp->y + pRectsTmp->height - offset1; box.x2 = box.x1 + pRectsTmp->width + offset2; box.y2 = box.y1 + offset2; TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); pRectsTmp++; } } (*pGC->ops->PolyRectangle) (pDrawable, pGC, nRects, pRects); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePolyArc(DrawablePtr pDrawable, GCPtr pGC, int nArcs, xArc * pArcs) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (nArcs && checkGCDamage(pDrawable, pGC)) { int extra = pGC->lineWidth >> 1; BoxRec box; int nArcsTmp = nArcs; xArc *pArcsTmp = pArcs; box.x1 = pArcsTmp->x; box.x2 = box.x1 + pArcsTmp->width; box.y1 = pArcsTmp->y; box.y2 = box.y1 + pArcsTmp->height; while (--nArcsTmp) { pArcsTmp++; if (box.x1 > pArcsTmp->x) box.x1 = pArcsTmp->x; if (box.x2 < (pArcsTmp->x + pArcsTmp->width)) box.x2 = pArcsTmp->x + pArcsTmp->width; if (box.y1 > pArcsTmp->y) box.y1 = pArcsTmp->y; if (box.y2 < (pArcsTmp->y + pArcsTmp->height)) box.y2 = pArcsTmp->y + pArcsTmp->height; } if (extra) { box.x1 -= extra; box.x2 += extra; box.y1 -= extra; box.y2 += extra; } box.x2++; box.y2++; TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->PolyArc) (pDrawable, pGC, nArcs, pArcs); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damageFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, int mode, int npt, DDXPointPtr ppt) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (npt > 2 && checkGCDamage(pDrawable, pGC)) { DDXPointPtr pptTmp = ppt; int nptTmp = npt; BoxRec box; box.x2 = box.x1 = pptTmp->x; box.y2 = box.y1 = pptTmp->y; if (mode != CoordModeOrigin) { int x = box.x1; int y = box.y1; while (--nptTmp) { pptTmp++; x += pptTmp->x; y += pptTmp->y; if (box.x1 > x) box.x1 = x; else if (box.x2 < x) box.x2 = x; if (box.y1 > y) box.y1 = y; else if (box.y2 < y) box.y2 = y; } } else { while (--nptTmp) { pptTmp++; if (box.x1 > pptTmp->x) box.x1 = pptTmp->x; else if (box.x2 < pptTmp->x) box.x2 = pptTmp->x; if (box.y1 > pptTmp->y) box.y1 = pptTmp->y; else if (box.y2 < pptTmp->y) box.y2 = pptTmp->y; } } box.x2++; box.y2++; TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, npt, ppt); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nRects, xRectangle *pRects) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (nRects && checkGCDamage(pDrawable, pGC)) { BoxRec box; xRectangle *pRectsTmp = pRects; int nRectsTmp = nRects; box.x1 = pRectsTmp->x; box.x2 = box.x1 + pRectsTmp->width; box.y1 = pRectsTmp->y; box.y2 = box.y1 + pRectsTmp->height; while (--nRectsTmp) { pRectsTmp++; if (box.x1 > pRectsTmp->x) box.x1 = pRectsTmp->x; if (box.x2 < (pRectsTmp->x + pRectsTmp->width)) box.x2 = pRectsTmp->x + pRectsTmp->width; if (box.y1 > pRectsTmp->y) box.y1 = pRectsTmp->y; if (box.y2 < (pRectsTmp->y + pRectsTmp->height)) box.y2 = pRectsTmp->y + pRectsTmp->height; } TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->PolyFillRect) (pDrawable, pGC, nRects, pRects); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int nArcs, xArc * pArcs) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (nArcs && checkGCDamage(pDrawable, pGC)) { BoxRec box; int nArcsTmp = nArcs; xArc *pArcsTmp = pArcs; box.x1 = pArcsTmp->x; box.x2 = box.x1 + pArcsTmp->width; box.y1 = pArcsTmp->y; box.y2 = box.y1 + pArcsTmp->height; while (--nArcsTmp) { pArcsTmp++; if (box.x1 > pArcsTmp->x) box.x1 = pArcsTmp->x; if (box.x2 < (pArcsTmp->x + pArcsTmp->width)) box.x2 = pArcsTmp->x + pArcsTmp->width; if (box.y1 > pArcsTmp->y) box.y1 = pArcsTmp->y; if (box.y2 < (pArcsTmp->y + pArcsTmp->height)) box.y2 = pArcsTmp->y + pArcsTmp->height; } TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->PolyFillArc) (pDrawable, pGC, nArcs, pArcs); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } /* * general Poly/Image text function. Extract glyph information, * compute bounding box and remove cursor if it is overlapped. */ static void damageDamageChars(DrawablePtr pDrawable, FontPtr font, int x, int y, unsigned int n, CharInfoPtr * charinfo, Bool imageblt, int subWindowMode) { ExtentInfoRec extents; BoxRec box; QueryGlyphExtents(font, charinfo, n, &extents); if (imageblt) { if (extents.overallWidth > extents.overallRight) extents.overallRight = extents.overallWidth; if (extents.overallWidth < extents.overallLeft) extents.overallLeft = extents.overallWidth; if (extents.overallLeft > 0) extents.overallLeft = 0; if (extents.fontAscent > extents.overallAscent) extents.overallAscent = extents.fontAscent; if (extents.fontDescent > extents.overallDescent) extents.overallDescent = extents.fontDescent; } box.x1 = x + extents.overallLeft; box.y1 = y - extents.overallAscent; box.x2 = x + extents.overallRight; box.y2 = y + extents.overallDescent; damageDamageBox(pDrawable, &box, subWindowMode); } /* * values for textType: */ #define TT_POLY8 0 #define TT_IMAGE8 1 #define TT_POLY16 2 #define TT_IMAGE16 3 static int damageText(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned long count, char *chars, FontEncoding fontEncoding, Bool textType) { CharInfoPtr *charinfo; CharInfoPtr *info; unsigned long i; unsigned int n; int w; Bool imageblt; imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16); charinfo = (CharInfoPtr *) ALLOCATE_LOCAL(count * sizeof(CharInfoPtr)); if (!charinfo) return x; GetGlyphs(pGC->font, count, (unsigned char *) chars, fontEncoding, &i, charinfo); n = (unsigned int) i; w = 0; if (!imageblt) for (info = charinfo; i--; info++) w += (*info)->metrics.characterWidth; if (n != 0) { damageDamageChars(pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n, charinfo, imageblt, pGC->subWindowMode); if (imageblt) (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); else (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); } DEALLOCATE_LOCAL(charinfo); return x + w; } static int damagePolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage(pDrawable, pGC)) x = damageText(pDrawable, pGC, x, y, (unsigned long) count, chars, Linear8Bit, TT_POLY8); else x = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); return x; } static int damagePolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage(pDrawable, pGC)) x = damageText(pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, TT_POLY16); else x = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); return x; } static void damageImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage(pDrawable, pGC)) damageText(pDrawable, pGC, x, y, (unsigned long) count, chars, Linear8Bit, TT_IMAGE8); else (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damageImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage(pDrawable, pGC)) damageText(pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, TT_IMAGE16); else (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damageImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr * ppci, pointer pglyphBase) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); damageDamageChars(pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, nglyph, ppci, TRUE, pGC->subWindowMode); (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr * ppci, pointer pglyphBase) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); damageDamageChars(pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, nglyph, ppci, FALSE, pGC->subWindowMode); (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damagePushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, int dx, int dy, int xOrg, int yOrg) { DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage(pDrawable, pGC)) { BoxRec box; box.x1 = xOrg; box.y1 = yOrg; if (!pGC->miTranslate) { box.x1 += pDrawable->x; box.y1 += pDrawable->y; } box.x2 = box.x1 + dx; box.y2 = box.y1 + dy; TRIM_BOX(box, pGC); if (BOX_NOT_EMPTY(box)) damageDamageBox(pDrawable, &box, pGC->subWindowMode); } (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg); damageReportPostOp(pDrawable); DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); } static void damageRemoveDamage(DamagePtr * pPrev, DamagePtr pDamage) { while (*pPrev) { if (*pPrev == pDamage) { *pPrev = pDamage->pNext; return; } pPrev = &(*pPrev)->pNext; } #if DAMAGE_VALIDATE_ENABLE ErrorF("Damage not on list\n"); abort(); #endif } static void damageInsertDamage(DamagePtr * pPrev, DamagePtr pDamage) { #if DAMAGE_VALIDATE_ENABLE DamagePtr pOld; for (pOld = *pPrev; pOld; pOld = pOld->pNext) if (pOld == pDamage) { ErrorF("Damage already on list\n"); abort(); } #endif pDamage->pNext = *pPrev; *pPrev = pDamage; } static Bool damageDestroyPixmap(PixmapPtr pPixmap) { ScreenPtr pScreen = pPixmap->drawable.pScreen; damageScrPriv(pScreen); if (pPixmap->refcnt == 1) { DamagePtr *pPrev = getPixmapDamageRef(pPixmap); DamagePtr pDamage; while ((pDamage = *pPrev)) { damageRemoveDamage(pPrev, pDamage); if (!pDamage->isWindow) DamageDestroy(pDamage); } } unwrap(pScrPriv, pScreen, DestroyPixmap); (*pScreen->DestroyPixmap) (pPixmap); wrap(pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap); return TRUE; } static void damagePaintWindow(WindowPtr pWindow, RegionPtr prgn, int what) { ScreenPtr pScreen = pWindow->drawable.pScreen; damageScrPriv(pScreen); /* * Painting background none doesn't actually *do* anything, so * no damage is recorded */ if ((what != PW_BACKGROUND || pWindow->backgroundState != None) && getWindowDamage(pWindow)) damageDamageRegion(&pWindow->drawable, prgn, FALSE, -1); if (what == PW_BACKGROUND) { unwrap(pScrPriv, pScreen, PaintWindowBackground); (*pScreen->PaintWindowBackground) (pWindow, prgn, what); damageReportPostOp(&pWindow->drawable); wrap(pScrPriv, pScreen, PaintWindowBackground, damagePaintWindow); } else { unwrap(pScrPriv, pScreen, PaintWindowBorder); (*pScreen->PaintWindowBorder) (pWindow, prgn, what); damageReportPostOp(&pWindow->drawable); wrap(pScrPriv, pScreen, PaintWindowBorder, damagePaintWindow); } } static void damageCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) { ScreenPtr pScreen = pWindow->drawable.pScreen; damageScrPriv(pScreen); if (getWindowDamage(pWindow)) { int dx = pWindow->drawable.x - ptOldOrg.x; int dy = pWindow->drawable.y - ptOldOrg.y; /* * The region comes in source relative, but the damage occurs * at the destination location. Translate back and forth. */ REGION_TRANSLATE(prgnSrc, dx, dy); damageDamageRegion(&pWindow->drawable, prgnSrc, FALSE, -1); REGION_TRANSLATE(prgnSrc, -dx, -dy); } unwrap(pScrPriv, pScreen, CopyWindow); (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); damageReportPostOp(&pWindow->drawable); wrap(pScrPriv, pScreen, CopyWindow, damageCopyWindow); } static GCOps damageGCOps = { damageFillSpans, damageSetSpans, damagePutImage, damageCopyArea, damageCopyPlane, damagePolyPoint, damagePolylines, damagePolySegment, damagePolyRectangle, damagePolyArc, damageFillPolygon, damagePolyFillRect, damagePolyFillArc, damagePolyText8, damagePolyText16, damageImageText8, damageImageText16, damageImageGlyphBlt, damagePolyGlyphBlt, damagePushPixels, {NULL} /* devPrivate */ }; static void damageSetWindowPixmap(WindowPtr pWindow, PixmapPtr pPixmap) { DamagePtr pDamage; ScreenPtr pScreen = pWindow->drawable.pScreen; damageScrPriv(pScreen); if ((pDamage = damageGetWinPriv(pWindow))) { PixmapPtr pOldPixmap = (*pScreen->GetWindowPixmap) (pWindow); DamagePtr *pPrev = getPixmapDamageRef(pOldPixmap); while (pDamage) { damageRemoveDamage(pPrev, pDamage); pDamage = pDamage->pNextWin; } } unwrap(pScrPriv, pScreen, SetWindowPixmap); (*pScreen->SetWindowPixmap) (pWindow, pPixmap); wrap(pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap); if ((pDamage = damageGetWinPriv(pWindow))) { DamagePtr *pPrev = getPixmapDamageRef(pPixmap); while (pDamage) { damageInsertDamage(pPrev, pDamage); pDamage = pDamage->pNextWin; } } } static Bool damageDestroyWindow(WindowPtr pWindow) { DamagePtr pDamage; ScreenPtr pScreen = pWindow->drawable.pScreen; Bool ret; damageScrPriv(pScreen); while ((pDamage = damageGetWinPriv(pWindow))) { DamageUnregister(&pWindow->drawable, pDamage); DamageDestroy(pDamage); } unwrap(pScrPriv, pScreen, DestroyWindow); ret = (*pScreen->DestroyWindow) (pWindow); wrap(pScrPriv, pScreen, DestroyWindow, damageDestroyWindow); return ret; } static Bool damageCloseScreen(int i, ScreenPtr pScreen) { damageScrPriv(pScreen); unwrap(pScrPriv, pScreen, DestroyPixmap); unwrap(pScrPriv, pScreen, CreateGC); unwrap(pScrPriv, pScreen, PaintWindowBackground); unwrap(pScrPriv, pScreen, PaintWindowBorder); unwrap(pScrPriv, pScreen, CopyWindow); unwrap(pScrPriv, pScreen, CloseScreen); free(pScrPriv); return (*pScreen->CloseScreen) (i, pScreen); } int damageScrPrivateIndex; int damagePixPrivateIndex; int damageGCPrivateIndex; int damageWinPrivateIndex; int damageGeneration; Bool DamageSetup(ScreenPtr pScreen) { DamageScrPrivPtr pScrPriv; PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); if (damageGeneration != serverGeneration) { damageScrPrivateIndex = AllocateScreenPrivateIndex(); if (damageScrPrivateIndex == -1) return FALSE; damageGCPrivateIndex = AllocateGCPrivateIndex(); if (damageGCPrivateIndex == -1) return FALSE; damagePixPrivateIndex = AllocatePixmapPrivateIndex(); if (damagePixPrivateIndex == -1) return FALSE; damageWinPrivateIndex = AllocateWindowPrivateIndex(); if (damageWinPrivateIndex == -1) return FALSE; damageGeneration = serverGeneration; } if (pScreen->devPrivates[damageScrPrivateIndex].ptr) return TRUE; if (!AllocateGCPrivate (pScreen, damageGCPrivateIndex, sizeof(DamageGCPrivRec))) return FALSE; if (!AllocatePixmapPrivate(pScreen, damagePixPrivateIndex, 0)) return FALSE; if (!AllocateWindowPrivate(pScreen, damageWinPrivateIndex, 0)) return FALSE; pScrPriv = malloc(sizeof(DamageScrPrivRec)); if (!pScrPriv) return FALSE; pScrPriv->internalLevel = 0; pScrPriv->pScreenDamage = 0; wrap(pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap); wrap(pScrPriv, pScreen, CreateGC, damageCreateGC); wrap(pScrPriv, pScreen, PaintWindowBackground, damagePaintWindow); wrap(pScrPriv, pScreen, PaintWindowBorder, damagePaintWindow); wrap(pScrPriv, pScreen, DestroyWindow, damageDestroyWindow); wrap(pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap); wrap(pScrPriv, pScreen, CopyWindow, damageCopyWindow); wrap(pScrPriv, pScreen, CloseScreen, damageCloseScreen); if (ps) { wrap(pScrPriv, ps, Glyphs, damageGlyphs); wrap(pScrPriv, ps, Composite, damageComposite); } pScreen->devPrivates[damageScrPrivateIndex].ptr = (pointer) pScrPriv; return TRUE; } DamagePtr DamageCreate(DamageReportFunc damageReport, DamageDestroyFunc damageDestroy, DamageReportLevel damageLevel, Bool isInternal, ScreenPtr pScreen, void *closure) { DamagePtr pDamage; pDamage = malloc(sizeof(DamageRec)); if (!pDamage) return 0; pDamage->pNext = 0; pDamage->pNextWin = 0; REGION_NULL(&pDamage->damage); REGION_NULL(&pDamage->pendingDamage); pDamage->damageLevel = damageLevel; pDamage->isInternal = isInternal; pDamage->closure = closure; pDamage->isWindow = FALSE; pDamage->pDrawable = 0; pDamage->reportAfter = FALSE; pDamage->damageReport = damageReport; pDamage->damageDestroy = damageDestroy; return pDamage; } void DamageRegister(DrawablePtr pDrawable, DamagePtr pDamage) { if (pDrawable->type == DRAWABLE_WINDOW) { WindowPtr pWindow = (WindowPtr) pDrawable; winDamageRef(pWindow); #if DAMAGE_VALIDATE_ENABLE DamagePtr pOld; for (pOld = *pPrev; pOld; pOld = pOld->pNextWin) if (pOld == pDamage) { ErrorF("Damage already on window list\n"); abort(); } #endif pDamage->pNextWin = *pPrev; *pPrev = pDamage; pDamage->isWindow = TRUE; } else pDamage->isWindow = FALSE; pDamage->pDrawable = pDrawable; damageInsertDamage(getDrawableDamageRef(pDrawable), pDamage); } void DamageDrawInternal(ScreenPtr pScreen, Bool enable) { damageScrPriv(pScreen); pScrPriv->internalLevel += enable ? 1 : -1; } void DamageUnregister(DrawablePtr pDrawable, DamagePtr pDamage) { if (pDrawable->type == DRAWABLE_WINDOW) { WindowPtr pWindow = (WindowPtr) pDrawable; winDamageRef(pWindow); #if DAMAGE_VALIDATE_ENABLE int found = 0; #endif while (*pPrev) { if (*pPrev == pDamage) { *pPrev = pDamage->pNextWin; #if DAMAGE_VALIDATE_ENABLE found = 1; #endif break; } pPrev = &(*pPrev)->pNextWin; } #if DAMAGE_VALIDATE_ENABLE if (!found) { ErrorF("Damage not on window list\n"); abort(); } #endif } pDamage->pDrawable = 0; damageRemoveDamage(getDrawableDamageRef(pDrawable), pDamage); } void DamageDestroy(DamagePtr pDamage) { if (pDamage->damageDestroy) (*pDamage->damageDestroy) (pDamage, pDamage->closure); REGION_UNINIT(&pDamage->damage); REGION_UNINIT(&pDamage->pendingDamage); free(pDamage); } Bool DamageSubtract(DamagePtr pDamage, const RegionPtr pRegion) { RegionPtr pClip; RegionRec pixmapClip; DrawablePtr pDrawable = pDamage->pDrawable; REGION_SUBTRACT(&pDamage->damage, &pDamage->damage, pRegion); if (pDrawable) { if (pDrawable->type == DRAWABLE_WINDOW) pClip = &((WindowPtr) pDrawable)->borderClip; else { BoxRec box; box.x1 = pDrawable->x; box.y1 = pDrawable->y; box.x2 = pDrawable->x + pDrawable->width; box.y2 = pDrawable->y + pDrawable->height; REGION_INIT(&pixmapClip, &box, 1); pClip = &pixmapClip; } REGION_TRANSLATE(&pDamage->damage, pDrawable->x, pDrawable->y); REGION_INTERSECT(&pDamage->damage, &pDamage->damage, pClip); REGION_TRANSLATE(&pDamage->damage, -pDrawable->x, -pDrawable->y); if (pDrawable->type != DRAWABLE_WINDOW) REGION_UNINIT(&pixmapClip); } return REGION_NOTEMPTY(&pDamage->damage); } void DamageEmpty(DamagePtr pDamage) { REGION_EMPTY(&pDamage->damage); } RegionPtr DamageRegion(DamagePtr pDamage) { return &pDamage->damage; } _X_EXPORT void DamageDamageRegion(DrawablePtr pDrawable, RegionPtr pRegion) { damageDamageRegion(pDrawable, pRegion, FALSE, -1); /* Go back and report this damage for DamagePtrs with reportAfter set, since * this call isn't part of an in-progress drawing op in the call chain and * the DDX probably just wants to know about it right away. */ damageReportPostOp(pDrawable); } void DamageSetReportAfterOp(DamagePtr pDamage, Bool reportAfter) { pDamage->reportAfter = reportAfter; }