/* * 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 *) \ dixLookupPrivateAddr(&(pPixmap)->devPrivates, damagePixPrivateKey)) #define pixmapDamage(pPixmap) damagePixPriv(pPixmap) static DevPrivateKeyRec damageScrPrivateKeyRec; #define damageScrPrivateKey (&damageScrPrivateKeyRec) static DevPrivateKeyRec damagePixPrivateKeyRec; #define damagePixPrivateKey (&damagePixPrivateKeyRec) static DevPrivateKeyRec damageGCPrivateKeyRec; #define damageGCPrivateKey (&damageGCPrivateKeyRec) static DevPrivateKeyRec damageWinPrivateKeyRec; #define damageWinPrivateKey (&damageWinPrivateKeyRec) static DamagePtr * getDrawableDamageRef(DrawablePtr pDrawable) { PixmapPtr pPixmap; if (WindowDrawable(pDrawable->type)) { 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 *) \ dixLookupPrivateAddr(&(pWindow)->devPrivates, damageWinPrivateKey) static void damageReportDamagePostRendering(DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pDamageRegion) { BoxRec tmpBox; RegionRec tmpRegion, newDamage; Bool was_empty; RegionUnion(&newDamage, pOldDamage, pDamageRegion); switch (pDamage->damageLevel) { case DamageReportRawRegion: (*pDamage->damageReportPostRendering) (pDamage, pDamageRegion, pDamage->closure); break; case DamageReportDeltaRegion: RegionNull(&tmpRegion); RegionSubtract(&tmpRegion, pDamageRegion, pOldDamage); if (RegionNotEmpty(&tmpRegion)) { (*pDamage->damageReportPostRendering) (pDamage, &tmpRegion, pDamage->closure); } RegionUninit(&tmpRegion); break; case DamageReportBoundingBox: tmpBox = *RegionExtents(pOldDamage); if (!BOX_SAME(&tmpBox, RegionExtents(&newDamage))) { (*pDamage->damageReportPostRendering) (pDamage, &newDamage, pDamage->closure); } break; case DamageReportNonEmpty: was_empty = !RegionNotEmpty(pOldDamage); if (was_empty && RegionNotEmpty(&newDamage)) { (*pDamage->damageReportPostRendering) (pDamage, &newDamage, pDamage->closure); } break; case DamageReportNone: break; } RegionUninit(&newDamage); } #if DAMAGE_DEBUG_ENABLE static void _damageRegionAppend(DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode, const char *where) #define damageRegionAppend(d,r,c,m) _damageRegionAppend(d,r,c,m,__FUNCTION__) #else static void damageRegionAppend(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; #ifdef COMPOSITE int screen_x = 0, screen_y = 0; #endif /* short circuit for empty regions */ if (!RegionNotEmpty(pRegion)) return; #ifdef COMPOSITE /* * When drawing to a pixmap which is storing window contents, * the region presented is in pixmap relative coordinates which * need to be converted to screen relative coordinates */ if (pDrawable->type != DRAWABLE_WINDOW) { screen_x = ((PixmapPtr) pDrawable)->screen_x - pDrawable->x; screen_y = ((PixmapPtr) pDrawable)->screen_y - pDrawable->y; } if (screen_x || screen_y) RegionTranslate(pRegion, screen_x, screen_y); #endif if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) (pDrawable))->backingStore == NotUseful) { if (subWindowMode == ClipByChildren) { RegionIntersect(pRegion, pRegion, &((WindowPtr) (pDrawable))->clipList); } else if (subWindowMode == IncludeInferiors) { RegionPtr pTempRegion = NotClippedByChildren((WindowPtr) (pDrawable)); RegionIntersect(pRegion, pRegion, pTempRegion); RegionDestroy(pTempRegion); } /* If subWindowMode is set to an invalid value, don't perform * any drawable-based clipping. */ } RegionNull(&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) { continue; } draw_x = pDamage->pDrawable->x; draw_y = pDamage->pDrawable->y; #ifdef COMPOSITE /* * Need to move everyone to screen coordinates * XXX what about off-screen pixmaps with non-zero x/y? */ if (!WindowDrawable(pDamage->pDrawable->type)) { draw_x += ((PixmapPtr) pDamage->pDrawable)->screen_x; draw_y += ((PixmapPtr) pDamage->pDrawable)->screen_y; } #endif /* * Clip against border or pixmap bounds */ pDamageRegion = pRegion; if (clip || pDamage->pDrawable != pDrawable) { pDamageRegion = &clippedRec; if (pDamage->pDrawable->type == DRAWABLE_WINDOW) { RegionIntersect(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; RegionInit(&pixClip, &box, 1); RegionIntersect(pDamageRegion, pRegion, &pixClip); RegionUninit(&pixClip); } /* * Short circuit empty results */ if (!RegionNotEmpty(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) RegionTranslate(pDamageRegion, -draw_x, -draw_y); /* Store damage region if needed after submission. */ if (pDamage->reportAfter || pDamage->damageMarker) RegionUnion(&pDamage->pendingDamage, &pDamage->pendingDamage, pDamageRegion); /* Duplicate current damage if needed. */ if (pDamage->damageMarker) RegionCopy(&pDamage->backupDamage, &pDamage->damage); /* Report damage now, if desired. */ if (!pDamage->reportAfter) { if (pDamage->damageReport) DamageReportDamage(pDamage, pDamageRegion); else RegionUnion(&pDamage->damage, &pDamage->damage, pDamageRegion); } /* * translate original region back */ if (pDamageRegion == pRegion && (draw_x || draw_y)) RegionTranslate(pDamageRegion, draw_x, draw_y); } #ifdef COMPOSITE if (screen_x || screen_y) RegionTranslate(pRegion, -screen_x, -screen_y); #endif RegionUninit(&clippedRec); } static void damageRegionProcessPending(DrawablePtr pDrawable) { drawableDamage(pDrawable); for (; pDamage != NULL; pDamage = pDamage->pNext) { /* submit damage marker whenever possible. */ if (pDamage->damageMarker) (*pDamage->damageMarker) (pDrawable, pDamage, &pDamage->backupDamage, &pDamage->pendingDamage, pDamage->closure); if (pDamage->reportAfter) { /* It's possible that there is only interest in postRendering reporting. */ if (pDamage->damageReport) DamageReportDamage(pDamage, &pDamage->pendingDamage); else RegionUnion(&pDamage->damage, &pDamage->damage, &pDamage->pendingDamage); } if (pDamage->reportAfter || pDamage->damageMarker) RegionEmpty(&pDamage->pendingDamage); if (pDamage->damageMarker) RegionEmpty(&pDamage->backupDamage); } } #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; RegionInit(®ion, pBox, 1); #if DAMAGE_DEBUG_ENABLE _damageRegionAppend(pDrawable, ®ion, TRUE, subWindowMode, where); #else damageRegionAppend(pDrawable, ®ion, TRUE, subWindowMode); #endif RegionUninit(®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 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; 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; } #define DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable) \ damageGCPriv(pGC); \ 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) { drawableDamage(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 ||\ RegionNotEmpty(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) && \ RegionNotEmpty(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); damageRegionProcessPending(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); damageRegionProcessPending(pDst->pDrawable); wrap(pScrPriv, ps, Glyphs, damageGlyphs); } static void damageAddTraps(PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntrap, xTrap * traps) { ScreenPtr pScreen = pPicture->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); damageScrPriv(pScreen); if (checkPictureDamage(pPicture)) { BoxRec box; int i; int x, y; xTrap *t = traps; box.x1 = 32767; box.y1 = 32767; box.x2 = -32767; box.y2 = -32767; x = pPicture->pDrawable->x + x_off; y = pPicture->pDrawable->y + y_off; for (i = 0; i < ntrap; i++) { pixman_fixed_t l = min(t->top.l, t->bot.l); pixman_fixed_t r = max(t->top.r, t->bot.r); int x1 = x + pixman_fixed_to_int(l); int x2 = x + pixman_fixed_to_int(pixman_fixed_ceil(r)); int y1 = y + pixman_fixed_to_int(t->top.y); int y2 = y + pixman_fixed_to_int(pixman_fixed_ceil(t->bot.y)); if (x1 < box.x1) box.x1 = x1; if (x2 > box.x2) box.x2 = x2; if (y1 < box.y1) box.y1 = y1; if (y2 > box.y2) box.y2 = y2; } TRIM_PICTURE_BOX(box, pPicture); if (BOX_NOT_EMPTY(box)) damageDamageBox(pPicture->pDrawable, &box, pPicture->subWindowMode); } unwrap(pScrPriv, ps, AddTraps); (*ps->AddTraps) (pPicture, x_off, y_off, ntrap, traps); damageRegionProcessPending(pPicture->pDrawable); wrap(pScrPriv, ps, AddTraps, damageAddTraps); } /**********************************************************/ 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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); 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); damageRegionProcessPending(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); 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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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 = malloc(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)); } free(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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); damageRegionProcessPending(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"); OsAbort(); #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"); OsAbort(); } #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 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. */ RegionTranslate(prgnSrc, dx, dy); damageRegionAppend(&pWindow->drawable, prgnSrc, FALSE, -1); RegionTranslate(prgnSrc, -dx, -dy); } unwrap(pScrPriv, pScreen, CopyWindow); (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); damageRegionProcessPending(&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, }; 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(ScreenPtr pScreen) { damageScrPriv(pScreen); unwrap(pScrPriv, pScreen, DestroyPixmap); unwrap(pScrPriv, pScreen, CreateGC); unwrap(pScrPriv, pScreen, CopyWindow); unwrap(pScrPriv, pScreen, CloseScreen); free(pScrPriv); return (*pScreen->CloseScreen) (pScreen); } /** * Default implementations of the damage management functions. */ void miDamageCreate(DamagePtr pDamage) { } /* * We only wrap into the GC when there's a registered listener. For windows, * damage includes damage to children. So if there's a GC validated against * a subwindow and we then register a damage on the parent, we need to bump * the serial numbers of the children to re-trigger validation. * * Since we can't know if a GC has been validated against one of the affected * children, just bump them all to be safe. */ static int damageRegisterVisit(WindowPtr pWin, void *data) { pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; return WT_WALKCHILDREN; } void miDamageRegister(DrawablePtr pDrawable, DamagePtr pDamage) { if (pDrawable->type == DRAWABLE_WINDOW) TraverseTree((WindowPtr)pDrawable, damageRegisterVisit, NULL); else pDrawable->serialNumber = NEXT_SERIAL_NUMBER; } void miDamageUnregister(DrawablePtr pDrawable, DamagePtr pDamage) { if (pDrawable->type == DRAWABLE_WINDOW) TraverseTree((WindowPtr)pDrawable, damageRegisterVisit, NULL); else pDrawable->serialNumber = NEXT_SERIAL_NUMBER; } void miDamageDestroy(DamagePtr pDamage) { } /** * Public functions for consumption outside this file. */ Bool DamageSetup(ScreenPtr pScreen) { DamageScrPrivPtr pScrPriv; PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); const DamageScreenFuncsRec miFuncs = { miDamageCreate, miDamageRegister, miDamageUnregister, miDamageDestroy }; if (!dixRegisterPrivateKey(&damageScrPrivateKeyRec, PRIVATE_SCREEN, 0)) return FALSE; if (dixLookupPrivate(&pScreen->devPrivates, damageScrPrivateKey)) return TRUE; if (!dixRegisterPrivateKey (&damageGCPrivateKeyRec, PRIVATE_GC, sizeof(DamageGCPrivRec))) return FALSE; if (!dixRegisterPrivateKey(&damagePixPrivateKeyRec, PRIVATE_PIXMAP, 0)) return FALSE; if (!dixRegisterPrivateKey(&damageWinPrivateKeyRec, PRIVATE_WINDOW, 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, 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); wrap(pScrPriv, ps, AddTraps, damageAddTraps); } pScrPriv->funcs = miFuncs; dixSetPrivate(&pScreen->devPrivates, damageScrPrivateKey, pScrPriv); return TRUE; } DamagePtr DamageCreate(DamageReportFunc damageReport, DamageDestroyFunc damageDestroy, DamageReportLevel damageLevel, Bool isInternal, ScreenPtr pScreen, void *closure) { damageScrPriv(pScreen); DamagePtr pDamage; pDamage = dixAllocateObjectWithPrivates(DamageRec, PRIVATE_DAMAGE); if (!pDamage) return 0; pDamage->pNext = 0; pDamage->pNextWin = 0; RegionNull(&pDamage->damage); RegionNull(&pDamage->pendingDamage); pDamage->damageLevel = damageLevel; pDamage->isInternal = isInternal; pDamage->closure = closure; pDamage->isWindow = FALSE; pDamage->pDrawable = 0; pDamage->reportAfter = FALSE; pDamage->damageReport = damageReport; pDamage->damageReportPostRendering = NULL; pDamage->damageDestroy = damageDestroy; pDamage->damageMarker = NULL; pDamage->pScreen = pScreen; (*pScrPriv->funcs.Create) (pDamage); return pDamage; } void DamageRegister(DrawablePtr pDrawable, DamagePtr pDamage) { ScreenPtr pScreen = pDrawable->pScreen; damageScrPriv(pScreen); #if DAMAGE_VALIDATE_ENABLE if (pDrawable->pScreen != pDamage->pScreen) { ErrorF("DamageRegister called with mismatched screens\n"); OsAbort(); } #endif 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"); OsAbort(); } #endif pDamage->pNextWin = *pPrev; *pPrev = pDamage; pDamage->isWindow = TRUE; } else pDamage->isWindow = FALSE; pDamage->pDrawable = pDrawable; damageInsertDamage(getDrawableDamageRef(pDrawable), pDamage); (*pScrPriv->funcs.Register) (pDrawable, pDamage); } void DamageDrawInternal(ScreenPtr pScreen, Bool enable) { damageScrPriv(pScreen); pScrPriv->internalLevel += enable ? 1 : -1; } void DamageUnregister(DrawablePtr pDrawable, DamagePtr pDamage) { ScreenPtr pScreen = pDrawable->pScreen; damageScrPriv(pScreen); (*pScrPriv->funcs.Unregister) (pDrawable, 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"); OsAbort(); } #endif } pDamage->pDrawable = 0; damageRemoveDamage(getDrawableDamageRef(pDrawable), pDamage); } void DamageDestroy(DamagePtr pDamage) { ScreenPtr pScreen = pDamage->pScreen; damageScrPriv(pScreen); if (pDamage->damageDestroy) (*pDamage->damageDestroy) (pDamage, pDamage->closure); (*pScrPriv->funcs.Destroy) (pDamage); RegionUninit(&pDamage->damage); RegionUninit(&pDamage->pendingDamage); dixFreeObjectWithPrivates(pDamage, PRIVATE_DAMAGE); } Bool DamageSubtract(DamagePtr pDamage, const RegionPtr pRegion) { RegionPtr pClip; RegionRec pixmapClip; DrawablePtr pDrawable = pDamage->pDrawable; RegionSubtract(&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; RegionInit(&pixmapClip, &box, 1); pClip = &pixmapClip; } RegionTranslate(&pDamage->damage, pDrawable->x, pDrawable->y); RegionIntersect(&pDamage->damage, &pDamage->damage, pClip); RegionTranslate(&pDamage->damage, -pDrawable->x, -pDrawable->y); if (pDrawable->type != DRAWABLE_WINDOW) RegionUninit(&pixmapClip); } return RegionNotEmpty(&pDamage->damage); } void DamageEmpty(DamagePtr pDamage) { RegionEmpty(&pDamage->damage); } RegionPtr DamageRegion(DamagePtr pDamage) { return &pDamage->damage; } RegionPtr DamagePendingRegion(DamagePtr pDamage) { return &pDamage->pendingDamage; } void DamageRegionAppend(DrawablePtr pDrawable, RegionPtr pRegion) { damageRegionAppend(pDrawable, pRegion, FALSE, -1); } void DamageRegionProcessPending(DrawablePtr pDrawable) { damageRegionProcessPending(pDrawable); } /* If a damage marker is provided, then this function must be called after rendering is done. */ /* Please do call back so any future enhancements can assume this function is called. */ /* There are no strict timing requirements for calling this function, just as soon as (is cheaply) possible. */ void DamageRegionRendered(DrawablePtr pDrawable, DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pRegion) { if (pDamage->damageReportPostRendering) damageReportDamagePostRendering(pDamage, pOldDamage, pRegion); } /* This call is very odd, i'm leaving it intact for API sake, but please don't use it. */ void DamageDamageRegion(DrawablePtr pDrawable, RegionPtr pRegion) { damageRegionAppend(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. */ damageRegionProcessPending(pDrawable); } void DamageSetReportAfterOp(DamagePtr pDamage, Bool reportAfter) { pDamage->reportAfter = reportAfter; } void DamageSetPostRenderingFunctions(DamagePtr pDamage, DamageReportFunc damageReportPostRendering, DamageMarkerFunc damageMarker) { pDamage->damageReportPostRendering = damageReportPostRendering; pDamage->damageMarker = damageMarker; } DamageScreenFuncsPtr DamageGetScreenFuncs(ScreenPtr pScreen) { damageScrPriv(pScreen); return &pScrPriv->funcs; } void DamageReportDamage(DamagePtr pDamage, RegionPtr pDamageRegion) { BoxRec tmpBox; RegionRec tmpRegion; Bool was_empty; switch (pDamage->damageLevel) { case DamageReportRawRegion: RegionUnion(&pDamage->damage, &pDamage->damage, pDamageRegion); (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure); break; case DamageReportDeltaRegion: RegionNull(&tmpRegion); RegionSubtract(&tmpRegion, pDamageRegion, &pDamage->damage); if (RegionNotEmpty(&tmpRegion)) { RegionUnion(&pDamage->damage, &pDamage->damage, pDamageRegion); (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure); } RegionUninit(&tmpRegion); break; case DamageReportBoundingBox: tmpBox = *RegionExtents(&pDamage->damage); RegionUnion(&pDamage->damage, &pDamage->damage, pDamageRegion); if (!BOX_SAME(&tmpBox, RegionExtents(&pDamage->damage))) { (*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure); } break; case DamageReportNonEmpty: was_empty = !RegionNotEmpty(&pDamage->damage); RegionUnion(&pDamage->damage, &pDamage->damage, pDamageRegion); if (was_empty && RegionNotEmpty(&pDamage->damage)) { (*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure); } break; case DamageReportNone: RegionUnion(&pDamage->damage, &pDamage->damage, pDamageRegion); break; } }