mi_widelin.c 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307
  1. /* This file is part of the GNU libxmi package.
  2. Copyright (C) 1985, 1986, 1987, 1988, 1989, X Consortium. For an
  3. associated permission notice, see the accompanying file README-X.
  4. GNU enhancements Copyright (C) 1998, 1999, 2000, 2005, Free Software
  5. Foundation, Inc.
  6. The GNU libxmi package is free software. You may redistribute it
  7. and/or modify it under the terms of the GNU General Public License as
  8. published by the Free Software foundation; either version 2, or (at your
  9. option) any later version.
  10. The GNU libxmi package is distributed in the hope that it will be
  11. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with the GNU plotutils package; see the file COPYING. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  17. Boston, MA 02110-1301, USA. */
  18. #include "sys-defines.h"
  19. #include "extern.h"
  20. /* Original author: Keith Packard, MIT X Consortium.
  21. Hacked by Robert S. Maier, 1998-99. */
  22. /* This module contains the miWideLine() and miWideDash() functions. They
  23. rasterize wide polylines (usually just called `wide lines'), either
  24. solid or dashed.
  25. Any wide line is treated as a polygon to be painted. (If it is dashed,
  26. each dash is treated as a polygon.) The painting follows libxmi's
  27. policy on painting of `edge' pixels, i.e., pixels that lie exactly on a
  28. boundary. A pixel is not painted if it lies on a `right' or `bottom'
  29. edge of a polygon.
  30. All painting goes through the low-level MI_PAINT_SPANS() macro. */
  31. #include "xmi.h"
  32. #include "mi_spans.h"
  33. #include "mi_gc.h"
  34. #include "mi_api.h"
  35. #include "mi_widelin.h"
  36. /* undefine if hypot is available (it's X_OPEN, but not ANSI or POSIX) */
  37. #define hypot(x, y) sqrt((x)*(x) + (y)*(y))
  38. /* internal functions that do painting of pixels */
  39. static void miFillPolyHelper (miPaintedSet *paintedSet, miPixel pixel, int y, unsigned int overall_height, PolyEdge *left, PolyEdge *right, int left_count, int right_count);
  40. static void miFillRectPolyHelper (miPaintedSet *paintedSet, miPixel pixel, int x, int y, unsigned int w, unsigned int h);
  41. static void miLineArc (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, LineFace *leftFace, LineFace *rightFace, double xorg, double yorg, bool isInt);
  42. static void miLineJoin (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, LineFace *pLeft, LineFace *pRight);
  43. static void miLineProjectingCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const LineFace *face, bool isLeft, bool isInt);
  44. static void miWideDashSegment (miPaintedSet *paintedSet, const miGC *pGC, int *pDashNum, int *pDashIndex, int *pDashOffset, int x1, int y1, int x2, int y2, bool projectLeft, bool projectRight, LineFace *leftFace, LineFace *rightFace);
  45. static void miWideSegment (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, int x1, int y1, int x2, int y2, bool projectLeft, bool projectRight, LineFace *leftFace, LineFace *rightFace);
  46. /* internal functions that don't do painting of pixels */
  47. static int miLineArcD (const miGC *pGC, double xorg, double yorg, miPoint *points, unsigned int *widths, PolyEdge *edge1, int edgey1, bool edgeleft1, PolyEdge *edge2, int edgey2, bool edgeleft2);
  48. static int miLineArcI (const miGC *pGC, int xorg, int yorg, miPoint *points, unsigned int *widths);
  49. static int miPolyBuildEdge (double x0, double y0, double k, int dx, int dy, int xi, int yi, bool left, PolyEdge *edge);
  50. static int miPolyBuildPoly (const PolyVertex *vertices, const PolySlope *slopes, int count, int xi, int yi, PolyEdge *left, PolyEdge *right, int *pnleft, int *pnright, unsigned int *h);
  51. static int miRoundCapClip (const LineFace *face, bool isInt, PolyEdge *edge, bool *leftEdge);
  52. static int miRoundJoinFace (const LineFace *face, PolyEdge *edge, bool *leftEdge);
  53. static void miRoundJoinClip (LineFace *pLeft, LineFace *pRight, PolyEdge *edge1, PolyEdge *edge2, int *y1, int *y2, bool *left1, bool *left2);
  54. /* Spans-based convex polygon filler. Paints a convex polygon, supplied as
  55. lists of `left' and `right' edges. Used for painting polygonal line
  56. caps and line joins.
  57. This implements libxmi's policy on painting `edge' pixels, i.e., pixels
  58. that lie exactly on the boundary of a polygon. A pixel is not painted
  59. if it lies on a `right' or `bottom' edge of the polygon. */
  60. /* ARGS: y = starting y coor, overall_height = height of entire segment */
  61. static void
  62. miFillPolyHelper (miPaintedSet *paintedSet, miPixel pixel, int y, unsigned int overall_height, PolyEdge *left, PolyEdge *right, int left_count, int right_count)
  63. {
  64. int left_x = 0, left_e = 0;
  65. int left_stepx = 0;
  66. int left_signdx = 0;
  67. int left_dy = 0, left_dx = 0;
  68. int right_x = 0, right_e = 0;
  69. int right_stepx = 0;
  70. int right_signdx = 0;
  71. int right_dy = 0, right_dx = 0;
  72. unsigned int left_height = 0, right_height = 0;
  73. miPoint *ppt;
  74. miPoint *pptInit = (miPoint *)NULL;
  75. unsigned int *pwidth;
  76. unsigned int *pwidthInit = (unsigned int *)NULL;
  77. pptInit = (miPoint *)mi_xmalloc(overall_height * sizeof(miPoint));
  78. pwidthInit = (unsigned int *)mi_xmalloc(overall_height * sizeof(unsigned int));
  79. ppt = pptInit;
  80. pwidth = pwidthInit;
  81. while ((left_count || left_height) && (right_count || right_height))
  82. {
  83. unsigned int height;
  84. /* load fields from next left edge, right edge */
  85. MIPOLYRELOADLEFT
  86. MIPOLYRELOADRIGHT
  87. height = UMIN (left_height, right_height);
  88. left_height -= height;
  89. right_height -= height;
  90. /* walk down to end of left or right edge, whichever comes first */
  91. while (height--)
  92. {
  93. if (right_x >= left_x)
  94. /* generate a span (omitting point on right end, see above) */
  95. {
  96. ppt->x = left_x;
  97. ppt->y = y;
  98. ppt++;
  99. *pwidth++ = (unsigned int)(right_x - left_x + 1);
  100. }
  101. y++;
  102. /* update left_x, right_x by stepping along left and right edges,
  103. using midpoint line algorithm */
  104. MIPOLYSTEPLEFT
  105. MIPOLYSTEPRIGHT
  106. }
  107. }
  108. MI_PAINT_SPANS(paintedSet, pixel, ppt - pptInit, pptInit, pwidthInit)
  109. }
  110. /* Rectangle filler. Policy mentioned above (no painting of right or
  111. bottom edges) is followed. */
  112. static void
  113. miFillRectPolyHelper (miPaintedSet *paintedSet, miPixel pixel, int x, int y, unsigned int w, unsigned int h)
  114. {
  115. miPoint *ppt, *pptInit;
  116. unsigned int *pwidth, *pwidthInit;
  117. pptInit = (miPoint *)mi_xmalloc (h * sizeof(miPoint));
  118. pwidthInit = (unsigned int *)mi_xmalloc (h * sizeof(unsigned int));
  119. ppt = pptInit;
  120. pwidth = pwidthInit;
  121. while (h--)
  122. {
  123. *pwidth++ = w;
  124. ppt->x = x;
  125. ppt->y = y;
  126. ppt++;
  127. y++;
  128. }
  129. MI_PAINT_SPANS(paintedSet, pixel, ppt - pptInit, pptInit, pwidthInit)
  130. }
  131. /* Build a single polygon edge (either a left edge or a right edge).
  132. I.e. compute integer edge data that can be used by the midpoint line
  133. algorithm. The edge will be traversed downward (on entry, dy != 0 is
  134. assumed). Returns starting value for y, i.e. integer y-value for top of
  135. edge. */
  136. /* Supplied: an integer offset (xi,yi), the exact floating-point edge start
  137. (x0,y0), its (rational) slope dy/dx, and the quantity k = x0*dy-y0*dx,
  138. which is a measure of distance of (x0,y0) from the parallel line segment
  139. that passes through (0,0). k will be transformed into the initial value
  140. for e, the integer decision variable for the midpoint line algorithm. */
  141. /* The integer edge data that are computed do not include the `height'
  142. field, i.e. the number of scanlines to process. */
  143. /* ARGS: x0,y0 = starting point of edge (rel. to x1,y1)
  144. k = x0 * dy - y0 * dx
  145. dx,dy specify rational slope dy/dx
  146. xi,yi = integer offsets for coor system
  147. left = left edge, not right edge?
  148. edge = integer edge data, to be filled in */
  149. /*ARGSUSED*/
  150. static int
  151. miPolyBuildEdge (double x0, double y0, double k, int dx, int dy, int xi, int yi, bool left, PolyEdge *edge)
  152. {
  153. int x, y, e;
  154. int xady;
  155. /* make dy positive, since edge will be traversed downward */
  156. if (dy < 0)
  157. {
  158. dy = -dy;
  159. dx = -dx;
  160. k = -k;
  161. }
  162. #if 0
  163. {
  164. double realk, kerror;
  165. realk = x0 * dy - y0 * dx;
  166. kerror = fabs (realk - k);
  167. if (kerror > .1)
  168. printf ("realk: %g\t k: %g\n", realk, k);
  169. }
  170. #endif
  171. /* integer starting value for y: round up the floating-point value */
  172. y = ICEIL (y0);
  173. /* work out integer starting value for x */
  174. xady = ICEIL (k) + y * dx;
  175. if (xady <= 0)
  176. x = - (-xady / dy) - 1;
  177. else
  178. x = (xady - 1) / dy;
  179. /* start working out initial value of decision variable */
  180. e = xady - x * dy; /* i.e. ICEIL(k) - (x * dy - y * dx) */
  181. /* work out optional and non-optional x increment, for algorithm */
  182. if (dx >= 0)
  183. {
  184. edge->signdx = 1; /* optional step */
  185. edge->stepx = dx / dy; /* non-optional step, 0 if dx<dy in mag. */
  186. edge->dx = dx % dy;
  187. }
  188. else
  189. {
  190. edge->signdx = -1; /* optional step */
  191. edge->stepx = - (-dx / dy); /* non-optional step, 0 if dx<dy in mag. */
  192. edge->dx = -dx % dy;
  193. e = dy - e + 1;
  194. }
  195. edge->dy = dy;
  196. edge->x = x + (left == true ? 1 : 0) + xi; /* starting value for x */
  197. edge->e = e - dy; /* bias: initial value for e */
  198. /* return integer starting value for y, i.e. top of edge */
  199. return y + yi;
  200. }
  201. /* add incr to v, cyclically; always stay in range 0..max */
  202. #define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
  203. /* Build lists of right and left polygon edges, from an array of vertex
  204. coordinates (floating-point), a precomputed array of PolySlopes
  205. (including a `k' value for each edge), and an integer offset vector.
  206. Also return overall vertical range and top (starting) y value. */
  207. /* ARGS: xi,yi = integer offset for polygon */
  208. static int
  209. miPolyBuildPoly (const PolyVertex *vertices, const PolySlope *slopes, int count, int xi, int yi, PolyEdge *left, PolyEdge *right, int *pnleft, int *pnright, unsigned int *h)
  210. {
  211. int top, bottom;
  212. double miny, maxy;
  213. int i;
  214. int j;
  215. int clockwise;
  216. int slopeoff;
  217. int s;
  218. int nright, nleft;
  219. int y, lasty = 0, bottomy, topy = 0;
  220. /* compute min, max y values for polygon (floating-point); also location
  221. of corresponding vertices in vertex array */
  222. maxy = miny = vertices[0].y;
  223. bottom = top = 0;
  224. for (i = 1; i < count; i++)
  225. {
  226. if (vertices[i].y < miny)
  227. {
  228. top = i;
  229. miny = vertices[i].y;
  230. }
  231. if (vertices[i].y >= maxy)
  232. {
  233. bottom = i;
  234. maxy = vertices[i].y;
  235. }
  236. }
  237. /* compute integer y-value for bottom of polygon (round up) */
  238. bottomy = ICEIL (maxy) + yi;
  239. /* determine whether should go `clockwise' or `counterclockwise'
  240. to move down the right side of the polygon */
  241. i = top;
  242. j = StepAround (top, -1, count);
  243. clockwise = 1;
  244. slopeoff = 0;
  245. if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
  246. {
  247. clockwise = -1;
  248. slopeoff = -1;
  249. }
  250. /* step around right side of polygon from top to bottom, building array
  251. of `right' edges (horizontal edges are ignored) */
  252. i = top;
  253. s = StepAround (top, slopeoff, count);
  254. nright = 0;
  255. while (i != bottom)
  256. {
  257. if (slopes[s].dy != 0)
  258. {
  259. y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
  260. slopes[s].k, slopes[s].dx, slopes[s].dy,
  261. xi, yi, false,
  262. &right[nright]);
  263. if (nright != 0)
  264. right[nright-1].height = y - lasty;
  265. else /* y is top of first edge */
  266. topy = y;
  267. nright++;
  268. lasty = y;
  269. }
  270. i = StepAround (i, clockwise, count);
  271. s = StepAround (s, clockwise, count);
  272. }
  273. if (nright != 0)
  274. right[nright-1].height = bottomy - lasty;
  275. /* step around left side of polygon from top to bottom, building array of
  276. `left' edges (horizontal edges are ignored) */
  277. if (slopeoff == 0)
  278. slopeoff = -1;
  279. else
  280. slopeoff = 0;
  281. i = top;
  282. s = StepAround (top, slopeoff, count);
  283. nleft = 0;
  284. while (i != bottom)
  285. {
  286. if (slopes[s].dy != 0)
  287. {
  288. y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
  289. slopes[s].k, slopes[s].dx, slopes[s].dy,
  290. xi, yi, true,
  291. &left[nleft]);
  292. if (nleft != 0)
  293. left[nleft-1].height = y - lasty;
  294. nleft++;
  295. lasty = y;
  296. }
  297. i = StepAround (i, -clockwise, count);
  298. s = StepAround (s, -clockwise, count);
  299. }
  300. if (nleft != 0)
  301. left[nleft-1].height = bottomy - lasty;
  302. /* return number of left-side and right-side edges; also height (vertical
  303. range, an unsigned int) and the vertical location of the top vertex
  304. (an integer) */
  305. *pnleft = nleft;
  306. *pnright = nright;
  307. *h = bottomy - topy;
  308. return topy;
  309. }
  310. /* Paint all types of line join: round/miter/bevel/triangular. Called by
  311. both miWideLine() and miWideDash(). Left and right line faces are
  312. supplied, each with its own value of k. They may be modified. */
  313. static void
  314. miLineJoin (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, LineFace *pLeft, LineFace *pRight)
  315. {
  316. double mx = 0.0, my = 0.0;
  317. int denom = 0; /* avoid compiler warnings */
  318. PolyVertex vertices[4];
  319. PolySlope slopes[4];
  320. int edgecount;
  321. PolyEdge left[4], right[4];
  322. int nleft, nright;
  323. int y;
  324. unsigned int height;
  325. bool swapslopes;
  326. int joinStyle = (int)pGC->joinStyle;
  327. int lw = (int)(pGC->lineWidth);
  328. if (joinStyle == (int)MI_JOIN_ROUND)
  329. {
  330. /* invoke miLineArc to fill the round join, isInt = true */
  331. miLineArc (paintedSet, pixel, pGC,
  332. pLeft, pRight, (double)0.0, (double)0.0, true);
  333. return;
  334. }
  335. denom = - pLeft->dx * pRight->dy + pRight->dx * pLeft->dy;
  336. if (denom == 0)
  337. return; /* no join to draw */
  338. /* Now must handle cases where line join is a small polygon to be filled;
  339. specify its vertices clockwise. */
  340. /* swap slopes if cross product of line faces has wrong sign */
  341. if (denom > 0)
  342. {
  343. swapslopes = false;
  344. pLeft->xa = -pLeft->xa;
  345. pLeft->ya = -pLeft->ya;
  346. pLeft->dx = -pLeft->dx;
  347. pLeft->dy = -pLeft->dy;
  348. }
  349. else
  350. {
  351. swapslopes = true;
  352. pRight->xa = -pRight->xa;
  353. pRight->ya = -pRight->ya;
  354. pRight->dx = -pRight->dx;
  355. pRight->dy = -pRight->dy;
  356. }
  357. /* vertex #0 is at the right end of the right face */
  358. vertices[0].x = pRight->xa;
  359. vertices[0].y = pRight->ya;
  360. slopes[0].dx = -pRight->dy;
  361. slopes[0].dy = pRight->dx;
  362. slopes[0].k = 0;
  363. /* vertex #1 is the nominal join point (i.e. halfway across both the
  364. right face and the left face) */
  365. vertices[1].x = 0;
  366. vertices[1].y = 0;
  367. slopes[1].dx = pLeft->dy;
  368. slopes[1].dy = -pLeft->dx;
  369. slopes[1].k = 0;
  370. /* vertex #2 is at the left end of the left face */
  371. vertices[2].x = pLeft->xa;
  372. vertices[2].y = pLeft->ya;
  373. if (joinStyle == (int)MI_JOIN_MITER)
  374. {
  375. double miterlimit = pGC->miterLimit;
  376. /* compute vertex (mx,my) of miter quadrilateral */
  377. my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
  378. pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) /
  379. (double) denom;
  380. if (pLeft->dy != 0)
  381. mx = pLeft->xa + (my - pLeft->ya) *
  382. (double) pLeft->dx / (double) pLeft->dy;
  383. else
  384. mx = pRight->xa + (my - pRight->ya) *
  385. (double) pRight->dx / (double) pRight->dy;
  386. /* if miter limit violated, switch to bevelled join */
  387. if ((mx * mx + my * my) * 4 > miterlimit * miterlimit * lw * lw)
  388. joinStyle = (int)MI_JOIN_BEVEL;
  389. }
  390. switch ((int)joinStyle)
  391. {
  392. double scale, dx, dy, adx, ady;
  393. case (int)MI_JOIN_MITER:
  394. default:
  395. /* join by adding a quadrilateral */
  396. edgecount = 4;
  397. slopes[2].dx = pLeft->dx;
  398. slopes[2].dy = pLeft->dy;
  399. slopes[2].k = pLeft->k;
  400. if (swapslopes)
  401. {
  402. slopes[2].dx = -slopes[2].dx;
  403. slopes[2].dy = -slopes[2].dy;
  404. slopes[2].k = -slopes[2].k;
  405. }
  406. /* vertex #3 is miter vertex (mx,my) */
  407. vertices[3].x = mx;
  408. vertices[3].y = my;
  409. slopes[3].dx = pRight->dx;
  410. slopes[3].dy = pRight->dy;
  411. slopes[3].k = pRight->k;
  412. if (swapslopes)
  413. {
  414. slopes[3].dx = -slopes[3].dx;
  415. slopes[3].dy = -slopes[3].dy;
  416. slopes[3].k = -slopes[3].k;
  417. }
  418. break;
  419. case (int)MI_JOIN_BEVEL:
  420. /* join by adding a triangle */
  421. {
  422. PolyVertex midpoint;
  423. edgecount = 3;
  424. /* third edge of triangle will pass through midpoint */
  425. midpoint.x = 0.5 * (pLeft->xa + pRight->xa);
  426. midpoint.y = 0.5 * (pLeft->ya + pRight->ya);
  427. /* vector along third edge of triangle */
  428. dx = pRight->xa - pLeft->xa;
  429. dy = pRight->ya - pLeft->ya;
  430. /* compute scale = max(|dx|,|dy|) */
  431. adx = dx;
  432. ady = dy;
  433. if (adx < 0)
  434. adx = -adx;
  435. if (ady < 0)
  436. ady = -ady;
  437. scale = ady;
  438. if (adx > ady)
  439. scale = adx;
  440. /* use integer dx, dy in range -65536..65536 */
  441. slopes[2].dx = (int)((dx * 65536) / scale);
  442. slopes[2].dy = (int)((dy * 65536) / scale);
  443. slopes[2].k = midpoint.x * slopes[2].dy - midpoint.y * slopes[2].dx;
  444. }
  445. break;
  446. case (int)MI_JOIN_TRIANGULAR:
  447. /* join by adding a stubby quadrilateral */
  448. {
  449. PolyVertex midpoint, newpoint;
  450. double mid2, mid, dx2, dy2, dx3, dy3;
  451. edgecount = 4;
  452. /* compute additional vertex, offset by linewidth/2 */
  453. midpoint.x = 0.5 * (pLeft->xa + pRight->xa);
  454. midpoint.y = 0.5 * (pLeft->ya + pRight->ya);
  455. mid2 = midpoint.x * midpoint.x + midpoint.y * midpoint.y;
  456. mid = sqrt (mid2);
  457. newpoint.x = 0.5 * lw * midpoint.x / mid;
  458. newpoint.y = 0.5 * lw * midpoint.y / mid;
  459. vertices[3] = newpoint;
  460. /* offset from vertices[2] to vertices[3] */
  461. dx2 = vertices[3].x - vertices[2].x;
  462. dy2 = vertices[3].y - vertices[2].y;
  463. /* offset from vertices[3] back to vertices[0] */
  464. dx3 = vertices[0].x - vertices[3].x;
  465. dy3 = vertices[0].y - vertices[3].y;
  466. /* compute scale = max(|dx|,|dy|), where (dx,dy) is offset between
  467. the two corners, i.e. vertices[0] and vertices[2] */
  468. dx = pRight->xa - pLeft->xa;
  469. dy = pRight->ya - pLeft->ya;
  470. adx = dx;
  471. ady = dy;
  472. if (adx < 0)
  473. adx = -adx;
  474. if (ady < 0)
  475. ady = -ady;
  476. scale = ady;
  477. if (adx > ady)
  478. scale = adx;
  479. /* use integer dx, dy in range -65536..65536 */
  480. slopes[2].dx = (int)((dx2 * 65536) / scale);
  481. slopes[2].dy = (int)((dy2 * 65536) / scale);
  482. slopes[2].k = newpoint.x * slopes[2].dy - newpoint.y * slopes[2].dx;
  483. /* use integer dx, dy in range -65536..65536 */
  484. slopes[3].dx = (int)((dx3 * 65536) / scale);
  485. slopes[3].dy = (int)((dy3 * 65536) / scale);
  486. slopes[3].k = newpoint.x * slopes[3].dy - newpoint.y * slopes[3].dx;
  487. }
  488. break;
  489. } /* end of switch */
  490. /* compute lists of left and right edges for the small polygon, using the
  491. just-computed slopes array */
  492. y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
  493. left, right, &nleft, &nright, &height);
  494. /* fill the small polygon */
  495. miFillPolyHelper (paintedSet, pixel,
  496. y, height, left, right, nleft, nright);
  497. }
  498. /* Paint either (1) a round cap on a line face or (2) a pie-wedge between
  499. two line faces. Used for round capping and round joining respectively.
  500. One or two line faces are supplied. They may be modified. */
  501. static void
  502. miLineArc (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, LineFace *leftFace, LineFace *rightFace, double xorg, double yorg, bool isInt)
  503. {
  504. miPoint *points;
  505. unsigned int *widths;
  506. int xorgi = 0, yorgi = 0;
  507. int n;
  508. PolyEdge edge1, edge2;
  509. int edgey1, edgey2;
  510. bool edgeleft1, edgeleft2;
  511. if (isInt)
  512. /* in integer case, take (xorgi,yorgi) from face; otherwise (0,0) */
  513. {
  514. xorgi = leftFace ? leftFace->x : rightFace->x;
  515. yorgi = leftFace ? leftFace->y : rightFace->y;
  516. }
  517. edgey1 = INT_MAX;
  518. edgey2 = INT_MAX;
  519. edge1.x = 0; /* not used, keep memory checkers happy */
  520. edge1.dy = -1;
  521. edge2.x = 0; /* not used, keep memory checkers happy */
  522. edge2.dy = -1;
  523. edgeleft1 = false;
  524. edgeleft2 = false;
  525. if ((pGC->lineStyle != (int)MI_LINE_SOLID || pGC->lineWidth > 2)
  526. &&
  527. ((pGC->capStyle == (int)MI_CAP_ROUND && pGC->joinStyle != (int)MI_JOIN_ROUND)
  528. ||
  529. (pGC->joinStyle == (int)MI_JOIN_ROUND && pGC->capStyle == (int)MI_CAP_BUTT)))
  530. /* construct clipping edges from the passed line faces (otherwise,
  531. ignore them; will just draw a disk) */
  532. {
  533. if (isInt)
  534. {
  535. xorg = (double) xorgi;
  536. yorg = (double) yorgi;
  537. }
  538. if (leftFace && rightFace)
  539. /* have two faces, so construct clipping edges for pie wedge */
  540. miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
  541. &edgey1, &edgey2, &edgeleft1, &edgeleft2);
  542. else if (leftFace)
  543. /* will draw half-disk on left face, so construct clipping edge */
  544. edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
  545. else if (rightFace)
  546. /* will draw half-disk on right face, so construct clipping edge */
  547. edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
  548. /* due to clipping, switch to using floating-point coordinates */
  549. isInt = false;
  550. }
  551. points = (miPoint *)mi_xmalloc(sizeof(miPoint) * pGC->lineWidth);
  552. widths = (unsigned int *)mi_xmalloc(sizeof(unsigned int) * pGC->lineWidth);
  553. /* construct a Spans by calling integer or floating point routine */
  554. if (isInt)
  555. /* integer routine, no clipping: just draw a disk */
  556. n = miLineArcI (pGC, xorgi, yorgi, points, widths);
  557. else
  558. /* call floating point routine, supporting clipping by edge(s) */
  559. n = miLineArcD (pGC, xorg, yorg, points, widths,
  560. &edge1, edgey1, edgeleft1,
  561. &edge2, edgey2, edgeleft2);
  562. MI_PAINT_SPANS(paintedSet, pixel, n, points, widths)
  563. }
  564. /* Draw a filled disk, of diameter equal to the linewidth, as a Spans.
  565. This is used for round caps or round joins, if the clipping by one or
  566. two edges can be ignored. Integer coordinates only are used. Returns
  567. number of spans in the Spans. */
  568. static int
  569. miLineArcI (const miGC *pGC, int xorg, int yorg, miPoint *points, unsigned int *widths)
  570. {
  571. miPoint *tpts, *bpts;
  572. unsigned int *twids, *bwids;
  573. int x, y, e, ex;
  574. int slw;
  575. tpts = points;
  576. twids = widths;
  577. slw = (int)(pGC->lineWidth);
  578. if (slw == 1)
  579. /* `disk' is a single pixel */
  580. {
  581. tpts->x = xorg;
  582. tpts->y = yorg;
  583. *twids = 1;
  584. return 1;
  585. }
  586. /* otherwise, draw the disk scanline by scanline */
  587. bpts = tpts + slw;
  588. bwids = twids + slw;
  589. y = (slw >> 1) + 1;
  590. if (slw & 1)
  591. e = - ((y << 2) + 3);
  592. else
  593. e = - (y << 3);
  594. ex = -4;
  595. x = 0;
  596. while (y)
  597. {
  598. e += (y << 3) - 4;
  599. while (e >= 0)
  600. {
  601. x++;
  602. e += (ex = -((x << 3) + 4));
  603. }
  604. y--;
  605. slw = (x << 1) + 1;
  606. if ((e == ex) && (slw > 1))
  607. slw--;
  608. tpts->x = xorg - x;
  609. tpts->y = yorg - y;
  610. tpts++;
  611. *twids++ = slw;
  612. if ((y != 0) && ((slw > 1) || (e != ex)))
  613. {
  614. bpts--;
  615. bpts->x = xorg - x;
  616. bpts->y = yorg + y;
  617. *--bwids = slw;
  618. }
  619. }
  620. /* return linewidth (no. of spans in the Spans) */
  621. return (int)(pGC->lineWidth);
  622. }
  623. #define CLIPSTEPEDGE(edgey,edge,edgeleft) \
  624. if (ybase == edgey) \
  625. { \
  626. if (edgeleft) \
  627. { \
  628. if (edge->x > xcl) \
  629. xcl = edge->x; \
  630. } \
  631. else \
  632. { \
  633. if (edge->x < xcr) \
  634. xcr = edge->x; \
  635. } \
  636. edgey++; \
  637. edge->x += edge->stepx; \
  638. edge->e += edge->dx; \
  639. if (edge->e > 0) \
  640. { \
  641. edge->x += edge->signdx; \
  642. edge->e -= edge->dy; \
  643. } \
  644. }
  645. /* Draw as a Spans a filled disk of diameter equal to the linewidth, paying
  646. attention to one or two clipping edges. This is used for round caps and
  647. round joins, respectively (it respectively yields a half-disk or a pie
  648. wedge). Floating point coordinates are used. Returns number of spans
  649. in the Spans. The clipping edges may be modified. */
  650. static int
  651. miLineArcD (const miGC *pGC, double xorg, double yorg, miPoint *points, unsigned int *widths, PolyEdge *edge1, int edgey1, bool edgeleft1, PolyEdge *edge2, int edgey2, bool edgeleft2)
  652. {
  653. miPoint *pts;
  654. unsigned int *wids;
  655. double radius, x0, y0, el, er, yk, xlk, xrk, k;
  656. int xbase, ybase, y, boty, xl, xr, xcl, xcr;
  657. int ymin, ymax;
  658. bool edge1IsMin, edge2IsMin;
  659. int ymin1, ymin2;
  660. pts = points;
  661. wids = widths;
  662. xbase = (int)(floor(xorg));
  663. x0 = xorg - xbase;
  664. ybase = ICEIL (yorg);
  665. y0 = yorg - ybase;
  666. xlk = x0 + x0 + 1.0;
  667. xrk = x0 + x0 - 1.0;
  668. yk = y0 + y0 - 1.0;
  669. radius = 0.5 * ((double)pGC->lineWidth);
  670. y = (int)(floor(radius - y0 + 1.0));
  671. ybase -= y;
  672. ymin = ybase;
  673. ymax = INT_MAX;
  674. edge1IsMin = false;
  675. ymin1 = edgey1;
  676. if (edge1->dy >= 0)
  677. {
  678. if (!edge1->dy)
  679. {
  680. if (edgeleft1)
  681. edge1IsMin = true;
  682. else
  683. ymax = edgey1;
  684. edgey1 = INT_MAX;
  685. }
  686. else
  687. {
  688. if ((edge1->signdx < 0) == edgeleft1)
  689. edge1IsMin = true;
  690. }
  691. }
  692. edge2IsMin = false;
  693. ymin2 = edgey2;
  694. if (edge2->dy >= 0)
  695. {
  696. if (!edge2->dy)
  697. {
  698. if (edgeleft2)
  699. edge2IsMin = true;
  700. else
  701. ymax = edgey2;
  702. edgey2 = INT_MAX;
  703. }
  704. else
  705. {
  706. if ((edge2->signdx < 0) == edgeleft2)
  707. edge2IsMin = true;
  708. }
  709. }
  710. if (edge1IsMin)
  711. {
  712. ymin = ymin1;
  713. if (edge2IsMin && ymin1 > ymin2)
  714. ymin = ymin2;
  715. }
  716. else if (edge2IsMin)
  717. ymin = ymin2;
  718. el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
  719. er = el + xrk;
  720. xl = 1;
  721. xr = 0;
  722. if (x0 < 0.5)
  723. {
  724. xl = 0;
  725. el -= xlk;
  726. }
  727. boty = (y0 < -0.5) ? 1 : 0;
  728. if (ybase + y - boty > ymax)
  729. boty = ymax - ybase - y;
  730. while (y > boty)
  731. {
  732. k = (y << 1) + yk;
  733. er += k;
  734. while (er > 0.0)
  735. {
  736. xr++;
  737. er += xrk - (xr << 1);
  738. }
  739. el += k;
  740. while (el >= 0.0)
  741. {
  742. xl--;
  743. el += (xl << 1) - xlk;
  744. }
  745. y--;
  746. ybase++;
  747. if (ybase < ymin)
  748. continue;
  749. xcl = xl + xbase;
  750. xcr = xr + xbase;
  751. CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
  752. CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
  753. if (xcr >= xcl)
  754. {
  755. pts->x = xcl;
  756. pts->y = ybase;
  757. pts++;
  758. *wids++ = (unsigned int)(xcr - xcl + 1);
  759. }
  760. }
  761. er = xrk - (xr << 1) - er;
  762. el = (xl << 1) - xlk - el;
  763. boty = (int)(floor(-y0 - radius + 1.0));
  764. if (ybase + y - boty > ymax)
  765. boty = ymax - ybase - y;
  766. while (y > boty)
  767. {
  768. k = (y << 1) + yk;
  769. er -= k;
  770. while ((er >= 0.0) && (xr >= 0))
  771. {
  772. xr--;
  773. er += xrk - (xr << 1);
  774. }
  775. el -= k;
  776. while ((el > 0.0) && (xl <= 0))
  777. {
  778. xl++;
  779. el += (xl << 1) - xlk;
  780. }
  781. y--;
  782. ybase++;
  783. if (ybase < ymin)
  784. continue;
  785. xcl = xl + xbase;
  786. xcr = xr + xbase;
  787. CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
  788. CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
  789. if (xcr >= xcl)
  790. {
  791. pts->x = xcl;
  792. pts->y = ybase;
  793. pts++;
  794. *wids++ = (unsigned int)(xcr - xcl + 1);
  795. }
  796. }
  797. /* return number of spans in the Spans */
  798. return (pts - points);
  799. }
  800. /* From two line faces, construct clipping edges that will be used by
  801. miLineArcD when drawing a pie wedge. The line faces may be modified. */
  802. static void
  803. miRoundJoinClip (LineFace *pLeft, LineFace *pRight, PolyEdge *edge1, PolyEdge *edge2, int *y1, int *y2, bool *left1, bool *left2)
  804. {
  805. int denom;
  806. denom = - pLeft->dx * pRight->dy + pRight->dx * pLeft->dy;
  807. if (denom >= 0)
  808. {
  809. pLeft->xa = -pLeft->xa;
  810. pLeft->ya = -pLeft->ya;
  811. }
  812. else
  813. {
  814. pRight->xa = -pRight->xa;
  815. pRight->ya = -pRight->ya;
  816. }
  817. *y1 = miRoundJoinFace (pLeft, edge1, left1);
  818. *y2 = miRoundJoinFace (pRight, edge2, left2);
  819. }
  820. /* helper function called by the preceding */
  821. static int
  822. miRoundJoinFace (const LineFace *face, PolyEdge *edge, bool *leftEdge)
  823. {
  824. int y;
  825. int dx, dy;
  826. double xa, ya;
  827. bool left;
  828. dx = -face->dy;
  829. dy = face->dx;
  830. xa = face->xa;
  831. ya = face->ya;
  832. left = true;
  833. if (ya > 0)
  834. {
  835. ya = 0.0;
  836. xa = 0.0;
  837. }
  838. if (dy < 0 || (dy == 0 && dx > 0))
  839. {
  840. dx = -dx;
  841. dy = -dy;
  842. left = (left ? false : true);
  843. }
  844. if (dx == 0 && dy == 0)
  845. dy = 1;
  846. if (dy == 0)
  847. {
  848. y = ICEIL (face->ya) + face->y;
  849. edge->x = INT_MIN;
  850. edge->stepx = 0;
  851. edge->signdx = 0;
  852. edge->e = -1;
  853. edge->dy = 0;
  854. edge->dx = 0;
  855. edge->height = 0;
  856. }
  857. else
  858. {
  859. y = miPolyBuildEdge (xa, ya,
  860. 0.0, dx, dy,
  861. face->x, face->y, (left ? false : true), edge);
  862. edge->height = UINT_MAX; /* number of scanlines to process */
  863. }
  864. *leftEdge = (left ? false : true);
  865. return y;
  866. }
  867. /* From a line face, construct a clipping edge that will be used by
  868. miLineArcD when drawing a half-disk. */
  869. static int
  870. miRoundCapClip (const LineFace *face, bool isInt, PolyEdge *edge, bool *leftEdge)
  871. {
  872. int y;
  873. int dx, dy;
  874. double xa, ya, k;
  875. bool left;
  876. dx = -face->dy;
  877. dy = face->dx;
  878. xa = face->xa;
  879. ya = face->ya;
  880. k = 0.0;
  881. if (!isInt)
  882. k = face->k;
  883. left = true;
  884. if (dy < 0 || (dy == 0 && dx > 0))
  885. {
  886. dx = -dx;
  887. dy = -dy;
  888. xa = -xa;
  889. ya = -ya;
  890. left = (left ? false : true);
  891. }
  892. if (dx == 0 && dy == 0)
  893. dy = 1;
  894. if (dy == 0)
  895. {
  896. y = ICEIL (face->ya) + face->y;
  897. edge->x = INT_MIN;
  898. edge->stepx = 0;
  899. edge->signdx = 0;
  900. edge->e = -1;
  901. edge->dy = 0;
  902. edge->dx = 0;
  903. edge->height = 0;
  904. }
  905. else
  906. {
  907. y = miPolyBuildEdge (xa, ya,
  908. k, dx, dy,
  909. face->x, face->y, (left ? false : true), edge);
  910. edge->height = UINT_MAX; /* number of scanlines to process */
  911. }
  912. *leftEdge = (left ? false : true);
  913. return y;
  914. }
  915. /* Paint a projecting rectangular cap on a line face. Called only by
  916. miWideDash (with isInt = true); not by miWideLine. */
  917. static void
  918. miLineProjectingCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const LineFace *face, bool isLeft, bool isInt)
  919. {
  920. int dx, dy;
  921. int topy, bottomy;
  922. int xorgi = 0, yorgi = 0;
  923. int lw = (int)(pGC->lineWidth);
  924. PolyEdge lefts[2], rights[2];
  925. if (isInt)
  926. /* in integer case, take (xorgi,yorgi) from face; otherwise (0,0) */
  927. {
  928. xorgi = face->x;
  929. yorgi = face->y;
  930. }
  931. dx = face->dx;
  932. dy = face->dy;
  933. if (dy == 0)
  934. /* special case: line face is horizontal */
  935. {
  936. lefts[0].height = (unsigned int)lw;
  937. lefts[0].x = xorgi;
  938. if (isLeft)
  939. lefts[0].x -= (lw >> 1);
  940. lefts[0].stepx = 0;
  941. lefts[0].signdx = 1;
  942. lefts[0].e = -lw;
  943. lefts[0].dx = 0;
  944. lefts[0].dy = lw;
  945. rights[0].height = (unsigned int)lw;
  946. rights[0].x = xorgi;
  947. if (!isLeft)
  948. rights[0].x += ((lw + 1) >> 1);
  949. rights[0].stepx = 0;
  950. rights[0].signdx = 1;
  951. rights[0].e = -lw;
  952. rights[0].dx = 0;
  953. rights[0].dy = lw;
  954. /* fill the rectangle (1 left edge, 1 right edge) */
  955. miFillPolyHelper (paintedSet, pixel,
  956. yorgi - (lw >> 1), (unsigned int)lw,
  957. lefts, rights, 1, 1);
  958. }
  959. else if (dx == 0)
  960. /* special case: line face is vertical */
  961. {
  962. topy = yorgi;
  963. bottomy = yorgi + dy;
  964. if (isLeft)
  965. topy -= (lw >> 1);
  966. else
  967. bottomy += (lw >> 1);
  968. lefts[0].height = (unsigned int)(bottomy - topy);
  969. lefts[0].x = xorgi - (lw >> 1);
  970. lefts[0].stepx = 0;
  971. lefts[0].signdx = 1;
  972. lefts[0].e = -dy;
  973. lefts[0].dx = dx;
  974. lefts[0].dy = dy;
  975. rights[0].height = (unsigned int)(bottomy - topy);
  976. rights[0].x = lefts[0].x + (lw - 1);
  977. rights[0].stepx = 0;
  978. rights[0].signdx = 1;
  979. rights[0].e = -dy;
  980. rights[0].dx = dx;
  981. rights[0].dy = dy;
  982. /* fill the rectangle (1 left edge, 1 right edge) */
  983. miFillPolyHelper (paintedSet, pixel, topy,
  984. (unsigned int)(bottomy - topy), lefts, rights, 1, 1);
  985. }
  986. else
  987. /* general case: line face is neither horizontal nor vertical */
  988. {
  989. int lefty, righty;
  990. int finaly;
  991. double xa,ya;
  992. double xap, yap;
  993. double maxy;
  994. double projectXoff, projectYoff;
  995. double k;
  996. PolyEdge *left, *right;
  997. PolyEdge *top, *bottom;
  998. k = face->k;
  999. xa = face->xa;
  1000. ya = face->ya;
  1001. projectXoff = -ya;
  1002. projectYoff = xa;
  1003. if (dx < 0)
  1004. {
  1005. right = &rights[1];
  1006. left = &lefts[0];
  1007. top = &rights[0];
  1008. bottom = &lefts[1];
  1009. }
  1010. else
  1011. {
  1012. right = &rights[0];
  1013. left = &lefts[1];
  1014. top = &lefts[0];
  1015. bottom = &rights[1];
  1016. }
  1017. if (isLeft)
  1018. /* cap goes left; build four edges */
  1019. {
  1020. righty = miPolyBuildEdge (xa, ya,
  1021. k, dx, dy,
  1022. xorgi, yorgi, false, right);
  1023. xa = -xa;
  1024. ya = -ya;
  1025. k = -k;
  1026. lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  1027. k, dx, dy,
  1028. xorgi, yorgi, true, left);
  1029. if (dx > 0)
  1030. {
  1031. ya = -ya;
  1032. xa = -xa;
  1033. }
  1034. xap = xa - projectXoff;
  1035. yap = ya - projectYoff;
  1036. topy = miPolyBuildEdge (xap, yap,
  1037. xap * dx + yap * dy, -dy, dx,
  1038. xorgi, yorgi, (dx > 0 ? true : false), top);
  1039. bottomy = miPolyBuildEdge (xa, ya,
  1040. 0.0, -dy, dx,
  1041. xorgi, yorgi, (dx < 0 ? true : false), bottom);
  1042. maxy = -ya;
  1043. }
  1044. else
  1045. /* cap goes right; build four edges */
  1046. {
  1047. righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  1048. k, dx, dy,
  1049. xorgi, yorgi, false, right);
  1050. xa = -xa;
  1051. ya = -ya;
  1052. k = -k;
  1053. lefty = miPolyBuildEdge (xa, ya,
  1054. k, dx, dy,
  1055. xorgi, yorgi, true, left);
  1056. if (dx > 0)
  1057. {
  1058. ya = -ya;
  1059. xa = -xa;
  1060. }
  1061. xap = xa - projectXoff;
  1062. yap = ya - projectYoff;
  1063. topy = miPolyBuildEdge (xa, ya,
  1064. 0.0, -dy, dx,
  1065. xorgi, xorgi, (dx > 0 ? true : false), top);
  1066. bottomy = miPolyBuildEdge (xap, yap,
  1067. xap * dx + yap * dy, -dy, dx,
  1068. xorgi, xorgi, (dx < 0 ? true : false), bottom);
  1069. maxy = -ya + projectYoff;
  1070. }
  1071. finaly = ICEIL(maxy) + yorgi;
  1072. if (dx < 0)
  1073. {
  1074. left->height = (unsigned int)(bottomy - lefty);
  1075. right->height = (unsigned int)(finaly - righty);
  1076. top->height = (unsigned int)(righty - topy);
  1077. }
  1078. else
  1079. {
  1080. right->height = (unsigned int)(bottomy - righty);
  1081. left->height = (unsigned int)(finaly - lefty);
  1082. top->height = (unsigned int)(lefty - topy);
  1083. }
  1084. bottom->height = (unsigned int)(finaly - bottomy);
  1085. /* fill the rectangle (2 left edges, 2 right edges) */
  1086. miFillPolyHelper (paintedSet, pixel, topy,
  1087. (unsigned int)(bottom->height + bottomy - topy),
  1088. lefts, rights, 2, 2);
  1089. }
  1090. }
  1091. /* Draw a wide, dashed polyline, by dashing each line segment and joining
  1092. appropriately. miWideDashSegment() is called to dash each line
  1093. segment. */
  1094. void
  1095. miWideDash (miPaintedSet *paintedSet, const miGC *pGC, miCoordMode mode, int npt, const miPoint *pPts)
  1096. {
  1097. int x1, y1, x2, y2;
  1098. int dashNum; /* absolute number of dash, starts with 0 */
  1099. int dashIndex; /* index into array (i.e. dashNum % length) */
  1100. int dashOffset; /* offset into selected dash */
  1101. int startPaintType, endPaintType = 0, prevEndPaintType = 0;
  1102. int firstPaintType = 0; /* used only for closed polylines; will be 1 */
  1103. int numPixels;
  1104. bool selfJoin; /* polyline is closed? */
  1105. bool first; /* first line segment of polyline */
  1106. bool somethingDrawn = false;
  1107. bool projectLeft, projectRight;
  1108. LineFace leftFace, rightFace, prevRightFace;
  1109. LineFace firstFace;
  1110. miPixel pixel;
  1111. /* ensure we have >=1 points */
  1112. if (npt <= 0)
  1113. return;
  1114. /* width 0 lines are handled specially; invoke Bresenham routine in
  1115. mi_zerolin.c */
  1116. if (pGC->lineWidth == 0)
  1117. {
  1118. miZeroDash (paintedSet, pGC, mode, npt, pPts);
  1119. return;
  1120. }
  1121. x2 = pPts->x;
  1122. y2 = pPts->y;
  1123. first = true; /* first line segment of polyline */
  1124. /* determine whether polyline is closed */
  1125. selfJoin = false;
  1126. if (mode == MI_COORD_MODE_PREVIOUS)
  1127. {
  1128. int nptTmp;
  1129. const miPoint *pPtsTmp;
  1130. x1 = x2;
  1131. y1 = y2;
  1132. nptTmp = npt;
  1133. pPtsTmp = pPts + 1;
  1134. while (--nptTmp)
  1135. {
  1136. x1 += pPtsTmp->x;
  1137. y1 += pPtsTmp->y;
  1138. ++pPtsTmp;
  1139. }
  1140. if (x2 == x1 && y2 == y1)
  1141. selfJoin = true;
  1142. }
  1143. else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
  1144. selfJoin = true;
  1145. /* dash segments (except for the last) will not project right; and
  1146. (except for the first) will not project left */
  1147. projectLeft =
  1148. (pGC->capStyle == (int)MI_CAP_PROJECTING && !selfJoin) ? true : false;
  1149. projectRight = false;
  1150. /* perform initial offsetting into the dash sequence */
  1151. dashNum = 0; /* absolute number of dash */
  1152. dashIndex = 0; /* index into dash array */
  1153. dashOffset = 0; /* index into selected dash */
  1154. miStepDash (pGC->dashOffset, &dashNum, &dashIndex,
  1155. pGC->dash, pGC->numInDashList, &dashOffset);
  1156. /* How many paint types? (Will cycle through 0..numPixels-1, beginning
  1157. with 1, with `off' dashes defined as those with paint type #0.) */
  1158. numPixels = pGC->numPixels;
  1159. /* iterate through points, drawing a dashed segment for each line segment
  1160. of nonzero length */
  1161. while (--npt)
  1162. {
  1163. x1 = x2;
  1164. y1 = y2;
  1165. ++pPts;
  1166. x2 = pPts->x;
  1167. y2 = pPts->y;
  1168. if (mode == MI_COORD_MODE_PREVIOUS)
  1169. {
  1170. x2 += x1;
  1171. y2 += y1;
  1172. }
  1173. if (x1 != x2 || y1 != y2)
  1174. /* have a line segment of nonzero length */
  1175. {
  1176. int prevDashNum, lastPaintedDashNum;
  1177. if (npt == 1 && pGC->capStyle == (int)MI_CAP_PROJECTING
  1178. && (!selfJoin || (firstPaintType == 0)))
  1179. /* final point; and need a projecting cap here */
  1180. projectRight = true;
  1181. prevDashNum = dashNum;
  1182. /* draw dashed segment, updating dashNum, dashIndex and
  1183. dashOffset, returning faces */
  1184. miWideDashSegment (paintedSet, pGC,
  1185. &dashNum, &dashIndex, &dashOffset,
  1186. x1, y1, x2, y2,
  1187. projectLeft, projectRight, &leftFace, &rightFace);
  1188. /* determine paint types used at start and end of just-drawn
  1189. segment */
  1190. startPaintType = ((dashNum & 1) ?
  1191. 0 : 1 + ((dashNum / 2) % (numPixels - 1)));
  1192. lastPaintedDashNum = (dashOffset != 0 ? dashNum : dashNum - 1);
  1193. endPaintType = ((lastPaintedDashNum & 1) ?
  1194. 0 : 1 + ((dashNum / 2) % (numPixels - 1)));
  1195. /* add round cap or line join at left end of just-drawn segment;
  1196. if OnOffDash, do so only if segment began with an `on' dash */
  1197. if (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH || (startPaintType != 0))
  1198. {
  1199. pixel = pGC->pixels[startPaintType];
  1200. if (first || (pGC->lineStyle == (int)MI_LINE_ON_OFF_DASH
  1201. && prevEndPaintType == 0))
  1202. /* draw cap at left end, unless this is first segment of a
  1203. closed polyline */
  1204. {
  1205. if (first && selfJoin)
  1206. {
  1207. firstFace = leftFace;
  1208. firstPaintType = startPaintType;
  1209. }
  1210. else if (pGC->capStyle == (int)MI_CAP_ROUND
  1211. || pGC->capStyle == (int)MI_CAP_TRIANGULAR)
  1212. /* invoke miLineArc to draw round cap, isInt = true */
  1213. miLineArc (paintedSet, pixel, pGC,
  1214. &leftFace, (LineFace *)NULL,
  1215. (double)0.0, (double)0.0, true);
  1216. }
  1217. else
  1218. /* draw join at left end */
  1219. miLineJoin (paintedSet, pixel, pGC,
  1220. &leftFace, &prevRightFace);
  1221. }
  1222. somethingDrawn = true;
  1223. first = false;
  1224. prevRightFace = rightFace;
  1225. prevEndPaintType = endPaintType;
  1226. projectLeft = false;
  1227. }
  1228. if (npt == 1 && somethingDrawn)
  1229. /* last point of a nonempty polyline, so add line join or round cap
  1230. if appropriate, i.e. if we're doing OnOffDash and ended on an
  1231. `on' dash, or if we're doing DoubleDash */
  1232. {
  1233. if (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH || (endPaintType != 0))
  1234. {
  1235. pixel = pGC->pixels[endPaintType];
  1236. if (selfJoin && (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH
  1237. || (firstPaintType != 0)))
  1238. /* closed, so draw a join */
  1239. miLineJoin (paintedSet, pixel, pGC,
  1240. &firstFace, &rightFace);
  1241. else
  1242. {
  1243. if (pGC->capStyle == (int)MI_CAP_ROUND
  1244. || pGC->capStyle == (int)MI_CAP_TRIANGULAR)
  1245. /* invoke miLineArc, isInt = true, to draw a round cap */
  1246. miLineArc (paintedSet, pixel, pGC,
  1247. (LineFace *)NULL, &rightFace,
  1248. (double)0.0, (double)0.0, true);
  1249. }
  1250. }
  1251. else
  1252. /* we're doing OnOffDash, and final segment of polyline ended
  1253. with an (undrawn) `off' dash */
  1254. {
  1255. if (selfJoin && (firstPaintType != 0))
  1256. /* closed; if projecting or round caps are being used, draw
  1257. one on the first face */
  1258. {
  1259. pixel = pGC->pixels[firstPaintType];
  1260. if (pGC->capStyle == (int)MI_CAP_PROJECTING)
  1261. miLineProjectingCap (paintedSet, pixel, pGC,
  1262. &firstFace, true, true);
  1263. else if (pGC->capStyle == (int)MI_CAP_ROUND
  1264. || pGC->capStyle == (int)MI_CAP_TRIANGULAR)
  1265. /* invoke miLineArc, isInt = true, to draw a round cap */
  1266. miLineArc (paintedSet, pixel, pGC,
  1267. &firstFace, (LineFace *)NULL,
  1268. (double)0.0, (double)0.0, true);
  1269. }
  1270. }
  1271. }
  1272. }
  1273. /* handle `all points coincident' crock, nothing yet drawn */
  1274. if (!somethingDrawn
  1275. && (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH || !(dashNum & 1)))
  1276. {
  1277. unsigned int w1;
  1278. pixel = (dashNum & 1) ? pGC->pixels[0] : pGC->pixels[1];
  1279. switch ((int)pGC->capStyle)
  1280. {
  1281. case (int)MI_CAP_ROUND:
  1282. case (int)MI_CAP_TRIANGULAR:
  1283. /* invoke miLineArc, isInt = false, to draw a round disk */
  1284. miLineArc (paintedSet, pixel, pGC,
  1285. (LineFace *)NULL, (LineFace *)NULL,
  1286. (double)x2, (double)y2,
  1287. false);
  1288. break;
  1289. case (int)MI_CAP_PROJECTING:
  1290. /* draw a square box with edge size equal to line width */
  1291. w1 = pGC->lineWidth;
  1292. miFillRectPolyHelper (paintedSet, pixel,
  1293. (int)(x2 - (w1 >> 1)), (int)(y2 - (w1 >> 1)),
  1294. w1, w1);
  1295. break;
  1296. case (int)MI_CAP_BUTT:
  1297. default:
  1298. break;
  1299. }
  1300. }
  1301. }
  1302. #define V_TOP 0
  1303. #define V_RIGHT 1
  1304. #define V_BOTTOM 2
  1305. #define V_LEFT 3
  1306. /* Helper function, called by miWideDash(). Draw a single dashed line
  1307. segment, i.e. a sequence of dashes including a possible final incomplete
  1308. dash, and step DashNum, DashIndex and DashOffset appropriately. Also
  1309. pass back left and right faces for the line segment, for possible use in
  1310. adding caps or joins. If the LineOnOffDash line style is used, each
  1311. dash will be given a round cap if lines are drawn in the rounded cap
  1312. style, and a projecting cap if lines are drawn in the projecting cap
  1313. style. */
  1314. /* ARGS: pDashNum = absolute number of dash
  1315. pDashIndex = index into array (i.e. dashNum % length)
  1316. pDashOffset = offset into selected dash */
  1317. static void
  1318. miWideDashSegment (miPaintedSet *paintedSet, const miGC *pGC, int *pDashNum, int *pDashIndex, int *pDashOffset, int x1, int y1, int x2, int y2, bool projectLeft, bool projectRight, LineFace *leftFace, LineFace *rightFace)
  1319. {
  1320. int dashNum, dashIndex, dashRemain;
  1321. unsigned int *pDash;
  1322. double L, l;
  1323. double k;
  1324. PolyVertex vertices[4];
  1325. PolyVertex saveRight, saveBottom;
  1326. PolySlope slopes[4];
  1327. PolyEdge left[2], right[2];
  1328. LineFace lcapFace, rcapFace;
  1329. int nleft, nright;
  1330. unsigned int h;
  1331. int y;
  1332. int dy, dx;
  1333. double LRemain;
  1334. double r;
  1335. double rdx, rdy;
  1336. double dashDx, dashDy;
  1337. double saveK = 0.0;
  1338. bool first = true;
  1339. double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
  1340. miPixel pixel;
  1341. int numPixels, paintType;
  1342. dx = x2 - x1;
  1343. dy = y2 - y1;
  1344. dashNum = *pDashNum;
  1345. dashIndex = *pDashIndex;
  1346. pDash = pGC->dash;
  1347. /* determine portion of current dash remaining (i.e. the portion after
  1348. the current offset */
  1349. dashRemain = (int)(pDash[dashIndex]) - *pDashOffset;
  1350. /* compute color of current dash */
  1351. numPixels = pGC->numPixels;
  1352. paintType = (dashNum & 1) ? 0 : 1 + ((dashNum / 2) % (numPixels - 1));
  1353. pixel = pGC->pixels[paintType];
  1354. /* compute e.g. L, the distance to go (for dashing) */
  1355. l = 0.5 * ((double) pGC->lineWidth);
  1356. if (dx == 0) /* vertical segment */
  1357. {
  1358. L = dy;
  1359. rdx = 0;
  1360. rdy = l;
  1361. if (dy < 0)
  1362. {
  1363. L = -dy;
  1364. rdy = -l;
  1365. }
  1366. }
  1367. else if (dy == 0) /* horizontal segment */
  1368. {
  1369. L = dx;
  1370. rdx = l;
  1371. rdy = 0;
  1372. if (dx < 0)
  1373. {
  1374. L = -dx;
  1375. rdx = -l;
  1376. }
  1377. }
  1378. else /* neither horizontal nor vertical */
  1379. {
  1380. L = hypot ((double) dx, (double) dy);
  1381. r = l / L; /* this is ell / L, not 1 / L */
  1382. rdx = r * dx;
  1383. rdy = r * dy;
  1384. }
  1385. k = l * L; /* this is ell * L, not 1 * L */
  1386. /* All position comments are relative to a line with dx and dy > 0,
  1387. * but the code does not depend on this. */
  1388. /* top */
  1389. slopes[V_TOP].dx = dx;
  1390. slopes[V_TOP].dy = dy;
  1391. slopes[V_TOP].k = k;
  1392. /* right */
  1393. slopes[V_RIGHT].dx = -dy;
  1394. slopes[V_RIGHT].dy = dx;
  1395. slopes[V_RIGHT].k = 0;
  1396. /* bottom */
  1397. slopes[V_BOTTOM].dx = -dx;
  1398. slopes[V_BOTTOM].dy = -dy;
  1399. slopes[V_BOTTOM].k = k;
  1400. /* left */
  1401. slopes[V_LEFT].dx = dy;
  1402. slopes[V_LEFT].dy = -dx;
  1403. slopes[V_LEFT].k = 0;
  1404. /* preload the start coordinates */
  1405. vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
  1406. vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
  1407. vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
  1408. vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
  1409. if (projectLeft)
  1410. /* offset the vertices appropriately */
  1411. {
  1412. vertices[V_TOP].x -= rdx;
  1413. vertices[V_TOP].y -= rdy;
  1414. vertices[V_LEFT].x -= rdx;
  1415. vertices[V_LEFT].y -= rdy;
  1416. slopes[V_LEFT].k = rdx * dx + rdy * dy;
  1417. }
  1418. /* starting point for first dash (floating point) */
  1419. lcenterx = x1;
  1420. lcentery = y1;
  1421. if (pGC->capStyle == (int)MI_CAP_ROUND
  1422. || pGC->capStyle == (int)MI_CAP_TRIANGULAR)
  1423. /* keep track of starting face (need only in OnOff case) */
  1424. {
  1425. lcapFace.dx = dx;
  1426. lcapFace.dy = dy;
  1427. lcapFace.x = x1;
  1428. lcapFace.y = y1;
  1429. rcapFace.dx = -dx;
  1430. rcapFace.dy = -dy;
  1431. rcapFace.x = x1;
  1432. rcapFace.y = y1;
  1433. }
  1434. /* draw dashes until end of line segment is reached, and no additional
  1435. (complete) dash can be drawn */
  1436. LRemain = L;
  1437. while (LRemain > dashRemain)
  1438. {
  1439. dashDx = (dashRemain * dx) / L;
  1440. dashDy = (dashRemain * dy) / L;
  1441. /* ending point for dash */
  1442. rcenterx = lcenterx + dashDx;
  1443. rcentery = lcentery + dashDy;
  1444. vertices[V_RIGHT].x += dashDx;
  1445. vertices[V_RIGHT].y += dashDy;
  1446. vertices[V_BOTTOM].x += dashDx;
  1447. vertices[V_BOTTOM].y += dashDy;
  1448. slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
  1449. /* draw dash (if OnOffDash, don't draw `off' dashes) */
  1450. if (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH || !(paintType == 0))
  1451. {
  1452. if (pGC->lineStyle == (int)MI_LINE_ON_OFF_DASH &&
  1453. pGC->capStyle == (int)MI_CAP_PROJECTING)
  1454. /* will draw projecting caps, so save vertices for later use */
  1455. {
  1456. saveRight = vertices[V_RIGHT];
  1457. saveBottom = vertices[V_BOTTOM];
  1458. saveK = slopes[V_RIGHT].k;
  1459. if (!first)
  1460. {
  1461. vertices[V_TOP].x -= rdx;
  1462. vertices[V_TOP].y -= rdy;
  1463. vertices[V_LEFT].x -= rdx;
  1464. vertices[V_LEFT].y -= rdy;
  1465. slopes[V_LEFT].k = vertices[V_LEFT].x *
  1466. slopes[V_LEFT].dy -
  1467. vertices[V_LEFT].y *
  1468. slopes[V_LEFT].dx;
  1469. }
  1470. vertices[V_RIGHT].x += rdx;
  1471. vertices[V_RIGHT].y += rdy;
  1472. vertices[V_BOTTOM].x += rdx;
  1473. vertices[V_BOTTOM].y += rdy;
  1474. slopes[V_RIGHT].k = vertices[V_RIGHT].x *
  1475. slopes[V_RIGHT].dy -
  1476. vertices[V_RIGHT].y *
  1477. slopes[V_RIGHT].dx;
  1478. }
  1479. /* build lists of left and right edges for the dash, using the
  1480. just-computed array of slopes */
  1481. y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
  1482. left, right, &nleft, &nright, &h);
  1483. /* fill the dash, with either fg or bg color (alternates) */
  1484. miFillPolyHelper (paintedSet, pixel,
  1485. y, h, left, right, nleft, nright);
  1486. if (pGC->lineStyle == (int)MI_LINE_ON_OFF_DASH)
  1487. /* if doing OnOffDash, add caps if any */
  1488. {
  1489. switch ((int)pGC->capStyle)
  1490. {
  1491. case (int)MI_CAP_BUTT:
  1492. default:
  1493. break;
  1494. case (int)MI_CAP_PROJECTING:
  1495. /* use saved vertices */
  1496. vertices[V_BOTTOM] = saveBottom;
  1497. vertices[V_RIGHT] = saveRight;
  1498. slopes[V_RIGHT].k = saveK;
  1499. break;
  1500. case (int)MI_CAP_ROUND:
  1501. case (int)MI_CAP_TRIANGULAR:
  1502. if (!first)
  1503. {
  1504. if (dx < 0)
  1505. {
  1506. lcapFace.xa = -vertices[V_LEFT].x;
  1507. lcapFace.ya = -vertices[V_LEFT].y;
  1508. lcapFace.k = slopes[V_LEFT].k;
  1509. }
  1510. else
  1511. {
  1512. lcapFace.xa = vertices[V_TOP].x;
  1513. lcapFace.ya = vertices[V_TOP].y;
  1514. lcapFace.k = -slopes[V_LEFT].k;
  1515. }
  1516. /* invoke miLineArc, isInt = false, to draw half-disk
  1517. on left end of dash (only if dash is not first) */
  1518. miLineArc (paintedSet, pixel, pGC,
  1519. &lcapFace, (LineFace *) NULL,
  1520. lcenterx, lcentery, false);
  1521. }
  1522. if (dx < 0)
  1523. {
  1524. rcapFace.xa = vertices[V_BOTTOM].x;
  1525. rcapFace.ya = vertices[V_BOTTOM].y;
  1526. rcapFace.k = slopes[V_RIGHT].k;
  1527. }
  1528. else
  1529. {
  1530. rcapFace.xa = -vertices[V_RIGHT].x;
  1531. rcapFace.ya = -vertices[V_RIGHT].y;
  1532. rcapFace.k = -slopes[V_RIGHT].k;
  1533. }
  1534. /* invoke miLineArc, isInt = false, to draw half-disk on
  1535. right end of dash */
  1536. miLineArc (paintedSet, pixel, pGC,
  1537. (LineFace *)NULL, &rcapFace,
  1538. rcenterx, rcentery, false);
  1539. break;
  1540. }
  1541. }
  1542. }
  1543. /* we just drew a dash, or (in the OnOff case) we either drew a dash
  1544. or we didn't */
  1545. LRemain -= dashRemain; /* decrement float by int (distance over
  1546. which we just drew, i.e. the remainder
  1547. of current dash) */
  1548. /* bump absolute dash number, and index of dash in array (cyclically) */
  1549. ++dashNum;
  1550. ++dashIndex;
  1551. if (dashIndex == pGC->numInDashList)
  1552. dashIndex = 0;
  1553. dashRemain = (int)(pDash[dashIndex]); /* whole new dash now `remains' */
  1554. /* compute color of next dash */
  1555. paintType = (dashNum & 1) ? 0 : 1 + ((dashNum / 2) % (numPixels - 1));
  1556. pixel = pGC->pixels[paintType];
  1557. /* next dash will start where previous one ended */
  1558. lcenterx = rcenterx;
  1559. lcentery = rcentery;
  1560. vertices[V_TOP] = vertices[V_RIGHT];
  1561. vertices[V_LEFT] = vertices[V_BOTTOM];
  1562. slopes[V_LEFT].k = -slopes[V_RIGHT].k;
  1563. first = false; /* no longer first dash of line segment */
  1564. }
  1565. /* final portion of segment is dashed specially, with an incomplete dash */
  1566. if (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH || !(paintType == 0))
  1567. {
  1568. vertices[V_TOP].x -= dx;
  1569. vertices[V_TOP].y -= dy;
  1570. vertices[V_LEFT].x -= dx;
  1571. vertices[V_LEFT].y -= dy;
  1572. vertices[V_RIGHT].x = rdy;
  1573. vertices[V_RIGHT].y = -rdx;
  1574. vertices[V_BOTTOM].x = -rdy;
  1575. vertices[V_BOTTOM].y = rdx;
  1576. if (projectRight)
  1577. /* offset appropriately */
  1578. {
  1579. vertices[V_RIGHT].x += rdx;
  1580. vertices[V_RIGHT].y += rdy;
  1581. vertices[V_BOTTOM].x += rdx;
  1582. vertices[V_BOTTOM].y += rdy;
  1583. slopes[V_RIGHT].k = vertices[V_RIGHT].x *
  1584. slopes[V_RIGHT].dy -
  1585. vertices[V_RIGHT].y *
  1586. slopes[V_RIGHT].dx;
  1587. }
  1588. else
  1589. slopes[V_RIGHT].k = 0;
  1590. /* if OnOffDash line style and cap mode is projecting, offset the
  1591. face, so as to draw a projecting cap */
  1592. if (!first && pGC->lineStyle == (int)MI_LINE_ON_OFF_DASH
  1593. && pGC->capStyle == (int)MI_CAP_PROJECTING)
  1594. {
  1595. vertices[V_TOP].x -= rdx;
  1596. vertices[V_TOP].y -= rdy;
  1597. vertices[V_LEFT].x -= rdx;
  1598. vertices[V_LEFT].y -= rdy;
  1599. slopes[V_LEFT].k = vertices[V_LEFT].x *
  1600. slopes[V_LEFT].dy -
  1601. vertices[V_LEFT].y *
  1602. slopes[V_LEFT].dx;
  1603. }
  1604. else
  1605. slopes[V_LEFT].k += dx * dx + dy * dy;
  1606. /* build lists of left and right edges for the final incomplete dash,
  1607. using the just-computed vertices and slopes */
  1608. y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
  1609. left, right, &nleft, &nright, &h);
  1610. /* fill the final dash */
  1611. miFillPolyHelper (paintedSet, pixel,
  1612. y, h, left, right, nleft, nright);
  1613. /* if OnOffDash line style and cap mode is round, draw a round cap */
  1614. if (!first && pGC->lineStyle == (int)MI_LINE_ON_OFF_DASH
  1615. && (pGC->capStyle == (int)MI_CAP_ROUND
  1616. || pGC->capStyle == (int)MI_CAP_TRIANGULAR))
  1617. {
  1618. lcapFace.x = x2;
  1619. lcapFace.y = y2;
  1620. if (dx < 0)
  1621. {
  1622. lcapFace.xa = -vertices[V_LEFT].x;
  1623. lcapFace.ya = -vertices[V_LEFT].y;
  1624. lcapFace.k = slopes[V_LEFT].k;
  1625. }
  1626. else
  1627. {
  1628. lcapFace.xa = vertices[V_TOP].x;
  1629. lcapFace.ya = vertices[V_TOP].y;
  1630. lcapFace.k = -slopes[V_LEFT].k;
  1631. }
  1632. /* invoke miLineArc, isInt = false, to draw disk on end */
  1633. miLineArc (paintedSet, pixel, pGC,
  1634. &lcapFace, (LineFace *) NULL,
  1635. rcenterx, rcentery, false);
  1636. }
  1637. }
  1638. /* work out left and right faces of the dashed segment, to pass back */
  1639. leftFace->x = x1;
  1640. leftFace->y = y1;
  1641. leftFace->dx = dx;
  1642. leftFace->dy = dy;
  1643. leftFace->xa = rdy;
  1644. leftFace->ya = -rdx;
  1645. leftFace->k = k;
  1646. rightFace->x = x2;
  1647. rightFace->y = y2;
  1648. rightFace->dx = -dx;
  1649. rightFace->dy = -dy;
  1650. rightFace->xa = -rdy;
  1651. rightFace->ya = rdx;
  1652. rightFace->k = k;
  1653. /* update absolute dash number, dash index, dash offset */
  1654. dashRemain = (int)(((double) dashRemain) - LRemain);
  1655. if (dashRemain == 0) /* on to next dash in array */
  1656. {
  1657. dashNum++; /* bump absolute dash number */
  1658. dashIndex++;
  1659. if (dashIndex == pGC->numInDashList) /* wrap */
  1660. dashIndex = 0;
  1661. dashRemain = (int)(pDash[dashIndex]);
  1662. }
  1663. *pDashNum = dashNum;
  1664. *pDashIndex = dashIndex;
  1665. *pDashOffset = (int)(pDash[dashIndex]) - dashRemain;
  1666. }
  1667. /* Helper function, called by miWideDash() above and also by miZeroPolyArc
  1668. (in mi_zerarc.c) and miZeroDash (in mi_zerolin.c) to perform initial
  1669. offsetting into the dash array, before dash #0 is drawn. In all cases,
  1670. dashNum=0, dashIndex=0 and dashOffset=0. */
  1671. /* FIXME: a negative offset is not supported, and if it is, then some
  1672. places elsewhere in the code, which assume dashNum>=0, may need to be
  1673. fixed too. */
  1674. /* ARGS: dist = add'l offset (assumed >= 0)
  1675. pDashNum = dash number
  1676. pDashIndex = current dash
  1677. pDash = dash list
  1678. numInDashList = dashlist length
  1679. pDashOffset = offset into current dash */
  1680. void
  1681. miStepDash (int dist, int *pDashNum, int *pDashIndex, const unsigned int *pDash, int numInDashList, int *pDashOffset)
  1682. {
  1683. int dashNum, dashIndex, dashOffset;
  1684. int totallen;
  1685. int i;
  1686. dashNum = *pDashNum;
  1687. dashIndex = *pDashIndex;
  1688. dashOffset = *pDashOffset;
  1689. if (dashOffset + dist < (int)(pDash[dashIndex]))
  1690. /* offset won't take us beyond end of present dash */
  1691. {
  1692. *pDashOffset = dashOffset + dist;
  1693. return;
  1694. }
  1695. /* move to next dash */
  1696. dist -= (int)(pDash[dashIndex]) - dashOffset;
  1697. dashNum++;
  1698. dashIndex++;
  1699. if (dashIndex == numInDashList)
  1700. /* wrap to beginning of dash list */
  1701. dashIndex = 0;
  1702. /* make it easy on ourselves: work modulo iteration interval */
  1703. totallen = 0;
  1704. for (i = 0; i < numInDashList; i++)
  1705. totallen += (int)(pDash[i]);
  1706. if (totallen <= dist)
  1707. dist = dist % totallen;
  1708. while (dist >= (int)(pDash[dashIndex]))
  1709. {
  1710. dist -= (int)(pDash[dashIndex]);
  1711. dashNum++;
  1712. dashIndex++;
  1713. if (dashIndex == numInDashList)
  1714. /* wrap to beginning of dash list */
  1715. dashIndex = 0;
  1716. }
  1717. *pDashNum = dashNum;
  1718. *pDashIndex = dashIndex;
  1719. *pDashOffset = dist;
  1720. }
  1721. /* Draw a wide polyline, undashed (if width=0, this simply calls
  1722. miZeroLine) */
  1723. void
  1724. miWideLine (miPaintedSet *paintedSet, const miGC *pGC, miCoordMode mode, int npt, const miPoint *pPts)
  1725. {
  1726. int x1, y1, x2, y2;
  1727. bool projectLeft, projectRight;
  1728. LineFace leftFace, rightFace, prevRightFace;
  1729. LineFace firstFace;
  1730. int first;
  1731. bool somethingDrawn = false;
  1732. bool selfJoin;
  1733. /* ensure we have >=1 points */
  1734. if (npt <= 0)
  1735. return;
  1736. /* width 0 lines are handled specially */
  1737. if (pGC->lineWidth == 0)
  1738. {
  1739. miZeroLine (paintedSet, pGC, mode, npt, pPts);
  1740. return;
  1741. }
  1742. x2 = pPts->x;
  1743. y2 = pPts->y;
  1744. first = true;
  1745. /* determine whether polyline is closed */
  1746. selfJoin = false;
  1747. if (npt > 1)
  1748. {
  1749. if (mode == MI_COORD_MODE_PREVIOUS)
  1750. {
  1751. int nptTmp;
  1752. const miPoint *pPtsTmp;
  1753. x1 = x2;
  1754. y1 = y2;
  1755. nptTmp = npt;
  1756. pPtsTmp = pPts + 1;
  1757. while (--nptTmp)
  1758. {
  1759. x1 += pPtsTmp->x;
  1760. y1 += pPtsTmp->y;
  1761. ++pPtsTmp;
  1762. }
  1763. if (x2 == x1 && y2 == y1)
  1764. selfJoin = true;
  1765. }
  1766. else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
  1767. selfJoin = true;
  1768. }
  1769. /* line segments (except for the last) will not project right; they'll
  1770. project left if the cap mode is "projecting" */
  1771. projectLeft =
  1772. (pGC->capStyle == (int)MI_CAP_PROJECTING && !selfJoin) ? true : false;
  1773. projectRight = false;
  1774. /* iterate through points, drawing all line segments of nonzero length */
  1775. while (--npt)
  1776. {
  1777. x1 = x2;
  1778. y1 = y2;
  1779. ++pPts;
  1780. x2 = pPts->x;
  1781. y2 = pPts->y;
  1782. if (mode == MI_COORD_MODE_PREVIOUS)
  1783. {
  1784. x2 += x1;
  1785. y2 += y1;
  1786. }
  1787. if (x1 != x2 || y1 != y2)
  1788. /* nonzero length */
  1789. {
  1790. somethingDrawn = true;
  1791. if (npt == 1 && pGC->capStyle == (int)MI_CAP_PROJECTING && !selfJoin)
  1792. /* last point; and need a projecting cap here */
  1793. projectRight = true;
  1794. /* draw segment (pixel=1), returning faces */
  1795. miWideSegment (paintedSet, pGC->pixels[1], pGC,
  1796. x1, y1, x2, y2,
  1797. projectLeft, projectRight, &leftFace, &rightFace);
  1798. if (first)
  1799. /* first line segment, draw round cap if needed */
  1800. {
  1801. if (selfJoin)
  1802. firstFace = leftFace;
  1803. else if (pGC->capStyle == (int)MI_CAP_ROUND
  1804. || pGC->capStyle == (int)MI_CAP_TRIANGULAR)
  1805. /* invoke miLineArc, isInt = true, to draw a round cap
  1806. on left face in paint type #1 */
  1807. miLineArc (paintedSet, pGC->pixels[1], pGC,
  1808. &leftFace, (LineFace *)NULL,
  1809. (double)0.0, (double)0.0,
  1810. true);
  1811. }
  1812. else
  1813. /* general case: draw join at beginning of segment (pixel=1) */
  1814. miLineJoin (paintedSet, pGC->pixels[1], pGC,
  1815. &leftFace, &prevRightFace);
  1816. prevRightFace = rightFace;
  1817. first = false;
  1818. projectLeft = false;
  1819. }
  1820. /* final point of polyline */
  1821. if (npt == 1 && somethingDrawn)
  1822. {
  1823. if (selfJoin)
  1824. /* add line join to close the polyline, pixel=1 */
  1825. miLineJoin (paintedSet, pGC->pixels[1], pGC,
  1826. &firstFace, &rightFace);
  1827. else if (pGC->capStyle == (int)MI_CAP_ROUND
  1828. || pGC->capStyle == (int)MI_CAP_TRIANGULAR)
  1829. /* invoke miLineArc, isInt = true, to draw round cap
  1830. on right face, pixel=1 */
  1831. miLineArc (paintedSet, pGC->pixels[1], pGC,
  1832. (LineFace *)NULL, &rightFace,
  1833. (double)0.0, (double)0.0,
  1834. true);
  1835. }
  1836. }
  1837. /* handle crock where all points are coincident */
  1838. if (!somethingDrawn)
  1839. {
  1840. projectLeft = (pGC->capStyle == (int)MI_CAP_PROJECTING) ? true : false;
  1841. miWideSegment (paintedSet, pGC->pixels[1], pGC, /* pixel=1 */
  1842. x2, y2, x2, y2, projectLeft, projectLeft,
  1843. &leftFace, &rightFace);
  1844. if (pGC->capStyle == (int)MI_CAP_ROUND
  1845. || pGC->capStyle == (int)MI_CAP_TRIANGULAR)
  1846. {
  1847. /* invoke miLineArc, isInt = true, to draw round cap
  1848. in paint type #1 */
  1849. miLineArc (paintedSet, pGC->pixels[1], pGC,
  1850. &leftFace, (LineFace *)NULL,
  1851. (double)0.0, (double)0.0,
  1852. true);
  1853. /* invoke miLineArc, isInt = true, to draw other round cap
  1854. in paint type #1 */
  1855. rightFace.dx = -1; /* sleazy hack to make it work */
  1856. miLineArc (paintedSet, pGC->pixels[1], pGC,
  1857. (LineFace *) NULL, &rightFace,
  1858. (double)0.0, (double)0.0,
  1859. true);
  1860. }
  1861. }
  1862. }
  1863. /* Helper function, called by miWideLine() with pixel=1. Draw a single
  1864. segment of a wide polyline, taking into account projecting caps, but not
  1865. round caps. Also pass back left and right faces for the line segment,
  1866. for possible use in adding caps or joins. */
  1867. static void
  1868. miWideSegment (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, int x1, int y1, int x2, int y2, bool projectLeft, bool projectRight, LineFace *leftFace, LineFace *rightFace)
  1869. {
  1870. int dx, dy;
  1871. int x, y;
  1872. int signdx;
  1873. int lw = (int)(pGC->lineWidth);
  1874. if (y2 < y1 || (y2 == y1 && x2 < x1))
  1875. /* interchange, so as always to draw top-to-bottom, or left-to-right if
  1876. horizontal */
  1877. {
  1878. int tx, ty;
  1879. bool tbool;
  1880. LineFace *tface;
  1881. tx = x1;
  1882. x1 = x2;
  1883. x2 = tx;
  1884. ty = y1;
  1885. y1 = y2;
  1886. y2 = ty;
  1887. tbool = projectLeft;
  1888. projectLeft = projectRight;
  1889. projectRight = tbool;
  1890. tface = leftFace;
  1891. leftFace = rightFace;
  1892. rightFace = tface;
  1893. }
  1894. dy = y2 - y1;
  1895. signdx = 1;
  1896. dx = x2 - x1;
  1897. if (dx < 0)
  1898. signdx = -1;
  1899. leftFace->x = x1;
  1900. leftFace->y = y1;
  1901. leftFace->dx = dx;
  1902. leftFace->dy = dy;
  1903. rightFace->x = x2;
  1904. rightFace->y = y2;
  1905. rightFace->dx = -dx; /* for faces, (dx,dy) points _into_ line */
  1906. rightFace->dy = -dy;
  1907. if (dy == 0)
  1908. /* segment is horizontal */
  1909. {
  1910. rightFace->xa = 0;
  1911. rightFace->ya = 0.5 * (double)lw;
  1912. rightFace->k = -0.5 * (double)(lw * dx); /* k = xa * dy - ya * dx */
  1913. leftFace->xa = 0;
  1914. leftFace->ya = -rightFace->ya;
  1915. leftFace->k = rightFace->k; /* k = xa * dy - ya * dx */
  1916. x = x1;
  1917. if (projectLeft)
  1918. x -= (lw >> 1);
  1919. y = y1 - (lw >> 1);
  1920. dx = x2 - x;
  1921. if (projectRight)
  1922. dx += ((lw + 1) >> 1);
  1923. dy = lw;
  1924. miFillRectPolyHelper (paintedSet, pixel,
  1925. x, y, (unsigned int)dx, (unsigned int)dy);
  1926. }
  1927. else if (dx == 0)
  1928. /* segment is vertical */
  1929. {
  1930. leftFace->xa = 0.5 * (double)lw;
  1931. leftFace->ya = 0;
  1932. leftFace->k = 0.5 * (double)(lw * dy); /* k = xa * dy - ya * dx */
  1933. rightFace->xa = -leftFace->xa;
  1934. rightFace->ya = 0;
  1935. rightFace->k = leftFace->k; /* k = xa * dy - ya * dx */
  1936. y = y1;
  1937. if (projectLeft)
  1938. y -= lw >> 1;
  1939. x = x1 - (lw >> 1);
  1940. dy = y2 - y;
  1941. if (projectRight)
  1942. dy += ((lw + 1) >> 1);
  1943. dx = lw;
  1944. miFillRectPolyHelper (paintedSet, pixel,
  1945. x, y, (unsigned int)dx, (unsigned int)dy);
  1946. }
  1947. else
  1948. /* general case: segment is neither horizontal nor vertical */
  1949. {
  1950. double l, L, r;
  1951. double xa, ya;
  1952. double projectXoff = 0.0, projectYoff = 0.0;
  1953. double k;
  1954. double maxy;
  1955. int finaly;
  1956. int lefty, righty, topy, bottomy;
  1957. PolyEdge lefts[2], rights[2];
  1958. PolyEdge *left, *right;
  1959. PolyEdge *top, *bottom;
  1960. l = 0.5 * ((double) lw);
  1961. L = hypot ((double) dx, (double) dy);
  1962. if (dx < 0)
  1963. {
  1964. right = &rights[1];
  1965. left = &lefts[0];
  1966. top = &rights[0];
  1967. bottom = &lefts[1];
  1968. }
  1969. else
  1970. {
  1971. right = &rights[0];
  1972. left = &lefts[1];
  1973. top = &lefts[0];
  1974. bottom = &rights[1];
  1975. }
  1976. r = l / L; /* this is ell / L, not 1 / L */
  1977. ya = -r * dx;
  1978. xa = r * dy;
  1979. if (projectLeft | projectRight)
  1980. {
  1981. projectXoff = -ya;
  1982. projectYoff = xa;
  1983. }
  1984. /* build first long edge */
  1985. k = l * L; /* xa * dy - ya * dx */
  1986. leftFace->xa = xa;
  1987. leftFace->ya = ya;
  1988. leftFace->k = k;
  1989. rightFace->xa = -xa;
  1990. rightFace->ya = -ya;
  1991. rightFace->k = k;
  1992. if (projectLeft)
  1993. righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  1994. k, dx, dy,
  1995. x1, y1, false, right);
  1996. else
  1997. righty = miPolyBuildEdge (xa, ya,
  1998. k, dx, dy,
  1999. x1, y1, false, right);
  2000. /* build second long edge */
  2001. ya = -ya;
  2002. xa = -xa;
  2003. k = -k; /* xa * dy - ya * dx */
  2004. if (projectLeft)
  2005. lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  2006. k, dx, dy,
  2007. x1, y1, true, left);
  2008. else
  2009. lefty = miPolyBuildEdge (xa, ya,
  2010. k, dx, dy,
  2011. x1, y1, true, left);
  2012. /* build first short edge, on left end */
  2013. if (signdx > 0)
  2014. {
  2015. ya = -ya;
  2016. xa = -xa;
  2017. }
  2018. if (projectLeft)
  2019. {
  2020. double xap = xa - projectXoff;
  2021. double yap = ya - projectYoff;
  2022. topy = miPolyBuildEdge (xap, yap,
  2023. xap * dx + yap * dy, -dy, dx,
  2024. x1, y1, (dx > 0 ? true : false), top);
  2025. }
  2026. else
  2027. topy = miPolyBuildEdge (xa, ya,
  2028. 0.0, -dy, dx,
  2029. x1, y1, (dx > 0 ? true : false), top);
  2030. /* build second short edge, on right end */
  2031. if (projectRight)
  2032. {
  2033. double xap = xa + projectXoff;
  2034. double yap = ya + projectYoff;
  2035. bottomy = miPolyBuildEdge (xap, yap,
  2036. xap * dx + yap * dy, -dy, dx,
  2037. x2, y2, (dx < 0 ? true : false), bottom);
  2038. maxy = -ya + projectYoff;
  2039. }
  2040. else
  2041. {
  2042. bottomy = miPolyBuildEdge (xa, ya,
  2043. 0.0, -dy, dx,
  2044. x2, y2, (dx < 0 ? true : false), bottom);
  2045. maxy = -ya;
  2046. }
  2047. finaly = ICEIL (maxy) + y2;
  2048. if (dx < 0)
  2049. {
  2050. left->height = (unsigned int)(bottomy - lefty);
  2051. right->height = (unsigned int)(finaly - righty);
  2052. top->height = (unsigned int)(righty - topy);
  2053. }
  2054. else
  2055. {
  2056. right->height = (unsigned int)(bottomy - righty);
  2057. left->height = (unsigned int)(finaly - lefty);
  2058. top->height = (unsigned int)(lefty - topy);
  2059. }
  2060. bottom->height = (unsigned int)(finaly - bottomy);
  2061. /* fill the rectangle (2 left edges, 2 right edges) */
  2062. miFillPolyHelper (paintedSet, pixel, topy,
  2063. (unsigned int)(bottom->height + bottomy - topy),
  2064. lefts, rights, 2, 2);
  2065. }
  2066. }