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