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