damage.c revision 4642e01f
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 int damageScrPrivateKeyIndex;
74static DevPrivateKey damageScrPrivateKey = &damageScrPrivateKeyIndex;
75static int damagePixPrivateKeyIndex;
76static DevPrivateKey damagePixPrivateKey = &damagePixPrivateKeyIndex;
77static int damageGCPrivateKeyIndex;
78static DevPrivateKey damageGCPrivateKey = &damageGCPrivateKeyIndex;
79static int damageWinPrivateKeyIndex;
80static DevPrivateKey damageWinPrivateKey = &damageWinPrivateKeyIndex;
81
82static DamagePtr *
83getDrawableDamageRef (DrawablePtr pDrawable)
84{
85    PixmapPtr   pPixmap;
86
87    if (pDrawable->type == DRAWABLE_WINDOW)
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	REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
133			 pDamageRegion);
134	(*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure);
135	break;
136    case DamageReportDeltaRegion:
137	REGION_NULL (pScreen, &tmpRegion);
138	REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, &pDamage->damage);
139	if (REGION_NOTEMPTY (pScreen, &tmpRegion)) {
140	    REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
141			 pDamageRegion);
142	    (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure);
143	}
144	REGION_UNINIT(pScreen, &tmpRegion);
145	break;
146    case DamageReportBoundingBox:
147	tmpBox = *REGION_EXTENTS (pScreen, &pDamage->damage);
148	REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
149		     pDamageRegion);
150	if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &pDamage->damage))) {
151	    (*pDamage->damageReport) (pDamage, &pDamage->damage,
152				      pDamage->closure);
153	}
154	break;
155    case DamageReportNonEmpty:
156	was_empty = !REGION_NOTEMPTY(pScreen, &pDamage->damage);
157	REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
158		     pDamageRegion);
159	if (was_empty && REGION_NOTEMPTY(pScreen, &pDamage->damage)) {
160	    (*pDamage->damageReport) (pDamage, &pDamage->damage,
161				      pDamage->closure);
162	}
163	break;
164    case DamageReportNone:
165	REGION_UNION(pScreen, &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    REGION_UNION(pScreem, &newDamage, pOldDamage, pDamageRegion);
179
180    switch (pDamage->damageLevel) {
181    case DamageReportRawRegion:
182	(*pDamage->damageReportPostRendering) (pDamage, pDamageRegion, pDamage->closure);
183	break;
184    case DamageReportDeltaRegion:
185	REGION_NULL (pScreen, &tmpRegion);
186	REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, pOldDamage);
187	if (REGION_NOTEMPTY (pScreen, &tmpRegion)) {
188	    (*pDamage->damageReportPostRendering) (pDamage, &tmpRegion, pDamage->closure);
189	}
190	REGION_UNINIT(pScreen, &tmpRegion);
191	break;
192    case DamageReportBoundingBox:
193	tmpBox = *REGION_EXTENTS (pScreen, pOldDamage);
194	if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &newDamage))) {
195	    (*pDamage->damageReportPostRendering) (pDamage, &newDamage,
196				      pDamage->closure);
197	}
198	break;
199    case DamageReportNonEmpty:
200	was_empty = !REGION_NOTEMPTY(pScreen, pOldDamage);
201	if (was_empty && REGION_NOTEMPTY(pScreen, &newDamage)) {
202	    (*pDamage->damageReportPostRendering) (pDamage, &newDamage,
203				      pDamage->closure);
204	}
205	break;
206    case DamageReportNone:
207	break;
208    }
209
210    REGION_UNINIT(pScreen, &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 (!REGION_NOTEMPTY(pScreen, 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        REGION_TRANSLATE (pScreen, 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	    REGION_INTERSECT(pScreen, pRegion, pRegion,
260			     &((WindowPtr)(pDrawable))->clipList);
261	}
262	else if (subWindowMode == IncludeInferiors)
263	{
264	    RegionPtr pTempRegion =
265		NotClippedByChildren((WindowPtr)(pDrawable));
266	    REGION_INTERSECT(pScreen, pRegion, pRegion, pTempRegion);
267	    REGION_DESTROY(pScreen, pTempRegion);
268	}
269	/* If subWindowMode is set to an invalid value, don't perform
270	 * any drawable-based clipping. */
271    }
272
273
274    REGION_NULL (pScreen, &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 (pDamage->pDrawable->type != DRAWABLE_WINDOW)
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		REGION_INTERSECT (pScreen, 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		REGION_INIT(pScreen, &pixClip, &box, 1);
328		REGION_INTERSECT (pScreen, pDamageRegion, pRegion, &pixClip);
329		REGION_UNINIT(pScreen, &pixClip);
330	    }
331	    /*
332	     * Short circuit empty results
333	     */
334	    if (!REGION_NOTEMPTY(pScreen, 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	    REGION_TRANSLATE (pScreen, pDamageRegion, -draw_x, -draw_y);
350
351	/* Store damage region if needed after submission. */
352	if (pDamage->reportAfter || pDamage->damageMarker)
353	    REGION_UNION(pScreen, &pDamage->pendingDamage,
354			 &pDamage->pendingDamage, pDamageRegion);
355
356	/* Duplicate current damage if needed. */
357	if (pDamage->damageMarker)
358	    REGION_COPY(pScreen, &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		REGION_UNION(pScreen, &pDamage->damage,
366			 &pDamage->damage, pDamageRegion);
367	}
368
369	/*
370	 * translate original region back
371	 */
372	if (pDamageRegion == pRegion && (draw_x || draw_y))
373	    REGION_TRANSLATE (pScreen, pDamageRegion, draw_x, draw_y);
374    }
375#ifdef COMPOSITE
376    if (screen_x || screen_y)
377	REGION_TRANSLATE (pScreen, pRegion, -screen_x, -screen_y);
378#endif
379
380    REGION_UNINIT (pScreen, &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		REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
399			&pDamage->pendingDamage);
400	}
401
402	if (pDamage->reportAfter || pDamage->damageMarker)
403	    REGION_EMPTY (pScreen, &pDamage->pendingDamage);
404	if (pDamage->damageMarker)
405	    REGION_EMPTY (pScreen, &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    REGION_INIT (pDrawable->pScreen, &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    REGION_UNINIT (pDrawable->pScreen, &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				  REGION_NOTEMPTY(d->pScreen, \
597						  g->pCompositeClip)))
598
599#ifdef RENDER
600
601#define TRIM_PICTURE_BOX(box, pDst) { \
602    BoxPtr extents = &pDst->pCompositeClip->extents;\
603    if(box.x1 < extents->x1) box.x1 = extents->x1; \
604    if(box.x2 > extents->x2) box.x2 = extents->x2; \
605    if(box.y1 < extents->y1) box.y1 = extents->y1; \
606    if(box.y2 > extents->y2) box.y2 = extents->y2; \
607    }
608
609#define checkPictureDamage(p)	(getDrawableDamage(p->pDrawable) && \
610				 REGION_NOTEMPTY(pScreen, p->pCompositeClip))
611
612static void
613damageComposite (CARD8      op,
614		   PicturePtr pSrc,
615		   PicturePtr pMask,
616		   PicturePtr pDst,
617		   INT16      xSrc,
618		   INT16      ySrc,
619		   INT16      xMask,
620		   INT16      yMask,
621		   INT16      xDst,
622		   INT16      yDst,
623		   CARD16     width,
624		   CARD16     height)
625{
626    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
627    PictureScreenPtr	ps = GetPictureScreen(pScreen);
628    damageScrPriv(pScreen);
629
630    if (checkPictureDamage (pDst))
631    {
632	BoxRec	box;
633
634	box.x1 = xDst + pDst->pDrawable->x;
635	box.y1 = yDst + pDst->pDrawable->y;
636	box.x2 = box.x1 + width;
637	box.y2 = box.y1 + height;
638	TRIM_PICTURE_BOX(box, pDst);
639	if (BOX_NOT_EMPTY(box))
640	    damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode);
641    }
642    unwrap (pScrPriv, ps, Composite);
643    (*ps->Composite) (op,
644		       pSrc,
645		       pMask,
646		       pDst,
647		       xSrc,
648		       ySrc,
649		       xMask,
650		       yMask,
651		       xDst,
652		       yDst,
653		       width,
654		       height);
655    damageRegionProcessPending (pDst->pDrawable);
656    wrap (pScrPriv, ps, Composite, damageComposite);
657}
658
659static void
660damageGlyphs (CARD8		op,
661		PicturePtr	pSrc,
662		PicturePtr	pDst,
663		PictFormatPtr	maskFormat,
664		INT16		xSrc,
665		INT16		ySrc,
666		int		nlist,
667		GlyphListPtr	list,
668		GlyphPtr	*glyphs)
669{
670    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
671    PictureScreenPtr	ps = GetPictureScreen(pScreen);
672    damageScrPriv(pScreen);
673
674    if (checkPictureDamage (pDst))
675    {
676	int		nlistTmp = nlist;
677	GlyphListPtr	listTmp = list;
678	GlyphPtr	*glyphsTmp = glyphs;
679	int		x, y;
680	int		n;
681	GlyphPtr	glyph;
682	BoxRec		box;
683	int		x1, y1, x2, y2;
684
685	box.x1 = 32767;
686	box.y1 = 32767;
687	box.x2 = -32767;
688	box.y2 = -32767;
689	x = pDst->pDrawable->x;
690	y = pDst->pDrawable->y;
691	while (nlistTmp--)
692	{
693	    x += listTmp->xOff;
694	    y += listTmp->yOff;
695	    n = listTmp->len;
696	    while (n--)
697	    {
698		glyph = *glyphsTmp++;
699		x1 = x - glyph->info.x;
700		y1 = y - glyph->info.y;
701		x2 = x1 + glyph->info.width;
702		y2 = y1 + glyph->info.height;
703		if (x1 < box.x1)
704		    box.x1 = x1;
705		if (y1 < box.y1)
706		    box.y1 = y1;
707		if (x2 > box.x2)
708		    box.x2 = x2;
709		if (y2 > box.y2)
710		    box.y2 = y2;
711		x += glyph->info.xOff;
712		y += glyph->info.yOff;
713	    }
714	    listTmp++;
715	}
716	TRIM_PICTURE_BOX (box, pDst);
717	if (BOX_NOT_EMPTY(box))
718	    damageDamageBox (pDst->pDrawable, &box, pDst->subWindowMode);
719    }
720    unwrap (pScrPriv, ps, Glyphs);
721    (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
722    damageRegionProcessPending (pDst->pDrawable);
723    wrap (pScrPriv, ps, Glyphs, damageGlyphs);
724}
725
726static void
727damageAddTraps (PicturePtr  pPicture,
728		INT16	    x_off,
729		INT16	    y_off,
730		int	    ntrap,
731		xTrap	    *traps)
732{
733    ScreenPtr		pScreen = pPicture->pDrawable->pScreen;
734    PictureScreenPtr	ps = GetPictureScreen(pScreen);
735    damageScrPriv(pScreen);
736
737    if (checkPictureDamage (pPicture))
738    {
739	BoxRec	box;
740	int	i;
741	int	x, y;
742	xTrap	*t = traps;
743
744	box.x1 = 32767;
745	box.y1 = 32767;
746	box.x2 = -32767;
747	box.y2 = -32767;
748	x = pPicture->pDrawable->x + x_off;
749	y = pPicture->pDrawable->y + y_off;
750	for (i = 0; i < ntrap; i++)
751	{
752	    pixman_fixed_t   l = min (t->top.l, t->bot.l);
753	    pixman_fixed_t   r = max (t->top.r, t->bot.r);
754	    int	    x1 = x + pixman_fixed_to_int (l);
755	    int	    x2 = x + pixman_fixed_to_int (pixman_fixed_ceil (r));
756	    int	    y1 = y + pixman_fixed_to_int (t->top.y);
757	    int	    y2 = y + pixman_fixed_to_int (pixman_fixed_ceil (t->bot.y));
758
759	    if (x1 < box.x1)
760		box.x1 = x1;
761	    if (x2 > box.x2)
762		box.x2 = x2;
763	    if (y1 < box.y1)
764		box.y1 = y1;
765	    if (y2 > box.y2)
766		box.y2 = y2;
767	}
768	TRIM_PICTURE_BOX (box, pPicture);
769	if (BOX_NOT_EMPTY(box))
770	    damageDamageBox (pPicture->pDrawable, &box, pPicture->subWindowMode);
771    }
772    unwrap (pScrPriv, ps, AddTraps);
773    (*ps->AddTraps) (pPicture, x_off, y_off, ntrap, traps);
774    damageRegionProcessPending (pPicture->pDrawable);
775    wrap (pScrPriv, ps, AddTraps, damageAddTraps);
776}
777#endif
778
779/**********************************************************/
780
781
782static void
783damageFillSpans(DrawablePtr pDrawable,
784		GC	    *pGC,
785		int	    npt,
786		DDXPointPtr ppt,
787		int	    *pwidth,
788		int	    fSorted)
789{
790    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
791
792    if (npt && checkGCDamage (pDrawable, pGC))
793    {
794	int	    nptTmp = npt;
795	DDXPointPtr pptTmp = ppt;
796	int	    *pwidthTmp = pwidth;
797	BoxRec	    box;
798
799	box.x1 = pptTmp->x;
800	box.x2 = box.x1 + *pwidthTmp;
801	box.y2 = box.y1 = pptTmp->y;
802
803	while(--nptTmp)
804	{
805	   pptTmp++;
806	   pwidthTmp++;
807	   if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
808	   if(box.x2 < (pptTmp->x + *pwidthTmp))
809		box.x2 = pptTmp->x + *pwidthTmp;
810	   if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
811	   else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
812	}
813
814	box.y2++;
815
816        if(!pGC->miTranslate) {
817           TRANSLATE_BOX(box, pDrawable);
818        }
819        TRIM_BOX(box, pGC);
820
821	if(BOX_NOT_EMPTY(box))
822	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
823    }
824
825    (*pGC->ops->FillSpans)(pDrawable, pGC, npt, ppt, pwidth, fSorted);
826
827    damageRegionProcessPending (pDrawable);
828    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
829}
830
831static void
832damageSetSpans(DrawablePtr  pDrawable,
833	       GCPtr	    pGC,
834	       char	    *pcharsrc,
835	       DDXPointPtr  ppt,
836	       int	    *pwidth,
837	       int	    npt,
838	       int	    fSorted)
839{
840    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
841
842    if (npt && checkGCDamage (pDrawable, pGC))
843    {
844	DDXPointPtr pptTmp = ppt;
845	int	    *pwidthTmp = pwidth;
846	int	    nptTmp = npt;
847	BoxRec	    box;
848
849	box.x1 = pptTmp->x;
850	box.x2 = box.x1 + *pwidthTmp;
851	box.y2 = box.y1 = pptTmp->y;
852
853	while(--nptTmp)
854	{
855	   pptTmp++;
856	   pwidthTmp++;
857	   if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
858	   if(box.x2 < (pptTmp->x + *pwidthTmp))
859		box.x2 = pptTmp->x + *pwidthTmp;
860	   if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
861	   else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
862	}
863
864	box.y2++;
865
866        if(!pGC->miTranslate) {
867           TRANSLATE_BOX(box, pDrawable);
868        }
869        TRIM_BOX(box, pGC);
870
871	if(BOX_NOT_EMPTY(box))
872	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
873    }
874    (*pGC->ops->SetSpans)(pDrawable, pGC, pcharsrc, ppt, pwidth, npt, fSorted);
875    damageRegionProcessPending (pDrawable);
876    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
877}
878
879static void
880damagePutImage(DrawablePtr  pDrawable,
881	       GCPtr	    pGC,
882	       int	    depth,
883	       int	    x,
884	       int	    y,
885	       int	    w,
886	       int	    h,
887	       int	    leftPad,
888	       int	    format,
889	       char	    *pImage)
890{
891    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
892    if (checkGCDamage (pDrawable, pGC))
893    {
894	BoxRec box;
895
896	box.x1 = x + pDrawable->x;
897	box.x2 = box.x1 + w;
898	box.y1 = y + pDrawable->y;
899	box.y2 = box.y1 + h;
900
901	TRIM_BOX(box, pGC);
902	if(BOX_NOT_EMPTY(box))
903	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
904    }
905    (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
906		leftPad, format, pImage);
907    damageRegionProcessPending (pDrawable);
908    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
909}
910
911static RegionPtr
912damageCopyArea(DrawablePtr   pSrc,
913	       DrawablePtr  pDst,
914	       GC	    *pGC,
915	       int	    srcx,
916	       int	    srcy,
917	       int	    width,
918	       int	    height,
919	       int	    dstx,
920	       int	    dsty)
921{
922    RegionPtr ret;
923    DAMAGE_GC_OP_PROLOGUE(pGC, pDst);
924
925    /* The driver will only call SourceValidate() when pSrc != pDst,
926     * but the software sprite (misprite.c) always need to know when a
927     * drawable is copied so it can remove the sprite. See #1030. */
928    if ((pSrc == pDst) && pSrc->pScreen->SourceValidate &&
929	pSrc->type == DRAWABLE_WINDOW &&
930	((WindowPtr)pSrc)->viewable)
931    {
932	(*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height);
933    }
934
935    if (checkGCDamage (pDst, pGC))
936    {
937	BoxRec box;
938
939	box.x1 = dstx + pDst->x;
940	box.x2 = box.x1 + width;
941	box.y1 = dsty + pDst->y;
942	box.y2 = box.y1 + height;
943
944	TRIM_BOX(box, pGC);
945	if(BOX_NOT_EMPTY(box))
946	   damageDamageBox (pDst, &box, pGC->subWindowMode);
947    }
948
949    ret = (*pGC->ops->CopyArea)(pSrc, pDst,
950            pGC, srcx, srcy, width, height, dstx, dsty);
951    damageRegionProcessPending (pDst);
952    DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
953    return ret;
954}
955
956static RegionPtr
957damageCopyPlane(DrawablePtr	pSrc,
958		DrawablePtr	pDst,
959		GCPtr		pGC,
960		int		srcx,
961		int		srcy,
962		int		width,
963		int		height,
964		int		dstx,
965		int		dsty,
966		unsigned long	bitPlane)
967{
968    RegionPtr ret;
969    DAMAGE_GC_OP_PROLOGUE(pGC, pDst);
970
971    /* The driver will only call SourceValidate() when pSrc != pDst,
972     * but the software sprite (misprite.c) always need to know when a
973     * drawable is copied so it can remove the sprite. See #1030. */
974    if ((pSrc == pDst) && pSrc->pScreen->SourceValidate &&
975	pSrc->type == DRAWABLE_WINDOW &&
976	((WindowPtr)pSrc)->viewable)
977    {
978        (*pSrc->pScreen->SourceValidate) (pSrc, srcx, srcy, width, height);
979    }
980
981    if (checkGCDamage (pDst, pGC))
982    {
983	BoxRec box;
984
985	box.x1 = dstx + pDst->x;
986	box.x2 = box.x1 + width;
987	box.y1 = dsty + pDst->y;
988	box.y2 = box.y1 + height;
989
990	TRIM_BOX(box, pGC);
991	if(BOX_NOT_EMPTY(box))
992	   damageDamageBox (pDst, &box, pGC->subWindowMode);
993    }
994
995    ret = (*pGC->ops->CopyPlane)(pSrc, pDst,
996	       pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
997    damageRegionProcessPending (pDst);
998    DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
999    return ret;
1000}
1001
1002static void
1003damagePolyPoint(DrawablePtr pDrawable,
1004		GCPtr	    pGC,
1005		int	    mode,
1006		int	    npt,
1007		xPoint	    *ppt)
1008{
1009    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1010
1011    if (npt && checkGCDamage (pDrawable, pGC))
1012    {
1013	BoxRec	box;
1014	int	nptTmp = npt;
1015	xPoint	*pptTmp = ppt;
1016
1017	box.x2 = box.x1 = pptTmp->x;
1018	box.y2 = box.y1 = pptTmp->y;
1019
1020	/* this could be slow if the points were spread out */
1021
1022	while(--nptTmp)
1023	{
1024	   pptTmp++;
1025	   if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
1026	   else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
1027	   if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
1028	   else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
1029	}
1030
1031	box.x2++;
1032	box.y2++;
1033
1034	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1035	if(BOX_NOT_EMPTY(box))
1036	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1037    }
1038    (*pGC->ops->PolyPoint)(pDrawable, pGC, mode, npt, ppt);
1039    damageRegionProcessPending (pDrawable);
1040    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1041}
1042
1043static void
1044damagePolylines(DrawablePtr pDrawable,
1045		GCPtr	    pGC,
1046		int	    mode,
1047		int	    npt,
1048		DDXPointPtr ppt)
1049{
1050    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1051
1052    if (npt && checkGCDamage (pDrawable, pGC))
1053    {
1054	int	    nptTmp = npt;
1055	DDXPointPtr pptTmp = ppt;
1056	BoxRec	    box;
1057	int	    extra = pGC->lineWidth >> 1;
1058
1059	box.x2 = box.x1 = pptTmp->x;
1060	box.y2 = box.y1 = pptTmp->y;
1061
1062	if(nptTmp > 1)
1063	{
1064	   if(pGC->joinStyle == JoinMiter)
1065		extra = 6 * pGC->lineWidth;
1066	   else if(pGC->capStyle == CapProjecting)
1067		extra = pGC->lineWidth;
1068        }
1069
1070	if(mode == CoordModePrevious)
1071	{
1072	   int x = box.x1;
1073	   int y = box.y1;
1074	   while(--nptTmp)
1075	   {
1076		pptTmp++;
1077		x += pptTmp->x;
1078		y += pptTmp->y;
1079		if(box.x1 > x) box.x1 = x;
1080		else if(box.x2 < x) box.x2 = x;
1081		if(box.y1 > y) box.y1 = y;
1082		else if(box.y2 < y) box.y2 = y;
1083	    }
1084	}
1085	else
1086	{
1087	   while(--nptTmp)
1088	   {
1089		pptTmp++;
1090		if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
1091		else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
1092		if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
1093		else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
1094	    }
1095	}
1096
1097	box.x2++;
1098	box.y2++;
1099
1100	if(extra)
1101	{
1102	   box.x1 -= extra;
1103	   box.x2 += extra;
1104	   box.y1 -= extra;
1105	   box.y2 += extra;
1106        }
1107
1108	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1109	if(BOX_NOT_EMPTY(box))
1110	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1111    }
1112    (*pGC->ops->Polylines)(pDrawable, pGC, mode, npt, ppt);
1113    damageRegionProcessPending (pDrawable);
1114    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1115}
1116
1117static void
1118damagePolySegment(DrawablePtr	pDrawable,
1119		  GCPtr		pGC,
1120		  int		nSeg,
1121		  xSegment	*pSeg)
1122{
1123    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1124
1125    if (nSeg && checkGCDamage (pDrawable, pGC))
1126    {
1127	BoxRec	    box;
1128	int	    extra = pGC->lineWidth;
1129	int	    nsegTmp = nSeg;
1130	xSegment    *pSegTmp = pSeg;
1131
1132        if(pGC->capStyle != CapProjecting)
1133	   extra >>= 1;
1134
1135	if(pSegTmp->x2 > pSegTmp->x1) {
1136	    box.x1 = pSegTmp->x1;
1137	    box.x2 = pSegTmp->x2;
1138	} else {
1139	    box.x2 = pSegTmp->x1;
1140	    box.x1 = pSegTmp->x2;
1141	}
1142
1143	if(pSegTmp->y2 > pSegTmp->y1) {
1144	    box.y1 = pSegTmp->y1;
1145	    box.y2 = pSegTmp->y2;
1146	} else {
1147	    box.y2 = pSegTmp->y1;
1148	    box.y1 = pSegTmp->y2;
1149	}
1150
1151	while(--nsegTmp)
1152	{
1153	    pSegTmp++;
1154	    if(pSegTmp->x2 > pSegTmp->x1)
1155	    {
1156		if(pSegTmp->x1 < box.x1) box.x1 = pSegTmp->x1;
1157		if(pSegTmp->x2 > box.x2) box.x2 = pSegTmp->x2;
1158	    }
1159	    else
1160	    {
1161		if(pSegTmp->x2 < box.x1) box.x1 = pSegTmp->x2;
1162		if(pSegTmp->x1 > box.x2) box.x2 = pSegTmp->x1;
1163	    }
1164	    if(pSegTmp->y2 > pSegTmp->y1)
1165	    {
1166		if(pSegTmp->y1 < box.y1) box.y1 = pSegTmp->y1;
1167		if(pSegTmp->y2 > box.y2) box.y2 = pSegTmp->y2;
1168	    }
1169	    else
1170	    {
1171		if(pSegTmp->y2 < box.y1) box.y1 = pSegTmp->y2;
1172		if(pSegTmp->y1 > box.y2) box.y2 = pSegTmp->y1;
1173	    }
1174	}
1175
1176	box.x2++;
1177	box.y2++;
1178
1179	if(extra)
1180	{
1181	   box.x1 -= extra;
1182	   box.x2 += extra;
1183	   box.y1 -= extra;
1184	   box.y2 += extra;
1185        }
1186
1187	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1188	if(BOX_NOT_EMPTY(box))
1189	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1190    }
1191    (*pGC->ops->PolySegment)(pDrawable, pGC, nSeg, pSeg);
1192    damageRegionProcessPending (pDrawable);
1193    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1194}
1195
1196static void
1197damagePolyRectangle(DrawablePtr  pDrawable,
1198		    GCPtr        pGC,
1199		    int	         nRects,
1200		    xRectangle  *pRects)
1201{
1202    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1203
1204    if (nRects && checkGCDamage (pDrawable, pGC))
1205    {
1206	BoxRec	    box;
1207	int	    offset1, offset2, offset3;
1208	int	    nRectsTmp = nRects;
1209	xRectangle  *pRectsTmp = pRects;
1210
1211	offset2 = pGC->lineWidth;
1212	if(!offset2) offset2 = 1;
1213	offset1 = offset2 >> 1;
1214	offset3 = offset2 - offset1;
1215
1216	while(nRectsTmp--)
1217	{
1218	    box.x1 = pRectsTmp->x - offset1;
1219	    box.y1 = pRectsTmp->y - offset1;
1220	    box.x2 = box.x1 + pRectsTmp->width + offset2;
1221	    box.y2 = box.y1 + offset2;
1222	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1223	    if(BOX_NOT_EMPTY(box))
1224		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1225
1226	    box.x1 = pRectsTmp->x - offset1;
1227	    box.y1 = pRectsTmp->y + offset3;
1228	    box.x2 = box.x1 + offset2;
1229	    box.y2 = box.y1 + pRectsTmp->height - offset2;
1230	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1231	    if(BOX_NOT_EMPTY(box))
1232		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1233
1234	    box.x1 = pRectsTmp->x + pRectsTmp->width - offset1;
1235	    box.y1 = pRectsTmp->y + offset3;
1236	    box.x2 = box.x1 + offset2;
1237	    box.y2 = box.y1 + pRectsTmp->height - offset2;
1238	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1239	    if(BOX_NOT_EMPTY(box))
1240		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1241
1242	    box.x1 = pRectsTmp->x - offset1;
1243	    box.y1 = pRectsTmp->y + pRectsTmp->height - offset1;
1244	    box.x2 = box.x1 + pRectsTmp->width + offset2;
1245	    box.y2 = box.y1 + offset2;
1246	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1247	    if(BOX_NOT_EMPTY(box))
1248		damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1249
1250	    pRectsTmp++;
1251	}
1252    }
1253    (*pGC->ops->PolyRectangle)(pDrawable, pGC, nRects, pRects);
1254    damageRegionProcessPending (pDrawable);
1255    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1256}
1257
1258static void
1259damagePolyArc(DrawablePtr   pDrawable,
1260	      GCPtr	    pGC,
1261	      int	    nArcs,
1262	      xArc	    *pArcs)
1263{
1264    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1265
1266    if (nArcs && checkGCDamage (pDrawable, pGC))
1267    {
1268	int	extra = pGC->lineWidth >> 1;
1269	BoxRec	box;
1270	int	nArcsTmp = nArcs;
1271	xArc	*pArcsTmp = pArcs;
1272
1273	box.x1 = pArcsTmp->x;
1274	box.x2 = box.x1 + pArcsTmp->width;
1275	box.y1 = pArcsTmp->y;
1276	box.y2 = box.y1 + pArcsTmp->height;
1277
1278	while(--nArcsTmp)
1279	{
1280	    pArcsTmp++;
1281	    if(box.x1 > pArcsTmp->x)
1282		box.x1 = pArcsTmp->x;
1283	    if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
1284		box.x2 = pArcsTmp->x + pArcsTmp->width;
1285	    if(box.y1 > pArcsTmp->y)
1286		box.y1 = pArcsTmp->y;
1287	    if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
1288		box.y2 = pArcsTmp->y + pArcsTmp->height;
1289        }
1290
1291	if(extra)
1292	{
1293	   box.x1 -= extra;
1294	   box.x2 += extra;
1295	   box.y1 -= extra;
1296	   box.y2 += extra;
1297        }
1298
1299	box.x2++;
1300	box.y2++;
1301
1302	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1303	if(BOX_NOT_EMPTY(box))
1304	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1305    }
1306    (*pGC->ops->PolyArc)(pDrawable, pGC, nArcs, pArcs);
1307    damageRegionProcessPending (pDrawable);
1308    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1309}
1310
1311static void
1312damageFillPolygon(DrawablePtr	pDrawable,
1313		  GCPtr		pGC,
1314		  int		shape,
1315		  int		mode,
1316		  int		npt,
1317		  DDXPointPtr	ppt)
1318{
1319    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1320
1321    if (npt > 2 && checkGCDamage (pDrawable, pGC))
1322    {
1323	DDXPointPtr pptTmp = ppt;
1324	int	    nptTmp = npt;
1325	BoxRec	    box;
1326
1327	box.x2 = box.x1 = pptTmp->x;
1328	box.y2 = box.y1 = pptTmp->y;
1329
1330	if(mode != CoordModeOrigin)
1331	{
1332	   int x = box.x1;
1333	   int y = box.y1;
1334	   while(--nptTmp)
1335	   {
1336		pptTmp++;
1337		x += pptTmp->x;
1338		y += pptTmp->y;
1339		if(box.x1 > x) box.x1 = x;
1340		else if(box.x2 < x) box.x2 = x;
1341		if(box.y1 > y) box.y1 = y;
1342		else if(box.y2 < y) box.y2 = y;
1343	    }
1344	}
1345	else
1346	{
1347	   while(--nptTmp)
1348	   {
1349		pptTmp++;
1350		if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
1351		else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
1352		if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
1353		else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
1354	    }
1355	}
1356
1357	box.x2++;
1358	box.y2++;
1359
1360	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1361	if(BOX_NOT_EMPTY(box))
1362	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1363    }
1364
1365    (*pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, npt, ppt);
1366    damageRegionProcessPending (pDrawable);
1367    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1368}
1369
1370
1371static void
1372damagePolyFillRect(DrawablePtr	pDrawable,
1373		   GCPtr	pGC,
1374		   int		nRects,
1375		   xRectangle	*pRects)
1376{
1377    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1378    if (nRects && checkGCDamage (pDrawable, pGC))
1379    {
1380	BoxRec	    box;
1381	xRectangle  *pRectsTmp = pRects;
1382	int	    nRectsTmp = nRects;
1383
1384	box.x1 = pRectsTmp->x;
1385	box.x2 = box.x1 + pRectsTmp->width;
1386	box.y1 = pRectsTmp->y;
1387	box.y2 = box.y1 + pRectsTmp->height;
1388
1389	while(--nRectsTmp)
1390	{
1391	    pRectsTmp++;
1392	    if(box.x1 > pRectsTmp->x) box.x1 = pRectsTmp->x;
1393	    if(box.x2 < (pRectsTmp->x + pRectsTmp->width))
1394		box.x2 = pRectsTmp->x + pRectsTmp->width;
1395	    if(box.y1 > pRectsTmp->y) box.y1 = pRectsTmp->y;
1396	    if(box.y2 < (pRectsTmp->y + pRectsTmp->height))
1397		box.y2 = pRectsTmp->y + pRectsTmp->height;
1398	}
1399
1400	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1401	if(BOX_NOT_EMPTY(box))
1402	    damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1403    }
1404    (*pGC->ops->PolyFillRect)(pDrawable, pGC, nRects, pRects);
1405    damageRegionProcessPending (pDrawable);
1406    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1407}
1408
1409
1410static void
1411damagePolyFillArc(DrawablePtr	pDrawable,
1412		  GCPtr		pGC,
1413		  int		nArcs,
1414		  xArc		*pArcs)
1415{
1416    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1417
1418    if (nArcs && checkGCDamage (pDrawable, pGC))
1419    {
1420	BoxRec	box;
1421	int	nArcsTmp = nArcs;
1422	xArc	*pArcsTmp = pArcs;
1423
1424	box.x1 = pArcsTmp->x;
1425	box.x2 = box.x1 + pArcsTmp->width;
1426	box.y1 = pArcsTmp->y;
1427	box.y2 = box.y1 + pArcsTmp->height;
1428
1429	while(--nArcsTmp)
1430	{
1431	    pArcsTmp++;
1432	    if(box.x1 > pArcsTmp->x)
1433		box.x1 = pArcsTmp->x;
1434	    if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
1435		box.x2 = pArcsTmp->x + pArcsTmp->width;
1436	    if(box.y1 > pArcsTmp->y)
1437		box.y1 = pArcsTmp->y;
1438	    if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
1439		box.y2 = pArcsTmp->y + pArcsTmp->height;
1440        }
1441
1442	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
1443	if(BOX_NOT_EMPTY(box))
1444	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1445    }
1446    (*pGC->ops->PolyFillArc)(pDrawable, pGC, nArcs, pArcs);
1447    damageRegionProcessPending (pDrawable);
1448    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1449}
1450
1451/*
1452 * general Poly/Image text function.  Extract glyph information,
1453 * compute bounding box and remove cursor if it is overlapped.
1454 */
1455
1456static void
1457damageDamageChars (DrawablePtr	pDrawable,
1458		   FontPtr	font,
1459		   int		x,
1460		   int		y,
1461		   unsigned int	n,
1462		   CharInfoPtr	*charinfo,
1463		   Bool		imageblt,
1464		   int		subWindowMode)
1465{
1466    ExtentInfoRec   extents;
1467    BoxRec	    box;
1468
1469    QueryGlyphExtents(font, charinfo, n, &extents);
1470    if (imageblt)
1471    {
1472	if (extents.overallWidth > extents.overallRight)
1473	    extents.overallRight = extents.overallWidth;
1474	if (extents.overallWidth < extents.overallLeft)
1475	    extents.overallLeft = extents.overallWidth;
1476	if (extents.overallLeft > 0)
1477	    extents.overallLeft = 0;
1478	if (extents.fontAscent > extents.overallAscent)
1479	    extents.overallAscent = extents.fontAscent;
1480	if (extents.fontDescent > extents.overallDescent)
1481	    extents.overallDescent = extents.fontDescent;
1482    }
1483    box.x1 = x + extents.overallLeft;
1484    box.y1 = y - extents.overallAscent;
1485    box.x2 = x + extents.overallRight;
1486    box.y2 = y + extents.overallDescent;
1487    damageDamageBox (pDrawable, &box, subWindowMode);
1488}
1489
1490/*
1491 * values for textType:
1492 */
1493#define TT_POLY8   0
1494#define TT_IMAGE8  1
1495#define TT_POLY16  2
1496#define TT_IMAGE16 3
1497
1498static int
1499damageText (DrawablePtr	    pDrawable,
1500	    GCPtr	    pGC,
1501	    int		    x,
1502	    int		    y,
1503	    unsigned long   count,
1504	    char	    *chars,
1505	    FontEncoding    fontEncoding,
1506	    Bool	    textType)
1507{
1508    CharInfoPtr	    *charinfo;
1509    CharInfoPtr	    *info;
1510    unsigned long   i;
1511    unsigned int    n;
1512    int		    w;
1513    Bool	    imageblt;
1514
1515    imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16);
1516
1517    charinfo = (CharInfoPtr *) xalloc(count * sizeof(CharInfoPtr));
1518    if (!charinfo)
1519	return x;
1520
1521    GetGlyphs(pGC->font, count, (unsigned char *)chars,
1522	      fontEncoding, &i, charinfo);
1523    n = (unsigned int)i;
1524    w = 0;
1525    if (!imageblt)
1526	for (info = charinfo; i--; info++)
1527	    w += (*info)->metrics.characterWidth;
1528
1529    if (n != 0) {
1530	damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n,
1531			   charinfo, imageblt, pGC->subWindowMode);
1532	if (imageblt)
1533	    (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo,
1534				       FONTGLYPHS(pGC->font));
1535	else
1536	    (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo,
1537				      FONTGLYPHS(pGC->font));
1538    }
1539    xfree(charinfo);
1540    return x + w;
1541}
1542
1543static int
1544damagePolyText8(DrawablePtr pDrawable,
1545		GCPtr	    pGC,
1546		int	    x,
1547		int	    y,
1548		int	    count,
1549		char	    *chars)
1550{
1551    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1552
1553    if (checkGCDamage (pDrawable, pGC))
1554	x = damageText (pDrawable, pGC, x, y, (unsigned long) count, chars,
1555		    Linear8Bit, TT_POLY8);
1556    else
1557	x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars);
1558    damageRegionProcessPending (pDrawable);
1559    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1560    return x;
1561}
1562
1563static int
1564damagePolyText16(DrawablePtr	pDrawable,
1565		 GCPtr		pGC,
1566		 int		x,
1567		 int		y,
1568		 int		count,
1569		 unsigned short	*chars)
1570{
1571    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1572
1573    if (checkGCDamage (pDrawable, pGC))
1574	x = damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
1575		    FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
1576		    TT_POLY16);
1577    else
1578	x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars);
1579    damageRegionProcessPending (pDrawable);
1580    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1581    return x;
1582}
1583
1584static void
1585damageImageText8(DrawablePtr	pDrawable,
1586		 GCPtr		pGC,
1587		 int		x,
1588		 int		y,
1589		 int		count,
1590		 char		*chars)
1591{
1592    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1593
1594    if (checkGCDamage (pDrawable, pGC))
1595	damageText (pDrawable, pGC, x, y, (unsigned long) count, chars,
1596		    Linear8Bit, TT_IMAGE8);
1597    else
1598	(*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars);
1599    damageRegionProcessPending (pDrawable);
1600    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1601}
1602
1603static void
1604damageImageText16(DrawablePtr	pDrawable,
1605		  GCPtr		pGC,
1606		  int		x,
1607		  int		y,
1608		  int		count,
1609		  unsigned short *chars)
1610{
1611    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1612
1613    if (checkGCDamage (pDrawable, pGC))
1614	damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
1615		    FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
1616		    TT_IMAGE16);
1617    else
1618	(*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars);
1619    damageRegionProcessPending (pDrawable);
1620    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1621}
1622
1623
1624static void
1625damageImageGlyphBlt(DrawablePtr	    pDrawable,
1626		    GCPtr	    pGC,
1627		    int		    x,
1628		    int		    y,
1629		    unsigned int    nglyph,
1630		    CharInfoPtr	    *ppci,
1631		    pointer	    pglyphBase)
1632{
1633    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1634    damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
1635		       nglyph, ppci, TRUE, pGC->subWindowMode);
1636    (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph,
1637					ppci, pglyphBase);
1638    damageRegionProcessPending (pDrawable);
1639    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1640}
1641
1642static void
1643damagePolyGlyphBlt(DrawablePtr	pDrawable,
1644		   GCPtr	pGC,
1645		   int		x,
1646		   int		y,
1647		   unsigned int	nglyph,
1648		   CharInfoPtr	*ppci,
1649		   pointer	pglyphBase)
1650{
1651    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1652    damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
1653		       nglyph, ppci, FALSE, pGC->subWindowMode);
1654    (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph,
1655				ppci, pglyphBase);
1656    damageRegionProcessPending (pDrawable);
1657    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1658}
1659
1660static void
1661damagePushPixels(GCPtr		pGC,
1662		 PixmapPtr	pBitMap,
1663		 DrawablePtr	pDrawable,
1664		 int		dx,
1665		 int		dy,
1666		 int		xOrg,
1667		 int		yOrg)
1668{
1669    DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);
1670    if(checkGCDamage (pDrawable, pGC))
1671    {
1672	BoxRec box;
1673
1674        box.x1 = xOrg;
1675        box.y1 = yOrg;
1676
1677        if(!pGC->miTranslate) {
1678           box.x1 += pDrawable->x;
1679           box.y1 += pDrawable->y;
1680        }
1681
1682	box.x2 = box.x1 + dx;
1683	box.y2 = box.y1 + dy;
1684
1685	TRIM_BOX(box, pGC);
1686	if(BOX_NOT_EMPTY(box))
1687	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
1688    }
1689    (*pGC->ops->PushPixels)(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg);
1690    damageRegionProcessPending (pDrawable);
1691    DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
1692}
1693
1694static void
1695damageRemoveDamage (DamagePtr *pPrev, DamagePtr pDamage)
1696{
1697    while (*pPrev)
1698    {
1699	if (*pPrev == pDamage)
1700	{
1701	    *pPrev = pDamage->pNext;
1702	    return;
1703	}
1704	pPrev = &(*pPrev)->pNext;
1705    }
1706#if DAMAGE_VALIDATE_ENABLE
1707    ErrorF ("Damage not on list\n");
1708    abort ();
1709#endif
1710}
1711
1712static void
1713damageInsertDamage (DamagePtr *pPrev, DamagePtr pDamage)
1714{
1715#if DAMAGE_VALIDATE_ENABLE
1716    DamagePtr	pOld;
1717
1718    for (pOld = *pPrev; pOld; pOld = pOld->pNext)
1719	if (pOld == pDamage) {
1720	    ErrorF ("Damage already on list\n");
1721	    abort ();
1722	}
1723#endif
1724    pDamage->pNext = *pPrev;
1725    *pPrev = pDamage;
1726}
1727
1728static Bool
1729damageDestroyPixmap (PixmapPtr pPixmap)
1730{
1731    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
1732    damageScrPriv(pScreen);
1733
1734    if (pPixmap->refcnt == 1)
1735    {
1736	DamagePtr	*pPrev = getPixmapDamageRef (pPixmap);
1737	DamagePtr	pDamage;
1738
1739	while ((pDamage = *pPrev))
1740	{
1741	    damageRemoveDamage (pPrev, pDamage);
1742	    if (!pDamage->isWindow)
1743		DamageDestroy (pDamage);
1744	}
1745    }
1746    unwrap (pScrPriv, pScreen, DestroyPixmap);
1747    (*pScreen->DestroyPixmap) (pPixmap);
1748    wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap);
1749    return TRUE;
1750}
1751
1752static void
1753damageCopyWindow(WindowPtr	pWindow,
1754		 DDXPointRec	ptOldOrg,
1755		 RegionPtr	prgnSrc)
1756{
1757    ScreenPtr pScreen = pWindow->drawable.pScreen;
1758    damageScrPriv(pScreen);
1759
1760    if (getWindowDamage (pWindow))
1761    {
1762	int dx = pWindow->drawable.x - ptOldOrg.x;
1763	int dy = pWindow->drawable.y - ptOldOrg.y;
1764
1765	/*
1766	 * The region comes in source relative, but the damage occurs
1767	 * at the destination location.  Translate back and forth.
1768	 */
1769	REGION_TRANSLATE (pScreen, prgnSrc, dx, dy);
1770	damageRegionAppend (&pWindow->drawable, prgnSrc, FALSE, -1);
1771	REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
1772    }
1773    unwrap (pScrPriv, pScreen, CopyWindow);
1774    (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
1775    damageRegionProcessPending (&pWindow->drawable);
1776    wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow);
1777}
1778
1779static GCOps damageGCOps = {
1780    damageFillSpans, damageSetSpans,
1781    damagePutImage, damageCopyArea,
1782    damageCopyPlane, damagePolyPoint,
1783    damagePolylines, damagePolySegment,
1784    damagePolyRectangle, damagePolyArc,
1785    damageFillPolygon, damagePolyFillRect,
1786    damagePolyFillArc, damagePolyText8,
1787    damagePolyText16, damageImageText8,
1788    damageImageText16, damageImageGlyphBlt,
1789    damagePolyGlyphBlt, damagePushPixels,
1790    {NULL}		/* devPrivate */
1791};
1792
1793static void
1794damageSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
1795{
1796    DamagePtr	pDamage;
1797    ScreenPtr	pScreen = pWindow->drawable.pScreen;
1798    damageScrPriv(pScreen);
1799
1800    if ((pDamage = damageGetWinPriv(pWindow)))
1801    {
1802	PixmapPtr   pOldPixmap = (*pScreen->GetWindowPixmap) (pWindow);
1803	DamagePtr   *pPrev = getPixmapDamageRef(pOldPixmap);
1804
1805	while (pDamage)
1806	{
1807	    damageRemoveDamage (pPrev, pDamage);
1808	    pDamage = pDamage->pNextWin;
1809	}
1810    }
1811    unwrap (pScrPriv, pScreen, SetWindowPixmap);
1812    (*pScreen->SetWindowPixmap) (pWindow, pPixmap);
1813    wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap);
1814    if ((pDamage = damageGetWinPriv(pWindow)))
1815    {
1816	DamagePtr   *pPrev = getPixmapDamageRef(pPixmap);
1817
1818	while (pDamage)
1819	{
1820	    damageInsertDamage (pPrev, pDamage);
1821	    pDamage = pDamage->pNextWin;
1822	}
1823    }
1824}
1825
1826static Bool
1827damageDestroyWindow (WindowPtr pWindow)
1828{
1829    DamagePtr	pDamage;
1830    ScreenPtr	pScreen = pWindow->drawable.pScreen;
1831    Bool	ret;
1832    damageScrPriv(pScreen);
1833
1834    while ((pDamage = damageGetWinPriv(pWindow)))
1835    {
1836	DamageUnregister (&pWindow->drawable, pDamage);
1837	DamageDestroy (pDamage);
1838    }
1839    unwrap (pScrPriv, pScreen, DestroyWindow);
1840    ret = (*pScreen->DestroyWindow) (pWindow);
1841    wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow);
1842    return ret;
1843}
1844
1845static Bool
1846damageCloseScreen (int i, ScreenPtr pScreen)
1847{
1848    damageScrPriv(pScreen);
1849
1850    unwrap (pScrPriv, pScreen, DestroyPixmap);
1851    unwrap (pScrPriv, pScreen, CreateGC);
1852    unwrap (pScrPriv, pScreen, CopyWindow);
1853    unwrap (pScrPriv, pScreen, CloseScreen);
1854    xfree (pScrPriv);
1855    return (*pScreen->CloseScreen) (i, pScreen);
1856}
1857
1858/**
1859 * Public functions for consumption outside this file.
1860 */
1861
1862Bool
1863DamageSetup (ScreenPtr pScreen)
1864{
1865    DamageScrPrivPtr	pScrPriv;
1866#ifdef RENDER
1867    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
1868#endif
1869
1870    if (dixLookupPrivate(&pScreen->devPrivates, damageScrPrivateKey))
1871	return TRUE;
1872
1873    if (!dixRequestPrivate(damageGCPrivateKey, sizeof(DamageGCPrivRec)))
1874	return FALSE;
1875
1876    pScrPriv = (DamageScrPrivPtr) xalloc (sizeof (DamageScrPrivRec));
1877    if (!pScrPriv)
1878	return FALSE;
1879
1880    pScrPriv->internalLevel = 0;
1881    pScrPriv->pScreenDamage = 0;
1882
1883    wrap (pScrPriv, pScreen, DestroyPixmap, damageDestroyPixmap);
1884    wrap (pScrPriv, pScreen, CreateGC, damageCreateGC);
1885    wrap (pScrPriv, pScreen, DestroyWindow, damageDestroyWindow);
1886    wrap (pScrPriv, pScreen, SetWindowPixmap, damageSetWindowPixmap);
1887    wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow);
1888    wrap (pScrPriv, pScreen, CloseScreen, damageCloseScreen);
1889#ifdef RENDER
1890    if (ps) {
1891	wrap (pScrPriv, ps, Glyphs, damageGlyphs);
1892	wrap (pScrPriv, ps, Composite, damageComposite);
1893	wrap (pScrPriv, ps, AddTraps, damageAddTraps);
1894    }
1895#endif
1896
1897    dixSetPrivate(&pScreen->devPrivates, damageScrPrivateKey, pScrPriv);
1898    return TRUE;
1899}
1900
1901DamagePtr
1902DamageCreate (DamageReportFunc  damageReport,
1903	      DamageDestroyFunc	damageDestroy,
1904	      DamageReportLevel	damageLevel,
1905	      Bool		isInternal,
1906	      ScreenPtr		pScreen,
1907	      void		*closure)
1908{
1909    DamagePtr	pDamage;
1910
1911    pDamage = xalloc (sizeof (DamageRec));
1912    if (!pDamage)
1913	return 0;
1914    pDamage->pNext = 0;
1915    pDamage->pNextWin = 0;
1916    REGION_NULL(pScreen, &pDamage->damage);
1917    REGION_NULL(pScreen, &pDamage->pendingDamage);
1918
1919    pDamage->damageLevel = damageLevel;
1920    pDamage->isInternal = isInternal;
1921    pDamage->closure = closure;
1922    pDamage->isWindow = FALSE;
1923    pDamage->pDrawable = 0;
1924    pDamage->reportAfter = FALSE;
1925
1926    pDamage->damageReport = damageReport;
1927    pDamage->damageReportPostRendering = NULL;
1928    pDamage->damageDestroy = damageDestroy;
1929    pDamage->damageMarker = NULL;
1930    return pDamage;
1931}
1932
1933void
1934DamageRegister (DrawablePtr pDrawable,
1935		DamagePtr   pDamage)
1936{
1937    if (pDrawable->type == DRAWABLE_WINDOW)
1938    {
1939	WindowPtr   pWindow = (WindowPtr) pDrawable;
1940	winDamageRef(pWindow);
1941
1942#if DAMAGE_VALIDATE_ENABLE
1943	DamagePtr   pOld;
1944
1945	for (pOld = *pPrev; pOld; pOld = pOld->pNextWin)
1946	    if (pOld == pDamage) {
1947		ErrorF ("Damage already on window list\n");
1948		abort ();
1949	    }
1950#endif
1951	pDamage->pNextWin = *pPrev;
1952	*pPrev = pDamage;
1953	pDamage->isWindow = TRUE;
1954    }
1955    else
1956	pDamage->isWindow = FALSE;
1957    pDamage->pDrawable = pDrawable;
1958    damageInsertDamage (getDrawableDamageRef (pDrawable), pDamage);
1959}
1960
1961void
1962DamageDrawInternal (ScreenPtr pScreen, Bool enable)
1963{
1964    damageScrPriv (pScreen);
1965
1966    pScrPriv->internalLevel += enable ? 1 : -1;
1967}
1968
1969void
1970DamageUnregister (DrawablePtr	    pDrawable,
1971		  DamagePtr	    pDamage)
1972{
1973    if (pDrawable->type == DRAWABLE_WINDOW)
1974    {
1975	WindowPtr   pWindow = (WindowPtr) pDrawable;
1976	winDamageRef (pWindow);
1977#if DAMAGE_VALIDATE_ENABLE
1978	int	found = 0;
1979#endif
1980
1981	while (*pPrev)
1982	{
1983	    if (*pPrev == pDamage)
1984	    {
1985		*pPrev = pDamage->pNextWin;
1986#if DAMAGE_VALIDATE_ENABLE
1987		found = 1;
1988#endif
1989		break;
1990	    }
1991	    pPrev = &(*pPrev)->pNextWin;
1992	}
1993#if DAMAGE_VALIDATE_ENABLE
1994	if (!found) {
1995	    ErrorF ("Damage not on window list\n");
1996	    abort ();
1997	}
1998#endif
1999    }
2000    pDamage->pDrawable = 0;
2001    damageRemoveDamage (getDrawableDamageRef (pDrawable), pDamage);
2002}
2003
2004void
2005DamageDestroy (DamagePtr    pDamage)
2006{
2007    if (pDamage->damageDestroy)
2008	(*pDamage->damageDestroy) (pDamage, pDamage->closure);
2009    REGION_UNINIT (pDamage->pDrawable->pScreen, &pDamage->damage);
2010    REGION_UNINIT (pDamage->pDrawable->pScreen, &pDamage->pendingDamage);
2011    xfree (pDamage);
2012}
2013
2014Bool
2015DamageSubtract (DamagePtr	    pDamage,
2016		const RegionPtr	    pRegion)
2017{
2018    RegionPtr	pClip;
2019    RegionRec	pixmapClip;
2020    DrawablePtr	pDrawable = pDamage->pDrawable;
2021
2022    REGION_SUBTRACT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pRegion);
2023    if (pDrawable)
2024    {
2025	if (pDrawable->type == DRAWABLE_WINDOW)
2026	    pClip = &((WindowPtr) pDrawable)->borderClip;
2027	else
2028	{
2029	    BoxRec  box;
2030
2031	    box.x1 = pDrawable->x;
2032	    box.y1 = pDrawable->y;
2033	    box.x2 = pDrawable->x + pDrawable->width;
2034	    box.y2 = pDrawable->y + pDrawable->height;
2035	    REGION_INIT (pDrawable->pScreen, &pixmapClip, &box, 1);
2036	    pClip = &pixmapClip;
2037	}
2038	REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, pDrawable->x, pDrawable->y);
2039	REGION_INTERSECT (pDrawable->pScreen, &pDamage->damage, &pDamage->damage, pClip);
2040	REGION_TRANSLATE (pDrawable->pScreen, &pDamage->damage, -pDrawable->x, -pDrawable->y);
2041	if (pDrawable->type != DRAWABLE_WINDOW)
2042	    REGION_UNINIT(pDrawable->pScreen, &pixmapClip);
2043    }
2044    return REGION_NOTEMPTY (pDrawable->pScreen, &pDamage->damage);
2045}
2046
2047void
2048DamageEmpty (DamagePtr	    pDamage)
2049{
2050    REGION_EMPTY (pDamage->pDrawable->pScreen, &pDamage->damage);
2051}
2052
2053_X_EXPORT RegionPtr
2054DamageRegion (DamagePtr		    pDamage)
2055{
2056    return &pDamage->damage;
2057}
2058
2059_X_EXPORT RegionPtr
2060DamagePendingRegion (DamagePtr	    pDamage)
2061{
2062    return &pDamage->pendingDamage;
2063}
2064
2065_X_EXPORT void
2066DamageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion)
2067{
2068    damageRegionAppend (pDrawable, pRegion, FALSE, -1);
2069}
2070
2071_X_EXPORT void
2072DamageRegionProcessPending (DrawablePtr pDrawable)
2073{
2074    damageRegionProcessPending (pDrawable);
2075}
2076
2077/* If a damage marker is provided, then this function must be called after rendering is done. */
2078/* Please do call back so any future enhancements can assume this function is called. */
2079/* There are no strict timing requirements for calling this function, just as soon as (is cheaply) possible. */
2080_X_EXPORT void
2081DamageRegionRendered (DrawablePtr pDrawable, DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pRegion)
2082{
2083    if (pDamage->damageReportPostRendering)
2084	damageReportDamagePostRendering (pDamage, pOldDamage, pRegion);
2085}
2086
2087/* This call is very odd, i'm leaving it intact for API sake, but please don't use it. */
2088_X_EXPORT void
2089DamageDamageRegion (DrawablePtr	pDrawable,
2090		    RegionPtr	pRegion)
2091{
2092    damageRegionAppend (pDrawable, pRegion, FALSE, -1);
2093
2094    /* Go back and report this damage for DamagePtrs with reportAfter set, since
2095     * this call isn't part of an in-progress drawing op in the call chain and
2096     * the DDX probably just wants to know about it right away.
2097     */
2098    damageRegionProcessPending (pDrawable);
2099}
2100
2101_X_EXPORT void
2102DamageSetReportAfterOp (DamagePtr pDamage, Bool reportAfter)
2103{
2104    pDamage->reportAfter = reportAfter;
2105}
2106
2107_X_EXPORT void
2108DamageSetPostRenderingFunctions(DamagePtr pDamage, DamageReportFunc damageReportPostRendering,
2109				DamageMarkerFunc damageMarker)
2110{
2111    pDamage->damageReportPostRendering = damageReportPostRendering;
2112    pDamage->damageMarker = damageMarker;
2113}
2114