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