damage.c revision 6747b715
1/*
2 * Copyright © 2003 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include <stdlib.h>
28
29#include    <X11/X.h>
30#include    "scrnintstr.h"
31#include    "windowstr.h"
32#include    <X11/fonts/font.h>
33#include    "dixfontstr.h"
34#include    <X11/fonts/fontstruct.h>
35#include    "mi.h"
36#include    "regionstr.h"
37#include    "globals.h"
38#include    "gcstruct.h"
39#include    "damage.h"
40#include    "damagestr.h"
41#ifdef COMPOSITE
42#include    "cw.h"
43#endif
44
45#define wrap(priv, real, mem, func) {\
46    priv->mem = real->mem; \
47    real->mem = func; \
48}
49
50#define unwrap(priv, real, mem) {\
51    real->mem = priv->mem; \
52}
53
54#define BOX_SAME(a,b) \
55    ((a)->x1 == (b)->x1 && \
56     (a)->y1 == (b)->y1 && \
57     (a)->x2 == (b)->x2 && \
58     (a)->y2 == (b)->y2)
59
60#define DAMAGE_VALIDATE_ENABLE 0
61#define DAMAGE_DEBUG_ENABLE 0
62#if DAMAGE_DEBUG_ENABLE
63#define DAMAGE_DEBUG(x)	ErrorF x
64#else
65#define DAMAGE_DEBUG(x)
66#endif
67
68#define getPixmapDamageRef(pPixmap) ((DamagePtr *) \
69    dixLookupPrivateAddr(&(pPixmap)->devPrivates, damagePixPrivateKey))
70
71#define pixmapDamage(pPixmap)		damagePixPriv(pPixmap)
72
73static DevPrivateKeyRec damageScrPrivateKeyRec;
74#define damageScrPrivateKey (&damageScrPrivateKeyRec)
75static DevPrivateKeyRec damagePixPrivateKeyRec;
76#define damagePixPrivateKey (&damagePixPrivateKeyRec)
77static DevPrivateKeyRec damageGCPrivateKeyRec;
78#define damageGCPrivateKey (&damageGCPrivateKeyRec)
79static DevPrivateKeyRec damageWinPrivateKeyRec;
80#define damageWinPrivateKey (&damageWinPrivateKeyRec)
81
82static DamagePtr *
83getDrawableDamageRef (DrawablePtr pDrawable)
84{
85    PixmapPtr   pPixmap;
86
87    if (WindowDrawable(pDrawable->type))
88    {
89	ScreenPtr   pScreen = pDrawable->pScreen;
90
91	pPixmap = 0;
92	if (pScreen->GetWindowPixmap
93#ifdef ROOTLESS_WORKAROUND
94	    && ((WindowPtr)pDrawable)->viewable
95#endif
96	    )
97	    pPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr)pDrawable);
98
99	if (!pPixmap)
100	{
101	    damageScrPriv(pScreen);
102
103	    return &pScrPriv->pScreenDamage;
104	}
105    }
106    else
107	pPixmap = (PixmapPtr) pDrawable;
108    return getPixmapDamageRef (pPixmap);
109}
110
111#define getDrawableDamage(pDrawable)	(*getDrawableDamageRef (pDrawable))
112#define getWindowDamage(pWin)		getDrawableDamage(&(pWin)->drawable)
113
114#define drawableDamage(pDrawable)	\
115    DamagePtr	pDamage = getDrawableDamage(pDrawable)
116
117#define windowDamage(pWin)		drawableDamage(&(pWin)->drawable)
118
119#define winDamageRef(pWindow) \
120    DamagePtr	*pPrev = (DamagePtr *) \
121	dixLookupPrivateAddr(&(pWindow)->devPrivates, damageWinPrivateKey)
122
123static void
124damageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion)
125{
126    BoxRec tmpBox;
127    RegionRec tmpRegion;
128    Bool was_empty;
129
130    switch (pDamage->damageLevel) {
131    case DamageReportRawRegion:
132	RegionUnion(&pDamage->damage, &pDamage->damage,
133			 pDamageRegion);
134	(*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure);
135	break;
136    case DamageReportDeltaRegion:
137	RegionNull(&tmpRegion);
138	RegionSubtract(&tmpRegion, pDamageRegion, &pDamage->damage);
139	if (RegionNotEmpty(&tmpRegion)) {
140	    RegionUnion(&pDamage->damage, &pDamage->damage,
141			 pDamageRegion);
142	    (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure);
143	}
144	RegionUninit(&tmpRegion);
145	break;
146    case DamageReportBoundingBox:
147	tmpBox = *RegionExtents(&pDamage->damage);
148	RegionUnion(&pDamage->damage, &pDamage->damage,
149		     pDamageRegion);
150	if (!BOX_SAME (&tmpBox, RegionExtents(&pDamage->damage))) {
151	    (*pDamage->damageReport) (pDamage, &pDamage->damage,
152				      pDamage->closure);
153	}
154	break;
155    case DamageReportNonEmpty:
156	was_empty = !RegionNotEmpty(&pDamage->damage);
157	RegionUnion(&pDamage->damage, &pDamage->damage,
158		     pDamageRegion);
159	if (was_empty && RegionNotEmpty(&pDamage->damage)) {
160	    (*pDamage->damageReport) (pDamage, &pDamage->damage,
161				      pDamage->closure);
162	}
163	break;
164    case DamageReportNone:
165	RegionUnion(&pDamage->damage, &pDamage->damage,
166		     pDamageRegion);
167	break;
168    }
169}
170
171static void
172damageReportDamagePostRendering (DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pDamageRegion)
173{
174    BoxRec tmpBox;
175    RegionRec tmpRegion, newDamage;
176    Bool was_empty;
177
178    RegionUnion(&newDamage, pOldDamage, pDamageRegion);
179
180    switch (pDamage->damageLevel) {
181    case DamageReportRawRegion:
182	(*pDamage->damageReportPostRendering) (pDamage, pDamageRegion, pDamage->closure);
183	break;
184    case DamageReportDeltaRegion:
185	RegionNull(&tmpRegion);
186	RegionSubtract(&tmpRegion, pDamageRegion, pOldDamage);
187	if (RegionNotEmpty(&tmpRegion)) {
188	    (*pDamage->damageReportPostRendering) (pDamage, &tmpRegion, pDamage->closure);
189	}
190	RegionUninit(&tmpRegion);
191	break;
192    case DamageReportBoundingBox:
193	tmpBox = *RegionExtents(pOldDamage);
194	if (!BOX_SAME (&tmpBox, RegionExtents(&newDamage))) {
195	    (*pDamage->damageReportPostRendering) (pDamage, &newDamage,
196				      pDamage->closure);
197	}
198	break;
199    case DamageReportNonEmpty:
200	was_empty = !RegionNotEmpty(pOldDamage);
201	if (was_empty && RegionNotEmpty(&newDamage)) {
202	    (*pDamage->damageReportPostRendering) (pDamage, &newDamage,
203				      pDamage->closure);
204	}
205	break;
206    case DamageReportNone:
207	break;
208    }
209
210    RegionUninit(&newDamage);
211}
212
213#if DAMAGE_DEBUG_ENABLE
214static void
215_damageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode, const char *where)
216#define damageRegionAppend(d,r,c,m) _damageRegionAppend(d,r,c,m,__FUNCTION__)
217#else
218static void
219damageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip,
220			int subWindowMode)
221#endif
222{
223    ScreenPtr	    pScreen = pDrawable->pScreen;
224    damageScrPriv(pScreen);
225    drawableDamage(pDrawable);
226    DamagePtr	    pNext;
227    RegionRec	    clippedRec;
228    RegionPtr	    pDamageRegion;
229    RegionRec	    pixClip;
230    int		    draw_x, draw_y;
231#ifdef COMPOSITE
232    int		    screen_x = 0, screen_y = 0;
233#endif
234
235    /* short circuit for empty regions */
236    if (!RegionNotEmpty(pRegion))
237	return;
238
239#ifdef COMPOSITE
240    /*
241     * When drawing to a pixmap which is storing window contents,
242     * the region presented is in pixmap relative coordinates which
243     * need to be converted to screen relative coordinates
244     */
245    if (pDrawable->type != DRAWABLE_WINDOW)
246    {
247	screen_x = ((PixmapPtr) pDrawable)->screen_x - pDrawable->x;
248	screen_y = ((PixmapPtr) pDrawable)->screen_y - pDrawable->y;
249    }
250    if (screen_x || screen_y)
251        RegionTranslate(pRegion, screen_x, screen_y);
252#endif
253
254    if (pDrawable->type == DRAWABLE_WINDOW &&
255	((WindowPtr)(pDrawable))->backingStore == NotUseful)
256    {
257	if (subWindowMode == ClipByChildren)
258	{
259	    RegionIntersect(pRegion, pRegion,
260			     &((WindowPtr)(pDrawable))->clipList);
261	}
262	else if (subWindowMode == IncludeInferiors)
263	{
264	    RegionPtr pTempRegion =
265		NotClippedByChildren((WindowPtr)(pDrawable));
266	    RegionIntersect(pRegion, pRegion, pTempRegion);
267	    RegionDestroy(pTempRegion);
268	}
269	/* If subWindowMode is set to an invalid value, don't perform
270	 * any drawable-based clipping. */
271    }
272
273
274    RegionNull(&clippedRec);
275    for (; pDamage; pDamage = pNext)
276    {
277	pNext = pDamage->pNext;
278	/*
279	 * Check for internal damage and don't send events
280	 */
281	if (pScrPriv->internalLevel > 0 && !pDamage->isInternal)
282	{
283	    DAMAGE_DEBUG (("non internal damage, skipping at %d\n",
284			   pScrPriv->internalLevel));
285	    continue;
286	}
287	/*
288	 * Check for unrealized windows
289	 */
290	if (pDamage->pDrawable->type == DRAWABLE_WINDOW &&
291	    !((WindowPtr) (pDamage->pDrawable))->realized)
292	{
293	    continue;
294	}
295
296	draw_x = pDamage->pDrawable->x;
297	draw_y = pDamage->pDrawable->y;
298#ifdef COMPOSITE
299	/*
300	 * Need to move everyone to screen coordinates
301	 * XXX what about off-screen pixmaps with non-zero x/y?
302	 */
303	if (!WindowDrawable(pDamage->pDrawable->type))
304	{
305	    draw_x += ((PixmapPtr) pDamage->pDrawable)->screen_x;
306	    draw_y += ((PixmapPtr) pDamage->pDrawable)->screen_y;
307	}
308#endif
309
310	/*
311	 * Clip against border or pixmap bounds
312	 */
313
314	pDamageRegion = pRegion;
315	if (clip || pDamage->pDrawable != pDrawable)
316	{
317	    pDamageRegion = &clippedRec;
318	    if (pDamage->pDrawable->type == DRAWABLE_WINDOW) {
319		RegionIntersect(pDamageRegion, pRegion,
320		    &((WindowPtr)(pDamage->pDrawable))->borderClip);
321	    } else {
322		BoxRec	box;
323		box.x1 = draw_x;
324		box.y1 = draw_y;
325		box.x2 = draw_x + pDamage->pDrawable->width;
326		box.y2 = draw_y + pDamage->pDrawable->height;
327		RegionInit(&pixClip, &box, 1);
328		RegionIntersect(pDamageRegion, pRegion, &pixClip);
329		RegionUninit(&pixClip);
330	    }
331	    /*
332	     * Short circuit empty results
333	     */
334	    if (!RegionNotEmpty(pDamageRegion))
335		continue;
336	}
337
338	DAMAGE_DEBUG (("%s %d x %d +%d +%d (target 0x%lx monitor 0x%lx)\n",
339		       where,
340		       pDamageRegion->extents.x2 - pDamageRegion->extents.x1,
341		       pDamageRegion->extents.y2 - pDamageRegion->extents.y1,
342		       pDamageRegion->extents.x1, pDamageRegion->extents.y1,
343		       pDrawable->id, pDamage->pDrawable->id));
344
345	/*
346	 * Move region to target coordinate space
347	 */
348	if (draw_x || draw_y)
349	    RegionTranslate(pDamageRegion, -draw_x, -draw_y);
350
351	/* Store damage region if needed after submission. */
352	if (pDamage->reportAfter || pDamage->damageMarker)
353	    RegionUnion(&pDamage->pendingDamage,
354			 &pDamage->pendingDamage, pDamageRegion);
355
356	/* Duplicate current damage if needed. */
357	if (pDamage->damageMarker)
358	    RegionCopy(&pDamage->backupDamage, &pDamage->damage);
359
360	/* Report damage now, if desired. */
361	if (!pDamage->reportAfter) {
362	    if (pDamage->damageReport)
363		damageReportDamage (pDamage, pDamageRegion);
364	    else
365		RegionUnion(&pDamage->damage,
366			 &pDamage->damage, pDamageRegion);
367	}
368
369	/*
370	 * translate original region back
371	 */
372	if (pDamageRegion == pRegion && (draw_x || draw_y))
373	    RegionTranslate(pDamageRegion, draw_x, draw_y);
374    }
375#ifdef COMPOSITE
376    if (screen_x || screen_y)
377	RegionTranslate(pRegion, -screen_x, -screen_y);
378#endif
379
380    RegionUninit(&clippedRec);
381}
382
383static void
384damageRegionProcessPending (DrawablePtr pDrawable)
385{
386    drawableDamage(pDrawable);
387
388    for (; pDamage != NULL; pDamage = pDamage->pNext)
389    {
390	/* submit damage marker whenever possible. */
391	if (pDamage->damageMarker)
392	    (*pDamage->damageMarker) (pDrawable, pDamage, &pDamage->backupDamage, &pDamage->pendingDamage, pDamage->closure);
393	if (pDamage->reportAfter) {
394	    /* It's possible that there is only interest in postRendering reporting. */
395	    if (pDamage->damageReport)
396		damageReportDamage (pDamage, &pDamage->pendingDamage);
397	    else
398		RegionUnion(&pDamage->damage, &pDamage->damage,
399			&pDamage->pendingDamage);
400	}
401
402	if (pDamage->reportAfter || pDamage->damageMarker)
403	    RegionEmpty(&pDamage->pendingDamage);
404	if (pDamage->damageMarker)
405	    RegionEmpty(&pDamage->backupDamage);
406    }
407
408}
409
410#if DAMAGE_DEBUG_ENABLE
411#define damageDamageBox(d,b,m) _damageDamageBox(d,b,m,__FUNCTION__)
412static void
413_damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode, const char *where)
414#else
415static void
416damageDamageBox (DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode)
417#endif
418{
419    RegionRec	region;
420
421    RegionInit(&region, pBox, 1);
422#if DAMAGE_DEBUG_ENABLE
423    _damageRegionAppend (pDrawable, &region, TRUE, subWindowMode, where);
424#else
425    damageRegionAppend (pDrawable, &region, TRUE, subWindowMode);
426#endif
427    RegionUninit(&region);
428}
429
430static void damageValidateGC(GCPtr, unsigned long, DrawablePtr);
431static void damageChangeGC(GCPtr, unsigned long);
432static void damageCopyGC(GCPtr, unsigned long, GCPtr);
433static void damageDestroyGC(GCPtr);
434static void damageChangeClip(GCPtr, int, pointer, int);
435static void damageDestroyClip(GCPtr);
436static void damageCopyClip(GCPtr, GCPtr);
437
438static GCFuncs damageGCFuncs = {
439    damageValidateGC, damageChangeGC, damageCopyGC, damageDestroyGC,
440    damageChangeClip, damageDestroyClip, damageCopyClip
441};
442
443static GCOps damageGCOps;
444
445static Bool
446damageCreateGC(GCPtr pGC)
447{
448    ScreenPtr pScreen = pGC->pScreen;
449    damageScrPriv(pScreen);
450    damageGCPriv(pGC);
451    Bool ret;
452
453    pGC->pCompositeClip = 0;
454    unwrap (pScrPriv, pScreen, CreateGC);
455    if((ret = (*pScreen->CreateGC) (pGC))) {
456	pGCPriv->ops = NULL;
457	pGCPriv->funcs = pGC->funcs;
458	pGC->funcs = &damageGCFuncs;
459    }
460    wrap (pScrPriv, pScreen, CreateGC, damageCreateGC);
461
462    return ret;
463}
464
465#ifdef NOTUSED
466static void
467damageWrapGC (GCPtr pGC)
468{
469    damageGCPriv(pGC);
470
471    pGCPriv->ops = NULL;
472    pGCPriv->funcs = pGC->funcs;
473    pGC->funcs = &damageGCFuncs;
474}
475
476static void
477damageUnwrapGC (GCPtr pGC)
478{
479    damageGCPriv(pGC);
480
481    pGC->funcs = pGCPriv->funcs;
482    if (pGCPriv->ops)
483	pGC->ops = pGCPriv->ops;
484}
485#endif
486
487#define DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable) \
488    damageGCPriv(pGC);  \
489    GCFuncs *oldFuncs = pGC->funcs; \
490    unwrap(pGCPriv, pGC, funcs);  \
491    unwrap(pGCPriv, pGC, ops); \
492
493#define DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable) \
494    wrap(pGCPriv, pGC, funcs, oldFuncs); \
495    wrap(pGCPriv, pGC, ops, &damageGCOps)
496
497#define DAMAGE_GC_FUNC_PROLOGUE(pGC) \
498    damageGCPriv(pGC); \
499    unwrap(pGCPriv, pGC, funcs); \
500    if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops)
501
502#define DAMAGE_GC_FUNC_EPILOGUE(pGC) \
503    wrap(pGCPriv, pGC, funcs, &damageGCFuncs);  \
504    if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &damageGCOps)
505
506static void
507damageValidateGC(GCPtr         pGC,
508		 unsigned long changes,
509		 DrawablePtr   pDrawable)
510{
511    DAMAGE_GC_FUNC_PROLOGUE (pGC);
512    (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
513    pGCPriv->ops = pGC->ops;  /* just so it's not NULL */
514    DAMAGE_GC_FUNC_EPILOGUE (pGC);
515}
516
517static void
518damageDestroyGC(GCPtr pGC)
519{
520    DAMAGE_GC_FUNC_PROLOGUE (pGC);
521    (*pGC->funcs->DestroyGC)(pGC);
522    DAMAGE_GC_FUNC_EPILOGUE (pGC);
523}
524
525static void
526damageChangeGC (GCPtr		pGC,
527		unsigned long   mask)
528{
529    DAMAGE_GC_FUNC_PROLOGUE (pGC);
530    (*pGC->funcs->ChangeGC) (pGC, mask);
531    DAMAGE_GC_FUNC_EPILOGUE (pGC);
532}
533
534static void
535damageCopyGC (GCPtr	    pGCSrc,
536	      unsigned long mask,
537	      GCPtr	    pGCDst)
538{
539    DAMAGE_GC_FUNC_PROLOGUE (pGCDst);
540    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
541    DAMAGE_GC_FUNC_EPILOGUE (pGCDst);
542}
543
544static void
545damageChangeClip (GCPtr	    pGC,
546		  int	    type,
547		  pointer   pvalue,
548		  int	    nrects)
549{
550    DAMAGE_GC_FUNC_PROLOGUE (pGC);
551    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
552    DAMAGE_GC_FUNC_EPILOGUE (pGC);
553}
554
555static void
556damageCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
557{
558    DAMAGE_GC_FUNC_PROLOGUE (pgcDst);
559    (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
560    DAMAGE_GC_FUNC_EPILOGUE (pgcDst);
561}
562
563static void
564damageDestroyClip(GCPtr pGC)
565{
566    DAMAGE_GC_FUNC_PROLOGUE (pGC);
567    (* pGC->funcs->DestroyClip)(pGC);
568    DAMAGE_GC_FUNC_EPILOGUE (pGC);
569}
570
571#define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) { \
572    BoxPtr extents = &pGC->pCompositeClip->extents;\
573    if(box.x1 < extents->x1) box.x1 = extents->x1; \
574    if(box.x2 > extents->x2) box.x2 = extents->x2; \
575    if(box.y1 < extents->y1) box.y1 = extents->y1; \
576    if(box.y2 > extents->y2) box.y2 = extents->y2; \
577    }
578
579#define TRANSLATE_BOX(box, pDrawable) { \
580    box.x1 += pDrawable->x; \
581    box.x2 += pDrawable->x; \
582    box.y1 += pDrawable->y; \
583    box.y2 += pDrawable->y; \
584    }
585
586#define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) { \
587    TRANSLATE_BOX(box, pDrawable); \
588    TRIM_BOX(box, pGC); \
589    }
590
591#define BOX_NOT_EMPTY(box) \
592    (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0))
593
594#define checkGCDamage(d,g)	(getDrawableDamage(d) && \
595				 (!g->pCompositeClip ||\
596				  RegionNotEmpty(g->pCompositeClip)))
597
598#define TRIM_PICTURE_BOX(box, pDst) { \
599    BoxPtr extents = &pDst->pCompositeClip->extents;\
600    if(box.x1 < extents->x1) box.x1 = extents->x1; \
601    if(box.x2 > extents->x2) box.x2 = extents->x2; \
602    if(box.y1 < extents->y1) box.y1 = extents->y1; \
603    if(box.y2 > extents->y2) box.y2 = extents->y2; \
604    }
605
606#define checkPictureDamage(p)	(getDrawableDamage(p->pDrawable) && \
607				 RegionNotEmpty(p->pCompositeClip))
608
609static void
610damageComposite (CARD8      op,
611		   PicturePtr pSrc,
612		   PicturePtr pMask,
613		   PicturePtr pDst,
614		   INT16      xSrc,
615		   INT16      ySrc,
616		   INT16      xMask,
617		   INT16      yMask,
618		   INT16      xDst,
619		   INT16      yDst,
620		   CARD16     width,
621		   CARD16     height)
622{
623    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
624    PictureScreenPtr	ps = GetPictureScreen(pScreen);
625    damageScrPriv(pScreen);
626
627    if (checkPictureDamage (pDst))
628    {
629	BoxRec	box;
630
631	box.x1 = xDst + pDst->pDrawable->x;
632	box.y1 = yDst + pDst->pDrawable->y;
633	box.x2 = box.x1 + width;
634	box.y2 = box.y1 + height;
635	TRIM_PICTURE_BOX(box, pDst);
636	if (BOX_NOT_EMPTY(box))
637	    damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode);
638    }
639    unwrap (pScrPriv, ps, Composite);
640    (*ps->Composite) (op,
641		       pSrc,
642		       pMask,
643		       pDst,
644		       xSrc,
645		       ySrc,
646		       xMask,
647		       yMask,
648		       xDst,
649		       yDst,
650		       width,
651		       height);
652    damageRegionProcessPending (pDst->pDrawable);
653    wrap (pScrPriv, ps, Composite, damageComposite);
654}
655
656static void
657damageGlyphs (CARD8		op,
658		PicturePtr	pSrc,
659		PicturePtr	pDst,
660		PictFormatPtr	maskFormat,
661		INT16		xSrc,
662		INT16		ySrc,
663		int		nlist,
664		GlyphListPtr	list,
665		GlyphPtr	*glyphs)
666{
667    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
668    PictureScreenPtr	ps = GetPictureScreen(pScreen);
669    damageScrPriv(pScreen);
670
671    if (checkPictureDamage (pDst))
672    {
673	int		nlistTmp = nlist;
674	GlyphListPtr	listTmp = list;
675	GlyphPtr	*glyphsTmp = glyphs;
676	int		x, y;
677	int		n;
678	GlyphPtr	glyph;
679	BoxRec		box;
680	int		x1, y1, x2, y2;
681
682	box.x1 = 32767;
683	box.y1 = 32767;
684	box.x2 = -32767;
685	box.y2 = -32767;
686	x = pDst->pDrawable->x;
687	y = pDst->pDrawable->y;
688	while (nlistTmp--)
689	{
690	    x += listTmp->xOff;
691	    y += listTmp->yOff;
692	    n = listTmp->len;
693	    while (n--)
694	    {
695		glyph = *glyphsTmp++;
696		x1 = x - glyph->info.x;
697		y1 = y - glyph->info.y;
698		x2 = x1 + glyph->info.width;
699		y2 = y1 + glyph->info.height;
700		if (x1 < box.x1)
701		    box.x1 = x1;
702		if (y1 < box.y1)
703		    box.y1 = y1;
704		if (x2 > box.x2)
705		    box.x2 = x2;
706		if (y2 > box.y2)
707		    box.y2 = y2;
708		x += glyph->info.xOff;
709		y += glyph->info.yOff;
710	    }
711	    listTmp++;
712	}
713	TRIM_PICTURE_BOX (box, pDst);
714	if (BOX_NOT_EMPTY(box))
715	    damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode);
716    }
717    unwrap (pScrPriv, ps, Glyphs);
718    (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
719    damageRegionProcessPending (pDst->pDrawable);
720    wrap (pScrPriv, ps, Glyphs, damageGlyphs);
721}
722
723static void
724damageAddTraps (PicturePtr  pPicture,
725		INT16	    x_off,
726		INT16	    y_off,
727		int	    ntrap,
728		xTrap	    *traps)
729{
730    ScreenPtr		pScreen = pPicture->pDrawable->pScreen;
731    PictureScreenPtr	ps = GetPictureScreen(pScreen);
732    damageScrPriv(pScreen);
733
734    if (checkPictureDamage (pPicture))
735    {
736	BoxRec	box;
737	int	i;
738	int	x, y;
739	xTrap	*t = traps;
740
741	box.x1 = 32767;
742	box.y1 = 32767;
743	box.x2 = -32767;
744	box.y2 = -32767;
745	x = pPicture->pDrawable->x + x_off;
746	y = pPicture->pDrawable->y + y_off;
747	for (i = 0; i < ntrap; i++)
748	{
749	    pixman_fixed_t   l = min (t->top.l, t->bot.l);
750	    pixman_fixed_t   r = max (t->top.r, t->bot.r);
751	    int	    x1 = x + pixman_fixed_to_int (l);
752	    int	    x2 = x + pixman_fixed_to_int (pixman_fixed_ceil (r));
753	    int	    y1 = y + pixman_fixed_to_int (t->top.y);
754	    int	    y2 = y + pixman_fixed_to_int (pixman_fixed_ceil (t->bot.y));
755
756	    if (x1 < box.x1)
757		box.x1 = x1;
758	    if (x2 > box.x2)
759		box.x2 = x2;
760	    if (y1 < box.y1)
761		box.y1 = y1;
762	    if (y2 > box.y2)
763		box.y2 = y2;
764	}
765	TRIM_PICTURE_BOX (box, pPicture);
766	if (BOX_NOT_EMPTY(box))
767	    damageDamageBox (pPicture->pDrawable, &box, pPicture->subWindowMode);
768    }
769    unwrap (pScrPriv, ps, AddTraps);
770    (*ps->AddTraps) (pPicture, x_off, y_off, ntrap, traps);
771    damageRegionProcessPending (pPicture->pDrawable);
772    wrap (pScrPriv, ps, AddTraps, damageAddTraps);
773}
774
775/**********************************************************/
776
777
778static void
779damageFillSpans(DrawablePtr pDrawable,
780		GC	    *pGC,
781		int	    npt,
782		DDXPointPtr ppt,
783		int	    *pwidth,
784		int	    fSorted)
785{
786    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
787
788    if (npt && checkGCDamage (pDrawable, pGC))
789    {
790	int	    nptTmp = npt;
791	DDXPointPtr pptTmp = ppt;
792	int	    *pwidthTmp = pwidth;
793	BoxRec	    box;
794
795	box.x1 = pptTmp->x;
796	box.x2 = box.x1 + *pwidthTmp;
797	box.y2 = box.y1 = pptTmp->y;
798
799	while(--nptTmp)
800	{
801	   pptTmp++;
802	   pwidthTmp++;
803	   if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
804	   if(box.x2 < (pptTmp->x + *pwidthTmp))
805		box.x2 = pptTmp->x + *pwidthTmp;
806	   if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
807	   else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
808	}
809
810	box.y2++;
811
812        if(!pGC->miTranslate) {
813           TRANSLATE_BOX(box, pDrawable);
814        }
815        TRIM_BOX(box, pGC);
816
817	if(BOX_NOT_EMPTY(box))
818	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
819    }
820
821    (*pGC->ops->FillSpans)(pDrawable, pGC, npt, ppt, pwidth, fSorted);
822
823    damageRegionProcessPending (pDrawable);
824    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
825}
826
827static void
828damageSetSpans(DrawablePtr  pDrawable,
829	       GCPtr	    pGC,
830	       char	    *pcharsrc,
831	       DDXPointPtr  ppt,
832	       int	    *pwidth,
833	       int	    npt,
834	       int	    fSorted)
835{
836    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
837
838    if (npt && checkGCDamage (pDrawable, pGC))
839    {
840	DDXPointPtr pptTmp = ppt;
841	int	    *pwidthTmp = pwidth;
842	int	    nptTmp = npt;
843	BoxRec	    box;
844
845	box.x1 = pptTmp->x;
846	box.x2 = box.x1 + *pwidthTmp;
847	box.y2 = box.y1 = pptTmp->y;
848
849	while(--nptTmp)
850	{
851	   pptTmp++;
852	   pwidthTmp++;
853	   if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
854	   if(box.x2 < (pptTmp->x + *pwidthTmp))
855		box.x2 = pptTmp->x + *pwidthTmp;
856	   if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
857	   else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
858	}
859
860	box.y2++;
861
862        if(!pGC->miTranslate) {
863           TRANSLATE_BOX(box, pDrawable);
864        }
865        TRIM_BOX(box, pGC);
866
867	if(BOX_NOT_EMPTY(box))
868	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
869    }
870    (*pGC->ops->SetSpans)(pDrawable, pGC, pcharsrc, ppt, pwidth, npt, fSorted);
871    damageRegionProcessPending (pDrawable);
872    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
873}
874
875static void
876damagePutImage(DrawablePtr  pDrawable,
877	       GCPtr	    pGC,
878	       int	    depth,
879	       int	    x,
880	       int	    y,
881	       int	    w,
882	       int	    h,
883	       int	    leftPad,
884	       int	    format,
885	       char	    *pImage)
886{
887    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
888    if (checkGCDamage (pDrawable, pGC))
889    {
890	BoxRec box;
891
892	box.x1 = x + pDrawable->x;
893	box.x2 = box.x1 + w;
894	box.y1 = y + pDrawable->y;
895	box.y2 = box.y1 + h;
896
897	TRIM_BOX(box, pGC);
898	if(BOX_NOT_EMPTY(box))
899	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
900    }
901    (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
902		leftPad, format, pImage);
903    damageRegionProcessPending (pDrawable);
904    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
905}
906
907static RegionPtr
908damageCopyArea(DrawablePtr   pSrc,
909	       DrawablePtr  pDst,
910	       GC	    *pGC,
911	       int	    srcx,
912	       int	    srcy,
913	       int	    width,
914	       int	    height,
915	       int	    dstx,
916	       int	    dsty)
917{
918    RegionPtr ret;
919    DAMAGE_GC_OP_PROLOGUE(pGC, pDst);
920
921    /* The driver will only call SourceValidate() when pSrc != pDst,
922     * but the software sprite (misprite.c) always need to know when a
923     * drawable is copied so it can remove the sprite. See #1030. */
924    if ((pSrc == pDst) && pSrc->pScreen->SourceValidate &&
925	pSrc->type == DRAWABLE_WINDOW &&
926	((WindowPtr)pSrc)->viewable)
927    {
928	(*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height);
929    }
930
931    if (checkGCDamage (pDst, pGC))
932    {
933	BoxRec box;
934
935	box.x1 = dstx + pDst->x;
936	box.x2 = box.x1 + width;
937	box.y1 = dsty + pDst->y;
938	box.y2 = box.y1 + height;
939
940	TRIM_BOX(box, pGC);
941	if(BOX_NOT_EMPTY(box))
942	   damageDamageBox (pDst, &box, pGC->subWindowMode);
943    }
944
945    ret = (*pGC->ops->CopyArea)(pSrc, pDst,
946            pGC, srcx, srcy, width, height, dstx, dsty);
947    damageRegionProcessPending (pDst);
948    DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
949    return ret;
950}
951
952static RegionPtr
953damageCopyPlane(DrawablePtr	pSrc,
954		DrawablePtr	pDst,
955		GCPtr		pGC,
956		int		srcx,
957		int		srcy,
958		int		width,
959		int		height,
960		int		dstx,
961		int		dsty,
962		unsigned long	bitPlane)
963{
964    RegionPtr ret;
965    DAMAGE_GC_OP_PROLOGUE(pGC, pDst);
966
967    /* The driver will only call SourceValidate() when pSrc != pDst,
968     * but the software sprite (misprite.c) always need to know when a
969     * drawable is copied so it can remove the sprite. See #1030. */
970    if ((pSrc == pDst) && pSrc->pScreen->SourceValidate &&
971	pSrc->type == DRAWABLE_WINDOW &&
972	((WindowPtr)pSrc)->viewable)
973    {
974        (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height);
975    }
976
977    if (checkGCDamage (pDst, pGC))
978    {
979	BoxRec box;
980
981	box.x1 = dstx + pDst->x;
982	box.x2 = box.x1 + width;
983	box.y1 = dsty + pDst->y;
984	box.y2 = box.y1 + height;
985
986	TRIM_BOX(box, pGC);
987	if(BOX_NOT_EMPTY(box))
988	   damageDamageBox (pDst, &box, pGC->subWindowMode);
989    }
990
991    ret = (*pGC->ops->CopyPlane)(pSrc, pDst,
992	       pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
993    damageRegionProcessPending (pDst);
994    DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
995    return ret;
996}
997
998static void
999damagePolyPoint(DrawablePtr pDrawable,
1000		GCPtr	    pGC,
1001		int	    mode,
1002		int	    npt,
1003		xPoint	    *ppt)
1004{
1005    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1006
1007    if (npt && checkGCDamage (pDrawable, pGC))
1008    {
1009	BoxRec	box;
1010	int	nptTmp = npt;
1011	xPoint	*pptTmp = ppt;
1012
1013	box.x2 = box.x1 = pptTmp->x;
1014	box.y2 = box.y1 = pptTmp->y;
1015
1016	/* this could be slow if the points were spread out */
1017
1018	while(--nptTmp)
1019	{
1020	   pptTmp++;
1021	   if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
1022	   else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
1023	   if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
1024	   else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
1025	}
1026
1027	box.x2++;
1028	box.y2++;
1029
1030	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1031	if(BOX_NOT_EMPTY(box))
1032	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1033    }
1034    (*pGC->ops->PolyPoint)(pDrawable, pGC, mode, npt, ppt);
1035    damageRegionProcessPending (pDrawable);
1036    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1037}
1038
1039static void
1040damagePolylines(DrawablePtr pDrawable,
1041		GCPtr	    pGC,
1042		int	    mode,
1043		int	    npt,
1044		DDXPointPtr ppt)
1045{
1046    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1047
1048    if (npt && checkGCDamage (pDrawable, pGC))
1049    {
1050	int	    nptTmp = npt;
1051	DDXPointPtr pptTmp = ppt;
1052	BoxRec	    box;
1053	int	    extra = pGC->lineWidth >> 1;
1054
1055	box.x2 = box.x1 = pptTmp->x;
1056	box.y2 = box.y1 = pptTmp->y;
1057
1058	if(nptTmp > 1)
1059	{
1060	   if(pGC->joinStyle == JoinMiter)
1061		extra = 6 * pGC->lineWidth;
1062	   else if(pGC->capStyle == CapProjecting)
1063		extra = pGC->lineWidth;
1064        }
1065
1066	if(mode == CoordModePrevious)
1067	{
1068	   int x = box.x1;
1069	   int y = box.y1;
1070	   while(--nptTmp)
1071	   {
1072		pptTmp++;
1073		x += pptTmp->x;
1074		y += pptTmp->y;
1075		if(box.x1 > x) box.x1 = x;
1076		else if(box.x2 < x) box.x2 = x;
1077		if(box.y1 > y) box.y1 = y;
1078		else if(box.y2 < y) box.y2 = y;
1079	    }
1080	}
1081	else
1082	{
1083	   while(--nptTmp)
1084	   {
1085		pptTmp++;
1086		if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
1087		else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
1088		if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
1089		else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
1090	    }
1091	}
1092
1093	box.x2++;
1094	box.y2++;
1095
1096	if(extra)
1097	{
1098	   box.x1 -= extra;
1099	   box.x2 += extra;
1100	   box.y1 -= extra;
1101	   box.y2 += extra;
1102        }
1103
1104	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1105	if(BOX_NOT_EMPTY(box))
1106	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1107    }
1108    (*pGC->ops->Polylines)(pDrawable, pGC, mode, npt, ppt);
1109    damageRegionProcessPending (pDrawable);
1110    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1111}
1112
1113static void
1114damagePolySegment(DrawablePtr	pDrawable,
1115		  GCPtr		pGC,
1116		  int		nSeg,
1117		  xSegment	*pSeg)
1118{
1119    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1120
1121    if (nSeg && checkGCDamage (pDrawable, pGC))
1122    {
1123	BoxRec	    box;
1124	int	    extra = pGC->lineWidth;
1125	int	    nsegTmp = nSeg;
1126	xSegment    *pSegTmp = pSeg;
1127
1128        if(pGC->capStyle != CapProjecting)
1129	   extra >>= 1;
1130
1131	if(pSegTmp->x2 > pSegTmp->x1) {
1132	    box.x1 = pSegTmp->x1;
1133	    box.x2 = pSegTmp->x2;
1134	} else {
1135	    box.x2 = pSegTmp->x1;
1136	    box.x1 = pSegTmp->x2;
1137	}
1138
1139	if(pSegTmp->y2 > pSegTmp->y1) {
1140	    box.y1 = pSegTmp->y1;
1141	    box.y2 = pSegTmp->y2;
1142	} else {
1143	    box.y2 = pSegTmp->y1;
1144	    box.y1 = pSegTmp->y2;
1145	}
1146
1147	while(--nsegTmp)
1148	{
1149	    pSegTmp++;
1150	    if(pSegTmp->x2 > pSegTmp->x1)
1151	    {
1152		if(pSegTmp->x1 < box.x1) box.x1 = pSegTmp->x1;
1153		if(pSegTmp->x2 > box.x2) box.x2 = pSegTmp->x2;
1154	    }
1155	    else
1156	    {
1157		if(pSegTmp->x2 < box.x1) box.x1 = pSegTmp->x2;
1158		if(pSegTmp->x1 > box.x2) box.x2 = pSegTmp->x1;
1159	    }
1160	    if(pSegTmp->y2 > pSegTmp->y1)
1161	    {
1162		if(pSegTmp->y1 < box.y1) box.y1 = pSegTmp->y1;
1163		if(pSegTmp->y2 > box.y2) box.y2 = pSegTmp->y2;
1164	    }
1165	    else
1166	    {
1167		if(pSegTmp->y2 < box.y1) box.y1 = pSegTmp->y2;
1168		if(pSegTmp->y1 > box.y2) box.y2 = pSegTmp->y1;
1169	    }
1170	}
1171
1172	box.x2++;
1173	box.y2++;
1174
1175	if(extra)
1176	{
1177	   box.x1 -= extra;
1178	   box.x2 += extra;
1179	   box.y1 -= extra;
1180	   box.y2 += extra;
1181        }
1182
1183	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1184	if(BOX_NOT_EMPTY(box))
1185	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1186    }
1187    (*pGC->ops->PolySegment)(pDrawable, pGC, nSeg, pSeg);
1188    damageRegionProcessPending (pDrawable);
1189    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1190}
1191
1192static void
1193damagePolyRectangle(DrawablePtr  pDrawable,
1194		    GCPtr        pGC,
1195		    int	         nRects,
1196		    xRectangle  *pRects)
1197{
1198    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1199
1200    if (nRects && checkGCDamage (pDrawable, pGC))
1201    {
1202	BoxRec	    box;
1203	int	    offset1, offset2, offset3;
1204	int	    nRectsTmp = nRects;
1205	xRectangle  *pRectsTmp = pRects;
1206
1207	offset2 = pGC->lineWidth;
1208	if(!offset2) offset2 = 1;
1209	offset1 = offset2 >> 1;
1210	offset3 = offset2 - offset1;
1211
1212	while(nRectsTmp--)
1213	{
1214	    box.x1 = pRectsTmp->x - offset1;
1215	    box.y1 = pRectsTmp->y - offset1;
1216	    box.x2 = box.x1 + pRectsTmp->width + offset2;
1217	    box.y2 = box.y1 + offset2;
1218	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1219	    if(BOX_NOT_EMPTY(box))
1220		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1221
1222	    box.x1 = pRectsTmp->x - offset1;
1223	    box.y1 = pRectsTmp->y + offset3;
1224	    box.x2 = box.x1 + offset2;
1225	    box.y2 = box.y1 + pRectsTmp->height - offset2;
1226	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1227	    if(BOX_NOT_EMPTY(box))
1228		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1229
1230	    box.x1 = pRectsTmp->x + pRectsTmp->width - offset1;
1231	    box.y1 = pRectsTmp->y + offset3;
1232	    box.x2 = box.x1 + offset2;
1233	    box.y2 = box.y1 + pRectsTmp->height - offset2;
1234	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1235	    if(BOX_NOT_EMPTY(box))
1236		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1237
1238	    box.x1 = pRectsTmp->x - offset1;
1239	    box.y1 = pRectsTmp->y + pRectsTmp->height - offset1;
1240	    box.x2 = box.x1 + pRectsTmp->width + offset2;
1241	    box.y2 = box.y1 + offset2;
1242	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1243	    if(BOX_NOT_EMPTY(box))
1244		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1245
1246	    pRectsTmp++;
1247	}
1248    }
1249    (*pGC->ops->PolyRectangle)(pDrawable, pGC, nRects, pRects);
1250    damageRegionProcessPending (pDrawable);
1251    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1252}
1253
1254static void
1255damagePolyArc(DrawablePtr   pDrawable,
1256	      GCPtr	    pGC,
1257	      int	    nArcs,
1258	      xArc	    *pArcs)
1259{
1260    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1261
1262    if (nArcs && checkGCDamage (pDrawable, pGC))
1263    {
1264	int	extra = pGC->lineWidth >> 1;
1265	BoxRec	box;
1266	int	nArcsTmp = nArcs;
1267	xArc	*pArcsTmp = pArcs;
1268
1269	box.x1 = pArcsTmp->x;
1270	box.x2 = box.x1 + pArcsTmp->width;
1271	box.y1 = pArcsTmp->y;
1272	box.y2 = box.y1 + pArcsTmp->height;
1273
1274	while(--nArcsTmp)
1275	{
1276	    pArcsTmp++;
1277	    if(box.x1 > pArcsTmp->x)
1278		box.x1 = pArcsTmp->x;
1279	    if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
1280		box.x2 = pArcsTmp->x + pArcsTmp->width;
1281	    if(box.y1 > pArcsTmp->y)
1282		box.y1 = pArcsTmp->y;
1283	    if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
1284		box.y2 = pArcsTmp->y + pArcsTmp->height;
1285        }
1286
1287	if(extra)
1288	{
1289	   box.x1 -= extra;
1290	   box.x2 += extra;
1291	   box.y1 -= extra;
1292	   box.y2 += extra;
1293        }
1294
1295	box.x2++;
1296	box.y2++;
1297
1298	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1299	if(BOX_NOT_EMPTY(box))
1300	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1301    }
1302    (*pGC->ops->PolyArc)(pDrawable, pGC, nArcs, pArcs);
1303    damageRegionProcessPending (pDrawable);
1304    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1305}
1306
1307static void
1308damageFillPolygon(DrawablePtr	pDrawable,
1309		  GCPtr		pGC,
1310		  int		shape,
1311		  int		mode,
1312		  int		npt,
1313		  DDXPointPtr	ppt)
1314{
1315    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1316
1317    if (npt > 2 && checkGCDamage (pDrawable, pGC))
1318    {
1319	DDXPointPtr pptTmp = ppt;
1320	int	    nptTmp = npt;
1321	BoxRec	    box;
1322
1323	box.x2 = box.x1 = pptTmp->x;
1324	box.y2 = box.y1 = pptTmp->y;
1325
1326	if(mode != CoordModeOrigin)
1327	{
1328	   int x = box.x1;
1329	   int y = box.y1;
1330	   while(--nptTmp)
1331	   {
1332		pptTmp++;
1333		x += pptTmp->x;
1334		y += pptTmp->y;
1335		if(box.x1 > x) box.x1 = x;
1336		else if(box.x2 < x) box.x2 = x;
1337		if(box.y1 > y) box.y1 = y;
1338		else if(box.y2 < y) box.y2 = y;
1339	    }
1340	}
1341	else
1342	{
1343	   while(--nptTmp)
1344	   {
1345		pptTmp++;
1346		if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
1347		else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
1348		if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
1349		else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
1350	    }
1351	}
1352
1353	box.x2++;
1354	box.y2++;
1355
1356	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1357	if(BOX_NOT_EMPTY(box))
1358	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1359    }
1360
1361    (*pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, npt, ppt);
1362    damageRegionProcessPending (pDrawable);
1363    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1364}
1365
1366
1367static void
1368damagePolyFillRect(DrawablePtr	pDrawable,
1369		   GCPtr	pGC,
1370		   int		nRects,
1371		   xRectangle	*pRects)
1372{
1373    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1374    if (nRects && checkGCDamage (pDrawable, pGC))
1375    {
1376	BoxRec	    box;
1377	xRectangle  *pRectsTmp = pRects;
1378	int	    nRectsTmp = nRects;
1379
1380	box.x1 = pRectsTmp->x;
1381	box.x2 = box.x1 + pRectsTmp->width;
1382	box.y1 = pRectsTmp->y;
1383	box.y2 = box.y1 + pRectsTmp->height;
1384
1385	while(--nRectsTmp)
1386	{
1387	    pRectsTmp++;
1388	    if(box.x1 > pRectsTmp->x) box.x1 = pRectsTmp->x;
1389	    if(box.x2 < (pRectsTmp->x + pRectsTmp->width))
1390		box.x2 = pRectsTmp->x + pRectsTmp->width;
1391	    if(box.y1 > pRectsTmp->y) box.y1 = pRectsTmp->y;
1392	    if(box.y2 < (pRectsTmp->y + pRectsTmp->height))
1393		box.y2 = pRectsTmp->y + pRectsTmp->height;
1394	}
1395
1396	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1397	if(BOX_NOT_EMPTY(box))
1398	    damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1399    }
1400    (*pGC->ops->PolyFillRect)(pDrawable, pGC, nRects, pRects);
1401    damageRegionProcessPending (pDrawable);
1402    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1403}
1404
1405
1406static void
1407damagePolyFillArc(DrawablePtr	pDrawable,
1408		  GCPtr		pGC,
1409		  int		nArcs,
1410		  xArc		*pArcs)
1411{
1412    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1413
1414    if (nArcs && checkGCDamage (pDrawable, pGC))
1415    {
1416	BoxRec	box;
1417	int	nArcsTmp = nArcs;
1418	xArc	*pArcsTmp = pArcs;
1419
1420	box.x1 = pArcsTmp->x;
1421	box.x2 = box.x1 + pArcsTmp->width;
1422	box.y1 = pArcsTmp->y;
1423	box.y2 = box.y1 + pArcsTmp->height;
1424
1425	while(--nArcsTmp)
1426	{
1427	    pArcsTmp++;
1428	    if(box.x1 > pArcsTmp->x)
1429		box.x1 = pArcsTmp->x;
1430	    if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
1431		box.x2 = pArcsTmp->x + pArcsTmp->width;
1432	    if(box.y1 > pArcsTmp->y)
1433		box.y1 = pArcsTmp->y;
1434	    if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
1435		box.y2 = pArcsTmp->y + pArcsTmp->height;
1436        }
1437
1438	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1439	if(BOX_NOT_EMPTY(box))
1440	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1441    }
1442    (*pGC->ops->PolyFillArc)(pDrawable, pGC, nArcs, pArcs);
1443    damageRegionProcessPending (pDrawable);
1444    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1445}
1446
1447/*
1448 * general Poly/Image text function.  Extract glyph information,
1449 * compute bounding box and remove cursor if it is overlapped.
1450 */
1451
1452static void
1453damageDamageChars (DrawablePtr	pDrawable,
1454		   FontPtr	font,
1455		   int		x,
1456		   int		y,
1457		   unsigned int	n,
1458		   CharInfoPtr	*charinfo,
1459		   Bool		imageblt,
1460		   int		subWindowMode)
1461{
1462    ExtentInfoRec   extents;
1463    BoxRec	    box;
1464
1465    QueryGlyphExtents(font, charinfo, n, &extents);
1466    if (imageblt)
1467    {
1468	if (extents.overallWidth > extents.overallRight)
1469	    extents.overallRight = extents.overallWidth;
1470	if (extents.overallWidth < extents.overallLeft)
1471	    extents.overallLeft = extents.overallWidth;
1472	if (extents.overallLeft > 0)
1473	    extents.overallLeft = 0;
1474	if (extents.fontAscent > extents.overallAscent)
1475	    extents.overallAscent = extents.fontAscent;
1476	if (extents.fontDescent > extents.overallDescent)
1477	    extents.overallDescent = extents.fontDescent;
1478    }
1479    box.x1 = x + extents.overallLeft;
1480    box.y1 = y - extents.overallAscent;
1481    box.x2 = x + extents.overallRight;
1482    box.y2 = y + extents.overallDescent;
1483    damageDamageBox (pDrawable, &box, subWindowMode);
1484}
1485
1486/*
1487 * values for textType:
1488 */
1489#define TT_POLY8   0
1490#define TT_IMAGE8  1
1491#define TT_POLY16  2
1492#define TT_IMAGE16 3
1493
1494static int
1495damageText (DrawablePtr	    pDrawable,
1496	    GCPtr	    pGC,
1497	    int		    x,
1498	    int		    y,
1499	    unsigned long   count,
1500	    char	    *chars,
1501	    FontEncoding    fontEncoding,
1502	    Bool	    textType)
1503{
1504    CharInfoPtr	    *charinfo;
1505    CharInfoPtr	    *info;
1506    unsigned long   i;
1507    unsigned int    n;
1508    int		    w;
1509    Bool	    imageblt;
1510
1511    imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16);
1512
1513    charinfo = malloc(count * sizeof(CharInfoPtr));
1514    if (!charinfo)
1515	return x;
1516
1517    GetGlyphs(pGC->font, count, (unsigned char *)chars,
1518	      fontEncoding, &i, charinfo);
1519    n = (unsigned int)i;
1520    w = 0;
1521    if (!imageblt)
1522	for (info = charinfo; i--; info++)
1523	    w += (*info)->metrics.characterWidth;
1524
1525    if (n != 0) {
1526	damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n,
1527			   charinfo, imageblt, pGC->subWindowMode);
1528	if (imageblt)
1529	    (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo,
1530				       FONTGLYPHS(pGC->font));
1531	else
1532	    (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo,
1533				      FONTGLYPHS(pGC->font));
1534    }
1535    free(charinfo);
1536    return x + w;
1537}
1538
1539static int
1540damagePolyText8(DrawablePtr pDrawable,
1541		GCPtr	    pGC,
1542		int	    x,
1543		int	    y,
1544		int	    count,
1545		char	    *chars)
1546{
1547    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1548
1549    if (checkGCDamage (pDrawable, pGC))
1550	x = damageText (pDrawable, pGC, x, y, (unsigned long) count, chars,
1551		    Linear8Bit, TT_POLY8);
1552    else
1553	x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars);
1554    damageRegionProcessPending (pDrawable);
1555    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1556    return x;
1557}
1558
1559static int
1560damagePolyText16(DrawablePtr	pDrawable,
1561		 GCPtr		pGC,
1562		 int		x,
1563		 int		y,
1564		 int		count,
1565		 unsigned short	*chars)
1566{
1567    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1568
1569    if (checkGCDamage (pDrawable, pGC))
1570	x = damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
1571		    FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
1572		    TT_POLY16);
1573    else
1574	x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars);
1575    damageRegionProcessPending (pDrawable);
1576    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1577    return x;
1578}
1579
1580static void
1581damageImageText8(DrawablePtr	pDrawable,
1582		 GCPtr		pGC,
1583		 int		x,
1584		 int		y,
1585		 int		count,
1586		 char		*chars)
1587{
1588    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1589
1590    if (checkGCDamage (pDrawable, pGC))
1591	damageText (pDrawable, pGC, x, y, (unsigned long) count, chars,
1592		    Linear8Bit, TT_IMAGE8);
1593    else
1594	(*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars);
1595    damageRegionProcessPending (pDrawable);
1596    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1597}
1598
1599static void
1600damageImageText16(DrawablePtr	pDrawable,
1601		  GCPtr		pGC,
1602		  int		x,
1603		  int		y,
1604		  int		count,
1605		  unsigned short *chars)
1606{
1607    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1608
1609    if (checkGCDamage (pDrawable, pGC))
1610	damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
1611		    FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
1612		    TT_IMAGE16);
1613    else
1614	(*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars);
1615    damageRegionProcessPending (pDrawable);
1616    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1617}
1618
1619
1620static void
1621damageImageGlyphBlt(DrawablePtr	    pDrawable,
1622		    GCPtr	    pGC,
1623		    int		    x,
1624		    int		    y,
1625		    unsigned int    nglyph,
1626		    CharInfoPtr	    *ppci,
1627		    pointer	    pglyphBase)
1628{
1629    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1630    damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
1631		       nglyph, ppci, TRUE, pGC->subWindowMode);
1632    (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph,
1633					ppci, pglyphBase);
1634    damageRegionProcessPending (pDrawable);
1635    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1636}
1637
1638static void
1639damagePolyGlyphBlt(DrawablePtr	pDrawable,
1640		   GCPtr	pGC,
1641		   int		x,
1642		   int		y,
1643		   unsigned int	nglyph,
1644		   CharInfoPtr	*ppci,
1645		   pointer	pglyphBase)
1646{
1647    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1648    damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
1649		       nglyph, ppci, FALSE, pGC->subWindowMode);
1650    (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph,
1651				ppci, pglyphBase);
1652    damageRegionProcessPending (pDrawable);
1653    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1654}
1655
1656static void
1657damagePushPixels(GCPtr		pGC,
1658		 PixmapPtr	pBitMap,
1659		 DrawablePtr	pDrawable,
1660		 int		dx,
1661		 int		dy,
1662		 int		xOrg,
1663		 int		yOrg)
1664{
1665    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1666    if(checkGCDamage (pDrawable, pGC))
1667    {
1668	BoxRec box;
1669
1670        box.x1 = xOrg;
1671        box.y1 = yOrg;
1672
1673        if(!pGC->miTranslate) {
1674           box.x1 += pDrawable->x;
1675           box.y1 += pDrawable->y;
1676        }
1677
1678	box.x2 = box.x1 + dx;
1679	box.y2 = box.y1 + dy;
1680
1681	TRIM_BOX(box, pGC);
1682	if(BOX_NOT_EMPTY(box))
1683	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1684    }
1685    (*pGC->ops->PushPixels)(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg);
1686    damageRegionProcessPending (pDrawable);
1687    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1688}
1689
1690static void
1691damageRemoveDamage (DamagePtr *pPrev, DamagePtr pDamage)
1692{
1693    while (*pPrev)
1694    {
1695	if (*pPrev == pDamage)
1696	{
1697	    *pPrev = pDamage->pNext;
1698	    return;
1699	}
1700	pPrev = &(*pPrev)->pNext;
1701    }
1702#if DAMAGE_VALIDATE_ENABLE
1703    ErrorF ("Damage not on list\n");
1704    OsAbort ();
1705#endif
1706}
1707
1708static void
1709damageInsertDamage (DamagePtr *pPrev, DamagePtr pDamage)
1710{
1711#if DAMAGE_VALIDATE_ENABLE
1712    DamagePtr	pOld;
1713
1714    for (pOld = *pPrev; pOld; pOld = pOld->pNext)
1715	if (pOld == pDamage) {
1716	    ErrorF ("Damage already on list\n");
1717	    OsAbort ();
1718	}
1719#endif
1720    pDamage->pNext = *pPrev;
1721    *pPrev = pDamage;
1722}
1723
1724static Bool
1725damageDestroyPixmap (PixmapPtr pPixmap)
1726{
1727    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
1728    damageScrPriv(pScreen);
1729
1730    if (pPixmap->refcnt == 1)
1731    {
1732	DamagePtr	*pPrev = getPixmapDamageRef (pPixmap);
1733	DamagePtr	pDamage;
1734
1735	while ((pDamage = *pPrev))
1736	{
1737	    damageRemoveDamage (pPrev, pDamage);
1738	    if (!pDamage->isWindow)
1739		DamageDestroy (pDamage);
1740	}
1741    }
1742    unwrap (pScrPriv, pScreen, DestroyPixmap);
1743    (*pScreen->DestroyPixmap) (pPixmap);
1744    wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap);
1745    return TRUE;
1746}
1747
1748static void
1749damageCopyWindow(WindowPtr	pWindow,
1750		 DDXPointRec	ptOldOrg,
1751		 RegionPtr	prgnSrc)
1752{
1753    ScreenPtr pScreen = pWindow->drawable.pScreen;
1754    damageScrPriv(pScreen);
1755
1756    if (getWindowDamage (pWindow))
1757    {
1758	int dx = pWindow->drawable.x - ptOldOrg.x;
1759	int dy = pWindow->drawable.y - ptOldOrg.y;
1760
1761	/*
1762	 * The region comes in source relative, but the damage occurs
1763	 * at the destination location.  Translate back and forth.
1764	 */
1765	RegionTranslate(prgnSrc, dx, dy);
1766	damageRegionAppend (&pWindow->drawable, prgnSrc, FALSE, -1);
1767	RegionTranslate(prgnSrc, -dx, -dy);
1768    }
1769    unwrap (pScrPriv, pScreen, CopyWindow);
1770    (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
1771    damageRegionProcessPending (&pWindow->drawable);
1772    wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow);
1773}
1774
1775static GCOps damageGCOps = {
1776    damageFillSpans, damageSetSpans,
1777    damagePutImage, damageCopyArea,
1778    damageCopyPlane, damagePolyPoint,
1779    damagePolylines, damagePolySegment,
1780    damagePolyRectangle, damagePolyArc,
1781    damageFillPolygon, damagePolyFillRect,
1782    damagePolyFillArc, damagePolyText8,
1783    damagePolyText16, damageImageText8,
1784    damageImageText16, damageImageGlyphBlt,
1785    damagePolyGlyphBlt, damagePushPixels,
1786    {NULL}		/* devPrivate */
1787};
1788
1789static void
1790damageSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
1791{
1792    DamagePtr	pDamage;
1793    ScreenPtr	pScreen = pWindow->drawable.pScreen;
1794    damageScrPriv(pScreen);
1795
1796    if ((pDamage = damageGetWinPriv(pWindow)))
1797    {
1798	PixmapPtr   pOldPixmap = (*pScreen->GetWindowPixmap) (pWindow);
1799	DamagePtr   *pPrev = getPixmapDamageRef(pOldPixmap);
1800
1801	while (pDamage)
1802	{
1803	    damageRemoveDamage (pPrev, pDamage);
1804	    pDamage = pDamage->pNextWin;
1805	}
1806    }
1807    unwrap (pScrPriv, pScreen, SetWindowPixmap);
1808    (*pScreen->SetWindowPixmap) (pWindow, pPixmap);
1809    wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap);
1810    if ((pDamage = damageGetWinPriv(pWindow)))
1811    {
1812	DamagePtr   *pPrev = getPixmapDamageRef(pPixmap);
1813
1814	while (pDamage)
1815	{
1816	    damageInsertDamage (pPrev, pDamage);
1817	    pDamage = pDamage->pNextWin;
1818	}
1819    }
1820}
1821
1822static Bool
1823damageDestroyWindow (WindowPtr pWindow)
1824{
1825    DamagePtr	pDamage;
1826    ScreenPtr	pScreen = pWindow->drawable.pScreen;
1827    Bool	ret;
1828    damageScrPriv(pScreen);
1829
1830    while ((pDamage = damageGetWinPriv(pWindow)))
1831    {
1832	DamageUnregister (&pWindow->drawable, pDamage);
1833	DamageDestroy (pDamage);
1834    }
1835    unwrap (pScrPriv, pScreen, DestroyWindow);
1836    ret = (*pScreen->DestroyWindow) (pWindow);
1837    wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow);
1838    return ret;
1839}
1840
1841static Bool
1842damageCloseScreen (int i, ScreenPtr pScreen)
1843{
1844    damageScrPriv(pScreen);
1845
1846    unwrap (pScrPriv, pScreen, DestroyPixmap);
1847    unwrap (pScrPriv, pScreen, CreateGC);
1848    unwrap (pScrPriv, pScreen, CopyWindow);
1849    unwrap (pScrPriv, pScreen, CloseScreen);
1850    free(pScrPriv);
1851    return (*pScreen->CloseScreen) (i, pScreen);
1852}
1853
1854/**
1855 * Default implementations of the damage management functions.
1856 */
1857void miDamageCreate (DamagePtr pDamage)
1858{
1859}
1860
1861void miDamageRegister (DrawablePtr pDrawable, DamagePtr pDamage)
1862{
1863}
1864
1865void miDamageUnregister (DrawablePtr pDrawable, DamagePtr pDamage)
1866{
1867}
1868
1869void miDamageDestroy (DamagePtr pDamage)
1870{
1871}
1872
1873/**
1874 * Public functions for consumption outside this file.
1875 */
1876
1877Bool
1878DamageSetup (ScreenPtr pScreen)
1879{
1880    DamageScrPrivPtr	pScrPriv;
1881    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
1882    const DamageScreenFuncsRec miFuncs = {
1883	miDamageCreate, miDamageRegister, miDamageUnregister, miDamageDestroy
1884    };
1885
1886    if (!dixRegisterPrivateKey(&damageScrPrivateKeyRec, PRIVATE_SCREEN, 0))
1887	return FALSE;
1888
1889    if (dixLookupPrivate(&pScreen->devPrivates, damageScrPrivateKey))
1890	return TRUE;
1891
1892    if (!dixRegisterPrivateKey(&damageGCPrivateKeyRec, PRIVATE_GC, sizeof(DamageGCPrivRec)))
1893	return FALSE;
1894
1895    if (!dixRegisterPrivateKey(&damagePixPrivateKeyRec, PRIVATE_PIXMAP, 0))
1896	return FALSE;
1897
1898    if (!dixRegisterPrivateKey(&damageWinPrivateKeyRec, PRIVATE_WINDOW, 0))
1899	return FALSE;
1900
1901    pScrPriv = malloc(sizeof (DamageScrPrivRec));
1902    if (!pScrPriv)
1903	return FALSE;
1904
1905    pScrPriv->internalLevel = 0;
1906    pScrPriv->pScreenDamage = 0;
1907
1908    wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap);
1909    wrap (pScrPriv, pScreen, CreateGC, damageCreateGC);
1910    wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow);
1911    wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap);
1912    wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow);
1913    wrap (pScrPriv, pScreen, CloseScreen, damageCloseScreen);
1914    if (ps) {
1915	wrap (pScrPriv, ps, Glyphs, damageGlyphs);
1916	wrap (pScrPriv, ps, Composite, damageComposite);
1917	wrap (pScrPriv, ps, AddTraps, damageAddTraps);
1918    }
1919
1920    pScrPriv->funcs = miFuncs;
1921
1922    dixSetPrivate(&pScreen->devPrivates, damageScrPrivateKey, pScrPriv);
1923    return TRUE;
1924}
1925
1926DamagePtr
1927DamageCreate (DamageReportFunc  damageReport,
1928	      DamageDestroyFunc	damageDestroy,
1929	      DamageReportLevel	damageLevel,
1930	      Bool		isInternal,
1931	      ScreenPtr		pScreen,
1932	      void		*closure)
1933{
1934    damageScrPriv(pScreen);
1935    DamagePtr	pDamage;
1936
1937    pDamage = dixAllocateObjectWithPrivates(DamageRec, PRIVATE_DAMAGE);
1938    if (!pDamage)
1939	return 0;
1940    pDamage->pNext = 0;
1941    pDamage->pNextWin = 0;
1942    RegionNull(&pDamage->damage);
1943    RegionNull(&pDamage->pendingDamage);
1944
1945    pDamage->damageLevel = damageLevel;
1946    pDamage->isInternal = isInternal;
1947    pDamage->closure = closure;
1948    pDamage->isWindow = FALSE;
1949    pDamage->pDrawable = 0;
1950    pDamage->reportAfter = FALSE;
1951
1952    pDamage->damageReport = damageReport;
1953    pDamage->damageReportPostRendering = NULL;
1954    pDamage->damageDestroy = damageDestroy;
1955    pDamage->damageMarker = NULL;
1956    pDamage->pScreen = pScreen;
1957
1958    (*pScrPriv->funcs.Create) (pDamage);
1959
1960    return pDamage;
1961}
1962
1963void
1964DamageRegister (DrawablePtr pDrawable,
1965		DamagePtr   pDamage)
1966{
1967    ScreenPtr pScreen = pDrawable->pScreen;
1968    damageScrPriv(pScreen);
1969
1970#if DAMAGE_VALIDATE_ENABLE
1971    if (pDrawable->pScreen != pDamage->pScreen)
1972    {
1973	ErrorF ("DamageRegister called with mismatched screens\n");
1974	OsAbort ();
1975    }
1976#endif
1977
1978    if (pDrawable->type == DRAWABLE_WINDOW)
1979    {
1980	WindowPtr   pWindow = (WindowPtr) pDrawable;
1981	winDamageRef(pWindow);
1982
1983#if DAMAGE_VALIDATE_ENABLE
1984	DamagePtr   pOld;
1985
1986	for (pOld = *pPrev; pOld; pOld = pOld->pNextWin)
1987	    if (pOld == pDamage) {
1988		ErrorF ("Damage already on window list\n");
1989		OsAbort ();
1990	    }
1991#endif
1992	pDamage->pNextWin = *pPrev;
1993	*pPrev = pDamage;
1994	pDamage->isWindow = TRUE;
1995    }
1996    else
1997	pDamage->isWindow = FALSE;
1998    pDamage->pDrawable = pDrawable;
1999    damageInsertDamage (getDrawableDamageRef (pDrawable), pDamage);
2000    (*pScrPriv->funcs.Register) (pDrawable, pDamage);
2001}
2002
2003void
2004DamageDrawInternal (ScreenPtr pScreen, Bool enable)
2005{
2006    damageScrPriv (pScreen);
2007
2008    pScrPriv->internalLevel += enable ? 1 : -1;
2009}
2010
2011void
2012DamageUnregister (DrawablePtr	    pDrawable,
2013		  DamagePtr	    pDamage)
2014{
2015    ScreenPtr pScreen = pDrawable->pScreen;
2016    damageScrPriv(pScreen);
2017
2018    (*pScrPriv->funcs.Unregister) (pDrawable, pDamage);
2019
2020    if (pDrawable->type == DRAWABLE_WINDOW)
2021    {
2022	WindowPtr   pWindow = (WindowPtr) pDrawable;
2023	winDamageRef (pWindow);
2024#if DAMAGE_VALIDATE_ENABLE
2025	int	found = 0;
2026#endif
2027
2028	while (*pPrev)
2029	{
2030	    if (*pPrev == pDamage)
2031	    {
2032		*pPrev = pDamage->pNextWin;
2033#if DAMAGE_VALIDATE_ENABLE
2034		found = 1;
2035#endif
2036		break;
2037	    }
2038	    pPrev = &(*pPrev)->pNextWin;
2039	}
2040#if DAMAGE_VALIDATE_ENABLE
2041	if (!found) {
2042	    ErrorF ("Damage not on window list\n");
2043	    OsAbort ();
2044	}
2045#endif
2046    }
2047    pDamage->pDrawable = 0;
2048    damageRemoveDamage (getDrawableDamageRef (pDrawable), pDamage);
2049}
2050
2051void
2052DamageDestroy (DamagePtr    pDamage)
2053{
2054    ScreenPtr pScreen = pDamage->pScreen;
2055    damageScrPriv(pScreen);
2056
2057    if (pDamage->damageDestroy)
2058	(*pDamage->damageDestroy) (pDamage, pDamage->closure);
2059    (*pScrPriv->funcs.Destroy) (pDamage);
2060    RegionUninit(&pDamage->damage);
2061    RegionUninit(&pDamage->pendingDamage);
2062    dixFreeObjectWithPrivates(pDamage, PRIVATE_DAMAGE);
2063}
2064
2065Bool
2066DamageSubtract (DamagePtr	    pDamage,
2067		const RegionPtr	    pRegion)
2068{
2069    RegionPtr	pClip;
2070    RegionRec	pixmapClip;
2071    DrawablePtr	pDrawable = pDamage->pDrawable;
2072
2073    RegionSubtract(&pDamage->damage, &pDamage->damage, pRegion);
2074    if (pDrawable)
2075    {
2076	if (pDrawable->type == DRAWABLE_WINDOW)
2077	    pClip = &((WindowPtr) pDrawable)->borderClip;
2078	else
2079	{
2080	    BoxRec  box;
2081
2082	    box.x1 = pDrawable->x;
2083	    box.y1 = pDrawable->y;
2084	    box.x2 = pDrawable->x + pDrawable->width;
2085	    box.y2 = pDrawable->y + pDrawable->height;
2086	    RegionInit(&pixmapClip, &box, 1);
2087	    pClip = &pixmapClip;
2088	}
2089	RegionTranslate(&pDamage->damage, pDrawable->x, pDrawable->y);
2090	RegionIntersect(&pDamage->damage, &pDamage->damage, pClip);
2091	RegionTranslate(&pDamage->damage, -pDrawable->x, -pDrawable->y);
2092	if (pDrawable->type != DRAWABLE_WINDOW)
2093	    RegionUninit(&pixmapClip);
2094    }
2095    return RegionNotEmpty(&pDamage->damage);
2096}
2097
2098void
2099DamageEmpty (DamagePtr	    pDamage)
2100{
2101    RegionEmpty(&pDamage->damage);
2102}
2103
2104RegionPtr
2105DamageRegion (DamagePtr		    pDamage)
2106{
2107    return &pDamage->damage;
2108}
2109
2110RegionPtr
2111DamagePendingRegion (DamagePtr	    pDamage)
2112{
2113    return &pDamage->pendingDamage;
2114}
2115
2116void
2117DamageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion)
2118{
2119    damageRegionAppend (pDrawable, pRegion, FALSE, -1);
2120}
2121
2122void
2123DamageRegionProcessPending (DrawablePtr pDrawable)
2124{
2125    damageRegionProcessPending (pDrawable);
2126}
2127
2128/* If a damage marker is provided, then this function must be called after rendering is done. */
2129/* Please do call back so any future enhancements can assume this function is called. */
2130/* There are no strict timing requirements for calling this function, just as soon as (is cheaply) possible. */
2131void
2132DamageRegionRendered (DrawablePtr pDrawable, DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pRegion)
2133{
2134    if (pDamage->damageReportPostRendering)
2135	damageReportDamagePostRendering (pDamage, pOldDamage, pRegion);
2136}
2137
2138/* This call is very odd, i'm leaving it intact for API sake, but please don't use it. */
2139void
2140DamageDamageRegion (DrawablePtr	pDrawable,
2141		    RegionPtr	pRegion)
2142{
2143    damageRegionAppend (pDrawable, pRegion, FALSE, -1);
2144
2145    /* Go back and report this damage for DamagePtrs with reportAfter set, since
2146     * this call isn't part of an in-progress drawing op in the call chain and
2147     * the DDX probably just wants to know about it right away.
2148     */
2149    damageRegionProcessPending (pDrawable);
2150}
2151
2152void
2153DamageSetReportAfterOp (DamagePtr pDamage, Bool reportAfter)
2154{
2155    pDamage->reportAfter = reportAfter;
2156}
2157
2158void
2159DamageSetPostRenderingFunctions(DamagePtr pDamage, DamageReportFunc damageReportPostRendering,
2160				DamageMarkerFunc damageMarker)
2161{
2162    pDamage->damageReportPostRendering = damageReportPostRendering;
2163    pDamage->damageMarker = damageMarker;
2164}
2165
2166DamageScreenFuncsPtr
2167DamageGetScreenFuncs (ScreenPtr pScreen)
2168{
2169    damageScrPriv(pScreen);
2170    return &pScrPriv->funcs;
2171}
2172