1 /***********************************************************
3 Copyright 1987, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 ******************************************************************/
46 /* Author: Keith Packard and Bob Scheifler */
47 /* Warning: this code is toxic, do not dally very long here. */
49 #include <dix-config.h>
53 #include <X11/Xprotostr.h>
56 #include "scrnintstr.h"
57 #include "pixmapstr.h"
58 #include "windowstr.h"
61 #include "mifillarc.h"
62 #include <X11/Xfuncproto.h>
64 #define EPSILON 0.000001
65 #define ISEQUAL(a,b) (fabs((a) - (b)) <= EPSILON)
66 #define UNEQUAL(a,b) (fabs((a) - (b)) > EPSILON)
67 #define PTISEQUAL(a,b) (ISEQUAL(a.x,b.x) && ISEQUAL(a.y,b.y))
68 #define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - for 11o miter cutoff */
70 /* Point with sub-pixel positioning. */
71 typedef struct _SppPoint
{
73 } SppPointRec
, *SppPointPtr
;
75 typedef struct _SppArc
{
76 double x
, y
, width
, height
;
77 double angle1
, angle2
;
78 } SppArcRec
, *SppArcPtr
;
80 static double miDsin(double a
);
81 static double miDcos(double a
);
82 static double miDasin(double v
);
83 static double miDatan2(double dy
, double dx
);
90 return pow(x
, 1.0 / 3.0);
92 return -pow(-x
, 1.0 / 3.0);
97 * some interesting semantic interpretation of the protocol:
99 * Self intersecting arcs (i.e. those spanning 360 degrees)
100 * never join with other arcs, and are drawn without caps
101 * (unless on/off dashed, in which case each dash segment
102 * is capped, except when the last segment meets the
103 * first segment, when no caps are drawn)
105 * double dash arcs are drawn in two parts, first the
106 * odd dashes (drawn in background) then the even dashes
107 * (drawn in foreground). This means that overlapping
108 * sections of foreground/background are drawn twice,
109 * first in background then in foreground. The double-draw
110 * occurs even when the function uses the destination values
111 * (e.g. xor mode). This is the same way the wide-line
112 * code works and should be "fixed".
124 #define boundedLe(value, bounds)\
125 ((bounds).min <= (value) && (value) <= (bounds).max)
132 #define intersectLine(y,line) (line.m * (y) + line.b)
135 * these are all y value bounds
139 struct bound ellipse
;
144 struct ibound inneri
;
145 struct ibound outeri
;
148 struct accelerators
{
159 struct line left
, right
;
170 #define todeg(xAngle) (((double) (xAngle)) / 64.0)
175 typedef struct _miArcJoin
{
176 int arcIndex0
, arcIndex1
;
179 } miArcJoinRec
, *miArcJoinPtr
;
181 typedef struct _miArcCap
{
184 } miArcCapRec
, *miArcCapPtr
;
186 typedef struct _miArcFace
{
189 SppPointRec counterClock
;
190 } miArcFaceRec
, *miArcFacePtr
;
192 typedef struct _miArcData
{
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
;
203 * This is an entire sequence of arcs, computed and categorized according
204 * to operation. miDashArcs generates either one or two of these.
207 typedef struct _miPolyArc
{
214 } miPolyArcRec
, *miPolyArcPtr
;
217 short lx
, lw
, rx
, rw
;
222 int count1
, count2
, k
;
226 static void fillSpans(DrawablePtr pDrawable
, GCPtr pGC
);
227 static void newFinalSpan(int y
, int xmin
, int xmax
);
228 static miArcSpanData
*drawArc(xArc
* tarc
, int l
, int a0
, int a1
,
229 miArcFacePtr right
, miArcFacePtr left
,
230 miArcSpanData
*spdata
);
231 static void drawZeroArc(DrawablePtr pDraw
, GCPtr pGC
, xArc
* tarc
, int lw
,
232 miArcFacePtr left
, miArcFacePtr right
);
233 static void miArcJoin(DrawablePtr pDraw
, GCPtr pGC
, miArcFacePtr pLeft
,
234 miArcFacePtr pRight
, int xOrgLeft
, int yOrgLeft
,
235 double xFtransLeft
, double yFtransLeft
,
236 int xOrgRight
, int yOrgRight
,
237 double xFtransRight
, double yFtransRight
);
238 static void miArcCap(DrawablePtr pDraw
, GCPtr pGC
, miArcFacePtr pFace
,
239 int end
, int xOrg
, int yOrg
, double xFtrans
,
241 static void miRoundCap(DrawablePtr pDraw
, GCPtr pGC
, SppPointRec pCenter
,
242 SppPointRec pEnd
, SppPointRec pCorner
,
243 SppPointRec pOtherCorner
, int fLineEnd
,
244 int xOrg
, int yOrg
, double xFtrans
, double yFtrans
);
245 static void miFreeArcs(miPolyArcPtr arcs
, GCPtr pGC
);
246 static miPolyArcPtr
miComputeArcs(xArc
* parcs
, int narcs
, GCPtr pGC
);
247 static int miGetArcPts(SppArcPtr parc
, int cpt
, SppPointPtr
* ppPts
);
249 #define CUBED_ROOT_2 1.2599210498948732038115849718451499938964
250 #define CUBED_ROOT_4 1.5874010519681993173435330390930175781250
253 * draw one segment of the arc using the arc spans generation routines
256 static miArcSpanData
*
257 miArcSegment(DrawablePtr pDraw
, GCPtr pGC
, xArc tarc
, miArcFacePtr right
,
258 miArcFacePtr left
, miArcSpanData
*spdata
)
260 int l
= pGC
->lineWidth
;
261 int a0
, a1
, startAngle
, endAngle
;
267 if (tarc
.width
== 0 || tarc
.height
== 0) {
268 drawZeroArc(pDraw
, pGC
, &tarc
, l
, left
, right
);
272 if (pGC
->miTranslate
) {
281 else if (a1
< -FULLCIRCLE
)
284 startAngle
= a0
+ a1
;
295 * bounds check the two angles
298 startAngle
= FULLCIRCLE
- (-startAngle
) % FULLCIRCLE
;
299 if (startAngle
>= FULLCIRCLE
)
300 startAngle
= startAngle
% FULLCIRCLE
;
302 endAngle
= FULLCIRCLE
- (-endAngle
) % FULLCIRCLE
;
303 if (endAngle
> FULLCIRCLE
)
304 endAngle
= (endAngle
- 1) % FULLCIRCLE
+ 1;
305 if ((startAngle
== endAngle
) && a1
) {
307 endAngle
= FULLCIRCLE
;
310 return drawArc(&tarc
, l
, startAngle
, endAngle
, right
, left
, spdata
);
315 Three equations combine to describe the boundaries of the arc
317 x^2/w^2 + y^2/h^2 = 1 ellipse itself
318 (X-x)^2 + (Y-y)^2 = r^2 circle at (x, y) on the ellipse
319 (Y-y) = (X-x)*w^2*y/(h^2*x) normal at (x, y) on the ellipse
321 These lead to a quartic relating Y and y
323 y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
324 - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
326 The reducible cubic obtained from this quartic is
328 z^3 - (3N)z^2 - 2V = 0
332 N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
333 V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
345 The discriminant of this cubic is
349 When D > 0, a real root is obtained as
351 z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
353 When D < 0, a real root is obtained as
355 z = N - 2m*cos(acos(-q/m^3)/3)
359 m = sqrt(|p|) * sign(q)
361 Given a real root Z of the cubic, the roots of the quartic are the roots
362 of the two quadratics
364 y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
368 A = +/- sqrt(8Z + b^2 - 4c)
369 b, c, d are the cubic, quadratic, and linear coefficients of the quartic
371 Some experimentation is then required to determine which solutions
372 correspond to the inner and outer boundaries.
376 static void drawQuadrant(struct arc_def
*def
, struct accelerators
*acc
,
377 int a0
, int a1
, int mask
, miArcFacePtr right
,
378 miArcFacePtr left
, miArcSpanData
* spdata
);
381 miComputeCircleSpans(int lw
, xArc
* parc
, miArcSpanData
* spdata
)
386 int xk
, yk
, xm
, ym
, dx
, dy
;
388 int inx
= 0, iny
, ine
= 0;
389 int inxk
= 0, inyk
= 0, inxm
= 0, inym
= 0;
392 slw
= parc
->width
- doinner
;
393 y
= parc
->height
>> 1;
394 dy
= parc
->height
& 1;
396 MIWIDEARCSETUP(x
, y
, dy
, slw
, e
, xk
, xm
, yk
, ym
);
397 inslw
= parc
->width
+ doinner
;
399 spdata
->hole
= spdata
->top
;
400 MIWIDEARCSETUP(inx
, iny
, dy
, inslw
, ine
, inxk
, inxm
, inyk
, inym
);
403 spdata
->hole
= FALSE
;
406 spdata
->count1
= -doinner
- spdata
->top
;
407 spdata
->count2
= y
+ doinner
;
408 span
= spdata
->spans
;
412 if (++doinner
<= 0) {
415 span
->rw
= span
->lx
+ slw
;
418 MIFILLINARCSTEP(inslw
);
420 span
->rx
= dy
- inx
+ inslw
;
421 span
->rw
= inx
- x
+ slw
- inslw
;
429 if (lw
> (int) parc
->height
)
430 span
[-1].rx
= span
[-1].rw
= -((lw
- (int) parc
->height
) >> 1);
439 miComputeEllipseSpans(int lw
, xArc
* parc
, miArcSpanData
* spdata
)
442 double w
, h
, r
, xorg
;
443 double Hs
, Hf
, WH
, K
, Vk
, Nk
, Fk
, Vr
, N
, Nc
, Z
, rs
;
444 double A
, T
, b
, d
, x
, y
, t
, inx
, outx
= 0.0, hepp
, hepm
;
447 w
= (double) parc
->width
/ 2.0;
448 h
= (double) parc
->height
/ 2.0;
454 Vk
= (Nk
* Hs
) / (WH
+ WH
);
456 Nk
= (Hf
- Nk
* Nk
) / WH
;
460 K
= h
+ ((lw
- 1) >> 1);
461 span
= spdata
->spans
;
473 spdata
->hole
= (spdata
->top
&&
474 (int) parc
->height
* lw
<= (int) (parc
->width
* parc
->width
)
475 && lw
< (int) parc
->height
);
476 for (; K
> 0.0; K
-= 1.0) {
477 N
= (K
* K
+ Nk
) / 6.0;
485 if ((b
< 0.0) == (t
< 0.0)) {
489 Z
= N
- 2.0 * b
* cos(acos(-t
/ d
) / 3.0);
490 if ((Z
< 0.0) == (Vr
< 0.0))
497 Z
= N
+ cbrt(t
+ d
) + cbrt(t
- d
);
500 A
= sqrt((Z
+ Z
) - Nk
);
501 T
= (Fk
- Z
) * K
/ A
;
505 d
= b
* b
- 4 * (Z
+ T
);
509 if ((y
>= 0.0) && (y
< hepp
)) {
514 x
= w
* sqrt(1 - (t
* t
));
516 if (rs
- (t
* t
) >= 0)
517 t
= sqrt(rs
- (t
* t
));
527 d
= b
* b
- 4 * (Z
- T
);
528 /* Because of the large magnitudes involved, we lose enough precision
529 * that sometimes we end up with a negative value near the axis, when
530 * it should be positive. This is a workaround.
532 if (d
< 0 && !solution
)
541 x
= w
* sqrt(1 - (t
* t
));
543 if (rs
- (t
* t
) >= 0)
544 inx
= x
- sqrt(rs
- (t
* t
));
553 x
= w
* sqrt(1 - (t
* t
));
555 if (rs
- (t
* t
) >= 0)
556 t
= sqrt(rs
- (t
* t
));
565 span
->lx
= ICEIL(xorg
- outx
);
568 span
->lw
= ICEIL(xorg
+ outx
) - span
->lx
;
569 span
->rx
= ICEIL(xorg
+ inx
);
570 span
->rw
= -ICEIL(xorg
- inx
);
574 span
->lw
= ICEIL(xorg
- inx
) - span
->lx
;
575 span
->rx
= ICEIL(xorg
+ inx
);
576 span
->rw
= ICEIL(xorg
+ outx
) - span
->rx
;
582 if (r
>= h
&& r
<= w
)
584 else if (Nk
< 0.0 && -Nk
< Hs
) {
585 inx
= w
* sqrt(1 + Nk
/ Hs
) - sqrt(rs
+ Nk
);
591 span
->lx
= ICEIL(xorg
- outx
);
593 span
->lw
= ICEIL(xorg
+ outx
) - span
->lx
;
594 span
->rx
= ICEIL(xorg
+ inx
);
595 span
->rw
= -ICEIL(xorg
- inx
);
598 span
->lw
= ICEIL(xorg
- inx
) - span
->lx
;
599 span
->rx
= ICEIL(xorg
+ inx
);
600 span
->rw
= ICEIL(xorg
+ outx
) - span
->rx
;
604 span
= &spdata
->spans
[spdata
->count1
];
605 span
->lw
= -span
->lx
;
615 struct arc_def
*def
, struct arc_bound
*bounds
, struct accelerators
*acc
)
618 double Hs
, Hf
, WH
, Vk
, Nk
, Fk
, Vr
, N
, Nc
, Z
, rs
;
619 double A
, T
, b
, d
, x
, y
, t
, hepp
, hepm
;
631 Vk
= (Nk
* Hs
) / (WH
+ WH
);
633 Nk
= (Hf
- Nk
* Nk
) / WH
;
635 if (Nk
< 0.0 && -Nk
< Hs
) {
636 xs
[0] = w
* sqrt(1 + Nk
/ Hs
) - sqrt(rs
+ Nk
);
638 if (acc
->left
.valid
&& boundedLe(K
, bounds
->left
) &&
639 !boundedLe(K
, bounds
->outer
) && xs
[0] >= 0.0 && xs
[1] >= 0.0)
641 if (acc
->right
.valid
&& boundedLe(K
, bounds
->right
) &&
642 !boundedLe(K
, bounds
->inner
) && xs
[0] <= 0.0 && xs
[1] <= 0.0)
651 N
= (K
* K
+ Nk
) / 6.0;
661 if ((b
< 0.0) == (t
< 0.0)) {
665 Z
= N
- 2.0 * b
* cos(acos(-t
/ d
) / 3.0);
666 if ((Z
< 0.0) == (Vr
< 0.0))
673 Z
= N
+ cbrt(t
+ d
) + cbrt(t
- d
);
676 A
= sqrt((Z
+ Z
) - Nk
);
677 T
= (Fk
- Z
) * K
/ A
;
680 d
= b
* b
- 4 * (Z
+ T
);
681 if (d
>= 0 && flip
== 2) {
684 if ((y
>= 0.0) && (y
< hepp
)) {
689 x
= w
* sqrt(1 - (t
* t
));
691 if (rs
- (t
* t
) >= 0)
692 t
= sqrt(rs
- (t
* t
));
699 d
= b
* b
- 4 * (Z
- T
);
700 /* Because of the large magnitudes involved, we lose enough precision
701 * that sometimes we end up with a negative value near the axis, when
702 * it should be positive. This is a workaround.
704 if (d
< 0 && !solution
)
713 x
= w
* sqrt(1 - (t
* t
));
715 if (rs
- (t
* t
) >= 0)
716 *xp
++ = x
- sqrt(rs
- (t
* t
));
721 if (y
>= 0.0 && flip
== 1) {
725 x
= w
* sqrt(1 - (t
* t
));
727 if (rs
- (t
* t
) >= 0)
728 t
= sqrt(rs
- (t
* t
));
735 if (acc
->left
.valid
&& boundedLe(K
, bounds
->left
) &&
736 !boundedLe(K
, bounds
->outer
) && xs
[0] >= 0.0 && xs
[1] >= 0.0)
738 if (acc
->right
.valid
&& boundedLe(K
, bounds
->right
) &&
739 !boundedLe(K
, bounds
->inner
) && xs
[0] <= 0.0 && xs
[1] <= 0.0)
745 static miArcSpanData
*
746 miComputeWideEllipse(int lw
, xArc
* parc
)
748 miArcSpanData
*spdata
= NULL
;
753 k
= (parc
->height
>> 1) + ((lw
- 1) >> 1);
754 spdata
= malloc(sizeof(miArcSpanData
) + sizeof(miArcSpan
) * (k
+ 2));
757 spdata
->spans
= (miArcSpan
*) (spdata
+ 1);
759 spdata
->top
= !(lw
& 1) && !(parc
->width
& 1);
760 spdata
->bot
= !(parc
->height
& 1);
761 if (parc
->width
== parc
->height
)
762 miComputeCircleSpans(lw
, parc
, spdata
);
764 miComputeEllipseSpans(lw
, parc
, spdata
);
769 miFillWideEllipse(DrawablePtr pDraw
, GCPtr pGC
, xArc
* parc
)
775 miArcSpanData
*spdata
;
777 int xorg
, yorgu
, yorgl
;
780 yorgu
= parc
->height
+ pGC
->lineWidth
;
781 n
= (sizeof(int) * 2) * yorgu
;
782 widths
= malloc(n
+ (sizeof(DDXPointRec
) * 2) * yorgu
);
785 points
= (DDXPointPtr
) ((char *) widths
+ n
);
786 spdata
= miComputeWideEllipse((int) pGC
->lineWidth
, parc
);
793 span
= spdata
->spans
;
794 xorg
= parc
->x
+ (parc
->width
>> 1);
795 yorgu
= parc
->y
+ (parc
->height
>> 1);
796 yorgl
= yorgu
+ (parc
->height
& 1);
797 if (pGC
->miTranslate
) {
811 for (n
= spdata
->count1
; --n
>= 0;) {
812 pts
[0].x
= xorg
+ span
->lx
;
831 for (n
= spdata
->count2
; --n
>= 0;) {
832 pts
[0].x
= xorg
+ span
->lx
;
835 pts
[1].x
= xorg
+ span
->rx
;
852 pts
[0].x
= xorg
+ span
->lx
;
859 pts
[0].x
= xorg
+ span
->lx
;
862 pts
[1].x
= xorg
+ span
->rx
;
870 (*pGC
->ops
->FillSpans
) (pDraw
, pGC
, pts
- points
, points
, widths
, FALSE
);
876 * miPolyArc strategy:
878 * If arc is zero width and solid, we don't have to worry about the rasterop
879 * or join styles. For wide solid circles, we use a fast integer algorithm.
880 * For wide solid ellipses, we use special case floating point code.
881 * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
882 * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is,
883 * if it involves the destination, then we use PushPixels to move the bits
884 * from the scratch drawable to pDraw. (See the wide line code for a
885 * fuller explanation of this.)
889 miWideArc(DrawablePtr pDraw
, GCPtr pGC
, int narcs
, xArc
* parcs
)
893 int xMin
, xMax
, yMin
, yMax
;
894 int pixmapWidth
= 0, pixmapHeight
= 0;
895 int xOrg
= 0, yOrg
= 0;
896 int width
= pGC
->lineWidth
;
901 miPolyArcPtr polyArcs
;
906 if (width
== 0 && pGC
->lineStyle
== LineSolid
) {
907 for (i
= narcs
, parc
= parcs
; --i
>= 0; parc
++) {
908 miArcSpanData
*spdata
;
909 spdata
= miArcSegment(pDraw
, pGC
, *parc
, NULL
, NULL
, NULL
);
912 fillSpans(pDraw
, pGC
);
916 if ((pGC
->lineStyle
== LineSolid
) && narcs
) {
917 while (parcs
->width
&& parcs
->height
&&
918 (parcs
->angle2
>= FULLCIRCLE
|| parcs
->angle2
<= -FULLCIRCLE
)) {
919 miFillWideEllipse(pDraw
, pGC
, parcs
);
926 /* Set up pDrawTo and pGCTo based on the rasterop */
928 case GXclear
: /* 0 */
929 case GXcopy
: /* src */
930 case GXcopyInverted
: /* NOT src */
939 /* find bounding box around arcs */
940 xMin
= yMin
= MAXSHORT
;
941 xMax
= yMax
= MINSHORT
;
943 for (i
= narcs
, parc
= parcs
; --i
>= 0; parc
++) {
944 xMin
= min(xMin
, parc
->x
);
945 yMin
= min(yMin
, parc
->y
);
946 xMax
= max(xMax
, (parc
->x
+ (int) parc
->width
));
947 yMax
= max(yMax
, (parc
->y
+ (int) parc
->height
));
950 /* expand box to deal with line widths */
951 halfWidth
= (width
+ 1) / 2;
957 /* compute pixmap size; limit it to size of drawable */
960 pixmapWidth
= min(xMax
, pDraw
->width
) - xOrg
;
961 pixmapHeight
= min(yMax
, pDraw
->height
) - yOrg
;
963 /* if nothing left, return */
964 if ((pixmapWidth
<= 0) || (pixmapHeight
<= 0))
967 for (i
= narcs
, parc
= parcs
; --i
>= 0; parc
++) {
971 if (pGC
->miTranslate
) {
976 /* set up scratch GC */
977 pGCTo
= GetScratchGC(1, pDraw
->pScreen
);
981 ChangeGCVal gcvals
[6];
983 gcvals
[0].val
= GXcopy
;
986 gcvals
[3].val
= pGC
->lineWidth
;
987 gcvals
[4].val
= pGC
->capStyle
;
988 gcvals
[5].val
= pGC
->joinStyle
;
989 ChangeGC(NullClient
, pGCTo
, GCFunction
|
990 GCForeground
| GCBackground
| GCLineWidth
|
991 GCCapStyle
| GCJoinStyle
, gcvals
);
994 /* allocate a bitmap of the appropriate size, and validate it */
995 pDrawTo
= (DrawablePtr
) (*pDraw
->pScreen
->CreatePixmap
)
996 (pDraw
->pScreen
, pixmapWidth
, pixmapHeight
, 1,
997 CREATE_PIXMAP_USAGE_SCRATCH
);
999 FreeScratchGC(pGCTo
);
1002 ValidateGC(pDrawTo
, pGCTo
);
1003 miClearDrawable(pDrawTo
, pGCTo
);
1009 /* the protocol sez these don't cause color changes */
1010 if ((pGC
->fillStyle
== FillTiled
) ||
1011 (pGC
->fillStyle
== FillOpaqueStippled
))
1014 polyArcs
= miComputeArcs(parcs
, narcs
, pGC
);
1018 cap
[0] = cap
[1] = 0;
1019 join
[0] = join
[1] = 0;
1020 for (iphase
= (pGC
->lineStyle
== LineDoubleDash
); iphase
>= 0; iphase
--) {
1021 miArcSpanData
*spdata
= NULL
;
1027 ChangeGC(NullClient
, pGC
, GCForeground
, &gcval
);
1028 ValidateGC(pDraw
, pGC
);
1030 else if (pGC
->lineStyle
== LineDoubleDash
) {
1032 ChangeGC(NullClient
, pGC
, GCForeground
, &gcval
);
1033 ValidateGC(pDraw
, pGC
);
1035 for (i
= 0; i
< polyArcs
[iphase
].narcs
; i
++) {
1036 miArcDataPtr arcData
;
1038 arcData
= &polyArcs
[iphase
].arcs
[i
];
1040 if (lastArc
.width
!= arcData
->arc
.width
||
1041 lastArc
.height
!= arcData
->arc
.height
) {
1046 memcpy(&lastArc
, &arcData
->arc
, sizeof(xArc
));
1047 spdata
= miArcSegment(pDrawTo
, pGCTo
, arcData
->arc
,
1048 &arcData
->bounds
[RIGHT_END
],
1049 &arcData
->bounds
[LEFT_END
], spdata
);
1050 if (polyArcs
[iphase
].arcs
[i
].render
) {
1051 fillSpans(pDrawTo
, pGCTo
);
1052 /* don't cap self-joining arcs */
1053 if (polyArcs
[iphase
].arcs
[i
].selfJoin
&&
1054 cap
[iphase
] < polyArcs
[iphase
].arcs
[i
].cap
)
1056 while (cap
[iphase
] < polyArcs
[iphase
].arcs
[i
].cap
) {
1058 miArcDataPtr arcData0
;
1060 arcIndex
= polyArcs
[iphase
].caps
[cap
[iphase
]].arcIndex
;
1061 end
= polyArcs
[iphase
].caps
[cap
[iphase
]].end
;
1062 arcData0
= &polyArcs
[iphase
].arcs
[arcIndex
];
1063 miArcCap(pDrawTo
, pGCTo
,
1064 &arcData0
->bounds
[end
], end
,
1065 arcData0
->arc
.x
, arcData0
->arc
.y
,
1066 (double) arcData0
->arc
.width
/ 2.0,
1067 (double) arcData0
->arc
.height
/ 2.0);
1070 while (join
[iphase
] < polyArcs
[iphase
].arcs
[i
].join
) {
1071 int arcIndex0
, arcIndex1
, end0
, end1
;
1073 miArcDataPtr arcData0
, arcData1
;
1076 joinp
= &polyArcs
[iphase
].joins
[join
[iphase
]];
1077 arcIndex0
= joinp
->arcIndex0
;
1079 arcIndex1
= joinp
->arcIndex1
;
1081 phase0
= joinp
->phase0
;
1082 phase1
= joinp
->phase1
;
1083 arcData0
= &polyArcs
[phase0
].arcs
[arcIndex0
];
1084 arcData1
= &polyArcs
[phase1
].arcs
[arcIndex1
];
1085 miArcJoin(pDrawTo
, pGCTo
,
1086 &arcData0
->bounds
[end0
],
1087 &arcData1
->bounds
[end1
],
1088 arcData0
->arc
.x
, arcData0
->arc
.y
,
1089 (double) arcData0
->arc
.width
/ 2.0,
1090 (double) arcData0
->arc
.height
/ 2.0,
1091 arcData1
->arc
.x
, arcData1
->arc
.y
,
1092 (double) arcData1
->arc
.width
/ 2.0,
1093 (double) arcData1
->arc
.height
/ 2.0);
1097 if (pGC
->serialNumber
!= pDraw
->serialNumber
)
1098 ValidateGC(pDraw
, pGC
);
1099 (*pGC
->ops
->PushPixels
) (pGC
, (PixmapPtr
) pDrawTo
,
1101 pixmapHeight
, xOrg
, yOrg
);
1102 miClearDrawable((DrawablePtr
) pDrawTo
, pGCTo
);
1109 miFreeArcs(polyArcs
, pGC
);
1113 (*pGCTo
->pScreen
->DestroyPixmap
) ((PixmapPtr
) pDrawTo
);
1114 FreeScratchGC(pGCTo
);
1118 /* Find the index of the point with the smallest y.also return the
1119 * smallest and largest y */
1121 GetFPolyYBounds(SppPointPtr pts
, int n
, double yFtrans
, int *by
, int *ty
)
1125 SppPointPtr ptsStart
= pts
;
1128 ymin
= ymax
= (pts
++)->y
;
1131 if (pts
->y
< ymin
) {
1141 *by
= ICEIL(ymin
+ yFtrans
);
1142 *ty
= ICEIL(ymax
+ yFtrans
- 1);
1143 return ptMin
- ptsStart
;
1147 * miFillSppPoly written by Todd Newman; April. 1987.
1149 * Fill a convex polygon. If the given polygon
1150 * is not convex, then the result is undefined.
1151 * The algorithm is to order the edges from smallest
1152 * y to largest by partitioning the array into a left
1153 * edge list and a right edge list. The algorithm used
1154 * to traverse each edge is digital differencing analyzer
1155 * line algorithm with y as the major axis. There's some funny linear
1156 * interpolation involved because of the subpixel postioning.
1159 miFillSppPoly(DrawablePtr dst
, GCPtr pgc
, int count
, /* number of points */
1160 SppPointPtr ptsIn
, /* the points */
1161 int xTrans
, int yTrans
, /* Translate each point by this */
1162 double xFtrans
, double yFtrans
/* translate before conversion
1163 by this amount. This provides
1164 a mechanism to match rounding
1165 errors with any shape that must
1166 meet the polygon exactly.
1170 double xl
= 0.0, xr
= 0.0, /* x vals of left and right edges */
1171 ml
= 0.0, /* left edge slope */
1172 mr
= 0.0, /* right edge slope */
1174 i
; /* loop counter */
1175 int y
, /* current scanline */
1176 j
, imin
, /* index of vertex with smallest y */
1177 ymin
, /* y-extents of polygon */
1178 ymax
, *width
, *FirstWidth
, /* output buffer */
1179 *Marked
; /* set if this vertex has been used */
1180 int left
, right
, /* indices to first endpoints */
1181 nextleft
, nextright
; /* indices to second endpoints */
1182 DDXPointPtr ptsOut
, FirstPoint
; /* output buffer */
1184 if (pgc
->miTranslate
) {
1189 imin
= GetFPolyYBounds(ptsIn
, count
, yFtrans
, &ymin
, &ymax
);
1191 y
= ymax
- ymin
+ 1;
1192 if ((count
< 3) || (y
<= 0))
1194 ptsOut
= FirstPoint
= xallocarray(y
, sizeof(DDXPointRec
));
1195 width
= FirstWidth
= xallocarray(y
, sizeof(int));
1196 Marked
= xallocarray(count
, sizeof(int));
1198 if (!ptsOut
|| !width
|| !Marked
) {
1205 for (j
= 0; j
< count
; j
++)
1207 nextleft
= nextright
= imin
;
1209 y
= ICEIL(ptsIn
[nextleft
].y
+ yFtrans
);
1212 * loop through all edges of the polygon
1215 /* add a left edge if we need to */
1216 if ((y
> (ptsIn
[nextleft
].y
+ yFtrans
) ||
1217 ISEQUAL(y
, ptsIn
[nextleft
].y
+ yFtrans
)) &&
1218 Marked
[nextleft
] != 1) {
1222 /* find the next edge, considering the end conditions */
1223 if (nextleft
>= count
)
1226 /* now compute the starting point and slope */
1227 dy
= ptsIn
[nextleft
].y
- ptsIn
[left
].y
;
1229 ml
= (ptsIn
[nextleft
].x
- ptsIn
[left
].x
) / dy
;
1230 dy
= y
- (ptsIn
[left
].y
+ yFtrans
);
1231 xl
= (ptsIn
[left
].x
+ xFtrans
) + ml
* max(dy
, 0);
1235 /* add a right edge if we need to */
1236 if ((y
> ptsIn
[nextright
].y
+ yFtrans
) ||
1237 (ISEQUAL(y
, ptsIn
[nextright
].y
+ yFtrans
)
1238 && Marked
[nextright
] != 1)) {
1239 Marked
[nextright
]++;
1240 right
= nextright
--;
1242 /* find the next edge, considering the end conditions */
1244 nextright
= count
- 1;
1246 /* now compute the starting point and slope */
1247 dy
= ptsIn
[nextright
].y
- ptsIn
[right
].y
;
1249 mr
= (ptsIn
[nextright
].x
- ptsIn
[right
].x
) / dy
;
1250 dy
= y
- (ptsIn
[right
].y
+ yFtrans
);
1251 xr
= (ptsIn
[right
].x
+ xFtrans
) + mr
* max(dy
, 0);
1256 * generate scans to fill while we still have
1257 * a right edge as well as a left edge.
1259 i
= (min(ptsIn
[nextleft
].y
, ptsIn
[nextright
].y
) + yFtrans
) - y
;
1262 if (Marked
[nextleft
] && Marked
[nextright
]) {
1263 /* Arrgh, we're trapped! (no more points)
1264 * Out, we've got to get out of here before this decadence saps
1265 * our will completely! */
1278 ptsOut
->y
= (y
) + yTrans
;
1282 /* reverse the edges if necessary */
1284 *(width
++) = cxr
- cxl
;
1285 (ptsOut
++)->x
= cxl
+ xTrans
;
1288 *(width
++) = cxl
- cxr
;
1289 (ptsOut
++)->x
= cxr
+ xTrans
;
1293 /* increment down the edges */
1298 } while (y
<= ymax
);
1300 /* Finally, fill the spans we've collected */
1301 (*pgc
->ops
->FillSpans
) (dst
, pgc
,
1302 ptsOut
- FirstPoint
, FirstPoint
, FirstWidth
, 1);
1308 angleBetween(SppPointRec center
, SppPointRec point1
, SppPointRec point2
)
1313 * reflect from X coordinates back to ellipse
1314 * coordinates -- y increasing upwards
1316 a1
= miDatan2(-(point1
.y
- center
.y
), point1
.x
- center
.x
);
1317 a2
= miDatan2(-(point2
.y
- center
.y
), point2
.x
- center
.x
);
1327 translateBounds(miArcFacePtr b
, int x
, int y
, double fx
, double fy
)
1335 b
->counterClock
.x
-= fx
;
1336 b
->counterClock
.y
-= fy
;
1340 miArcJoin(DrawablePtr pDraw
, GCPtr pGC
, miArcFacePtr pLeft
,
1341 miArcFacePtr pRight
, int xOrgLeft
, int yOrgLeft
,
1342 double xFtransLeft
, double yFtransLeft
,
1343 int xOrgRight
, int yOrgRight
,
1344 double xFtransRight
, double yFtransRight
)
1346 SppPointRec center
, corner
, otherCorner
;
1347 SppPointRec poly
[5], e
;
1348 SppPointPtr pArcPts
;
1351 miArcFaceRec Right
, Left
;
1354 double xFtrans
, yFtrans
;
1356 double ae
, ac2
, ec2
, bc2
, de
;
1359 xOrg
= (xOrgRight
+ xOrgLeft
) / 2;
1360 yOrg
= (yOrgRight
+ yOrgLeft
) / 2;
1361 xFtrans
= (xFtransLeft
+ xFtransRight
) / 2;
1362 yFtrans
= (yFtransLeft
+ yFtransRight
) / 2;
1364 translateBounds(&Right
, xOrg
- xOrgRight
, yOrg
- yOrgRight
,
1365 xFtrans
- xFtransRight
, yFtrans
- yFtransRight
);
1367 translateBounds(&Left
, xOrg
- xOrgLeft
, yOrg
- yOrgLeft
,
1368 xFtrans
- xFtransLeft
, yFtrans
- yFtransLeft
);
1372 if (pRight
->clock
.x
== pLeft
->counterClock
.x
&&
1373 pRight
->clock
.y
== pLeft
->counterClock
.y
)
1375 center
= pRight
->center
;
1376 if (0 <= (a
= angleBetween(center
, pRight
->clock
, pLeft
->counterClock
))
1378 corner
= pRight
->clock
;
1379 otherCorner
= pLeft
->counterClock
;
1382 a
= angleBetween(center
, pLeft
->clock
, pRight
->counterClock
);
1383 corner
= pLeft
->clock
;
1384 otherCorner
= pRight
->counterClock
;
1386 switch (pGC
->joinStyle
) {
1388 width
= (pGC
->lineWidth
? (double) pGC
->lineWidth
: (double) 1);
1390 arc
.x
= center
.x
- width
/ 2;
1391 arc
.y
= center
.y
- width
/ 2;
1394 arc
.angle1
= -miDatan2(corner
.y
- center
.y
, corner
.x
- center
.x
);
1396 pArcPts
= malloc(3 * sizeof(SppPointRec
));
1399 pArcPts
[0].x
= otherCorner
.x
;
1400 pArcPts
[0].y
= otherCorner
.y
;
1401 pArcPts
[1].x
= center
.x
;
1402 pArcPts
[1].y
= center
.y
;
1403 pArcPts
[2].x
= corner
.x
;
1404 pArcPts
[2].y
= corner
.y
;
1405 if ((cpt
= miGetArcPts(&arc
, 3, &pArcPts
))) {
1406 /* by drawing with miFillSppPoly and setting the endpoints of the arc
1407 * to be the corners, we assure that the cap will meet up with the
1408 * rest of the line */
1409 miFillSppPoly(pDraw
, pGC
, cpt
, pArcPts
, xOrg
, yOrg
, xFtrans
,
1416 * don't miter arcs with less than 11 degrees between them
1421 poly
[2] = otherCorner
;
1422 bc2
= (corner
.x
- otherCorner
.x
) * (corner
.x
- otherCorner
.x
) +
1423 (corner
.y
- otherCorner
.y
) * (corner
.y
- otherCorner
.y
);
1425 ac2
= (corner
.x
- center
.x
) * (corner
.x
- center
.x
) +
1426 (corner
.y
- center
.y
) * (corner
.y
- center
.y
);
1427 ae
= sqrt(ac2
- ec2
);
1429 e
.x
= (corner
.x
+ otherCorner
.x
) / 2;
1430 e
.y
= (corner
.y
+ otherCorner
.y
) / 2;
1431 poly
[3].x
= e
.x
+ de
* (e
.x
- center
.x
) / ae
;
1432 poly
[3].y
= e
.y
+ de
* (e
.y
- center
.y
) / ae
;
1440 poly
[2] = otherCorner
;
1445 miFillSppPoly(pDraw
, pGC
, polyLen
, poly
, xOrg
, yOrg
, xFtrans
, yFtrans
);
1448 /*ARGSUSED*/ static void
1449 miArcCap(DrawablePtr pDraw
,
1452 int end
, int xOrg
, int yOrg
, double xFtrans
, double yFtrans
)
1454 SppPointRec corner
, otherCorner
, center
, endPoint
, poly
[5];
1456 corner
= pFace
->clock
;
1457 otherCorner
= pFace
->counterClock
;
1458 center
= pFace
->center
;
1459 switch (pGC
->capStyle
) {
1461 poly
[0].x
= otherCorner
.x
;
1462 poly
[0].y
= otherCorner
.y
;
1463 poly
[1].x
= corner
.x
;
1464 poly
[1].y
= corner
.y
;
1465 poly
[2].x
= corner
.x
- (center
.y
- corner
.y
);
1466 poly
[2].y
= corner
.y
+ (center
.x
- corner
.x
);
1467 poly
[3].x
= otherCorner
.x
- (otherCorner
.y
- center
.y
);
1468 poly
[3].y
= otherCorner
.y
+ (otherCorner
.x
- center
.x
);
1469 poly
[4].x
= otherCorner
.x
;
1470 poly
[4].y
= otherCorner
.y
;
1471 miFillSppPoly(pDraw
, pGC
, 5, poly
, xOrg
, yOrg
, xFtrans
, yFtrans
);
1475 * miRoundCap just needs these to be unequal.
1478 endPoint
.x
= endPoint
.x
+ 100;
1479 miRoundCap(pDraw
, pGC
, center
, endPoint
, corner
, otherCorner
, 0,
1480 -xOrg
, -yOrg
, xFtrans
, yFtrans
);
1485 /* MIROUNDCAP -- a private helper function
1486 * Put Rounded cap on end. pCenter is the center of this end of the line
1487 * pEnd is the center of the other end of the line. pCorner is one of the
1488 * two corners at this end of the line.
1489 * NOTE: pOtherCorner must be counter-clockwise from pCorner.
1491 /*ARGSUSED*/ static void
1492 miRoundCap(DrawablePtr pDraw
,
1494 SppPointRec pCenter
,
1496 SppPointRec pCorner
,
1497 SppPointRec pOtherCorner
,
1498 int fLineEnd
, int xOrg
, int yOrg
, double xFtrans
, double yFtrans
)
1503 SppPointPtr pArcPts
;
1505 width
= (pGC
->lineWidth
? (double) pGC
->lineWidth
: (double) 1);
1507 arc
.x
= pCenter
.x
- width
/ 2;
1508 arc
.y
= pCenter
.y
- width
/ 2;
1511 arc
.angle1
= -miDatan2(pCorner
.y
- pCenter
.y
, pCorner
.x
- pCenter
.x
);
1512 if (PTISEQUAL(pCenter
, pEnd
))
1513 arc
.angle2
= -180.0;
1516 -miDatan2(pOtherCorner
.y
- pCenter
.y
,
1517 pOtherCorner
.x
- pCenter
.x
) - arc
.angle1
;
1519 arc
.angle2
+= 360.0;
1521 pArcPts
= (SppPointPtr
) NULL
;
1522 if ((cpt
= miGetArcPts(&arc
, 0, &pArcPts
))) {
1523 /* by drawing with miFillSppPoly and setting the endpoints of the arc
1524 * to be the corners, we assure that the cap will meet up with the
1525 * rest of the line */
1526 miFillSppPoly(pDraw
, pGC
, cpt
, pArcPts
, -xOrg
, -yOrg
, xFtrans
, yFtrans
);
1532 * To avoid inaccuracy at the cardinal points, use trig functions
1533 * which are exact for those angles
1537 #define M_PI 3.14159265358979323846
1540 #define M_PI_2 1.57079632679489661923
1543 #define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
1544 #define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
1545 #define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-(a)) % (b))
1552 if (floor(a
/ 90) == a
/ 90) {
1553 i
= (int) (a
/ 90.0);
1554 switch (mod(i
, 4)) {
1565 return cos(a
* M_PI
/ 180.0);
1573 if (floor(a
/ 90) == a
/ 90) {
1574 i
= (int) (a
/ 90.0);
1575 switch (mod(i
, 4)) {
1586 return sin(a
* M_PI
/ 180.0);
1598 return asin(v
) * (180.0 / M_PI
);
1602 miDatan2(double dy
, double dx
)
1614 else if (fabs(dy
) == fabs(dx
)) {
1627 return atan2(dy
, dx
) * (180.0 / M_PI
);
1631 /* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
1632 * routine for filled arc and line (round cap) code.
1633 * Returns the number of points in the arc. Note that it takes a pointer
1634 * to a pointer to where it should put the points and an index (cpt).
1635 * This procedure allocates the space necessary to fit the arc points.
1636 * Sometimes it's convenient for those points to be at the end of an existing
1637 * array. (For example, if we want to leave a spare point to make sectors
1638 * instead of segments.) So we pass in the malloc()ed chunk that contains the
1639 * array and an index saying where we should start stashing the points.
1640 * If there isn't an array already, we just pass in a null pointer and
1641 * count on realloc() to handle the null pointer correctly.
1644 miGetArcPts(SppArcPtr parc
, /* points to an arc */
1645 int cpt
, /* number of points already in arc list */
1646 SppPointPtr
* ppPts
)
1647 { /* pointer to pointer to arc-list -- modified */
1648 double st
, /* Start Theta, start angle */
1649 et
, /* End Theta, offset from start theta */
1650 dt
, /* Delta Theta, angle to sweep ellipse */
1651 cdt
, /* Cos Delta Theta, actually 2 cos(dt) */
1652 x0
, y0
, /* the recurrence formula needs two points to start */
1653 x1
, y1
, x2
, y2
, /* this will be the new point generated */
1654 xc
, yc
; /* the center point */
1658 /* The spec says that positive angles indicate counterclockwise motion.
1659 * Given our coordinate system (with 0,0 in the upper left corner),
1660 * the screen appears flipped in Y. The easiest fix is to negate the
1667 /* Try to get a delta theta that is within 1/2 pixel. Then adjust it
1668 * so that it divides evenly into the total.
1669 * I'm just using cdt 'cause I'm lazy.
1672 if (parc
->height
> cdt
)
1679 dt
= miDasin(1.0 / cdt
); /* minimum step necessary */
1681 count
= abs(count
) + 1;
1685 cdt
= 2 * miDcos(dt
);
1686 if (!(poly
= reallocarray(*ppPts
, cpt
+ count
, sizeof(SppPointRec
))))
1690 xc
= parc
->width
/ 2.0; /* store half width and half height */
1691 yc
= parc
->height
/ 2.0;
1693 x0
= xc
* miDcos(st
);
1694 y0
= yc
* miDsin(st
);
1695 x1
= xc
* miDcos(st
+ dt
);
1696 y1
= yc
* miDsin(st
+ dt
);
1697 xc
+= parc
->x
; /* by adding initial point, these become */
1698 yc
+= parc
->y
; /* the center point */
1700 poly
[cpt
].x
= (xc
+ x0
);
1701 poly
[cpt
].y
= (yc
+ y0
);
1702 poly
[cpt
+ 1].x
= (xc
+ x1
);
1703 poly
[cpt
+ 1].y
= (yc
+ y1
);
1705 for (i
= 2; i
< count
; i
++) {
1709 poly
[cpt
+ i
].x
= (xc
+ x2
);
1710 poly
[cpt
+ i
].y
= (yc
+ y2
);
1717 /* adjust the last point */
1718 if (fabs(parc
->angle2
) >= 360.0)
1719 poly
[cpt
+ i
- 1] = poly
[0];
1721 poly
[cpt
+ i
- 1].x
= (miDcos(st
+ et
) * parc
->width
/ 2.0 + xc
);
1722 poly
[cpt
+ i
- 1].y
= (miDsin(st
+ et
) * parc
->height
/ 2.0 + yc
);
1729 double x0
, y0
, x1
, y1
;
1733 #define ADD_REALLOC_STEP 20
1736 addCap(miArcCapPtr
* capsp
, int *ncapsp
, int *sizep
, int end
, int arcIndex
)
1741 if (*ncapsp
== *sizep
) {
1742 newsize
= *sizep
+ ADD_REALLOC_STEP
;
1743 cap
= reallocarray(*capsp
, newsize
, sizeof(**capsp
));
1749 cap
= &(*capsp
)[*ncapsp
];
1751 cap
->arcIndex
= arcIndex
;
1756 addJoin(miArcJoinPtr
* joinsp
,
1759 int end0
, int index0
, int phase0
, int end1
, int index1
, int phase1
)
1764 if (*njoinsp
== *sizep
) {
1765 newsize
= *sizep
+ ADD_REALLOC_STEP
;
1766 join
= reallocarray(*joinsp
, newsize
, sizeof(**joinsp
));
1772 join
= &(*joinsp
)[*njoinsp
];
1774 join
->arcIndex0
= index0
;
1775 join
->phase0
= phase0
;
1777 join
->arcIndex1
= index1
;
1778 join
->phase1
= phase1
;
1783 addArc(miArcDataPtr
* arcsp
, int *narcsp
, int *sizep
, xArc
* xarc
)
1788 if (*narcsp
== *sizep
) {
1789 newsize
= *sizep
+ ADD_REALLOC_STEP
;
1790 arc
= reallocarray(*arcsp
, newsize
, sizeof(**arcsp
));
1796 arc
= &(*arcsp
)[*narcsp
];
1803 miFreeArcs(miPolyArcPtr arcs
, GCPtr pGC
)
1807 for (iphase
= ((pGC
->lineStyle
== LineDoubleDash
) ? 1 : 0);
1808 iphase
>= 0; iphase
--) {
1809 if (arcs
[iphase
].narcs
> 0)
1810 free(arcs
[iphase
].arcs
);
1811 if (arcs
[iphase
].njoins
> 0)
1812 free(arcs
[iphase
].joins
);
1813 if (arcs
[iphase
].ncaps
> 0)
1814 free(arcs
[iphase
].caps
);
1820 * map angles to radial distance. This only deals with the first quadrant
1824 * a polygonal approximation to the arc for computing arc lengths
1827 #define DASH_MAP_SIZE 91
1829 #define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
1830 #define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
1831 #define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
1832 #define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
1835 double map
[DASH_MAP_SIZE
];
1838 static int computeAngleFromPath(int startAngle
, int endAngle
, dashMap
* map
,
1839 int *lenp
, int backwards
);
1842 computeDashMap(xArc
* arcp
, dashMap
* map
)
1845 double a
, x
, y
, prevx
= 0.0, prevy
= 0.0, dist
;
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
);
1855 dist
= hypot(x
- prevx
, y
- prevy
);
1856 map
->map
[di
] = map
->map
[di
- 1] + dist
;
1863 typedef enum { HORIZONTAL
, VERTICAL
, OTHER
} arcTypes
;
1865 /* this routine is a bit gory */
1868 miComputeArcs(xArc
* parcs
, int narcs
, GCPtr pGC
)
1870 int isDashed
, isDoubleDash
;
1873 int start
, i
, j
, k
= 0, nexti
, nextk
= 0;
1879 struct arcData
*data
;
1882 int iphase
, prevphase
= 0, joinphase
;
1886 int iDash
= 0, dashRemaining
= 0;
1887 int iDashStart
= 0, dashRemainingStart
= 0, iphaseStart
;
1888 int startAngle
, spanAngle
, endAngle
, backwards
= 0;
1889 int prevDashAngle
, dashAngle
;
1892 isDashed
= !(pGC
->lineStyle
== LineSolid
);
1893 isDoubleDash
= (pGC
->lineStyle
== LineDoubleDash
);
1894 dashOffset
= pGC
->dashOffset
;
1896 data
= xallocarray(narcs
, sizeof(struct arcData
));
1899 arcs
= xallocarray(isDoubleDash
? 2 : 1, sizeof(*arcs
));
1904 for (i
= 0; i
< narcs
; i
++) {
1905 a0
= todeg(parcs
[i
].angle1
);
1906 angle2
= parcs
[i
].angle2
;
1907 if (angle2
> FULLCIRCLE
)
1908 angle2
= FULLCIRCLE
;
1909 else if (angle2
< -FULLCIRCLE
)
1910 angle2
= -FULLCIRCLE
;
1911 data
[i
].selfJoin
= angle2
== FULLCIRCLE
|| angle2
== -FULLCIRCLE
;
1912 a1
= todeg(parcs
[i
].angle1
+ angle2
);
1914 parcs
[i
].x
+ (double) parcs
[i
].width
/ 2 * (1 + miDcos(a0
));
1916 parcs
[i
].y
+ (double) parcs
[i
].height
/ 2 * (1 - miDsin(a0
));
1918 parcs
[i
].x
+ (double) parcs
[i
].width
/ 2 * (1 + miDcos(a1
));
1920 parcs
[i
].y
+ (double) parcs
[i
].height
/ 2 * (1 - miDsin(a1
));
1923 for (iphase
= 0; iphase
< (isDoubleDash
? 2 : 1); iphase
++) {
1924 arcs
[iphase
].njoins
= 0;
1925 arcs
[iphase
].joins
= 0;
1926 joinSize
[iphase
] = 0;
1928 arcs
[iphase
].ncaps
= 0;
1929 arcs
[iphase
].caps
= 0;
1930 capSize
[iphase
] = 0;
1932 arcs
[iphase
].narcs
= 0;
1933 arcs
[iphase
].arcs
= 0;
1934 arcSize
[iphase
] = 0;
1940 dashRemaining
= pGC
->dash
[0];
1941 while (dashOffset
> 0) {
1942 if (dashOffset
>= dashRemaining
) {
1943 dashOffset
-= dashRemaining
;
1944 iphase
= iphase
? 0 : 1;
1946 if (iDash
== pGC
->numInDashList
)
1948 dashRemaining
= pGC
->dash
[iDash
];
1951 dashRemaining
-= dashOffset
;
1956 dashRemainingStart
= dashRemaining
;
1958 iphaseStart
= iphase
;
1960 for (i
= narcs
- 1; i
>= 0; i
--) {
1964 if (data
[i
].selfJoin
|| i
== j
||
1965 (UNEQUAL(data
[i
].x1
, data
[j
].x0
) ||
1966 UNEQUAL(data
[i
].y1
, data
[j
].y0
))) {
1967 if (iphase
== 0 || isDoubleDash
)
1968 addCap(&arcs
[iphase
].caps
, &arcs
[iphase
].ncaps
,
1969 &capSize
[iphase
], RIGHT_END
, 0);
1986 ** deal with dashed arcs. Use special rules for certain 0 area arcs.
1987 ** Presumably, the other 0 area arcs still aren't done right.
1989 arcTypes arcType
= OTHER
;
1992 if (parcs
[i
].height
== 0
1993 && (parcs
[i
].angle1
% FULLCIRCLE
) == 0x2d00
1994 && parcs
[i
].angle2
== 0x2d00)
1995 arcType
= HORIZONTAL
;
1996 else if (parcs
[i
].width
== 0
1997 && (parcs
[i
].angle1
% FULLCIRCLE
) == 0x1680
1998 && parcs
[i
].angle2
== 0x2d00)
2000 if (arcType
== OTHER
) {
2002 * precompute an approximation map
2004 computeDashMap(&parcs
[i
], &map
);
2006 * compute each individual dash segment using the path
2009 startAngle
= parcs
[i
].angle1
;
2010 spanAngle
= parcs
[i
].angle2
;
2011 if (spanAngle
> FULLCIRCLE
)
2012 spanAngle
= FULLCIRCLE
;
2013 else if (spanAngle
< -FULLCIRCLE
)
2014 spanAngle
= -FULLCIRCLE
;
2016 startAngle
= FULLCIRCLE
- (-startAngle
) % FULLCIRCLE
;
2017 if (startAngle
>= FULLCIRCLE
)
2018 startAngle
= startAngle
% FULLCIRCLE
;
2019 endAngle
= startAngle
+ spanAngle
;
2020 backwards
= spanAngle
< 0;
2024 if (arcType
== VERTICAL
) {
2025 xarc
.angle1
= 0x1680;
2026 startAngle
= parcs
[i
].y
;
2027 endAngle
= startAngle
+ parcs
[i
].height
;
2030 xarc
.angle1
= 0x2d00;
2031 startAngle
= parcs
[i
].x
;
2032 endAngle
= startAngle
+ parcs
[i
].width
;
2035 dashAngle
= startAngle
;
2036 selfJoin
= data
[i
].selfJoin
&& (iphase
== 0 || isDoubleDash
);
2038 * add dashed arcs to each bucket
2041 while (dashAngle
!= endAngle
) {
2042 prevDashAngle
= dashAngle
;
2043 if (arcType
== OTHER
) {
2044 dashAngle
= computeAngleFromPath(prevDashAngle
, endAngle
,
2045 &map
, &dashRemaining
,
2047 /* avoid troubles with huge arcs and small dashes */
2048 if (dashAngle
== prevDashAngle
) {
2056 thisLength
= (dashAngle
+ dashRemaining
<= endAngle
) ?
2057 dashRemaining
: endAngle
- dashAngle
;
2058 if (arcType
== VERTICAL
) {
2060 xarc
.height
= thisLength
;
2064 xarc
.width
= thisLength
;
2066 dashAngle
+= thisLength
;
2067 dashRemaining
-= thisLength
;
2069 if (iphase
== 0 || isDoubleDash
) {
2070 if (arcType
== OTHER
) {
2072 spanAngle
= prevDashAngle
;
2074 spanAngle
= FULLCIRCLE
- (-spanAngle
) % FULLCIRCLE
;
2075 if (spanAngle
>= FULLCIRCLE
)
2076 spanAngle
= spanAngle
% FULLCIRCLE
;
2077 xarc
.angle1
= spanAngle
;
2078 spanAngle
= dashAngle
- prevDashAngle
;
2080 if (dashAngle
> prevDashAngle
)
2081 spanAngle
= -FULLCIRCLE
+ spanAngle
;
2084 if (dashAngle
< prevDashAngle
)
2085 spanAngle
= FULLCIRCLE
+ spanAngle
;
2087 if (spanAngle
> FULLCIRCLE
)
2088 spanAngle
= FULLCIRCLE
;
2089 if (spanAngle
< -FULLCIRCLE
)
2090 spanAngle
= -FULLCIRCLE
;
2091 xarc
.angle2
= spanAngle
;
2093 arc
= addArc(&arcs
[iphase
].arcs
, &arcs
[iphase
].narcs
,
2094 &arcSize
[iphase
], &xarc
);
2098 * cap each end of an on/off dash
2100 if (!isDoubleDash
) {
2101 if (prevDashAngle
!= startAngle
) {
2102 addCap(&arcs
[iphase
].caps
,
2103 &arcs
[iphase
].ncaps
,
2104 &capSize
[iphase
], RIGHT_END
,
2105 arc
- arcs
[iphase
].arcs
);
2108 if (dashAngle
!= endAngle
) {
2109 addCap(&arcs
[iphase
].caps
,
2110 &arcs
[iphase
].ncaps
,
2111 &capSize
[iphase
], LEFT_END
,
2112 arc
- arcs
[iphase
].arcs
);
2115 arc
->cap
= arcs
[iphase
].ncaps
;
2116 arc
->join
= arcs
[iphase
].njoins
;
2119 if (dashAngle
== endAngle
)
2120 arc
->selfJoin
= selfJoin
;
2123 if (dashRemaining
<= 0) {
2125 if (iDash
== pGC
->numInDashList
)
2127 iphase
= iphase
? 0 : 1;
2128 dashRemaining
= pGC
->dash
[iDash
];
2132 * make sure a place exists for the position data when
2133 * drawing a zero-length arc
2135 if (startAngle
== endAngle
) {
2137 if (!isDoubleDash
&& iphase
== 1)
2139 arc
= addArc(&arcs
[prevphase
].arcs
, &arcs
[prevphase
].narcs
,
2140 &arcSize
[prevphase
], &parcs
[i
]);
2143 arc
->join
= arcs
[prevphase
].njoins
;
2144 arc
->cap
= arcs
[prevphase
].ncaps
;
2145 arc
->selfJoin
= data
[i
].selfJoin
;
2149 arc
= addArc(&arcs
[iphase
].arcs
, &arcs
[iphase
].narcs
,
2150 &arcSize
[iphase
], &parcs
[i
]);
2153 arc
->join
= arcs
[iphase
].njoins
;
2154 arc
->cap
= arcs
[iphase
].ncaps
;
2155 arc
->selfJoin
= data
[i
].selfJoin
;
2158 if (prevphase
== 0 || isDoubleDash
)
2159 k
= arcs
[prevphase
].narcs
- 1;
2160 if (iphase
== 0 || isDoubleDash
)
2161 nextk
= arcs
[iphase
].narcs
;
2162 if (nexti
== start
) {
2166 iphase
= iphaseStart
;
2167 dashRemaining
= dashRemainingStart
;
2170 arcsJoin
= narcs
> 1 && i
!= j
&&
2171 ISEQUAL(data
[i
].x1
, data
[j
].x0
) &&
2172 ISEQUAL(data
[i
].y1
, data
[j
].y0
) &&
2173 !data
[i
].selfJoin
&& !data
[j
].selfJoin
;
2181 (prevphase
== 0 || isDoubleDash
) && (iphase
== 0 || isDoubleDash
)) {
2185 joinphase
= iphaseStart
;
2187 * if the join is right at the dash,
2188 * draw the join in foreground
2189 * This is because the foreground
2190 * arcs are computed second, the results
2191 * of which are needed to draw the join
2193 if (joinphase
!= prevphase
)
2196 if (joinphase
== 0 || isDoubleDash
) {
2197 addJoin(&arcs
[joinphase
].joins
,
2198 &arcs
[joinphase
].njoins
,
2199 &joinSize
[joinphase
],
2200 LEFT_END
, k
, prevphase
, RIGHT_END
, nextk
, iphase
);
2201 arc
->join
= arcs
[prevphase
].njoins
;
2206 * cap the left end of this arc
2207 * unless it joins itself
2209 if ((prevphase
== 0 || isDoubleDash
) && !arc
->selfJoin
) {
2210 addCap(&arcs
[prevphase
].caps
, &arcs
[prevphase
].ncaps
,
2211 &capSize
[prevphase
], LEFT_END
, k
);
2212 arc
->cap
= arcs
[prevphase
].ncaps
;
2214 if (isDashed
&& !arcsJoin
) {
2216 iphase
= iphaseStart
;
2217 dashRemaining
= dashRemainingStart
;
2219 nextk
= arcs
[iphase
].narcs
;
2220 if (nexti
== start
) {
2223 iphase
= iphaseStart
;
2224 dashRemaining
= dashRemainingStart
;
2227 * cap the right end of the next arc. If the
2228 * next arc is actually the first arc, only
2229 * cap it if it joins with this arc. This
2230 * case will occur when the final dash segment
2231 * of an on/off dash is off. Of course, this
2232 * cap will be drawn at a strange time, but that
2235 if ((iphase
== 0 || isDoubleDash
) &&
2236 (nexti
!= start
|| (arcsJoin
&& isDashed
)))
2237 addCap(&arcs
[iphase
].caps
, &arcs
[iphase
].ncaps
,
2238 &capSize
[iphase
], RIGHT_END
, nextk
);
2245 * make sure the last section is rendered
2247 for (iphase
= 0; iphase
< (isDoubleDash
? 2 : 1); iphase
++)
2248 if (arcs
[iphase
].narcs
> 0) {
2249 arcs
[iphase
].arcs
[arcs
[iphase
].narcs
- 1].render
= 1;
2250 arcs
[iphase
].arcs
[arcs
[iphase
].narcs
- 1].join
=
2251 arcs
[iphase
].njoins
;
2252 arcs
[iphase
].arcs
[arcs
[iphase
].narcs
- 1].cap
= arcs
[iphase
].ncaps
;
2257 miFreeArcs(arcs
, pGC
);
2263 angleToLength(int angle
, dashMap
* map
)
2265 double len
, excesslen
, sidelen
= map
->map
[DASH_MAP_SIZE
- 1], totallen
;
2268 Bool oddSide
= FALSE
;
2272 while (angle
>= 90 * 64) {
2274 totallen
+= sidelen
;
2281 totallen
-= sidelen
;
2286 angle
= 90 * 64 - angle
;
2288 di
= xAngleToDashIndex(angle
);
2289 excess
= angle
- dashIndexToXAngle(di
);
2293 * linearly interpolate between this point and the next
2296 excesslen
= (map
->map
[di
+ 1] - map
->map
[di
]) *
2297 ((double) excess
) / dashXAngleStep
;
2301 totallen
+= (sidelen
- len
);
2308 * len is along the arc, but may be more than one rotation
2312 lengthToAngle(double len
, dashMap
* map
)
2314 double sidelen
= map
->map
[DASH_MAP_SIZE
- 1];
2315 int angle
, angleexcess
;
2316 Bool oddSide
= FALSE
;
2321 * step around the ellipse, subtracting sidelens and
2322 * adding 90 degrees. oddSide will tell if the
2323 * map should be interpolated in reverse
2327 return 2 * FULLCIRCLE
; /* infinity */
2328 while (len
>= sidelen
) {
2336 return -2 * FULLCIRCLE
; /* infinity */
2344 len
= sidelen
- len
;
2346 a1
= DASH_MAP_SIZE
- 1;
2348 * binary search for the closest pre-computed length
2350 while (a1
- a0
> 1) {
2352 if (len
> map
->map
[a
])
2357 angleexcess
= dashIndexToXAngle(a0
);
2359 * linearly interpolate to the next point
2361 angleexcess
+= (len
- map
->map
[a0
]) /
2362 (map
->map
[a0
+ 1] - map
->map
[a0
]) * dashXAngleStep
;
2364 angle
+= (90 * 64) - angleexcess
;
2366 angle
+= angleexcess
;
2371 * compute the angle of an ellipse which corresponds to
2372 * the given path length. Note that the correct solution
2373 * to this problem is an eliptic integral, we'll punt and
2374 * approximate (it's only for dashes anyway). This
2375 * approximation uses a polygon.
2377 * The remaining portion of len is stored in *lenp -
2378 * this will be negative if the arc extends beyond
2379 * len and positive if len extends beyond the arc.
2383 computeAngleFromPath(int startAngle
, int endAngle
, /* normalized absolute angles in *64 degrees */
2384 dashMap
* map
, int *lenp
, int backwards
)
2395 * flip the problem around to always be
2398 a0
= FULLCIRCLE
- a0
;
2399 a1
= FULLCIRCLE
- a1
;
2403 len0
= angleToLength(a0
, map
);
2404 a
= lengthToAngle(len0
+ len
, map
);
2407 len
-= angleToLength(a1
, map
) - len0
;
2418 * scan convert wide arcs.
2422 * draw zero width/height arcs
2426 drawZeroArc(DrawablePtr pDraw
,
2428 xArc
* tarc
, int lw
, miArcFacePtr left
, miArcFacePtr right
)
2430 double x0
= 0.0, y0
= 0.0, x1
= 0.0, y1
= 0.0, w
, h
, x
, y
;
2431 double xmax
, ymax
, xmin
, ymin
;
2433 double a
, startAngle
, endAngle
;
2439 if (a1
> FULLCIRCLE
)
2441 else if (a1
< -FULLCIRCLE
)
2443 w
= (double) tarc
->width
/ 2.0;
2444 h
= (double) tarc
->height
/ 2.0;
2446 * play in X coordinates right away
2448 startAngle
= -((double) a0
/ 64.0);
2449 endAngle
= -((double) (a0
+ a1
) / 64.0);
2459 if (a
== startAngle
) {
2463 if (a
== endAngle
) {
2477 if (a1
< 0) { /* clockwise */
2478 if (floor(a
/ 90.0) == floor(endAngle
/ 90.0))
2481 a
= 90 * (floor(a
/ 90.0) + 1);
2484 if (ceil(a
/ 90.0) == ceil(endAngle
/ 90.0))
2487 a
= 90 * (ceil(a
/ 90.0) - 1);
2491 if ((x1
- x0
) + (y1
- y0
) < 0)
2500 right
->center
.x
= x0
;
2501 right
->center
.y
= y0
;
2502 right
->clock
.x
= x0
- lx
;
2503 right
->clock
.y
= y0
- ly
;
2504 right
->counterClock
.x
= x0
+ lx
;
2505 right
->counterClock
.y
= y0
+ ly
;
2508 left
->center
.x
= x1
;
2509 left
->center
.y
= y1
;
2510 left
->clock
.x
= x1
+ lx
;
2511 left
->clock
.y
= y1
+ ly
;
2512 left
->counterClock
.x
= x1
- lx
;
2513 left
->counterClock
.y
= y1
- ly
;
2528 if (xmax
!= xmin
&& ymax
!= ymin
) {
2529 int minx
, maxx
, miny
, maxy
;
2532 minx
= ICEIL(xmin
+ w
) + tarc
->x
;
2533 maxx
= ICEIL(xmax
+ w
) + tarc
->x
;
2534 miny
= ICEIL(ymin
+ h
) + tarc
->y
;
2535 maxy
= ICEIL(ymax
+ h
) + tarc
->y
;
2538 rect
.width
= maxx
- minx
;
2539 rect
.height
= maxy
- miny
;
2540 (*pGC
->ops
->PolyFillRect
) (pDraw
, pGC
, 1, &rect
);
2545 * this computes the ellipse y value associated with the
2546 * bottom of the tail.
2550 tailEllipseY(struct arc_def
*def
, struct accelerators
*acc
)
2555 if (def
->w
== def
->h
)
2557 t
= def
->l
* def
->w
;
2558 if (def
->w
> def
->h
) {
2566 t
= 2.0 * def
->h
* t
;
2567 t
= (CUBED_ROOT_4
* acc
->h2
- cbrt(t
* t
)) / acc
->h2mw2
;
2569 acc
->tail_y
= def
->h
/ CUBED_ROOT_2
* sqrt(t
);
2573 * inverse functions -- compute edge coordinates
2578 outerXfromXY(double x
, double y
, struct arc_def
*def
, struct accelerators
*acc
)
2580 return x
+ (x
* acc
->h2l
) / sqrt(x
* x
* acc
->h4
+ y
* y
* acc
->w4
);
2584 outerYfromXY(double x
, double y
, struct arc_def
*def
, struct accelerators
*acc
)
2586 return y
+ (y
* acc
->w2l
) / sqrt(x
* x
* acc
->h4
+ y
* y
* acc
->w4
);
2590 innerXfromXY(double x
, double y
, struct arc_def
*def
, struct accelerators
*acc
)
2592 return x
- (x
* acc
->h2l
) / sqrt(x
* x
* acc
->h4
+ y
* y
* acc
->w4
);
2596 innerYfromXY(double x
, double y
, struct arc_def
*def
, struct accelerators
*acc
)
2598 return y
- (y
* acc
->w2l
) / sqrt(x
* x
* acc
->h4
+ y
* y
* acc
->w4
);
2602 innerYfromY(double y
, struct arc_def
*def
, struct accelerators
*acc
)
2606 x
= (def
->w
/ def
->h
) * sqrt(acc
->h2
- y
* y
);
2608 return y
- (y
* acc
->w2l
) / sqrt(x
* x
* acc
->h4
+ y
* y
* acc
->w4
);
2612 computeLine(double x1
, double y1
, double x2
, double y2
, struct line
*line
)
2617 line
->m
= (x1
- x2
) / (y1
- y2
);
2618 line
->b
= x1
- y1
* line
->m
;
2624 * compute various accelerators for an ellipse. These
2625 * are simply values that are used repeatedly in
2630 computeAcc(xArc
* tarc
, int lw
, struct arc_def
*def
, struct accelerators
*acc
)
2632 def
->w
= ((double) tarc
->width
) / 2.0;
2633 def
->h
= ((double) tarc
->height
) / 2.0;
2634 def
->l
= ((double) lw
) / 2.0;
2635 acc
->h2
= def
->h
* def
->h
;
2636 acc
->w2
= def
->w
* def
->w
;
2637 acc
->h4
= acc
->h2
* acc
->h2
;
2638 acc
->w4
= acc
->w2
* acc
->w2
;
2639 acc
->h2l
= acc
->h2
* def
->l
;
2640 acc
->w2l
= acc
->w2
* def
->l
;
2641 acc
->h2mw2
= acc
->h2
- acc
->w2
;
2642 acc
->fromIntX
= (tarc
->width
& 1) ? 0.5 : 0.0;
2643 acc
->fromIntY
= (tarc
->height
& 1) ? 0.5 : 0.0;
2644 acc
->xorg
= tarc
->x
+ (tarc
->width
>> 1);
2645 acc
->yorgu
= tarc
->y
+ (tarc
->height
>> 1);
2646 acc
->yorgl
= acc
->yorgu
+ (tarc
->height
& 1);
2647 tailEllipseY(def
, acc
);
2651 * compute y value bounds of various portions of the arc,
2652 * the outer edge, the ellipse and the inner edge.
2656 computeBound(struct arc_def
*def
,
2657 struct arc_bound
*bound
,
2658 struct accelerators
*acc
, miArcFacePtr right
, miArcFacePtr left
)
2663 struct bound innerx
, outerx
;
2664 struct bound ellipsex
;
2666 bound
->ellipse
.min
= Dsin(def
->a0
) * def
->h
;
2667 bound
->ellipse
.max
= Dsin(def
->a1
) * def
->h
;
2668 if (def
->a0
== 45 && def
->w
== def
->h
)
2669 ellipsex
.min
= bound
->ellipse
.min
;
2671 ellipsex
.min
= Dcos(def
->a0
) * def
->w
;
2672 if (def
->a1
== 45 && def
->w
== def
->h
)
2673 ellipsex
.max
= bound
->ellipse
.max
;
2675 ellipsex
.max
= Dcos(def
->a1
) * def
->w
;
2676 bound
->outer
.min
= outerYfromXY(ellipsex
.min
, bound
->ellipse
.min
, def
, acc
);
2677 bound
->outer
.max
= outerYfromXY(ellipsex
.max
, bound
->ellipse
.max
, def
, acc
);
2678 bound
->inner
.min
= innerYfromXY(ellipsex
.min
, bound
->ellipse
.min
, def
, acc
);
2679 bound
->inner
.max
= innerYfromXY(ellipsex
.max
, bound
->ellipse
.max
, def
, acc
);
2681 outerx
.min
= outerXfromXY(ellipsex
.min
, bound
->ellipse
.min
, def
, acc
);
2682 outerx
.max
= outerXfromXY(ellipsex
.max
, bound
->ellipse
.max
, def
, acc
);
2683 innerx
.min
= innerXfromXY(ellipsex
.min
, bound
->ellipse
.min
, def
, acc
);
2684 innerx
.max
= innerXfromXY(ellipsex
.max
, bound
->ellipse
.max
, def
, acc
);
2687 * save the line end points for the
2688 * cap code to use. Careful here, these are
2689 * in cartesean coordinates (y increasing upwards)
2690 * while the cap code uses inverted coordinates
2691 * (y increasing downwards)
2695 right
->counterClock
.y
= bound
->outer
.min
;
2696 right
->counterClock
.x
= outerx
.min
;
2697 right
->center
.y
= bound
->ellipse
.min
;
2698 right
->center
.x
= ellipsex
.min
;
2699 right
->clock
.y
= bound
->inner
.min
;
2700 right
->clock
.x
= innerx
.min
;
2704 left
->clock
.y
= bound
->outer
.max
;
2705 left
->clock
.x
= outerx
.max
;
2706 left
->center
.y
= bound
->ellipse
.max
;
2707 left
->center
.x
= ellipsex
.max
;
2708 left
->counterClock
.y
= bound
->inner
.max
;
2709 left
->counterClock
.x
= innerx
.max
;
2712 bound
->left
.min
= bound
->inner
.max
;
2713 bound
->left
.max
= bound
->outer
.max
;
2714 bound
->right
.min
= bound
->inner
.min
;
2715 bound
->right
.max
= bound
->outer
.min
;
2717 computeLine(innerx
.min
, bound
->inner
.min
, outerx
.min
, bound
->outer
.min
,
2719 computeLine(innerx
.max
, bound
->inner
.max
, outerx
.max
, bound
->outer
.max
,
2722 if (bound
->inner
.min
> bound
->inner
.max
) {
2723 t
= bound
->inner
.min
;
2724 bound
->inner
.min
= bound
->inner
.max
;
2725 bound
->inner
.max
= t
;
2727 tail_y
= acc
->tail_y
;
2728 if (tail_y
> bound
->ellipse
.max
)
2729 tail_y
= bound
->ellipse
.max
;
2730 else if (tail_y
< bound
->ellipse
.min
)
2731 tail_y
= bound
->ellipse
.min
;
2732 innerTaily
= innerYfromY(tail_y
, def
, acc
);
2733 if (bound
->inner
.min
> innerTaily
)
2734 bound
->inner
.min
= innerTaily
;
2735 if (bound
->inner
.max
< innerTaily
)
2736 bound
->inner
.max
= innerTaily
;
2737 bound
->inneri
.min
= ICEIL(bound
->inner
.min
- acc
->fromIntY
);
2738 bound
->inneri
.max
= floor(bound
->inner
.max
- acc
->fromIntY
);
2739 bound
->outeri
.min
= ICEIL(bound
->outer
.min
- acc
->fromIntY
);
2740 bound
->outeri
.max
= floor(bound
->outer
.max
- acc
->fromIntY
);
2744 * this section computes the x value of the span at y
2745 * intersected with the specified face of the ellipse.
2747 * this is the min/max X value over the set of normal
2748 * lines to the entire ellipse, the equation of the
2752 * x = ------------ y + ellipse_x (1 - --- )
2755 * compute the derivative with-respect-to ellipse_y and solve
2758 * (w^2 - h^2) ellipse_y^3 + h^4 y
2759 * 0 = - ----------------------------------
2760 * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
2763 * ellipse_y = ( ---------- ) ^ (1/3)
2766 * The other two solutions to the equation are imaginary.
2768 * This gives the position on the ellipse which generates
2769 * the normal with the largest/smallest x intersection point.
2771 * Now compute the second derivative to check whether
2772 * the intersection is a minimum or maximum:
2774 * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2775 * - -------------------------------------------
2776 * w y0^3 (sqrt (h^2 - y^2)) ^ 3
2778 * as we only care about the sign,
2780 * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2782 * or (to use accelerators),
2784 * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2)
2789 * computes the position on the ellipse whose normal line
2790 * intersects the given scan line maximally
2794 hookEllipseY(double scan_y
,
2795 struct arc_bound
*bound
, struct accelerators
*acc
, int left
)
2799 if (acc
->h2mw2
== 0) {
2800 if ((scan_y
> 0 && !left
) || (scan_y
< 0 && left
))
2801 return bound
->ellipse
.min
;
2802 return bound
->ellipse
.max
;
2804 ret
= (acc
->h4
* scan_y
) / (acc
->h2mw2
);
2812 * computes the X value of the intersection of the
2813 * given scan line with the right side of the lower hook
2817 hookX(double scan_y
,
2818 struct arc_def
*def
,
2819 struct arc_bound
*bound
, struct accelerators
*acc
, int left
)
2821 double ellipse_y
, x
;
2824 if (def
->w
!= def
->h
) {
2825 ellipse_y
= hookEllipseY(scan_y
, bound
, acc
, left
);
2826 if (boundedLe(ellipse_y
, bound
->ellipse
)) {
2828 * compute the value of the second
2831 maxMin
= ellipse_y
* ellipse_y
* ellipse_y
* acc
->h2mw2
-
2832 acc
->h2
* scan_y
* (3 * ellipse_y
* ellipse_y
- 2 * acc
->h2
);
2833 if ((left
&& maxMin
> 0) || (!left
&& maxMin
< 0)) {
2835 return def
->w
+ left
? -def
->l
: def
->l
;
2836 x
= (acc
->h2
* scan_y
- ellipse_y
* acc
->h2mw2
) *
2837 sqrt(acc
->h2
- ellipse_y
* ellipse_y
) /
2838 (def
->h
* def
->w
* ellipse_y
);
2844 if (acc
->left
.valid
&& boundedLe(scan_y
, bound
->left
)) {
2845 x
= intersectLine(scan_y
, acc
->left
);
2848 if (acc
->right
.valid
)
2849 x
= intersectLine(scan_y
, acc
->right
);
2851 x
= def
->w
- def
->l
;
2855 if (acc
->right
.valid
&& boundedLe(scan_y
, bound
->right
)) {
2856 x
= intersectLine(scan_y
, acc
->right
);
2859 if (acc
->left
.valid
)
2860 x
= intersectLine(scan_y
, acc
->left
);
2862 x
= def
->w
- def
->l
;
2869 * generate the set of spans with
2870 * the given y coordinate
2879 struct arc_def
*def
,
2880 struct arc_bound
*bounds
, struct accelerators
*acc
, int mask
)
2882 int linx
, loutx
, rinx
, routx
;
2885 if (boundedLe(y
, bounds
->inneri
)) {
2891 * intersection with left face
2893 x
= hookX(y
+ acc
->fromIntY
, def
, bounds
, acc
, 1);
2894 if (acc
->right
.valid
&& boundedLe(y
+ acc
->fromIntY
, bounds
->right
)) {
2895 altx
= intersectLine(y
+ acc
->fromIntY
, acc
->right
);
2899 linx
= -ICEIL(acc
->fromIntX
- x
);
2900 rinx
= ICEIL(acc
->fromIntX
+ x
);
2902 if (boundedLe(y
, bounds
->outeri
)) {
2908 * intersection with right face
2910 x
= hookX(y
+ acc
->fromIntY
, def
, bounds
, acc
, 0);
2911 if (acc
->left
.valid
&& boundedLe(y
+ acc
->fromIntY
, bounds
->left
)) {
2913 x
= intersectLine(y
+ acc
->fromIntY
, acc
->left
);
2917 loutx
= -ICEIL(acc
->fromIntX
- x
);
2918 routx
= ICEIL(acc
->fromIntX
+ x
);
2922 newFinalSpan(acc
->yorgu
- y
, acc
->xorg
+ rinx
, acc
->xorg
+ routx
);
2924 newFinalSpan(acc
->yorgl
+ y
, acc
->xorg
+ rinx
, acc
->xorg
+ routx
);
2928 newFinalSpan(acc
->yorgu
- y
, acc
->xorg
- loutx
, acc
->xorg
- linx
);
2930 newFinalSpan(acc
->yorgl
+ y
, acc
->xorg
- loutx
, acc
->xorg
- linx
);
2939 struct arc_def
*def
,
2940 struct arc_bound
*bounds
, struct accelerators
*acc
, int mask
)
2944 if (boundedLe(0, bounds
->inneri
) &&
2945 acc
->left
.valid
&& boundedLe(0, bounds
->left
) && acc
->left
.b
> 0) {
2946 x
= def
->w
- def
->l
;
2947 if (acc
->left
.b
< x
)
2949 lw
= ICEIL(acc
->fromIntX
- x
) - lx
;
2951 rx
= ICEIL(acc
->fromIntX
+ x
);
2954 arcSpan(0, lx
, lw
, rx
, rw
, def
, bounds
, acc
, mask
);
2961 struct arc_def
*def
,
2962 struct arc_bound
*bounds
, struct accelerators
*acc
, int mask
)
2964 double yy
, xalt
, x
, lx
, rx
;
2967 if (boundedLe(y
, bounds
->outeri
))
2968 arcSpan(y
, 0, lw
, -rw
, rw
, def
, bounds
, acc
, mask
);
2969 else if (def
->w
!= def
->h
) {
2970 yy
= y
+ acc
->fromIntY
;
2971 x
= tailX(yy
, def
, bounds
, acc
);
2972 if (yy
== 0.0 && x
== -rw
- acc
->fromIntX
)
2974 if (acc
->right
.valid
&& boundedLe(yy
, bounds
->right
)) {
2977 xalt
= intersectLine(yy
, acc
->right
);
2978 if (xalt
>= -rw
- acc
->fromIntX
&& xalt
<= rx
)
2980 n
= ICEIL(acc
->fromIntX
+ lx
);
2983 newFinalSpan(acc
->yorgu
- y
, acc
->xorg
+ n
, acc
->xorg
+ lw
);
2985 newFinalSpan(acc
->yorgl
+ y
, acc
->xorg
+ n
, acc
->xorg
+ lw
);
2987 n
= ICEIL(acc
->fromIntX
+ rx
);
2990 newFinalSpan(acc
->yorgu
- y
, acc
->xorg
- rw
, acc
->xorg
+ n
);
2992 newFinalSpan(acc
->yorgl
+ y
, acc
->xorg
- rw
, acc
->xorg
+ n
);
2996 ICEIL(acc
->fromIntX
- x
), 0,
2997 ICEIL(acc
->fromIntX
+ x
), 0, def
, bounds
, acc
, mask
);
3002 * create whole arcs out of pieces. This code is
3006 static struct finalSpan
**finalSpans
= NULL
;
3007 static int finalMiny
= 0, finalMaxy
= -1;
3008 static int finalSize
= 0;
3010 static int nspans
= 0; /* total spans, not just y coords */
3013 struct finalSpan
*next
;
3014 int min
, max
; /* x values */
3017 static struct finalSpan
*freeFinalSpans
, *tmpFinalSpan
;
3019 #define allocFinalSpan() (freeFinalSpans ?\
3020 ((tmpFinalSpan = freeFinalSpans), \
3021 (freeFinalSpans = freeFinalSpans->next), \
3022 (tmpFinalSpan->next = 0), \
3026 #define SPAN_CHUNK_SIZE 128
3028 struct finalSpanChunk
{
3029 struct finalSpan data
[SPAN_CHUNK_SIZE
];
3030 struct finalSpanChunk
*next
;
3033 static struct finalSpanChunk
*chunks
;
3035 static struct finalSpan
*
3038 struct finalSpanChunk
*newChunk
;
3039 struct finalSpan
*span
;
3042 newChunk
= malloc(sizeof(struct finalSpanChunk
));
3044 return (struct finalSpan
*) NULL
;
3045 newChunk
->next
= chunks
;
3047 freeFinalSpans
= span
= newChunk
->data
+ 1;
3048 for (i
= 1; i
< SPAN_CHUNK_SIZE
- 1; i
++) {
3049 span
->next
= span
+ 1;
3053 span
= newChunk
->data
;
3059 disposeFinalSpans(void)
3061 struct finalSpanChunk
*chunk
, *next
;
3063 for (chunk
= chunks
; chunk
; chunk
= next
) {
3074 fillSpans(DrawablePtr pDrawable
, GCPtr pGC
)
3076 struct finalSpan
*span
;
3080 struct finalSpan
**f
;
3087 xSpan
= xSpans
= xallocarray(nspans
, sizeof(DDXPointRec
));
3088 xWidth
= xWidths
= xallocarray(nspans
, sizeof(int));
3089 if (xSpans
&& xWidths
) {
3092 for (spany
= finalMiny
; spany
<= finalMaxy
; spany
++, f
++) {
3093 for (span
= *f
; span
; span
= span
->next
) {
3094 if (span
->max
<= span
->min
)
3096 xSpan
->x
= span
->min
;
3099 *xWidth
++ = span
->max
- span
->min
;
3103 (*pGC
->ops
->FillSpans
) (pDrawable
, pGC
, i
, xSpans
, xWidths
, TRUE
);
3105 disposeFinalSpans();
3114 #define SPAN_REALLOC 100
3116 #define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \
3117 &finalSpans[(y) - finalMiny] : \
3120 static struct finalSpan
**
3123 struct finalSpan
**newSpans
;
3124 int newSize
, newMiny
, newMaxy
;
3128 if (y
< finalMiny
|| y
> finalMaxy
) {
3134 change
= finalMiny
- y
;
3136 change
= y
- finalMaxy
;
3137 if (change
>= SPAN_REALLOC
)
3138 change
+= SPAN_REALLOC
;
3140 change
= SPAN_REALLOC
;
3141 newSize
= finalSize
+ change
;
3142 newSpans
= xallocarray(newSize
, sizeof(struct finalSpan
*));
3145 newMiny
= finalMiny
;
3146 newMaxy
= finalMaxy
;
3148 newMiny
= finalMiny
- change
;
3150 newMaxy
= finalMaxy
+ change
;
3152 memcpy(((char *) newSpans
) +
3153 (finalMiny
- newMiny
) * sizeof(struct finalSpan
*),
3155 finalSize
* sizeof(struct finalSpan
*));
3158 if ((i
= finalMiny
- newMiny
) > 0)
3159 memset((char *) newSpans
, 0, i
* sizeof(struct finalSpan
*));
3160 if ((i
= newMaxy
- finalMaxy
) > 0)
3161 memset((char *) (newSpans
+ newSize
- i
), 0,
3162 i
* sizeof(struct finalSpan
*));
3163 finalSpans
= newSpans
;
3164 finalMaxy
= newMaxy
;
3165 finalMiny
= newMiny
;
3166 finalSize
= newSize
;
3168 return &finalSpans
[y
- finalMiny
];
3172 newFinalSpan(int y
, int xmin
, int xmax
)
3174 struct finalSpan
*x
;
3175 struct finalSpan
**f
;
3176 struct finalSpan
*oldx
;
3177 struct finalSpan
*prev
;
3185 for (x
= *f
; x
; x
= x
->next
) {
3190 if (x
->min
<= xmax
&& xmin
<= x
->max
) {
3192 oldx
->min
= min(x
->min
, xmin
);
3193 oldx
->max
= max(x
->max
, xmax
);
3195 prev
->next
= x
->next
;
3201 x
->min
= min(x
->min
, xmin
);
3202 x
->max
= max(x
->max
, xmax
);
3215 x
= allocFinalSpan();
3227 mirrorSppPoint(int quadrant
, SppPointPtr sppPoint
)
3233 sppPoint
->x
= -sppPoint
->x
;
3236 sppPoint
->x
= -sppPoint
->x
;
3237 sppPoint
->y
= -sppPoint
->y
;
3240 sppPoint
->y
= -sppPoint
->y
;
3244 * and translate to X coordinate system
3246 sppPoint
->y
= -sppPoint
->y
;
3250 * split an arc into pieces which are scan-converted
3251 * in the first-quadrant and mirrored into position.
3252 * This is necessary as the scan-conversion code can
3253 * only deal with arcs completely contained in the
3257 static miArcSpanData
*
3258 drawArc(xArc
* tarc
, int l
, int a0
, int a1
, miArcFacePtr right
,
3259 miArcFacePtr left
, miArcSpanData
*spdata
)
3260 { /* save end line points */
3262 struct accelerators acc
;
3263 int startq
, endq
, curq
;
3264 int rightq
, leftq
= 0, righta
= 0, lefta
= 0;
3265 miArcFacePtr passRight
, passLeft
;
3266 int q0
= 0, q1
= 0, mask
;
3270 } band
[5], sweep
[20];
3271 int bandno
, sweepno
;
3273 int flipRight
= 0, flipLeft
= 0;
3277 spdata
= miComputeWideEllipse(l
, tarc
);
3283 startq
= a0
/ (90 * 64);
3287 endq
= (a1
- 1) / (90 * 64);
3299 q1
= min(a1
, 90 * 64);
3302 if (curq
== startq
&& a0
== q0
&& rightq
< 0) {
3306 if (curq
== endq
&& a1
== q1
) {
3315 q0
= 180 * 64 - min(a1
, 180 * 64);
3319 q1
= 180 * 64 - max(a0
, 90 * 64);
3320 if (curq
== startq
&& 180 * 64 - a0
== q1
) {
3324 if (curq
== endq
&& 180 * 64 - a1
== q0
) {
3333 q0
= max(a0
, 180 * 64) - 180 * 64;
3337 q1
= min(a1
, 270 * 64) - 180 * 64;
3338 if (curq
== startq
&& a0
- 180 * 64 == q0
) {
3342 if (curq
== endq
&& a1
- 180 * 64 == q1
) {
3351 q0
= 360 * 64 - min(a1
, 360 * 64);
3352 q1
= 360 * 64 - max(a0
, 270 * 64);
3353 if (curq
== startq
&& 360 * 64 - a0
== q1
) {
3357 if (curq
== endq
&& 360 * 64 - a1
== q0
) {
3363 band
[bandno
].a0
= q0
;
3364 band
[bandno
].a1
= q1
;
3365 band
[bandno
].mask
= 1 << curq
;
3382 * find left-most point
3384 for (i
= 0; i
< bandno
; i
++)
3385 if (band
[i
].a0
<= q0
) {
3388 mask
= band
[i
].mask
;
3393 * locate next point of change
3395 for (i
= 0; i
< bandno
; i
++)
3396 if (!(mask
& band
[i
].mask
)) {
3397 if (band
[i
].a0
== q0
) {
3398 if (band
[i
].a1
< q1
)
3400 mask
|= band
[i
].mask
;
3402 else if (band
[i
].a0
< q1
)
3406 * create a new sweep
3408 sweep
[sweepno
].a0
= q0
;
3409 sweep
[sweepno
].a1
= q1
;
3410 sweep
[sweepno
].mask
= mask
;
3413 * subtract the sweep from the affected bands
3415 for (i
= 0; i
< bandno
; i
++)
3416 if (band
[i
].a0
== q0
) {
3419 * check if this band is empty
3421 if (band
[i
].a0
== band
[i
].a1
)
3422 band
[i
].a1
= band
[i
].a0
= 90 * 64 + 1;
3425 computeAcc(tarc
, l
, &def
, &acc
);
3426 for (j
= 0; j
< sweepno
; j
++) {
3427 mask
= sweep
[j
].mask
;
3428 passRight
= passLeft
= 0;
3429 if (mask
& (1 << rightq
)) {
3430 if (sweep
[j
].a0
== righta
)
3432 else if (sweep
[j
].a1
== righta
) {
3437 if (mask
& (1 << leftq
)) {
3438 if (sweep
[j
].a1
== lefta
) {
3443 else if (sweep
[j
].a0
== lefta
) {
3450 drawQuadrant(&def
, &acc
, sweep
[j
].a0
, sweep
[j
].a1
, mask
,
3451 passRight
, passLeft
, spdata
);
3454 * when copyEnd is set, both ends of the arc were computed
3455 * at the same time; drawQuadrant only takes one end though,
3456 * so the left end will be the only one holding the data. Copy
3462 * mirror the coordinates generated for the
3466 mirrorSppPoint(rightq
, &right
->clock
);
3467 mirrorSppPoint(rightq
, &right
->center
);
3468 mirrorSppPoint(rightq
, &right
->counterClock
);
3472 temp
= right
->clock
;
3473 right
->clock
= right
->counterClock
;
3474 right
->counterClock
= temp
;
3478 mirrorSppPoint(leftq
, &left
->counterClock
);
3479 mirrorSppPoint(leftq
, &left
->center
);
3480 mirrorSppPoint(leftq
, &left
->clock
);
3485 left
->clock
= left
->counterClock
;
3486 left
->counterClock
= temp
;
3493 drawQuadrant(struct arc_def
*def
,
3494 struct accelerators
*acc
,
3498 miArcFacePtr right
, miArcFacePtr left
, miArcSpanData
* spdata
)
3500 struct arc_bound bound
;
3506 def
->a0
= ((double) a0
) / 64.0;
3507 def
->a1
= ((double) a1
) / 64.0;
3508 computeBound(def
, &bound
, acc
, right
, left
);
3509 yy
= bound
.inner
.min
;
3510 if (bound
.outer
.min
< yy
)
3511 yy
= bound
.outer
.min
;
3512 miny
= ICEIL(yy
- acc
->fromIntY
);
3513 yy
= bound
.inner
.max
;
3514 if (bound
.outer
.max
> yy
)
3515 yy
= bound
.outer
.max
;
3516 maxy
= floor(yy
- acc
->fromIntY
);
3518 span
= spdata
->spans
;
3520 if (a1
== 90 * 64 && (mask
& 1))
3521 newFinalSpan(acc
->yorgu
- y
- 1, acc
->xorg
, acc
->xorg
+ 1);
3524 for (n
= spdata
->count1
; --n
>= 0;) {
3529 span
->lx
, -span
->lx
, 0, span
->lx
+ span
->lw
,
3530 def
, &bound
, acc
, mask
);
3531 if (span
->rw
+ span
->rx
)
3532 tailSpan(y
, -span
->rw
, -span
->rx
, def
, &bound
, acc
, mask
);
3541 arcSpan(y
, 0, 0, 0, 1, def
, &bound
, acc
, mask
& 0xc);
3543 for (n
= spdata
->count2
; --n
>= 0;) {
3547 arcSpan(y
, span
->lx
, span
->lw
, span
->rx
, span
->rw
,
3548 def
, &bound
, acc
, mask
);
3552 if (spdata
->bot
&& miny
<= y
&& y
<= maxy
) {
3556 if (span
->rw
<= 0) {
3557 arcSpan0(span
->lx
, -span
->lx
, 0, span
->lx
+ span
->lw
,
3558 def
, &bound
, acc
, n
);
3559 if (span
->rw
+ span
->rx
)
3560 tailSpan(y
, -span
->rw
, -span
->rx
, def
, &bound
, acc
, n
);
3563 arcSpan0(span
->lx
, span
->lw
, span
->rx
, span
->rw
,
3564 def
, &bound
, acc
, n
);
3568 yy
= y
+ acc
->fromIntY
;
3569 if (def
->w
== def
->h
) {
3570 xalt
= def
->w
- def
->l
;
3571 x
= -sqrt(xalt
* xalt
- yy
* yy
);
3574 x
= tailX(yy
, def
, &bound
, acc
);
3575 if (acc
->left
.valid
&& boundedLe(yy
, bound
.left
)) {
3576 xalt
= intersectLine(yy
, acc
->left
);
3580 if (acc
->right
.valid
&& boundedLe(yy
, bound
.right
)) {
3581 xalt
= intersectLine(yy
, acc
->right
);
3587 ICEIL(acc
->fromIntX
- x
), 0,
3588 ICEIL(acc
->fromIntX
+ x
), 0, def
, &bound
, acc
, mask
);
3594 miPolyArc(DrawablePtr pDraw
, GCPtr pGC
, int narcs
, xArc
* parcs
)
3596 if (pGC
->lineWidth
== 0)
3597 miZeroPolyArc(pDraw
, pGC
, narcs
, parcs
);
3599 miWideArc(pDraw
, pGC
, narcs
, parcs
);