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