/* * 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 <dix-config.h> #endif #include <stdlib.h> #include <X11/X.h> #include "scrnintstr.h" #include "windowstr.h" #include <X11/fonts/font.h> #include "dixfontstr.h" #include <X11/fonts/fontstruct.h> #include "mi.h" #include "regionstr.h" #include "globals.h" #include "gcstruct.h" #include "damage.h" #include "damagestr.h" #ifdef COMPOSITE #include "cw.h" #endif #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 int damageScrPrivateKeyIndex; static DevPrivateKey damageScrPrivateKey = &damageScrPrivateKeyIndex; static int damagePixPrivateKeyIndex; static DevPrivateKey damagePixPrivateKey = &damagePixPrivateKeyIndex; static int damageGCPrivateKeyIndex; static DevPrivateKey damageGCPrivateKey = &damageGCPrivateKeyIndex; static int damageWinPrivateKeyIndex; static DevPrivateKey damageWinPrivateKey = &damageWinPrivateKeyIndex; 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 *) \ dixLookupPrivateAddr(&(pWindow)->devPrivates, damageWinPrivateKey) static void damageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion) { BoxRec tmpBox; RegionRec tmpRegion; Bool was_empty; switch (pDamage->damageLevel) { case DamageReportRawRegion: REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pDamageRegion); (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure); break; case DamageReportDeltaRegion: REGION_NULL (pScreen, &tmpRegion); REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, &pDamage->damage); if (REGION_NOTEMPTY (pScreen, &tmpRegion)) { REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pDamageRegion); (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure); } REGION_UNINIT(pScreen, &tmpRegion); break; case DamageReportBoundingBox: tmpBox = *REGION_EXTENTS (pScreen, &pDamage->damage); REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pDamageRegion); if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &pDamage->damage))) { (*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure); } break; case DamageReportNonEmpty: was_empty = !REGION_NOTEMPTY(pScreen, &pDamage->damage); REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pDamageRegion); if (was_empty && REGION_NOTEMPTY(pScreen, &pDamage->damage)) { (*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure); } break; case DamageReportNone: REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pDamageRegion); break; } } static void damageReportDamagePostRendering (DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pDamageRegion) { BoxRec tmpBox; RegionRec tmpRegion, newDamage; Bool was_empty; REGION_UNION(pScreem, &newDamage, pOldDamage, pDamageRegion); switch (pDamage->damageLevel) { case DamageReportRawRegion: (*pDamage->damageReportPostRendering) (pDamage, pDamageRegion, pDamage->closure); break; case DamageReportDeltaRegion: REGION_NULL (pScreen, &tmpRegion); REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, pOldDamage); if (REGION_NOTEMPTY (pScreen, &tmpRegion)) { (*pDamage->damageReportPostRendering) (pDamage, &tmpRegion, pDamage->closure); } REGION_UNINIT(pScreen, &tmpRegion); break; case DamageReportBoundingBox: tmpBox = *REGION_EXTENTS (pScreen, pOldDamage); if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &newDamage))) { (*pDamage->damageReportPostRendering) (pDamage, &newDamage, pDamage->closure); } break; case DamageReportNonEmpty: was_empty = !REGION_NOTEMPTY(pScreen, pOldDamage); if (was_empty && REGION_NOTEMPTY(pScreen, &newDamage)) { (*pDamage->damageReportPostRendering) (pDamage, &newDamage, pDamage->closure); } break; case DamageReportNone: break; } REGION_UNINIT(pScreen, &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 (!REGION_NOTEMPTY(pScreen, 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) REGION_TRANSLATE (pScreen, pRegion, screen_x, screen_y); #endif if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)(pDrawable))->backingStore == NotUseful) { if (subWindowMode == ClipByChildren) { REGION_INTERSECT(pScreen, pRegion, pRegion, &((WindowPtr)(pDrawable))->clipList); } else if (subWindowMode == IncludeInferiors) { RegionPtr pTempRegion = NotClippedByChildren((WindowPtr)(pDrawable)); REGION_INTERSECT(pScreen, pRegion, pRegion, pTempRegion); REGION_DESTROY(pScreen, pTempRegion); } /* If subWindowMode is set to an invalid value, don't perform * any drawable-based clipping. */ } REGION_NULL (pScreen, &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 (pDamage->pDrawable->type != DRAWABLE_WINDOW) { 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) { REGION_INTERSECT (pScreen, 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(pScreen, &pixClip, &box, 1); REGION_INTERSECT (pScreen, pDamageRegion, pRegion, &pixClip); REGION_UNINIT(pScreen, &pixClip); } /* * Short circuit empty results */ if (!REGION_NOTEMPTY(pScreen, 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 (pScreen, pDamageRegion, -draw_x, -draw_y); /* Store damage region if needed after submission. */ if (pDamage->reportAfter || pDamage->damageMarker) REGION_UNION(pScreen, &pDamage->pendingDamage, &pDamage->pendingDamage, pDamageRegion); /* Duplicate current damage if needed. */ if (pDamage->damageMarker) REGION_COPY(pScreen, &pDamage->backupDamage, &pDamage->damage); /* Report damage now, if desired. */ if (!pDamage->reportAfter) { if (pDamage->damageReport) damageReportDamage (pDamage, pDamageRegion); else REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, pDamageRegion); } /* * translate original region back */ if (pDamageRegion == pRegion && (draw_x || draw_y)) REGION_TRANSLATE (pScreen, pDamageRegion, draw_x, draw_y); } #ifdef COMPOSITE if (screen_x || screen_y) REGION_TRANSLATE (pScreen, pRegion, -screen_x, -screen_y); #endif REGION_UNINIT (pScreen, &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 REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage, &pDamage->pendingDamage); } if (pDamage->reportAfter || pDamage->damageMarker) REGION_EMPTY (pScreen, &pDamage->pendingDamage); if (pDamage->damageMarker) REGION_EMPTY (pScreen, &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; REGION_INIT (pDrawable->pScreen, ®ion, pBox, 1); #if DAMAGE_DEBUG_ENABLE _damageRegionAppend (pDrawable, ®ion, TRUE, subWindowMode, where); #else damageRegionAppend (pDrawable, ®ion, TRUE, subWindowMode); #endif REGION_UNINIT (pDrawable->pScreen, ®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; 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); \ 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(d->pScreen, \ g->pCompositeClip))) #ifdef RENDER #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(pScreen, 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); } #endif /**********************************************************/ 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); /* 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); 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); /* 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); 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 = xalloc(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)); } xfree(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"); 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 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 (pScreen, prgnSrc, dx, dy); damageRegionAppend (&pWindow->drawable, prgnSrc, FALSE, -1); REGION_TRANSLATE (pScreen, 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, {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, CopyWindow); unwrap (pScrPriv, pScreen, CloseScreen); xfree (pScrPriv); return (*pScreen->CloseScreen) (i, pScreen); } /** * Default implementations of the damage management functions. */ void miDamageCreate (DamagePtr pDamage) { } void miDamageRegister (DrawablePtr pDrawable, DamagePtr pDamage) { } void miDamageUnregister (DrawablePtr pDrawable, DamagePtr pDamage) { } void miDamageDestroy (DamagePtr pDamage) { } /** * Public functions for consumption outside this file. */ Bool DamageSetup (ScreenPtr pScreen) { DamageScrPrivPtr pScrPriv; #ifdef RENDER PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); #endif const DamageScreenFuncsRec miFuncs = { miDamageCreate, miDamageRegister, miDamageUnregister, miDamageDestroy }; if (dixLookupPrivate(&pScreen->devPrivates, damageScrPrivateKey)) return TRUE; if (!dixRequestPrivate(damageGCPrivateKey, sizeof(DamageGCPrivRec))) return FALSE; pScrPriv = xalloc (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); #ifdef RENDER if (ps) { wrap (pScrPriv, ps, Glyphs, damageGlyphs); wrap (pScrPriv, ps, Composite, damageComposite); wrap (pScrPriv, ps, AddTraps, damageAddTraps); } #endif 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 = xalloc (sizeof (DamageRec)); if (!pDamage) return 0; pDamage->pNext = 0; pDamage->pNextWin = 0; REGION_NULL(pScreen, &pDamage->damage); REGION_NULL(pScreen, &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; pDamage->devPrivates = NULL; (*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"); abort (); } #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"); abort (); } #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"); abort (); } #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); dixFreePrivates(pDamage->devPrivates); pDamage->devPrivates = NULL; REGION_UNINIT (pScreen, &pDamage->damage); REGION_UNINIT (pScreen, &pDamage->pendingDamage); xfree (pDamage); } Bool DamageSubtract (DamagePtr pDamage, const RegionPtr pRegion) { RegionPtr pClip; RegionRec pixmapClip; DrawablePtr pDrawable = pDamage->pDrawable; REGION_SUBTRACT (pDrawable->pScreen, &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 (pDrawable->pScreen, &pixmapClip, &box, 1); pClip = &pixmapClip; } REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, pDrawable->x, pDrawable->y); REGION_INTERSECT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pClip); REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, -pDrawable->x, -pDrawable->y); if (pDrawable->type != DRAWABLE_WINDOW) REGION_UNINIT(pDrawable->pScreen, &pixmapClip); } return REGION_NOTEMPTY (pDrawable->pScreen, &pDamage->damage); } void DamageEmpty (DamagePtr pDamage) { REGION_EMPTY (pDamage->pDrawable->pScreen, &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, const 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; }