fbseg.c revision 05b261ec
1/* 2 * Copyright © 1998 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Keith Packard not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Keith Packard makes no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_DIX_CONFIG_H 24#include <dix-config.h> 25#endif 26 27#include <stdlib.h> 28 29#include "fb.h" 30#include "miline.h" 31 32#define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \ 33 ((dir < 0) ? FbStipLeft(mask,bpp) : \ 34 FbStipRight(mask,bpp))) 35 36void 37fbBresSolid (DrawablePtr pDrawable, 38 GCPtr pGC, 39 int dashOffset, 40 int signdx, 41 int signdy, 42 int axis, 43 int x1, 44 int y1, 45 int e, 46 int e1, 47 int e3, 48 int len) 49{ 50 FbStip *dst; 51 FbStride dstStride; 52 int dstBpp; 53 int dstXoff, dstYoff; 54 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 55 FbStip and = (FbStip) pPriv->and; 56 FbStip xor = (FbStip) pPriv->xor; 57 FbStip mask, mask0; 58 FbStip bits; 59 60 fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 61 dst += ((y1 + dstYoff) * dstStride); 62 x1 = (x1 + dstXoff) * dstBpp; 63 dst += x1 >> FB_STIP_SHIFT; 64 x1 &= FB_STIP_MASK; 65 mask0 = FbStipMask(0, dstBpp); 66 mask = FbStipRight (mask0, x1); 67 if (signdx < 0) 68 mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp); 69 if (signdy < 0) 70 dstStride = -dstStride; 71 if (axis == X_AXIS) 72 { 73 bits = 0; 74 while (len--) 75 { 76 bits |= mask; 77 mask = fbBresShiftMask(mask,signdx,dstBpp); 78 if (!mask) 79 { 80 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); 81 bits = 0; 82 dst += signdx; 83 mask = mask0; 84 } 85 e += e1; 86 if (e >= 0) 87 { 88 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); 89 bits = 0; 90 dst += dstStride; 91 e += e3; 92 } 93 } 94 if (bits) 95 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); 96 } 97 else 98 { 99 while (len--) 100 { 101 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask)); 102 dst += dstStride; 103 e += e1; 104 if (e >= 0) 105 { 106 e += e3; 107 mask = fbBresShiftMask(mask,signdx,dstBpp); 108 if (!mask) 109 { 110 dst += signdx; 111 mask = mask0; 112 } 113 } 114 } 115 } 116 117 fbFinishAccess (pDrawable); 118} 119 120void 121fbBresDash (DrawablePtr pDrawable, 122 GCPtr pGC, 123 int dashOffset, 124 int signdx, 125 int signdy, 126 int axis, 127 int x1, 128 int y1, 129 int e, 130 int e1, 131 int e3, 132 int len) 133{ 134 FbStip *dst; 135 FbStride dstStride; 136 int dstBpp; 137 int dstXoff, dstYoff; 138 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 139 FbStip and = (FbStip) pPriv->and; 140 FbStip xor = (FbStip) pPriv->xor; 141 FbStip bgand = (FbStip) pPriv->bgand; 142 FbStip bgxor = (FbStip) pPriv->bgxor; 143 FbStip mask, mask0; 144 FbDashDeclare; 145 int dashlen; 146 Bool even; 147 Bool doOdd; 148 149 fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 150 doOdd = pGC->lineStyle == LineDoubleDash; 151 152 FbDashInit (pGC, pPriv, dashOffset, dashlen, even); 153 154 dst += ((y1 + dstYoff) * dstStride); 155 x1 = (x1 + dstXoff) * dstBpp; 156 dst += x1 >> FB_STIP_SHIFT; 157 x1 &= FB_STIP_MASK; 158 mask0 = FbStipMask(0, dstBpp); 159 mask = FbStipRight (mask0, x1); 160 if (signdx < 0) 161 mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp); 162 if (signdy < 0) 163 dstStride = -dstStride; 164 while (len--) 165 { 166 if (even) 167 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask)); 168 else if (doOdd) 169 WRITE(dst, FbDoMaskRRop (READ(dst), bgand, bgxor, mask)); 170 if (axis == X_AXIS) 171 { 172 mask = fbBresShiftMask(mask,signdx,dstBpp); 173 if (!mask) 174 { 175 dst += signdx; 176 mask = mask0; 177 } 178 e += e1; 179 if (e >= 0) 180 { 181 dst += dstStride; 182 e += e3; 183 } 184 } 185 else 186 { 187 dst += dstStride; 188 e += e1; 189 if (e >= 0) 190 { 191 e += e3; 192 mask = fbBresShiftMask(mask,signdx,dstBpp); 193 if (!mask) 194 { 195 dst += signdx; 196 mask = mask0; 197 } 198 } 199 } 200 FbDashStep (dashlen, even); 201 } 202 203 fbFinishAccess (pDrawable); 204} 205 206void 207fbBresFill (DrawablePtr pDrawable, 208 GCPtr pGC, 209 int dashOffset, 210 int signdx, 211 int signdy, 212 int axis, 213 int x1, 214 int y1, 215 int e, 216 int e1, 217 int e3, 218 int len) 219{ 220 while (len--) 221 { 222 fbFill (pDrawable, pGC, x1, y1, 1, 1); 223 if (axis == X_AXIS) 224 { 225 x1 += signdx; 226 e += e1; 227 if (e >= 0) 228 { 229 e += e3; 230 y1 += signdy; 231 } 232 } 233 else 234 { 235 y1 += signdy; 236 e += e1; 237 if (e >= 0) 238 { 239 e += e3; 240 x1 += signdx; 241 } 242 } 243 } 244} 245 246static void 247fbSetFg (DrawablePtr pDrawable, 248 GCPtr pGC, 249 Pixel fg) 250{ 251 if (fg != pGC->fgPixel) 252 { 253 DoChangeGC (pGC, GCForeground, (XID *) &fg, FALSE); 254 ValidateGC (pDrawable, pGC); 255 } 256} 257 258void 259fbBresFillDash (DrawablePtr pDrawable, 260 GCPtr pGC, 261 int dashOffset, 262 int signdx, 263 int signdy, 264 int axis, 265 int x1, 266 int y1, 267 int e, 268 int e1, 269 int e3, 270 int len) 271{ 272 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 273 FbDashDeclare; 274 int dashlen; 275 Bool even; 276 Bool doOdd; 277 Bool doBg; 278 Pixel fg, bg; 279 280 fg = pGC->fgPixel; 281 bg = pGC->bgPixel; 282 283 /* whether to fill the odd dashes */ 284 doOdd = pGC->lineStyle == LineDoubleDash; 285 /* whether to switch fg to bg when filling odd dashes */ 286 doBg = doOdd && (pGC->fillStyle == FillSolid || 287 pGC->fillStyle == FillStippled); 288 289 /* compute current dash position */ 290 FbDashInit (pGC, pPriv, dashOffset, dashlen, even); 291 292 while (len--) 293 { 294 if (even || doOdd) 295 { 296 if (doBg) 297 { 298 if (even) 299 fbSetFg (pDrawable, pGC, fg); 300 else 301 fbSetFg (pDrawable, pGC, bg); 302 } 303 fbFill (pDrawable, pGC, x1, y1, 1, 1); 304 } 305 if (axis == X_AXIS) 306 { 307 x1 += signdx; 308 e += e1; 309 if (e >= 0) 310 { 311 e += e3; 312 y1 += signdy; 313 } 314 } 315 else 316 { 317 y1 += signdy; 318 e += e1; 319 if (e >= 0) 320 { 321 e += e3; 322 x1 += signdx; 323 } 324 } 325 FbDashStep (dashlen, even); 326 } 327 if (doBg) 328 fbSetFg (pDrawable, pGC, fg); 329} 330 331#ifdef FB_24BIT 332static void 333fbBresSolid24RRop (DrawablePtr pDrawable, 334 GCPtr pGC, 335 int dashOffset, 336 int signdx, 337 int signdy, 338 int axis, 339 int x1, 340 int y1, 341 int e, 342 int e1, 343 int e3, 344 int len) 345{ 346 FbStip *dst; 347 FbStride dstStride; 348 int dstBpp; 349 int dstXoff, dstYoff; 350 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 351 FbStip and = pPriv->and; 352 FbStip xor = pPriv->xor; 353 FbStip leftMask, rightMask; 354 int nl; 355 FbStip *d; 356 int x; 357 int rot; 358 FbStip andT, xorT; 359 360 fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 361 dst += ((y1 + dstYoff) * dstStride); 362 x1 = (x1 + dstXoff) * 24; 363 if (signdy < 0) 364 dstStride = -dstStride; 365 signdx *= 24; 366 while (len--) 367 { 368 d = dst + (x1 >> FB_STIP_SHIFT); 369 x = x1 & FB_STIP_MASK; 370 rot = FbFirst24Rot (x); 371 andT = FbRot24Stip(and,rot); 372 xorT = FbRot24Stip(xor,rot); 373 FbMaskStip (x, 24, leftMask, nl, rightMask); 374 if (leftMask) 375 { 376 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); 377 d++; 378 andT = FbNext24Stip (andT); 379 xorT = FbNext24Stip (xorT); 380 } 381 if (rightMask) 382 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); 383 if (axis == X_AXIS) 384 { 385 x1 += signdx; 386 e += e1; 387 if (e >= 0) 388 { 389 e += e3; 390 dst += dstStride; 391 } 392 } 393 else 394 { 395 dst += dstStride; 396 e += e1; 397 if (e >= 0) 398 { 399 e += e3; 400 x1 += signdx; 401 } 402 } 403 } 404 405 fbFinishAccess (pDrawable); 406} 407 408static void 409fbBresDash24RRop (DrawablePtr pDrawable, 410 GCPtr pGC, 411 int dashOffset, 412 int signdx, 413 int signdy, 414 int axis, 415 int x1, 416 int y1, 417 int e, 418 int e1, 419 int e3, 420 int len) 421{ 422 FbStip *dst; 423 FbStride dstStride; 424 int dstBpp; 425 int dstXoff, dstYoff; 426 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 427 FbStip andT, xorT; 428 FbStip fgand = pPriv->and; 429 FbStip fgxor = pPriv->xor; 430 FbStip bgand = pPriv->bgand; 431 FbStip bgxor = pPriv->bgxor; 432 FbStip leftMask, rightMask; 433 int nl; 434 FbStip *d; 435 int x; 436 int rot; 437 FbDashDeclare; 438 int dashlen; 439 Bool even; 440 Bool doOdd; 441 442 fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 443 doOdd = pGC->lineStyle == LineDoubleDash; 444 445 /* compute current dash position */ 446 FbDashInit(pGC, pPriv, dashOffset, dashlen, even); 447 448 dst += ((y1 + dstYoff) * dstStride); 449 x1 = (x1 + dstXoff) * 24; 450 if (signdy < 0) 451 dstStride = -dstStride; 452 signdx *= 24; 453 while (len--) 454 { 455 if (even || doOdd) 456 { 457 if (even) 458 { 459 andT = fgand; 460 xorT = fgxor; 461 } 462 else 463 { 464 andT = bgand; 465 xorT = bgxor; 466 } 467 d = dst + (x1 >> FB_STIP_SHIFT); 468 x = x1 & FB_STIP_MASK; 469 rot = FbFirst24Rot (x); 470 andT = FbRot24Stip (andT, rot); 471 xorT = FbRot24Stip (xorT, rot); 472 FbMaskStip (x, 24, leftMask, nl, rightMask); 473 if (leftMask) 474 { 475 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); 476 d++; 477 andT = FbNext24Stip (andT); 478 xorT = FbNext24Stip (xorT); 479 } 480 if (rightMask) 481 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); 482 } 483 if (axis == X_AXIS) 484 { 485 x1 += signdx; 486 e += e1; 487 if (e >= 0) 488 { 489 e += e3; 490 dst += dstStride; 491 } 492 } 493 else 494 { 495 dst += dstStride; 496 e += e1; 497 if (e >= 0) 498 { 499 e += e3; 500 x1 += signdx; 501 } 502 } 503 FbDashStep (dashlen, even); 504 } 505 506 fbFinishAccess (pDrawable); 507} 508#endif 509 510/* 511 * For drivers that want to bail drawing some lines, this 512 * function takes care of selecting the appropriate rasterizer 513 * based on the contents of the specified GC. 514 */ 515 516FbBres * 517fbSelectBres (DrawablePtr pDrawable, 518 GCPtr pGC) 519{ 520 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 521 int dstBpp = pDrawable->bitsPerPixel; 522 FbBres * bres; 523 524 if (pGC->lineStyle == LineSolid) 525 { 526 bres = fbBresFill; 527 if (pGC->fillStyle == FillSolid) 528 { 529 bres = fbBresSolid; 530#ifdef FB_24BIT 531 if (dstBpp == 24) 532 bres = fbBresSolid24RRop; 533#endif 534#ifndef FBNOPIXADDR 535 if (pPriv->and == 0) 536 { 537 switch (dstBpp) { 538 case 8: bres = fbBresSolid8; break; 539 case 16: bres = fbBresSolid16; break; 540#ifdef FB_24BIT 541 case 24: bres = fbBresSolid24; break; 542#endif 543 case 32: bres = fbBresSolid32; break; 544 } 545 } 546#endif 547 } 548 } 549 else 550 { 551 bres = fbBresFillDash; 552 if (pGC->fillStyle == FillSolid) 553 { 554 bres = fbBresDash; 555#ifdef FB_24BIT 556 if (dstBpp == 24) 557 bres = fbBresDash24RRop; 558#endif 559#ifndef FBNOPIXADDR 560 if (pPriv->and == 0 && 561 (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) 562 { 563 switch (dstBpp) { 564 case 8: bres = fbBresDash8; break; 565 case 16: bres = fbBresDash16; break; 566#ifdef FB_24BIT 567 case 24: bres = fbBresDash24; break; 568#endif 569 case 32: bres = fbBresDash32; break; 570 } 571 } 572#endif 573 } 574 } 575 return bres; 576} 577 578void 579fbBres (DrawablePtr pDrawable, 580 GCPtr pGC, 581 int dashOffset, 582 int signdx, 583 int signdy, 584 int axis, 585 int x1, 586 int y1, 587 int e, 588 int e1, 589 int e3, 590 int len) 591{ 592 (*fbSelectBres (pDrawable, pGC)) (pDrawable, pGC, dashOffset, 593 signdx, signdy, axis, x1, y1, 594 e, e1, e3, len); 595} 596 597void 598fbSegment (DrawablePtr pDrawable, 599 GCPtr pGC, 600 int x1, 601 int y1, 602 int x2, 603 int y2, 604 Bool drawLast, 605 int *dashOffset) 606{ 607 FbBres * bres; 608 RegionPtr pClip = fbGetCompositeClip(pGC); 609 BoxPtr pBox; 610 int nBox; 611 int adx; /* abs values of dx and dy */ 612 int ady; 613 int signdx; /* sign of dx and dy */ 614 int signdy; 615 int e, e1, e2, e3; /* bresenham error and increments */ 616 int len; /* length of segment */ 617 int axis; /* major axis */ 618 int octant; 619 int dashoff; 620 int doff; 621 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen); 622 unsigned int oc1; /* outcode of point 1 */ 623 unsigned int oc2; /* outcode of point 2 */ 624 625 nBox = REGION_NUM_RECTS (pClip); 626 pBox = REGION_RECTS (pClip); 627 628 bres = fbSelectBres (pDrawable, pGC); 629 630 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 631 1, 1, octant); 632 633 if (adx > ady) 634 { 635 axis = X_AXIS; 636 e1 = ady << 1; 637 e2 = e1 - (adx << 1); 638 e = e1 - adx; 639 len = adx; 640 } 641 else 642 { 643 axis = Y_AXIS; 644 e1 = adx << 1; 645 e2 = e1 - (ady << 1); 646 e = e1 - ady; 647 SetYMajorOctant(octant); 648 len = ady; 649 } 650 651 FIXUP_ERROR (e, octant, bias); 652 653 /* 654 * Adjust error terms to compare against zero 655 */ 656 e3 = e2 - e1; 657 e = e - e1; 658 659 /* we have bresenham parameters and two points. 660 all we have to do now is clip and draw. 661 */ 662 663 if (drawLast) 664 len++; 665 dashoff = *dashOffset; 666 *dashOffset = dashoff + len; 667 while(nBox--) 668 { 669 oc1 = 0; 670 oc2 = 0; 671 OUTCODES(oc1, x1, y1, pBox); 672 OUTCODES(oc2, x2, y2, pBox); 673 if ((oc1 | oc2) == 0) 674 { 675 (*bres) (pDrawable, pGC, dashoff, 676 signdx, signdy, axis, x1, y1, 677 e, e1, e3, len); 678 break; 679 } 680 else if (oc1 & oc2) 681 { 682 pBox++; 683 } 684 else 685 { 686 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2; 687 int clip1 = 0, clip2 = 0; 688 int clipdx, clipdy; 689 int err; 690 691 if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1, 692 pBox->y2-1, 693 &new_x1, &new_y1, &new_x2, &new_y2, 694 adx, ady, &clip1, &clip2, 695 octant, bias, oc1, oc2) == -1) 696 { 697 pBox++; 698 continue; 699 } 700 701 if (axis == X_AXIS) 702 len = abs(new_x2 - new_x1); 703 else 704 len = abs(new_y2 - new_y1); 705 if (clip2 != 0 || drawLast) 706 len++; 707 if (len) 708 { 709 /* unwind bresenham error term to first point */ 710 doff = dashoff; 711 err = e; 712 if (clip1) 713 { 714 clipdx = abs(new_x1 - x1); 715 clipdy = abs(new_y1 - y1); 716 if (axis == X_AXIS) 717 { 718 doff += clipdx; 719 err += e3 * clipdy + e1 * clipdx; 720 } 721 else 722 { 723 doff += clipdy; 724 err += e3 * clipdx + e1 * clipdy; 725 } 726 } 727 (*bres) (pDrawable, pGC, doff, 728 signdx, signdy, axis, new_x1, new_y1, 729 err, e1, e3, len); 730 } 731 pBox++; 732 } 733 } /* while (nBox--) */ 734} 735