miarc.c 84 KB

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