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