miarc.c revision 4642e01f
1/*********************************************************** 2 3Copyright 1987, 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 in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25 26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46******************************************************************/ 47/* Author: Keith Packard and Bob Scheifler */ 48/* Warning: this code is toxic, do not dally very long here. */ 49 50#ifdef HAVE_DIX_CONFIG_H 51#include <dix-config.h> 52#endif 53 54#include <math.h> 55#include <X11/X.h> 56#include <X11/Xprotostr.h> 57#include "misc.h" 58#include "gcstruct.h" 59#include "scrnintstr.h" 60#include "pixmapstr.h" 61#include "windowstr.h" 62#include "mifpoly.h" 63#include "mi.h" 64#include "mifillarc.h" 65#include <X11/Xfuncproto.h> 66 67static double miDsin(double a); 68static double miDcos(double a); 69static double miDasin(double v); 70static double miDatan2(double dy, double dx); 71 72#ifndef HAVE_CBRT 73static double 74cbrt(double x) 75{ 76 if (x > 0.0) 77 return pow(x, 1.0/3.0); 78 else 79 return -pow(-x, 1.0/3.0); 80} 81#endif 82 83/* 84 * some interesting sematic interpretation of the protocol: 85 * 86 * Self intersecting arcs (i.e. those spanning 360 degrees) 87 * never join with other arcs, and are drawn without caps 88 * (unless on/off dashed, in which case each dash segment 89 * is capped, except when the last segment meets the 90 * first segment, when no caps are drawn) 91 * 92 * double dash arcs are drawn in two parts, first the 93 * odd dashes (drawn in background) then the even dashes 94 * (drawn in foreground). This means that overlapping 95 * sections of foreground/background are drawn twice, 96 * first in background then in foreground. The double-draw 97 * occurs even when the function uses the destination values 98 * (e.g. xor mode). This is the same way the wide-line 99 * code works and should be "fixed". 100 * 101 */ 102 103#undef max 104#undef min 105 106_X_INLINE static int max (const int x, const int y) 107{ 108 return x>y? x:y; 109} 110 111_X_INLINE static int min (const int x, const int y) 112{ 113 return x<y? x:y; 114} 115 116struct bound { 117 double min, max; 118}; 119 120struct ibound { 121 int min, max; 122}; 123 124#define boundedLe(value, bounds)\ 125 ((bounds).min <= (value) && (value) <= (bounds).max) 126 127struct line { 128 double m, b; 129 int valid; 130}; 131 132#define intersectLine(y,line) (line.m * (y) + line.b) 133 134/* 135 * these are all y value bounds 136 */ 137 138struct arc_bound { 139 struct bound ellipse; 140 struct bound inner; 141 struct bound outer; 142 struct bound right; 143 struct bound left; 144 struct ibound inneri; 145 struct ibound outeri; 146}; 147 148struct accelerators { 149 double tail_y; 150 double h2; 151 double w2; 152 double h4; 153 double w4; 154 double h2mw2; 155 double h2l; 156 double w2l; 157 double fromIntX; 158 double fromIntY; 159 struct line left, right; 160 int yorgu; 161 int yorgl; 162 int xorg; 163}; 164 165struct arc_def { 166 double w, h, l; 167 double a0, a1; 168}; 169 170# define todeg(xAngle) (((double) (xAngle)) / 64.0) 171 172# define RIGHT_END 0 173# define LEFT_END 1 174 175typedef struct _miArcJoin { 176 int arcIndex0, arcIndex1; 177 int phase0, phase1; 178 int end0, end1; 179} miArcJoinRec, *miArcJoinPtr; 180 181typedef struct _miArcCap { 182 int arcIndex; 183 int end; 184} miArcCapRec, *miArcCapPtr; 185 186typedef struct _miArcFace { 187 SppPointRec clock; 188 SppPointRec center; 189 SppPointRec counterClock; 190} miArcFaceRec, *miArcFacePtr; 191 192typedef struct _miArcData { 193 xArc arc; 194 int render; /* non-zero means render after drawing */ 195 int join; /* related join */ 196 int cap; /* related cap */ 197 int selfJoin; /* final dash meets first dash */ 198 miArcFaceRec bounds[2]; 199 double x0, y0, x1, y1; 200} miArcDataRec, *miArcDataPtr; 201 202/* 203 * This is an entire sequence of arcs, computed and categorized according 204 * to operation. miDashArcs generates either one or two of these. 205 */ 206 207typedef struct _miPolyArc { 208 int narcs; 209 miArcDataPtr arcs; 210 int ncaps; 211 miArcCapPtr caps; 212 int njoins; 213 miArcJoinPtr joins; 214} miPolyArcRec, *miPolyArcPtr; 215 216#define GCValsFunction 0 217#define GCValsForeground 1 218#define GCValsBackground 2 219#define GCValsLineWidth 3 220#define GCValsCapStyle 4 221#define GCValsJoinStyle 5 222#define GCValsMask (GCFunction | GCForeground | GCBackground | \ 223 GCLineWidth | GCCapStyle | GCJoinStyle) 224static CARD32 gcvals[6]; 225 226static void fillSpans(DrawablePtr pDrawable, GCPtr pGC); 227static void newFinalSpan(int y, int xmin, int xmax); 228static void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right, 229 miArcFacePtr left); 230static void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc *tarc, int lw, 231 miArcFacePtr left, miArcFacePtr right); 232static void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, 233 miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, 234 double xFtransLeft, double yFtransLeft, 235 int xOrgRight, int yOrgRight, 236 double xFtransRight, double yFtransRight); 237static void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace, 238 int end, int xOrg, int yOrg, double xFtrans, 239 double yFtrans); 240static void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter, 241 SppPointRec pEnd, SppPointRec pCorner, 242 SppPointRec pOtherCorner, int fLineEnd, 243 int xOrg, int yOrg, double xFtrans, double yFtrans); 244static void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC); 245static miPolyArcPtr miComputeArcs(xArc *parcs, int narcs, GCPtr pGC); 246static int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts); 247 248# define CUBED_ROOT_2 1.2599210498948732038115849718451499938964 249# define CUBED_ROOT_4 1.5874010519681993173435330390930175781250 250 251/* 252 * draw one segment of the arc using the arc spans generation routines 253 */ 254 255static void 256miArcSegment( 257 DrawablePtr pDraw, 258 GCPtr pGC, 259 xArc tarc, 260 miArcFacePtr right, 261 miArcFacePtr left) 262{ 263 int l = pGC->lineWidth; 264 int a0, a1, startAngle, endAngle; 265 miArcFacePtr temp; 266 267 if (!l) 268 l = 1; 269 270 if (tarc.width == 0 || tarc.height == 0) { 271 drawZeroArc (pDraw, pGC, &tarc, l, left, right); 272 return; 273 } 274 275 if (pGC->miTranslate) { 276 tarc.x += pDraw->x; 277 tarc.y += pDraw->y; 278 } 279 280 a0 = tarc.angle1; 281 a1 = tarc.angle2; 282 if (a1 > FULLCIRCLE) 283 a1 = FULLCIRCLE; 284 else if (a1 < -FULLCIRCLE) 285 a1 = -FULLCIRCLE; 286 if (a1 < 0) { 287 startAngle = a0 + a1; 288 endAngle = a0; 289 temp = right; 290 right = left; 291 left = temp; 292 } else { 293 startAngle = a0; 294 endAngle = a0 + a1; 295 } 296 /* 297 * bounds check the two angles 298 */ 299 if (startAngle < 0) 300 startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; 301 if (startAngle >= FULLCIRCLE) 302 startAngle = startAngle % FULLCIRCLE; 303 if (endAngle < 0) 304 endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; 305 if (endAngle > FULLCIRCLE) 306 endAngle = (endAngle-1) % FULLCIRCLE + 1; 307 if ((startAngle == endAngle) && a1) { 308 startAngle = 0; 309 endAngle = FULLCIRCLE; 310 } 311 312 drawArc (&tarc, l, startAngle, endAngle, right, left); 313} 314 315/* 316 317Three equations combine to describe the boundaries of the arc 318 319x^2/w^2 + y^2/h^2 = 1 ellipse itself 320(X-x)^2 + (Y-y)^2 = r^2 circle at (x, y) on the ellipse 321(Y-y) = (X-x)*w^2*y/(h^2*x) normal at (x, y) on the ellipse 322 323These lead to a quartic relating Y and y 324 325y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2 326 - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0 327 328The reducible cubic obtained from this quartic is 329 330z^3 - (3N)z^2 - 2V = 0 331 332where 333 334N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6 335V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2) 336 337Let 338 339t = z - N 340p = -N^2 341q = -N^3 - V 342 343Then we get 344 345t^3 + 3pt + 2q = 0 346 347The discriminant of this cubic is 348 349D = q^2 + p^3 350 351When D > 0, a real root is obtained as 352 353z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D)) 354 355When D < 0, a real root is obtained as 356 357z = N - 2m*cos(acos(-q/m^3)/3) 358 359where 360 361m = sqrt(|p|) * sign(q) 362 363Given a real root Z of the cubic, the roots of the quartic are the roots 364of the two quadratics 365 366y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0 367 368where 369 370A = +/- sqrt(8Z + b^2 - 4c) 371b, c, d are the cubic, quadratic, and linear coefficients of the quartic 372 373Some experimentation is then required to determine which solutions 374correspond to the inner and outer boundaries. 375 376*/ 377 378typedef struct { 379 short lx, lw, rx, rw; 380} miArcSpan; 381 382typedef struct { 383 miArcSpan *spans; 384 int count1, count2, k; 385 char top, bot, hole; 386} miArcSpanData; 387 388typedef struct { 389 unsigned long lrustamp; 390 unsigned short lw; 391 unsigned short width, height; 392 miArcSpanData *spdata; 393} arcCacheRec; 394 395#define CACHESIZE 25 396 397static void drawQuadrant(struct arc_def *def, struct accelerators *acc, 398 int a0, int a1, int mask, miArcFacePtr right, 399 miArcFacePtr left, miArcSpanData *spdata); 400 401static arcCacheRec arcCache[CACHESIZE]; 402static unsigned long lrustamp; 403static arcCacheRec *lastCacheHit = &arcCache[0]; 404static RESTYPE cacheType; 405 406static int 407miFreeArcCache (pointer data, XID id) 408{ 409 int k; 410 arcCacheRec *cent; 411 412 if (id) 413 cacheType = 0; 414 415 for (k = CACHESIZE, cent = &arcCache[0]; --k >= 0; cent++) 416 { 417 if (cent->spdata) 418 { 419 cent->lrustamp = 0; 420 cent->lw = 0; 421 xfree(cent->spdata); 422 cent->spdata = NULL; 423 } 424 } 425 lrustamp = 0; 426 return Success; 427} 428 429static void 430miComputeCircleSpans( 431 int lw, 432 xArc *parc, 433 miArcSpanData *spdata) 434{ 435 miArcSpan *span; 436 int doinner; 437 int x, y, e; 438 int xk, yk, xm, ym, dx, dy; 439 int slw, inslw; 440 int inx = 0, iny, ine = 0; 441 int inxk = 0, inyk = 0, inxm = 0, inym = 0; 442 443 doinner = -lw; 444 slw = parc->width - doinner; 445 y = parc->height >> 1; 446 dy = parc->height & 1; 447 dx = 1 - dy; 448 MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym); 449 inslw = parc->width + doinner; 450 if (inslw > 0) 451 { 452 spdata->hole = spdata->top; 453 MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym); 454 } 455 else 456 { 457 spdata->hole = FALSE; 458 doinner = -y; 459 } 460 spdata->count1 = -doinner - spdata->top; 461 spdata->count2 = y + doinner; 462 span = spdata->spans; 463 while (y) 464 { 465 MIFILLARCSTEP(slw); 466 span->lx = dy - x; 467 if (++doinner <= 0) 468 { 469 span->lw = slw; 470 span->rx = 0; 471 span->rw = span->lx + slw; 472 } 473 else 474 { 475 MIFILLINARCSTEP(inslw); 476 span->lw = x - inx; 477 span->rx = dy - inx + inslw; 478 span->rw = inx - x + slw - inslw; 479 } 480 span++; 481 } 482 if (spdata->bot) 483 { 484 if (spdata->count2) 485 spdata->count2--; 486 else 487 { 488 if (lw > (int)parc->height) 489 span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1); 490 else 491 span[-1].rw = 0; 492 spdata->count1--; 493 } 494 } 495} 496 497static void 498miComputeEllipseSpans( 499 int lw, 500 xArc *parc, 501 miArcSpanData *spdata) 502{ 503 miArcSpan *span; 504 double w, h, r, xorg; 505 double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs; 506 double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm; 507 int flip, solution; 508 509 w = (double)parc->width / 2.0; 510 h = (double)parc->height / 2.0; 511 r = lw / 2.0; 512 rs = r * r; 513 Hs = h * h; 514 WH = w * w - Hs; 515 Nk = w * r; 516 Vk = (Nk * Hs) / (WH + WH); 517 Hf = Hs * Hs; 518 Nk = (Hf - Nk * Nk) / WH; 519 Fk = Hf / WH; 520 hepp = h + EPSILON; 521 hepm = h - EPSILON; 522 K = h + ((lw - 1) >> 1); 523 span = spdata->spans; 524 if (parc->width & 1) 525 xorg = .5; 526 else 527 xorg = 0.0; 528 if (spdata->top) 529 { 530 span->lx = 0; 531 span->lw = 1; 532 span++; 533 } 534 spdata->count1 = 0; 535 spdata->count2 = 0; 536 spdata->hole = (spdata->top && 537 (int)parc->height * lw <= (int)(parc->width * parc->width) && 538 lw < (int)parc->height); 539 for (; K > 0.0; K -= 1.0) 540 { 541 N = (K * K + Nk) / 6.0; 542 Nc = N * N * N; 543 Vr = Vk * K; 544 t = Nc + Vr * Vr; 545 d = Nc + t; 546 if (d < 0.0) { 547 d = Nc; 548 b = N; 549 if ( (b < 0.0) == (t < 0.0) ) 550 { 551 b = -b; 552 d = -d; 553 } 554 Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); 555 if ( (Z < 0.0) == (Vr < 0.0) ) 556 flip = 2; 557 else 558 flip = 1; 559 } 560 else 561 { 562 d = Vr * sqrt(d); 563 Z = N + cbrt(t + d) + cbrt(t - d); 564 flip = 0; 565 } 566 A = sqrt((Z + Z) - Nk); 567 T = (Fk - Z) * K / A; 568 inx = 0.0; 569 solution = FALSE; 570 b = -A + K; 571 d = b * b - 4 * (Z + T); 572 if (d >= 0) 573 { 574 d = sqrt(d); 575 y = (b + d) / 2; 576 if ((y >= 0.0) && (y < hepp)) 577 { 578 solution = TRUE; 579 if (y > hepm) 580 y = h; 581 t = y / h; 582 x = w * sqrt(1 - (t * t)); 583 t = K - y; 584 if (rs - (t * t) >= 0) 585 t = sqrt(rs - (t * t)); 586 else 587 t = 0; 588 if (flip == 2) 589 inx = x - t; 590 else 591 outx = x + t; 592 } 593 } 594 b = A + K; 595 d = b * b - 4 * (Z - T); 596 /* Because of the large magnitudes involved, we lose enough precision 597 * that sometimes we end up with a negative value near the axis, when 598 * it should be positive. This is a workaround. 599 */ 600 if (d < 0 && !solution) 601 d = 0.0; 602 if (d >= 0) { 603 d = sqrt(d); 604 y = (b + d) / 2; 605 if (y < hepp) 606 { 607 if (y > hepm) 608 y = h; 609 t = y / h; 610 x = w * sqrt(1 - (t * t)); 611 t = K - y; 612 if (rs - (t * t) >= 0) 613 inx = x - sqrt(rs - (t * t)); 614 else 615 inx = x; 616 } 617 y = (b - d) / 2; 618 if (y >= 0.0) 619 { 620 if (y > hepm) 621 y = h; 622 t = y / h; 623 x = w * sqrt(1 - (t * t)); 624 t = K - y; 625 if (rs - (t * t) >= 0) 626 t = sqrt(rs - (t * t)); 627 else 628 t = 0; 629 if (flip == 1) 630 inx = x - t; 631 else 632 outx = x + t; 633 } 634 } 635 span->lx = ICEIL(xorg - outx); 636 if (inx <= 0.0) 637 { 638 spdata->count1++; 639 span->lw = ICEIL(xorg + outx) - span->lx; 640 span->rx = ICEIL(xorg + inx); 641 span->rw = -ICEIL(xorg - inx); 642 } 643 else 644 { 645 spdata->count2++; 646 span->lw = ICEIL(xorg - inx) - span->lx; 647 span->rx = ICEIL(xorg + inx); 648 span->rw = ICEIL(xorg + outx) - span->rx; 649 } 650 span++; 651 } 652 if (spdata->bot) 653 { 654 outx = w + r; 655 if (r >= h && r <= w) 656 inx = 0.0; 657 else if (Nk < 0.0 && -Nk < Hs) 658 { 659 inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); 660 if (inx > w - r) 661 inx = w - r; 662 } 663 else 664 inx = w - r; 665 span->lx = ICEIL(xorg - outx); 666 if (inx <= 0.0) 667 { 668 span->lw = ICEIL(xorg + outx) - span->lx; 669 span->rx = ICEIL(xorg + inx); 670 span->rw = -ICEIL(xorg - inx); 671 } 672 else 673 { 674 span->lw = ICEIL(xorg - inx) - span->lx; 675 span->rx = ICEIL(xorg + inx); 676 span->rw = ICEIL(xorg + outx) - span->rx; 677 } 678 } 679 if (spdata->hole) 680 { 681 span = &spdata->spans[spdata->count1]; 682 span->lw = -span->lx; 683 span->rx = 1; 684 span->rw = span->lw; 685 spdata->count1--; 686 spdata->count2++; 687 } 688} 689 690static double 691tailX( 692 double K, 693 struct arc_def *def, 694 struct arc_bound *bounds, 695 struct accelerators *acc) 696{ 697 double w, h, r; 698 double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs; 699 double A, T, b, d, x, y, t, hepp, hepm; 700 int flip, solution; 701 double xs[2]; 702 double *xp; 703 704 w = def->w; 705 h = def->h; 706 r = def->l; 707 rs = r * r; 708 Hs = acc->h2; 709 WH = -acc->h2mw2; 710 Nk = def->w * r; 711 Vk = (Nk * Hs) / (WH + WH); 712 Hf = acc->h4; 713 Nk = (Hf - Nk * Nk) / WH; 714 if (K == 0.0) { 715 if (Nk < 0.0 && -Nk < Hs) { 716 xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); 717 xs[1] = w - r; 718 if (acc->left.valid && boundedLe(K, bounds->left) && 719 !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) 720 return xs[1]; 721 if (acc->right.valid && boundedLe(K, bounds->right) && 722 !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) 723 return xs[1]; 724 return xs[0]; 725 } 726 return w - r; 727 } 728 Fk = Hf / WH; 729 hepp = h + EPSILON; 730 hepm = h - EPSILON; 731 N = (K * K + Nk) / 6.0; 732 Nc = N * N * N; 733 Vr = Vk * K; 734 xp = xs; 735 xs[0] = 0.0; 736 t = Nc + Vr * Vr; 737 d = Nc + t; 738 if (d < 0.0) { 739 d = Nc; 740 b = N; 741 if ( (b < 0.0) == (t < 0.0) ) 742 { 743 b = -b; 744 d = -d; 745 } 746 Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); 747 if ( (Z < 0.0) == (Vr < 0.0) ) 748 flip = 2; 749 else 750 flip = 1; 751 } 752 else 753 { 754 d = Vr * sqrt(d); 755 Z = N + cbrt(t + d) + cbrt(t - d); 756 flip = 0; 757 } 758 A = sqrt((Z + Z) - Nk); 759 T = (Fk - Z) * K / A; 760 solution = FALSE; 761 b = -A + K; 762 d = b * b - 4 * (Z + T); 763 if (d >= 0 && flip == 2) 764 { 765 d = sqrt(d); 766 y = (b + d) / 2; 767 if ((y >= 0.0) && (y < hepp)) 768 { 769 solution = TRUE; 770 if (y > hepm) 771 y = h; 772 t = y / h; 773 x = w * sqrt(1 - (t * t)); 774 t = K - y; 775 if (rs - (t * t) >= 0) 776 t = sqrt(rs - (t * t)); 777 else 778 t = 0; 779 *xp++ = x - t; 780 } 781 } 782 b = A + K; 783 d = b * b - 4 * (Z - T); 784 /* Because of the large magnitudes involved, we lose enough precision 785 * that sometimes we end up with a negative value near the axis, when 786 * it should be positive. This is a workaround. 787 */ 788 if (d < 0 && !solution) 789 d = 0.0; 790 if (d >= 0) { 791 d = sqrt(d); 792 y = (b + d) / 2; 793 if (y < hepp) 794 { 795 if (y > hepm) 796 y = h; 797 t = y / h; 798 x = w * sqrt(1 - (t * t)); 799 t = K - y; 800 if (rs - (t * t) >= 0) 801 *xp++ = x - sqrt(rs - (t * t)); 802 else 803 *xp++ = x; 804 } 805 y = (b - d) / 2; 806 if (y >= 0.0 && flip == 1) 807 { 808 if (y > hepm) 809 y = h; 810 t = y / h; 811 x = w * sqrt(1 - (t * t)); 812 t = K - y; 813 if (rs - (t * t) >= 0) 814 t = sqrt(rs - (t * t)); 815 else 816 t = 0; 817 *xp++ = x - t; 818 } 819 } 820 if (xp > &xs[1]) { 821 if (acc->left.valid && boundedLe(K, bounds->left) && 822 !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) 823 return xs[1]; 824 if (acc->right.valid && boundedLe(K, bounds->right) && 825 !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) 826 return xs[1]; 827 } 828 return xs[0]; 829} 830 831static miArcSpanData * 832miComputeWideEllipse( 833 int lw, 834 xArc *parc, 835 Bool *mustFree) 836{ 837 miArcSpanData *spdata; 838 arcCacheRec *cent, *lruent; 839 int k; 840 arcCacheRec fakeent; 841 842 if (!lw) 843 lw = 1; 844 if (parc->height <= 1500) 845 { 846 *mustFree = FALSE; 847 cent = lastCacheHit; 848 if (cent->lw == lw && 849 cent->width == parc->width && cent->height == parc->height) 850 { 851 cent->lrustamp = ++lrustamp; 852 return cent->spdata; 853 } 854 lruent = &arcCache[0]; 855 for (k = CACHESIZE, cent = lruent; --k >= 0; cent++) 856 { 857 if (cent->lw == lw && 858 cent->width == parc->width && cent->height == parc->height) 859 { 860 cent->lrustamp = ++lrustamp; 861 lastCacheHit = cent; 862 return cent->spdata; 863 } 864 if (cent->lrustamp < lruent->lrustamp) 865 lruent = cent; 866 } 867 if (!cacheType) 868 { 869 cacheType = CreateNewResourceType(miFreeArcCache); 870 (void) AddResource(FakeClientID(0), cacheType, NULL); 871 } 872 } else { 873 lruent = &fakeent; 874 lruent->spdata = NULL; 875 *mustFree = TRUE; 876 } 877 k = (parc->height >> 1) + ((lw - 1) >> 1); 878 spdata = lruent->spdata; 879 if (!spdata || spdata->k != k) 880 { 881 if (spdata) 882 xfree(spdata); 883 spdata = (miArcSpanData *)xalloc(sizeof(miArcSpanData) + 884 sizeof(miArcSpan) * (k + 2)); 885 lruent->spdata = spdata; 886 if (!spdata) 887 { 888 lruent->lrustamp = 0; 889 lruent->lw = 0; 890 return spdata; 891 } 892 spdata->spans = (miArcSpan *)(spdata + 1); 893 spdata->k = k; 894 } 895 spdata->top = !(lw & 1) && !(parc->width & 1); 896 spdata->bot = !(parc->height & 1); 897 lruent->lrustamp = ++lrustamp; 898 lruent->lw = lw; 899 lruent->width = parc->width; 900 lruent->height = parc->height; 901 if (lruent != &fakeent) 902 lastCacheHit = lruent; 903 if (parc->width == parc->height) 904 miComputeCircleSpans(lw, parc, spdata); 905 else 906 miComputeEllipseSpans(lw, parc, spdata); 907 return spdata; 908} 909 910static void 911miFillWideEllipse( 912 DrawablePtr pDraw, 913 GCPtr pGC, 914 xArc *parc) 915{ 916 DDXPointPtr points; 917 DDXPointPtr pts; 918 int *widths; 919 int *wids; 920 miArcSpanData *spdata; 921 Bool mustFree; 922 miArcSpan *span; 923 int xorg, yorgu, yorgl; 924 int n; 925 926 yorgu = parc->height + pGC->lineWidth; 927 n = (sizeof(int) * 2) * yorgu; 928 widths = (int *)xalloc(n + (sizeof(DDXPointRec) * 2) * yorgu); 929 if (!widths) 930 return; 931 points = (DDXPointPtr)((char *)widths + n); 932 spdata = miComputeWideEllipse((int)pGC->lineWidth, parc, &mustFree); 933 if (!spdata) 934 { 935 xfree(widths); 936 return; 937 } 938 pts = points; 939 wids = widths; 940 span = spdata->spans; 941 xorg = parc->x + (parc->width >> 1); 942 yorgu = parc->y + (parc->height >> 1); 943 yorgl = yorgu + (parc->height & 1); 944 if (pGC->miTranslate) 945 { 946 xorg += pDraw->x; 947 yorgu += pDraw->y; 948 yorgl += pDraw->y; 949 } 950 yorgu -= spdata->k; 951 yorgl += spdata->k; 952 if (spdata->top) 953 { 954 pts->x = xorg; 955 pts->y = yorgu - 1; 956 pts++; 957 *wids++ = 1; 958 span++; 959 } 960 for (n = spdata->count1; --n >= 0; ) 961 { 962 pts[0].x = xorg + span->lx; 963 pts[0].y = yorgu; 964 wids[0] = span->lw; 965 pts[1].x = pts[0].x; 966 pts[1].y = yorgl; 967 wids[1] = wids[0]; 968 yorgu++; 969 yorgl--; 970 pts += 2; 971 wids += 2; 972 span++; 973 } 974 if (spdata->hole) 975 { 976 pts[0].x = xorg; 977 pts[0].y = yorgl; 978 wids[0] = 1; 979 pts++; 980 wids++; 981 } 982 for (n = spdata->count2; --n >= 0; ) 983 { 984 pts[0].x = xorg + span->lx; 985 pts[0].y = yorgu; 986 wids[0] = span->lw; 987 pts[1].x = xorg + span->rx; 988 pts[1].y = pts[0].y; 989 wids[1] = span->rw; 990 pts[2].x = pts[0].x; 991 pts[2].y = yorgl; 992 wids[2] = wids[0]; 993 pts[3].x = pts[1].x; 994 pts[3].y = pts[2].y; 995 wids[3] = wids[1]; 996 yorgu++; 997 yorgl--; 998 pts += 4; 999 wids += 4; 1000 span++; 1001 } 1002 if (spdata->bot) 1003 { 1004 if (span->rw <= 0) 1005 { 1006 pts[0].x = xorg + span->lx; 1007 pts[0].y = yorgu; 1008 wids[0] = span->lw; 1009 pts++; 1010 wids++; 1011 } 1012 else 1013 { 1014 pts[0].x = xorg + span->lx; 1015 pts[0].y = yorgu; 1016 wids[0] = span->lw; 1017 pts[1].x = xorg + span->rx; 1018 pts[1].y = pts[0].y; 1019 wids[1] = span->rw; 1020 pts += 2; 1021 wids += 2; 1022 } 1023 } 1024 if (mustFree) 1025 xfree(spdata); 1026 (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); 1027 1028 xfree(widths); 1029} 1030 1031/* 1032 * miPolyArc strategy: 1033 * 1034 * If arc is zero width and solid, we don't have to worry about the rasterop 1035 * or join styles. For wide solid circles, we use a fast integer algorithm. 1036 * For wide solid ellipses, we use special case floating point code. 1037 * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then 1038 * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is, 1039 * if it involves the destination, then we use PushPixels to move the bits 1040 * from the scratch drawable to pDraw. (See the wide line code for a 1041 * fuller explanation of this.) 1042 */ 1043 1044_X_EXPORT void 1045miPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) 1046{ 1047 int i; 1048 xArc *parc; 1049 int xMin, xMax, yMin, yMax; 1050 int pixmapWidth = 0, pixmapHeight = 0; 1051 int xOrg = 0, yOrg = 0; 1052 int width; 1053 Bool fTricky; 1054 DrawablePtr pDrawTo; 1055 CARD32 fg, bg; 1056 GCPtr pGCTo; 1057 miPolyArcPtr polyArcs; 1058 int cap[2], join[2]; 1059 int iphase; 1060 int halfWidth; 1061 1062 width = pGC->lineWidth; 1063 if(width == 0 && pGC->lineStyle == LineSolid) 1064 { 1065 for(i = narcs, parc = parcs; --i >= 0; parc++) 1066 miArcSegment( pDraw, pGC, *parc, 1067 (miArcFacePtr) 0, (miArcFacePtr) 0 ); 1068 fillSpans (pDraw, pGC); 1069 } 1070 else 1071 { 1072 if ((pGC->lineStyle == LineSolid) && narcs) 1073 { 1074 while (parcs->width && parcs->height && 1075 (parcs->angle2 >= FULLCIRCLE || 1076 parcs->angle2 <= -FULLCIRCLE)) 1077 { 1078 miFillWideEllipse(pDraw, pGC, parcs); 1079 if (!--narcs) 1080 return; 1081 parcs++; 1082 } 1083 } 1084 1085 /* Set up pDrawTo and pGCTo based on the rasterop */ 1086 switch(pGC->alu) 1087 { 1088 case GXclear: /* 0 */ 1089 case GXcopy: /* src */ 1090 case GXcopyInverted: /* NOT src */ 1091 case GXset: /* 1 */ 1092 fTricky = FALSE; 1093 pDrawTo = pDraw; 1094 pGCTo = pGC; 1095 break; 1096 default: 1097 fTricky = TRUE; 1098 1099 /* find bounding box around arcs */ 1100 xMin = yMin = MAXSHORT; 1101 xMax = yMax = MINSHORT; 1102 1103 for(i = narcs, parc = parcs; --i >= 0; parc++) 1104 { 1105 xMin = min (xMin, parc->x); 1106 yMin = min (yMin, parc->y); 1107 xMax = max (xMax, (parc->x + (int) parc->width)); 1108 yMax = max (yMax, (parc->y + (int) parc->height)); 1109 } 1110 1111 /* expand box to deal with line widths */ 1112 halfWidth = (width + 1)/2; 1113 xMin -= halfWidth; 1114 yMin -= halfWidth; 1115 xMax += halfWidth; 1116 yMax += halfWidth; 1117 1118 /* compute pixmap size; limit it to size of drawable */ 1119 xOrg = max(xMin, 0); 1120 yOrg = max(yMin, 0); 1121 pixmapWidth = min(xMax, pDraw->width) - xOrg; 1122 pixmapHeight = min(yMax, pDraw->height) - yOrg; 1123 1124 /* if nothing left, return */ 1125 if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return; 1126 1127 for(i = narcs, parc = parcs; --i >= 0; parc++) 1128 { 1129 parc->x -= xOrg; 1130 parc->y -= yOrg; 1131 } 1132 if (pGC->miTranslate) 1133 { 1134 xOrg += pDraw->x; 1135 yOrg += pDraw->y; 1136 } 1137 1138 /* set up scratch GC */ 1139 1140 pGCTo = GetScratchGC(1, pDraw->pScreen); 1141 if (!pGCTo) 1142 return; 1143 gcvals[GCValsFunction] = GXcopy; 1144 gcvals[GCValsForeground] = 1; 1145 gcvals[GCValsBackground] = 0; 1146 gcvals[GCValsLineWidth] = pGC->lineWidth; 1147 gcvals[GCValsCapStyle] = pGC->capStyle; 1148 gcvals[GCValsJoinStyle] = pGC->joinStyle; 1149 dixChangeGC(NullClient, pGCTo, GCValsMask, gcvals, NULL); 1150 1151 /* allocate a 1 bit deep pixmap of the appropriate size, and 1152 * validate it */ 1153 pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap) 1154 (pDraw->pScreen, pixmapWidth, pixmapHeight, 1, 1155 CREATE_PIXMAP_USAGE_SCRATCH); 1156 if (!pDrawTo) 1157 { 1158 FreeScratchGC(pGCTo); 1159 return; 1160 } 1161 ValidateGC(pDrawTo, pGCTo); 1162 miClearDrawable(pDrawTo, pGCTo); 1163 } 1164 1165 fg = pGC->fgPixel; 1166 bg = pGC->bgPixel; 1167 if ((pGC->fillStyle == FillTiled) || 1168 (pGC->fillStyle == FillOpaqueStippled)) 1169 bg = fg; /* the protocol sez these don't cause color changes */ 1170 1171 polyArcs = miComputeArcs (parcs, narcs, pGC); 1172 1173 if (!polyArcs) 1174 { 1175 if (fTricky) { 1176 (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo); 1177 FreeScratchGC (pGCTo); 1178 } 1179 return; 1180 } 1181 1182 cap[0] = cap[1] = 0; 1183 join[0] = join[1] = 0; 1184 for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); 1185 iphase >= 0; 1186 iphase--) 1187 { 1188 if (iphase == 1) { 1189 dixChangeGC (NullClient, pGC, GCForeground, &bg, NULL); 1190 ValidateGC (pDraw, pGC); 1191 } else if (pGC->lineStyle == LineDoubleDash) { 1192 dixChangeGC (NullClient, pGC, GCForeground, &fg, NULL); 1193 ValidateGC (pDraw, pGC); 1194 } 1195 for (i = 0; i < polyArcs[iphase].narcs; i++) { 1196 miArcDataPtr arcData; 1197 1198 arcData = &polyArcs[iphase].arcs[i]; 1199 miArcSegment(pDrawTo, pGCTo, arcData->arc, 1200 &arcData->bounds[RIGHT_END], 1201 &arcData->bounds[LEFT_END]); 1202 if (polyArcs[iphase].arcs[i].render) { 1203 fillSpans (pDrawTo, pGCTo); 1204 /* 1205 * don't cap self-joining arcs 1206 */ 1207 if (polyArcs[iphase].arcs[i].selfJoin && 1208 cap[iphase] < polyArcs[iphase].arcs[i].cap) 1209 cap[iphase]++; 1210 while (cap[iphase] < polyArcs[iphase].arcs[i].cap) { 1211 int arcIndex, end; 1212 miArcDataPtr arcData0; 1213 1214 arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex; 1215 end = polyArcs[iphase].caps[cap[iphase]].end; 1216 arcData0 = &polyArcs[iphase].arcs[arcIndex]; 1217 miArcCap (pDrawTo, pGCTo, 1218 &arcData0->bounds[end], end, 1219 arcData0->arc.x, arcData0->arc.y, 1220 (double) arcData0->arc.width / 2.0, 1221 (double) arcData0->arc.height / 2.0); 1222 ++cap[iphase]; 1223 } 1224 while (join[iphase] < polyArcs[iphase].arcs[i].join) { 1225 int arcIndex0, arcIndex1, end0, end1; 1226 int phase0, phase1; 1227 miArcDataPtr arcData0, arcData1; 1228 miArcJoinPtr joinp; 1229 1230 joinp = &polyArcs[iphase].joins[join[iphase]]; 1231 arcIndex0 = joinp->arcIndex0; 1232 end0 = joinp->end0; 1233 arcIndex1 = joinp->arcIndex1; 1234 end1 = joinp->end1; 1235 phase0 = joinp->phase0; 1236 phase1 = joinp->phase1; 1237 arcData0 = &polyArcs[phase0].arcs[arcIndex0]; 1238 arcData1 = &polyArcs[phase1].arcs[arcIndex1]; 1239 miArcJoin (pDrawTo, pGCTo, 1240 &arcData0->bounds[end0], 1241 &arcData1->bounds[end1], 1242 arcData0->arc.x, arcData0->arc.y, 1243 (double) arcData0->arc.width / 2.0, 1244 (double) arcData0->arc.height / 2.0, 1245 arcData1->arc.x, arcData1->arc.y, 1246 (double) arcData1->arc.width / 2.0, 1247 (double) arcData1->arc.height / 2.0); 1248 ++join[iphase]; 1249 } 1250 if (fTricky) { 1251 if (pGC->serialNumber != pDraw->serialNumber) 1252 ValidateGC (pDraw, pGC); 1253 (*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo, 1254 pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg); 1255 miClearDrawable ((DrawablePtr) pDrawTo, pGCTo); 1256 } 1257 } 1258 } 1259 } 1260 miFreeArcs(polyArcs, pGC); 1261 1262 if(fTricky) 1263 { 1264 (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo); 1265 FreeScratchGC(pGCTo); 1266 } 1267 } 1268} 1269 1270static double 1271angleBetween (SppPointRec center, SppPointRec point1, SppPointRec point2) 1272{ 1273 double a1, a2, a; 1274 1275 /* 1276 * reflect from X coordinates back to ellipse 1277 * coordinates -- y increasing upwards 1278 */ 1279 a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x); 1280 a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x); 1281 a = a2 - a1; 1282 if (a <= -180.0) 1283 a += 360.0; 1284 else if (a > 180.0) 1285 a -= 360.0; 1286 return a; 1287} 1288 1289static void 1290translateBounds ( 1291 miArcFacePtr b, 1292 int x, 1293 int y, 1294 double fx, 1295 double fy) 1296{ 1297 fx += x; 1298 fy += y; 1299 b->clock.x -= fx; 1300 b->clock.y -= fy; 1301 b->center.x -= fx; 1302 b->center.y -= fy; 1303 b->counterClock.x -= fx; 1304 b->counterClock.y -= fy; 1305} 1306 1307static void 1308miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, 1309 miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, 1310 double xFtransLeft, double yFtransLeft, 1311 int xOrgRight, int yOrgRight, 1312 double xFtransRight, double yFtransRight) 1313{ 1314 SppPointRec center, corner, otherCorner; 1315 SppPointRec poly[5], e; 1316 SppPointPtr pArcPts; 1317 int cpt; 1318 SppArcRec arc; 1319 miArcFaceRec Right, Left; 1320 int polyLen = 0; 1321 int xOrg, yOrg; 1322 double xFtrans, yFtrans; 1323 double a; 1324 double ae, ac2, ec2, bc2, de; 1325 double width; 1326 1327 xOrg = (xOrgRight + xOrgLeft) / 2; 1328 yOrg = (yOrgRight + yOrgLeft) / 2; 1329 xFtrans = (xFtransLeft + xFtransRight) / 2; 1330 yFtrans = (yFtransLeft + yFtransRight) / 2; 1331 Right = *pRight; 1332 translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight, 1333 xFtrans - xFtransRight, yFtrans - yFtransRight); 1334 Left = *pLeft; 1335 translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft, 1336 xFtrans - xFtransLeft, yFtrans - yFtransLeft); 1337 pRight = &Right; 1338 pLeft = &Left; 1339 1340 if (pRight->clock.x == pLeft->counterClock.x && 1341 pRight->clock.y == pLeft->counterClock.y) 1342 return; 1343 center = pRight->center; 1344 if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock)) 1345 && a <= 180.0) 1346 { 1347 corner = pRight->clock; 1348 otherCorner = pLeft->counterClock; 1349 } else { 1350 a = angleBetween (center, pLeft->clock, pRight->counterClock); 1351 corner = pLeft->clock; 1352 otherCorner = pRight->counterClock; 1353 } 1354 switch (pGC->joinStyle) { 1355 case JoinRound: 1356 width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); 1357 1358 arc.x = center.x - width/2; 1359 arc.y = center.y - width/2; 1360 arc.width = width; 1361 arc.height = width; 1362 arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x); 1363 arc.angle2 = a; 1364 pArcPts = (SppPointPtr) xalloc (3 * sizeof (SppPointRec)); 1365 if (!pArcPts) 1366 return; 1367 pArcPts[0].x = otherCorner.x; 1368 pArcPts[0].y = otherCorner.y; 1369 pArcPts[1].x = center.x; 1370 pArcPts[1].y = center.y; 1371 pArcPts[2].x = corner.x; 1372 pArcPts[2].y = corner.y; 1373 if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) ) 1374 { 1375 /* by drawing with miFillSppPoly and setting the endpoints of the arc 1376 * to be the corners, we assure that the cap will meet up with the 1377 * rest of the line */ 1378 miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans); 1379 } 1380 xfree(pArcPts); 1381 return; 1382 case JoinMiter: 1383 /* 1384 * don't miter arcs with less than 11 degrees between them 1385 */ 1386 if (a < 169.0) { 1387 poly[0] = corner; 1388 poly[1] = center; 1389 poly[2] = otherCorner; 1390 bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) + 1391 (corner.y - otherCorner.y) * (corner.y - otherCorner.y); 1392 ec2 = bc2 / 4; 1393 ac2 = (corner.x - center.x) * (corner.x - center.x) + 1394 (corner.y - center.y) * (corner.y - center.y); 1395 ae = sqrt (ac2 - ec2); 1396 de = ec2 / ae; 1397 e.x = (corner.x + otherCorner.x) / 2; 1398 e.y = (corner.y + otherCorner.y) / 2; 1399 poly[3].x = e.x + de * (e.x - center.x) / ae; 1400 poly[3].y = e.y + de * (e.y - center.y) / ae; 1401 poly[4] = corner; 1402 polyLen = 5; 1403 break; 1404 } 1405 case JoinBevel: 1406 poly[0] = corner; 1407 poly[1] = center; 1408 poly[2] = otherCorner; 1409 poly[3] = corner; 1410 polyLen = 4; 1411 break; 1412 } 1413 miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans); 1414} 1415 1416/*ARGSUSED*/ 1417static void 1418miArcCap ( 1419 DrawablePtr pDraw, 1420 GCPtr pGC, 1421 miArcFacePtr pFace, 1422 int end, 1423 int xOrg, 1424 int yOrg, 1425 double xFtrans, 1426 double yFtrans) 1427{ 1428 SppPointRec corner, otherCorner, center, endPoint, poly[5]; 1429 1430 corner = pFace->clock; 1431 otherCorner = pFace->counterClock; 1432 center = pFace->center; 1433 switch (pGC->capStyle) { 1434 case CapProjecting: 1435 poly[0].x = otherCorner.x; 1436 poly[0].y = otherCorner.y; 1437 poly[1].x = corner.x; 1438 poly[1].y = corner.y; 1439 poly[2].x = corner.x - 1440 (center.y - corner.y); 1441 poly[2].y = corner.y + 1442 (center.x - corner.x); 1443 poly[3].x = otherCorner.x - 1444 (otherCorner.y - center.y); 1445 poly[3].y = otherCorner.y + 1446 (otherCorner.x - center.x); 1447 poly[4].x = otherCorner.x; 1448 poly[4].y = otherCorner.y; 1449 miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans); 1450 break; 1451 case CapRound: 1452 /* 1453 * miRoundCap just needs these to be unequal. 1454 */ 1455 endPoint = center; 1456 endPoint.x = endPoint.x + 100; 1457 miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0, 1458 -xOrg, -yOrg, xFtrans, yFtrans); 1459 break; 1460 } 1461} 1462 1463/* MIROUNDCAP -- a private helper function 1464 * Put Rounded cap on end. pCenter is the center of this end of the line 1465 * pEnd is the center of the other end of the line. pCorner is one of the 1466 * two corners at this end of the line. 1467 * NOTE: pOtherCorner must be counter-clockwise from pCorner. 1468 */ 1469/*ARGSUSED*/ 1470static void 1471miRoundCap( 1472 DrawablePtr pDraw, 1473 GCPtr pGC, 1474 SppPointRec pCenter, 1475 SppPointRec pEnd, 1476 SppPointRec pCorner, 1477 SppPointRec pOtherCorner, 1478 int fLineEnd, 1479 int xOrg, 1480 int yOrg, 1481 double xFtrans, 1482 double yFtrans) 1483{ 1484 int cpt; 1485 double width; 1486 SppArcRec arc; 1487 SppPointPtr pArcPts; 1488 1489 width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); 1490 1491 arc.x = pCenter.x - width/2; 1492 arc.y = pCenter.y - width/2; 1493 arc.width = width; 1494 arc.height = width; 1495 arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x); 1496 if(PTISEQUAL(pCenter, pEnd)) 1497 arc.angle2 = - 180.0; 1498 else { 1499 arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1; 1500 if (arc.angle2 < 0) 1501 arc.angle2 += 360.0; 1502 } 1503 pArcPts = (SppPointPtr) NULL; 1504 if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) ) 1505 { 1506 /* by drawing with miFillSppPoly and setting the endpoints of the arc 1507 * to be the corners, we assure that the cap will meet up with the 1508 * rest of the line */ 1509 miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans); 1510 } 1511 xfree(pArcPts); 1512} 1513 1514/* 1515 * To avoid inaccuracy at the cardinal points, use trig functions 1516 * which are exact for those angles 1517 */ 1518 1519#ifndef M_PI 1520#define M_PI 3.14159265358979323846 1521#endif 1522#ifndef M_PI_2 1523#define M_PI_2 1.57079632679489661923 1524#endif 1525 1526# define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0))) 1527# define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) 1528# define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) 1529 1530static double 1531miDcos (double a) 1532{ 1533 int i; 1534 1535 if (floor (a/90) == a/90) { 1536 i = (int) (a/90.0); 1537 switch (mod (i, 4)) { 1538 case 0: return 1; 1539 case 1: return 0; 1540 case 2: return -1; 1541 case 3: return 0; 1542 } 1543 } 1544 return cos (a * M_PI / 180.0); 1545} 1546 1547static double 1548miDsin (double a) 1549{ 1550 int i; 1551 1552 if (floor (a/90) == a/90) { 1553 i = (int) (a/90.0); 1554 switch (mod (i, 4)) { 1555 case 0: return 0; 1556 case 1: return 1; 1557 case 2: return 0; 1558 case 3: return -1; 1559 } 1560 } 1561 return sin (a * M_PI / 180.0); 1562} 1563 1564static double 1565miDasin (double v) 1566{ 1567 if (v == 0) 1568 return 0.0; 1569 if (v == 1.0) 1570 return 90.0; 1571 if (v == -1.0) 1572 return -90.0; 1573 return asin(v) * (180.0 / M_PI); 1574} 1575 1576static double 1577miDatan2 (double dy, double dx) 1578{ 1579 if (dy == 0) { 1580 if (dx >= 0) 1581 return 0.0; 1582 return 180.0; 1583 } else if (dx == 0) { 1584 if (dy > 0) 1585 return 90.0; 1586 return -90.0; 1587 } else if (Fabs (dy) == Fabs (dx)) { 1588 if (dy > 0) { 1589 if (dx > 0) 1590 return 45.0; 1591 return 135.0; 1592 } else { 1593 if (dx > 0) 1594 return 315.0; 1595 return 225.0; 1596 } 1597 } else { 1598 return atan2 (dy, dx) * (180.0 / M_PI); 1599 } 1600} 1601 1602/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper 1603 * routine for filled arc and line (round cap) code. 1604 * Returns the number of points in the arc. Note that it takes a pointer 1605 * to a pointer to where it should put the points and an index (cpt). 1606 * This procedure allocates the space necessary to fit the arc points. 1607 * Sometimes it's convenient for those points to be at the end of an existing 1608 * array. (For example, if we want to leave a spare point to make sectors 1609 * instead of segments.) So we pass in the xalloc()ed chunk that contains the 1610 * array and an index saying where we should start stashing the points. 1611 * If there isn't an array already, we just pass in a null pointer and 1612 * count on xrealloc() to handle the null pointer correctly. 1613 */ 1614static int 1615miGetArcPts( 1616 SppArcPtr parc, /* points to an arc */ 1617 int cpt, /* number of points already in arc list */ 1618 SppPointPtr *ppPts) /* pointer to pointer to arc-list -- modified */ 1619{ 1620 double st, /* Start Theta, start angle */ 1621 et, /* End Theta, offset from start theta */ 1622 dt, /* Delta Theta, angle to sweep ellipse */ 1623 cdt, /* Cos Delta Theta, actually 2 cos(dt) */ 1624 x0, y0, /* the recurrence formula needs two points to start */ 1625 x1, y1, 1626 x2, y2, /* this will be the new point generated */ 1627 xc, yc; /* the center point */ 1628 int count, i; 1629 SppPointPtr poly; 1630 1631 /* The spec says that positive angles indicate counterclockwise motion. 1632 * Given our coordinate system (with 0,0 in the upper left corner), 1633 * the screen appears flipped in Y. The easiest fix is to negate the 1634 * angles given */ 1635 1636 st = - parc->angle1; 1637 1638 et = - parc->angle2; 1639 1640 /* Try to get a delta theta that is within 1/2 pixel. Then adjust it 1641 * so that it divides evenly into the total. 1642 * I'm just using cdt 'cause I'm lazy. 1643 */ 1644 cdt = parc->width; 1645 if (parc->height > cdt) 1646 cdt = parc->height; 1647 cdt /= 2.0; 1648 if(cdt <= 0) 1649 return 0; 1650 if (cdt < 1.0) 1651 cdt = 1.0; 1652 dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */ 1653 count = et/dt; 1654 count = abs(count) + 1; 1655 dt = et/count; 1656 count++; 1657 1658 cdt = 2 * miDcos(dt); 1659 if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts, 1660 (cpt + count) * sizeof(SppPointRec)))) 1661 return(0); 1662 *ppPts = poly; 1663 1664 xc = parc->width/2.0; /* store half width and half height */ 1665 yc = parc->height/2.0; 1666 1667 x0 = xc * miDcos(st); 1668 y0 = yc * miDsin(st); 1669 x1 = xc * miDcos(st + dt); 1670 y1 = yc * miDsin(st + dt); 1671 xc += parc->x; /* by adding initial point, these become */ 1672 yc += parc->y; /* the center point */ 1673 1674 poly[cpt].x = (xc + x0); 1675 poly[cpt].y = (yc + y0); 1676 poly[cpt + 1].x = (xc + x1); 1677 poly[cpt + 1].y = (yc + y1); 1678 1679 for(i = 2; i < count; i++) 1680 { 1681 x2 = cdt * x1 - x0; 1682 y2 = cdt * y1 - y0; 1683 1684 poly[cpt + i].x = (xc + x2); 1685 poly[cpt + i].y = (yc + y2); 1686 1687 x0 = x1; y0 = y1; 1688 x1 = x2; y1 = y2; 1689 } 1690 /* adjust the last point */ 1691 if (abs(parc->angle2) >= 360.0) 1692 poly[cpt +i -1] = poly[0]; 1693 else { 1694 poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc); 1695 poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc); 1696 } 1697 1698 return(count); 1699} 1700 1701struct arcData { 1702 double x0, y0, x1, y1; 1703 int selfJoin; 1704}; 1705 1706# define ADD_REALLOC_STEP 20 1707 1708static void 1709addCap ( 1710 miArcCapPtr *capsp, 1711 int *ncapsp, 1712 int *sizep, 1713 int end, 1714 int arcIndex) 1715{ 1716 int newsize; 1717 miArcCapPtr cap; 1718 1719 if (*ncapsp == *sizep) 1720 { 1721 newsize = *sizep + ADD_REALLOC_STEP; 1722 cap = (miArcCapPtr) xrealloc (*capsp, 1723 newsize * sizeof (**capsp)); 1724 if (!cap) 1725 return; 1726 *sizep = newsize; 1727 *capsp = cap; 1728 } 1729 cap = &(*capsp)[*ncapsp]; 1730 cap->end = end; 1731 cap->arcIndex = arcIndex; 1732 ++*ncapsp; 1733} 1734 1735static void 1736addJoin ( 1737 miArcJoinPtr *joinsp, 1738 int *njoinsp, 1739 int *sizep, 1740 int end0, 1741 int index0, 1742 int phase0, 1743 int end1, 1744 int index1, 1745 int phase1) 1746{ 1747 int newsize; 1748 miArcJoinPtr join; 1749 1750 if (*njoinsp == *sizep) 1751 { 1752 newsize = *sizep + ADD_REALLOC_STEP; 1753 join = (miArcJoinPtr) xrealloc (*joinsp, 1754 newsize * sizeof (**joinsp)); 1755 if (!join) 1756 return; 1757 *sizep = newsize; 1758 *joinsp = join; 1759 } 1760 join = &(*joinsp)[*njoinsp]; 1761 join->end0 = end0; 1762 join->arcIndex0 = index0; 1763 join->phase0 = phase0; 1764 join->end1 = end1; 1765 join->arcIndex1 = index1; 1766 join->phase1 = phase1; 1767 ++*njoinsp; 1768} 1769 1770static miArcDataPtr 1771addArc ( 1772 miArcDataPtr *arcsp, 1773 int *narcsp, 1774 int *sizep, 1775 xArc *xarc) 1776{ 1777 int newsize; 1778 miArcDataPtr arc; 1779 1780 if (*narcsp == *sizep) 1781 { 1782 newsize = *sizep + ADD_REALLOC_STEP; 1783 arc = (miArcDataPtr) xrealloc (*arcsp, 1784 newsize * sizeof (**arcsp)); 1785 if (!arc) 1786 return (miArcDataPtr)NULL; 1787 *sizep = newsize; 1788 *arcsp = arc; 1789 } 1790 arc = &(*arcsp)[*narcsp]; 1791 arc->arc = *xarc; 1792 ++*narcsp; 1793 return arc; 1794} 1795 1796static void 1797miFreeArcs( 1798 miPolyArcPtr arcs, 1799 GCPtr pGC) 1800{ 1801 int iphase; 1802 1803 for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); 1804 iphase >= 0; 1805 iphase--) 1806 { 1807 if (arcs[iphase].narcs > 0) 1808 xfree(arcs[iphase].arcs); 1809 if (arcs[iphase].njoins > 0) 1810 xfree(arcs[iphase].joins); 1811 if (arcs[iphase].ncaps > 0) 1812 xfree(arcs[iphase].caps); 1813 } 1814 xfree(arcs); 1815} 1816 1817/* 1818 * map angles to radial distance. This only deals with the first quadrant 1819 */ 1820 1821/* 1822 * a polygonal approximation to the arc for computing arc lengths 1823 */ 1824 1825# define DASH_MAP_SIZE 91 1826 1827# define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1)) 1828# define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64)) 1829# define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1)) 1830# define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1))) 1831 1832typedef struct { 1833 double map[DASH_MAP_SIZE]; 1834} dashMap; 1835 1836static int computeAngleFromPath(int startAngle, int endAngle, dashMap *map, 1837 int *lenp, int backwards); 1838 1839static void 1840computeDashMap ( 1841 xArc *arcp, 1842 dashMap *map) 1843{ 1844 int di; 1845 double a, x, y, prevx = 0.0, prevy = 0.0, dist; 1846 1847 for (di = 0; di < DASH_MAP_SIZE; di++) { 1848 a = dashIndexToAngle (di); 1849 x = ((double) arcp->width / 2.0) * miDcos (a); 1850 y = ((double) arcp->height / 2.0) * miDsin (a); 1851 if (di == 0) { 1852 map->map[di] = 0.0; 1853 } else { 1854 dist = hypot (x - prevx, y - prevy); 1855 map->map[di] = map->map[di - 1] + dist; 1856 } 1857 prevx = x; 1858 prevy = y; 1859 } 1860} 1861 1862typedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes; 1863 1864/* this routine is a bit gory */ 1865 1866static miPolyArcPtr 1867miComputeArcs ( 1868 xArc *parcs, 1869 int narcs, 1870 GCPtr pGC) 1871{ 1872 int isDashed, isDoubleDash; 1873 int dashOffset; 1874 miPolyArcPtr arcs; 1875 int start, i, j, k = 0, nexti, nextk = 0; 1876 int joinSize[2]; 1877 int capSize[2]; 1878 int arcSize[2]; 1879 int angle2; 1880 double a0, a1; 1881 struct arcData *data; 1882 miArcDataPtr arc; 1883 xArc xarc; 1884 int iphase, prevphase = 0, joinphase; 1885 int arcsJoin; 1886 int selfJoin; 1887 1888 int iDash = 0, dashRemaining; 1889 int iDashStart = 0, dashRemainingStart = 0, iphaseStart; 1890 int startAngle, spanAngle, endAngle, backwards = 0; 1891 int prevDashAngle, dashAngle; 1892 dashMap map; 1893 1894 isDashed = !(pGC->lineStyle == LineSolid); 1895 isDoubleDash = (pGC->lineStyle == LineDoubleDash); 1896 dashOffset = pGC->dashOffset; 1897 1898 data = (struct arcData *) xalloc (narcs * sizeof (struct arcData)); 1899 if (!data) 1900 return (miPolyArcPtr)NULL; 1901 arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1)); 1902 if (!arcs) 1903 { 1904 xfree(data); 1905 return (miPolyArcPtr)NULL; 1906 } 1907 for (i = 0; i < narcs; i++) { 1908 a0 = todeg (parcs[i].angle1); 1909 angle2 = parcs[i].angle2; 1910 if (angle2 > FULLCIRCLE) 1911 angle2 = FULLCIRCLE; 1912 else if (angle2 < -FULLCIRCLE) 1913 angle2 = -FULLCIRCLE; 1914 data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE; 1915 a1 = todeg (parcs[i].angle1 + angle2); 1916 data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0)); 1917 data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0)); 1918 data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1)); 1919 data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1)); 1920 } 1921 1922 for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) { 1923 arcs[iphase].njoins = 0; 1924 arcs[iphase].joins = 0; 1925 joinSize[iphase] = 0; 1926 1927 arcs[iphase].ncaps = 0; 1928 arcs[iphase].caps = 0; 1929 capSize[iphase] = 0; 1930 1931 arcs[iphase].narcs = 0; 1932 arcs[iphase].arcs = 0; 1933 arcSize[iphase] = 0; 1934 } 1935 1936 iphase = 0; 1937 if (isDashed) { 1938 iDash = 0; 1939 dashRemaining = pGC->dash[0]; 1940 while (dashOffset > 0) { 1941 if (dashOffset >= dashRemaining) { 1942 dashOffset -= dashRemaining; 1943 iphase = iphase ? 0 : 1; 1944 iDash++; 1945 if (iDash == pGC->numInDashList) 1946 iDash = 0; 1947 dashRemaining = pGC->dash[iDash]; 1948 } else { 1949 dashRemaining -= dashOffset; 1950 dashOffset = 0; 1951 } 1952 } 1953 iDashStart = iDash; 1954 dashRemainingStart = dashRemaining; 1955 } 1956 iphaseStart = iphase; 1957 1958 for (i = narcs - 1; i >= 0; i--) { 1959 j = i + 1; 1960 if (j == narcs) 1961 j = 0; 1962 if (data[i].selfJoin || i == j || 1963 (UNEQUAL (data[i].x1, data[j].x0) || 1964 UNEQUAL (data[i].y1, data[j].y0))) 1965 { 1966 if (iphase == 0 || isDoubleDash) 1967 addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, 1968 &capSize[iphase], RIGHT_END, 0); 1969 break; 1970 } 1971 } 1972 start = i + 1; 1973 if (start == narcs) 1974 start = 0; 1975 i = start; 1976 for (;;) { 1977 j = i + 1; 1978 if (j == narcs) 1979 j = 0; 1980 nexti = i+1; 1981 if (nexti == narcs) 1982 nexti = 0; 1983 if (isDashed) { 1984 /* 1985 ** deal with dashed arcs. Use special rules for certain 0 area arcs. 1986 ** Presumably, the other 0 area arcs still aren't done right. 1987 */ 1988 arcTypes arcType = OTHER; 1989 CARD16 thisLength; 1990 1991 if (parcs[i].height == 0 1992 && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00 1993 && parcs[i].angle2 == 0x2d00) 1994 arcType = HORIZONTAL; 1995 else if (parcs[i].width == 0 1996 && (parcs[i].angle1 % FULLCIRCLE) == 0x1680 1997 && parcs[i].angle2 == 0x2d00) 1998 arcType = VERTICAL; 1999 if (arcType == OTHER) { 2000 /* 2001 * precompute an approximation map 2002 */ 2003 computeDashMap (&parcs[i], &map); 2004 /* 2005 * compute each individual dash segment using the path 2006 * length function 2007 */ 2008 startAngle = parcs[i].angle1; 2009 spanAngle = parcs[i].angle2; 2010 if (spanAngle > FULLCIRCLE) 2011 spanAngle = FULLCIRCLE; 2012 else if (spanAngle < -FULLCIRCLE) 2013 spanAngle = -FULLCIRCLE; 2014 if (startAngle < 0) 2015 startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; 2016 if (startAngle >= FULLCIRCLE) 2017 startAngle = startAngle % FULLCIRCLE; 2018 endAngle = startAngle + spanAngle; 2019 backwards = spanAngle < 0; 2020 } else { 2021 xarc = parcs[i]; 2022 if (arcType == VERTICAL) { 2023 xarc.angle1 = 0x1680; 2024 startAngle = parcs[i].y; 2025 endAngle = startAngle + parcs[i].height; 2026 } else { 2027 xarc.angle1 = 0x2d00; 2028 startAngle = parcs[i].x; 2029 endAngle = startAngle + parcs[i].width; 2030 } 2031 } 2032 dashAngle = startAngle; 2033 selfJoin = data[i].selfJoin && 2034 (iphase == 0 || isDoubleDash); 2035 /* 2036 * add dashed arcs to each bucket 2037 */ 2038 arc = 0; 2039 while (dashAngle != endAngle) { 2040 prevDashAngle = dashAngle; 2041 if (arcType == OTHER) { 2042 dashAngle = computeAngleFromPath (prevDashAngle, endAngle, 2043 &map, &dashRemaining, backwards); 2044 /* avoid troubles with huge arcs and small dashes */ 2045 if (dashAngle == prevDashAngle) { 2046 if (backwards) 2047 dashAngle--; 2048 else 2049 dashAngle++; 2050 } 2051 } else { 2052 thisLength = (dashAngle + dashRemaining <= endAngle) ? 2053 dashRemaining : endAngle - dashAngle; 2054 if (arcType == VERTICAL) { 2055 xarc.y = dashAngle; 2056 xarc.height = thisLength; 2057 } else { 2058 xarc.x = dashAngle; 2059 xarc.width = thisLength; 2060 } 2061 dashAngle += thisLength; 2062 dashRemaining -= thisLength; 2063 } 2064 if (iphase == 0 || isDoubleDash) { 2065 if (arcType == OTHER) { 2066 xarc = parcs[i]; 2067 spanAngle = prevDashAngle; 2068 if (spanAngle < 0) 2069 spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE; 2070 if (spanAngle >= FULLCIRCLE) 2071 spanAngle = spanAngle % FULLCIRCLE; 2072 xarc.angle1 = spanAngle; 2073 spanAngle = dashAngle - prevDashAngle; 2074 if (backwards) { 2075 if (dashAngle > prevDashAngle) 2076 spanAngle = - FULLCIRCLE + spanAngle; 2077 } else { 2078 if (dashAngle < prevDashAngle) 2079 spanAngle = FULLCIRCLE + spanAngle; 2080 } 2081 if (spanAngle > FULLCIRCLE) 2082 spanAngle = FULLCIRCLE; 2083 if (spanAngle < -FULLCIRCLE) 2084 spanAngle = -FULLCIRCLE; 2085 xarc.angle2 = spanAngle; 2086 } 2087 arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, 2088 &arcSize[iphase], &xarc); 2089 if (!arc) 2090 goto arcfail; 2091 /* 2092 * cap each end of an on/off dash 2093 */ 2094 if (!isDoubleDash) { 2095 if (prevDashAngle != startAngle) { 2096 addCap (&arcs[iphase].caps, 2097 &arcs[iphase].ncaps, 2098 &capSize[iphase], RIGHT_END, 2099 arc - arcs[iphase].arcs); 2100 2101 } 2102 if (dashAngle != endAngle) { 2103 addCap (&arcs[iphase].caps, 2104 &arcs[iphase].ncaps, 2105 &capSize[iphase], LEFT_END, 2106 arc - arcs[iphase].arcs); 2107 } 2108 } 2109 arc->cap = arcs[iphase].ncaps; 2110 arc->join = arcs[iphase].njoins; 2111 arc->render = 0; 2112 arc->selfJoin = 0; 2113 if (dashAngle == endAngle) 2114 arc->selfJoin = selfJoin; 2115 } 2116 prevphase = iphase; 2117 if (dashRemaining <= 0) { 2118 ++iDash; 2119 if (iDash == pGC->numInDashList) 2120 iDash = 0; 2121 iphase = iphase ? 0:1; 2122 dashRemaining = pGC->dash[iDash]; 2123 } 2124 } 2125 /* 2126 * make sure a place exists for the position data when 2127 * drawing a zero-length arc 2128 */ 2129 if (startAngle == endAngle) { 2130 prevphase = iphase; 2131 if (!isDoubleDash && iphase == 1) 2132 prevphase = 0; 2133 arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs, 2134 &arcSize[prevphase], &parcs[i]); 2135 if (!arc) 2136 goto arcfail; 2137 arc->join = arcs[prevphase].njoins; 2138 arc->cap = arcs[prevphase].ncaps; 2139 arc->selfJoin = data[i].selfJoin; 2140 } 2141 } else { 2142 arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, 2143 &arcSize[iphase], &parcs[i]); 2144 if (!arc) 2145 goto arcfail; 2146 arc->join = arcs[iphase].njoins; 2147 arc->cap = arcs[iphase].ncaps; 2148 arc->selfJoin = data[i].selfJoin; 2149 prevphase = iphase; 2150 } 2151 if (prevphase == 0 || isDoubleDash) 2152 k = arcs[prevphase].narcs - 1; 2153 if (iphase == 0 || isDoubleDash) 2154 nextk = arcs[iphase].narcs; 2155 if (nexti == start) { 2156 nextk = 0; 2157 if (isDashed) { 2158 iDash = iDashStart; 2159 iphase = iphaseStart; 2160 dashRemaining = dashRemainingStart; 2161 } 2162 } 2163 arcsJoin = narcs > 1 && i != j && 2164 ISEQUAL (data[i].x1, data[j].x0) && 2165 ISEQUAL (data[i].y1, data[j].y0) && 2166 !data[i].selfJoin && !data[j].selfJoin; 2167 if (arc) 2168 { 2169 if (arcsJoin) 2170 arc->render = 0; 2171 else 2172 arc->render = 1; 2173 } 2174 if (arcsJoin && 2175 (prevphase == 0 || isDoubleDash) && 2176 (iphase == 0 || isDoubleDash)) 2177 { 2178 joinphase = iphase; 2179 if (isDoubleDash) { 2180 if (nexti == start) 2181 joinphase = iphaseStart; 2182 /* 2183 * if the join is right at the dash, 2184 * draw the join in foreground 2185 * This is because the foreground 2186 * arcs are computed second, the results 2187 * of which are needed to draw the join 2188 */ 2189 if (joinphase != prevphase) 2190 joinphase = 0; 2191 } 2192 if (joinphase == 0 || isDoubleDash) { 2193 addJoin (&arcs[joinphase].joins, 2194 &arcs[joinphase].njoins, 2195 &joinSize[joinphase], 2196 LEFT_END, k, prevphase, 2197 RIGHT_END, nextk, iphase); 2198 arc->join = arcs[prevphase].njoins; 2199 } 2200 } else { 2201 /* 2202 * cap the left end of this arc 2203 * unless it joins itself 2204 */ 2205 if ((prevphase == 0 || isDoubleDash) && 2206 !arc->selfJoin) 2207 { 2208 addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps, 2209 &capSize[prevphase], LEFT_END, k); 2210 arc->cap = arcs[prevphase].ncaps; 2211 } 2212 if (isDashed && !arcsJoin) { 2213 iDash = iDashStart; 2214 iphase = iphaseStart; 2215 dashRemaining = dashRemainingStart; 2216 } 2217 nextk = arcs[iphase].narcs; 2218 if (nexti == start) { 2219 nextk = 0; 2220 iDash = iDashStart; 2221 iphase = iphaseStart; 2222 dashRemaining = dashRemainingStart; 2223 } 2224 /* 2225 * cap the right end of the next arc. If the 2226 * next arc is actually the first arc, only 2227 * cap it if it joins with this arc. This 2228 * case will occur when the final dash segment 2229 * of an on/off dash is off. Of course, this 2230 * cap will be drawn at a strange time, but that 2231 * hardly matters... 2232 */ 2233 if ((iphase == 0 || isDoubleDash) && 2234 (nexti != start || (arcsJoin && isDashed))) 2235 addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, 2236 &capSize[iphase], RIGHT_END, nextk); 2237 } 2238 i = nexti; 2239 if (i == start) 2240 break; 2241 } 2242 /* 2243 * make sure the last section is rendered 2244 */ 2245 for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) 2246 if (arcs[iphase].narcs > 0) { 2247 arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1; 2248 arcs[iphase].arcs[arcs[iphase].narcs-1].join = 2249 arcs[iphase].njoins; 2250 arcs[iphase].arcs[arcs[iphase].narcs-1].cap = 2251 arcs[iphase].ncaps; 2252 } 2253 xfree(data); 2254 return arcs; 2255arcfail: 2256 miFreeArcs(arcs, pGC); 2257 xfree(data); 2258 return (miPolyArcPtr)NULL; 2259} 2260 2261static double 2262angleToLength ( 2263 int angle, 2264 dashMap *map) 2265{ 2266 double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen; 2267 int di; 2268 int excess; 2269 Bool oddSide = FALSE; 2270 2271 totallen = 0; 2272 if (angle >= 0) { 2273 while (angle >= 90 * 64) { 2274 angle -= 90 * 64; 2275 totallen += sidelen; 2276 oddSide = !oddSide; 2277 } 2278 } else { 2279 while (angle < 0) { 2280 angle += 90 * 64; 2281 totallen -= sidelen; 2282 oddSide = !oddSide; 2283 } 2284 } 2285 if (oddSide) 2286 angle = 90 * 64 - angle; 2287 2288 di = xAngleToDashIndex (angle); 2289 excess = angle - dashIndexToXAngle (di); 2290 2291 len = map->map[di]; 2292 /* 2293 * linearly interpolate between this point and the next 2294 */ 2295 if (excess > 0) { 2296 excesslen = (map->map[di + 1] - map->map[di]) * 2297 ((double) excess) / dashXAngleStep; 2298 len += excesslen; 2299 } 2300 if (oddSide) 2301 totallen += (sidelen - len); 2302 else 2303 totallen += len; 2304 return totallen; 2305} 2306 2307/* 2308 * len is along the arc, but may be more than one rotation 2309 */ 2310 2311static int 2312lengthToAngle ( 2313 double len, 2314 dashMap *map) 2315{ 2316 double sidelen = map->map[DASH_MAP_SIZE - 1]; 2317 int angle, angleexcess; 2318 Bool oddSide = FALSE; 2319 int a0, a1, a; 2320 2321 angle = 0; 2322 /* 2323 * step around the ellipse, subtracting sidelens and 2324 * adding 90 degrees. oddSide will tell if the 2325 * map should be interpolated in reverse 2326 */ 2327 if (len >= 0) { 2328 if (sidelen == 0) 2329 return 2 * FULLCIRCLE; /* infinity */ 2330 while (len >= sidelen) { 2331 angle += 90 * 64; 2332 len -= sidelen; 2333 oddSide = !oddSide; 2334 } 2335 } else { 2336 if (sidelen == 0) 2337 return -2 * FULLCIRCLE; /* infinity */ 2338 while (len < 0) { 2339 angle -= 90 * 64; 2340 len += sidelen; 2341 oddSide = !oddSide; 2342 } 2343 } 2344 if (oddSide) 2345 len = sidelen - len; 2346 a0 = 0; 2347 a1 = DASH_MAP_SIZE - 1; 2348 /* 2349 * binary search for the closest pre-computed length 2350 */ 2351 while (a1 - a0 > 1) { 2352 a = (a0 + a1) / 2; 2353 if (len > map->map[a]) 2354 a0 = a; 2355 else 2356 a1 = a; 2357 } 2358 angleexcess = dashIndexToXAngle (a0); 2359 /* 2360 * linearly interpolate to the next point 2361 */ 2362 angleexcess += (len - map->map[a0]) / 2363 (map->map[a0+1] - map->map[a0]) * dashXAngleStep; 2364 if (oddSide) 2365 angle += (90 * 64) - angleexcess; 2366 else 2367 angle += angleexcess; 2368 return angle; 2369} 2370 2371/* 2372 * compute the angle of an ellipse which cooresponds to 2373 * the given path length. Note that the correct solution 2374 * to this problem is an eliptic integral, we'll punt and 2375 * approximate (it's only for dashes anyway). This 2376 * approximation uses a polygon. 2377 * 2378 * The remaining portion of len is stored in *lenp - 2379 * this will be negative if the arc extends beyond 2380 * len and positive if len extends beyond the arc. 2381 */ 2382 2383static int 2384computeAngleFromPath ( 2385 int startAngle, 2386 int endAngle, /* normalized absolute angles in *64 degrees */ 2387 dashMap *map, 2388 int *lenp, 2389 int backwards) 2390{ 2391 int a0, a1, a; 2392 double len0; 2393 int len; 2394 2395 a0 = startAngle; 2396 a1 = endAngle; 2397 len = *lenp; 2398 if (backwards) { 2399 /* 2400 * flip the problem around to always be 2401 * forwards 2402 */ 2403 a0 = FULLCIRCLE - a0; 2404 a1 = FULLCIRCLE - a1; 2405 } 2406 if (a1 < a0) 2407 a1 += FULLCIRCLE; 2408 len0 = angleToLength (a0, map); 2409 a = lengthToAngle (len0 + len, map); 2410 if (a > a1) { 2411 a = a1; 2412 len -= angleToLength (a1, map) - len0; 2413 } else 2414 len = 0; 2415 if (backwards) 2416 a = FULLCIRCLE - a; 2417 *lenp = len; 2418 return a; 2419} 2420 2421/* 2422 * scan convert wide arcs. 2423 */ 2424 2425/* 2426 * draw zero width/height arcs 2427 */ 2428 2429static void 2430drawZeroArc ( 2431 DrawablePtr pDraw, 2432 GCPtr pGC, 2433 xArc *tarc, 2434 int lw, 2435 miArcFacePtr left, 2436 miArcFacePtr right) 2437{ 2438 double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y; 2439 double xmax, ymax, xmin, ymin; 2440 int a0, a1; 2441 double a, startAngle, endAngle; 2442 double l, lx, ly; 2443 2444 l = lw / 2.0; 2445 a0 = tarc->angle1; 2446 a1 = tarc->angle2; 2447 if (a1 > FULLCIRCLE) 2448 a1 = FULLCIRCLE; 2449 else if (a1 < -FULLCIRCLE) 2450 a1 = -FULLCIRCLE; 2451 w = (double)tarc->width / 2.0; 2452 h = (double)tarc->height / 2.0; 2453 /* 2454 * play in X coordinates right away 2455 */ 2456 startAngle = - ((double) a0 / 64.0); 2457 endAngle = - ((double) (a0 + a1) / 64.0); 2458 2459 xmax = -w; 2460 xmin = w; 2461 ymax = -h; 2462 ymin = h; 2463 a = startAngle; 2464 for (;;) 2465 { 2466 x = w * miDcos(a); 2467 y = h * miDsin(a); 2468 if (a == startAngle) 2469 { 2470 x0 = x; 2471 y0 = y; 2472 } 2473 if (a == endAngle) 2474 { 2475 x1 = x; 2476 y1 = y; 2477 } 2478 if (x > xmax) 2479 xmax = x; 2480 if (x < xmin) 2481 xmin = x; 2482 if (y > ymax) 2483 ymax = y; 2484 if (y < ymin) 2485 ymin = y; 2486 if (a == endAngle) 2487 break; 2488 if (a1 < 0) /* clockwise */ 2489 { 2490 if (floor (a / 90.0) == floor (endAngle / 90.0)) 2491 a = endAngle; 2492 else 2493 a = 90 * (floor (a/90.0) + 1); 2494 } 2495 else 2496 { 2497 if (ceil (a / 90.0) == ceil (endAngle / 90.0)) 2498 a = endAngle; 2499 else 2500 a = 90 * (ceil (a/90.0) - 1); 2501 } 2502 } 2503 lx = ly = l; 2504 if ((x1 - x0) + (y1 - y0) < 0) 2505 lx = ly = -l; 2506 if (h) 2507 { 2508 ly = 0.0; 2509 lx = -lx; 2510 } 2511 else 2512 lx = 0.0; 2513 if (right) 2514 { 2515 right->center.x = x0; 2516 right->center.y = y0; 2517 right->clock.x = x0 - lx; 2518 right->clock.y = y0 - ly; 2519 right->counterClock.x = x0 + lx; 2520 right->counterClock.y = y0 + ly; 2521 } 2522 if (left) 2523 { 2524 left->center.x = x1; 2525 left->center.y = y1; 2526 left->clock.x = x1 + lx; 2527 left->clock.y = y1 + ly; 2528 left->counterClock.x = x1 - lx; 2529 left->counterClock.y = y1 - ly; 2530 } 2531 2532 x0 = xmin; 2533 x1 = xmax; 2534 y0 = ymin; 2535 y1 = ymax; 2536 if (ymin != y1) { 2537 xmin = -l; 2538 xmax = l; 2539 } else { 2540 ymin = -l; 2541 ymax = l; 2542 } 2543 if (xmax != xmin && ymax != ymin) { 2544 int minx, maxx, miny, maxy; 2545 xRectangle rect; 2546 2547 minx = ICEIL (xmin + w) + tarc->x; 2548 maxx = ICEIL (xmax + w) + tarc->x; 2549 miny = ICEIL (ymin + h) + tarc->y; 2550 maxy = ICEIL (ymax + h) + tarc->y; 2551 rect.x = minx; 2552 rect.y = miny; 2553 rect.width = maxx - minx; 2554 rect.height = maxy - miny; 2555 (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); 2556 } 2557} 2558 2559/* 2560 * this computes the ellipse y value associated with the 2561 * bottom of the tail. 2562 */ 2563 2564static void 2565tailEllipseY ( 2566 struct arc_def *def, 2567 struct accelerators *acc) 2568{ 2569 double t; 2570 2571 acc->tail_y = 0.0; 2572 if (def->w == def->h) 2573 return; 2574 t = def->l * def->w; 2575 if (def->w > def->h) { 2576 if (t < acc->h2) 2577 return; 2578 } else { 2579 if (t > acc->h2) 2580 return; 2581 } 2582 t = 2.0 * def->h * t; 2583 t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2; 2584 if (t > 0.0) 2585 acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t); 2586} 2587 2588/* 2589 * inverse functions -- compute edge coordinates 2590 * from the ellipse 2591 */ 2592 2593static double 2594outerXfromXY ( 2595 double x, 2596 double y, 2597 struct arc_def *def, 2598 struct accelerators *acc) 2599{ 2600 return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2601} 2602 2603static double 2604outerYfromXY ( 2605 double x, 2606 double y, 2607 struct arc_def *def, 2608 struct accelerators *acc) 2609{ 2610 return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2611} 2612 2613static double 2614innerXfromXY ( 2615 double x, 2616 double y, 2617 struct arc_def *def, 2618 struct accelerators *acc) 2619{ 2620 return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2621} 2622 2623static double 2624innerYfromXY ( 2625 double x, 2626 double y, 2627 struct arc_def *def, 2628 struct accelerators *acc) 2629{ 2630 return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2631} 2632 2633static double 2634innerYfromY ( 2635 double y, 2636 struct arc_def *def, 2637 struct accelerators *acc) 2638{ 2639 double x; 2640 2641 x = (def->w / def->h) * sqrt (acc->h2 - y*y); 2642 2643 return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2644} 2645 2646static void 2647computeLine ( 2648 double x1, 2649 double y1, 2650 double x2, 2651 double y2, 2652 struct line *line) 2653{ 2654 if (y1 == y2) 2655 line->valid = 0; 2656 else { 2657 line->m = (x1 - x2) / (y1 - y2); 2658 line->b = x1 - y1 * line->m; 2659 line->valid = 1; 2660 } 2661} 2662 2663/* 2664 * compute various accelerators for an ellipse. These 2665 * are simply values that are used repeatedly in 2666 * the computations 2667 */ 2668 2669static void 2670computeAcc ( 2671 xArc *tarc, 2672 int lw, 2673 struct arc_def *def, 2674 struct accelerators *acc) 2675{ 2676 def->w = ((double) tarc->width) / 2.0; 2677 def->h = ((double) tarc->height) / 2.0; 2678 def->l = ((double) lw) / 2.0; 2679 acc->h2 = def->h * def->h; 2680 acc->w2 = def->w * def->w; 2681 acc->h4 = acc->h2 * acc->h2; 2682 acc->w4 = acc->w2 * acc->w2; 2683 acc->h2l = acc->h2 * def->l; 2684 acc->w2l = acc->w2 * def->l; 2685 acc->h2mw2 = acc->h2 - acc->w2; 2686 acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0; 2687 acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0; 2688 acc->xorg = tarc->x + (tarc->width >> 1); 2689 acc->yorgu = tarc->y + (tarc->height >> 1); 2690 acc->yorgl = acc->yorgu + (tarc->height & 1); 2691 tailEllipseY (def, acc); 2692} 2693 2694/* 2695 * compute y value bounds of various portions of the arc, 2696 * the outer edge, the ellipse and the inner edge. 2697 */ 2698 2699static void 2700computeBound ( 2701 struct arc_def *def, 2702 struct arc_bound *bound, 2703 struct accelerators *acc, 2704 miArcFacePtr right, 2705 miArcFacePtr left) 2706{ 2707 double t; 2708 double innerTaily; 2709 double tail_y; 2710 struct bound innerx, outerx; 2711 struct bound ellipsex; 2712 2713 bound->ellipse.min = Dsin (def->a0) * def->h; 2714 bound->ellipse.max = Dsin (def->a1) * def->h; 2715 if (def->a0 == 45 && def->w == def->h) 2716 ellipsex.min = bound->ellipse.min; 2717 else 2718 ellipsex.min = Dcos (def->a0) * def->w; 2719 if (def->a1 == 45 && def->w == def->h) 2720 ellipsex.max = bound->ellipse.max; 2721 else 2722 ellipsex.max = Dcos (def->a1) * def->w; 2723 bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2724 bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2725 bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2726 bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2727 2728 outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2729 outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2730 innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2731 innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2732 2733 /* 2734 * save the line end points for the 2735 * cap code to use. Careful here, these are 2736 * in cartesean coordinates (y increasing upwards) 2737 * while the cap code uses inverted coordinates 2738 * (y increasing downwards) 2739 */ 2740 2741 if (right) { 2742 right->counterClock.y = bound->outer.min; 2743 right->counterClock.x = outerx.min; 2744 right->center.y = bound->ellipse.min; 2745 right->center.x = ellipsex.min; 2746 right->clock.y = bound->inner.min; 2747 right->clock.x = innerx.min; 2748 } 2749 2750 if (left) { 2751 left->clock.y = bound->outer.max; 2752 left->clock.x = outerx.max; 2753 left->center.y = bound->ellipse.max; 2754 left->center.x = ellipsex.max; 2755 left->counterClock.y = bound->inner.max; 2756 left->counterClock.x = innerx.max; 2757 } 2758 2759 bound->left.min = bound->inner.max; 2760 bound->left.max = bound->outer.max; 2761 bound->right.min = bound->inner.min; 2762 bound->right.max = bound->outer.min; 2763 2764 computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min, 2765 &acc->right); 2766 computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max, 2767 &acc->left); 2768 2769 if (bound->inner.min > bound->inner.max) { 2770 t = bound->inner.min; 2771 bound->inner.min = bound->inner.max; 2772 bound->inner.max = t; 2773 } 2774 tail_y = acc->tail_y; 2775 if (tail_y > bound->ellipse.max) 2776 tail_y = bound->ellipse.max; 2777 else if (tail_y < bound->ellipse.min) 2778 tail_y = bound->ellipse.min; 2779 innerTaily = innerYfromY (tail_y, def, acc); 2780 if (bound->inner.min > innerTaily) 2781 bound->inner.min = innerTaily; 2782 if (bound->inner.max < innerTaily) 2783 bound->inner.max = innerTaily; 2784 bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY); 2785 bound->inneri.max = floor(bound->inner.max - acc->fromIntY); 2786 bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY); 2787 bound->outeri.max = floor(bound->outer.max - acc->fromIntY); 2788} 2789 2790/* 2791 * this section computes the x value of the span at y 2792 * intersected with the specified face of the ellipse. 2793 * 2794 * this is the min/max X value over the set of normal 2795 * lines to the entire ellipse, the equation of the 2796 * normal lines is: 2797 * 2798 * ellipse_x h^2 h^2 2799 * x = ------------ y + ellipse_x (1 - --- ) 2800 * ellipse_y w^2 w^2 2801 * 2802 * compute the derivative with-respect-to ellipse_y and solve 2803 * for zero: 2804 * 2805 * (w^2 - h^2) ellipse_y^3 + h^4 y 2806 * 0 = - ---------------------------------- 2807 * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2) 2808 * 2809 * ( h^4 y ) 2810 * ellipse_y = ( ---------- ) ^ (1/3) 2811 * ( (h^2 - w^2) ) 2812 * 2813 * The other two solutions to the equation are imaginary. 2814 * 2815 * This gives the position on the ellipse which generates 2816 * the normal with the largest/smallest x intersection point. 2817 * 2818 * Now compute the second derivative to check whether 2819 * the intersection is a minimum or maximum: 2820 * 2821 * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) 2822 * - ------------------------------------------- 2823 * w y0^3 (sqrt (h^2 - y^2)) ^ 3 2824 * 2825 * as we only care about the sign, 2826 * 2827 * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) 2828 * 2829 * or (to use accelerators), 2830 * 2831 * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) 2832 * 2833 */ 2834 2835/* 2836 * computes the position on the ellipse whose normal line 2837 * intersects the given scan line maximally 2838 */ 2839 2840static double 2841hookEllipseY ( 2842 double scan_y, 2843 struct arc_bound *bound, 2844 struct accelerators *acc, 2845 int left) 2846{ 2847 double ret; 2848 2849 if (acc->h2mw2 == 0) { 2850 if ( (scan_y > 0 && !left) || (scan_y < 0 && left) ) 2851 return bound->ellipse.min; 2852 return bound->ellipse.max; 2853 } 2854 ret = (acc->h4 * scan_y) / (acc->h2mw2); 2855 if (ret >= 0) 2856 return cbrt (ret); 2857 else 2858 return -cbrt (-ret); 2859} 2860 2861/* 2862 * computes the X value of the intersection of the 2863 * given scan line with the right side of the lower hook 2864 */ 2865 2866static double 2867hookX ( 2868 double scan_y, 2869 struct arc_def *def, 2870 struct arc_bound *bound, 2871 struct accelerators *acc, 2872 int left) 2873{ 2874 double ellipse_y, x; 2875 double maxMin; 2876 2877 if (def->w != def->h) { 2878 ellipse_y = hookEllipseY (scan_y, bound, acc, left); 2879 if (boundedLe (ellipse_y, bound->ellipse)) { 2880 /* 2881 * compute the value of the second 2882 * derivative 2883 */ 2884 maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 - 2885 acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2); 2886 if ((left && maxMin > 0) || (!left && maxMin < 0)) { 2887 if (ellipse_y == 0) 2888 return def->w + left ? -def->l : def->l; 2889 x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) * 2890 sqrt (acc->h2 - ellipse_y * ellipse_y) / 2891 (def->h * def->w * ellipse_y); 2892 return x; 2893 } 2894 } 2895 } 2896 if (left) { 2897 if (acc->left.valid && boundedLe (scan_y, bound->left)) { 2898 x = intersectLine (scan_y, acc->left); 2899 } else { 2900 if (acc->right.valid) 2901 x = intersectLine (scan_y, acc->right); 2902 else 2903 x = def->w - def->l; 2904 } 2905 } else { 2906 if (acc->right.valid && boundedLe (scan_y, bound->right)) { 2907 x = intersectLine (scan_y, acc->right); 2908 } else { 2909 if (acc->left.valid) 2910 x = intersectLine (scan_y, acc->left); 2911 else 2912 x = def->w - def->l; 2913 } 2914 } 2915 return x; 2916} 2917 2918/* 2919 * generate the set of spans with 2920 * the given y coordinate 2921 */ 2922 2923static void 2924arcSpan ( 2925 int y, 2926 int lx, 2927 int lw, 2928 int rx, 2929 int rw, 2930 struct arc_def *def, 2931 struct arc_bound *bounds, 2932 struct accelerators *acc, 2933 int mask) 2934{ 2935 int linx, loutx, rinx, routx; 2936 double x, altx; 2937 2938 if (boundedLe (y, bounds->inneri)) { 2939 linx = -(lx + lw); 2940 rinx = rx; 2941 } else { 2942 /* 2943 * intersection with left face 2944 */ 2945 x = hookX (y + acc->fromIntY, def, bounds, acc, 1); 2946 if (acc->right.valid && 2947 boundedLe (y + acc->fromIntY, bounds->right)) 2948 { 2949 altx = intersectLine (y + acc->fromIntY, acc->right); 2950 if (altx < x) 2951 x = altx; 2952 } 2953 linx = -ICEIL(acc->fromIntX - x); 2954 rinx = ICEIL(acc->fromIntX + x); 2955 } 2956 if (boundedLe (y, bounds->outeri)) { 2957 loutx = -lx; 2958 routx = rx + rw; 2959 } else { 2960 /* 2961 * intersection with right face 2962 */ 2963 x = hookX (y + acc->fromIntY, def, bounds, acc, 0); 2964 if (acc->left.valid && 2965 boundedLe (y + acc->fromIntY, bounds->left)) 2966 { 2967 altx = x; 2968 x = intersectLine (y + acc->fromIntY, acc->left); 2969 if (x < altx) 2970 x = altx; 2971 } 2972 loutx = -ICEIL(acc->fromIntX - x); 2973 routx = ICEIL(acc->fromIntX + x); 2974 } 2975 if (routx > rinx) { 2976 if (mask & 1) 2977 newFinalSpan (acc->yorgu - y, 2978 acc->xorg + rinx, acc->xorg + routx); 2979 if (mask & 8) 2980 newFinalSpan (acc->yorgl + y, 2981 acc->xorg + rinx, acc->xorg + routx); 2982 } 2983 if (loutx > linx) { 2984 if (mask & 2) 2985 newFinalSpan (acc->yorgu - y, 2986 acc->xorg - loutx, acc->xorg - linx); 2987 if (mask & 4) 2988 newFinalSpan (acc->yorgl + y, 2989 acc->xorg - loutx, acc->xorg - linx); 2990 } 2991} 2992 2993static void 2994arcSpan0 ( 2995 int lx, 2996 int lw, 2997 int rx, 2998 int rw, 2999 struct arc_def *def, 3000 struct arc_bound *bounds, 3001 struct accelerators *acc, 3002 int mask) 3003{ 3004 double x; 3005 3006 if (boundedLe (0, bounds->inneri) && 3007 acc->left.valid && boundedLe (0, bounds->left) && 3008 acc->left.b > 0) 3009 { 3010 x = def->w - def->l; 3011 if (acc->left.b < x) 3012 x = acc->left.b; 3013 lw = ICEIL(acc->fromIntX - x) - lx; 3014 rw += rx; 3015 rx = ICEIL(acc->fromIntX + x); 3016 rw -= rx; 3017 } 3018 arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask); 3019} 3020 3021static void 3022tailSpan ( 3023 int y, 3024 int lw, 3025 int rw, 3026 struct arc_def *def, 3027 struct arc_bound *bounds, 3028 struct accelerators *acc, 3029 int mask) 3030{ 3031 double yy, xalt, x, lx, rx; 3032 int n; 3033 3034 if (boundedLe(y, bounds->outeri)) 3035 arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask); 3036 else if (def->w != def->h) { 3037 yy = y + acc->fromIntY; 3038 x = tailX(yy, def, bounds, acc); 3039 if (yy == 0.0 && x == -rw - acc->fromIntX) 3040 return; 3041 if (acc->right.valid && boundedLe (yy, bounds->right)) { 3042 rx = x; 3043 lx = -x; 3044 xalt = intersectLine (yy, acc->right); 3045 if (xalt >= -rw - acc->fromIntX && xalt <= rx) 3046 rx = xalt; 3047 n = ICEIL(acc->fromIntX + lx); 3048 if (lw > n) { 3049 if (mask & 2) 3050 newFinalSpan (acc->yorgu - y, 3051 acc->xorg + n, acc->xorg + lw); 3052 if (mask & 4) 3053 newFinalSpan (acc->yorgl + y, 3054 acc->xorg + n, acc->xorg + lw); 3055 } 3056 n = ICEIL(acc->fromIntX + rx); 3057 if (n > -rw) { 3058 if (mask & 1) 3059 newFinalSpan (acc->yorgu - y, 3060 acc->xorg - rw, acc->xorg + n); 3061 if (mask & 8) 3062 newFinalSpan (acc->yorgl + y, 3063 acc->xorg - rw, acc->xorg + n); 3064 } 3065 } 3066 arcSpan (y, 3067 ICEIL(acc->fromIntX - x), 0, 3068 ICEIL(acc->fromIntX + x), 0, 3069 def, bounds, acc, mask); 3070 } 3071} 3072 3073/* 3074 * create whole arcs out of pieces. This code is 3075 * very bad. 3076 */ 3077 3078static struct finalSpan **finalSpans = NULL; 3079static int finalMiny = 0, finalMaxy = -1; 3080static int finalSize = 0; 3081 3082static int nspans = 0; /* total spans, not just y coords */ 3083 3084struct finalSpan { 3085 struct finalSpan *next; 3086 int min, max; /* x values */ 3087}; 3088 3089static struct finalSpan *freeFinalSpans, *tmpFinalSpan; 3090 3091# define allocFinalSpan() (freeFinalSpans ?\ 3092 ((tmpFinalSpan = freeFinalSpans), \ 3093 (freeFinalSpans = freeFinalSpans->next), \ 3094 (tmpFinalSpan->next = 0), \ 3095 tmpFinalSpan) : \ 3096 realAllocSpan ()) 3097 3098# define SPAN_CHUNK_SIZE 128 3099 3100struct finalSpanChunk { 3101 struct finalSpan data[SPAN_CHUNK_SIZE]; 3102 struct finalSpanChunk *next; 3103}; 3104 3105static struct finalSpanChunk *chunks; 3106 3107static struct finalSpan * 3108realAllocSpan (void) 3109{ 3110 struct finalSpanChunk *newChunk; 3111 struct finalSpan *span; 3112 int i; 3113 3114 newChunk = (struct finalSpanChunk *) xalloc (sizeof (struct finalSpanChunk)); 3115 if (!newChunk) 3116 return (struct finalSpan *) NULL; 3117 newChunk->next = chunks; 3118 chunks = newChunk; 3119 freeFinalSpans = span = newChunk->data + 1; 3120 for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) { 3121 span->next = span+1; 3122 span++; 3123 } 3124 span->next = 0; 3125 span = newChunk->data; 3126 span->next = 0; 3127 return span; 3128} 3129 3130static void 3131disposeFinalSpans (void) 3132{ 3133 struct finalSpanChunk *chunk, *next; 3134 3135 for (chunk = chunks; chunk; chunk = next) { 3136 next = chunk->next; 3137 xfree (chunk); 3138 } 3139 chunks = 0; 3140 freeFinalSpans = 0; 3141 xfree(finalSpans); 3142 finalSpans = 0; 3143} 3144 3145static void 3146fillSpans ( 3147 DrawablePtr pDrawable, 3148 GCPtr pGC) 3149{ 3150 struct finalSpan *span; 3151 DDXPointPtr xSpan; 3152 int *xWidth; 3153 int i; 3154 struct finalSpan **f; 3155 int spany; 3156 DDXPointPtr xSpans; 3157 int *xWidths; 3158 3159 if (nspans == 0) 3160 return; 3161 xSpan = xSpans = (DDXPointPtr) xalloc (nspans * sizeof (DDXPointRec)); 3162 xWidth = xWidths = (int *) xalloc (nspans * sizeof (int)); 3163 if (xSpans && xWidths) 3164 { 3165 i = 0; 3166 f = finalSpans; 3167 for (spany = finalMiny; spany <= finalMaxy; spany++, f++) { 3168 for (span = *f; span; span=span->next) { 3169 if (span->max <= span->min) 3170 continue; 3171 xSpan->x = span->min; 3172 xSpan->y = spany; 3173 ++xSpan; 3174 *xWidth++ = span->max - span->min; 3175 ++i; 3176 } 3177 } 3178 (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE); 3179 } 3180 disposeFinalSpans (); 3181 if (xSpans) 3182 xfree (xSpans); 3183 if (xWidths) 3184 xfree (xWidths); 3185 finalMiny = 0; 3186 finalMaxy = -1; 3187 finalSize = 0; 3188 nspans = 0; 3189} 3190 3191# define SPAN_REALLOC 100 3192 3193# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \ 3194 &finalSpans[(y) - finalMiny] : \ 3195 realFindSpan (y)) 3196 3197static struct finalSpan ** 3198realFindSpan (int y) 3199{ 3200 struct finalSpan **newSpans; 3201 int newSize, newMiny, newMaxy; 3202 int change; 3203 int i; 3204 3205 if (y < finalMiny || y > finalMaxy) { 3206 if (!finalSize) { 3207 finalMiny = y; 3208 finalMaxy = y - 1; 3209 } 3210 if (y < finalMiny) 3211 change = finalMiny - y; 3212 else 3213 change = y - finalMaxy; 3214 if (change >= SPAN_REALLOC) 3215 change += SPAN_REALLOC; 3216 else 3217 change = SPAN_REALLOC; 3218 newSize = finalSize + change; 3219 newSpans = (struct finalSpan **) xalloc 3220 (newSize * sizeof (struct finalSpan *)); 3221 if (!newSpans) 3222 return (struct finalSpan **)NULL; 3223 newMiny = finalMiny; 3224 newMaxy = finalMaxy; 3225 if (y < finalMiny) 3226 newMiny = finalMiny - change; 3227 else 3228 newMaxy = finalMaxy + change; 3229 if (finalSpans) { 3230 memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *), 3231 (char *) finalSpans, 3232 finalSize * sizeof (struct finalSpan *)); 3233 xfree (finalSpans); 3234 } 3235 if ((i = finalMiny - newMiny) > 0) 3236 bzero ((char *)newSpans, i * sizeof (struct finalSpan *)); 3237 if ((i = newMaxy - finalMaxy) > 0) 3238 bzero ((char *)(newSpans + newSize - i), 3239 i * sizeof (struct finalSpan *)); 3240 finalSpans = newSpans; 3241 finalMaxy = newMaxy; 3242 finalMiny = newMiny; 3243 finalSize = newSize; 3244 } 3245 return &finalSpans[y - finalMiny]; 3246} 3247 3248static void 3249newFinalSpan ( 3250 int y, 3251 int xmin, 3252 int xmax) 3253{ 3254 struct finalSpan *x; 3255 struct finalSpan **f; 3256 struct finalSpan *oldx; 3257 struct finalSpan *prev; 3258 3259 f = findSpan (y); 3260 if (!f) 3261 return; 3262 oldx = 0; 3263 for (;;) { 3264 prev = 0; 3265 for (x = *f; x; x=x->next) { 3266 if (x == oldx) { 3267 prev = x; 3268 continue; 3269 } 3270 if (x->min <= xmax && xmin <= x->max) { 3271 if (oldx) { 3272 oldx->min = min (x->min, xmin); 3273 oldx->max = max (x->max, xmax); 3274 if (prev) 3275 prev->next = x->next; 3276 else 3277 *f = x->next; 3278 --nspans; 3279 } else { 3280 x->min = min (x->min, xmin); 3281 x->max = max (x->max, xmax); 3282 oldx = x; 3283 } 3284 xmin = oldx->min; 3285 xmax = oldx->max; 3286 break; 3287 } 3288 prev = x; 3289 } 3290 if (!x) 3291 break; 3292 } 3293 if (!oldx) { 3294 x = allocFinalSpan (); 3295 if (x) 3296 { 3297 x->min = xmin; 3298 x->max = xmax; 3299 x->next = *f; 3300 *f = x; 3301 ++nspans; 3302 } 3303 } 3304} 3305 3306static void 3307mirrorSppPoint ( 3308 int quadrant, 3309 SppPointPtr sppPoint) 3310{ 3311 switch (quadrant) { 3312 case 0: 3313 break; 3314 case 1: 3315 sppPoint->x = -sppPoint->x; 3316 break; 3317 case 2: 3318 sppPoint->x = -sppPoint->x; 3319 sppPoint->y = -sppPoint->y; 3320 break; 3321 case 3: 3322 sppPoint->y = -sppPoint->y; 3323 break; 3324 } 3325 /* 3326 * and translate to X coordinate system 3327 */ 3328 sppPoint->y = -sppPoint->y; 3329} 3330 3331/* 3332 * split an arc into pieces which are scan-converted 3333 * in the first-quadrant and mirrored into position. 3334 * This is necessary as the scan-conversion code can 3335 * only deal with arcs completely contained in the 3336 * first quadrant. 3337 */ 3338 3339static void 3340drawArc ( 3341 xArc *tarc, 3342 int l, 3343 int a0, 3344 int a1, 3345 miArcFacePtr right, 3346 miArcFacePtr left) /* save end line points */ 3347{ 3348 struct arc_def def; 3349 struct accelerators acc; 3350 int startq, endq, curq; 3351 int rightq, leftq = 0, righta = 0, lefta = 0; 3352 miArcFacePtr passRight, passLeft; 3353 int q0 = 0, q1 = 0, mask; 3354 struct band { 3355 int a0, a1; 3356 int mask; 3357 } band[5], sweep[20]; 3358 int bandno, sweepno; 3359 int i, j; 3360 int flipRight = 0, flipLeft = 0; 3361 int copyEnd = 0; 3362 miArcSpanData *spdata; 3363 Bool mustFree; 3364 3365 spdata = miComputeWideEllipse(l, tarc, &mustFree); 3366 if (!spdata) 3367 return; 3368 3369 if (a1 < a0) 3370 a1 += 360 * 64; 3371 startq = a0 / (90 * 64); 3372 if (a0 == a1) 3373 endq = startq; 3374 else 3375 endq = (a1-1) / (90 * 64); 3376 bandno = 0; 3377 curq = startq; 3378 rightq = -1; 3379 for (;;) { 3380 switch (curq) { 3381 case 0: 3382 if (a0 > 90 * 64) 3383 q0 = 0; 3384 else 3385 q0 = a0; 3386 if (a1 < 360 * 64) 3387 q1 = min (a1, 90 * 64); 3388 else 3389 q1 = 90 * 64; 3390 if (curq == startq && a0 == q0 && rightq < 0) { 3391 righta = q0; 3392 rightq = curq; 3393 } 3394 if (curq == endq && a1 == q1) { 3395 lefta = q1; 3396 leftq = curq; 3397 } 3398 break; 3399 case 1: 3400 if (a1 < 90 * 64) 3401 q0 = 0; 3402 else 3403 q0 = 180 * 64 - min (a1, 180 * 64); 3404 if (a0 > 180 * 64) 3405 q1 = 90 * 64; 3406 else 3407 q1 = 180 * 64 - max (a0, 90 * 64); 3408 if (curq == startq && 180 * 64 - a0 == q1) { 3409 righta = q1; 3410 rightq = curq; 3411 } 3412 if (curq == endq && 180 * 64 - a1 == q0) { 3413 lefta = q0; 3414 leftq = curq; 3415 } 3416 break; 3417 case 2: 3418 if (a0 > 270 * 64) 3419 q0 = 0; 3420 else 3421 q0 = max (a0, 180 * 64) - 180 * 64; 3422 if (a1 < 180 * 64) 3423 q1 = 90 * 64; 3424 else 3425 q1 = min (a1, 270 * 64) - 180 * 64; 3426 if (curq == startq && a0 - 180*64 == q0) { 3427 righta = q0; 3428 rightq = curq; 3429 } 3430 if (curq == endq && a1 - 180 * 64 == q1) { 3431 lefta = q1; 3432 leftq = curq; 3433 } 3434 break; 3435 case 3: 3436 if (a1 < 270 * 64) 3437 q0 = 0; 3438 else 3439 q0 = 360 * 64 - min (a1, 360 * 64); 3440 q1 = 360 * 64 - max (a0, 270 * 64); 3441 if (curq == startq && 360 * 64 - a0 == q1) { 3442 righta = q1; 3443 rightq = curq; 3444 } 3445 if (curq == endq && 360 * 64 - a1 == q0) { 3446 lefta = q0; 3447 leftq = curq; 3448 } 3449 break; 3450 } 3451 band[bandno].a0 = q0; 3452 band[bandno].a1 = q1; 3453 band[bandno].mask = 1 << curq; 3454 bandno++; 3455 if (curq == endq) 3456 break; 3457 curq++; 3458 if (curq == 4) { 3459 a0 = 0; 3460 a1 -= 360 * 64; 3461 curq = 0; 3462 endq -= 4; 3463 } 3464 } 3465 sweepno = 0; 3466 for (;;) { 3467 q0 = 90 * 64; 3468 mask = 0; 3469 /* 3470 * find left-most point 3471 */ 3472 for (i = 0; i < bandno; i++) 3473 if (band[i].a0 <= q0) { 3474 q0 = band[i].a0; 3475 q1 = band[i].a1; 3476 mask = band[i].mask; 3477 } 3478 if (!mask) 3479 break; 3480 /* 3481 * locate next point of change 3482 */ 3483 for (i = 0; i < bandno; i++) 3484 if (!(mask & band[i].mask)) { 3485 if (band[i].a0 == q0) { 3486 if (band[i].a1 < q1) 3487 q1 = band[i].a1; 3488 mask |= band[i].mask; 3489 } else if (band[i].a0 < q1) 3490 q1 = band[i].a0; 3491 } 3492 /* 3493 * create a new sweep 3494 */ 3495 sweep[sweepno].a0 = q0; 3496 sweep[sweepno].a1 = q1; 3497 sweep[sweepno].mask = mask; 3498 sweepno++; 3499 /* 3500 * subtract the sweep from the affected bands 3501 */ 3502 for (i = 0; i < bandno; i++) 3503 if (band[i].a0 == q0) { 3504 band[i].a0 = q1; 3505 /* 3506 * check if this band is empty 3507 */ 3508 if (band[i].a0 == band[i].a1) 3509 band[i].a1 = band[i].a0 = 90 * 64 + 1; 3510 } 3511 } 3512 computeAcc (tarc, l, &def, &acc); 3513 for (j = 0; j < sweepno; j++) { 3514 mask = sweep[j].mask; 3515 passRight = passLeft = 0; 3516 if (mask & (1 << rightq)) { 3517 if (sweep[j].a0 == righta) 3518 passRight = right; 3519 else if (sweep[j].a1 == righta) { 3520 passLeft = right; 3521 flipRight = 1; 3522 } 3523 } 3524 if (mask & (1 << leftq)) { 3525 if (sweep[j].a1 == lefta) 3526 { 3527 if (passLeft) 3528 copyEnd = 1; 3529 passLeft = left; 3530 } 3531 else if (sweep[j].a0 == lefta) { 3532 if (passRight) 3533 copyEnd = 1; 3534 passRight = left; 3535 flipLeft = 1; 3536 } 3537 } 3538 drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, 3539 passRight, passLeft, spdata); 3540 } 3541 /* 3542 * when copyEnd is set, both ends of the arc were computed 3543 * at the same time; drawQuadrant only takes one end though, 3544 * so the left end will be the only one holding the data. Copy 3545 * it from there. 3546 */ 3547 if (copyEnd) 3548 *right = *left; 3549 /* 3550 * mirror the coordinates generated for the 3551 * faces of the arc 3552 */ 3553 if (right) { 3554 mirrorSppPoint (rightq, &right->clock); 3555 mirrorSppPoint (rightq, &right->center); 3556 mirrorSppPoint (rightq, &right->counterClock); 3557 if (flipRight) { 3558 SppPointRec temp; 3559 3560 temp = right->clock; 3561 right->clock = right->counterClock; 3562 right->counterClock = temp; 3563 } 3564 } 3565 if (left) { 3566 mirrorSppPoint (leftq, &left->counterClock); 3567 mirrorSppPoint (leftq, &left->center); 3568 mirrorSppPoint (leftq, &left->clock); 3569 if (flipLeft) { 3570 SppPointRec temp; 3571 3572 temp = left->clock; 3573 left->clock = left->counterClock; 3574 left->counterClock = temp; 3575 } 3576 } 3577 if (mustFree) 3578 xfree(spdata); 3579} 3580 3581static void 3582drawQuadrant ( 3583 struct arc_def *def, 3584 struct accelerators *acc, 3585 int a0, 3586 int a1, 3587 int mask, 3588 miArcFacePtr right, 3589 miArcFacePtr left, 3590 miArcSpanData *spdata) 3591{ 3592 struct arc_bound bound; 3593 double yy, x, xalt; 3594 int y, miny, maxy; 3595 int n; 3596 miArcSpan *span; 3597 3598 def->a0 = ((double) a0) / 64.0; 3599 def->a1 = ((double) a1) / 64.0; 3600 computeBound (def, &bound, acc, right, left); 3601 yy = bound.inner.min; 3602 if (bound.outer.min < yy) 3603 yy = bound.outer.min; 3604 miny = ICEIL(yy - acc->fromIntY); 3605 yy = bound.inner.max; 3606 if (bound.outer.max > yy) 3607 yy = bound.outer.max; 3608 maxy = floor(yy - acc->fromIntY); 3609 y = spdata->k; 3610 span = spdata->spans; 3611 if (spdata->top) 3612 { 3613 if (a1 == 90 * 64 && (mask & 1)) 3614 newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1); 3615 span++; 3616 } 3617 for (n = spdata->count1; --n >= 0; ) 3618 { 3619 if (y < miny) 3620 return; 3621 if (y <= maxy) { 3622 arcSpan (y, 3623 span->lx, -span->lx, 0, span->lx + span->lw, 3624 def, &bound, acc, mask); 3625 if (span->rw + span->rx) 3626 tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask); 3627 } 3628 y--; 3629 span++; 3630 } 3631 if (y < miny) 3632 return; 3633 if (spdata->hole) 3634 { 3635 if (y <= maxy) 3636 arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc); 3637 } 3638 for (n = spdata->count2; --n >= 0; ) 3639 { 3640 if (y < miny) 3641 return; 3642 if (y <= maxy) 3643 arcSpan (y, span->lx, span->lw, span->rx, span->rw, 3644 def, &bound, acc, mask); 3645 y--; 3646 span++; 3647 } 3648 if (spdata->bot && miny <= y && y <= maxy) 3649 { 3650 n = mask; 3651 if (y == miny) 3652 n &= 0xc; 3653 if (span->rw <= 0) { 3654 arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw, 3655 def, &bound, acc, n); 3656 if (span->rw + span->rx) 3657 tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n); 3658 } 3659 else 3660 arcSpan0 (span->lx, span->lw, span->rx, span->rw, 3661 def, &bound, acc, n); 3662 y--; 3663 } 3664 while (y >= miny) { 3665 yy = y + acc->fromIntY; 3666 if (def->w == def->h) { 3667 xalt = def->w - def->l; 3668 x = -sqrt(xalt * xalt - yy * yy); 3669 } else { 3670 x = tailX(yy, def, &bound, acc); 3671 if (acc->left.valid && boundedLe (yy, bound.left)) { 3672 xalt = intersectLine (yy, acc->left); 3673 if (xalt < x) 3674 x = xalt; 3675 } 3676 if (acc->right.valid && boundedLe (yy, bound.right)) { 3677 xalt = intersectLine (yy, acc->right); 3678 if (xalt < x) 3679 x = xalt; 3680 } 3681 } 3682 arcSpan (y, 3683 ICEIL(acc->fromIntX - x), 0, 3684 ICEIL(acc->fromIntX + x), 0, 3685 def, &bound, acc, mask); 3686 y--; 3687 } 3688} 3689