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 
72 static DevPrivateKeyRec damageScrPrivateKeyRec;
73 
74 #define damageScrPrivateKey (&damageScrPrivateKeyRec)
75 static DevPrivateKeyRec damagePixPrivateKeyRec;
76 
77 #define damagePixPrivateKey (&damagePixPrivateKeyRec)
78 static DevPrivateKeyRec damageGCPrivateKeyRec;
79 
80 #define damageGCPrivateKey (&damageGCPrivateKeyRec)
81 static DevPrivateKeyRec damageWinPrivateKeyRec;
82 
83 #define damageWinPrivateKey (&damageWinPrivateKeyRec)
84 
85 static DamagePtr *
getDrawableDamageRef(DrawablePtr pDrawable)86 getDrawableDamageRef(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
125 static void
_damageRegionAppend(DrawablePtr pDrawable,RegionPtr pRegion,Bool clip,int subWindowMode,const char * where)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
130 static void
131 damageRegionAppend(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 
285 static void
damageRegionProcessPending(DrawablePtr pDrawable)286 damageRegionProcessPending(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__)
308 static void
_damageDamageBox(DrawablePtr pDrawable,BoxPtr pBox,int subWindowMode,const char * where)309 _damageDamageBox(DrawablePtr pDrawable, BoxPtr pBox, int subWindowMode,
310                  const char *where)
311 #else
312 static void
313 damageDamageBox(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 
327 static void damageValidateGC(GCPtr, unsigned long, DrawablePtr);
328 static void damageChangeGC(GCPtr, unsigned long);
329 static void damageCopyGC(GCPtr, unsigned long, GCPtr);
330 static void damageDestroyGC(GCPtr);
331 static void damageChangeClip(GCPtr, int, void *, int);
332 static void damageDestroyClip(GCPtr);
333 static void damageCopyClip(GCPtr, GCPtr);
334 
335 static GCFuncs damageGCFuncs = {
336     damageValidateGC, damageChangeGC, damageCopyGC, damageDestroyGC,
337     damageChangeClip, damageDestroyClip, damageCopyClip
338 };
339 
340 static GCOps damageGCOps;
341 
342 static Bool
damageCreateGC(GCPtr pGC)343 damageCreateGC(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 
381 static void
damageValidateGC(GCPtr pGC,unsigned long changes,DrawablePtr pDrawable)382 damageValidateGC(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 
390 static void
damageDestroyGC(GCPtr pGC)391 damageDestroyGC(GCPtr pGC)
392 {
393     DAMAGE_GC_FUNC_PROLOGUE(pGC);
394     (*pGC->funcs->DestroyGC) (pGC);
395     DAMAGE_GC_FUNC_EPILOGUE(pGC);
396 }
397 
398 static void
damageChangeGC(GCPtr pGC,unsigned long mask)399 damageChangeGC(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 
406 static void
damageCopyGC(GCPtr pGCSrc,unsigned long mask,GCPtr pGCDst)407 damageCopyGC(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 
414 static void
damageChangeClip(GCPtr pGC,int type,void * pvalue,int nrects)415 damageChangeClip(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 
422 static void
damageCopyClip(GCPtr pgcDst,GCPtr pgcSrc)423 damageCopyClip(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 
430 static void
damageDestroyClip(GCPtr pGC)431 damageDestroyClip(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 
476 static void
damageComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)477 damageComposite(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 
522 static void
damageGlyphs(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int nlist,GlyphListPtr list,GlyphPtr * glyphs)523 damageGlyphs(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 
584 static void
damageAddTraps(PicturePtr pPicture,INT16 x_off,INT16 y_off,int ntrap,xTrap * traps)585 damageAddTraps(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 
634 static void
damageFillSpans(DrawablePtr pDrawable,GC * pGC,int npt,DDXPointPtr ppt,int * pwidth,int fSorted)635 damageFillSpans(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 
680 static void
damageSetSpans(DrawablePtr pDrawable,GCPtr pGC,char * pcharsrc,DDXPointPtr ppt,int * pwidth,int npt,int fSorted)681 damageSetSpans(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 
726 static void
damagePutImage(DrawablePtr pDrawable,GCPtr pGC,int depth,int x,int y,int w,int h,int leftPad,int format,char * pImage)727 damagePutImage(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 
752 static RegionPtr
damageCopyArea(DrawablePtr pSrc,DrawablePtr pDst,GC * pGC,int srcx,int srcy,int width,int height,int dstx,int dsty)753 damageCopyArea(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 
782 static RegionPtr
damageCopyPlane(DrawablePtr pSrc,DrawablePtr pDst,GCPtr pGC,int srcx,int srcy,int width,int height,int dstx,int dsty,unsigned long bitPlane)783 damageCopyPlane(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 
816 static void
damagePolyPoint(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,xPoint * ppt)817 damagePolyPoint(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 
876 static void
damagePolylines(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,DDXPointPtr ppt)877 damagePolylines(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 
949 static void
damagePolySegment(DrawablePtr pDrawable,GCPtr pGC,int nSeg,xSegment * pSeg)950 damagePolySegment(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 
1028 static void
damagePolyRectangle(DrawablePtr pDrawable,GCPtr pGC,int nRects,xRectangle * pRects)1029 damagePolyRectangle(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 
1087 static void
damagePolyArc(DrawablePtr pDrawable,GCPtr pGC,int nArcs,xArc * pArcs)1088 damagePolyArc(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 
1134 static void
damageFillPolygon(DrawablePtr pDrawable,GCPtr pGC,int shape,int mode,int npt,DDXPointPtr ppt)1135 damageFillPolygon(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 
1193 static void
damagePolyFillRect(DrawablePtr pDrawable,GCPtr pGC,int nRects,xRectangle * pRects)1194 damagePolyFillRect(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 
1229 static void
damagePolyFillArc(DrawablePtr pDrawable,GCPtr pGC,int nArcs,xArc * pArcs)1230 damagePolyFillArc(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 
1270 static void
damageDamageChars(DrawablePtr pDrawable,FontPtr font,int x,int y,unsigned int n,CharInfoPtr * charinfo,Bool imageblt,int subWindowMode)1271 damageDamageChars(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 
1309 static void
damageText(DrawablePtr pDrawable,GCPtr pGC,int x,int y,unsigned long count,char * chars,FontEncoding fontEncoding,Bool textType)1310 damageText(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 
1343 static int
damagePolyText8(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,char * chars)1344 damagePolyText8(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 
1356 static int
damagePolyText16(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,unsigned short * chars)1357 damagePolyText16(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 
1370 static void
damageImageText8(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,char * chars)1371 damageImageText8(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 
1382 static void
damageImageText16(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,unsigned short * chars)1383 damageImageText16(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 
1395 static void
damageImageGlyphBlt(DrawablePtr pDrawable,GCPtr pGC,int x,int y,unsigned int nglyph,CharInfoPtr * ppci,void * pglyphBase)1396 damageImageGlyphBlt(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 
1410 static void
damagePolyGlyphBlt(DrawablePtr pDrawable,GCPtr pGC,int x,int y,unsigned int nglyph,CharInfoPtr * ppci,void * pglyphBase)1411 damagePolyGlyphBlt(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 
1425 static void
damagePushPixels(GCPtr pGC,PixmapPtr pBitMap,DrawablePtr pDrawable,int dx,int dy,int xOrg,int yOrg)1426 damagePushPixels(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 
1454 static void
damageRemoveDamage(DamagePtr * pPrev,DamagePtr pDamage)1455 damageRemoveDamage(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 
1470 static void
damageInsertDamage(DamagePtr * pPrev,DamagePtr pDamage)1471 damageInsertDamage(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 
1486 static Bool
damageDestroyPixmap(PixmapPtr pPixmap)1487 damageDestroyPixmap(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 
1509 static void
damageCopyWindow(WindowPtr pWindow,DDXPointRec ptOldOrg,RegionPtr prgnSrc)1510 damageCopyWindow(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 
1534 static 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 
1547 static void
damageSetWindowPixmap(WindowPtr pWindow,PixmapPtr pPixmap)1548 damageSetWindowPixmap(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 
1577 static Bool
damageDestroyWindow(WindowPtr pWindow)1578 damageDestroyWindow(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 
1595 static Bool
damageCloseScreen(ScreenPtr pScreen)1596 damageCloseScreen(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  */
1611 void
miDamageCreate(DamagePtr pDamage)1612 miDamageCreate(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  */
1625 static int
damageRegisterVisit(WindowPtr pWin,void * data)1626 damageRegisterVisit(WindowPtr pWin, void *data)
1627 {
1628     pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1629     return WT_WALKCHILDREN;
1630 }
1631 
1632 void
miDamageRegister(DrawablePtr pDrawable,DamagePtr pDamage)1633 miDamageRegister(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 
1641 void
miDamageUnregister(DrawablePtr pDrawable,DamagePtr pDamage)1642 miDamageUnregister(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 
1650 void
miDamageDestroy(DamagePtr pDamage)1651 miDamageDestroy(DamagePtr pDamage)
1652 {
1653 }
1654 
1655 /**
1656  * Public functions for consumption outside this file.
1657  */
1658 
1659 Bool
DamageSetup(ScreenPtr pScreen)1660 DamageSetup(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 
1710 DamagePtr
DamageCreate(DamageReportFunc damageReport,DamageDestroyFunc damageDestroy,DamageReportLevel damageLevel,Bool isInternal,ScreenPtr pScreen,void * closure)1711 DamageCreate(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 
1743 void
DamageRegister(DrawablePtr pDrawable,DamagePtr pDamage)1744 DamageRegister(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 
1782 void
DamageDrawInternal(ScreenPtr pScreen,Bool enable)1783 DamageDrawInternal(ScreenPtr pScreen, Bool enable)
1784 {
1785     damageScrPriv(pScreen);
1786 
1787     pScrPriv->internalLevel += enable ? 1 : -1;
1788 }
1789 
1790 void
DamageUnregister(DamagePtr pDamage)1791 DamageUnregister(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 
1829 void
DamageDestroy(DamagePtr pDamage)1830 DamageDestroy(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 
1847 Bool
DamageSubtract(DamagePtr pDamage,const RegionPtr pRegion)1848 DamageSubtract(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 
1877 void
DamageEmpty(DamagePtr pDamage)1878 DamageEmpty(DamagePtr pDamage)
1879 {
1880     RegionEmpty(&pDamage->damage);
1881 }
1882 
1883 RegionPtr
DamageRegion(DamagePtr pDamage)1884 DamageRegion(DamagePtr pDamage)
1885 {
1886     return &pDamage->damage;
1887 }
1888 
1889 RegionPtr
DamagePendingRegion(DamagePtr pDamage)1890 DamagePendingRegion(DamagePtr pDamage)
1891 {
1892     return &pDamage->pendingDamage;
1893 }
1894 
1895 void
DamageRegionAppend(DrawablePtr pDrawable,RegionPtr pRegion)1896 DamageRegionAppend(DrawablePtr pDrawable, RegionPtr pRegion)
1897 {
1898     damageRegionAppend(pDrawable, pRegion, FALSE, -1);
1899 }
1900 
1901 void
DamageRegionProcessPending(DrawablePtr pDrawable)1902 DamageRegionProcessPending(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. */
1908 void
DamageDamageRegion(DrawablePtr pDrawable,RegionPtr pRegion)1909 DamageDamageRegion(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 
1920 void
DamageSetReportAfterOp(DamagePtr pDamage,Bool reportAfter)1921 DamageSetReportAfterOp(DamagePtr pDamage, Bool reportAfter)
1922 {
1923     pDamage->reportAfter = reportAfter;
1924 }
1925 
1926 DamageScreenFuncsPtr
DamageGetScreenFuncs(ScreenPtr pScreen)1927 DamageGetScreenFuncs(ScreenPtr pScreen)
1928 {
1929     damageScrPriv(pScreen);
1930     return &pScrPriv->funcs;
1931 }
1932 
1933 void
DamageReportDamage(DamagePtr pDamage,RegionPtr pDamageRegion)1934 DamageReportDamage(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