draw_path.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. #include "fitz-internal.h"
  2. #define MAX_DEPTH 8
  3. static void
  4. line(fz_gel *gel, const fz_matrix *ctm, float x0, float y0, float x1, float y1)
  5. {
  6. float tx0 = ctm->a * x0 + ctm->c * y0 + ctm->e;
  7. float ty0 = ctm->b * x0 + ctm->d * y0 + ctm->f;
  8. float tx1 = ctm->a * x1 + ctm->c * y1 + ctm->e;
  9. float ty1 = ctm->b * x1 + ctm->d * y1 + ctm->f;
  10. fz_insert_gel(gel, tx0, ty0, tx1, ty1);
  11. }
  12. static void
  13. bezier(fz_gel *gel, const fz_matrix *ctm, float flatness,
  14. float xa, float ya,
  15. float xb, float yb,
  16. float xc, float yc,
  17. float xd, float yd, int depth)
  18. {
  19. float dmax;
  20. float xab, yab;
  21. float xbc, ybc;
  22. float xcd, ycd;
  23. float xabc, yabc;
  24. float xbcd, ybcd;
  25. float xabcd, yabcd;
  26. /* termination check */
  27. dmax = fz_abs(xa - xb);
  28. dmax = fz_max(dmax, fz_abs(ya - yb));
  29. dmax = fz_max(dmax, fz_abs(xd - xc));
  30. dmax = fz_max(dmax, fz_abs(yd - yc));
  31. if (dmax < flatness || depth >= MAX_DEPTH)
  32. {
  33. line(gel, ctm, xa, ya, xd, yd);
  34. return;
  35. }
  36. xab = xa + xb;
  37. yab = ya + yb;
  38. xbc = xb + xc;
  39. ybc = yb + yc;
  40. xcd = xc + xd;
  41. ycd = yc + yd;
  42. xabc = xab + xbc;
  43. yabc = yab + ybc;
  44. xbcd = xbc + xcd;
  45. ybcd = ybc + ycd;
  46. xabcd = xabc + xbcd;
  47. yabcd = yabc + ybcd;
  48. xab *= 0.5f; yab *= 0.5f;
  49. xbc *= 0.5f; ybc *= 0.5f;
  50. xcd *= 0.5f; ycd *= 0.5f;
  51. xabc *= 0.25f; yabc *= 0.25f;
  52. xbcd *= 0.25f; ybcd *= 0.25f;
  53. xabcd *= 0.125f; yabcd *= 0.125f;
  54. bezier(gel, ctm, flatness, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1);
  55. bezier(gel, ctm, flatness, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1);
  56. }
  57. void
  58. fz_flatten_fill_path(fz_gel *gel, fz_path *path, const fz_matrix *ctm, float flatness)
  59. {
  60. float x1, y1, x2, y2, x3, y3;
  61. float cx = 0;
  62. float cy = 0;
  63. float bx = 0;
  64. float by = 0;
  65. int i = 0;
  66. while (i < path->len)
  67. {
  68. switch (path->items[i++].k)
  69. {
  70. case FZ_MOVETO:
  71. /* implicit closepath before moveto */
  72. if (cx != bx || cy != by)
  73. line(gel, ctm, cx, cy, bx, by);
  74. x1 = path->items[i++].v;
  75. y1 = path->items[i++].v;
  76. cx = bx = x1;
  77. cy = by = y1;
  78. break;
  79. case FZ_LINETO:
  80. x1 = path->items[i++].v;
  81. y1 = path->items[i++].v;
  82. line(gel, ctm, cx, cy, x1, y1);
  83. cx = x1;
  84. cy = y1;
  85. break;
  86. case FZ_CURVETO:
  87. x1 = path->items[i++].v;
  88. y1 = path->items[i++].v;
  89. x2 = path->items[i++].v;
  90. y2 = path->items[i++].v;
  91. x3 = path->items[i++].v;
  92. y3 = path->items[i++].v;
  93. bezier(gel, ctm, flatness, cx, cy, x1, y1, x2, y2, x3, y3, 0);
  94. cx = x3;
  95. cy = y3;
  96. break;
  97. case FZ_CLOSE_PATH:
  98. line(gel, ctm, cx, cy, bx, by);
  99. cx = bx;
  100. cy = by;
  101. break;
  102. }
  103. }
  104. if (cx != bx || cy != by)
  105. line(gel, ctm, cx, cy, bx, by);
  106. }
  107. struct sctx
  108. {
  109. fz_gel *gel;
  110. const fz_matrix *ctm;
  111. float flatness;
  112. int linejoin;
  113. float linewidth;
  114. float miterlimit;
  115. fz_point beg[2];
  116. fz_point seg[2];
  117. int sn, bn;
  118. int dot;
  119. int from_bezier;
  120. float *dash_list;
  121. float dash_phase;
  122. int dash_len;
  123. int toggle, cap;
  124. int offset;
  125. float phase;
  126. fz_point cur;
  127. };
  128. static void
  129. fz_add_line(struct sctx *s, float x0, float y0, float x1, float y1)
  130. {
  131. float tx0 = s->ctm->a * x0 + s->ctm->c * y0 + s->ctm->e;
  132. float ty0 = s->ctm->b * x0 + s->ctm->d * y0 + s->ctm->f;
  133. float tx1 = s->ctm->a * x1 + s->ctm->c * y1 + s->ctm->e;
  134. float ty1 = s->ctm->b * x1 + s->ctm->d * y1 + s->ctm->f;
  135. fz_insert_gel(s->gel, tx0, ty0, tx1, ty1);
  136. }
  137. static void
  138. fz_add_arc(struct sctx *s,
  139. float xc, float yc,
  140. float x0, float y0,
  141. float x1, float y1)
  142. {
  143. float th0, th1, r;
  144. float theta;
  145. float ox, oy, nx, ny;
  146. int n, i;
  147. r = fabsf(s->linewidth);
  148. theta = 2 * (float)M_SQRT2 * sqrtf(s->flatness / r);
  149. th0 = atan2f(y0, x0);
  150. th1 = atan2f(y1, x1);
  151. if (r > 0)
  152. {
  153. if (th0 < th1)
  154. th0 += (float)M_PI * 2;
  155. n = ceilf((th0 - th1) / theta);
  156. }
  157. else
  158. {
  159. if (th1 < th0)
  160. th1 += (float)M_PI * 2;
  161. n = ceilf((th1 - th0) / theta);
  162. }
  163. ox = x0;
  164. oy = y0;
  165. for (i = 1; i < n; i++)
  166. {
  167. theta = th0 + (th1 - th0) * i / n;
  168. nx = cosf(theta) * r;
  169. ny = sinf(theta) * r;
  170. fz_add_line(s, xc + ox, yc + oy, xc + nx, yc + ny);
  171. ox = nx;
  172. oy = ny;
  173. }
  174. fz_add_line(s, xc + ox, yc + oy, xc + x1, yc + y1);
  175. }
  176. static void
  177. fz_add_line_stroke(struct sctx *s, fz_point a, fz_point b)
  178. {
  179. float dx = b.x - a.x;
  180. float dy = b.y - a.y;
  181. float scale = s->linewidth / sqrtf(dx * dx + dy * dy);
  182. float dlx = dy * scale;
  183. float dly = -dx * scale;
  184. fz_add_line(s, a.x - dlx, a.y - dly, b.x - dlx, b.y - dly);
  185. fz_add_line(s, b.x + dlx, b.y + dly, a.x + dlx, a.y + dly);
  186. }
  187. static void
  188. fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c, int join_under)
  189. {
  190. float miterlimit = s->miterlimit;
  191. float linewidth = s->linewidth;
  192. fz_linejoin linejoin = s->linejoin;
  193. float dx0, dy0;
  194. float dx1, dy1;
  195. float dlx0, dly0;
  196. float dlx1, dly1;
  197. float dmx, dmy;
  198. float dmr2;
  199. float scale;
  200. float cross;
  201. float len0, len1;
  202. dx0 = b.x - a.x;
  203. dy0 = b.y - a.y;
  204. dx1 = c.x - b.x;
  205. dy1 = c.y - b.y;
  206. cross = dx1 * dy0 - dx0 * dy1;
  207. /* Ensure that cross >= 0 */
  208. if (cross < 0)
  209. {
  210. float tmp;
  211. tmp = dx1; dx1 = -dx0; dx0 = -tmp;
  212. tmp = dy1; dy1 = -dy0; dy0 = -tmp;
  213. cross = -cross;
  214. }
  215. len0 = dx0 * dx0 + dy0 * dy0;
  216. if (len0 < FLT_EPSILON)
  217. linejoin = FZ_LINEJOIN_BEVEL;
  218. len1 = dx1 * dx1 + dy1 * dy1;
  219. if (len1 < FLT_EPSILON)
  220. linejoin = FZ_LINEJOIN_BEVEL;
  221. scale = linewidth / sqrtf(len0);
  222. dlx0 = dy0 * scale;
  223. dly0 = -dx0 * scale;
  224. scale = linewidth / sqrtf(len1);
  225. dlx1 = dy1 * scale;
  226. dly1 = -dx1 * scale;
  227. dmx = (dlx0 + dlx1) * 0.5f;
  228. dmy = (dly0 + dly1) * 0.5f;
  229. dmr2 = dmx * dmx + dmy * dmy;
  230. if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0)
  231. linejoin = FZ_LINEJOIN_BEVEL;
  232. if (join_under)
  233. {
  234. fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0);
  235. }
  236. else
  237. {
  238. fz_add_line(s, b.x + dlx1, b.y + dly1, b.x, b.y);
  239. fz_add_line(s, b.x, b.y, b.x + dlx0, b.y + dly0);
  240. }
  241. /* XPS miter joins are clipped at miterlength, rather than simply
  242. * being converted to bevelled joins. */
  243. if (linejoin == FZ_LINEJOIN_MITER_XPS)
  244. {
  245. if (cross == 0)
  246. linejoin = FZ_LINEJOIN_BEVEL;
  247. else if (dmr2 * miterlimit * miterlimit >= linewidth * linewidth)
  248. linejoin = FZ_LINEJOIN_MITER;
  249. else
  250. {
  251. float k, t0x, t0y, t1x, t1y;
  252. scale = linewidth * linewidth / dmr2;
  253. dmx *= scale;
  254. dmy *= scale;
  255. k = (scale - linewidth * miterlimit / sqrtf(dmr2)) / (scale - 1);
  256. t0x = b.x - dmx + k * (dmx - dlx0);
  257. t0y = b.y - dmy + k * (dmy - dly0);
  258. t1x = b.x - dmx + k * (dmx - dlx1);
  259. t1y = b.y - dmy + k * (dmy - dly1);
  260. fz_add_line(s, b.x - dlx0, b.y - dly0, t0x, t0y);
  261. fz_add_line(s, t0x, t0y, t1x, t1y);
  262. fz_add_line(s, t1x, t1y, b.x - dlx1, b.y - dly1);
  263. }
  264. }
  265. else if (linejoin == FZ_LINEJOIN_MITER)
  266. if (dmr2 * miterlimit * miterlimit < linewidth * linewidth)
  267. linejoin = FZ_LINEJOIN_BEVEL;
  268. if (linejoin == FZ_LINEJOIN_MITER)
  269. {
  270. scale = linewidth * linewidth / dmr2;
  271. dmx *= scale;
  272. dmy *= scale;
  273. fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dmx, b.y - dmy);
  274. fz_add_line(s, b.x - dmx, b.y - dmy, b.x - dlx1, b.y - dly1);
  275. }
  276. if (linejoin == FZ_LINEJOIN_BEVEL)
  277. {
  278. fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1);
  279. }
  280. if (linejoin == FZ_LINEJOIN_ROUND)
  281. {
  282. fz_add_arc(s, b.x, b.y, -dlx0, -dly0, -dlx1, -dly1);
  283. }
  284. }
  285. static void
  286. fz_add_line_cap(struct sctx *s, fz_point a, fz_point b, fz_linecap linecap)
  287. {
  288. float flatness = s->flatness;
  289. float linewidth = s->linewidth;
  290. float dx = b.x - a.x;
  291. float dy = b.y - a.y;
  292. float scale = linewidth / sqrtf(dx * dx + dy * dy);
  293. float dlx = dy * scale;
  294. float dly = -dx * scale;
  295. if (linecap == FZ_LINECAP_BUTT)
  296. fz_add_line(s, b.x - dlx, b.y - dly, b.x + dlx, b.y + dly);
  297. if (linecap == FZ_LINECAP_ROUND)
  298. {
  299. int i;
  300. int n = ceilf((float)M_PI / (2.0f * (float)M_SQRT2 * sqrtf(flatness / linewidth)));
  301. float ox = b.x - dlx;
  302. float oy = b.y - dly;
  303. for (i = 1; i < n; i++)
  304. {
  305. float theta = (float)M_PI * i / n;
  306. float cth = cosf(theta);
  307. float sth = sinf(theta);
  308. float nx = b.x - dlx * cth - dly * sth;
  309. float ny = b.y - dly * cth + dlx * sth;
  310. fz_add_line(s, ox, oy, nx, ny);
  311. ox = nx;
  312. oy = ny;
  313. }
  314. fz_add_line(s, ox, oy, b.x + dlx, b.y + dly);
  315. }
  316. if (linecap == FZ_LINECAP_SQUARE)
  317. {
  318. fz_add_line(s, b.x - dlx, b.y - dly,
  319. b.x - dlx - dly, b.y - dly + dlx);
  320. fz_add_line(s, b.x - dlx - dly, b.y - dly + dlx,
  321. b.x + dlx - dly, b.y + dly + dlx);
  322. fz_add_line(s, b.x + dlx - dly, b.y + dly + dlx,
  323. b.x + dlx, b.y + dly);
  324. }
  325. if (linecap == FZ_LINECAP_TRIANGLE)
  326. {
  327. float mx = -dly;
  328. float my = dlx;
  329. fz_add_line(s, b.x - dlx, b.y - dly, b.x + mx, b.y + my);
  330. fz_add_line(s, b.x + mx, b.y + my, b.x + dlx, b.y + dly);
  331. }
  332. }
  333. static void
  334. fz_add_line_dot(struct sctx *s, fz_point a)
  335. {
  336. float flatness = s->flatness;
  337. float linewidth = s->linewidth;
  338. int n = ceilf((float)M_PI / ((float)M_SQRT2 * sqrtf(flatness / linewidth)));
  339. float ox = a.x - linewidth;
  340. float oy = a.y;
  341. int i;
  342. for (i = 1; i < n; i++)
  343. {
  344. float theta = (float)M_PI * 2 * i / n;
  345. float cth = cosf(theta);
  346. float sth = sinf(theta);
  347. float nx = a.x - cth * linewidth;
  348. float ny = a.y + sth * linewidth;
  349. fz_add_line(s, ox, oy, nx, ny);
  350. ox = nx;
  351. oy = ny;
  352. }
  353. fz_add_line(s, ox, oy, a.x - linewidth, a.y);
  354. }
  355. static void
  356. fz_stroke_flush(struct sctx *s, fz_linecap start_cap, fz_linecap end_cap)
  357. {
  358. if (s->sn == 2)
  359. {
  360. fz_add_line_cap(s, s->beg[1], s->beg[0], start_cap);
  361. fz_add_line_cap(s, s->seg[0], s->seg[1], end_cap);
  362. }
  363. else if (s->dot)
  364. {
  365. fz_add_line_dot(s, s->beg[0]);
  366. }
  367. }
  368. static void
  369. fz_stroke_moveto(struct sctx *s, fz_point cur)
  370. {
  371. s->seg[0] = cur;
  372. s->beg[0] = cur;
  373. s->sn = 1;
  374. s->bn = 1;
  375. s->dot = 0;
  376. s->from_bezier = 0;
  377. }
  378. static void
  379. fz_stroke_lineto(struct sctx *s, fz_point cur, int from_bezier)
  380. {
  381. float dx = cur.x - s->seg[s->sn-1].x;
  382. float dy = cur.y - s->seg[s->sn-1].y;
  383. if (dx * dx + dy * dy < FLT_EPSILON)
  384. {
  385. if (s->cap == FZ_LINECAP_ROUND || s->dash_list)
  386. s->dot = 1;
  387. return;
  388. }
  389. fz_add_line_stroke(s, s->seg[s->sn-1], cur);
  390. if (s->sn == 2)
  391. {
  392. fz_add_line_join(s, s->seg[0], s->seg[1], cur, s->from_bezier & from_bezier);
  393. s->seg[0] = s->seg[1];
  394. s->seg[1] = cur;
  395. }
  396. s->from_bezier = from_bezier;
  397. if (s->sn == 1)
  398. s->seg[s->sn++] = cur;
  399. if (s->bn == 1)
  400. s->beg[s->bn++] = cur;
  401. }
  402. static void
  403. fz_stroke_closepath(struct sctx *s)
  404. {
  405. if (s->sn == 2)
  406. {
  407. fz_stroke_lineto(s, s->beg[0], 0);
  408. if (s->seg[1].x == s->beg[0].x && s->seg[1].y == s->beg[0].y)
  409. fz_add_line_join(s, s->seg[0], s->beg[0], s->beg[1], 0);
  410. else
  411. fz_add_line_join(s, s->seg[1], s->beg[0], s->beg[1], 0);
  412. }
  413. else if (s->dot)
  414. {
  415. fz_add_line_dot(s, s->beg[0]);
  416. }
  417. s->seg[0] = s->beg[0];
  418. s->bn = 1;
  419. s->sn = 1;
  420. s->dot = 0;
  421. s->from_bezier = 0;
  422. }
  423. static void
  424. fz_stroke_bezier(struct sctx *s,
  425. float xa, float ya,
  426. float xb, float yb,
  427. float xc, float yc,
  428. float xd, float yd, int depth)
  429. {
  430. float dmax;
  431. float xab, yab;
  432. float xbc, ybc;
  433. float xcd, ycd;
  434. float xabc, yabc;
  435. float xbcd, ybcd;
  436. float xabcd, yabcd;
  437. /* termination check */
  438. dmax = fz_abs(xa - xb);
  439. dmax = fz_max(dmax, fz_abs(ya - yb));
  440. dmax = fz_max(dmax, fz_abs(xd - xc));
  441. dmax = fz_max(dmax, fz_abs(yd - yc));
  442. if (dmax < s->flatness || depth >= MAX_DEPTH)
  443. {
  444. fz_point p;
  445. p.x = xd;
  446. p.y = yd;
  447. fz_stroke_lineto(s, p, 1);
  448. return;
  449. }
  450. xab = xa + xb;
  451. yab = ya + yb;
  452. xbc = xb + xc;
  453. ybc = yb + yc;
  454. xcd = xc + xd;
  455. ycd = yc + yd;
  456. xabc = xab + xbc;
  457. yabc = yab + ybc;
  458. xbcd = xbc + xcd;
  459. ybcd = ybc + ycd;
  460. xabcd = xabc + xbcd;
  461. yabcd = yabc + ybcd;
  462. xab *= 0.5f; yab *= 0.5f;
  463. xbc *= 0.5f; ybc *= 0.5f;
  464. xcd *= 0.5f; ycd *= 0.5f;
  465. xabc *= 0.25f; yabc *= 0.25f;
  466. xbcd *= 0.25f; ybcd *= 0.25f;
  467. xabcd *= 0.125f; yabcd *= 0.125f;
  468. fz_stroke_bezier(s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1);
  469. fz_stroke_bezier(s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1);
  470. }
  471. void
  472. fz_flatten_stroke_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth)
  473. {
  474. struct sctx s;
  475. fz_point p0, p1, p2, p3;
  476. int i;
  477. s.gel = gel;
  478. s.ctm = ctm;
  479. s.flatness = flatness;
  480. s.linejoin = stroke->linejoin;
  481. s.linewidth = linewidth * 0.5f; /* hairlines use a different value from the path value */
  482. s.miterlimit = stroke->miterlimit;
  483. s.sn = 0;
  484. s.bn = 0;
  485. s.dot = 0;
  486. s.dash_list = NULL;
  487. s.dash_phase = 0;
  488. s.dash_len = 0;
  489. s.toggle = 0;
  490. s.offset = 0;
  491. s.phase = 0;
  492. s.cap = stroke->start_cap;
  493. i = 0;
  494. if (path->len > 0 && path->items[0].k != FZ_MOVETO)
  495. return;
  496. p0.x = p0.y = 0;
  497. while (i < path->len)
  498. {
  499. switch (path->items[i++].k)
  500. {
  501. case FZ_MOVETO:
  502. p1.x = path->items[i++].v;
  503. p1.y = path->items[i++].v;
  504. fz_stroke_flush(&s, stroke->start_cap, stroke->end_cap);
  505. fz_stroke_moveto(&s, p1);
  506. p0 = p1;
  507. break;
  508. case FZ_LINETO:
  509. p1.x = path->items[i++].v;
  510. p1.y = path->items[i++].v;
  511. fz_stroke_lineto(&s, p1, 0);
  512. p0 = p1;
  513. break;
  514. case FZ_CURVETO:
  515. p1.x = path->items[i++].v;
  516. p1.y = path->items[i++].v;
  517. p2.x = path->items[i++].v;
  518. p2.y = path->items[i++].v;
  519. p3.x = path->items[i++].v;
  520. p3.y = path->items[i++].v;
  521. fz_stroke_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0);
  522. p0 = p3;
  523. break;
  524. case FZ_CLOSE_PATH:
  525. fz_stroke_closepath(&s);
  526. break;
  527. }
  528. }
  529. fz_stroke_flush(&s, stroke->start_cap, stroke->end_cap);
  530. }
  531. static void
  532. fz_dash_moveto(struct sctx *s, fz_point a, fz_linecap start_cap, fz_linecap end_cap)
  533. {
  534. s->toggle = 1;
  535. s->offset = 0;
  536. s->phase = s->dash_phase;
  537. while (s->phase >= s->dash_list[s->offset])
  538. {
  539. s->toggle = !s->toggle;
  540. s->phase -= s->dash_list[s->offset];
  541. s->offset ++;
  542. if (s->offset == s->dash_len)
  543. s->offset = 0;
  544. }
  545. s->cur = a;
  546. if (s->toggle)
  547. {
  548. fz_stroke_flush(s, s->cap, end_cap);
  549. s->cap = start_cap;
  550. fz_stroke_moveto(s, a);
  551. }
  552. }
  553. static void
  554. fz_dash_lineto(struct sctx *s, fz_point b, int dash_cap, int from_bezier)
  555. {
  556. float dx, dy;
  557. float total, used, ratio;
  558. fz_point a;
  559. fz_point m;
  560. a = s->cur;
  561. dx = b.x - a.x;
  562. dy = b.y - a.y;
  563. total = sqrtf(dx * dx + dy * dy);
  564. used = 0;
  565. while (total - used > s->dash_list[s->offset] - s->phase)
  566. {
  567. used += s->dash_list[s->offset] - s->phase;
  568. ratio = used / total;
  569. m.x = a.x + ratio * dx;
  570. m.y = a.y + ratio * dy;
  571. if (s->toggle)
  572. {
  573. fz_stroke_lineto(s, m, from_bezier);
  574. }
  575. else
  576. {
  577. fz_stroke_flush(s, s->cap, dash_cap);
  578. s->cap = dash_cap;
  579. fz_stroke_moveto(s, m);
  580. }
  581. s->toggle = !s->toggle;
  582. s->phase = 0;
  583. s->offset ++;
  584. if (s->offset == s->dash_len)
  585. s->offset = 0;
  586. }
  587. s->phase += total - used;
  588. s->cur = b;
  589. if (s->toggle)
  590. {
  591. fz_stroke_lineto(s, b, from_bezier);
  592. }
  593. }
  594. static void
  595. fz_dash_bezier(struct sctx *s,
  596. float xa, float ya,
  597. float xb, float yb,
  598. float xc, float yc,
  599. float xd, float yd, int depth,
  600. int dash_cap)
  601. {
  602. float dmax;
  603. float xab, yab;
  604. float xbc, ybc;
  605. float xcd, ycd;
  606. float xabc, yabc;
  607. float xbcd, ybcd;
  608. float xabcd, yabcd;
  609. /* termination check */
  610. dmax = fz_abs(xa - xb);
  611. dmax = fz_max(dmax, fz_abs(ya - yb));
  612. dmax = fz_max(dmax, fz_abs(xd - xc));
  613. dmax = fz_max(dmax, fz_abs(yd - yc));
  614. if (dmax < s->flatness || depth >= MAX_DEPTH)
  615. {
  616. fz_point p;
  617. p.x = xd;
  618. p.y = yd;
  619. fz_dash_lineto(s, p, dash_cap, 1);
  620. return;
  621. }
  622. xab = xa + xb;
  623. yab = ya + yb;
  624. xbc = xb + xc;
  625. ybc = yb + yc;
  626. xcd = xc + xd;
  627. ycd = yc + yd;
  628. xabc = xab + xbc;
  629. yabc = yab + ybc;
  630. xbcd = xbc + xcd;
  631. ybcd = ybc + ycd;
  632. xabcd = xabc + xbcd;
  633. yabcd = yabc + ybcd;
  634. xab *= 0.5f; yab *= 0.5f;
  635. xbc *= 0.5f; ybc *= 0.5f;
  636. xcd *= 0.5f; ycd *= 0.5f;
  637. xabc *= 0.25f; yabc *= 0.25f;
  638. xbcd *= 0.25f; ybcd *= 0.25f;
  639. xabcd *= 0.125f; yabcd *= 0.125f;
  640. fz_dash_bezier(s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1, dash_cap);
  641. fz_dash_bezier(s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1, dash_cap);
  642. }
  643. void
  644. fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth)
  645. {
  646. struct sctx s;
  647. fz_point p0, p1, p2, p3, beg;
  648. float phase_len, max_expand;
  649. int i;
  650. s.gel = gel;
  651. s.ctm = ctm;
  652. s.flatness = flatness;
  653. s.linejoin = stroke->linejoin;
  654. s.linewidth = linewidth * 0.5f;
  655. s.miterlimit = stroke->miterlimit;
  656. s.sn = 0;
  657. s.bn = 0;
  658. s.dot = 0;
  659. s.dash_list = stroke->dash_list;
  660. s.dash_phase = stroke->dash_phase;
  661. s.dash_len = stroke->dash_len;
  662. s.toggle = 0;
  663. s.offset = 0;
  664. s.phase = 0;
  665. s.cap = stroke->start_cap;
  666. if (path->len > 0 && path->items[0].k != FZ_MOVETO)
  667. return;
  668. phase_len = 0;
  669. for (i = 0; i < stroke->dash_len; i++)
  670. phase_len += stroke->dash_list[i];
  671. max_expand = fz_matrix_max_expansion(ctm);
  672. if (phase_len < 0.01f || phase_len * max_expand < 0.5f)
  673. {
  674. fz_flatten_stroke_path(gel, path, stroke, ctm, flatness, linewidth);
  675. return;
  676. }
  677. p0.x = p0.y = 0;
  678. i = 0;
  679. while (i < path->len)
  680. {
  681. switch (path->items[i++].k)
  682. {
  683. case FZ_MOVETO:
  684. p1.x = path->items[i++].v;
  685. p1.y = path->items[i++].v;
  686. fz_dash_moveto(&s, p1, stroke->start_cap, stroke->end_cap);
  687. beg = p0 = p1;
  688. break;
  689. case FZ_LINETO:
  690. p1.x = path->items[i++].v;
  691. p1.y = path->items[i++].v;
  692. fz_dash_lineto(&s, p1, stroke->dash_cap, 0);
  693. p0 = p1;
  694. break;
  695. case FZ_CURVETO:
  696. p1.x = path->items[i++].v;
  697. p1.y = path->items[i++].v;
  698. p2.x = path->items[i++].v;
  699. p2.y = path->items[i++].v;
  700. p3.x = path->items[i++].v;
  701. p3.y = path->items[i++].v;
  702. fz_dash_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0, stroke->dash_cap);
  703. p0 = p3;
  704. break;
  705. case FZ_CLOSE_PATH:
  706. fz_dash_lineto(&s, beg, stroke->dash_cap, 0);
  707. p0 = p1 = beg;
  708. break;
  709. }
  710. }
  711. fz_stroke_flush(&s, s.cap, stroke->end_cap);
  712. }