428261197a
Tested by ajacoutot@, krw@, shadchin@ and jasper@ on various configurations including multihead with both zaphod and xrandr.
2172 lines
54 KiB
C
2172 lines
54 KiB
C
/*
|
|
* 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 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
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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 ||\
|
|
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);
|
|
|
|
/* 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 = 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,
|
|
{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);
|
|
free(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;
|
|
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;
|
|
}
|