1/* 2 * Graphics Context support for generic rootless X server 3 */ 4/* 5 * Copyright (c) 2001 Greg Parker. All Rights Reserved. 6 * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. 7 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the sale, 29 * use or other dealings in this Software without prior written authorization. 30 */ 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include <stddef.h> /* For NULL */ 37#include "mi.h" 38#include "scrnintstr.h" 39#include "gcstruct.h" 40#include "pixmapstr.h" 41#include "windowstr.h" 42#include "dixfontstr.h" 43#include "mivalidate.h" 44#include "fb.h" 45 46#include <sys/types.h> 47#include <sys/stat.h> 48#include <fcntl.h> 49 50#include "rootlessCommon.h" 51 52// GC functions 53static void RootlessValidateGC(GCPtr pGC, unsigned long changes, 54 DrawablePtr pDrawable); 55static void RootlessChangeGC(GCPtr pGC, unsigned long mask); 56static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); 57static void RootlessDestroyGC(GCPtr pGC); 58static void RootlessChangeClip(GCPtr pGC, int type, void *pvalue, int nrects); 59static void RootlessDestroyClip(GCPtr pGC); 60static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc); 61 62Bool RootlessCreateGC(GCPtr pGC); 63 64GCFuncs rootlessGCFuncs = { 65 RootlessValidateGC, 66 RootlessChangeGC, 67 RootlessCopyGC, 68 RootlessDestroyGC, 69 RootlessChangeClip, 70 RootlessDestroyClip, 71 RootlessCopyClip, 72}; 73 74// GC operations 75static void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, 76 DDXPointPtr pptInit, int *pwidthInit, int sorted); 77static void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, 78 DDXPointPtr pptInit, int *pwidthInit, 79 int nspans, int sorted); 80static void RootlessPutImage(DrawablePtr dst, GCPtr pGC, 81 int depth, int x, int y, int w, int h, 82 int leftPad, int format, char *pBits); 83static RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, 84 int srcx, int srcy, int w, int h, 85 int dstx, int dsty); 86static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst, 87 GCPtr pGC, int srcx, int srcy, 88 int w, int h, int dstx, int dsty, 89 unsigned long plane); 90static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC, 91 int mode, int npt, DDXPointPtr pptInit); 92static void RootlessPolylines(DrawablePtr dst, GCPtr pGC, 93 int mode, int npt, DDXPointPtr pptInit); 94static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC, 95 int nseg, xSegment * pSeg); 96static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC, 97 int nRects, xRectangle *pRects); 98static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, 99 xArc * parcs); 100static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, int shape, int mode, 101 int count, DDXPointPtr pptInit); 102static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, int nRectsInit, 103 xRectangle *pRectsInit); 104static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit, 105 xArc * parcsInit); 106static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, int x, int y, 107 int count, char *chars); 108static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, int x, int y, 109 int count, unsigned short *chars); 110static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, int x, int y, 111 int count, char *chars); 112static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, int x, int y, 113 int count, unsigned short *chars); 114static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y, 115 unsigned int nglyphInit, 116 CharInfoPtr * ppciInit, void *unused); 117static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y, 118 unsigned int nglyph, CharInfoPtr * ppci, 119 void *pglyphBase); 120static void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, 121 int dx, int dy, int xOrg, int yOrg); 122 123static GCOps rootlessGCOps = { 124 RootlessFillSpans, 125 RootlessSetSpans, 126 RootlessPutImage, 127 RootlessCopyArea, 128 RootlessCopyPlane, 129 RootlessPolyPoint, 130 RootlessPolylines, 131 RootlessPolySegment, 132 RootlessPolyRectangle, 133 RootlessPolyArc, 134 RootlessFillPolygon, 135 RootlessPolyFillRect, 136 RootlessPolyFillArc, 137 RootlessPolyText8, 138 RootlessPolyText16, 139 RootlessImageText8, 140 RootlessImageText16, 141 RootlessImageGlyphBlt, 142 RootlessPolyGlyphBlt, 143 RootlessPushPixels 144}; 145 146/* 147 If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha 148 channel of the on screen windows is always opaque. fb makes this harder 149 than it would otherwise be by noticing that a planemask of 0x00ffffff 150 includes all bits when depth==24, and so it "optimizes" the planemask to 151 0xffffffff. We work around this by temporarily setting depth=bpp while 152 changing the GC. 153 154 So the normal situation (in 32 bit mode) is that the planemask is 155 0x00ffffff and thus fb leaves the alpha channel alone. The rootless 156 implementation is responsible for setting the alpha channel opaque 157 initially. 158 159 Unfortunately drawing with a planemask that doesn't have all bits set 160 normally causes fb to fall off its fastest paths when blitting and 161 filling. So we try to recognize when we can relax the planemask back to 162 0xffffffff, and do that for the duration of the drawing operation, 163 setting the alpha channel in fg/bg pixels to opaque at the same time. We 164 can do this when drawing op is GXcopy. We can also do this when copying 165 from another window since its alpha channel must also be opaque. 166 167 The three macros below are used to implement this. Drawing ops that can 168 potentially have their planemask relaxed look like: 169 170 OP { 171 GC_SAVE(gc); 172 GCOP_UNWRAP(gc); 173 174 ... 175 176 if (canAccelxxx(..) && otherwise-suitable) 177 GC_UNSET_PM(gc, dst); 178 179 gc->funcs->OP(gc, ...); 180 181 GC_RESTORE(gc, dst); 182 GCOP_WRAP(gc); 183 } 184 185 */ 186 187#define GC_SAVE(pGC) \ 188 unsigned long _save_fg = (pGC)->fgPixel; \ 189 unsigned long _save_bg = (pGC)->bgPixel; \ 190 unsigned long _save_pm = (pGC)->planemask; \ 191 Bool _changed = FALSE 192 193#define GC_RESTORE(pGC, pDraw) \ 194 do { \ 195 if (_changed) { \ 196 unsigned int depth = (pDraw)->depth; \ 197 (pGC)->fgPixel = _save_fg; \ 198 (pGC)->bgPixel = _save_bg; \ 199 (pGC)->planemask = _save_pm; \ 200 (pDraw)->depth = (pDraw)->bitsPerPixel; \ 201 VALIDATE_GC(pGC, GCForeground | GCBackground | \ 202 GCPlaneMask, pDraw); \ 203 (pDraw)->depth = depth; \ 204 } \ 205 } while (0) 206 207#define GC_UNSET_PM(pGC, pDraw) \ 208 do { \ 209 unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel); \ 210 if (((pGC)->planemask & mask) != mask) { \ 211 unsigned int depth = (pDraw)->depth; \ 212 (pGC)->fgPixel |= mask; \ 213 (pGC)->bgPixel |= mask; \ 214 (pGC)->planemask |= mask; \ 215 (pDraw)->depth = (pDraw)->bitsPerPixel; \ 216 VALIDATE_GC(pGC, GCForeground | \ 217 GCBackground | GCPlaneMask, pDraw); \ 218 (pDraw)->depth = depth; \ 219 _changed = TRUE; \ 220 } \ 221 } while (0) 222 223#define VALIDATE_GC(pGC, changes, pDrawable) \ 224 do { \ 225 pGC->funcs->ValidateGC(pGC, changes, pDrawable); \ 226 if (((WindowPtr) pDrawable)->viewable) { \ 227 gcrec->originalOps = pGC->ops; \ 228 } \ 229 } while(0) 230 231static RootlessWindowRec * 232canAccelBlit(DrawablePtr pDraw, GCPtr pGC) 233{ 234 WindowPtr pTop; 235 RootlessWindowRec *winRec; 236 unsigned int pm; 237 238 if (pGC->alu != GXcopy) 239 return NULL; 240 241 if (pDraw->type != DRAWABLE_WINDOW) 242 return NULL; 243 244 pm = ~RootlessAlphaMask(pDraw->bitsPerPixel); 245 if ((pGC->planemask & pm) != pm) 246 return NULL; 247 248 pTop = TopLevelParent((WindowPtr) pDraw); 249 if (pTop == NULL) 250 return NULL; 251 252 winRec = WINREC(pTop); 253 if (winRec == NULL) 254 return NULL; 255 256 return winRec; 257} 258 259static inline RootlessWindowRec * 260canAccelFill(DrawablePtr pDraw, GCPtr pGC) 261{ 262 if (pGC->fillStyle != FillSolid) 263 return NULL; 264 265 return canAccelBlit(pDraw, pGC); 266} 267 268/* 269 * Screen function to create a graphics context 270 */ 271Bool 272RootlessCreateGC(GCPtr pGC) 273{ 274 RootlessGCRec *gcrec; 275 RootlessScreenRec *s; 276 Bool result; 277 278 SCREEN_UNWRAP(pGC->pScreen, CreateGC); 279 s = SCREENREC(pGC->pScreen); 280 result = s->CreateGC(pGC); 281 282 gcrec = (RootlessGCRec *) 283 dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey); 284 gcrec->originalOps = NULL; // don't wrap ops yet 285 gcrec->originalFuncs = pGC->funcs; 286 pGC->funcs = &rootlessGCFuncs; 287 288 SCREEN_WRAP(pGC->pScreen, CreateGC); 289 return result; 290} 291 292/* 293 * GC funcs 294 * 295 * These wrap lower level GC funcs. 296 * ValidateGC wraps the GC ops iff dest is viewable. 297 * All the others just unwrap and call. 298 */ 299 300// GCFUNC_UNRAP assumes funcs have been wrapped and 301// does not assume ops have been wrapped 302#define GCFUNC_UNWRAP(pGC) \ 303 RootlessGCRec *gcrec = (RootlessGCRec *) \ 304 dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \ 305 (pGC)->funcs = gcrec->originalFuncs; \ 306 if (gcrec->originalOps) { \ 307 (pGC)->ops = gcrec->originalOps; \ 308} 309 310#define GCFUNC_WRAP(pGC) \ 311 gcrec->originalFuncs = (pGC)->funcs; \ 312 (pGC)->funcs = &rootlessGCFuncs; \ 313 if (gcrec->originalOps) { \ 314 gcrec->originalOps = (pGC)->ops; \ 315 (pGC)->ops = &rootlessGCOps; \ 316} 317 318static void 319RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) 320{ 321 GCFUNC_UNWRAP(pGC); 322 323 gcrec->originalOps = NULL; 324 325 if (pDrawable->type == DRAWABLE_WINDOW) { 326#ifdef ROOTLESS_PROTECT_ALPHA 327 unsigned int depth = pDrawable->depth; 328 329 // We force a planemask so fb doesn't overwrite the alpha channel. 330 // Left to its own devices, fb will optimize away the planemask. 331 pDrawable->depth = pDrawable->bitsPerPixel; 332 pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel); 333 VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable); 334 pDrawable->depth = depth; 335#else 336 VALIDATE_GC(pGC, changes, pDrawable); 337#endif 338 } 339 else { 340 pGC->funcs->ValidateGC(pGC, changes, pDrawable); 341 } 342 343 GCFUNC_WRAP(pGC); 344} 345 346static void 347RootlessChangeGC(GCPtr pGC, unsigned long mask) 348{ 349 GCFUNC_UNWRAP(pGC); 350 pGC->funcs->ChangeGC(pGC, mask); 351 GCFUNC_WRAP(pGC); 352} 353 354static void 355RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) 356{ 357 GCFUNC_UNWRAP(pGCDst); 358 pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst); 359 GCFUNC_WRAP(pGCDst); 360} 361 362static void 363RootlessDestroyGC(GCPtr pGC) 364{ 365 GCFUNC_UNWRAP(pGC); 366 pGC->funcs->DestroyGC(pGC); 367 GCFUNC_WRAP(pGC); 368} 369 370static void 371RootlessChangeClip(GCPtr pGC, int type, void *pvalue, int nrects) 372{ 373 GCFUNC_UNWRAP(pGC); 374 pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); 375 GCFUNC_WRAP(pGC); 376} 377 378static void 379RootlessDestroyClip(GCPtr pGC) 380{ 381 GCFUNC_UNWRAP(pGC); 382 pGC->funcs->DestroyClip(pGC); 383 GCFUNC_WRAP(pGC); 384} 385 386static void 387RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc) 388{ 389 GCFUNC_UNWRAP(pgcDst); 390 pgcDst->funcs->CopyClip(pgcDst, pgcSrc); 391 GCFUNC_WRAP(pgcDst); 392} 393 394/* 395 * GC ops 396 * 397 * We can't use shadowfb because shadowfb assumes one pixmap 398 * and our root window is a special case. 399 * However, much of this code is copied from shadowfb. 400 */ 401 402// assumes both funcs and ops are wrapped 403#define GCOP_UNWRAP(pGC) \ 404 RootlessGCRec *gcrec = (RootlessGCRec *) \ 405 dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \ 406 const GCFuncs *saveFuncs = pGC->funcs; \ 407 (pGC)->funcs = gcrec->originalFuncs; \ 408 (pGC)->ops = gcrec->originalOps; 409 410#define GCOP_WRAP(pGC) \ 411 gcrec->originalOps = (pGC)->ops; \ 412 (pGC)->funcs = saveFuncs; \ 413 (pGC)->ops = &rootlessGCOps; 414 415static void 416RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, 417 DDXPointPtr pptInit, int *pwidthInit, int sorted) 418{ 419 GC_SAVE(pGC); 420 GCOP_UNWRAP(pGC); 421 RL_DEBUG_MSG("fill spans start "); 422 423 if (nInit <= 0) { 424 pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); 425 } 426 else { 427 DDXPointPtr ppt = pptInit; 428 int *pwidth = pwidthInit; 429 int i = nInit; 430 BoxRec box; 431 432 box.x1 = ppt->x; 433 box.x2 = box.x1 + *pwidth; 434 box.y2 = box.y1 = ppt->y; 435 436 while (--i) { 437 ppt++; 438 pwidth++; 439 if (box.x1 > ppt->x) 440 box.x1 = ppt->x; 441 if (box.x2 < (ppt->x + *pwidth)) 442 box.x2 = ppt->x + *pwidth; 443 if (box.y1 > ppt->y) 444 box.y1 = ppt->y; 445 else if (box.y2 < ppt->y) 446 box.y2 = ppt->y; 447 } 448 449 box.y2++; 450 451 RootlessStartDrawing((WindowPtr) dst); 452 453 if (canAccelFill(dst, pGC)) { 454 GC_UNSET_PM(pGC, dst); 455 } 456 457 pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); 458 459 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 460 if (BOX_NOT_EMPTY(box)) 461 RootlessDamageBox((WindowPtr) dst, &box); 462 } 463 464 GC_RESTORE(pGC, dst); 465 GCOP_WRAP(pGC); 466 RL_DEBUG_MSG("fill spans end\n"); 467} 468 469static void 470RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, 471 DDXPointPtr pptInit, int *pwidthInit, int nspans, int sorted) 472{ 473 GCOP_UNWRAP(pGC); 474 RL_DEBUG_MSG("set spans start "); 475 476 if (nspans <= 0) { 477 pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted); 478 } 479 else { 480 DDXPointPtr ppt = pptInit; 481 int *pwidth = pwidthInit; 482 int i = nspans; 483 BoxRec box; 484 485 box.x1 = ppt->x; 486 box.x2 = box.x1 + *pwidth; 487 box.y2 = box.y1 = ppt->y; 488 489 while (--i) { 490 ppt++; 491 pwidth++; 492 if (box.x1 > ppt->x) 493 box.x1 = ppt->x; 494 if (box.x2 < (ppt->x + *pwidth)) 495 box.x2 = ppt->x + *pwidth; 496 if (box.y1 > ppt->y) 497 box.y1 = ppt->y; 498 else if (box.y2 < ppt->y) 499 box.y2 = ppt->y; 500 } 501 502 box.y2++; 503 504 RootlessStartDrawing((WindowPtr) dst); 505 pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted); 506 507 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 508 if (BOX_NOT_EMPTY(box)) 509 RootlessDamageBox((WindowPtr) dst, &box); 510 } 511 GCOP_WRAP(pGC); 512 RL_DEBUG_MSG("set spans end\n"); 513} 514 515static void 516RootlessPutImage(DrawablePtr dst, GCPtr pGC, 517 int depth, int x, int y, int w, int h, 518 int leftPad, int format, char *pBits) 519{ 520 BoxRec box; 521 522 GCOP_UNWRAP(pGC); 523 RL_DEBUG_MSG("put image start "); 524 525 RootlessStartDrawing((WindowPtr) dst); 526 pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBits); 527 528 box.x1 = x + dst->x; 529 box.x2 = box.x1 + w; 530 box.y1 = y + dst->y; 531 box.y2 = box.y1 + h; 532 533 TRIM_BOX(box, pGC); 534 if (BOX_NOT_EMPTY(box)) 535 RootlessDamageBox((WindowPtr) dst, &box); 536 537 GCOP_WRAP(pGC); 538 RL_DEBUG_MSG("put image end\n"); 539} 540 541/* changed area is *dest* rect */ 542static RegionPtr 543RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, 544 int srcx, int srcy, int w, int h, int dstx, int dsty) 545{ 546 RegionPtr result; 547 BoxRec box; 548 549 GC_SAVE(pGC); 550 GCOP_UNWRAP(pGC); 551 552 RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst); 553 554 if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) { 555 /* If both source and dest are windows, and we're doing 556 a simple copy operation, we can remove the alpha-protecting 557 planemask (since source has opaque alpha as well) */ 558 559 if (canAccelBlit(pSrc, pGC)) { 560 GC_UNSET_PM(pGC, dst); 561 } 562 563 RootlessStartDrawing((WindowPtr) pSrc); 564 } 565 RootlessStartDrawing((WindowPtr) dst); 566 result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty); 567 568 box.x1 = dstx + dst->x; 569 box.x2 = box.x1 + w; 570 box.y1 = dsty + dst->y; 571 box.y2 = box.y1 + h; 572 573 TRIM_BOX(box, pGC); 574 if (BOX_NOT_EMPTY(box)) 575 RootlessDamageBox((WindowPtr) dst, &box); 576 577 GC_RESTORE(pGC, dst); 578 GCOP_WRAP(pGC); 579 RL_DEBUG_MSG("copy area end\n"); 580 return result; 581} 582 583/* changed area is *dest* rect */ 584static RegionPtr 585RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst, 586 GCPtr pGC, int srcx, int srcy, 587 int w, int h, int dstx, int dsty, unsigned long plane) 588{ 589 RegionPtr result; 590 BoxRec box; 591 592 GCOP_UNWRAP(pGC); 593 594 RL_DEBUG_MSG("copy plane start "); 595 596 if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) { 597 RootlessStartDrawing((WindowPtr) pSrc); 598 } 599 RootlessStartDrawing((WindowPtr) dst); 600 result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, 601 dstx, dsty, plane); 602 603 box.x1 = dstx + dst->x; 604 box.x2 = box.x1 + w; 605 box.y1 = dsty + dst->y; 606 box.y2 = box.y1 + h; 607 608 TRIM_BOX(box, pGC); 609 if (BOX_NOT_EMPTY(box)) 610 RootlessDamageBox((WindowPtr) dst, &box); 611 612 GCOP_WRAP(pGC); 613 RL_DEBUG_MSG("copy plane end\n"); 614 return result; 615} 616 617// Options for size of changed area: 618// 0 = box per point 619// 1 = big box around all points 620// 2 = accumulate point in 20 pixel radius 621#define ROOTLESS_CHANGED_AREA 1 622#define abs(a) ((a) > 0 ? (a) : -(a)) 623 624/* changed area is box around all points */ 625static void 626RootlessPolyPoint(DrawablePtr dst, GCPtr pGC, 627 int mode, int npt, DDXPointPtr pptInit) 628{ 629 GCOP_UNWRAP(pGC); 630 RL_DEBUG_MSG("polypoint start "); 631 632 RootlessStartDrawing((WindowPtr) dst); 633 pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit); 634 635 if (npt > 0) { 636#if ROOTLESS_CHANGED_AREA==0 637 // box per point 638 BoxRec box; 639 640 while (npt) { 641 box.x1 = pptInit->x; 642 box.y1 = pptInit->y; 643 box.x2 = box.x1 + 1; 644 box.y2 = box.y1 + 1; 645 646 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 647 if (BOX_NOT_EMPTY(box)) 648 RootlessDamageBox((WindowPtr) dst, &box); 649 650 npt--; 651 pptInit++; 652 } 653 654#elif ROOTLESS_CHANGED_AREA==1 655 // one big box 656 BoxRec box; 657 658 box.x2 = box.x1 = pptInit->x; 659 box.y2 = box.y1 = pptInit->y; 660 while (--npt) { 661 pptInit++; 662 if (box.x1 > pptInit->x) 663 box.x1 = pptInit->x; 664 else if (box.x2 < pptInit->x) 665 box.x2 = pptInit->x; 666 if (box.y1 > pptInit->y) 667 box.y1 = pptInit->y; 668 else if (box.y2 < pptInit->y) 669 box.y2 = pptInit->y; 670 } 671 672 box.x2++; 673 box.y2++; 674 675 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 676 if (BOX_NOT_EMPTY(box)) 677 RootlessDamageBox((WindowPtr) dst, &box); 678 679#elif ROOTLESS_CHANGED_AREA==2 680 // clever(?) method: accumulate point in 20-pixel radius 681 BoxRec box; 682 int firstx, firsty; 683 684 box.x2 = box.x1 = firstx = pptInit->x; 685 box.y2 = box.y1 = firsty = pptInit->y; 686 while (--npt) { 687 pptInit++; 688 if (abs(pptInit->x - firstx) > 20 || abs(pptInit->y - firsty) > 20) { 689 box.x2++; 690 box.y2++; 691 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 692 if (BOX_NOT_EMPTY(box)) 693 RootlessDamageBox((WindowPtr) dst, &box); 694 box.x2 = box.x1 = firstx = pptInit->x; 695 box.y2 = box.y1 = firsty = pptInit->y; 696 } 697 else { 698 if (box.x1 > pptInit->x) 699 box.x1 = pptInit->x; 700 else if (box.x2 < pptInit->x) 701 box.x2 = pptInit->x; 702 if (box.y1 > pptInit->y) 703 box.y1 = pptInit->y; 704 else if (box.y2 < pptInit->y) 705 box.y2 = pptInit->y; 706 } 707 } 708 box.x2++; 709 box.y2++; 710 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 711 if (BOX_NOT_EMPTY(box)) 712 RootlessDamageBox((WindowPtr) dst, &box); 713#endif /* ROOTLESS_CHANGED_AREA */ 714 } 715 716 GCOP_WRAP(pGC); 717 RL_DEBUG_MSG("polypoint end\n"); 718} 719 720#undef ROOTLESS_CHANGED_AREA 721 722/* changed area is box around each line */ 723static void 724RootlessPolylines(DrawablePtr dst, GCPtr pGC, 725 int mode, int npt, DDXPointPtr pptInit) 726{ 727 GCOP_UNWRAP(pGC); 728 RL_DEBUG_MSG("poly lines start "); 729 730 RootlessStartDrawing((WindowPtr) dst); 731 pGC->ops->Polylines(dst, pGC, mode, npt, pptInit); 732 733 if (npt > 0) { 734 BoxRec box; 735 int extra = pGC->lineWidth >> 1; 736 737 box.x2 = box.x1 = pptInit->x; 738 box.y2 = box.y1 = pptInit->y; 739 740 if (npt > 1) { 741 if (pGC->joinStyle == JoinMiter) 742 extra = 6 * pGC->lineWidth; 743 else if (pGC->capStyle == CapProjecting) 744 extra = pGC->lineWidth; 745 } 746 747 if (mode == CoordModePrevious) { 748 int x = box.x1; 749 int y = box.y1; 750 751 while (--npt) { 752 pptInit++; 753 x += pptInit->x; 754 y += pptInit->y; 755 if (box.x1 > x) 756 box.x1 = x; 757 else if (box.x2 < x) 758 box.x2 = x; 759 if (box.y1 > y) 760 box.y1 = y; 761 else if (box.y2 < y) 762 box.y2 = y; 763 } 764 } 765 else { 766 while (--npt) { 767 pptInit++; 768 if (box.x1 > pptInit->x) 769 box.x1 = pptInit->x; 770 else if (box.x2 < pptInit->x) 771 box.x2 = pptInit->x; 772 if (box.y1 > pptInit->y) 773 box.y1 = pptInit->y; 774 else if (box.y2 < pptInit->y) 775 box.y2 = pptInit->y; 776 } 777 } 778 779 box.x2++; 780 box.y2++; 781 782 if (extra) { 783 box.x1 -= extra; 784 box.x2 += extra; 785 box.y1 -= extra; 786 box.y2 += extra; 787 } 788 789 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 790 if (BOX_NOT_EMPTY(box)) 791 RootlessDamageBox((WindowPtr) dst, &box); 792 } 793 794 GCOP_WRAP(pGC); 795 RL_DEBUG_MSG("poly lines end\n"); 796} 797 798/* changed area is box around each line segment */ 799static void 800RootlessPolySegment(DrawablePtr dst, GCPtr pGC, int nseg, xSegment * pSeg) 801{ 802 GCOP_UNWRAP(pGC); 803 RL_DEBUG_MSG("poly segment start (win 0x%x)", dst); 804 805 RootlessStartDrawing((WindowPtr) dst); 806 pGC->ops->PolySegment(dst, pGC, nseg, pSeg); 807 808 if (nseg > 0) { 809 BoxRec box; 810 int extra = pGC->lineWidth; 811 812 if (pGC->capStyle != CapProjecting) 813 extra >>= 1; 814 815 if (pSeg->x2 > pSeg->x1) { 816 box.x1 = pSeg->x1; 817 box.x2 = pSeg->x2; 818 } 819 else { 820 box.x2 = pSeg->x1; 821 box.x1 = pSeg->x2; 822 } 823 824 if (pSeg->y2 > pSeg->y1) { 825 box.y1 = pSeg->y1; 826 box.y2 = pSeg->y2; 827 } 828 else { 829 box.y2 = pSeg->y1; 830 box.y1 = pSeg->y2; 831 } 832 833 while (--nseg) { 834 pSeg++; 835 if (pSeg->x2 > pSeg->x1) { 836 if (pSeg->x1 < box.x1) 837 box.x1 = pSeg->x1; 838 if (pSeg->x2 > box.x2) 839 box.x2 = pSeg->x2; 840 } 841 else { 842 if (pSeg->x2 < box.x1) 843 box.x1 = pSeg->x2; 844 if (pSeg->x1 > box.x2) 845 box.x2 = pSeg->x1; 846 } 847 if (pSeg->y2 > pSeg->y1) { 848 if (pSeg->y1 < box.y1) 849 box.y1 = pSeg->y1; 850 if (pSeg->y2 > box.y2) 851 box.y2 = pSeg->y2; 852 } 853 else { 854 if (pSeg->y2 < box.y1) 855 box.y1 = pSeg->y2; 856 if (pSeg->y1 > box.y2) 857 box.y2 = pSeg->y1; 858 } 859 } 860 861 box.x2++; 862 box.y2++; 863 864 if (extra) { 865 box.x1 -= extra; 866 box.x2 += extra; 867 box.y1 -= extra; 868 box.y2 += extra; 869 } 870 871 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 872 if (BOX_NOT_EMPTY(box)) 873 RootlessDamageBox((WindowPtr) dst, &box); 874 } 875 876 GCOP_WRAP(pGC); 877 RL_DEBUG_MSG("poly segment end\n"); 878} 879 880/* changed area is box around each line (not entire rects) */ 881static void 882RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC, 883 int nRects, xRectangle *pRects) 884{ 885 GCOP_UNWRAP(pGC); 886 RL_DEBUG_MSG("poly rectangle start "); 887 888 RootlessStartDrawing((WindowPtr) dst); 889 pGC->ops->PolyRectangle(dst, pGC, nRects, pRects); 890 891 if (nRects > 0) { 892 BoxRec box; 893 int offset1, offset2, offset3; 894 895 offset2 = pGC->lineWidth; 896 if (!offset2) 897 offset2 = 1; 898 offset1 = offset2 >> 1; 899 offset3 = offset2 - offset1; 900 901 while (nRects--) { 902 box.x1 = pRects->x - offset1; 903 box.y1 = pRects->y - offset1; 904 box.x2 = box.x1 + pRects->width + offset2; 905 box.y2 = box.y1 + offset2; 906 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 907 if (BOX_NOT_EMPTY(box)) 908 RootlessDamageBox((WindowPtr) dst, &box); 909 910 box.x1 = pRects->x - offset1; 911 box.y1 = pRects->y + offset3; 912 box.x2 = box.x1 + offset2; 913 box.y2 = box.y1 + pRects->height - offset2; 914 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 915 if (BOX_NOT_EMPTY(box)) 916 RootlessDamageBox((WindowPtr) dst, &box); 917 918 box.x1 = pRects->x + pRects->width - offset1; 919 box.y1 = pRects->y + offset3; 920 box.x2 = box.x1 + offset2; 921 box.y2 = box.y1 + pRects->height - offset2; 922 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 923 if (BOX_NOT_EMPTY(box)) 924 RootlessDamageBox((WindowPtr) dst, &box); 925 926 box.x1 = pRects->x - offset1; 927 box.y1 = pRects->y + pRects->height - offset1; 928 box.x2 = box.x1 + pRects->width + offset2; 929 box.y2 = box.y1 + offset2; 930 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 931 if (BOX_NOT_EMPTY(box)) 932 RootlessDamageBox((WindowPtr) dst, &box); 933 934 pRects++; 935 } 936 } 937 938 GCOP_WRAP(pGC); 939 RL_DEBUG_MSG("poly rectangle end\n"); 940} 941 942/* changed area is box around each arc (assumes all arcs are 360 degrees) */ 943static void 944RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc * parcs) 945{ 946 GCOP_UNWRAP(pGC); 947 RL_DEBUG_MSG("poly arc start "); 948 949 RootlessStartDrawing((WindowPtr) dst); 950 pGC->ops->PolyArc(dst, pGC, narcs, parcs); 951 952 if (narcs > 0) { 953 int extra = pGC->lineWidth >> 1; 954 BoxRec box; 955 956 box.x1 = parcs->x; 957 box.x2 = box.x1 + parcs->width; 958 box.y1 = parcs->y; 959 box.y2 = box.y1 + parcs->height; 960 961 /* should I break these up instead ? */ 962 963 while (--narcs) { 964 parcs++; 965 if (box.x1 > parcs->x) 966 box.x1 = parcs->x; 967 if (box.x2 < (parcs->x + parcs->width)) 968 box.x2 = parcs->x + parcs->width; 969 if (box.y1 > parcs->y) 970 box.y1 = parcs->y; 971 if (box.y2 < (parcs->y + parcs->height)) 972 box.y2 = parcs->y + parcs->height; 973 } 974 975 if (extra) { 976 box.x1 -= extra; 977 box.x2 += extra; 978 box.y1 -= extra; 979 box.y2 += extra; 980 } 981 982 box.x2++; 983 box.y2++; 984 985 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 986 if (BOX_NOT_EMPTY(box)) 987 RootlessDamageBox((WindowPtr) dst, &box); 988 } 989 990 GCOP_WRAP(pGC); 991 RL_DEBUG_MSG("poly arc end\n"); 992} 993 994/* changed area is box around each poly */ 995static void 996RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, 997 int shape, int mode, int count, DDXPointPtr pptInit) 998{ 999 GC_SAVE(pGC); 1000 GCOP_UNWRAP(pGC); 1001 RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst, 1002 pGC->fillStyle); 1003 1004 if (count <= 2) { 1005 pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); 1006 } 1007 else { 1008 DDXPointPtr ppt = pptInit; 1009 int i = count; 1010 BoxRec box; 1011 1012 box.x2 = box.x1 = ppt->x; 1013 box.y2 = box.y1 = ppt->y; 1014 1015 if (mode != CoordModeOrigin) { 1016 int x = box.x1; 1017 int y = box.y1; 1018 1019 while (--i) { 1020 ppt++; 1021 x += ppt->x; 1022 y += ppt->y; 1023 if (box.x1 > x) 1024 box.x1 = x; 1025 else if (box.x2 < x) 1026 box.x2 = x; 1027 if (box.y1 > y) 1028 box.y1 = y; 1029 else if (box.y2 < y) 1030 box.y2 = y; 1031 } 1032 } 1033 else { 1034 while (--i) { 1035 ppt++; 1036 if (box.x1 > ppt->x) 1037 box.x1 = ppt->x; 1038 else if (box.x2 < ppt->x) 1039 box.x2 = ppt->x; 1040 if (box.y1 > ppt->y) 1041 box.y1 = ppt->y; 1042 else if (box.y2 < ppt->y) 1043 box.y2 = ppt->y; 1044 } 1045 } 1046 1047 box.x2++; 1048 box.y2++; 1049 1050 RootlessStartDrawing((WindowPtr) dst); 1051 1052 if (canAccelFill(dst, pGC)) { 1053 GC_UNSET_PM(pGC, dst); 1054 } 1055 1056 pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); 1057 1058 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 1059 if (BOX_NOT_EMPTY(box)) 1060 RootlessDamageBox((WindowPtr) dst, &box); 1061 } 1062 1063 GC_RESTORE(pGC, dst); 1064 GCOP_WRAP(pGC); 1065 RL_DEBUG_MSG("fill poly end\n"); 1066} 1067 1068/* changed area is the rects */ 1069static void 1070RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, 1071 int nRectsInit, xRectangle *pRectsInit) 1072{ 1073 GC_SAVE(pGC); 1074 GCOP_UNWRAP(pGC); 1075 RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst, 1076 pGC->fillStyle); 1077 1078 if (nRectsInit <= 0) { 1079 pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); 1080 } 1081 else { 1082 BoxRec box; 1083 xRectangle *pRects = pRectsInit; 1084 int nRects = nRectsInit; 1085 1086 box.x1 = pRects->x; 1087 box.x2 = box.x1 + pRects->width; 1088 box.y1 = pRects->y; 1089 box.y2 = box.y1 + pRects->height; 1090 1091 while (--nRects) { 1092 pRects++; 1093 if (box.x1 > pRects->x) 1094 box.x1 = pRects->x; 1095 if (box.x2 < (pRects->x + pRects->width)) 1096 box.x2 = pRects->x + pRects->width; 1097 if (box.y1 > pRects->y) 1098 box.y1 = pRects->y; 1099 if (box.y2 < (pRects->y + pRects->height)) 1100 box.y2 = pRects->y + pRects->height; 1101 } 1102 1103 RootlessStartDrawing((WindowPtr) dst); 1104 1105 if (canAccelFill(dst, pGC)) { 1106 GC_UNSET_PM(pGC, dst); 1107 } 1108 1109 pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); 1110 1111 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 1112 if (BOX_NOT_EMPTY(box)) 1113 RootlessDamageBox((WindowPtr) dst, &box); 1114 } 1115 1116 GC_RESTORE(pGC, dst); 1117 GCOP_WRAP(pGC); 1118 RL_DEBUG_MSG("fill rect end\n"); 1119} 1120 1121/* changed area is box around each arc (assuming arcs are all 360 degrees) */ 1122static void 1123RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit, xArc * parcsInit) 1124{ 1125 GC_SAVE(pGC); 1126 GCOP_UNWRAP(pGC); 1127 RL_DEBUG_MSG("fill arc start "); 1128 1129 if (narcsInit > 0) { 1130 BoxRec box; 1131 int narcs = narcsInit; 1132 xArc *parcs = parcsInit; 1133 1134 box.x1 = parcs->x; 1135 box.x2 = box.x1 + parcs->width; 1136 box.y1 = parcs->y; 1137 box.y2 = box.y1 + parcs->height; 1138 1139 /* should I break these up instead ? */ 1140 1141 while (--narcs) { 1142 parcs++; 1143 if (box.x1 > parcs->x) 1144 box.x1 = parcs->x; 1145 if (box.x2 < (parcs->x + parcs->width)) 1146 box.x2 = parcs->x + parcs->width; 1147 if (box.y1 > parcs->y) 1148 box.y1 = parcs->y; 1149 if (box.y2 < (parcs->y + parcs->height)) 1150 box.y2 = parcs->y + parcs->height; 1151 } 1152 1153 RootlessStartDrawing((WindowPtr) dst); 1154 1155 if (canAccelFill(dst, pGC)) { 1156 GC_UNSET_PM(pGC, dst); 1157 } 1158 1159 pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); 1160 1161 TRIM_AND_TRANSLATE_BOX(box, dst, pGC); 1162 if (BOX_NOT_EMPTY(box)) 1163 RootlessDamageBox((WindowPtr) dst, &box); 1164 } 1165 else { 1166 pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); 1167 } 1168 1169 GC_RESTORE(pGC, dst); 1170 GCOP_WRAP(pGC); 1171 RL_DEBUG_MSG("fill arc end\n"); 1172} 1173 1174static void 1175RootlessImageText8(DrawablePtr dst, GCPtr pGC, 1176 int x, int y, int count, char *chars) 1177{ 1178 GC_SAVE(pGC); 1179 GCOP_UNWRAP(pGC); 1180 RL_DEBUG_MSG("imagetext8 start "); 1181 1182 if (count > 0) { 1183 int top, bot, Min, Max; 1184 BoxRec box; 1185 1186 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); 1187 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); 1188 1189 Min = count * FONTMINBOUNDS(pGC->font, characterWidth); 1190 if (Min > 0) 1191 Min = 0; 1192 Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); 1193 if (Max < 0) 1194 Max = 0; 1195 1196 /* ugh */ 1197 box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing); 1198 box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing); 1199 1200 box.y1 = dst->y + y - top; 1201 box.y2 = dst->y + y + bot; 1202 1203 RootlessStartDrawing((WindowPtr) dst); 1204 1205 if (canAccelFill(dst, pGC)) { 1206 GC_UNSET_PM(pGC, dst); 1207 } 1208 1209 pGC->ops->ImageText8(dst, pGC, x, y, count, chars); 1210 1211 TRIM_BOX(box, pGC); 1212 if (BOX_NOT_EMPTY(box)) 1213 RootlessDamageBox((WindowPtr) dst, &box); 1214 } 1215 else { 1216 pGC->ops->ImageText8(dst, pGC, x, y, count, chars); 1217 } 1218 1219 GC_RESTORE(pGC, dst); 1220 GCOP_WRAP(pGC); 1221 RL_DEBUG_MSG("imagetext8 end\n"); 1222} 1223 1224static int 1225RootlessPolyText8(DrawablePtr dst, GCPtr pGC, 1226 int x, int y, int count, char *chars) 1227{ 1228 int width; // the result, sorta 1229 1230 GCOP_UNWRAP(pGC); 1231 1232 RL_DEBUG_MSG("polytext8 start "); 1233 1234 RootlessStartDrawing((WindowPtr) dst); 1235 width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars); 1236 width -= x; 1237 1238 if (width > 0) { 1239 BoxRec box; 1240 1241 /* ugh */ 1242 box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); 1243 box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); 1244 1245 if (count > 1) { 1246 box.x2 += width; 1247 } 1248 1249 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); 1250 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); 1251 1252 TRIM_BOX(box, pGC); 1253 if (BOX_NOT_EMPTY(box)) 1254 RootlessDamageBox((WindowPtr) dst, &box); 1255 } 1256 1257 GCOP_WRAP(pGC); 1258 RL_DEBUG_MSG("polytext8 end\n"); 1259 return width + x; 1260} 1261 1262static void 1263RootlessImageText16(DrawablePtr dst, GCPtr pGC, 1264 int x, int y, int count, unsigned short *chars) 1265{ 1266 GC_SAVE(pGC); 1267 GCOP_UNWRAP(pGC); 1268 RL_DEBUG_MSG("imagetext16 start "); 1269 1270 if (count > 0) { 1271 int top, bot, Min, Max; 1272 BoxRec box; 1273 1274 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); 1275 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); 1276 1277 Min = count * FONTMINBOUNDS(pGC->font, characterWidth); 1278 if (Min > 0) 1279 Min = 0; 1280 Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); 1281 if (Max < 0) 1282 Max = 0; 1283 1284 /* ugh */ 1285 box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing); 1286 box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing); 1287 1288 box.y1 = dst->y + y - top; 1289 box.y2 = dst->y + y + bot; 1290 1291 RootlessStartDrawing((WindowPtr) dst); 1292 1293 if (canAccelFill(dst, pGC)) { 1294 GC_UNSET_PM(pGC, dst); 1295 } 1296 1297 pGC->ops->ImageText16(dst, pGC, x, y, count, chars); 1298 1299 TRIM_BOX(box, pGC); 1300 if (BOX_NOT_EMPTY(box)) 1301 RootlessDamageBox((WindowPtr) dst, &box); 1302 } 1303 else { 1304 pGC->ops->ImageText16(dst, pGC, x, y, count, chars); 1305 } 1306 1307 GC_RESTORE(pGC, dst); 1308 GCOP_WRAP(pGC); 1309 RL_DEBUG_MSG("imagetext16 end\n"); 1310} 1311 1312static int 1313RootlessPolyText16(DrawablePtr dst, GCPtr pGC, 1314 int x, int y, int count, unsigned short *chars) 1315{ 1316 int width; // the result, sorta 1317 1318 GCOP_UNWRAP(pGC); 1319 1320 RL_DEBUG_MSG("polytext16 start "); 1321 1322 RootlessStartDrawing((WindowPtr) dst); 1323 width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars); 1324 width -= x; 1325 1326 if (width > 0) { 1327 BoxRec box; 1328 1329 /* ugh */ 1330 box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); 1331 box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); 1332 1333 if (count > 1) { 1334 box.x2 += width; 1335 } 1336 1337 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); 1338 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); 1339 1340 TRIM_BOX(box, pGC); 1341 if (BOX_NOT_EMPTY(box)) 1342 RootlessDamageBox((WindowPtr) dst, &box); 1343 } 1344 1345 GCOP_WRAP(pGC); 1346 RL_DEBUG_MSG("polytext16 end\n"); 1347 return width + x; 1348} 1349 1350static void 1351RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, 1352 int x, int y, unsigned int nglyphInit, 1353 CharInfoPtr * ppciInit, void *unused) 1354{ 1355 GC_SAVE(pGC); 1356 GCOP_UNWRAP(pGC); 1357 RL_DEBUG_MSG("imageglyph start "); 1358 1359 if (nglyphInit > 0) { 1360 int top, bot, width = 0; 1361 BoxRec box; 1362 unsigned int nglyph = nglyphInit; 1363 CharInfoPtr *ppci = ppciInit; 1364 1365 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); 1366 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); 1367 1368 box.x1 = ppci[0]->metrics.leftSideBearing; 1369 if (box.x1 > 0) 1370 box.x1 = 0; 1371 box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - 1372 ppci[nglyph - 1]->metrics.characterWidth; 1373 if (box.x2 < 0) 1374 box.x2 = 0; 1375 1376 box.x2 += dst->x + x; 1377 box.x1 += dst->x + x; 1378 1379 while (nglyph--) { 1380 width += (*ppci)->metrics.characterWidth; 1381 ppci++; 1382 } 1383 1384 if (width > 0) 1385 box.x2 += width; 1386 else 1387 box.x1 += width; 1388 1389 box.y1 = dst->y + y - top; 1390 box.y2 = dst->y + y + bot; 1391 1392 RootlessStartDrawing((WindowPtr) dst); 1393 1394 if (canAccelFill(dst, pGC)) { 1395 GC_UNSET_PM(pGC, dst); 1396 } 1397 1398 pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); 1399 1400 TRIM_BOX(box, pGC); 1401 if (BOX_NOT_EMPTY(box)) 1402 RootlessDamageBox((WindowPtr) dst, &box); 1403 } 1404 else { 1405 pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); 1406 } 1407 1408 GC_RESTORE(pGC, dst); 1409 GCOP_WRAP(pGC); 1410 RL_DEBUG_MSG("imageglyph end\n"); 1411} 1412 1413static void 1414RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, 1415 int x, int y, unsigned int nglyph, 1416 CharInfoPtr * ppci, void *pglyphBase) 1417{ 1418 GCOP_UNWRAP(pGC); 1419 RL_DEBUG_MSG("polyglyph start "); 1420 1421 RootlessStartDrawing((WindowPtr) dst); 1422 pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase); 1423 1424 if (nglyph > 0) { 1425 BoxRec box; 1426 1427 /* ugh */ 1428 box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing; 1429 box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing; 1430 1431 if (nglyph > 1) { 1432 int width = 0; 1433 1434 while (--nglyph) { 1435 width += (*ppci)->metrics.characterWidth; 1436 ppci++; 1437 } 1438 1439 if (width > 0) 1440 box.x2 += width; 1441 else 1442 box.x1 += width; 1443 } 1444 1445 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); 1446 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); 1447 1448 TRIM_BOX(box, pGC); 1449 if (BOX_NOT_EMPTY(box)) 1450 RootlessDamageBox((WindowPtr) dst, &box); 1451 } 1452 1453 GCOP_WRAP(pGC); 1454 RL_DEBUG_MSG("polyglyph end\n"); 1455} 1456 1457/* changed area is in dest */ 1458static void 1459RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, 1460 int dx, int dy, int xOrg, int yOrg) 1461{ 1462 BoxRec box; 1463 1464 GCOP_UNWRAP(pGC); 1465 RL_DEBUG_MSG("push pixels start "); 1466 1467 RootlessStartDrawing((WindowPtr) dst); 1468 pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg); 1469 1470 box.x1 = xOrg + dst->x; 1471 box.x2 = box.x1 + dx; 1472 box.y1 = yOrg + dst->y; 1473 box.y2 = box.y1 + dy; 1474 1475 TRIM_BOX(box, pGC); 1476 if (BOX_NOT_EMPTY(box)) 1477 RootlessDamageBox((WindowPtr) dst, &box); 1478 1479 GCOP_WRAP(pGC); 1480 RL_DEBUG_MSG("push pixels end\n"); 1481} 1482