Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2.  
  3. #define BBOX_MIN -(1<<20)
  4. #define BBOX_MAX (1<<20)
  5.  
  6. /* divide and floor towards -inf */
  7. static inline int fz_idiv(int a, int b)
  8. {
  9.         return a < 0 ? (a - b + 1) / b : a / b;
  10. }
  11.  
  12. /* If AA_BITS is defined, then we assume constant N bits of antialiasing. We
  13.  * will attempt to provide at least that number of bits of accuracy in the
  14.  * antialiasing (to a maximum of 8). If it is defined to be 0 then no
  15.  * antialiasing is done. If it is undefined to we will leave the antialiasing
  16.  * accuracy as a run time choice.
  17.  */
  18.  
  19. #ifndef AA_BITS
  20. #define AA_SCALE(x) ((x * fz_aa_scale) >> 8)
  21. static int fz_aa_hscale = 17;
  22. static int fz_aa_vscale = 15;
  23. static int fz_aa_scale = 256;
  24. static int fz_aa_level = 8;
  25.  
  26. #elif AA_BITS > 6
  27. #define AA_SCALE(x) (x)
  28. #define fz_aa_hscale 17
  29. #define fz_aa_vscale 15
  30. #define fz_aa_level 8
  31.  
  32. #elif AA_BITS > 4
  33. #define AA_SCALE(x) ((x * 255) >> 6)
  34. #define fz_aa_hscale 8
  35. #define fz_aa_vscale 8
  36. #define fz_aa_level 6
  37.  
  38. #elif AA_BITS > 2
  39. #define AA_SCALE(x) (x * 17)
  40. #define fz_aa_hscale 5
  41. #define fz_aa_vscale 3
  42. #define fz_aa_level 4
  43.  
  44. #elif AA_BITS > 0
  45. #define AA_SCALE(x) ((x * 255) >> 2)
  46. #define fz_aa_hscale 2
  47. #define fz_aa_vscale 2
  48. #define fz_aa_level 2
  49.  
  50. #else
  51. #define AA_SCALE(x) (x * 255)
  52. #define fz_aa_hscale 1
  53. #define fz_aa_vscale 1
  54. #define fz_aa_level 0
  55.  
  56. #endif
  57.  
  58. int
  59. fz_get_aa_level(void)
  60. {
  61.         return fz_aa_level;
  62. }
  63.  
  64. void
  65. fz_set_aa_level(int level)
  66. {
  67. #ifdef AA_BITS
  68.         fz_warn("anti-aliasing was compiled with a fixed precision of %d bits", fz_aa_level);
  69. #else
  70.         if (level > 6)
  71.         {
  72.                 fz_aa_hscale = 17;
  73.                 fz_aa_vscale = 15;
  74.                 fz_aa_level = 8;
  75.         }
  76.         else if (level > 4)
  77.         {
  78.                 fz_aa_hscale = 8;
  79.                 fz_aa_vscale = 8;
  80.                 fz_aa_level = 6;
  81.         }
  82.         else if (level > 2)
  83.         {
  84.                 fz_aa_hscale = 5;
  85.                 fz_aa_vscale = 3;
  86.                 fz_aa_level = 4;
  87.         }
  88.         else if (level > 0)
  89.         {
  90.                 fz_aa_hscale = 2;
  91.                 fz_aa_vscale = 2;
  92.                 fz_aa_level = 2;
  93.         }
  94.         else
  95.         {
  96.                 fz_aa_hscale = 1;
  97.                 fz_aa_vscale = 1;
  98.                 fz_aa_level = 0;
  99.         }
  100.         fz_aa_scale = 0xFF00 / (fz_aa_hscale * fz_aa_vscale);
  101. #endif
  102. }
  103.  
  104. /*
  105.  * Global Edge List -- list of straight path segments for scan conversion
  106.  *
  107.  * Stepping along the edges is with bresenham's line algorithm.
  108.  *
  109.  * See Mike Abrash -- Graphics Programming Black Book (notably chapter 40)
  110.  */
  111.  
  112. typedef struct fz_edge_s fz_edge;
  113.  
  114. struct fz_edge_s
  115. {
  116.         int x, e, h, y;
  117.         int adj_up, adj_down;
  118.         int xmove;
  119.         int xdir, ydir; /* -1 or +1 */
  120. };
  121.  
  122. struct fz_gel_s
  123. {
  124.         fz_bbox clip;
  125.         fz_bbox bbox;
  126.         int cap, len;
  127.         fz_edge *edges;
  128.         int acap, alen;
  129.         fz_edge **active;
  130. };
  131.  
  132. fz_gel *
  133. fz_new_gel(void)
  134. {
  135.         fz_gel *gel;
  136.  
  137.         gel = fz_malloc(sizeof(fz_gel));
  138.         gel->cap = 512;
  139.         gel->len = 0;
  140.         gel->edges = fz_calloc(gel->cap, sizeof(fz_edge));
  141.  
  142.         gel->clip.x0 = gel->clip.y0 = BBOX_MAX;
  143.         gel->clip.x1 = gel->clip.y1 = BBOX_MIN;
  144.  
  145.         gel->bbox.x0 = gel->bbox.y0 = BBOX_MAX;
  146.         gel->bbox.x1 = gel->bbox.y1 = BBOX_MIN;
  147.  
  148.         gel->acap = 64;
  149.         gel->alen = 0;
  150.         gel->active = fz_calloc(gel->acap, sizeof(fz_edge*));
  151.  
  152.         return gel;
  153. }
  154.  
  155. void
  156. fz_reset_gel(fz_gel *gel, fz_bbox clip)
  157. {
  158.         if (fz_is_infinite_rect(clip))
  159.         {
  160.                 gel->clip.x0 = gel->clip.y0 = BBOX_MAX;
  161.                 gel->clip.x1 = gel->clip.y1 = BBOX_MIN;
  162.         }
  163.         else {
  164.                 gel->clip.x0 = clip.x0 * fz_aa_hscale;
  165.                 gel->clip.x1 = clip.x1 * fz_aa_hscale;
  166.                 gel->clip.y0 = clip.y0 * fz_aa_vscale;
  167.                 gel->clip.y1 = clip.y1 * fz_aa_vscale;
  168.         }
  169.  
  170.         gel->bbox.x0 = gel->bbox.y0 = BBOX_MAX;
  171.         gel->bbox.x1 = gel->bbox.y1 = BBOX_MIN;
  172.  
  173.         gel->len = 0;
  174. }
  175.  
  176. void
  177. fz_free_gel(fz_gel *gel)
  178. {
  179.         fz_free(gel->active);
  180.         fz_free(gel->edges);
  181.         fz_free(gel);
  182. }
  183.  
  184. fz_bbox
  185. fz_bound_gel(fz_gel *gel)
  186. {
  187.         fz_bbox bbox;
  188.         if (gel->len == 0)
  189.                 return fz_empty_bbox;
  190.         bbox.x0 = fz_idiv(gel->bbox.x0, fz_aa_hscale);
  191.         bbox.y0 = fz_idiv(gel->bbox.y0, fz_aa_vscale);
  192.         bbox.x1 = fz_idiv(gel->bbox.x1, fz_aa_hscale) + 1;
  193.         bbox.y1 = fz_idiv(gel->bbox.y1, fz_aa_vscale) + 1;
  194.         return bbox;
  195. }
  196.  
  197. enum { INSIDE, OUTSIDE, LEAVE, ENTER };
  198.  
  199. #define clip_lerp_y(v,m,x0,y0,x1,y1,t) clip_lerp_x(v,m,y0,x0,y1,x1,t)
  200.  
  201. static int
  202. clip_lerp_x(int val, int m, int x0, int y0, int x1, int y1, int *out)
  203. {
  204.         int v0out = m ? x0 > val : x0 < val;
  205.         int v1out = m ? x1 > val : x1 < val;
  206.  
  207.         if (v0out + v1out == 0)
  208.                 return INSIDE;
  209.  
  210.         if (v0out + v1out == 2)
  211.                 return OUTSIDE;
  212.  
  213.         if (v1out)
  214.         {
  215.                 *out = y0 + (y1 - y0) * (val - x0) / (x1 - x0);
  216.                 return LEAVE;
  217.         }
  218.  
  219.         else
  220.         {
  221.                 *out = y1 + (y0 - y1) * (val - x1) / (x0 - x1);
  222.                 return ENTER;
  223.         }
  224. }
  225.  
  226. static void
  227. fz_insert_gel_raw(fz_gel *gel, int x0, int y0, int x1, int y1)
  228. {
  229.         fz_edge *edge;
  230.         int dx, dy;
  231.         int winding;
  232.         int width;
  233.         int tmp;
  234.  
  235.         if (y0 == y1)
  236.                 return;
  237.  
  238.         if (y0 > y1) {
  239.                 winding = -1;
  240.                 tmp = x0; x0 = x1; x1 = tmp;
  241.                 tmp = y0; y0 = y1; y1 = tmp;
  242.         }
  243.         else
  244.                 winding = 1;
  245.  
  246.         if (x0 < gel->bbox.x0) gel->bbox.x0 = x0;
  247.         if (x0 > gel->bbox.x1) gel->bbox.x1 = x0;
  248.         if (x1 < gel->bbox.x0) gel->bbox.x0 = x1;
  249.         if (x1 > gel->bbox.x1) gel->bbox.x1 = x1;
  250.  
  251.         if (y0 < gel->bbox.y0) gel->bbox.y0 = y0;
  252.         if (y1 > gel->bbox.y1) gel->bbox.y1 = y1;
  253.  
  254.         if (gel->len + 1 == gel->cap) {
  255.                 gel->cap = gel->cap + 512;
  256.                 gel->edges = fz_realloc(gel->edges, gel->cap, sizeof(fz_edge));
  257.         }
  258.  
  259.         edge = &gel->edges[gel->len++];
  260.  
  261.         dy = y1 - y0;
  262.         dx = x1 - x0;
  263.         width = ABS(dx);
  264.  
  265.         edge->xdir = dx > 0 ? 1 : -1;
  266.         edge->ydir = winding;
  267.         edge->x = x0;
  268.         edge->y = y0;
  269.         edge->h = dy;
  270.         edge->adj_down = dy;
  271.  
  272.         /* initial error term going l->r and r->l */
  273.         if (dx >= 0)
  274.                 edge->e = 0;
  275.         else
  276.                 edge->e = -dy + 1;
  277.  
  278.         /* y-major edge */
  279.         if (dy >= width) {
  280.                 edge->xmove = 0;
  281.                 edge->adj_up = width;
  282.         }
  283.  
  284.         /* x-major edge */
  285.         else {
  286.                 edge->xmove = (width / dy) * edge->xdir;
  287.                 edge->adj_up = width % dy;
  288.         }
  289. }
  290.  
  291. void
  292. fz_insert_gel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1)
  293. {
  294.         int x0, y0, x1, y1;
  295.         int d, v;
  296.  
  297.         fx0 = floorf(fx0 * fz_aa_hscale);
  298.         fx1 = floorf(fx1 * fz_aa_hscale);
  299.         fy0 = floorf(fy0 * fz_aa_vscale);
  300.         fy1 = floorf(fy1 * fz_aa_vscale);
  301.  
  302.         x0 = CLAMP(fx0, BBOX_MIN, BBOX_MAX);
  303.         y0 = CLAMP(fy0, BBOX_MIN, BBOX_MAX);
  304.         x1 = CLAMP(fx1, BBOX_MIN, BBOX_MAX);
  305.         y1 = CLAMP(fy1, BBOX_MIN, BBOX_MAX);
  306.  
  307.         d = clip_lerp_y(gel->clip.y0, 0, x0, y0, x1, y1, &v);
  308.         if (d == OUTSIDE) return;
  309.         if (d == LEAVE) { y1 = gel->clip.y0; x1 = v; }
  310.         if (d == ENTER) { y0 = gel->clip.y0; x0 = v; }
  311.  
  312.         d = clip_lerp_y(gel->clip.y1, 1, x0, y0, x1, y1, &v);
  313.         if (d == OUTSIDE) return;
  314.         if (d == LEAVE) { y1 = gel->clip.y1; x1 = v; }
  315.         if (d == ENTER) { y0 = gel->clip.y1; x0 = v; }
  316.  
  317.         d = clip_lerp_x(gel->clip.x0, 0, x0, y0, x1, y1, &v);
  318.         if (d == OUTSIDE) {
  319.                 x0 = x1 = gel->clip.x0;
  320.         }
  321.         if (d == LEAVE) {
  322.                 fz_insert_gel_raw(gel, gel->clip.x0, v, gel->clip.x0, y1);
  323.                 x1 = gel->clip.x0;
  324.                 y1 = v;
  325.         }
  326.         if (d == ENTER) {
  327.                 fz_insert_gel_raw(gel, gel->clip.x0, y0, gel->clip.x0, v);
  328.                 x0 = gel->clip.x0;
  329.                 y0 = v;
  330.         }
  331.  
  332.         d = clip_lerp_x(gel->clip.x1, 1, x0, y0, x1, y1, &v);
  333.         if (d == OUTSIDE) {
  334.                 x0 = x1 = gel->clip.x1;
  335.         }
  336.         if (d == LEAVE) {
  337.                 fz_insert_gel_raw(gel, gel->clip.x1, v, gel->clip.x1, y1);
  338.                 x1 = gel->clip.x1;
  339.                 y1 = v;
  340.         }
  341.         if (d == ENTER) {
  342.                 fz_insert_gel_raw(gel, gel->clip.x1, y0, gel->clip.x1, v);
  343.                 x0 = gel->clip.x1;
  344.                 y0 = v;
  345.         }
  346.  
  347.         fz_insert_gel_raw(gel, x0, y0, x1, y1);
  348. }
  349.  
  350. void
  351. fz_sort_gel(fz_gel *gel)
  352. {
  353.         fz_edge *a = gel->edges;
  354.         int n = gel->len;
  355.  
  356.         int h, i, k;
  357.         fz_edge t;
  358.  
  359.         h = 1;
  360.         if (n < 14) {
  361.                 h = 1;
  362.         }
  363.         else {
  364.                 while (h < n)
  365.                         h = 3 * h + 1;
  366.                 h /= 3;
  367.                 h /= 3;
  368.         }
  369.  
  370.         while (h > 0)
  371.         {
  372.                 for (i = 0; i < n; i++) {
  373.                         t = a[i];
  374.                         k = i - h;
  375.                         /* TODO: sort on y major, x minor */
  376.                         while (k >= 0 && a[k].y > t.y) {
  377.                                 a[k + h] = a[k];
  378.                                 k -= h;
  379.                         }
  380.                         a[k + h] = t;
  381.                 }
  382.  
  383.                 h /= 3;
  384.         }
  385. }
  386.  
  387. int
  388. fz_is_rect_gel(fz_gel *gel)
  389. {
  390.         /* a rectangular path is converted into two vertical edges of identical height */
  391.         if (gel->len == 2)
  392.         {
  393.                 fz_edge *a = gel->edges + 0;
  394.                 fz_edge *b = gel->edges + 1;
  395.                 return a->y == b->y && a->h == b->h &&
  396.                         a->xmove == 0 && a->adj_up == 0 &&
  397.                         b->xmove == 0 && b->adj_up == 0;
  398.         }
  399.         return 0;
  400. }
  401.  
  402. /*
  403.  * Active Edge List -- keep track of active edges while sweeping
  404.  */
  405.  
  406. static void
  407. sort_active(fz_edge **a, int n)
  408. {
  409.         int h, i, k;
  410.         fz_edge *t;
  411.  
  412.         h = 1;
  413.         if (n < 14) {
  414.                 h = 1;
  415.         }
  416.         else {
  417.                 while (h < n)
  418.                         h = 3 * h + 1;
  419.                 h /= 3;
  420.                 h /= 3;
  421.         }
  422.  
  423.         while (h > 0)
  424.         {
  425.                 for (i = 0; i < n; i++) {
  426.                         t = a[i];
  427.                         k = i - h;
  428.                         while (k >= 0 && a[k]->x > t->x) {
  429.                                 a[k + h] = a[k];
  430.                                 k -= h;
  431.                         }
  432.                         a[k + h] = t;
  433.                 }
  434.  
  435.                 h /= 3;
  436.         }
  437. }
  438.  
  439. static void
  440. insert_active(fz_gel *gel, int y, int *e)
  441. {
  442.         /* insert edges that start here */
  443.         while (*e < gel->len && gel->edges[*e].y == y) {
  444.                 if (gel->alen + 1 == gel->acap) {
  445.                         int newcap = gel->acap + 64;
  446.                         fz_edge **newactive = fz_realloc(gel->active, newcap, sizeof(fz_edge*));
  447.                         gel->active = newactive;
  448.                         gel->acap = newcap;
  449.                 }
  450.                 gel->active[gel->alen++] = &gel->edges[(*e)++];
  451.         }
  452.  
  453.         /* shell-sort the edges by increasing x */
  454.         sort_active(gel->active, gel->alen);
  455. }
  456.  
  457. static void
  458. advance_active(fz_gel *gel)
  459. {
  460.         fz_edge *edge;
  461.         int i = 0;
  462.  
  463.         while (i < gel->alen)
  464.         {
  465.                 edge = gel->active[i];
  466.  
  467.                 edge->h --;
  468.  
  469.                 /* terminator! */
  470.                 if (edge->h == 0) {
  471.                         gel->active[i] = gel->active[--gel->alen];
  472.                 }
  473.  
  474.                 else {
  475.                         edge->x += edge->xmove;
  476.                         edge->e += edge->adj_up;
  477.                         if (edge->e > 0) {
  478.                                 edge->x += edge->xdir;
  479.                                 edge->e -= edge->adj_down;
  480.                         }
  481.                         i ++;
  482.                 }
  483.         }
  484. }
  485.  
  486. /*
  487.  * Anti-aliased scan conversion.
  488.  */
  489.  
  490. static inline void add_span_aa(int *list, int x0, int x1, int xofs)
  491. {
  492.         int x0pix, x0sub;
  493.         int x1pix, x1sub;
  494.  
  495.         if (x0 == x1)
  496.                 return;
  497.  
  498.         /* x between 0 and width of bbox */
  499.         x0 -= xofs;
  500.         x1 -= xofs;
  501.  
  502.         x0pix = x0 / fz_aa_hscale;
  503.         x0sub = x0 % fz_aa_hscale;
  504.         x1pix = x1 / fz_aa_hscale;
  505.         x1sub = x1 % fz_aa_hscale;
  506.  
  507.         if (x0pix == x1pix)
  508.         {
  509.                 list[x0pix] += x1sub - x0sub;
  510.                 list[x0pix+1] += x0sub - x1sub;
  511.         }
  512.  
  513.         else
  514.         {
  515.                 list[x0pix] += fz_aa_hscale - x0sub;
  516.                 list[x0pix+1] += x0sub;
  517.                 list[x1pix] += x1sub - fz_aa_hscale;
  518.                 list[x1pix+1] += -x1sub;
  519.         }
  520. }
  521.  
  522. static inline void non_zero_winding_aa(fz_gel *gel, int *list, int xofs)
  523. {
  524.         int winding = 0;
  525.         int x = 0;
  526.         int i;
  527.         for (i = 0; i < gel->alen; i++)
  528.         {
  529.                 if (!winding && (winding + gel->active[i]->ydir))
  530.                         x = gel->active[i]->x;
  531.                 if (winding && !(winding + gel->active[i]->ydir))
  532.                         add_span_aa(list, x, gel->active[i]->x, xofs);
  533.                 winding += gel->active[i]->ydir;
  534.         }
  535. }
  536.  
  537. static inline void even_odd_aa(fz_gel *gel, int *list, int xofs)
  538. {
  539.         int even = 0;
  540.         int x = 0;
  541.         int i;
  542.         for (i = 0; i < gel->alen; i++)
  543.         {
  544.                 if (!even)
  545.                         x = gel->active[i]->x;
  546.                 else
  547.                         add_span_aa(list, x, gel->active[i]->x, xofs);
  548.                 even = !even;
  549.         }
  550. }
  551.  
  552. static inline void undelta_aa(unsigned char * restrict out, int * restrict in, int n)
  553. {
  554.         int d = 0;
  555.         while (n--)
  556.         {
  557.                 d += *in++;
  558.                 *out++ = AA_SCALE(d);
  559.         }
  560. }
  561.  
  562. static inline void blit_aa(fz_pixmap *dst, int x, int y,
  563.         unsigned char *mp, int w, unsigned char *color)
  564. {
  565.         unsigned char *dp;
  566.         dp = dst->samples + ( (y - dst->y) * dst->w + (x - dst->x) ) * dst->n;
  567.         if (color)
  568.                 fz_paint_span_with_color(dp, mp, dst->n, w, color);
  569.         else
  570.                 fz_paint_span(dp, mp, 1, w, 255);
  571. }
  572.  
  573. static void
  574. fz_scan_convert_aa(fz_gel *gel, int eofill, fz_bbox clip,
  575.         fz_pixmap *dst, unsigned char *color)
  576. {
  577.         unsigned char *alphas;
  578.         int *deltas;
  579.         int y, e;
  580.         int yd, yc;
  581.  
  582.         int xmin = fz_idiv(gel->bbox.x0, fz_aa_hscale);
  583.         int xmax = fz_idiv(gel->bbox.x1, fz_aa_hscale) + 1;
  584.  
  585.         int xofs = xmin * fz_aa_hscale;
  586.  
  587.         int skipx = clip.x0 - xmin;
  588.         int clipn = clip.x1 - clip.x0;
  589.  
  590.         if (gel->len == 0)
  591.                 return;
  592.  
  593.         assert(clip.x0 >= xmin);
  594.         assert(clip.x1 <= xmax);
  595.  
  596.         alphas = fz_malloc(xmax - xmin + 1);
  597.         deltas = fz_malloc((xmax - xmin + 1) * sizeof(int));
  598.         memset(deltas, 0, (xmax - xmin + 1) * sizeof(int));
  599.  
  600.         e = 0;
  601.         y = gel->edges[0].y;
  602.         yc = fz_idiv(y, fz_aa_vscale);
  603.         yd = yc;
  604.  
  605.         while (gel->alen > 0 || e < gel->len)
  606.         {
  607.                 yc = fz_idiv(y, fz_aa_vscale);
  608.                 if (yc != yd)
  609.                 {
  610.                         if (yd >= clip.y0 && yd < clip.y1)
  611.                         {
  612.                                 undelta_aa(alphas, deltas, skipx + clipn);
  613.                                 blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color);
  614.                                 memset(deltas, 0, (skipx + clipn) * sizeof(int));
  615.                         }
  616.                 }
  617.                 yd = yc;
  618.  
  619.                 insert_active(gel, y, &e);
  620.  
  621.                 if (yd >= clip.y0 && yd < clip.y1)
  622.                 {
  623.                         if (eofill)
  624.                                 even_odd_aa(gel, deltas, xofs);
  625.                         else
  626.                                 non_zero_winding_aa(gel, deltas, xofs);
  627.                 }
  628.  
  629.                 advance_active(gel);
  630.  
  631.                 if (gel->alen > 0)
  632.                         y ++;
  633.                 else if (e < gel->len)
  634.                         y = gel->edges[e].y;
  635.         }
  636.  
  637.         if (yd >= clip.y0 && yd < clip.y1)
  638.         {
  639.                 undelta_aa(alphas, deltas, skipx + clipn);
  640.                 blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color);
  641.         }
  642.  
  643.         fz_free(deltas);
  644.         fz_free(alphas);
  645. }
  646.  
  647. /*
  648.  * Sharp (not anti-aliased) scan conversion
  649.  */
  650.  
  651. static inline void blit_sharp(int x0, int x1, int y,
  652.         fz_bbox clip, fz_pixmap *dst, unsigned char *color)
  653. {
  654.         unsigned char *dp;
  655.         x0 = CLAMP(x0, dst->x, dst->x + dst->w);
  656.         x1 = CLAMP(x1, dst->x, dst->x + dst->w);
  657.         if (x0 < x1)
  658.         {
  659.                 dp = dst->samples + ( (y - dst->y) * dst->w + (x0 - dst->x) ) * dst->n;
  660.                 if (color)
  661.                         fz_paint_solid_color(dp, dst->n, x1 - x0, color);
  662.                 else
  663.                         fz_paint_solid_alpha(dp, x1 - x0, 255);
  664.         }
  665. }
  666.  
  667. static inline void non_zero_winding_sharp(fz_gel *gel, int y,
  668.         fz_bbox clip, fz_pixmap *dst, unsigned char *color)
  669. {
  670.         int winding = 0;
  671.         int x = 0;
  672.         int i;
  673.         for (i = 0; i < gel->alen; i++)
  674.         {
  675.                 if (!winding && (winding + gel->active[i]->ydir))
  676.                         x = gel->active[i]->x;
  677.                 if (winding && !(winding + gel->active[i]->ydir))
  678.                         blit_sharp(x, gel->active[i]->x, y, clip, dst, color);
  679.                 winding += gel->active[i]->ydir;
  680.         }
  681. }
  682.  
  683. static inline void even_odd_sharp(fz_gel *gel, int y,
  684.         fz_bbox clip, fz_pixmap *dst, unsigned char *color)
  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);
  695.                 even = !even;
  696.         }
  697. }
  698.  
  699. static void
  700. fz_scan_convert_sharp(fz_gel *gel, int eofill, fz_bbox clip,
  701.         fz_pixmap *dst, unsigned char *color)
  702. {
  703.         int e = 0;
  704.         int y = gel->edges[0].y;
  705.  
  706.         while (gel->alen > 0 || e < gel->len)
  707.         {
  708.                 insert_active(gel, y, &e);
  709.  
  710.                 if (y >= clip.y0 && y < clip.y1)
  711.                 {
  712.                         if (eofill)
  713.                                 even_odd_sharp(gel, y, clip, dst, color);
  714.                         else
  715.                                 non_zero_winding_sharp(gel, y, clip, dst, color);
  716.                 }
  717.  
  718.                 advance_active(gel);
  719.  
  720.                 if (gel->alen > 0)
  721.                         y ++;
  722.                 else if (e < gel->len)
  723.                         y = gel->edges[e].y;
  724.         }
  725. }
  726.  
  727. void
  728. fz_scan_convert(fz_gel *gel, int eofill, fz_bbox clip,
  729.         fz_pixmap *dst, unsigned char *color)
  730. {
  731.         if (fz_aa_level > 0)
  732.                 fz_scan_convert_aa(gel, eofill, clip, dst, color);
  733.         else
  734.                 fz_scan_convert_sharp(gel, eofill, clip, dst, color);
  735. }
  736.