miwideline.c revision 4642e01f
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) xalloc (overall_height * sizeof(*ppt)); 99 if (!pptInit) 100 return; 101 pwidthInit = (int *) xalloc (overall_height * sizeof(*pwidth)); 102 if (!pwidthInit) 103 { 104 xfree (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 xfree (pwidthInit); 171 xfree (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 ( 256 double x0, 257 double y0, 258 double k, /* x0 * dy - y0 * dx */ 259 int dx, 260 int dy, 261 int xi, 262 int yi, 263 int left, 264 PolyEdgePtr edge) 265{ 266 int x, y, e; 267 int xady; 268 269 if (dy < 0) 270 { 271 dy = -dy; 272 dx = -dx; 273 k = -k; 274 } 275 276#ifdef NOTDEF 277 { 278 double realk, kerror; 279 realk = x0 * dy - y0 * dx; 280 kerror = Fabs (realk - k); 281 if (kerror > .1) 282 printf ("realk: %g k: %g\n", realk, k); 283 } 284#endif 285 y = ICEIL (y0); 286 xady = ICEIL (k) + y * dx; 287 288 if (xady <= 0) 289 x = - (-xady / dy) - 1; 290 else 291 x = (xady - 1) / dy; 292 293 e = xady - x * dy; 294 295 if (dx >= 0) 296 { 297 edge->signdx = 1; 298 edge->stepx = dx / dy; 299 edge->dx = dx % dy; 300 } 301 else 302 { 303 edge->signdx = -1; 304 edge->stepx = - (-dx / dy); 305 edge->dx = -dx % dy; 306 e = dy - e + 1; 307 } 308 edge->dy = dy; 309 edge->x = x + left + xi; 310 edge->e = e - dy; /* bias to compare against 0 instead of dy */ 311 return y + yi; 312} 313 314#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr))) 315 316_X_EXPORT /* static */ int 317miPolyBuildPoly ( 318 PolyVertexPtr vertices, 319 PolySlopePtr slopes, 320 int count, 321 int xi, 322 int yi, 323 PolyEdgePtr left, 324 PolyEdgePtr right, 325 int *pnleft, 326 int *pnright, 327 int *h) 328{ 329 int top, bottom; 330 double miny, maxy; 331 int i; 332 int j; 333 int clockwise; 334 int slopeoff; 335 int s; 336 int nright, nleft; 337 int y, lasty = 0, bottomy, topy = 0; 338 339 /* find the top of the polygon */ 340 maxy = miny = vertices[0].y; 341 bottom = top = 0; 342 for (i = 1; i < count; i++) 343 { 344 if (vertices[i].y < miny) 345 { 346 top = i; 347 miny = vertices[i].y; 348 } 349 if (vertices[i].y >= maxy) 350 { 351 bottom = i; 352 maxy = vertices[i].y; 353 } 354 } 355 clockwise = 1; 356 slopeoff = 0; 357 358 i = top; 359 j = StepAround (top, -1, count); 360 361 if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx) 362 { 363 clockwise = -1; 364 slopeoff = -1; 365 } 366 367 bottomy = ICEIL (maxy) + yi; 368 369 nright = 0; 370 371 s = StepAround (top, slopeoff, count); 372 i = top; 373 while (i != bottom) 374 { 375 if (slopes[s].dy != 0) 376 { 377 y = miPolyBuildEdge (vertices[i].x, vertices[i].y, 378 slopes[s].k, 379 slopes[s].dx, slopes[s].dy, 380 xi, yi, 0, 381 &right[nright]); 382 if (nright != 0) 383 right[nright-1].height = y - lasty; 384 else 385 topy = y; 386 nright++; 387 lasty = y; 388 } 389 390 i = StepAround (i, clockwise, count); 391 s = StepAround (s, clockwise, count); 392 } 393 if (nright != 0) 394 right[nright-1].height = bottomy - lasty; 395 396 if (slopeoff == 0) 397 slopeoff = -1; 398 else 399 slopeoff = 0; 400 401 nleft = 0; 402 s = StepAround (top, slopeoff, count); 403 i = top; 404 while (i != bottom) 405 { 406 if (slopes[s].dy != 0) 407 { 408 y = miPolyBuildEdge (vertices[i].x, vertices[i].y, 409 slopes[s].k, 410 slopes[s].dx, slopes[s].dy, xi, yi, 1, 411 &left[nleft]); 412 413 if (nleft != 0) 414 left[nleft-1].height = y - lasty; 415 nleft++; 416 lasty = y; 417 } 418 i = StepAround (i, -clockwise, count); 419 s = StepAround (s, -clockwise, count); 420 } 421 if (nleft != 0) 422 left[nleft-1].height = bottomy - lasty; 423 *pnleft = nleft; 424 *pnright = nright; 425 *h = bottomy - topy; 426 return topy; 427} 428 429static void 430miLineOnePoint ( 431 DrawablePtr pDrawable, 432 GCPtr pGC, 433 unsigned long pixel, 434 SpanDataPtr spanData, 435 int x, 436 int y) 437{ 438 DDXPointRec pt; 439 int wid; 440 unsigned long oldPixel; 441 442 MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel); 443 if (pGC->fillStyle == FillSolid) 444 { 445 pt.x = x; 446 pt.y = y; 447 (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt); 448 } 449 else 450 { 451 wid = 1; 452 if (pGC->miTranslate) 453 { 454 x += pDrawable->x; 455 y += pDrawable->y; 456 } 457 pt.x = x; 458 pt.y = y; 459 (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE); 460 } 461 MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel); 462} 463 464static void 465miLineJoin ( 466 DrawablePtr pDrawable, 467 GCPtr pGC, 468 unsigned long pixel, 469 SpanDataPtr spanData, 470 LineFacePtr pLeft, 471 LineFacePtr pRight) 472{ 473 double mx = 0, my = 0; 474 double denom = 0.0; 475 PolyVertexRec vertices[4]; 476 PolySlopeRec slopes[4]; 477 int edgecount; 478 PolyEdgeRec left[4], right[4]; 479 int nleft, nright; 480 int y, height; 481 int swapslopes; 482 int joinStyle = pGC->joinStyle; 483 int lw = pGC->lineWidth; 484 485 if (lw == 1 && !spanData) { 486 /* See if one of the lines will draw the joining pixel */ 487 if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0)) 488 return; 489 if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0)) 490 return; 491 if (joinStyle != JoinRound) { 492 denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; 493 if (denom == 0) 494 return; /* no join to draw */ 495 } 496 if (joinStyle != JoinMiter) { 497 miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y); 498 return; 499 } 500 } else { 501 if (joinStyle == JoinRound) 502 { 503 miLineArc(pDrawable, pGC, pixel, spanData, 504 pLeft, pRight, 505 (double)0.0, (double)0.0, TRUE); 506 return; 507 } 508 denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; 509 if (denom == 0.0) 510 return; /* no join to draw */ 511 } 512 513 swapslopes = 0; 514 if (denom > 0) 515 { 516 pLeft->xa = -pLeft->xa; 517 pLeft->ya = -pLeft->ya; 518 pLeft->dx = -pLeft->dx; 519 pLeft->dy = -pLeft->dy; 520 } 521 else 522 { 523 swapslopes = 1; 524 pRight->xa = -pRight->xa; 525 pRight->ya = -pRight->ya; 526 pRight->dx = -pRight->dx; 527 pRight->dy = -pRight->dy; 528 } 529 530 vertices[0].x = pRight->xa; 531 vertices[0].y = pRight->ya; 532 slopes[0].dx = -pRight->dy; 533 slopes[0].dy = pRight->dx; 534 slopes[0].k = 0; 535 536 vertices[1].x = 0; 537 vertices[1].y = 0; 538 slopes[1].dx = pLeft->dy; 539 slopes[1].dy = -pLeft->dx; 540 slopes[1].k = 0; 541 542 vertices[2].x = pLeft->xa; 543 vertices[2].y = pLeft->ya; 544 545 if (joinStyle == JoinMiter) 546 { 547 my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) - 548 pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) / 549 denom; 550 if (pLeft->dy != 0) 551 { 552 mx = pLeft->xa + (my - pLeft->ya) * 553 (double) pLeft->dx / (double) pLeft->dy; 554 } 555 else 556 { 557 mx = pRight->xa + (my - pRight->ya) * 558 (double) pRight->dx / (double) pRight->dy; 559 } 560 /* check miter limit */ 561 if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw) 562 joinStyle = JoinBevel; 563 } 564 565 if (joinStyle == JoinMiter) 566 { 567 slopes[2].dx = pLeft->dx; 568 slopes[2].dy = pLeft->dy; 569 slopes[2].k = pLeft->k; 570 if (swapslopes) 571 { 572 slopes[2].dx = -slopes[2].dx; 573 slopes[2].dy = -slopes[2].dy; 574 slopes[2].k = -slopes[2].k; 575 } 576 vertices[3].x = mx; 577 vertices[3].y = my; 578 slopes[3].dx = pRight->dx; 579 slopes[3].dy = pRight->dy; 580 slopes[3].k = pRight->k; 581 if (swapslopes) 582 { 583 slopes[3].dx = -slopes[3].dx; 584 slopes[3].dy = -slopes[3].dy; 585 slopes[3].k = -slopes[3].k; 586 } 587 edgecount = 4; 588 } 589 else 590 { 591 double scale, dx, dy, adx, ady; 592 593 adx = dx = pRight->xa - pLeft->xa; 594 ady = dy = pRight->ya - pLeft->ya; 595 if (adx < 0) 596 adx = -adx; 597 if (ady < 0) 598 ady = -ady; 599 scale = ady; 600 if (adx > ady) 601 scale = adx; 602 slopes[2].dx = (dx * 65536) / scale; 603 slopes[2].dy = (dy * 65536) / scale; 604 slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy - 605 (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0; 606 edgecount = 3; 607 } 608 609 y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y, 610 left, right, &nleft, &nright, &height); 611 miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright); 612} 613 614static int 615miLineArcI ( 616 DrawablePtr pDraw, 617 GCPtr pGC, 618 int xorg, 619 int yorg, 620 DDXPointPtr points, 621 int *widths) 622{ 623 DDXPointPtr tpts, bpts; 624 int *twids, *bwids; 625 int x, y, e, ex, slw; 626 627 tpts = points; 628 twids = widths; 629 if (pGC->miTranslate) 630 { 631 xorg += pDraw->x; 632 yorg += pDraw->y; 633 } 634 slw = pGC->lineWidth; 635 if (slw == 1) 636 { 637 tpts->x = xorg; 638 tpts->y = yorg; 639 *twids = 1; 640 return 1; 641 } 642 bpts = tpts + slw; 643 bwids = twids + slw; 644 y = (slw >> 1) + 1; 645 if (slw & 1) 646 e = - ((y << 2) + 3); 647 else 648 e = - (y << 3); 649 ex = -4; 650 x = 0; 651 while (y) 652 { 653 e += (y << 3) - 4; 654 while (e >= 0) 655 { 656 x++; 657 e += (ex = -((x << 3) + 4)); 658 } 659 y--; 660 slw = (x << 1) + 1; 661 if ((e == ex) && (slw > 1)) 662 slw--; 663 tpts->x = xorg - x; 664 tpts->y = yorg - y; 665 tpts++; 666 *twids++ = slw; 667 if ((y != 0) && ((slw > 1) || (e != ex))) 668 { 669 bpts--; 670 bpts->x = xorg - x; 671 bpts->y = yorg + y; 672 *--bwids = slw; 673 } 674 } 675 return (pGC->lineWidth); 676} 677 678#define CLIPSTEPEDGE(edgey,edge,edgeleft) \ 679 if (ybase == edgey) \ 680 { \ 681 if (edgeleft) \ 682 { \ 683 if (edge->x > xcl) \ 684 xcl = edge->x; \ 685 } \ 686 else \ 687 { \ 688 if (edge->x < xcr) \ 689 xcr = edge->x; \ 690 } \ 691 edgey++; \ 692 edge->x += edge->stepx; \ 693 edge->e += edge->dx; \ 694 if (edge->e > 0) \ 695 { \ 696 edge->x += edge->signdx; \ 697 edge->e -= edge->dy; \ 698 } \ 699 } 700 701static int 702miLineArcD ( 703 DrawablePtr pDraw, 704 GCPtr pGC, 705 double xorg, 706 double yorg, 707 DDXPointPtr points, 708 int *widths, 709 PolyEdgePtr edge1, 710 int edgey1, 711 Bool edgeleft1, 712 PolyEdgePtr edge2, 713 int edgey2, 714 Bool edgeleft2) 715{ 716 DDXPointPtr pts; 717 int *wids; 718 double radius, x0, y0, el, er, yk, xlk, xrk, k; 719 int xbase, ybase, y, boty, xl, xr, xcl, xcr; 720 int ymin, ymax; 721 Bool edge1IsMin, edge2IsMin; 722 int ymin1, ymin2; 723 724 pts = points; 725 wids = widths; 726 xbase = floor(xorg); 727 x0 = xorg - xbase; 728 ybase = ICEIL (yorg); 729 y0 = yorg - ybase; 730 if (pGC->miTranslate) 731 { 732 xbase += pDraw->x; 733 ybase += pDraw->y; 734 edge1->x += pDraw->x; 735 edge2->x += pDraw->x; 736 edgey1 += pDraw->y; 737 edgey2 += pDraw->y; 738 } 739 xlk = x0 + x0 + 1.0; 740 xrk = x0 + x0 - 1.0; 741 yk = y0 + y0 - 1.0; 742 radius = ((double)pGC->lineWidth) / 2.0; 743 y = floor(radius - y0 + 1.0); 744 ybase -= y; 745 ymin = ybase; 746 ymax = 65536; 747 edge1IsMin = FALSE; 748 ymin1 = edgey1; 749 if (edge1->dy >= 0) 750 { 751 if (!edge1->dy) 752 { 753 if (edgeleft1) 754 edge1IsMin = TRUE; 755 else 756 ymax = edgey1; 757 edgey1 = 65536; 758 } 759 else 760 { 761 if ((edge1->signdx < 0) == edgeleft1) 762 edge1IsMin = TRUE; 763 } 764 } 765 edge2IsMin = FALSE; 766 ymin2 = edgey2; 767 if (edge2->dy >= 0) 768 { 769 if (!edge2->dy) 770 { 771 if (edgeleft2) 772 edge2IsMin = TRUE; 773 else 774 ymax = edgey2; 775 edgey2 = 65536; 776 } 777 else 778 { 779 if ((edge2->signdx < 0) == edgeleft2) 780 edge2IsMin = TRUE; 781 } 782 } 783 if (edge1IsMin) 784 { 785 ymin = ymin1; 786 if (edge2IsMin && ymin1 > ymin2) 787 ymin = ymin2; 788 } else if (edge2IsMin) 789 ymin = ymin2; 790 el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0); 791 er = el + xrk; 792 xl = 1; 793 xr = 0; 794 if (x0 < 0.5) 795 { 796 xl = 0; 797 el -= xlk; 798 } 799 boty = (y0 < -0.5) ? 1 : 0; 800 if (ybase + y - boty > ymax) 801 boty = ymax - ybase - y; 802 while (y > boty) 803 { 804 k = (y << 1) + yk; 805 er += k; 806 while (er > 0.0) 807 { 808 xr++; 809 er += xrk - (xr << 1); 810 } 811 el += k; 812 while (el >= 0.0) 813 { 814 xl--; 815 el += (xl << 1) - xlk; 816 } 817 y--; 818 ybase++; 819 if (ybase < ymin) 820 continue; 821 xcl = xl + xbase; 822 xcr = xr + xbase; 823 CLIPSTEPEDGE(edgey1, edge1, edgeleft1); 824 CLIPSTEPEDGE(edgey2, edge2, edgeleft2); 825 if (xcr >= xcl) 826 { 827 pts->x = xcl; 828 pts->y = ybase; 829 pts++; 830 *wids++ = xcr - xcl + 1; 831 } 832 } 833 er = xrk - (xr << 1) - er; 834 el = (xl << 1) - xlk - el; 835 boty = floor(-y0 - radius + 1.0); 836 if (ybase + y - boty > ymax) 837 boty = ymax - ybase - y; 838 while (y > boty) 839 { 840 k = (y << 1) + yk; 841 er -= k; 842 while ((er >= 0.0) && (xr >= 0)) 843 { 844 xr--; 845 er += xrk - (xr << 1); 846 } 847 el -= k; 848 while ((el > 0.0) && (xl <= 0)) 849 { 850 xl++; 851 el += (xl << 1) - xlk; 852 } 853 y--; 854 ybase++; 855 if (ybase < ymin) 856 continue; 857 xcl = xl + xbase; 858 xcr = xr + xbase; 859 CLIPSTEPEDGE(edgey1, edge1, edgeleft1); 860 CLIPSTEPEDGE(edgey2, edge2, edgeleft2); 861 if (xcr >= xcl) 862 { 863 pts->x = xcl; 864 pts->y = ybase; 865 pts++; 866 *wids++ = xcr - xcl + 1; 867 } 868 } 869 return (pts - points); 870} 871 872static int 873miRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge) 874{ 875 int y; 876 int dx, dy; 877 double xa, ya; 878 Bool left; 879 880 dx = -face->dy; 881 dy = face->dx; 882 xa = face->xa; 883 ya = face->ya; 884 left = 1; 885 if (ya > 0) 886 { 887 ya = 0.0; 888 xa = 0.0; 889 } 890 if (dy < 0 || (dy == 0 && dx > 0)) 891 { 892 dx = -dx; 893 dy = -dy; 894 left = !left; 895 } 896 if (dx == 0 && dy == 0) 897 dy = 1; 898 if (dy == 0) 899 { 900 y = ICEIL (face->ya) + face->y; 901 edge->x = -32767; 902 edge->stepx = 0; 903 edge->signdx = 0; 904 edge->e = -1; 905 edge->dy = 0; 906 edge->dx = 0; 907 edge->height = 0; 908 } 909 else 910 { 911 y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge); 912 edge->height = 32767; 913 } 914 *leftEdge = !left; 915 return y; 916} 917 918_X_EXPORT void 919miRoundJoinClip (LineFacePtr pLeft, LineFacePtr pRight, 920 PolyEdgePtr edge1, PolyEdgePtr edge2, 921 int *y1, int *y2, Bool *left1, Bool *left2) 922{ 923 double denom; 924 925 denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; 926 927 if (denom >= 0) 928 { 929 pLeft->xa = -pLeft->xa; 930 pLeft->ya = -pLeft->ya; 931 } 932 else 933 { 934 pRight->xa = -pRight->xa; 935 pRight->ya = -pRight->ya; 936 } 937 *y1 = miRoundJoinFace (pLeft, edge1, left1); 938 *y2 = miRoundJoinFace (pRight, edge2, left2); 939} 940 941_X_EXPORT int 942miRoundCapClip (LineFacePtr face, Bool isInt, PolyEdgePtr edge, 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)xalloc(sizeof(DDXPointRec) * pGC->lineWidth); 1049 if (!points) 1050 return; 1051 widths = (int *)xalloc(sizeof(int) * pGC->lineWidth); 1052 if (!widths) 1053 { 1054 xfree(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 xfree(widths); 1090 xfree(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 (DrawablePtr pDrawable, GCPtr pGC, 1529 int mode, int npt, DDXPointPtr pPts) 1530{ 1531 int x1, y1, x2, y2; 1532 SpanDataRec spanDataRec; 1533 SpanDataPtr spanData; 1534 long pixel; 1535 Bool projectLeft, projectRight; 1536 LineFaceRec leftFace, rightFace, prevRightFace; 1537 LineFaceRec firstFace; 1538 int first; 1539 Bool somethingDrawn = FALSE; 1540 Bool selfJoin; 1541 1542 spanData = miSetupSpanData (pGC, &spanDataRec, npt); 1543 pixel = pGC->fgPixel; 1544 x2 = pPts->x; 1545 y2 = pPts->y; 1546 first = TRUE; 1547 selfJoin = FALSE; 1548 if (npt > 1) 1549 { 1550 if (mode == CoordModePrevious) 1551 { 1552 int nptTmp; 1553 DDXPointPtr pPtsTmp; 1554 1555 x1 = x2; 1556 y1 = y2; 1557 nptTmp = npt; 1558 pPtsTmp = pPts + 1; 1559 while (--nptTmp) 1560 { 1561 x1 += pPtsTmp->x; 1562 y1 += pPtsTmp->y; 1563 ++pPtsTmp; 1564 } 1565 if (x2 == x1 && y2 == y1) 1566 selfJoin = TRUE; 1567 } 1568 else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) 1569 { 1570 selfJoin = TRUE; 1571 } 1572 } 1573 projectLeft = pGC->capStyle == CapProjecting && !selfJoin; 1574 projectRight = FALSE; 1575 while (--npt) 1576 { 1577 x1 = x2; 1578 y1 = y2; 1579 ++pPts; 1580 x2 = pPts->x; 1581 y2 = pPts->y; 1582 if (mode == CoordModePrevious) 1583 { 1584 x2 += x1; 1585 y2 += y1; 1586 } 1587 if (x1 != x2 || y1 != y2) 1588 { 1589 somethingDrawn = TRUE; 1590 if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin) 1591 projectRight = TRUE; 1592 miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2, 1593 projectLeft, projectRight, &leftFace, &rightFace); 1594 if (first) 1595 { 1596 if (selfJoin) 1597 firstFace = leftFace; 1598 else if (pGC->capStyle == CapRound) 1599 { 1600 if (pGC->lineWidth == 1 && !spanData) 1601 miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1); 1602 else 1603 miLineArc (pDrawable, pGC, pixel, spanData, 1604 &leftFace, (LineFacePtr) NULL, 1605 (double)0.0, (double)0.0, 1606 TRUE); 1607 } 1608 } 1609 else 1610 { 1611 miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, 1612 &prevRightFace); 1613 } 1614 prevRightFace = rightFace; 1615 first = FALSE; 1616 projectLeft = FALSE; 1617 } 1618 if (npt == 1 && somethingDrawn) 1619 { 1620 if (selfJoin) 1621 miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, 1622 &rightFace); 1623 else if (pGC->capStyle == CapRound) 1624 { 1625 if (pGC->lineWidth == 1 && !spanData) 1626 miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2); 1627 else 1628 miLineArc (pDrawable, pGC, pixel, spanData, 1629 (LineFacePtr) NULL, &rightFace, 1630 (double)0.0, (double)0.0, 1631 TRUE); 1632 } 1633 } 1634 } 1635 /* handle crock where all points are coincedent */ 1636 if (!somethingDrawn) 1637 { 1638 projectLeft = pGC->capStyle == CapProjecting; 1639 miWideSegment (pDrawable, pGC, pixel, spanData, 1640 x2, y2, x2, y2, projectLeft, projectLeft, 1641 &leftFace, &rightFace); 1642 if (pGC->capStyle == CapRound) 1643 { 1644 miLineArc (pDrawable, pGC, pixel, spanData, 1645 &leftFace, (LineFacePtr) NULL, 1646 (double)0.0, (double)0.0, 1647 TRUE); 1648 rightFace.dx = -1; /* sleezy hack to make it work */ 1649 miLineArc (pDrawable, pGC, pixel, spanData, 1650 (LineFacePtr) NULL, &rightFace, 1651 (double)0.0, (double)0.0, 1652 TRUE); 1653 } 1654 } 1655 if (spanData) 1656 miCleanupSpanData (pDrawable, pGC, spanData); 1657} 1658 1659#define V_TOP 0 1660#define V_RIGHT 1 1661#define V_BOTTOM 2 1662#define V_LEFT 3 1663 1664static void 1665miWideDashSegment ( 1666 DrawablePtr pDrawable, 1667 GCPtr pGC, 1668 SpanDataPtr spanData, 1669 int *pDashOffset, 1670 int *pDashIndex, 1671 int x1, 1672 int y1, 1673 int x2, 1674 int y2, 1675 Bool projectLeft, 1676 Bool projectRight, 1677 LineFacePtr leftFace, 1678 LineFacePtr rightFace) 1679{ 1680 int dashIndex, dashRemain; 1681 unsigned char *pDash; 1682 double L, l; 1683 double k; 1684 PolyVertexRec vertices[4]; 1685 PolyVertexRec saveRight, saveBottom; 1686 PolySlopeRec slopes[4]; 1687 PolyEdgeRec left[2], right[2]; 1688 LineFaceRec lcapFace, rcapFace; 1689 int nleft, nright; 1690 int h; 1691 int y; 1692 int dy, dx; 1693 unsigned long pixel; 1694 double LRemain; 1695 double r; 1696 double rdx, rdy; 1697 double dashDx, dashDy; 1698 double saveK = 0.0; 1699 Bool first = TRUE; 1700 double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0; 1701 unsigned long fgPixel, bgPixel; 1702 1703 dx = x2 - x1; 1704 dy = y2 - y1; 1705 dashIndex = *pDashIndex; 1706 pDash = pGC->dash; 1707 dashRemain = pDash[dashIndex] - *pDashOffset; 1708 fgPixel = pGC->fgPixel; 1709 bgPixel = pGC->bgPixel; 1710 if (pGC->fillStyle == FillOpaqueStippled || 1711 pGC->fillStyle == FillTiled) 1712 { 1713 bgPixel = fgPixel; 1714 } 1715 1716 l = ((double) pGC->lineWidth) / 2.0; 1717 if (dx == 0) 1718 { 1719 L = dy; 1720 rdx = 0; 1721 rdy = l; 1722 if (dy < 0) 1723 { 1724 L = -dy; 1725 rdy = -l; 1726 } 1727 } 1728 else if (dy == 0) 1729 { 1730 L = dx; 1731 rdx = l; 1732 rdy = 0; 1733 if (dx < 0) 1734 { 1735 L = -dx; 1736 rdx = -l; 1737 } 1738 } 1739 else 1740 { 1741 L = hypot ((double) dx, (double) dy); 1742 r = l / L; 1743 1744 rdx = r * dx; 1745 rdy = r * dy; 1746 } 1747 k = l * L; 1748 LRemain = L; 1749 /* All position comments are relative to a line with dx and dy > 0, 1750 * but the code does not depend on this */ 1751 /* top */ 1752 slopes[V_TOP].dx = dx; 1753 slopes[V_TOP].dy = dy; 1754 slopes[V_TOP].k = k; 1755 /* right */ 1756 slopes[V_RIGHT].dx = -dy; 1757 slopes[V_RIGHT].dy = dx; 1758 slopes[V_RIGHT].k = 0; 1759 /* bottom */ 1760 slopes[V_BOTTOM].dx = -dx; 1761 slopes[V_BOTTOM].dy = -dy; 1762 slopes[V_BOTTOM].k = k; 1763 /* left */ 1764 slopes[V_LEFT].dx = dy; 1765 slopes[V_LEFT].dy = -dx; 1766 slopes[V_LEFT].k = 0; 1767 1768 /* preload the start coordinates */ 1769 vertices[V_RIGHT].x = vertices[V_TOP].x = rdy; 1770 vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx; 1771 1772 vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy; 1773 vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx; 1774 1775 if (projectLeft) 1776 { 1777 vertices[V_TOP].x -= rdx; 1778 vertices[V_TOP].y -= rdy; 1779 1780 vertices[V_LEFT].x -= rdx; 1781 vertices[V_LEFT].y -= rdy; 1782 1783 slopes[V_LEFT].k = rdx * dx + rdy * dy; 1784 } 1785 1786 lcenterx = x1; 1787 lcentery = y1; 1788 1789 if (pGC->capStyle == CapRound) 1790 { 1791 lcapFace.dx = dx; 1792 lcapFace.dy = dy; 1793 lcapFace.x = x1; 1794 lcapFace.y = y1; 1795 1796 rcapFace.dx = -dx; 1797 rcapFace.dy = -dy; 1798 rcapFace.x = x1; 1799 rcapFace.y = y1; 1800 } 1801 while (LRemain > dashRemain) 1802 { 1803 dashDx = (dashRemain * dx) / L; 1804 dashDy = (dashRemain * dy) / L; 1805 1806 rcenterx = lcenterx + dashDx; 1807 rcentery = lcentery + dashDy; 1808 1809 vertices[V_RIGHT].x += dashDx; 1810 vertices[V_RIGHT].y += dashDy; 1811 1812 vertices[V_BOTTOM].x += dashDx; 1813 vertices[V_BOTTOM].y += dashDy; 1814 1815 slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy; 1816 1817 if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) 1818 { 1819 if (pGC->lineStyle == LineOnOffDash && 1820 pGC->capStyle == CapProjecting) 1821 { 1822 saveRight = vertices[V_RIGHT]; 1823 saveBottom = vertices[V_BOTTOM]; 1824 saveK = slopes[V_RIGHT].k; 1825 1826 if (!first) 1827 { 1828 vertices[V_TOP].x -= rdx; 1829 vertices[V_TOP].y -= rdy; 1830 1831 vertices[V_LEFT].x -= rdx; 1832 vertices[V_LEFT].y -= rdy; 1833 1834 slopes[V_LEFT].k = vertices[V_LEFT].x * 1835 slopes[V_LEFT].dy - 1836 vertices[V_LEFT].y * 1837 slopes[V_LEFT].dx; 1838 } 1839 1840 vertices[V_RIGHT].x += rdx; 1841 vertices[V_RIGHT].y += rdy; 1842 1843 vertices[V_BOTTOM].x += rdx; 1844 vertices[V_BOTTOM].y += rdy; 1845 1846 slopes[V_RIGHT].k = vertices[V_RIGHT].x * 1847 slopes[V_RIGHT].dy - 1848 vertices[V_RIGHT].y * 1849 slopes[V_RIGHT].dx; 1850 } 1851 y = miPolyBuildPoly (vertices, slopes, 4, x1, y1, 1852 left, right, &nleft, &nright, &h); 1853 pixel = (dashIndex & 1) ? bgPixel : fgPixel; 1854 miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); 1855 1856 if (pGC->lineStyle == LineOnOffDash) 1857 { 1858 switch (pGC->capStyle) 1859 { 1860 case CapProjecting: 1861 vertices[V_BOTTOM] = saveBottom; 1862 vertices[V_RIGHT] = saveRight; 1863 slopes[V_RIGHT].k = saveK; 1864 break; 1865 case CapRound: 1866 if (!first) 1867 { 1868 if (dx < 0) 1869 { 1870 lcapFace.xa = -vertices[V_LEFT].x; 1871 lcapFace.ya = -vertices[V_LEFT].y; 1872 lcapFace.k = slopes[V_LEFT].k; 1873 } 1874 else 1875 { 1876 lcapFace.xa = vertices[V_TOP].x; 1877 lcapFace.ya = vertices[V_TOP].y; 1878 lcapFace.k = -slopes[V_LEFT].k; 1879 } 1880 miLineArc (pDrawable, pGC, pixel, spanData, 1881 &lcapFace, (LineFacePtr) NULL, 1882 lcenterx, lcentery, FALSE); 1883 } 1884 if (dx < 0) 1885 { 1886 rcapFace.xa = vertices[V_BOTTOM].x; 1887 rcapFace.ya = vertices[V_BOTTOM].y; 1888 rcapFace.k = slopes[V_RIGHT].k; 1889 } 1890 else 1891 { 1892 rcapFace.xa = -vertices[V_RIGHT].x; 1893 rcapFace.ya = -vertices[V_RIGHT].y; 1894 rcapFace.k = -slopes[V_RIGHT].k; 1895 } 1896 miLineArc (pDrawable, pGC, pixel, spanData, 1897 (LineFacePtr) NULL, &rcapFace, 1898 rcenterx, rcentery, FALSE); 1899 break; 1900 } 1901 } 1902 } 1903 LRemain -= dashRemain; 1904 ++dashIndex; 1905 if (dashIndex == pGC->numInDashList) 1906 dashIndex = 0; 1907 dashRemain = pDash[dashIndex]; 1908 1909 lcenterx = rcenterx; 1910 lcentery = rcentery; 1911 1912 vertices[V_TOP] = vertices[V_RIGHT]; 1913 vertices[V_LEFT] = vertices[V_BOTTOM]; 1914 slopes[V_LEFT].k = -slopes[V_RIGHT].k; 1915 first = FALSE; 1916 } 1917 1918 if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) 1919 { 1920 vertices[V_TOP].x -= dx; 1921 vertices[V_TOP].y -= dy; 1922 1923 vertices[V_LEFT].x -= dx; 1924 vertices[V_LEFT].y -= dy; 1925 1926 vertices[V_RIGHT].x = rdy; 1927 vertices[V_RIGHT].y = -rdx; 1928 1929 vertices[V_BOTTOM].x = -rdy; 1930 vertices[V_BOTTOM].y = rdx; 1931 1932 1933 if (projectRight) 1934 { 1935 vertices[V_RIGHT].x += rdx; 1936 vertices[V_RIGHT].y += rdy; 1937 1938 vertices[V_BOTTOM].x += rdx; 1939 vertices[V_BOTTOM].y += rdy; 1940 slopes[V_RIGHT].k = vertices[V_RIGHT].x * 1941 slopes[V_RIGHT].dy - 1942 vertices[V_RIGHT].y * 1943 slopes[V_RIGHT].dx; 1944 } 1945 else 1946 slopes[V_RIGHT].k = 0; 1947 1948 if (!first && pGC->lineStyle == LineOnOffDash && 1949 pGC->capStyle == CapProjecting) 1950 { 1951 vertices[V_TOP].x -= rdx; 1952 vertices[V_TOP].y -= rdy; 1953 1954 vertices[V_LEFT].x -= rdx; 1955 vertices[V_LEFT].y -= rdy; 1956 slopes[V_LEFT].k = vertices[V_LEFT].x * 1957 slopes[V_LEFT].dy - 1958 vertices[V_LEFT].y * 1959 slopes[V_LEFT].dx; 1960 } 1961 else 1962 slopes[V_LEFT].k += dx * dx + dy * dy; 1963 1964 1965 y = miPolyBuildPoly (vertices, slopes, 4, x2, y2, 1966 left, right, &nleft, &nright, &h); 1967 1968 pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; 1969 miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); 1970 if (!first && pGC->lineStyle == LineOnOffDash && 1971 pGC->capStyle == CapRound) 1972 { 1973 lcapFace.x = x2; 1974 lcapFace.y = y2; 1975 if (dx < 0) 1976 { 1977 lcapFace.xa = -vertices[V_LEFT].x; 1978 lcapFace.ya = -vertices[V_LEFT].y; 1979 lcapFace.k = slopes[V_LEFT].k; 1980 } 1981 else 1982 { 1983 lcapFace.xa = vertices[V_TOP].x; 1984 lcapFace.ya = vertices[V_TOP].y; 1985 lcapFace.k = -slopes[V_LEFT].k; 1986 } 1987 miLineArc (pDrawable, pGC, pixel, spanData, 1988 &lcapFace, (LineFacePtr) NULL, 1989 rcenterx, rcentery, FALSE); 1990 } 1991 } 1992 dashRemain = ((double) dashRemain) - LRemain; 1993 if (dashRemain == 0) 1994 { 1995 dashIndex++; 1996 if (dashIndex == pGC->numInDashList) 1997 dashIndex = 0; 1998 dashRemain = pDash[dashIndex]; 1999 } 2000 2001 leftFace->x = x1; 2002 leftFace->y = y1; 2003 leftFace->dx = dx; 2004 leftFace->dy = dy; 2005 leftFace->xa = rdy; 2006 leftFace->ya = -rdx; 2007 leftFace->k = k; 2008 2009 rightFace->x = x2; 2010 rightFace->y = y2; 2011 rightFace->dx = -dx; 2012 rightFace->dy = -dy; 2013 rightFace->xa = -rdy; 2014 rightFace->ya = rdx; 2015 rightFace->k = k; 2016 2017 *pDashIndex = dashIndex; 2018 *pDashOffset = pDash[dashIndex] - dashRemain; 2019} 2020 2021_X_EXPORT void 2022miWideDash (DrawablePtr pDrawable, GCPtr pGC, 2023 int mode, int npt, DDXPointPtr pPts) 2024{ 2025 int x1, y1, x2, y2; 2026 unsigned long pixel; 2027 Bool projectLeft, projectRight; 2028 LineFaceRec leftFace, rightFace, prevRightFace; 2029 LineFaceRec firstFace; 2030 int first; 2031 int dashIndex, dashOffset; 2032 int prevDashIndex; 2033 SpanDataRec spanDataRec; 2034 SpanDataPtr spanData; 2035 Bool somethingDrawn = FALSE; 2036 Bool selfJoin; 2037 Bool endIsFg = FALSE, startIsFg = FALSE; 2038 Bool firstIsFg = FALSE, prevIsFg = FALSE; 2039 2040#if 0 2041 /* XXX backward compatibility */ 2042 if (pGC->lineWidth == 0) 2043 { 2044 miZeroDashLine (pDrawable, pGC, mode, npt, pPts); 2045 return; 2046 } 2047#endif 2048 if (pGC->lineStyle == LineDoubleDash && 2049 (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) 2050 { 2051 miWideLine (pDrawable, pGC, mode, npt, pPts); 2052 return; 2053 } 2054 if (npt == 0) 2055 return; 2056 spanData = miSetupSpanData (pGC, &spanDataRec, npt); 2057 x2 = pPts->x; 2058 y2 = pPts->y; 2059 first = TRUE; 2060 selfJoin = FALSE; 2061 if (mode == CoordModePrevious) 2062 { 2063 int nptTmp; 2064 DDXPointPtr pPtsTmp; 2065 2066 x1 = x2; 2067 y1 = y2; 2068 nptTmp = npt; 2069 pPtsTmp = pPts + 1; 2070 while (--nptTmp) 2071 { 2072 x1 += pPtsTmp->x; 2073 y1 += pPtsTmp->y; 2074 ++pPtsTmp; 2075 } 2076 if (x2 == x1 && y2 == y1) 2077 selfJoin = TRUE; 2078 } 2079 else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) 2080 { 2081 selfJoin = TRUE; 2082 } 2083 projectLeft = pGC->capStyle == CapProjecting && !selfJoin; 2084 projectRight = FALSE; 2085 dashIndex = 0; 2086 dashOffset = 0; 2087 miStepDash ((int)pGC->dashOffset, &dashIndex, 2088 pGC->dash, (int)pGC->numInDashList, &dashOffset); 2089 while (--npt) 2090 { 2091 x1 = x2; 2092 y1 = y2; 2093 ++pPts; 2094 x2 = pPts->x; 2095 y2 = pPts->y; 2096 if (mode == CoordModePrevious) 2097 { 2098 x2 += x1; 2099 y2 += y1; 2100 } 2101 if (x1 != x2 || y1 != y2) 2102 { 2103 somethingDrawn = TRUE; 2104 if (npt == 1 && pGC->capStyle == CapProjecting && 2105 (!selfJoin || !firstIsFg)) 2106 projectRight = TRUE; 2107 prevDashIndex = dashIndex; 2108 miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex, 2109 x1, y1, x2, y2, 2110 projectLeft, projectRight, &leftFace, &rightFace); 2111 startIsFg = !(prevDashIndex & 1); 2112 endIsFg = (dashIndex & 1) ^ (dashOffset != 0); 2113 if (pGC->lineStyle == LineDoubleDash || startIsFg) 2114 { 2115 pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel; 2116 if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) 2117 { 2118 if (first && selfJoin) 2119 { 2120 firstFace = leftFace; 2121 firstIsFg = startIsFg; 2122 } 2123 else if (pGC->capStyle == CapRound) 2124 miLineArc (pDrawable, pGC, pixel, spanData, 2125 &leftFace, (LineFacePtr) NULL, 2126 (double)0.0, (double)0.0, TRUE); 2127 } 2128 else 2129 { 2130 miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, 2131 &prevRightFace); 2132 } 2133 } 2134 prevRightFace = rightFace; 2135 prevIsFg = endIsFg; 2136 first = FALSE; 2137 projectLeft = FALSE; 2138 } 2139 if (npt == 1 && somethingDrawn) 2140 { 2141 if (pGC->lineStyle == LineDoubleDash || endIsFg) 2142 { 2143 pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel; 2144 if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) 2145 { 2146 miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, 2147 &rightFace); 2148 } 2149 else 2150 { 2151 if (pGC->capStyle == CapRound) 2152 miLineArc (pDrawable, pGC, pixel, spanData, 2153 (LineFacePtr) NULL, &rightFace, 2154 (double)0.0, (double)0.0, TRUE); 2155 } 2156 } 2157 else 2158 { 2159 /* glue a cap to the start of the line if 2160 * we're OnOffDash and ended on odd dash 2161 */ 2162 if (selfJoin && firstIsFg) 2163 { 2164 pixel = pGC->fgPixel; 2165 if (pGC->capStyle == CapProjecting) 2166 miLineProjectingCap (pDrawable, pGC, pixel, spanData, 2167 &firstFace, TRUE, 2168 (double)0.0, (double)0.0, TRUE); 2169 else if (pGC->capStyle == CapRound) 2170 miLineArc (pDrawable, pGC, pixel, spanData, 2171 &firstFace, (LineFacePtr) NULL, 2172 (double)0.0, (double)0.0, TRUE); 2173 } 2174 } 2175 } 2176 } 2177 /* handle crock where all points are coincident */ 2178 if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) 2179 { 2180 /* not the same as endIsFg computation above */ 2181 pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; 2182 switch (pGC->capStyle) { 2183 case CapRound: 2184 miLineArc (pDrawable, pGC, pixel, spanData, 2185 (LineFacePtr) NULL, (LineFacePtr) NULL, 2186 (double)x2, (double)y2, 2187 FALSE); 2188 break; 2189 case CapProjecting: 2190 x1 = pGC->lineWidth; 2191 miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, 2192 x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1); 2193 break; 2194 } 2195 } 2196 if (spanData) 2197 miCleanupSpanData (pDrawable, pGC, spanData); 2198} 2199