draw-edge.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include "draw-imp.h"
  24. #include <assert.h>
  25. #include <limits.h>
  26. #include <math.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. /*
  30. * Global Edge List -- list of straight path segments for scan conversion
  31. *
  32. * Stepping along the edges is with Bresenham's line algorithm.
  33. *
  34. * See Mike Abrash -- Graphics Programming Black Book (notably chapter 40)
  35. */
  36. typedef struct fz_edge_s
  37. {
  38. int x, e, h, y;
  39. int adj_up, adj_down;
  40. int xmove;
  41. int xdir, ydir; /* -1 or +1 */
  42. } fz_edge;
  43. typedef struct fz_gel_s
  44. {
  45. fz_rasterizer super;
  46. int cap, len;
  47. fz_edge *edges;
  48. int acap, alen;
  49. fz_edge **active;
  50. int bcap;
  51. unsigned char *alphas;
  52. int *deltas;
  53. } fz_gel;
  54. static int
  55. fz_reset_gel(fz_context *ctx, fz_rasterizer *rast)
  56. {
  57. fz_gel *gel = (fz_gel *)rast;
  58. gel->len = 0;
  59. gel->alen = 0;
  60. return 0;
  61. }
  62. static void
  63. fz_drop_gel(fz_context *ctx, fz_rasterizer *rast)
  64. {
  65. fz_gel *gel = (fz_gel *)rast;
  66. if (gel == NULL)
  67. return;
  68. fz_free(ctx, gel->active);
  69. fz_free(ctx, gel->edges);
  70. fz_free(ctx, gel->alphas);
  71. fz_free(ctx, gel->deltas);
  72. fz_free(ctx, gel);
  73. }
  74. enum { INSIDE, OUTSIDE, LEAVE, ENTER };
  75. #define clip_lerp_y(v,m,x0,y0,x1,y1,t) clip_lerp_x(v,m,y0,x0,y1,x1,t)
  76. static int
  77. clip_lerp_x(int val, int m, int x0, int y0, int x1, int y1, int *out)
  78. {
  79. int v0out = m ? x0 > val : x0 < val;
  80. int v1out = m ? x1 > val : x1 < val;
  81. if (v0out + v1out == 0)
  82. return INSIDE;
  83. if (v0out + v1out == 2)
  84. return OUTSIDE;
  85. if (v1out)
  86. {
  87. *out = y0 + (int)(((float)(y1 - y0)) * (val - x0) / (x1 - x0));
  88. return LEAVE;
  89. }
  90. else
  91. {
  92. *out = y1 + (int)(((float)(y0 - y1)) * (val - x1) / (x0 - x1));
  93. return ENTER;
  94. }
  95. }
  96. static void
  97. fz_insert_gel_raw(fz_context *ctx, fz_rasterizer *ras, int x0, int y0, int x1, int y1)
  98. {
  99. fz_gel *gel = (fz_gel *)ras;
  100. fz_edge *edge;
  101. int dx, dy;
  102. int winding;
  103. int width;
  104. int tmp;
  105. if (y0 == y1)
  106. return;
  107. if (y0 > y1) {
  108. winding = -1;
  109. tmp = x0; x0 = x1; x1 = tmp;
  110. tmp = y0; y0 = y1; y1 = tmp;
  111. }
  112. else
  113. winding = 1;
  114. if (x0 < gel->super.bbox.x0) gel->super.bbox.x0 = x0;
  115. if (x0 > gel->super.bbox.x1) gel->super.bbox.x1 = x0;
  116. if (x1 < gel->super.bbox.x0) gel->super.bbox.x0 = x1;
  117. if (x1 > gel->super.bbox.x1) gel->super.bbox.x1 = x1;
  118. if (y0 < gel->super.bbox.y0) gel->super.bbox.y0 = y0;
  119. if (y1 > gel->super.bbox.y1) gel->super.bbox.y1 = y1;
  120. if (gel->len + 1 == gel->cap) {
  121. int new_cap = gel->cap * 2;
  122. gel->edges = fz_realloc_array(ctx, gel->edges, new_cap, fz_edge);
  123. gel->cap = new_cap;
  124. }
  125. edge = &gel->edges[gel->len++];
  126. dy = y1 - y0;
  127. dx = x1 - x0;
  128. width = fz_absi(dx);
  129. edge->xdir = dx > 0 ? 1 : -1;
  130. edge->ydir = winding;
  131. edge->x = x0;
  132. edge->y = y0;
  133. edge->h = dy;
  134. edge->adj_down = dy;
  135. /* initial error term going l->r and r->l */
  136. if (dx >= 0)
  137. edge->e = 0;
  138. else
  139. edge->e = -dy + 1;
  140. /* y-major edge */
  141. if (dy >= width) {
  142. edge->xmove = 0;
  143. edge->adj_up = width;
  144. }
  145. /* x-major edge */
  146. else {
  147. edge->xmove = (width / dy) * edge->xdir;
  148. edge->adj_up = width % dy;
  149. }
  150. }
  151. static void
  152. fz_insert_gel(fz_context *ctx, fz_rasterizer *ras, float fx0, float fy0, float fx1, float fy1, int rev)
  153. {
  154. int x0, y0, x1, y1;
  155. int d, v;
  156. const int hscale = fz_rasterizer_aa_hscale(ras);
  157. const int vscale = fz_rasterizer_aa_vscale(ras);
  158. fx0 = floorf(fx0 * hscale);
  159. fx1 = floorf(fx1 * hscale);
  160. fy0 = floorf(fy0 * vscale);
  161. fy1 = floorf(fy1 * vscale);
  162. /* Call fz_clamp so that clamping is done in the float domain, THEN
  163. * cast down to an int. Calling fz_clampi causes problems due to the
  164. * implicit cast down from float to int of the first argument
  165. * over/underflowing and flipping sign at extreme values. */
  166. x0 = (int)fz_clamp(fx0, BBOX_MIN * hscale, BBOX_MAX * hscale);
  167. y0 = (int)fz_clamp(fy0, BBOX_MIN * vscale, BBOX_MAX * vscale);
  168. x1 = (int)fz_clamp(fx1, BBOX_MIN * hscale, BBOX_MAX * hscale);
  169. y1 = (int)fz_clamp(fy1, BBOX_MIN * vscale, BBOX_MAX * vscale);
  170. d = clip_lerp_y(ras->clip.y0, 0, x0, y0, x1, y1, &v);
  171. if (d == OUTSIDE) return;
  172. if (d == LEAVE) { y1 = ras->clip.y0; x1 = v; }
  173. if (d == ENTER) { y0 = ras->clip.y0; x0 = v; }
  174. d = clip_lerp_y(ras->clip.y1, 1, x0, y0, x1, y1, &v);
  175. if (d == OUTSIDE) return;
  176. if (d == LEAVE) { y1 = ras->clip.y1; x1 = v; }
  177. if (d == ENTER) { y0 = ras->clip.y1; x0 = v; }
  178. d = clip_lerp_x(ras->clip.x0, 0, x0, y0, x1, y1, &v);
  179. if (d == OUTSIDE) {
  180. x0 = x1 = ras->clip.x0;
  181. }
  182. if (d == LEAVE) {
  183. fz_insert_gel_raw(ctx, ras, ras->clip.x0, v, ras->clip.x0, y1);
  184. x1 = ras->clip.x0;
  185. y1 = v;
  186. }
  187. if (d == ENTER) {
  188. fz_insert_gel_raw(ctx, ras, ras->clip.x0, y0, ras->clip.x0, v);
  189. x0 = ras->clip.x0;
  190. y0 = v;
  191. }
  192. d = clip_lerp_x(ras->clip.x1, 1, x0, y0, x1, y1, &v);
  193. if (d == OUTSIDE) {
  194. x0 = x1 = ras->clip.x1;
  195. }
  196. if (d == LEAVE) {
  197. fz_insert_gel_raw(ctx, ras, ras->clip.x1, v, ras->clip.x1, y1);
  198. x1 = ras->clip.x1;
  199. y1 = v;
  200. }
  201. if (d == ENTER) {
  202. fz_insert_gel_raw(ctx, ras, ras->clip.x1, y0, ras->clip.x1, v);
  203. x0 = ras->clip.x1;
  204. y0 = v;
  205. }
  206. fz_insert_gel_raw(ctx, ras, x0, y0, x1, y1);
  207. }
  208. static void
  209. fz_insert_gel_rect(fz_context *ctx, fz_rasterizer *ras, float fx0, float fy0, float fx1, float fy1)
  210. {
  211. int x0, y0, x1, y1;
  212. const int hscale = fz_rasterizer_aa_hscale(ras);
  213. const int vscale = fz_rasterizer_aa_vscale(ras);
  214. fx0 = floorf(fx0 * hscale);
  215. fx1 = floorf(fx1 * hscale);
  216. if (fx1 == fx0)
  217. fx1++;
  218. fy0 = floorf(fy0 * vscale);
  219. fy1 = floorf(fy1 * vscale);
  220. if (fy1 == fy0)
  221. fy1++;
  222. fx0 = fz_clamp(fx0, ras->clip.x0, ras->clip.x1);
  223. fx1 = fz_clamp(fx1, ras->clip.x0, ras->clip.x1);
  224. fy0 = fz_clamp(fy0, ras->clip.y0, ras->clip.y1);
  225. fy1 = fz_clamp(fy1, ras->clip.y0, ras->clip.y1);
  226. /* Call fz_clamp so that clamping is done in the float domain, THEN
  227. * cast down to an int. Calling fz_clampi causes problems due to the
  228. * implicit cast down from float to int of the first argument
  229. * over/underflowing and flipping sign at extreme values. */
  230. x0 = (int)fz_clamp(fx0, BBOX_MIN * hscale, BBOX_MAX * hscale);
  231. y0 = (int)fz_clamp(fy0, BBOX_MIN * vscale, BBOX_MAX * vscale);
  232. x1 = (int)fz_clamp(fx1, BBOX_MIN * hscale, BBOX_MAX * hscale);
  233. y1 = (int)fz_clamp(fy1, BBOX_MIN * vscale, BBOX_MAX * vscale);
  234. fz_insert_gel_raw(ctx, ras, x1, y0, x1, y1);
  235. fz_insert_gel_raw(ctx, ras, x0, y1, x0, y0);
  236. }
  237. static int
  238. cmpedge(const void *va, const void *vb)
  239. {
  240. const fz_edge *a = va;
  241. const fz_edge *b = vb;
  242. return a->y - b->y;
  243. }
  244. static void
  245. sort_gel(fz_context *ctx, fz_gel *gel)
  246. {
  247. fz_edge *a = gel->edges;
  248. int n = gel->len;
  249. int h, i, k;
  250. fz_edge t;
  251. /* quick sort for long lists */
  252. if (n > 10000)
  253. {
  254. qsort(a, n, sizeof *a, cmpedge);
  255. return;
  256. }
  257. /* shell sort for short lists */
  258. h = 1;
  259. if (n < 14) {
  260. h = 1;
  261. }
  262. else {
  263. while (h < n)
  264. h = 3 * h + 1;
  265. h /= 3;
  266. h /= 3;
  267. }
  268. while (h > 0)
  269. {
  270. for (i = 0; i < n; i++) {
  271. t = a[i];
  272. k = i - h;
  273. /* TODO: sort on y major, x minor */
  274. while (k >= 0 && a[k].y > t.y) {
  275. a[k + h] = a[k];
  276. k -= h;
  277. }
  278. a[k + h] = t;
  279. }
  280. h /= 3;
  281. }
  282. }
  283. static int
  284. fz_is_rect_gel(fz_context *ctx, fz_rasterizer *ras)
  285. {
  286. fz_gel *gel = (fz_gel *)ras;
  287. /* a rectangular path is converted into two vertical edges of identical height */
  288. if (gel->len == 2)
  289. {
  290. fz_edge *a = gel->edges + 0;
  291. fz_edge *b = gel->edges + 1;
  292. return a->y == b->y && a->h == b->h &&
  293. a->xmove == 0 && a->adj_up == 0 &&
  294. b->xmove == 0 && b->adj_up == 0;
  295. }
  296. return 0;
  297. }
  298. /*
  299. * Active Edge List -- keep track of active edges while sweeping
  300. */
  301. static void
  302. sort_active(fz_edge **a, int n)
  303. {
  304. int h, i, k;
  305. fz_edge *t;
  306. h = 1;
  307. if (n < 14) {
  308. h = 1;
  309. }
  310. else {
  311. while (h < n)
  312. h = 3 * h + 1;
  313. h /= 3;
  314. h /= 3;
  315. }
  316. while (h > 0)
  317. {
  318. for (i = 0; i < n; i++) {
  319. t = a[i];
  320. k = i - h;
  321. while (k >= 0 && a[k]->x > t->x) {
  322. a[k + h] = a[k];
  323. k -= h;
  324. }
  325. a[k + h] = t;
  326. }
  327. h /= 3;
  328. }
  329. }
  330. static int
  331. insert_active(fz_context *ctx, fz_gel *gel, int y, int *e_)
  332. {
  333. int h_min = INT_MAX;
  334. int e = *e_;
  335. /* insert edges that start here */
  336. if (e < gel->len && gel->edges[e].y == y)
  337. {
  338. do {
  339. if (gel->alen + 1 == gel->acap) {
  340. int newcap = gel->acap + 64;
  341. fz_edge **newactive = fz_realloc_array(ctx, gel->active, newcap, fz_edge*);
  342. gel->active = newactive;
  343. gel->acap = newcap;
  344. }
  345. gel->active[gel->alen++] = &gel->edges[e++];
  346. } while (e < gel->len && gel->edges[e].y == y);
  347. *e_ = e;
  348. }
  349. if (e < gel->len)
  350. h_min = gel->edges[e].y - y;
  351. for (e=0; e < gel->alen; e++)
  352. {
  353. if (gel->active[e]->xmove != 0 || gel->active[e]->adj_up != 0)
  354. {
  355. h_min = 1;
  356. break;
  357. }
  358. if (gel->active[e]->h < h_min)
  359. {
  360. h_min = gel->active[e]->h;
  361. if (h_min == 1)
  362. break;
  363. }
  364. }
  365. /* shell-sort the edges by increasing x */
  366. sort_active(gel->active, gel->alen);
  367. return h_min;
  368. }
  369. static void
  370. advance_active(fz_context *ctx, fz_gel *gel, int inc)
  371. {
  372. fz_edge *edge;
  373. int i = 0;
  374. while (i < gel->alen)
  375. {
  376. edge = gel->active[i];
  377. edge->h -= inc;
  378. /* terminator! */
  379. if (edge->h == 0) {
  380. gel->active[i] = gel->active[--gel->alen];
  381. }
  382. else {
  383. edge->x += edge->xmove;
  384. edge->e += edge->adj_up;
  385. if (edge->e > 0) {
  386. edge->x += edge->xdir;
  387. edge->e -= edge->adj_down;
  388. }
  389. i ++;
  390. }
  391. }
  392. }
  393. /*
  394. * Anti-aliased scan conversion.
  395. */
  396. static inline void
  397. add_span_aa(fz_context *ctx, fz_gel *gel, int *list, int x0, int x1, int xofs, int h)
  398. {
  399. int x0pix, x0sub;
  400. int x1pix, x1sub;
  401. const int hscale = fz_rasterizer_aa_hscale(&gel->super);
  402. if (x0 == x1)
  403. return;
  404. /* x between 0 and width of bbox */
  405. x0 -= xofs;
  406. x1 -= xofs;
  407. /* The cast to unsigned below helps the compiler produce faster
  408. * code on ARMs as the multiply by reciprocal trick it uses does not
  409. * need to correct for signedness. */
  410. x0pix = ((unsigned int)x0) / hscale;
  411. x0sub = ((unsigned int)x0) % hscale;
  412. x1pix = ((unsigned int)x1) / hscale;
  413. x1sub = ((unsigned int)x1) % hscale;
  414. if (x0pix == x1pix)
  415. {
  416. list[x0pix] += h*(x1sub - x0sub);
  417. list[x0pix+1] += h*(x0sub - x1sub);
  418. }
  419. else
  420. {
  421. list[x0pix] += h*(hscale - x0sub);
  422. list[x0pix+1] += h*x0sub;
  423. list[x1pix] += h*(x1sub - hscale);
  424. list[x1pix+1] += h*-x1sub;
  425. }
  426. }
  427. static inline void
  428. non_zero_winding_aa(fz_context *ctx, fz_gel *gel, int *list, int xofs, int h)
  429. {
  430. int winding = 0;
  431. int x = 0;
  432. int i;
  433. for (i = 0; i < gel->alen; i++)
  434. {
  435. if (!winding && (winding + gel->active[i]->ydir))
  436. x = gel->active[i]->x;
  437. if (winding && !(winding + gel->active[i]->ydir))
  438. add_span_aa(ctx, gel, list, x, gel->active[i]->x, xofs, h);
  439. winding += gel->active[i]->ydir;
  440. }
  441. }
  442. static inline void
  443. even_odd_aa(fz_context *ctx, fz_gel *gel, int *list, int xofs, int h)
  444. {
  445. int even = 0;
  446. int x = 0;
  447. int i;
  448. for (i = 0; i < gel->alen; i++)
  449. {
  450. if (!even)
  451. x = gel->active[i]->x;
  452. else
  453. add_span_aa(ctx, gel, list, x, gel->active[i]->x, xofs, h);
  454. even = !even;
  455. }
  456. }
  457. static inline void
  458. undelta_aa(fz_context *ctx, unsigned char * FZ_RESTRICT out, int * FZ_RESTRICT in, int n, int scale)
  459. {
  460. int d = 0;
  461. (void)scale; /* Avoid warnings in some builds */
  462. while (n--)
  463. {
  464. d += *in++;
  465. *out++ = AA_SCALE(scale, d);
  466. }
  467. }
  468. static inline void
  469. blit_aa(fz_pixmap *dst, int x, int y, unsigned char *mp, int w, unsigned char *color, void *fn, fz_overprint *eop)
  470. {
  471. unsigned char *dp;
  472. dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
  473. if (color)
  474. (*(fz_span_color_painter_t *)fn)(dp, mp, dst->n, w, color, dst->alpha, eop);
  475. else
  476. (*(fz_span_painter_t *)fn)(dp, dst->alpha, mp, 1, 0, w, 255, eop);
  477. }
  478. static void
  479. fz_scan_convert_aa(fz_context *ctx, fz_gel *gel, int eofill, const fz_irect *clip, fz_pixmap *dst, unsigned char *color, void *painter, fz_overprint *eop)
  480. {
  481. unsigned char *alphas;
  482. int *deltas;
  483. int y, e;
  484. int yd, yc;
  485. int height, h0, rh;
  486. int bcap;
  487. const int hscale = fz_rasterizer_aa_hscale(&gel->super);
  488. const int vscale = fz_rasterizer_aa_vscale(&gel->super);
  489. const int scale = fz_rasterizer_aa_scale(&gel->super);
  490. int xmin = fz_idiv(gel->super.bbox.x0, hscale);
  491. int xmax = fz_idiv_up(gel->super.bbox.x1, hscale);
  492. int xofs = xmin * hscale;
  493. int skipx = clip->x0 - xmin;
  494. int clipn = clip->x1 - clip->x0;
  495. if (gel->len == 0)
  496. return;
  497. assert(xmin < xmax);
  498. assert(clip->x0 >= xmin);
  499. assert(clip->x1 <= xmax);
  500. bcap = xmax - xmin + 2; /* big enough for both alphas and deltas */
  501. if (bcap > gel->bcap)
  502. {
  503. gel->bcap = bcap;
  504. fz_free(ctx, gel->alphas);
  505. fz_free(ctx, gel->deltas);
  506. gel->alphas = NULL;
  507. gel->deltas = NULL;
  508. gel->alphas = Memento_label(fz_malloc_array(ctx, bcap, unsigned char), "gel_alphas");
  509. gel->deltas = Memento_label(fz_malloc_array(ctx, bcap, int), "gel_deltas");
  510. }
  511. alphas = gel->alphas;
  512. deltas = gel->deltas;
  513. memset(deltas, 0, (xmax - xmin + 1) * sizeof(int));
  514. gel->alen = 0;
  515. /* The theory here is that we have a list of the edges (gel) of length
  516. * gel->len. We have an initially empty list of 'active' edges (of
  517. * length gel->alen). As we increase y, we move any edge that is
  518. * active at this point into the active list. We know that any edge
  519. * before index 'e' is either active, or has been retired.
  520. * Once the length of the active list is 0, and e has reached gel->len
  521. * we know we are finished.
  522. *
  523. * As we move through the list, we group fz_aa_vscale 'sub scanlines'
  524. * into single scanlines, and we blit them.
  525. */
  526. e = 0;
  527. y = gel->edges[0].y;
  528. yd = fz_idiv(y, vscale);
  529. /* Quickly skip to the start of the clip region */
  530. while (yd < clip->y0 && (gel->alen > 0 || e < gel->len))
  531. {
  532. /* rh = remaining height = number of subscanlines left to be
  533. * inserted into the current scanline, which will be plotted
  534. * at yd. */
  535. rh = (yd+1)*vscale - y;
  536. /* height = The number of subscanlines with identical edge
  537. * positions (i.e. 1 if we have any non vertical edges). */
  538. height = insert_active(ctx, gel, y, &e);
  539. h0 = height;
  540. if (h0 >= rh)
  541. {
  542. /* We have enough subscanlines to skip to the next
  543. * scanline. */
  544. h0 -= rh;
  545. yd++;
  546. }
  547. /* Skip any whole scanlines we can */
  548. while (yd < clip->y0 && h0 >= vscale)
  549. {
  550. h0 -= vscale;
  551. yd++;
  552. }
  553. /* If we haven't hit the start of the clip region, then we
  554. * have less than a scanline left. */
  555. if (yd < clip->y0)
  556. {
  557. h0 = 0;
  558. }
  559. height -= h0;
  560. advance_active(ctx, gel, height);
  561. y += height;
  562. }
  563. /* Now do the active lines */
  564. while (gel->alen > 0 || e < gel->len)
  565. {
  566. yc = fz_idiv(y, vscale); /* yc = current scanline */
  567. /* rh = remaining height = number of subscanlines left to be
  568. * inserted into the current scanline, which will be plotted
  569. * at yd. */
  570. rh = (yc+1)*vscale - y;
  571. if (yc != yd)
  572. {
  573. undelta_aa(ctx, alphas, deltas, skipx + clipn, scale);
  574. blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color, painter, eop);
  575. memset(deltas, 0, (skipx + clipn) * sizeof(int));
  576. }
  577. yd = yc;
  578. if (yd >= clip->y1)
  579. break;
  580. /* height = The number of subscanlines with identical edge
  581. * positions (i.e. 1 if we have any non vertical edges). */
  582. height = insert_active(ctx, gel, y, &e);
  583. h0 = height;
  584. if (h0 > rh)
  585. {
  586. if (rh < vscale)
  587. {
  588. /* We have to finish a scanline off, and we
  589. * have more sub scanlines than will fit into
  590. * it. */
  591. if (eofill)
  592. even_odd_aa(ctx, gel, deltas, xofs, rh);
  593. else
  594. non_zero_winding_aa(ctx, gel, deltas, xofs, rh);
  595. undelta_aa(ctx, alphas, deltas, skipx + clipn, scale);
  596. blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color, painter, eop);
  597. memset(deltas, 0, (skipx + clipn) * sizeof(int));
  598. yd++;
  599. if (yd >= clip->y1)
  600. break;
  601. h0 -= rh;
  602. }
  603. if (h0 > vscale)
  604. {
  605. /* Calculate the deltas for any completely full
  606. * scanlines. */
  607. h0 -= vscale;
  608. if (eofill)
  609. even_odd_aa(ctx, gel, deltas, xofs, vscale);
  610. else
  611. non_zero_winding_aa(ctx, gel, deltas, xofs, vscale);
  612. undelta_aa(ctx, alphas, deltas, skipx + clipn, scale);
  613. do
  614. {
  615. /* Do any successive whole scanlines - no need
  616. * to recalculate deltas here. */
  617. blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color, painter, eop);
  618. yd++;
  619. if (yd >= clip->y1)
  620. goto clip_ended;
  621. h0 -= vscale;
  622. }
  623. while (h0 > 0);
  624. /* If we have exactly one full scanline left
  625. * to go, then the deltas/alphas are set up
  626. * already. */
  627. if (h0 == 0)
  628. goto advance;
  629. memset(deltas, 0, (skipx + clipn) * sizeof(int));
  630. h0 += vscale;
  631. }
  632. }
  633. if (eofill)
  634. even_odd_aa(ctx, gel, deltas, xofs, h0);
  635. else
  636. non_zero_winding_aa(ctx, gel, deltas, xofs, h0);
  637. advance:
  638. advance_active(ctx, gel, height);
  639. y += height;
  640. }
  641. if (yd < clip->y1)
  642. {
  643. undelta_aa(ctx, alphas, deltas, skipx + clipn, scale);
  644. blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color, painter, eop);
  645. }
  646. clip_ended:
  647. ;
  648. }
  649. /*
  650. * Sharp (not anti-aliased) scan conversion
  651. */
  652. static inline void
  653. blit_sharp(int x0, int x1, int y, const fz_irect *clip, fz_pixmap *dst, unsigned char *color, fz_solid_color_painter_t *fn, fz_overprint *eop)
  654. {
  655. unsigned char *dp;
  656. int da = dst->alpha;
  657. x0 = fz_clampi(x0, dst->x, dst->x + dst->w);
  658. x1 = fz_clampi(x1, dst->x, dst->x + dst->w);
  659. if (x0 < x1)
  660. {
  661. dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x0 - dst->x) * (size_t)dst->n;
  662. if (color)
  663. (*fn)(dp, dst->n, x1 - x0, color, da, eop);
  664. else
  665. memset(dp, 255, x1-x0);
  666. }
  667. }
  668. static inline void
  669. non_zero_winding_sharp(fz_context *ctx, fz_gel *gel, int y, const fz_irect *clip, fz_pixmap *dst, unsigned char *color, fz_solid_color_painter_t *fn, fz_overprint *eop)
  670. {
  671. int winding = 0;
  672. int x = 0;
  673. int i;
  674. for (i = 0; i < gel->alen; i++)
  675. {
  676. if (!winding && (winding + gel->active[i]->ydir))
  677. x = gel->active[i]->x;
  678. if (winding && !(winding + gel->active[i]->ydir))
  679. blit_sharp(x, gel->active[i]->x, y, clip, dst, color, fn, eop);
  680. winding += gel->active[i]->ydir;
  681. }
  682. }
  683. static inline void
  684. even_odd_sharp(fz_context *ctx, fz_gel *gel, int y, const fz_irect *clip, fz_pixmap *dst, unsigned char *color, fz_solid_color_painter_t *fn, fz_overprint *eop)
  685. {
  686. int even = 0;
  687. int x = 0;
  688. int i;
  689. for (i = 0; i < gel->alen; i++)
  690. {
  691. if (!even)
  692. x = gel->active[i]->x;
  693. else
  694. blit_sharp(x, gel->active[i]->x, y, clip, dst, color, fn, eop);
  695. even = !even;
  696. }
  697. }
  698. static void
  699. fz_scan_convert_sharp(fz_context *ctx,
  700. fz_gel *gel, int eofill, const fz_irect *clip,
  701. fz_pixmap *dst, unsigned char *color, fz_solid_color_painter_t *fn, fz_overprint *eop)
  702. {
  703. int e = 0;
  704. int y = gel->edges[0].y;
  705. int height;
  706. gel->alen = 0;
  707. /* Skip any lines before the clip region */
  708. if (y < clip->y0)
  709. {
  710. while (gel->alen > 0 || e < gel->len)
  711. {
  712. height = insert_active(ctx, gel, y, &e);
  713. y += height;
  714. if (y >= clip->y0)
  715. {
  716. y = clip->y0;
  717. break;
  718. }
  719. }
  720. }
  721. /* Now process as lines within the clip region */
  722. while (gel->alen > 0 || e < gel->len)
  723. {
  724. height = insert_active(ctx, gel, y, &e);
  725. if (gel->alen == 0)
  726. y += height;
  727. else
  728. {
  729. int h;
  730. if (height >= clip->y1 - y)
  731. height = clip->y1 - y;
  732. h = height;
  733. while (h--)
  734. {
  735. if (eofill)
  736. even_odd_sharp(ctx, gel, y, clip, dst, color, fn, eop);
  737. else
  738. non_zero_winding_sharp(ctx, gel, y, clip, dst, color, fn, eop);
  739. y++;
  740. }
  741. }
  742. if (y >= clip->y1)
  743. break;
  744. advance_active(ctx, gel, height);
  745. }
  746. }
  747. static void
  748. fz_convert_gel(fz_context *ctx, fz_rasterizer *rast, int eofill, const fz_irect *clip, fz_pixmap *dst, unsigned char *color, fz_overprint *eop)
  749. {
  750. fz_gel *gel = (fz_gel *)rast;
  751. sort_gel(ctx, gel);
  752. if (fz_aa_bits > 0)
  753. {
  754. void *fn;
  755. if (color)
  756. fn = (void *)fz_get_span_color_painter(dst->n, dst->alpha, color, eop);
  757. else
  758. fn = (void *)fz_get_span_painter(dst->alpha, 1, 0, 255, eop);
  759. if (fn == NULL)
  760. return;
  761. fz_scan_convert_aa(ctx, gel, eofill, clip, dst, color, fn, eop);
  762. }
  763. else
  764. {
  765. fz_solid_color_painter_t *fn = fz_get_solid_color_painter(dst->n, color, dst->alpha, eop);
  766. assert(fn);
  767. if (fn == NULL)
  768. return;
  769. fz_scan_convert_sharp(ctx, gel, eofill, clip, dst, color, (fz_solid_color_painter_t *)fn, eop);
  770. }
  771. }
  772. static const fz_rasterizer_fns gel_rasterizer =
  773. {
  774. fz_drop_gel,
  775. fz_reset_gel,
  776. NULL, /* postindex */
  777. fz_insert_gel,
  778. fz_insert_gel_rect,
  779. NULL, /* gap */
  780. fz_convert_gel,
  781. fz_is_rect_gel,
  782. 0 /* Not reusable */
  783. };
  784. fz_rasterizer *
  785. fz_new_gel(fz_context *ctx)
  786. {
  787. fz_gel *gel;
  788. gel = fz_new_derived_rasterizer(ctx, fz_gel, &gel_rasterizer);
  789. fz_try(ctx)
  790. {
  791. gel->edges = NULL;
  792. gel->cap = 512;
  793. gel->len = 0;
  794. gel->edges = Memento_label(fz_malloc_array(ctx, gel->cap, fz_edge), "gel_edges");
  795. gel->acap = 64;
  796. gel->alen = 0;
  797. gel->active = Memento_label(fz_malloc_array(ctx, gel->acap, fz_edge*), "gel_active");
  798. }
  799. fz_catch(ctx)
  800. {
  801. fz_free(ctx, gel->edges);
  802. fz_free(ctx, gel);
  803. fz_rethrow(ctx);
  804. }
  805. return &gel->super;
  806. }