fbseg.c revision 35c4bbdf
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 36static void 37fbBresSolid(DrawablePtr pDrawable, 38 GCPtr pGC, 39 int dashOffset, 40 int signdx, 41 int signdy, 42 int axis, int x1, int y1, int e, int e1, int e3, int len) 43{ 44 FbStip *dst; 45 FbStride dstStride; 46 int dstBpp; 47 int dstXoff, dstYoff; 48 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 49 FbStip and = (FbStip) pPriv->and; 50 FbStip xor = (FbStip) pPriv->xor; 51 FbStip mask, mask0; 52 FbStip bits; 53 54 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 55 dst += ((y1 + dstYoff) * dstStride); 56 x1 = (x1 + dstXoff) * dstBpp; 57 dst += x1 >> FB_STIP_SHIFT; 58 x1 &= FB_STIP_MASK; 59 mask0 = FbStipMask(0, dstBpp); 60 mask = FbStipRight(mask0, x1); 61 if (signdx < 0) 62 mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp); 63 if (signdy < 0) 64 dstStride = -dstStride; 65 if (axis == X_AXIS) { 66 bits = 0; 67 while (len--) { 68 bits |= mask; 69 mask = fbBresShiftMask(mask, signdx, dstBpp); 70 if (!mask) { 71 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits)); 72 bits = 0; 73 dst += signdx; 74 mask = mask0; 75 } 76 e += e1; 77 if (e >= 0) { 78 if (bits) { 79 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits)); 80 bits = 0; 81 } 82 dst += dstStride; 83 e += e3; 84 } 85 } 86 if (bits) 87 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits)); 88 } 89 else { 90 while (len--) { 91 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask)); 92 dst += dstStride; 93 e += e1; 94 if (e >= 0) { 95 e += e3; 96 mask = fbBresShiftMask(mask, signdx, dstBpp); 97 if (!mask) { 98 dst += signdx; 99 mask = mask0; 100 } 101 } 102 } 103 } 104 105 fbFinishAccess(pDrawable); 106} 107 108static void 109fbBresDash(DrawablePtr pDrawable, 110 GCPtr pGC, 111 int dashOffset, 112 int signdx, 113 int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len) 114{ 115 FbStip *dst; 116 FbStride dstStride; 117 int dstBpp; 118 int dstXoff, dstYoff; 119 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 120 FbStip and = (FbStip) pPriv->and; 121 FbStip xor = (FbStip) pPriv->xor; 122 FbStip bgand = (FbStip) pPriv->bgand; 123 FbStip bgxor = (FbStip) pPriv->bgxor; 124 FbStip mask, mask0; 125 126 FbDashDeclare; 127 int dashlen; 128 Bool even; 129 Bool doOdd; 130 131 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 132 doOdd = pGC->lineStyle == LineDoubleDash; 133 134 FbDashInit(pGC, pPriv, dashOffset, dashlen, even); 135 136 dst += ((y1 + dstYoff) * dstStride); 137 x1 = (x1 + dstXoff) * dstBpp; 138 dst += x1 >> FB_STIP_SHIFT; 139 x1 &= FB_STIP_MASK; 140 mask0 = FbStipMask(0, dstBpp); 141 mask = FbStipRight(mask0, x1); 142 if (signdx < 0) 143 mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp); 144 if (signdy < 0) 145 dstStride = -dstStride; 146 while (len--) { 147 if (even) 148 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask)); 149 else if (doOdd) 150 WRITE(dst, FbDoMaskRRop(READ(dst), bgand, bgxor, mask)); 151 if (axis == X_AXIS) { 152 mask = fbBresShiftMask(mask, signdx, dstBpp); 153 if (!mask) { 154 dst += signdx; 155 mask = mask0; 156 } 157 e += e1; 158 if (e >= 0) { 159 dst += dstStride; 160 e += e3; 161 } 162 } 163 else { 164 dst += dstStride; 165 e += e1; 166 if (e >= 0) { 167 e += e3; 168 mask = fbBresShiftMask(mask, signdx, dstBpp); 169 if (!mask) { 170 dst += signdx; 171 mask = mask0; 172 } 173 } 174 } 175 FbDashStep(dashlen, even); 176 } 177 178 fbFinishAccess(pDrawable); 179} 180 181static void 182fbBresFill(DrawablePtr pDrawable, 183 GCPtr pGC, 184 int dashOffset, 185 int signdx, 186 int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len) 187{ 188 while (len--) { 189 fbFill(pDrawable, pGC, x1, y1, 1, 1); 190 if (axis == X_AXIS) { 191 x1 += signdx; 192 e += e1; 193 if (e >= 0) { 194 e += e3; 195 y1 += signdy; 196 } 197 } 198 else { 199 y1 += signdy; 200 e += e1; 201 if (e >= 0) { 202 e += e3; 203 x1 += signdx; 204 } 205 } 206 } 207} 208 209static void 210fbSetFg(DrawablePtr pDrawable, GCPtr pGC, Pixel fg) 211{ 212 if (fg != pGC->fgPixel) { 213 ChangeGCVal val; 214 215 val.val = fg; 216 ChangeGC(NullClient, pGC, GCForeground, &val); 217 ValidateGC(pDrawable, pGC); 218 } 219} 220 221static void 222fbBresFillDash(DrawablePtr pDrawable, 223 GCPtr pGC, 224 int dashOffset, 225 int signdx, 226 int signdy, 227 int axis, int x1, int y1, int e, int e1, int e3, int len) 228{ 229 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 230 231 FbDashDeclare; 232 int dashlen; 233 Bool even; 234 Bool doOdd; 235 Bool doBg; 236 Pixel fg, bg; 237 238 fg = pGC->fgPixel; 239 bg = pGC->bgPixel; 240 241 /* whether to fill the odd dashes */ 242 doOdd = pGC->lineStyle == LineDoubleDash; 243 /* whether to switch fg to bg when filling odd dashes */ 244 doBg = doOdd && (pGC->fillStyle == FillSolid || 245 pGC->fillStyle == FillStippled); 246 247 /* compute current dash position */ 248 FbDashInit(pGC, pPriv, dashOffset, dashlen, even); 249 250 while (len--) { 251 if (even || doOdd) { 252 if (doBg) { 253 if (even) 254 fbSetFg(pDrawable, pGC, fg); 255 else 256 fbSetFg(pDrawable, pGC, bg); 257 } 258 fbFill(pDrawable, pGC, x1, y1, 1, 1); 259 } 260 if (axis == X_AXIS) { 261 x1 += signdx; 262 e += e1; 263 if (e >= 0) { 264 e += e3; 265 y1 += signdy; 266 } 267 } 268 else { 269 y1 += signdy; 270 e += e1; 271 if (e >= 0) { 272 e += e3; 273 x1 += signdx; 274 } 275 } 276 FbDashStep(dashlen, even); 277 } 278 if (doBg) 279 fbSetFg(pDrawable, pGC, fg); 280} 281 282static void 283fbBresSolid24RRop(DrawablePtr pDrawable, 284 GCPtr pGC, 285 int dashOffset, 286 int signdx, 287 int signdy, 288 int axis, int x1, int y1, int e, int e1, int e3, int len) 289{ 290 FbStip *dst; 291 FbStride dstStride; 292 int dstBpp; 293 int dstXoff, dstYoff; 294 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 295 FbStip and = pPriv->and; 296 FbStip xor = pPriv->xor; 297 FbStip leftMask, rightMask; 298 int nl; 299 FbStip *d; 300 int x; 301 int rot; 302 FbStip andT, xorT; 303 304 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 305 dst += ((y1 + dstYoff) * dstStride); 306 x1 = (x1 + dstXoff) * 24; 307 if (signdy < 0) 308 dstStride = -dstStride; 309 signdx *= 24; 310 while (len--) { 311 d = dst + (x1 >> FB_STIP_SHIFT); 312 x = x1 & FB_STIP_MASK; 313 rot = FbFirst24Rot(x); 314 andT = FbRot24Stip(and, rot); 315 xorT = FbRot24Stip(xor, rot); 316 FbMaskStip(x, 24, leftMask, nl, rightMask); 317 if (leftMask) { 318 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, leftMask)); 319 d++; 320 andT = FbNext24Stip(andT); 321 xorT = FbNext24Stip(xorT); 322 } 323 if (rightMask) 324 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, rightMask)); 325 if (axis == X_AXIS) { 326 x1 += signdx; 327 e += e1; 328 if (e >= 0) { 329 e += e3; 330 dst += dstStride; 331 } 332 } 333 else { 334 dst += dstStride; 335 e += e1; 336 if (e >= 0) { 337 e += e3; 338 x1 += signdx; 339 } 340 } 341 } 342 343 fbFinishAccess(pDrawable); 344} 345 346static void 347fbBresDash24RRop(DrawablePtr pDrawable, 348 GCPtr pGC, 349 int dashOffset, 350 int signdx, 351 int signdy, 352 int axis, int x1, int y1, int e, int e1, int e3, int len) 353{ 354 FbStip *dst; 355 FbStride dstStride; 356 int dstBpp; 357 int dstXoff, dstYoff; 358 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 359 FbStip andT, xorT; 360 FbStip fgand = pPriv->and; 361 FbStip fgxor = pPriv->xor; 362 FbStip bgand = pPriv->bgand; 363 FbStip bgxor = pPriv->bgxor; 364 FbStip leftMask, rightMask; 365 int nl; 366 FbStip *d; 367 int x; 368 int rot; 369 370 FbDashDeclare; 371 int dashlen; 372 Bool even; 373 Bool doOdd; 374 375 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 376 doOdd = pGC->lineStyle == LineDoubleDash; 377 378 /* compute current dash position */ 379 FbDashInit(pGC, pPriv, dashOffset, dashlen, even); 380 381 dst += ((y1 + dstYoff) * dstStride); 382 x1 = (x1 + dstXoff) * 24; 383 if (signdy < 0) 384 dstStride = -dstStride; 385 signdx *= 24; 386 while (len--) { 387 if (even || doOdd) { 388 if (even) { 389 andT = fgand; 390 xorT = fgxor; 391 } 392 else { 393 andT = bgand; 394 xorT = bgxor; 395 } 396 d = dst + (x1 >> FB_STIP_SHIFT); 397 x = x1 & FB_STIP_MASK; 398 rot = FbFirst24Rot(x); 399 andT = FbRot24Stip(andT, rot); 400 xorT = FbRot24Stip(xorT, rot); 401 FbMaskStip(x, 24, leftMask, nl, rightMask); 402 if (leftMask) { 403 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, leftMask)); 404 d++; 405 andT = FbNext24Stip(andT); 406 xorT = FbNext24Stip(xorT); 407 } 408 if (rightMask) 409 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, rightMask)); 410 } 411 if (axis == X_AXIS) { 412 x1 += signdx; 413 e += e1; 414 if (e >= 0) { 415 e += e3; 416 dst += dstStride; 417 } 418 } 419 else { 420 dst += dstStride; 421 e += e1; 422 if (e >= 0) { 423 e += e3; 424 x1 += signdx; 425 } 426 } 427 FbDashStep(dashlen, even); 428 } 429 430 fbFinishAccess(pDrawable); 431} 432 433/* 434 * For drivers that want to bail drawing some lines, this 435 * function takes care of selecting the appropriate rasterizer 436 * based on the contents of the specified GC. 437 */ 438 439static FbBres * 440fbSelectBres(DrawablePtr pDrawable, GCPtr pGC) 441{ 442 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 443 int dstBpp = pDrawable->bitsPerPixel; 444 FbBres *bres; 445 446 if (pGC->lineStyle == LineSolid) { 447 bres = fbBresFill; 448 if (pGC->fillStyle == FillSolid) { 449 bres = fbBresSolid; 450 if (dstBpp == 24) 451 bres = fbBresSolid24RRop; 452 if (pPriv->and == 0) { 453 switch (dstBpp) { 454 case 8: 455 bres = fbBresSolid8; 456 break; 457 case 16: 458 bres = fbBresSolid16; 459 break; 460 case 24: 461 bres = fbBresSolid24; 462 break; 463 case 32: 464 bres = fbBresSolid32; 465 break; 466 } 467 } 468 } 469 } 470 else { 471 bres = fbBresFillDash; 472 if (pGC->fillStyle == FillSolid) { 473 bres = fbBresDash; 474 if (dstBpp == 24) 475 bres = fbBresDash24RRop; 476 if (pPriv->and == 0 && 477 (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) { 478 switch (dstBpp) { 479 case 8: 480 bres = fbBresDash8; 481 break; 482 case 16: 483 bres = fbBresDash16; 484 break; 485 case 24: 486 bres = fbBresDash24; 487 break; 488 case 32: 489 bres = fbBresDash32; 490 break; 491 } 492 } 493 } 494 } 495 return bres; 496} 497 498void 499fbSegment(DrawablePtr pDrawable, 500 GCPtr pGC, 501 int x1, int y1, int x2, int y2, Bool drawLast, int *dashOffset) 502{ 503 FbBres *bres; 504 RegionPtr pClip = fbGetCompositeClip(pGC); 505 BoxPtr pBox; 506 int nBox; 507 int adx; /* abs values of dx and dy */ 508 int ady; 509 int signdx; /* sign of dx and dy */ 510 int signdy; 511 int e, e1, e2, e3; /* bresenham error and increments */ 512 int len; /* length of segment */ 513 int axis; /* major axis */ 514 int octant; 515 int dashoff; 516 int doff; 517 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen); 518 unsigned int oc1; /* outcode of point 1 */ 519 unsigned int oc2; /* outcode of point 2 */ 520 521 nBox = RegionNumRects(pClip); 522 pBox = RegionRects(pClip); 523 524 bres = fbSelectBres(pDrawable, pGC); 525 526 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant); 527 528 if (adx > ady) { 529 axis = X_AXIS; 530 e1 = ady << 1; 531 e2 = e1 - (adx << 1); 532 e = e1 - adx; 533 len = adx; 534 } 535 else { 536 axis = Y_AXIS; 537 e1 = adx << 1; 538 e2 = e1 - (ady << 1); 539 e = e1 - ady; 540 SetYMajorOctant(octant); 541 len = ady; 542 } 543 544 FIXUP_ERROR(e, octant, bias); 545 546 /* 547 * Adjust error terms to compare against zero 548 */ 549 e3 = e2 - e1; 550 e = e - e1; 551 552 /* we have bresenham parameters and two points. 553 all we have to do now is clip and draw. 554 */ 555 556 if (drawLast) 557 len++; 558 dashoff = *dashOffset; 559 *dashOffset = dashoff + len; 560 while (nBox--) { 561 oc1 = 0; 562 oc2 = 0; 563 OUTCODES(oc1, x1, y1, pBox); 564 OUTCODES(oc2, x2, y2, pBox); 565 if ((oc1 | oc2) == 0) { 566 (*bres) (pDrawable, pGC, dashoff, 567 signdx, signdy, axis, x1, y1, e, e1, e3, len); 568 break; 569 } 570 else if (oc1 & oc2) { 571 pBox++; 572 } 573 else { 574 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2; 575 int clip1 = 0, clip2 = 0; 576 int clipdx, clipdy; 577 int err; 578 579 if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2 - 1, 580 pBox->y2 - 1, 581 &new_x1, &new_y1, &new_x2, &new_y2, 582 adx, ady, &clip1, &clip2, 583 octant, bias, oc1, oc2) == -1) { 584 pBox++; 585 continue; 586 } 587 588 if (axis == X_AXIS) 589 len = abs(new_x2 - new_x1); 590 else 591 len = abs(new_y2 - new_y1); 592 if (clip2 != 0 || drawLast) 593 len++; 594 if (len) { 595 /* unwind bresenham error term to first point */ 596 doff = dashoff; 597 err = e; 598 if (clip1) { 599 clipdx = abs(new_x1 - x1); 600 clipdy = abs(new_y1 - y1); 601 if (axis == X_AXIS) { 602 doff += clipdx; 603 err += e3 * clipdy + e1 * clipdx; 604 } 605 else { 606 doff += clipdy; 607 err += e3 * clipdx + e1 * clipdy; 608 } 609 } 610 (*bres) (pDrawable, pGC, doff, 611 signdx, signdy, axis, new_x1, new_y1, 612 err, e1, e3, len); 613 } 614 pBox++; 615 } 616 } /* while (nBox--) */ 617} 618