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 ChangeGCVal val; 254 val.val = fg; 255 ChangeGC (NullClient, pGC, GCForeground, &val); 256 ValidateGC (pDrawable, pGC); 257 } 258} 259 260void 261fbBresFillDash (DrawablePtr pDrawable, 262 GCPtr pGC, 263 int dashOffset, 264 int signdx, 265 int signdy, 266 int axis, 267 int x1, 268 int y1, 269 int e, 270 int e1, 271 int e3, 272 int len) 273{ 274 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 275 FbDashDeclare; 276 int dashlen; 277 Bool even; 278 Bool doOdd; 279 Bool doBg; 280 Pixel fg, bg; 281 282 fg = pGC->fgPixel; 283 bg = pGC->bgPixel; 284 285 /* whether to fill the odd dashes */ 286 doOdd = pGC->lineStyle == LineDoubleDash; 287 /* whether to switch fg to bg when filling odd dashes */ 288 doBg = doOdd && (pGC->fillStyle == FillSolid || 289 pGC->fillStyle == FillStippled); 290 291 /* compute current dash position */ 292 FbDashInit (pGC, pPriv, dashOffset, dashlen, even); 293 294 while (len--) 295 { 296 if (even || doOdd) 297 { 298 if (doBg) 299 { 300 if (even) 301 fbSetFg (pDrawable, pGC, fg); 302 else 303 fbSetFg (pDrawable, pGC, bg); 304 } 305 fbFill (pDrawable, pGC, x1, y1, 1, 1); 306 } 307 if (axis == X_AXIS) 308 { 309 x1 += signdx; 310 e += e1; 311 if (e >= 0) 312 { 313 e += e3; 314 y1 += signdy; 315 } 316 } 317 else 318 { 319 y1 += signdy; 320 e += e1; 321 if (e >= 0) 322 { 323 e += e3; 324 x1 += signdx; 325 } 326 } 327 FbDashStep (dashlen, even); 328 } 329 if (doBg) 330 fbSetFg (pDrawable, pGC, fg); 331} 332 333#ifdef FB_24BIT 334static void 335fbBresSolid24RRop (DrawablePtr pDrawable, 336 GCPtr pGC, 337 int dashOffset, 338 int signdx, 339 int signdy, 340 int axis, 341 int x1, 342 int y1, 343 int e, 344 int e1, 345 int e3, 346 int len) 347{ 348 FbStip *dst; 349 FbStride dstStride; 350 int dstBpp; 351 int dstXoff, dstYoff; 352 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 353 FbStip and = pPriv->and; 354 FbStip xor = pPriv->xor; 355 FbStip leftMask, rightMask; 356 int nl; 357 FbStip *d; 358 int x; 359 int rot; 360 FbStip andT, xorT; 361 362 fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 363 dst += ((y1 + dstYoff) * dstStride); 364 x1 = (x1 + dstXoff) * 24; 365 if (signdy < 0) 366 dstStride = -dstStride; 367 signdx *= 24; 368 while (len--) 369 { 370 d = dst + (x1 >> FB_STIP_SHIFT); 371 x = x1 & FB_STIP_MASK; 372 rot = FbFirst24Rot (x); 373 andT = FbRot24Stip(and,rot); 374 xorT = FbRot24Stip(xor,rot); 375 FbMaskStip (x, 24, leftMask, nl, rightMask); 376 if (leftMask) 377 { 378 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); 379 d++; 380 andT = FbNext24Stip (andT); 381 xorT = FbNext24Stip (xorT); 382 } 383 if (rightMask) 384 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); 385 if (axis == X_AXIS) 386 { 387 x1 += signdx; 388 e += e1; 389 if (e >= 0) 390 { 391 e += e3; 392 dst += dstStride; 393 } 394 } 395 else 396 { 397 dst += dstStride; 398 e += e1; 399 if (e >= 0) 400 { 401 e += e3; 402 x1 += signdx; 403 } 404 } 405 } 406 407 fbFinishAccess (pDrawable); 408} 409 410static void 411fbBresDash24RRop (DrawablePtr pDrawable, 412 GCPtr pGC, 413 int dashOffset, 414 int signdx, 415 int signdy, 416 int axis, 417 int x1, 418 int y1, 419 int e, 420 int e1, 421 int e3, 422 int len) 423{ 424 FbStip *dst; 425 FbStride dstStride; 426 int dstBpp; 427 int dstXoff, dstYoff; 428 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 429 FbStip andT, xorT; 430 FbStip fgand = pPriv->and; 431 FbStip fgxor = pPriv->xor; 432 FbStip bgand = pPriv->bgand; 433 FbStip bgxor = pPriv->bgxor; 434 FbStip leftMask, rightMask; 435 int nl; 436 FbStip *d; 437 int x; 438 int rot; 439 FbDashDeclare; 440 int dashlen; 441 Bool even; 442 Bool doOdd; 443 444 fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 445 doOdd = pGC->lineStyle == LineDoubleDash; 446 447 /* compute current dash position */ 448 FbDashInit(pGC, pPriv, dashOffset, dashlen, even); 449 450 dst += ((y1 + dstYoff) * dstStride); 451 x1 = (x1 + dstXoff) * 24; 452 if (signdy < 0) 453 dstStride = -dstStride; 454 signdx *= 24; 455 while (len--) 456 { 457 if (even || doOdd) 458 { 459 if (even) 460 { 461 andT = fgand; 462 xorT = fgxor; 463 } 464 else 465 { 466 andT = bgand; 467 xorT = bgxor; 468 } 469 d = dst + (x1 >> FB_STIP_SHIFT); 470 x = x1 & FB_STIP_MASK; 471 rot = FbFirst24Rot (x); 472 andT = FbRot24Stip (andT, rot); 473 xorT = FbRot24Stip (xorT, rot); 474 FbMaskStip (x, 24, leftMask, nl, rightMask); 475 if (leftMask) 476 { 477 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask)); 478 d++; 479 andT = FbNext24Stip (andT); 480 xorT = FbNext24Stip (xorT); 481 } 482 if (rightMask) 483 WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask)); 484 } 485 if (axis == X_AXIS) 486 { 487 x1 += signdx; 488 e += e1; 489 if (e >= 0) 490 { 491 e += e3; 492 dst += dstStride; 493 } 494 } 495 else 496 { 497 dst += dstStride; 498 e += e1; 499 if (e >= 0) 500 { 501 e += e3; 502 x1 += signdx; 503 } 504 } 505 FbDashStep (dashlen, even); 506 } 507 508 fbFinishAccess (pDrawable); 509} 510#endif 511 512/* 513 * For drivers that want to bail drawing some lines, this 514 * function takes care of selecting the appropriate rasterizer 515 * based on the contents of the specified GC. 516 */ 517 518FbBres * 519fbSelectBres (DrawablePtr pDrawable, 520 GCPtr pGC) 521{ 522 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 523 int dstBpp = pDrawable->bitsPerPixel; 524 FbBres * bres; 525 526 if (pGC->lineStyle == LineSolid) 527 { 528 bres = fbBresFill; 529 if (pGC->fillStyle == FillSolid) 530 { 531 bres = fbBresSolid; 532#ifdef FB_24BIT 533 if (dstBpp == 24) 534 bres = fbBresSolid24RRop; 535#endif 536#ifndef FBNOPIXADDR 537 if (pPriv->and == 0) 538 { 539 switch (dstBpp) { 540 case 8: bres = fbBresSolid8; break; 541 case 16: bres = fbBresSolid16; break; 542#ifdef FB_24BIT 543 case 24: bres = fbBresSolid24; break; 544#endif 545 case 32: bres = fbBresSolid32; break; 546 } 547 } 548#endif 549 } 550 } 551 else 552 { 553 bres = fbBresFillDash; 554 if (pGC->fillStyle == FillSolid) 555 { 556 bres = fbBresDash; 557#ifdef FB_24BIT 558 if (dstBpp == 24) 559 bres = fbBresDash24RRop; 560#endif 561#ifndef FBNOPIXADDR 562 if (pPriv->and == 0 && 563 (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) 564 { 565 switch (dstBpp) { 566 case 8: bres = fbBresDash8; break; 567 case 16: bres = fbBresDash16; break; 568#ifdef FB_24BIT 569 case 24: bres = fbBresDash24; break; 570#endif 571 case 32: bres = fbBresDash32; break; 572 } 573 } 574#endif 575 } 576 } 577 return bres; 578} 579 580void 581fbBres (DrawablePtr pDrawable, 582 GCPtr pGC, 583 int dashOffset, 584 int signdx, 585 int signdy, 586 int axis, 587 int x1, 588 int y1, 589 int e, 590 int e1, 591 int e3, 592 int len) 593{ 594 (*fbSelectBres (pDrawable, pGC)) (pDrawable, pGC, dashOffset, 595 signdx, signdy, axis, x1, y1, 596 e, e1, e3, len); 597} 598 599void 600fbSegment (DrawablePtr pDrawable, 601 GCPtr pGC, 602 int x1, 603 int y1, 604 int x2, 605 int y2, 606 Bool drawLast, 607 int *dashOffset) 608{ 609 FbBres * bres; 610 RegionPtr pClip = fbGetCompositeClip(pGC); 611 BoxPtr pBox; 612 int nBox; 613 int adx; /* abs values of dx and dy */ 614 int ady; 615 int signdx; /* sign of dx and dy */ 616 int signdy; 617 int e, e1, e2, e3; /* bresenham error and increments */ 618 int len; /* length of segment */ 619 int axis; /* major axis */ 620 int octant; 621 int dashoff; 622 int doff; 623 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen); 624 unsigned int oc1; /* outcode of point 1 */ 625 unsigned int oc2; /* outcode of point 2 */ 626 627 nBox = RegionNumRects (pClip); 628 pBox = RegionRects (pClip); 629 630 bres = fbSelectBres (pDrawable, pGC); 631 632 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 633 1, 1, octant); 634 635 if (adx > ady) 636 { 637 axis = X_AXIS; 638 e1 = ady << 1; 639 e2 = e1 - (adx << 1); 640 e = e1 - adx; 641 len = adx; 642 } 643 else 644 { 645 axis = Y_AXIS; 646 e1 = adx << 1; 647 e2 = e1 - (ady << 1); 648 e = e1 - ady; 649 SetYMajorOctant(octant); 650 len = ady; 651 } 652 653 FIXUP_ERROR (e, octant, bias); 654 655 /* 656 * Adjust error terms to compare against zero 657 */ 658 e3 = e2 - e1; 659 e = e - e1; 660 661 /* we have bresenham parameters and two points. 662 all we have to do now is clip and draw. 663 */ 664 665 if (drawLast) 666 len++; 667 dashoff = *dashOffset; 668 *dashOffset = dashoff + len; 669 while(nBox--) 670 { 671 oc1 = 0; 672 oc2 = 0; 673 OUTCODES(oc1, x1, y1, pBox); 674 OUTCODES(oc2, x2, y2, pBox); 675 if ((oc1 | oc2) == 0) 676 { 677 (*bres) (pDrawable, pGC, dashoff, 678 signdx, signdy, axis, x1, y1, 679 e, e1, e3, len); 680 break; 681 } 682 else if (oc1 & oc2) 683 { 684 pBox++; 685 } 686 else 687 { 688 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2; 689 int clip1 = 0, clip2 = 0; 690 int clipdx, clipdy; 691 int err; 692 693 if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1, 694 pBox->y2-1, 695 &new_x1, &new_y1, &new_x2, &new_y2, 696 adx, ady, &clip1, &clip2, 697 octant, bias, oc1, oc2) == -1) 698 { 699 pBox++; 700 continue; 701 } 702 703 if (axis == X_AXIS) 704 len = abs(new_x2 - new_x1); 705 else 706 len = abs(new_y2 - new_y1); 707 if (clip2 != 0 || drawLast) 708 len++; 709 if (len) 710 { 711 /* unwind bresenham error term to first point */ 712 doff = dashoff; 713 err = e; 714 if (clip1) 715 { 716 clipdx = abs(new_x1 - x1); 717 clipdy = abs(new_y1 - y1); 718 if (axis == X_AXIS) 719 { 720 doff += clipdx; 721 err += e3 * clipdy + e1 * clipdx; 722 } 723 else 724 { 725 doff += clipdy; 726 err += e3 * clipdx + e1 * clipdy; 727 } 728 } 729 (*bres) (pDrawable, pGC, doff, 730 signdx, signdy, axis, new_x1, new_y1, 731 err, e1, e3, len); 732 } 733 pBox++; 734 } 735 } /* while (nBox--) */ 736} 737