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(®ion, pBox, 1);
319 #if DAMAGE_DEBUG_ENABLE
320 _damageRegionAppend(pDrawable, ®ion, TRUE, subWindowMode, where);
321 #else
322 damageRegionAppend(pDrawable, ®ion, TRUE, subWindowMode);
323 #endif
324 RegionUninit(®ion);
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