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