miwideline.c revision 05b261ec
1/* 2 3Copyright 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29/* Author: Keith Packard, MIT X Consortium */ 30 31/* 32 * Mostly integer wideline code. Uses a technique similar to 33 * bresenham zero-width lines, except walks an X edge 34 */ 35 36#ifdef HAVE_DIX_CONFIG_H 37#include <dix-config.h> 38#endif 39 40#include <stdio.h> 41#ifdef _XOPEN_SOURCE 42#include <math.h> 43#else 44#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */ 45#include <math.h> 46#undef _XOPEN_SOURCE 47#endif 48#include <X11/X.h> 49#include "windowstr.h" 50#include "gcstruct.h" 51#include "regionstr.h" 52#include "miwideline.h" 53#include "mi.h" 54 55static void miLineArc(DrawablePtr pDraw, GCPtr pGC, 56 unsigned long pixel, SpanDataPtr spanData, 57 LineFacePtr leftFace, 58 LineFacePtr rightFace, 59 double xorg, double yorg, Bool isInt); 60 61 62/* 63 * spans-based polygon filler 64 */ 65 66static void 67miFillPolyHelper (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, 68 SpanDataPtr spanData, int y, int overall_height, 69 PolyEdgePtr left, PolyEdgePtr right, 70 int left_count, int right_count) 71{ 72 int left_x = 0, left_e = 0; 73 int left_stepx = 0; 74 int left_signdx = 0; 75 int left_dy = 0, left_dx = 0; 76 77 int right_x = 0, right_e = 0; 78 int right_stepx = 0; 79 int right_signdx = 0; 80 int right_dy = 0, right_dx = 0; 81 82 int height = 0; 83 int left_height = 0, right_height = 0; 84 85 DDXPointPtr ppt; 86 DDXPointPtr pptInit = NULL; 87 int *pwidth; 88 int *pwidthInit = NULL; 89 XID oldPixel; 90 int xorg; 91 Spans spanRec; 92 93 left_height = 0; 94 right_height = 0; 95 96 if (!spanData) 97 { 98 pptInit = (DDXPointPtr) ALLOCATE_LOCAL (overall_height * sizeof(*ppt)); 99 if (!pptInit) 100 return; 101 pwidthInit = (int *) ALLOCATE_LOCAL (overall_height * sizeof(*pwidth)); 102 if (!pwidthInit) 103 { 104 DEALLOCATE_LOCAL (pptInit); 105 return; 106 } 107 ppt = pptInit; 108 pwidth = pwidthInit; 109 oldPixel = pGC->fgPixel; 110 if (pixel != oldPixel) 111 { 112 XID tmpPixel = (XID)pixel; 113 DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE); 114 ValidateGC (pDrawable, pGC); 115 } 116 } 117 else 118 { 119 spanRec.points = (DDXPointPtr) xalloc (overall_height * sizeof (*ppt)); 120 if (!spanRec.points) 121 return; 122 spanRec.widths = (int *) xalloc (overall_height * sizeof (int)); 123 if (!spanRec.widths) 124 { 125 xfree (spanRec.points); 126 return; 127 } 128 ppt = spanRec.points; 129 pwidth = spanRec.widths; 130 } 131 132 xorg = 0; 133 if (pGC->miTranslate) 134 { 135 y += pDrawable->y; 136 xorg = pDrawable->x; 137 } 138 while ((left_count || left_height) && 139 (right_count || right_height)) 140 { 141 MIPOLYRELOADLEFT 142 MIPOLYRELOADRIGHT 143 144 height = left_height; 145 if (height > right_height) 146 height = right_height; 147 148 left_height -= height; 149 right_height -= height; 150 151 while (--height >= 0) 152 { 153 if (right_x >= left_x) 154 { 155 ppt->y = y; 156 ppt->x = left_x + xorg; 157 ppt++; 158 *pwidth++ = right_x - left_x + 1; 159 } 160 y++; 161 162 MIPOLYSTEPLEFT 163 164 MIPOLYSTEPRIGHT 165 } 166 } 167 if (!spanData) 168 { 169 (*pGC->ops->FillSpans) (pDrawable, pGC, ppt - pptInit, pptInit, pwidthInit, TRUE); 170 DEALLOCATE_LOCAL (pwidthInit); 171 DEALLOCATE_LOCAL (pptInit); 172 if (pixel != oldPixel) 173 { 174 DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); 175 ValidateGC (pDrawable, pGC); 176 } 177 } 178 else 179 { 180 spanRec.count = ppt - spanRec.points; 181 AppendSpanGroup (pGC, pixel, &spanRec, spanData) 182 } 183} 184 185static void 186miFillRectPolyHelper ( 187 DrawablePtr pDrawable, 188 GCPtr pGC, 189 unsigned long pixel, 190 SpanDataPtr spanData, 191 int x, 192 int y, 193 int w, 194 int h) 195{ 196 DDXPointPtr ppt; 197 int *pwidth; 198 XID oldPixel; 199 Spans spanRec; 200 xRectangle rect; 201 202 if (!spanData) 203 { 204 rect.x = x; 205 rect.y = y; 206 rect.width = w; 207 rect.height = h; 208 oldPixel = pGC->fgPixel; 209 if (pixel != oldPixel) 210 { 211 XID tmpPixel = (XID)pixel; 212 DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE); 213 ValidateGC (pDrawable, pGC); 214 } 215 (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect); 216 if (pixel != oldPixel) 217 { 218 DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); 219 ValidateGC (pDrawable, pGC); 220 } 221 } 222 else 223 { 224 spanRec.points = (DDXPointPtr) xalloc (h * sizeof (*ppt)); 225 if (!spanRec.points) 226 return; 227 spanRec.widths = (int *) xalloc (h * sizeof (int)); 228 if (!spanRec.widths) 229 { 230 xfree (spanRec.points); 231 return; 232 } 233 ppt = spanRec.points; 234 pwidth = spanRec.widths; 235 236 if (pGC->miTranslate) 237 { 238 y += pDrawable->y; 239 x += pDrawable->x; 240 } 241 while (h--) 242 { 243 ppt->x = x; 244 ppt->y = y; 245 ppt++; 246 *pwidth++ = w; 247 y++; 248 } 249 spanRec.count = ppt - spanRec.points; 250 AppendSpanGroup (pGC, pixel, &spanRec, spanData) 251 } 252} 253 254_X_EXPORT /* static */ int 255miPolyBuildEdge (x0, y0, k, dx, dy, xi, yi, left, edge) 256 double x0, y0; 257 double k; /* x0 * dy - y0 * dx */ 258 int dx, dy; 259 int xi, yi; 260 int left; 261 PolyEdgePtr edge; 262{ 263 int x, y, e; 264 int xady; 265 266 if (dy < 0) 267 { 268 dy = -dy; 269 dx = -dx; 270 k = -k; 271 } 272 273#ifdef NOTDEF 274 { 275 double realk, kerror; 276 realk = x0 * dy - y0 * dx; 277 kerror = Fabs (realk - k); 278 if (kerror > .1) 279 printf ("realk: %g k: %g\n", realk, k); 280 } 281#endif 282 y = ICEIL (y0); 283 xady = ICEIL (k) + y * dx; 284 285 if (xady <= 0) 286 x = - (-xady / dy) - 1; 287 else 288 x = (xady - 1) / dy; 289 290 e = xady - x * dy; 291 292 if (dx >= 0) 293 { 294 edge->signdx = 1; 295 edge->stepx = dx / dy; 296 edge->dx = dx % dy; 297 } 298 else 299 { 300 edge->signdx = -1; 301 edge->stepx = - (-dx / dy); 302 edge->dx = -dx % dy; 303 e = dy - e + 1; 304 } 305 edge->dy = dy; 306 edge->x = x + left + xi; 307 edge->e = e - dy; /* bias to compare against 0 instead of dy */ 308 return y + yi; 309} 310 311#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr))) 312 313_X_EXPORT /* static */ int 314miPolyBuildPoly (vertices, slopes, count, xi, yi, left, right, pnleft, pnright, h) 315 PolyVertexPtr vertices; 316 PolySlopePtr slopes; 317 int count; 318 int xi, yi; 319 PolyEdgePtr left, right; 320 int *pnleft, *pnright; 321 int *h; 322{ 323 int top, bottom; 324 double miny, maxy; 325 int i; 326 int j; 327 int clockwise; 328 int slopeoff; 329 int s; 330 int nright, nleft; 331 int y, lasty = 0, bottomy, topy = 0; 332 333 /* find the top of the polygon */ 334 maxy = miny = vertices[0].y; 335 bottom = top = 0; 336 for (i = 1; i < count; i++) 337 { 338 if (vertices[i].y < miny) 339 { 340 top = i; 341 miny = vertices[i].y; 342 } 343 if (vertices[i].y >= maxy) 344 { 345 bottom = i; 346 maxy = vertices[i].y; 347 } 348 } 349 clockwise = 1; 350 slopeoff = 0; 351 352 i = top; 353 j = StepAround (top, -1, count); 354 355 if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx) 356 { 357 clockwise = -1; 358 slopeoff = -1; 359 } 360 361 bottomy = ICEIL (maxy) + yi; 362 363 nright = 0; 364 365 s = StepAround (top, slopeoff, count); 366 i = top; 367 while (i != bottom) 368 { 369 if (slopes[s].dy != 0) 370 { 371 y = miPolyBuildEdge (vertices[i].x, vertices[i].y, 372 slopes[s].k, 373 slopes[s].dx, slopes[s].dy, 374 xi, yi, 0, 375 &right[nright]); 376 if (nright != 0) 377 right[nright-1].height = y - lasty; 378 else 379 topy = y; 380 nright++; 381 lasty = y; 382 } 383 384 i = StepAround (i, clockwise, count); 385 s = StepAround (s, clockwise, count); 386 } 387 if (nright != 0) 388 right[nright-1].height = bottomy - lasty; 389 390 if (slopeoff == 0) 391 slopeoff = -1; 392 else 393 slopeoff = 0; 394 395 nleft = 0; 396 s = StepAround (top, slopeoff, count); 397 i = top; 398 while (i != bottom) 399 { 400 if (slopes[s].dy != 0) 401 { 402 y = miPolyBuildEdge (vertices[i].x, vertices[i].y, 403 slopes[s].k, 404 slopes[s].dx, slopes[s].dy, xi, yi, 1, 405 &left[nleft]); 406 407 if (nleft != 0) 408 left[nleft-1].height = y - lasty; 409 nleft++; 410 lasty = y; 411 } 412 i = StepAround (i, -clockwise, count); 413 s = StepAround (s, -clockwise, count); 414 } 415 if (nleft != 0) 416 left[nleft-1].height = bottomy - lasty; 417 *pnleft = nleft; 418 *pnright = nright; 419 *h = bottomy - topy; 420 return topy; 421} 422 423static void 424miLineOnePoint ( 425 DrawablePtr pDrawable, 426 GCPtr pGC, 427 unsigned long pixel, 428 SpanDataPtr spanData, 429 int x, 430 int y) 431{ 432 DDXPointRec pt; 433 int wid; 434 unsigned long oldPixel; 435 436 MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel); 437 if (pGC->fillStyle == FillSolid) 438 { 439 pt.x = x; 440 pt.y = y; 441 (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt); 442 } 443 else 444 { 445 wid = 1; 446 if (pGC->miTranslate) 447 { 448 x += pDrawable->x; 449 y += pDrawable->y; 450 } 451 pt.x = x; 452 pt.y = y; 453 (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE); 454 } 455 MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel); 456} 457 458static void 459miLineJoin ( 460 DrawablePtr pDrawable, 461 GCPtr pGC, 462 unsigned long pixel, 463 SpanDataPtr spanData, 464 LineFacePtr pLeft, 465 LineFacePtr pRight) 466{ 467 double mx = 0, my = 0; 468 double denom = 0.0; 469 PolyVertexRec vertices[4]; 470 PolySlopeRec slopes[4]; 471 int edgecount; 472 PolyEdgeRec left[4], right[4]; 473 int nleft, nright; 474 int y, height; 475 int swapslopes; 476 int joinStyle = pGC->joinStyle; 477 int lw = pGC->lineWidth; 478 479 if (lw == 1 && !spanData) { 480 /* See if one of the lines will draw the joining pixel */ 481 if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0)) 482 return; 483 if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0)) 484 return; 485 if (joinStyle != JoinRound) { 486 denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; 487 if (denom == 0) 488 return; /* no join to draw */ 489 } 490 if (joinStyle != JoinMiter) { 491 miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y); 492 return; 493 } 494 } else { 495 if (joinStyle == JoinRound) 496 { 497 miLineArc(pDrawable, pGC, pixel, spanData, 498 pLeft, pRight, 499 (double)0.0, (double)0.0, TRUE); 500 return; 501 } 502 denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; 503 if (denom == 0.0) 504 return; /* no join to draw */ 505 } 506 507 swapslopes = 0; 508 if (denom > 0) 509 { 510 pLeft->xa = -pLeft->xa; 511 pLeft->ya = -pLeft->ya; 512 pLeft->dx = -pLeft->dx; 513 pLeft->dy = -pLeft->dy; 514 } 515 else 516 { 517 swapslopes = 1; 518 pRight->xa = -pRight->xa; 519 pRight->ya = -pRight->ya; 520 pRight->dx = -pRight->dx; 521 pRight->dy = -pRight->dy; 522 } 523 524 vertices[0].x = pRight->xa; 525 vertices[0].y = pRight->ya; 526 slopes[0].dx = -pRight->dy; 527 slopes[0].dy = pRight->dx; 528 slopes[0].k = 0; 529 530 vertices[1].x = 0; 531 vertices[1].y = 0; 532 slopes[1].dx = pLeft->dy; 533 slopes[1].dy = -pLeft->dx; 534 slopes[1].k = 0; 535 536 vertices[2].x = pLeft->xa; 537 vertices[2].y = pLeft->ya; 538 539 if (joinStyle == JoinMiter) 540 { 541 my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) - 542 pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) / 543 denom; 544 if (pLeft->dy != 0) 545 { 546 mx = pLeft->xa + (my - pLeft->ya) * 547 (double) pLeft->dx / (double) pLeft->dy; 548 } 549 else 550 { 551 mx = pRight->xa + (my - pRight->ya) * 552 (double) pRight->dx / (double) pRight->dy; 553 } 554 /* check miter limit */ 555 if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw) 556 joinStyle = JoinBevel; 557 } 558 559 if (joinStyle == JoinMiter) 560 { 561 slopes[2].dx = pLeft->dx; 562 slopes[2].dy = pLeft->dy; 563 slopes[2].k = pLeft->k; 564 if (swapslopes) 565 { 566 slopes[2].dx = -slopes[2].dx; 567 slopes[2].dy = -slopes[2].dy; 568 slopes[2].k = -slopes[2].k; 569 } 570 vertices[3].x = mx; 571 vertices[3].y = my; 572 slopes[3].dx = pRight->dx; 573 slopes[3].dy = pRight->dy; 574 slopes[3].k = pRight->k; 575 if (swapslopes) 576 { 577 slopes[3].dx = -slopes[3].dx; 578 slopes[3].dy = -slopes[3].dy; 579 slopes[3].k = -slopes[3].k; 580 } 581 edgecount = 4; 582 } 583 else 584 { 585 double scale, dx, dy, adx, ady; 586 587 adx = dx = pRight->xa - pLeft->xa; 588 ady = dy = pRight->ya - pLeft->ya; 589 if (adx < 0) 590 adx = -adx; 591 if (ady < 0) 592 ady = -ady; 593 scale = ady; 594 if (adx > ady) 595 scale = adx; 596 slopes[2].dx = (dx * 65536) / scale; 597 slopes[2].dy = (dy * 65536) / scale; 598 slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy - 599 (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0; 600 edgecount = 3; 601 } 602 603 y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y, 604 left, right, &nleft, &nright, &height); 605 miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright); 606} 607 608static int 609miLineArcI ( 610 DrawablePtr pDraw, 611 GCPtr pGC, 612 int xorg, 613 int yorg, 614 DDXPointPtr points, 615 int *widths) 616{ 617 DDXPointPtr tpts, bpts; 618 int *twids, *bwids; 619 int x, y, e, ex, slw; 620 621 tpts = points; 622 twids = widths; 623 if (pGC->miTranslate) 624 { 625 xorg += pDraw->x; 626 yorg += pDraw->y; 627 } 628 slw = pGC->lineWidth; 629 if (slw == 1) 630 { 631 tpts->x = xorg; 632 tpts->y = yorg; 633 *twids = 1; 634 return 1; 635 } 636 bpts = tpts + slw; 637 bwids = twids + slw; 638 y = (slw >> 1) + 1; 639 if (slw & 1) 640 e = - ((y << 2) + 3); 641 else 642 e = - (y << 3); 643 ex = -4; 644 x = 0; 645 while (y) 646 { 647 e += (y << 3) - 4; 648 while (e >= 0) 649 { 650 x++; 651 e += (ex = -((x << 3) + 4)); 652 } 653 y--; 654 slw = (x << 1) + 1; 655 if ((e == ex) && (slw > 1)) 656 slw--; 657 tpts->x = xorg - x; 658 tpts->y = yorg - y; 659 tpts++; 660 *twids++ = slw; 661 if ((y != 0) && ((slw > 1) || (e != ex))) 662 { 663 bpts--; 664 bpts->x = xorg - x; 665 bpts->y = yorg + y; 666 *--bwids = slw; 667 } 668 } 669 return (pGC->lineWidth); 670} 671 672#define CLIPSTEPEDGE(edgey,edge,edgeleft) \ 673 if (ybase == edgey) \ 674 { \ 675 if (edgeleft) \ 676 { \ 677 if (edge->x > xcl) \ 678 xcl = edge->x; \ 679 } \ 680 else \ 681 { \ 682 if (edge->x < xcr) \ 683 xcr = edge->x; \ 684 } \ 685 edgey++; \ 686 edge->x += edge->stepx; \ 687 edge->e += edge->dx; \ 688 if (edge->e > 0) \ 689 { \ 690 edge->x += edge->signdx; \ 691 edge->e -= edge->dy; \ 692 } \ 693 } 694 695static int 696miLineArcD ( 697 DrawablePtr pDraw, 698 GCPtr pGC, 699 double xorg, 700 double yorg, 701 DDXPointPtr points, 702 int *widths, 703 PolyEdgePtr edge1, 704 int edgey1, 705 Bool edgeleft1, 706 PolyEdgePtr edge2, 707 int edgey2, 708 Bool edgeleft2) 709{ 710 DDXPointPtr pts; 711 int *wids; 712 double radius, x0, y0, el, er, yk, xlk, xrk, k; 713 int xbase, ybase, y, boty, xl, xr, xcl, xcr; 714 int ymin, ymax; 715 Bool edge1IsMin, edge2IsMin; 716 int ymin1, ymin2; 717 718 pts = points; 719 wids = widths; 720 xbase = floor(xorg); 721 x0 = xorg - xbase; 722 ybase = ICEIL (yorg); 723 y0 = yorg - ybase; 724 if (pGC->miTranslate) 725 { 726 xbase += pDraw->x; 727 ybase += pDraw->y; 728 edge1->x += pDraw->x; 729 edge2->x += pDraw->x; 730 edgey1 += pDraw->y; 731 edgey2 += pDraw->y; 732 } 733 xlk = x0 + x0 + 1.0; 734 xrk = x0 + x0 - 1.0; 735 yk = y0 + y0 - 1.0; 736 radius = ((double)pGC->lineWidth) / 2.0; 737 y = floor(radius - y0 + 1.0); 738 ybase -= y; 739 ymin = ybase; 740 ymax = 65536; 741 edge1IsMin = FALSE; 742 ymin1 = edgey1; 743 if (edge1->dy >= 0) 744 { 745 if (!edge1->dy) 746 { 747 if (edgeleft1) 748 edge1IsMin = TRUE; 749 else 750 ymax = edgey1; 751 edgey1 = 65536; 752 } 753 else 754 { 755 if ((edge1->signdx < 0) == edgeleft1) 756 edge1IsMin = TRUE; 757 } 758 } 759 edge2IsMin = FALSE; 760 ymin2 = edgey2; 761 if (edge2->dy >= 0) 762 { 763 if (!edge2->dy) 764 { 765 if (edgeleft2) 766 edge2IsMin = TRUE; 767 else 768 ymax = edgey2; 769 edgey2 = 65536; 770 } 771 else 772 { 773 if ((edge2->signdx < 0) == edgeleft2) 774 edge2IsMin = TRUE; 775 } 776 } 777 if (edge1IsMin) 778 { 779 ymin = ymin1; 780 if (edge2IsMin && ymin1 > ymin2) 781 ymin = ymin2; 782 } else if (edge2IsMin) 783 ymin = ymin2; 784 el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0); 785 er = el + xrk; 786 xl = 1; 787 xr = 0; 788 if (x0 < 0.5) 789 { 790 xl = 0; 791 el -= xlk; 792 } 793 boty = (y0 < -0.5) ? 1 : 0; 794 if (ybase + y - boty > ymax) 795 boty = ymax - ybase - y; 796 while (y > boty) 797 { 798 k = (y << 1) + yk; 799 er += k; 800 while (er > 0.0) 801 { 802 xr++; 803 er += xrk - (xr << 1); 804 } 805 el += k; 806 while (el >= 0.0) 807 { 808 xl--; 809 el += (xl << 1) - xlk; 810 } 811 y--; 812 ybase++; 813 if (ybase < ymin) 814 continue; 815 xcl = xl + xbase; 816 xcr = xr + xbase; 817 CLIPSTEPEDGE(edgey1, edge1, edgeleft1); 818 CLIPSTEPEDGE(edgey2, edge2, edgeleft2); 819 if (xcr >= xcl) 820 { 821 pts->x = xcl; 822 pts->y = ybase; 823 pts++; 824 *wids++ = xcr - xcl + 1; 825 } 826 } 827 er = xrk - (xr << 1) - er; 828 el = (xl << 1) - xlk - el; 829 boty = floor(-y0 - radius + 1.0); 830 if (ybase + y - boty > ymax) 831 boty = ymax - ybase - y; 832 while (y > boty) 833 { 834 k = (y << 1) + yk; 835 er -= k; 836 while ((er >= 0.0) && (xr >= 0)) 837 { 838 xr--; 839 er += xrk - (xr << 1); 840 } 841 el -= k; 842 while ((el > 0.0) && (xl <= 0)) 843 { 844 xl++; 845 el += (xl << 1) - xlk; 846 } 847 y--; 848 ybase++; 849 if (ybase < ymin) 850 continue; 851 xcl = xl + xbase; 852 xcr = xr + xbase; 853 CLIPSTEPEDGE(edgey1, edge1, edgeleft1); 854 CLIPSTEPEDGE(edgey2, edge2, edgeleft2); 855 if (xcr >= xcl) 856 { 857 pts->x = xcl; 858 pts->y = ybase; 859 pts++; 860 *wids++ = xcr - xcl + 1; 861 } 862 } 863 return (pts - points); 864} 865 866static int 867miRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge) 868{ 869 int y; 870 int dx, dy; 871 double xa, ya; 872 Bool left; 873 874 dx = -face->dy; 875 dy = face->dx; 876 xa = face->xa; 877 ya = face->ya; 878 left = 1; 879 if (ya > 0) 880 { 881 ya = 0.0; 882 xa = 0.0; 883 } 884 if (dy < 0 || (dy == 0 && dx > 0)) 885 { 886 dx = -dx; 887 dy = -dy; 888 left = !left; 889 } 890 if (dx == 0 && dy == 0) 891 dy = 1; 892 if (dy == 0) 893 { 894 y = ICEIL (face->ya) + face->y; 895 edge->x = -32767; 896 edge->stepx = 0; 897 edge->signdx = 0; 898 edge->e = -1; 899 edge->dy = 0; 900 edge->dx = 0; 901 edge->height = 0; 902 } 903 else 904 { 905 y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge); 906 edge->height = 32767; 907 } 908 *leftEdge = !left; 909 return y; 910} 911 912_X_EXPORT void 913miRoundJoinClip (pLeft, pRight, edge1, edge2, y1, y2, left1, left2) 914 LineFacePtr pLeft, pRight; 915 PolyEdgePtr edge1, edge2; 916 int *y1, *y2; 917 Bool *left1, *left2; 918{ 919 double denom; 920 921 denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; 922 923 if (denom >= 0) 924 { 925 pLeft->xa = -pLeft->xa; 926 pLeft->ya = -pLeft->ya; 927 } 928 else 929 { 930 pRight->xa = -pRight->xa; 931 pRight->ya = -pRight->ya; 932 } 933 *y1 = miRoundJoinFace (pLeft, edge1, left1); 934 *y2 = miRoundJoinFace (pRight, edge2, left2); 935} 936 937_X_EXPORT int 938miRoundCapClip (face, isInt, edge, leftEdge) 939 LineFacePtr face; 940 Bool isInt; 941 PolyEdgePtr edge; 942 Bool *leftEdge; 943{ 944 int y; 945 int dx, dy; 946 double xa, ya, k; 947 Bool left; 948 949 dx = -face->dy; 950 dy = face->dx; 951 xa = face->xa; 952 ya = face->ya; 953 k = 0.0; 954 if (!isInt) 955 k = face->k; 956 left = 1; 957 if (dy < 0 || (dy == 0 && dx > 0)) 958 { 959 dx = -dx; 960 dy = -dy; 961 xa = -xa; 962 ya = -ya; 963 left = !left; 964 } 965 if (dx == 0 && dy == 0) 966 dy = 1; 967 if (dy == 0) 968 { 969 y = ICEIL (face->ya) + face->y; 970 edge->x = -32767; 971 edge->stepx = 0; 972 edge->signdx = 0; 973 edge->e = -1; 974 edge->dy = 0; 975 edge->dx = 0; 976 edge->height = 0; 977 } 978 else 979 { 980 y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge); 981 edge->height = 32767; 982 } 983 *leftEdge = !left; 984 return y; 985} 986 987static void 988miLineArc ( 989 DrawablePtr pDraw, 990 GCPtr pGC, 991 unsigned long pixel, 992 SpanDataPtr spanData, 993 LineFacePtr leftFace, 994 LineFacePtr rightFace, 995 double xorg, 996 double yorg, 997 Bool isInt) 998{ 999 DDXPointPtr points; 1000 int *widths; 1001 int xorgi = 0, yorgi = 0; 1002 XID oldPixel; 1003 Spans spanRec; 1004 int n; 1005 PolyEdgeRec edge1, edge2; 1006 int edgey1, edgey2; 1007 Bool edgeleft1, edgeleft2; 1008 1009 if (isInt) 1010 { 1011 xorgi = leftFace ? leftFace->x : rightFace->x; 1012 yorgi = leftFace ? leftFace->y : rightFace->y; 1013 } 1014 edgey1 = 65536; 1015 edgey2 = 65536; 1016 edge1.x = 0; /* not used, keep memory checkers happy */ 1017 edge1.dy = -1; 1018 edge2.x = 0; /* not used, keep memory checkers happy */ 1019 edge2.dy = -1; 1020 edgeleft1 = FALSE; 1021 edgeleft2 = FALSE; 1022 if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) && 1023 ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) || 1024 (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))) 1025 { 1026 if (isInt) 1027 { 1028 xorg = (double) xorgi; 1029 yorg = (double) yorgi; 1030 } 1031 if (leftFace && rightFace) 1032 { 1033 miRoundJoinClip (leftFace, rightFace, &edge1, &edge2, 1034 &edgey1, &edgey2, &edgeleft1, &edgeleft2); 1035 } 1036 else if (leftFace) 1037 { 1038 edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1); 1039 } 1040 else if (rightFace) 1041 { 1042 edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2); 1043 } 1044 isInt = FALSE; 1045 } 1046 if (!spanData) 1047 { 1048 points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * pGC->lineWidth); 1049 if (!points) 1050 return; 1051 widths = (int *)ALLOCATE_LOCAL(sizeof(int) * pGC->lineWidth); 1052 if (!widths) 1053 { 1054 DEALLOCATE_LOCAL(points); 1055 return; 1056 } 1057 oldPixel = pGC->fgPixel; 1058 if (pixel != oldPixel) 1059 { 1060 XID tmpPixel = (XID)pixel; 1061 DoChangeGC(pGC, GCForeground, &tmpPixel, FALSE); 1062 ValidateGC (pDraw, pGC); 1063 } 1064 } 1065 else 1066 { 1067 points = (DDXPointPtr) xalloc (pGC->lineWidth * sizeof (DDXPointRec)); 1068 if (!points) 1069 return; 1070 widths = (int *) xalloc (pGC->lineWidth * sizeof (int)); 1071 if (!widths) 1072 { 1073 xfree (points); 1074 return; 1075 } 1076 spanRec.points = points; 1077 spanRec.widths = widths; 1078 } 1079 if (isInt) 1080 n = miLineArcI(pDraw, pGC, xorgi, yorgi, points, widths); 1081 else 1082 n = miLineArcD(pDraw, pGC, xorg, yorg, points, widths, 1083 &edge1, edgey1, edgeleft1, 1084 &edge2, edgey2, edgeleft2); 1085 1086 if (!spanData) 1087 { 1088 (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, TRUE); 1089 DEALLOCATE_LOCAL(widths); 1090 DEALLOCATE_LOCAL(points); 1091 if (pixel != oldPixel) 1092 { 1093 DoChangeGC(pGC, GCForeground, &oldPixel, FALSE); 1094 ValidateGC (pDraw, pGC); 1095 } 1096 } 1097 else 1098 { 1099 spanRec.count = n; 1100 AppendSpanGroup (pGC, pixel, &spanRec, spanData) 1101 } 1102} 1103 1104static void 1105miLineProjectingCap (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, 1106 SpanDataPtr spanData, LineFacePtr face, Bool isLeft, 1107 double xorg, double yorg, Bool isInt) 1108{ 1109 int xorgi = 0, yorgi = 0; 1110 int lw; 1111 PolyEdgeRec lefts[2], rights[2]; 1112 int lefty, righty, topy, bottomy; 1113 PolyEdgePtr left, right; 1114 PolyEdgePtr top, bottom; 1115 double xa,ya; 1116 double k; 1117 double xap, yap; 1118 int dx, dy; 1119 double projectXoff, projectYoff; 1120 double maxy; 1121 int finaly; 1122 1123 if (isInt) 1124 { 1125 xorgi = face->x; 1126 yorgi = face->y; 1127 } 1128 lw = pGC->lineWidth; 1129 dx = face->dx; 1130 dy = face->dy; 1131 k = face->k; 1132 if (dy == 0) 1133 { 1134 lefts[0].height = lw; 1135 lefts[0].x = xorgi; 1136 if (isLeft) 1137 lefts[0].x -= (lw >> 1); 1138 lefts[0].stepx = 0; 1139 lefts[0].signdx = 1; 1140 lefts[0].e = -lw; 1141 lefts[0].dx = 0; 1142 lefts[0].dy = lw; 1143 rights[0].height = lw; 1144 rights[0].x = xorgi; 1145 if (!isLeft) 1146 rights[0].x += ((lw + 1) >> 1); 1147 rights[0].stepx = 0; 1148 rights[0].signdx = 1; 1149 rights[0].e = -lw; 1150 rights[0].dx = 0; 1151 rights[0].dy = lw; 1152 miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw, 1153 lefts, rights, 1, 1); 1154 } 1155 else if (dx == 0) 1156 { 1157 if (dy < 0) { 1158 dy = -dy; 1159 isLeft = !isLeft; 1160 } 1161 topy = yorgi; 1162 bottomy = yorgi + dy; 1163 if (isLeft) 1164 topy -= (lw >> 1); 1165 else 1166 bottomy += (lw >> 1); 1167 lefts[0].height = bottomy - topy; 1168 lefts[0].x = xorgi - (lw >> 1); 1169 lefts[0].stepx = 0; 1170 lefts[0].signdx = 1; 1171 lefts[0].e = -dy; 1172 lefts[0].dx = dx; 1173 lefts[0].dy = dy; 1174 1175 rights[0].height = bottomy - topy; 1176 rights[0].x = lefts[0].x + (lw-1); 1177 rights[0].stepx = 0; 1178 rights[0].signdx = 1; 1179 rights[0].e = -dy; 1180 rights[0].dx = dx; 1181 rights[0].dy = dy; 1182 miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1); 1183 } 1184 else 1185 { 1186 xa = face->xa; 1187 ya = face->ya; 1188 projectXoff = -ya; 1189 projectYoff = xa; 1190 if (dx < 0) 1191 { 1192 right = &rights[1]; 1193 left = &lefts[0]; 1194 top = &rights[0]; 1195 bottom = &lefts[1]; 1196 } 1197 else 1198 { 1199 right = &rights[0]; 1200 left = &lefts[1]; 1201 top = &lefts[0]; 1202 bottom = &rights[1]; 1203 } 1204 if (isLeft) 1205 { 1206 righty = miPolyBuildEdge (xa, ya, 1207 k, dx, dy, xorgi, yorgi, 0, right); 1208 1209 xa = -xa; 1210 ya = -ya; 1211 k = -k; 1212 lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, 1213 k, dx, dy, xorgi, yorgi, 1, left); 1214 if (dx > 0) 1215 { 1216 ya = -ya; 1217 xa = -xa; 1218 } 1219 xap = xa - projectXoff; 1220 yap = ya - projectYoff; 1221 topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, 1222 -dy, dx, xorgi, yorgi, dx > 0, top); 1223 bottomy = miPolyBuildEdge (xa, ya, 1224 0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom); 1225 maxy = -ya; 1226 } 1227 else 1228 { 1229 righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, 1230 k, dx, dy, xorgi, yorgi, 0, right); 1231 1232 xa = -xa; 1233 ya = -ya; 1234 k = -k; 1235 lefty = miPolyBuildEdge (xa, ya, 1236 k, dx, dy, xorgi, yorgi, 1, left); 1237 if (dx > 0) 1238 { 1239 ya = -ya; 1240 xa = -xa; 1241 } 1242 xap = xa - projectXoff; 1243 yap = ya - projectYoff; 1244 topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top); 1245 bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, 1246 -dy, dx, xorgi, xorgi, dx < 0, bottom); 1247 maxy = -ya + projectYoff; 1248 } 1249 finaly = ICEIL(maxy) + yorgi; 1250 if (dx < 0) 1251 { 1252 left->height = bottomy - lefty; 1253 right->height = finaly - righty; 1254 top->height = righty - topy; 1255 } 1256 else 1257 { 1258 right->height = bottomy - righty; 1259 left->height = finaly - lefty; 1260 top->height = lefty - topy; 1261 } 1262 bottom->height = finaly - bottomy; 1263 miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, 1264 bottom->height + bottomy - topy, lefts, rights, 2, 2); 1265 } 1266} 1267 1268static void 1269miWideSegment ( 1270 DrawablePtr pDrawable, 1271 GCPtr pGC, 1272 unsigned long pixel, 1273 SpanDataPtr spanData, 1274 int x1, 1275 int y1, 1276 int x2, 1277 int y2, 1278 Bool projectLeft, 1279 Bool projectRight, 1280 LineFacePtr leftFace, 1281 LineFacePtr rightFace) 1282{ 1283 double l, L, r; 1284 double xa, ya; 1285 double projectXoff = 0.0, projectYoff = 0.0; 1286 double k; 1287 double maxy; 1288 int x, y; 1289 int dx, dy; 1290 int finaly; 1291 PolyEdgePtr left, right; 1292 PolyEdgePtr top, bottom; 1293 int lefty, righty, topy, bottomy; 1294 int signdx; 1295 PolyEdgeRec lefts[2], rights[2]; 1296 LineFacePtr tface; 1297 int lw = pGC->lineWidth; 1298 1299 /* draw top-to-bottom always */ 1300 if (y2 < y1 || (y2 == y1 && x2 < x1)) 1301 { 1302 x = x1; 1303 x1 = x2; 1304 x2 = x; 1305 1306 y = y1; 1307 y1 = y2; 1308 y2 = y; 1309 1310 x = projectLeft; 1311 projectLeft = projectRight; 1312 projectRight = x; 1313 1314 tface = leftFace; 1315 leftFace = rightFace; 1316 rightFace = tface; 1317 } 1318 1319 dy = y2 - y1; 1320 signdx = 1; 1321 dx = x2 - x1; 1322 if (dx < 0) 1323 signdx = -1; 1324 1325 leftFace->x = x1; 1326 leftFace->y = y1; 1327 leftFace->dx = dx; 1328 leftFace->dy = dy; 1329 1330 rightFace->x = x2; 1331 rightFace->y = y2; 1332 rightFace->dx = -dx; 1333 rightFace->dy = -dy; 1334 1335 if (dy == 0) 1336 { 1337 rightFace->xa = 0; 1338 rightFace->ya = (double) lw / 2.0; 1339 rightFace->k = -(double) (lw * dx) / 2.0; 1340 leftFace->xa = 0; 1341 leftFace->ya = -rightFace->ya; 1342 leftFace->k = rightFace->k; 1343 x = x1; 1344 if (projectLeft) 1345 x -= (lw >> 1); 1346 y = y1 - (lw >> 1); 1347 dx = x2 - x; 1348 if (projectRight) 1349 dx += ((lw + 1) >> 1); 1350 dy = lw; 1351 miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, 1352 x, y, dx, dy); 1353 } 1354 else if (dx == 0) 1355 { 1356 leftFace->xa = (double) lw / 2.0; 1357 leftFace->ya = 0; 1358 leftFace->k = (double) (lw * dy) / 2.0; 1359 rightFace->xa = -leftFace->xa; 1360 rightFace->ya = 0; 1361 rightFace->k = leftFace->k; 1362 y = y1; 1363 if (projectLeft) 1364 y -= lw >> 1; 1365 x = x1 - (lw >> 1); 1366 dy = y2 - y; 1367 if (projectRight) 1368 dy += ((lw + 1) >> 1); 1369 dx = lw; 1370 miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, 1371 x, y, dx, dy); 1372 } 1373 else 1374 { 1375 l = ((double) lw) / 2.0; 1376 L = hypot ((double) dx, (double) dy); 1377 1378 if (dx < 0) 1379 { 1380 right = &rights[1]; 1381 left = &lefts[0]; 1382 top = &rights[0]; 1383 bottom = &lefts[1]; 1384 } 1385 else 1386 { 1387 right = &rights[0]; 1388 left = &lefts[1]; 1389 top = &lefts[0]; 1390 bottom = &rights[1]; 1391 } 1392 r = l / L; 1393 1394 /* coord of upper bound at integral y */ 1395 ya = -r * dx; 1396 xa = r * dy; 1397 1398 if (projectLeft | projectRight) 1399 { 1400 projectXoff = -ya; 1401 projectYoff = xa; 1402 } 1403 1404 /* xa * dy - ya * dx */ 1405 k = l * L; 1406 1407 leftFace->xa = xa; 1408 leftFace->ya = ya; 1409 leftFace->k = k; 1410 rightFace->xa = -xa; 1411 rightFace->ya = -ya; 1412 rightFace->k = k; 1413 1414 if (projectLeft) 1415 righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, 1416 k, dx, dy, x1, y1, 0, right); 1417 else 1418 righty = miPolyBuildEdge (xa, ya, 1419 k, dx, dy, x1, y1, 0, right); 1420 1421 /* coord of lower bound at integral y */ 1422 ya = -ya; 1423 xa = -xa; 1424 1425 /* xa * dy - ya * dx */ 1426 k = - k; 1427 1428 if (projectLeft) 1429 lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, 1430 k, dx, dy, x1, y1, 1, left); 1431 else 1432 lefty = miPolyBuildEdge (xa, ya, 1433 k, dx, dy, x1, y1, 1, left); 1434 1435 /* coord of top face at integral y */ 1436 1437 if (signdx > 0) 1438 { 1439 ya = -ya; 1440 xa = -xa; 1441 } 1442 1443 if (projectLeft) 1444 { 1445 double xap = xa - projectXoff; 1446 double yap = ya - projectYoff; 1447 topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, 1448 -dy, dx, x1, y1, dx > 0, top); 1449 } 1450 else 1451 topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top); 1452 1453 /* coord of bottom face at integral y */ 1454 1455 if (projectRight) 1456 { 1457 double xap = xa + projectXoff; 1458 double yap = ya + projectYoff; 1459 bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, 1460 -dy, dx, x2, y2, dx < 0, bottom); 1461 maxy = -ya + projectYoff; 1462 } 1463 else 1464 { 1465 bottomy = miPolyBuildEdge (xa, ya, 1466 0.0, -dy, dx, x2, y2, dx < 0, bottom); 1467 maxy = -ya; 1468 } 1469 1470 finaly = ICEIL (maxy) + y2; 1471 1472 if (dx < 0) 1473 { 1474 left->height = bottomy - lefty; 1475 right->height = finaly - righty; 1476 top->height = righty - topy; 1477 } 1478 else 1479 { 1480 right->height = bottomy - righty; 1481 left->height = finaly - lefty; 1482 top->height = lefty - topy; 1483 } 1484 bottom->height = finaly - bottomy; 1485 miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, 1486 bottom->height + bottomy - topy, lefts, rights, 2, 2); 1487 } 1488} 1489 1490static SpanDataPtr 1491miSetupSpanData (GCPtr pGC, SpanDataPtr spanData, int npt) 1492{ 1493 if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu)) 1494 return (SpanDataPtr) NULL; 1495 if (pGC->lineStyle == LineDoubleDash) 1496 miInitSpanGroup (&spanData->bgGroup); 1497 miInitSpanGroup (&spanData->fgGroup); 1498 return spanData; 1499} 1500 1501static void 1502miCleanupSpanData (DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData) 1503{ 1504 if (pGC->lineStyle == LineDoubleDash) 1505 { 1506 XID oldPixel, pixel; 1507 1508 pixel = pGC->bgPixel; 1509 oldPixel = pGC->fgPixel; 1510 if (pixel != oldPixel) 1511 { 1512 DoChangeGC (pGC, GCForeground, &pixel, FALSE); 1513 ValidateGC (pDrawable, pGC); 1514 } 1515 miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup); 1516 miFreeSpanGroup (&spanData->bgGroup); 1517 if (pixel != oldPixel) 1518 { 1519 DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); 1520 ValidateGC (pDrawable, pGC); 1521 } 1522 } 1523 miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup); 1524 miFreeSpanGroup (&spanData->fgGroup); 1525} 1526 1527_X_EXPORT void 1528miWideLine (pDrawable, pGC, mode, npt, pPts) 1529 DrawablePtr pDrawable; 1530 GCPtr pGC; 1531 int mode; 1532 int npt; 1533 DDXPointPtr pPts; 1534{ 1535 int x1, y1, x2, y2; 1536 SpanDataRec spanDataRec; 1537 SpanDataPtr spanData; 1538 long pixel; 1539 Bool projectLeft, projectRight; 1540 LineFaceRec leftFace, rightFace, prevRightFace; 1541 LineFaceRec firstFace; 1542 int first; 1543 Bool somethingDrawn = FALSE; 1544 Bool selfJoin; 1545 1546 spanData = miSetupSpanData (pGC, &spanDataRec, npt); 1547 pixel = pGC->fgPixel; 1548 x2 = pPts->x; 1549 y2 = pPts->y; 1550 first = TRUE; 1551 selfJoin = FALSE; 1552 if (npt > 1) 1553 { 1554 if (mode == CoordModePrevious) 1555 { 1556 int nptTmp; 1557 DDXPointPtr pPtsTmp; 1558 1559 x1 = x2; 1560 y1 = y2; 1561 nptTmp = npt; 1562 pPtsTmp = pPts + 1; 1563 while (--nptTmp) 1564 { 1565 x1 += pPtsTmp->x; 1566 y1 += pPtsTmp->y; 1567 ++pPtsTmp; 1568 } 1569 if (x2 == x1 && y2 == y1) 1570 selfJoin = TRUE; 1571 } 1572 else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) 1573 { 1574 selfJoin = TRUE; 1575 } 1576 } 1577 projectLeft = pGC->capStyle == CapProjecting && !selfJoin; 1578 projectRight = FALSE; 1579 while (--npt) 1580 { 1581 x1 = x2; 1582 y1 = y2; 1583 ++pPts; 1584 x2 = pPts->x; 1585 y2 = pPts->y; 1586 if (mode == CoordModePrevious) 1587 { 1588 x2 += x1; 1589 y2 += y1; 1590 } 1591 if (x1 != x2 || y1 != y2) 1592 { 1593 somethingDrawn = TRUE; 1594 if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin) 1595 projectRight = TRUE; 1596 miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2, 1597 projectLeft, projectRight, &leftFace, &rightFace); 1598 if (first) 1599 { 1600 if (selfJoin) 1601 firstFace = leftFace; 1602 else if (pGC->capStyle == CapRound) 1603 { 1604 if (pGC->lineWidth == 1 && !spanData) 1605 miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1); 1606 else 1607 miLineArc (pDrawable, pGC, pixel, spanData, 1608 &leftFace, (LineFacePtr) NULL, 1609 (double)0.0, (double)0.0, 1610 TRUE); 1611 } 1612 } 1613 else 1614 { 1615 miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, 1616 &prevRightFace); 1617 } 1618 prevRightFace = rightFace; 1619 first = FALSE; 1620 projectLeft = FALSE; 1621 } 1622 if (npt == 1 && somethingDrawn) 1623 { 1624 if (selfJoin) 1625 miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, 1626 &rightFace); 1627 else if (pGC->capStyle == CapRound) 1628 { 1629 if (pGC->lineWidth == 1 && !spanData) 1630 miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2); 1631 else 1632 miLineArc (pDrawable, pGC, pixel, spanData, 1633 (LineFacePtr) NULL, &rightFace, 1634 (double)0.0, (double)0.0, 1635 TRUE); 1636 } 1637 } 1638 } 1639 /* handle crock where all points are coincedent */ 1640 if (!somethingDrawn) 1641 { 1642 projectLeft = pGC->capStyle == CapProjecting; 1643 miWideSegment (pDrawable, pGC, pixel, spanData, 1644 x2, y2, x2, y2, projectLeft, projectLeft, 1645 &leftFace, &rightFace); 1646 if (pGC->capStyle == CapRound) 1647 { 1648 miLineArc (pDrawable, pGC, pixel, spanData, 1649 &leftFace, (LineFacePtr) NULL, 1650 (double)0.0, (double)0.0, 1651 TRUE); 1652 rightFace.dx = -1; /* sleezy hack to make it work */ 1653 miLineArc (pDrawable, pGC, pixel, spanData, 1654 (LineFacePtr) NULL, &rightFace, 1655 (double)0.0, (double)0.0, 1656 TRUE); 1657 } 1658 } 1659 if (spanData) 1660 miCleanupSpanData (pDrawable, pGC, spanData); 1661} 1662 1663#define V_TOP 0 1664#define V_RIGHT 1 1665#define V_BOTTOM 2 1666#define V_LEFT 3 1667 1668static void 1669miWideDashSegment ( 1670 DrawablePtr pDrawable, 1671 GCPtr pGC, 1672 SpanDataPtr spanData, 1673 int *pDashOffset, 1674 int *pDashIndex, 1675 int x1, 1676 int y1, 1677 int x2, 1678 int y2, 1679 Bool projectLeft, 1680 Bool projectRight, 1681 LineFacePtr leftFace, 1682 LineFacePtr rightFace) 1683{ 1684 int dashIndex, dashRemain; 1685 unsigned char *pDash; 1686 double L, l; 1687 double k; 1688 PolyVertexRec vertices[4]; 1689 PolyVertexRec saveRight, saveBottom; 1690 PolySlopeRec slopes[4]; 1691 PolyEdgeRec left[2], right[2]; 1692 LineFaceRec lcapFace, rcapFace; 1693 int nleft, nright; 1694 int h; 1695 int y; 1696 int dy, dx; 1697 unsigned long pixel; 1698 double LRemain; 1699 double r; 1700 double rdx, rdy; 1701 double dashDx, dashDy; 1702 double saveK = 0.0; 1703 Bool first = TRUE; 1704 double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0; 1705 unsigned long fgPixel, bgPixel; 1706 1707 dx = x2 - x1; 1708 dy = y2 - y1; 1709 dashIndex = *pDashIndex; 1710 pDash = pGC->dash; 1711 dashRemain = pDash[dashIndex] - *pDashOffset; 1712 fgPixel = pGC->fgPixel; 1713 bgPixel = pGC->bgPixel; 1714 if (pGC->fillStyle == FillOpaqueStippled || 1715 pGC->fillStyle == FillTiled) 1716 { 1717 bgPixel = fgPixel; 1718 } 1719 1720 l = ((double) pGC->lineWidth) / 2.0; 1721 if (dx == 0) 1722 { 1723 L = dy; 1724 rdx = 0; 1725 rdy = l; 1726 if (dy < 0) 1727 { 1728 L = -dy; 1729 rdy = -l; 1730 } 1731 } 1732 else if (dy == 0) 1733 { 1734 L = dx; 1735 rdx = l; 1736 rdy = 0; 1737 if (dx < 0) 1738 { 1739 L = -dx; 1740 rdx = -l; 1741 } 1742 } 1743 else 1744 { 1745 L = hypot ((double) dx, (double) dy); 1746 r = l / L; 1747 1748 rdx = r * dx; 1749 rdy = r * dy; 1750 } 1751 k = l * L; 1752 LRemain = L; 1753 /* All position comments are relative to a line with dx and dy > 0, 1754 * but the code does not depend on this */ 1755 /* top */ 1756 slopes[V_TOP].dx = dx; 1757 slopes[V_TOP].dy = dy; 1758 slopes[V_TOP].k = k; 1759 /* right */ 1760 slopes[V_RIGHT].dx = -dy; 1761 slopes[V_RIGHT].dy = dx; 1762 slopes[V_RIGHT].k = 0; 1763 /* bottom */ 1764 slopes[V_BOTTOM].dx = -dx; 1765 slopes[V_BOTTOM].dy = -dy; 1766 slopes[V_BOTTOM].k = k; 1767 /* left */ 1768 slopes[V_LEFT].dx = dy; 1769 slopes[V_LEFT].dy = -dx; 1770 slopes[V_LEFT].k = 0; 1771 1772 /* preload the start coordinates */ 1773 vertices[V_RIGHT].x = vertices[V_TOP].x = rdy; 1774 vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx; 1775 1776 vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy; 1777 vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx; 1778 1779 if (projectLeft) 1780 { 1781 vertices[V_TOP].x -= rdx; 1782 vertices[V_TOP].y -= rdy; 1783 1784 vertices[V_LEFT].x -= rdx; 1785 vertices[V_LEFT].y -= rdy; 1786 1787 slopes[V_LEFT].k = rdx * dx + rdy * dy; 1788 } 1789 1790 lcenterx = x1; 1791 lcentery = y1; 1792 1793 if (pGC->capStyle == CapRound) 1794 { 1795 lcapFace.dx = dx; 1796 lcapFace.dy = dy; 1797 lcapFace.x = x1; 1798 lcapFace.y = y1; 1799 1800 rcapFace.dx = -dx; 1801 rcapFace.dy = -dy; 1802 rcapFace.x = x1; 1803 rcapFace.y = y1; 1804 } 1805 while (LRemain > dashRemain) 1806 { 1807 dashDx = (dashRemain * dx) / L; 1808 dashDy = (dashRemain * dy) / L; 1809 1810 rcenterx = lcenterx + dashDx; 1811 rcentery = lcentery + dashDy; 1812 1813 vertices[V_RIGHT].x += dashDx; 1814 vertices[V_RIGHT].y += dashDy; 1815 1816 vertices[V_BOTTOM].x += dashDx; 1817 vertices[V_BOTTOM].y += dashDy; 1818 1819 slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy; 1820 1821 if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) 1822 { 1823 if (pGC->lineStyle == LineOnOffDash && 1824 pGC->capStyle == CapProjecting) 1825 { 1826 saveRight = vertices[V_RIGHT]; 1827 saveBottom = vertices[V_BOTTOM]; 1828 saveK = slopes[V_RIGHT].k; 1829 1830 if (!first) 1831 { 1832 vertices[V_TOP].x -= rdx; 1833 vertices[V_TOP].y -= rdy; 1834 1835 vertices[V_LEFT].x -= rdx; 1836 vertices[V_LEFT].y -= rdy; 1837 1838 slopes[V_LEFT].k = vertices[V_LEFT].x * 1839 slopes[V_LEFT].dy - 1840 vertices[V_LEFT].y * 1841 slopes[V_LEFT].dx; 1842 } 1843 1844 vertices[V_RIGHT].x += rdx; 1845 vertices[V_RIGHT].y += rdy; 1846 1847 vertices[V_BOTTOM].x += rdx; 1848 vertices[V_BOTTOM].y += rdy; 1849 1850 slopes[V_RIGHT].k = vertices[V_RIGHT].x * 1851 slopes[V_RIGHT].dy - 1852 vertices[V_RIGHT].y * 1853 slopes[V_RIGHT].dx; 1854 } 1855 y = miPolyBuildPoly (vertices, slopes, 4, x1, y1, 1856 left, right, &nleft, &nright, &h); 1857 pixel = (dashIndex & 1) ? bgPixel : fgPixel; 1858 miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); 1859 1860 if (pGC->lineStyle == LineOnOffDash) 1861 { 1862 switch (pGC->capStyle) 1863 { 1864 case CapProjecting: 1865 vertices[V_BOTTOM] = saveBottom; 1866 vertices[V_RIGHT] = saveRight; 1867 slopes[V_RIGHT].k = saveK; 1868 break; 1869 case CapRound: 1870 if (!first) 1871 { 1872 if (dx < 0) 1873 { 1874 lcapFace.xa = -vertices[V_LEFT].x; 1875 lcapFace.ya = -vertices[V_LEFT].y; 1876 lcapFace.k = slopes[V_LEFT].k; 1877 } 1878 else 1879 { 1880 lcapFace.xa = vertices[V_TOP].x; 1881 lcapFace.ya = vertices[V_TOP].y; 1882 lcapFace.k = -slopes[V_LEFT].k; 1883 } 1884 miLineArc (pDrawable, pGC, pixel, spanData, 1885 &lcapFace, (LineFacePtr) NULL, 1886 lcenterx, lcentery, FALSE); 1887 } 1888 if (dx < 0) 1889 { 1890 rcapFace.xa = vertices[V_BOTTOM].x; 1891 rcapFace.ya = vertices[V_BOTTOM].y; 1892 rcapFace.k = slopes[V_RIGHT].k; 1893 } 1894 else 1895 { 1896 rcapFace.xa = -vertices[V_RIGHT].x; 1897 rcapFace.ya = -vertices[V_RIGHT].y; 1898 rcapFace.k = -slopes[V_RIGHT].k; 1899 } 1900 miLineArc (pDrawable, pGC, pixel, spanData, 1901 (LineFacePtr) NULL, &rcapFace, 1902 rcenterx, rcentery, FALSE); 1903 break; 1904 } 1905 } 1906 } 1907 LRemain -= dashRemain; 1908 ++dashIndex; 1909 if (dashIndex == pGC->numInDashList) 1910 dashIndex = 0; 1911 dashRemain = pDash[dashIndex]; 1912 1913 lcenterx = rcenterx; 1914 lcentery = rcentery; 1915 1916 vertices[V_TOP] = vertices[V_RIGHT]; 1917 vertices[V_LEFT] = vertices[V_BOTTOM]; 1918 slopes[V_LEFT].k = -slopes[V_RIGHT].k; 1919 first = FALSE; 1920 } 1921 1922 if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) 1923 { 1924 vertices[V_TOP].x -= dx; 1925 vertices[V_TOP].y -= dy; 1926 1927 vertices[V_LEFT].x -= dx; 1928 vertices[V_LEFT].y -= dy; 1929 1930 vertices[V_RIGHT].x = rdy; 1931 vertices[V_RIGHT].y = -rdx; 1932 1933 vertices[V_BOTTOM].x = -rdy; 1934 vertices[V_BOTTOM].y = rdx; 1935 1936 1937 if (projectRight) 1938 { 1939 vertices[V_RIGHT].x += rdx; 1940 vertices[V_RIGHT].y += rdy; 1941 1942 vertices[V_BOTTOM].x += rdx; 1943 vertices[V_BOTTOM].y += rdy; 1944 slopes[V_RIGHT].k = vertices[V_RIGHT].x * 1945 slopes[V_RIGHT].dy - 1946 vertices[V_RIGHT].y * 1947 slopes[V_RIGHT].dx; 1948 } 1949 else 1950 slopes[V_RIGHT].k = 0; 1951 1952 if (!first && pGC->lineStyle == LineOnOffDash && 1953 pGC->capStyle == CapProjecting) 1954 { 1955 vertices[V_TOP].x -= rdx; 1956 vertices[V_TOP].y -= rdy; 1957 1958 vertices[V_LEFT].x -= rdx; 1959 vertices[V_LEFT].y -= rdy; 1960 slopes[V_LEFT].k = vertices[V_LEFT].x * 1961 slopes[V_LEFT].dy - 1962 vertices[V_LEFT].y * 1963 slopes[V_LEFT].dx; 1964 } 1965 else 1966 slopes[V_LEFT].k += dx * dx + dy * dy; 1967 1968 1969 y = miPolyBuildPoly (vertices, slopes, 4, x2, y2, 1970 left, right, &nleft, &nright, &h); 1971 1972 pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; 1973 miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); 1974 if (!first && pGC->lineStyle == LineOnOffDash && 1975 pGC->capStyle == CapRound) 1976 { 1977 lcapFace.x = x2; 1978 lcapFace.y = y2; 1979 if (dx < 0) 1980 { 1981 lcapFace.xa = -vertices[V_LEFT].x; 1982 lcapFace.ya = -vertices[V_LEFT].y; 1983 lcapFace.k = slopes[V_LEFT].k; 1984 } 1985 else 1986 { 1987 lcapFace.xa = vertices[V_TOP].x; 1988 lcapFace.ya = vertices[V_TOP].y; 1989 lcapFace.k = -slopes[V_LEFT].k; 1990 } 1991 miLineArc (pDrawable, pGC, pixel, spanData, 1992 &lcapFace, (LineFacePtr) NULL, 1993 rcenterx, rcentery, FALSE); 1994 } 1995 } 1996 dashRemain = ((double) dashRemain) - LRemain; 1997 if (dashRemain == 0) 1998 { 1999 dashIndex++; 2000 if (dashIndex == pGC->numInDashList) 2001 dashIndex = 0; 2002 dashRemain = pDash[dashIndex]; 2003 } 2004 2005 leftFace->x = x1; 2006 leftFace->y = y1; 2007 leftFace->dx = dx; 2008 leftFace->dy = dy; 2009 leftFace->xa = rdy; 2010 leftFace->ya = -rdx; 2011 leftFace->k = k; 2012 2013 rightFace->x = x2; 2014 rightFace->y = y2; 2015 rightFace->dx = -dx; 2016 rightFace->dy = -dy; 2017 rightFace->xa = -rdy; 2018 rightFace->ya = rdx; 2019 rightFace->k = k; 2020 2021 *pDashIndex = dashIndex; 2022 *pDashOffset = pDash[dashIndex] - dashRemain; 2023} 2024 2025_X_EXPORT void 2026miWideDash (pDrawable, pGC, mode, npt, pPts) 2027 DrawablePtr pDrawable; 2028 GCPtr pGC; 2029 int mode; 2030 int npt; 2031 DDXPointPtr pPts; 2032{ 2033 int x1, y1, x2, y2; 2034 unsigned long pixel; 2035 Bool projectLeft, projectRight; 2036 LineFaceRec leftFace, rightFace, prevRightFace; 2037 LineFaceRec firstFace; 2038 int first; 2039 int dashIndex, dashOffset; 2040 int prevDashIndex; 2041 SpanDataRec spanDataRec; 2042 SpanDataPtr spanData; 2043 Bool somethingDrawn = FALSE; 2044 Bool selfJoin; 2045 Bool endIsFg = FALSE, startIsFg = FALSE; 2046 Bool firstIsFg = FALSE, prevIsFg = FALSE; 2047 2048#if 0 2049 /* XXX backward compatibility */ 2050 if (pGC->lineWidth == 0) 2051 { 2052 miZeroDashLine (pDrawable, pGC, mode, npt, pPts); 2053 return; 2054 } 2055#endif 2056 if (pGC->lineStyle == LineDoubleDash && 2057 (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) 2058 { 2059 miWideLine (pDrawable, pGC, mode, npt, pPts); 2060 return; 2061 } 2062 if (npt == 0) 2063 return; 2064 spanData = miSetupSpanData (pGC, &spanDataRec, npt); 2065 x2 = pPts->x; 2066 y2 = pPts->y; 2067 first = TRUE; 2068 selfJoin = FALSE; 2069 if (mode == CoordModePrevious) 2070 { 2071 int nptTmp; 2072 DDXPointPtr pPtsTmp; 2073 2074 x1 = x2; 2075 y1 = y2; 2076 nptTmp = npt; 2077 pPtsTmp = pPts + 1; 2078 while (--nptTmp) 2079 { 2080 x1 += pPtsTmp->x; 2081 y1 += pPtsTmp->y; 2082 ++pPtsTmp; 2083 } 2084 if (x2 == x1 && y2 == y1) 2085 selfJoin = TRUE; 2086 } 2087 else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) 2088 { 2089 selfJoin = TRUE; 2090 } 2091 projectLeft = pGC->capStyle == CapProjecting && !selfJoin; 2092 projectRight = FALSE; 2093 dashIndex = 0; 2094 dashOffset = 0; 2095 miStepDash ((int)pGC->dashOffset, &dashIndex, 2096 pGC->dash, (int)pGC->numInDashList, &dashOffset); 2097 while (--npt) 2098 { 2099 x1 = x2; 2100 y1 = y2; 2101 ++pPts; 2102 x2 = pPts->x; 2103 y2 = pPts->y; 2104 if (mode == CoordModePrevious) 2105 { 2106 x2 += x1; 2107 y2 += y1; 2108 } 2109 if (x1 != x2 || y1 != y2) 2110 { 2111 somethingDrawn = TRUE; 2112 if (npt == 1 && pGC->capStyle == CapProjecting && 2113 (!selfJoin || !firstIsFg)) 2114 projectRight = TRUE; 2115 prevDashIndex = dashIndex; 2116 miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex, 2117 x1, y1, x2, y2, 2118 projectLeft, projectRight, &leftFace, &rightFace); 2119 startIsFg = !(prevDashIndex & 1); 2120 endIsFg = (dashIndex & 1) ^ (dashOffset != 0); 2121 if (pGC->lineStyle == LineDoubleDash || startIsFg) 2122 { 2123 pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel; 2124 if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) 2125 { 2126 if (first && selfJoin) 2127 { 2128 firstFace = leftFace; 2129 firstIsFg = startIsFg; 2130 } 2131 else if (pGC->capStyle == CapRound) 2132 miLineArc (pDrawable, pGC, pixel, spanData, 2133 &leftFace, (LineFacePtr) NULL, 2134 (double)0.0, (double)0.0, TRUE); 2135 } 2136 else 2137 { 2138 miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, 2139 &prevRightFace); 2140 } 2141 } 2142 prevRightFace = rightFace; 2143 prevIsFg = endIsFg; 2144 first = FALSE; 2145 projectLeft = FALSE; 2146 } 2147 if (npt == 1 && somethingDrawn) 2148 { 2149 if (pGC->lineStyle == LineDoubleDash || endIsFg) 2150 { 2151 pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel; 2152 if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) 2153 { 2154 miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, 2155 &rightFace); 2156 } 2157 else 2158 { 2159 if (pGC->capStyle == CapRound) 2160 miLineArc (pDrawable, pGC, pixel, spanData, 2161 (LineFacePtr) NULL, &rightFace, 2162 (double)0.0, (double)0.0, TRUE); 2163 } 2164 } 2165 else 2166 { 2167 /* glue a cap to the start of the line if 2168 * we're OnOffDash and ended on odd dash 2169 */ 2170 if (selfJoin && firstIsFg) 2171 { 2172 pixel = pGC->fgPixel; 2173 if (pGC->capStyle == CapProjecting) 2174 miLineProjectingCap (pDrawable, pGC, pixel, spanData, 2175 &firstFace, TRUE, 2176 (double)0.0, (double)0.0, TRUE); 2177 else if (pGC->capStyle == CapRound) 2178 miLineArc (pDrawable, pGC, pixel, spanData, 2179 &firstFace, (LineFacePtr) NULL, 2180 (double)0.0, (double)0.0, TRUE); 2181 } 2182 } 2183 } 2184 } 2185 /* handle crock where all points are coincident */ 2186 if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) 2187 { 2188 /* not the same as endIsFg computation above */ 2189 pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; 2190 switch (pGC->capStyle) { 2191 case CapRound: 2192 miLineArc (pDrawable, pGC, pixel, spanData, 2193 (LineFacePtr) NULL, (LineFacePtr) NULL, 2194 (double)x2, (double)y2, 2195 FALSE); 2196 break; 2197 case CapProjecting: 2198 x1 = pGC->lineWidth; 2199 miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, 2200 x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1); 2201 break; 2202 } 2203 } 2204 if (spanData) 2205 miCleanupSpanData (pDrawable, pGC, spanData); 2206} 2207