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 QUANT(x,a) (((int)((x) * (a))) / (a))
  4. #define HSUBPIX 5.0
  5. #define VSUBPIX 5.0
  6.  
  7. #define STACK_SIZE 96
  8.  
  9. /* Enable the following to attempt to support knockout and/or isolated
  10.  * blending groups. This code is known to give incorrect results currently
  11.  * so disabled by default. See bug 692377. */
  12. #undef ATTEMPT_KNOCKOUT_AND_ISOLATED
  13.  
  14. /* Enable the following to help debug group blending. */
  15. #undef DUMP_GROUP_BLENDS
  16.  
  17. /* Note #1: At various points in this code (notably when clipping with non
  18.  * rectangular masks), we create a new (empty) destination pixmap. We then
  19.  * render this pixmap, then plot it back into the original destination
  20.  * through a mask. This works well for normal blending, but falls down for
  21.  * non-zero blending modes; effectively we are forcing ourselves to use an
  22.  * isolated group.
  23.  *
  24.  * The fix for this would be to copy the contents from the underlying dest
  25.  * into the newly created dest. This would enable us to use a non
  26.  * FZ_BLEND_ISOLATED blendmode. Unfortunately, tt would break tiling, as
  27.  * we could no longer render once and blend back multiple times.
  28.  */
  29.  
  30.  
  31. typedef struct fz_draw_device_s fz_draw_device;
  32.  
  33. enum {
  34.         FZ_DRAWDEV_FLAGS_TYPE3 = 1,
  35. };
  36.  
  37. struct fz_draw_device_s
  38. {
  39.         fz_glyph_cache *cache;
  40.         fz_gel *gel;
  41.  
  42.         fz_pixmap *dest;
  43.         fz_pixmap *shape;
  44.         fz_bbox scissor;
  45.  
  46.         int flags;
  47.         int top;
  48.         int blendmode;
  49.         struct {
  50.                 fz_bbox scissor;
  51.                 fz_pixmap *dest;
  52.                 fz_pixmap *mask;
  53.                 fz_pixmap *shape;
  54.                 int blendmode;
  55.                 int luminosity;
  56.                 float alpha;
  57.                 fz_matrix ctm;
  58.                 float xstep, ystep;
  59.                 fz_rect area;
  60.         } stack[STACK_SIZE];
  61. };
  62.  
  63. #ifdef DUMP_GROUP_BLENDS
  64. static int group_dump_count = 0;
  65.  
  66. static void fz_dump_blend(fz_pixmap *pix, const char *s)
  67. {
  68.         char name[80];
  69.  
  70.         if (pix == NULL)
  71.                 return;
  72.  
  73.         sprintf(name, "dump%02d.png", group_dump_count);
  74.         if (s)
  75.                 printf("%s%02d", s, group_dump_count);
  76.         group_dump_count++;
  77.  
  78.         fz_write_png(pix, name, (pix->n > 1));
  79. }
  80.  
  81. static void dump_spaces(int x, const char *s)
  82. {
  83.         int i;
  84.         for (i = 0; i < x; i++)
  85.                 printf(" ");
  86.         printf("%s", s);
  87. }
  88.  
  89. #endif
  90.  
  91. static void fz_knockout_begin(void *user)
  92. {
  93.         fz_draw_device *dev = user;
  94.         fz_bbox bbox;
  95.         fz_pixmap *dest, *shape;
  96.         int isolated = dev->blendmode & FZ_BLEND_ISOLATED;
  97.  
  98.         if ((dev->blendmode & FZ_BLEND_KNOCKOUT) == 0)
  99.                 return;
  100.  
  101.         if (dev->top == STACK_SIZE)
  102.         {
  103.                 fz_warn("assert: too many buffers on stack");
  104.                 return;
  105.         }
  106.  
  107.         bbox = fz_bound_pixmap(dev->dest);
  108.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  109.         dest = fz_new_pixmap_with_rect(dev->dest->colorspace, bbox);
  110.  
  111.         if (isolated)
  112.         {
  113.                 fz_clear_pixmap(dest);
  114.         }
  115.         else
  116.         {
  117.                 fz_pixmap *prev;
  118.                 int i  = dev->top;
  119.                 do
  120.                         prev = dev->stack[--i].dest;
  121.                 while (prev == NULL);
  122.                 fz_copy_pixmap_rect(dest, prev, bbox);
  123.         }
  124.  
  125.         if (dev->blendmode == 0 && isolated)
  126.         {
  127.                 /* We can render direct to any existing shape plane. If there
  128.                  * isn't one, we don't need to make one. */
  129.                 shape = dev->shape;
  130.         }
  131.         else
  132.         {
  133.                 shape = fz_new_pixmap_with_rect(NULL, bbox);
  134.                 fz_clear_pixmap(shape);
  135.         }
  136.         dev->stack[dev->top].blendmode = dev->blendmode;
  137.         dev->stack[dev->top].scissor = dev->scissor;
  138.         dev->stack[dev->top].dest = dev->dest;
  139.         dev->stack[dev->top].shape = dev->shape;
  140. #ifdef DUMP_GROUP_BLENDS
  141.         dump_spaces(dev->top, "Knockout begin\n");
  142. #endif
  143.         dev->top++;
  144.  
  145.         dev->scissor = bbox;
  146.         dev->dest = dest;
  147.         dev->shape = shape;
  148.         dev->blendmode &= ~FZ_BLEND_MODEMASK;
  149. }
  150.  
  151. static void fz_knockout_end(void *user)
  152. {
  153.         fz_draw_device *dev = user;
  154.         fz_pixmap *group = dev->dest;
  155.         fz_pixmap *shape = dev->shape;
  156.         int blendmode;
  157.         int isolated;
  158.  
  159.         if ((dev->blendmode & FZ_BLEND_KNOCKOUT) == 0)
  160.                 return;
  161.  
  162.         if (dev->top == STACK_SIZE)
  163.         {
  164.                 fz_warn("assert: too many buffers on stack");
  165.                 return;
  166.         }
  167.  
  168.         if (dev->top > 0)
  169.         {
  170.                 dev->top--;
  171.                 blendmode = dev->blendmode & FZ_BLEND_MODEMASK;
  172.                 isolated = dev->blendmode & FZ_BLEND_ISOLATED;
  173.                 dev->blendmode = dev->stack[dev->top].blendmode;
  174.                 dev->shape = dev->stack[dev->top].shape;
  175.                 dev->dest = dev->stack[dev->top].dest;
  176.                 dev->scissor = dev->stack[dev->top].scissor;
  177.  
  178. #ifdef DUMP_GROUP_BLENDS
  179.                 dump_spaces(dev->top, "");
  180.                 fz_dump_blend(group, "Blending ");
  181.                 if (shape)
  182.                         fz_dump_blend(shape, "/");
  183.                 fz_dump_blend(dev->dest, " onto ");
  184.                 if (dev->shape)
  185.                         fz_dump_blend(dev->shape, "/");
  186.                 if (blendmode != 0)
  187.                         printf(" (blend %d)", blendmode);
  188.                 if (isolated != 0)
  189.                         printf(" (isolated)");
  190.                 printf(" (knockout)");
  191. #endif
  192.                 if ((blendmode == 0) && (shape == NULL))
  193.                         fz_paint_pixmap(dev->dest, group, 255);
  194.                 else
  195.                         fz_blend_pixmap(dev->dest, group, 255, blendmode, isolated, shape);
  196.  
  197.                 fz_drop_pixmap(group);
  198.                 if (shape != dev->shape)
  199.                 {
  200.                         if (dev->shape)
  201.                         {
  202.                                 fz_paint_pixmap(dev->shape, shape, 255);
  203.                         }
  204.                         fz_drop_pixmap(shape);
  205.                 }
  206. #ifdef DUMP_GROUP_BLENDS
  207.                 fz_dump_blend(dev->dest, " to get ");
  208.                 if (dev->shape)
  209.                         fz_dump_blend(dev->shape, "/");
  210.                 printf("\n");
  211. #endif
  212.         }
  213. }
  214.  
  215. static void
  216. fz_draw_fill_path(void *user, fz_path *path, int even_odd, fz_matrix ctm,
  217.         fz_colorspace *colorspace, float *color, float alpha)
  218. {
  219.         fz_draw_device *dev = user;
  220.         fz_colorspace *model = dev->dest->colorspace;
  221.         float expansion = fz_matrix_expansion(ctm);
  222.         float flatness = 0.3f / expansion;
  223.         unsigned char colorbv[FZ_MAX_COLORS + 1];
  224.         float colorfv[FZ_MAX_COLORS];
  225.         fz_bbox bbox;
  226.         int i;
  227.  
  228.         fz_reset_gel(dev->gel, dev->scissor);
  229.         fz_flatten_fill_path(dev->gel, path, ctm, flatness);
  230.         fz_sort_gel(dev->gel);
  231.  
  232.         bbox = fz_bound_gel(dev->gel);
  233.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  234.  
  235.         if (fz_is_empty_rect(bbox))
  236.                 return;
  237.  
  238.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  239.                 fz_knockout_begin(dev);
  240.  
  241.         fz_convert_color(colorspace, color, model, colorfv);
  242.         for (i = 0; i < model->n; i++)
  243.                 colorbv[i] = colorfv[i] * 255;
  244.         colorbv[i] = alpha * 255;
  245.  
  246.         fz_scan_convert(dev->gel, even_odd, bbox, dev->dest, colorbv);
  247.         if (dev->shape)
  248.         {
  249.                 fz_reset_gel(dev->gel, dev->scissor);
  250.                 fz_flatten_fill_path(dev->gel, path, ctm, flatness);
  251.                 fz_sort_gel(dev->gel);
  252.  
  253.                 colorbv[0] = alpha * 255;
  254.                 fz_scan_convert(dev->gel, even_odd, bbox, dev->shape, colorbv);
  255.         }
  256.  
  257.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  258.                 fz_knockout_end(dev);
  259. }
  260.  
  261. static void
  262. fz_draw_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm,
  263.         fz_colorspace *colorspace, float *color, float alpha)
  264. {
  265.         fz_draw_device *dev = user;
  266.         fz_colorspace *model = dev->dest->colorspace;
  267.         float expansion = fz_matrix_expansion(ctm);
  268.         float flatness = 0.3f / expansion;
  269.         float linewidth = stroke->linewidth;
  270.         unsigned char colorbv[FZ_MAX_COLORS + 1];
  271.         float colorfv[FZ_MAX_COLORS];
  272.         fz_bbox bbox;
  273.         int i;
  274.  
  275.         if (linewidth * expansion < 0.1f)
  276.                 linewidth = 1 / expansion;
  277.  
  278.         fz_reset_gel(dev->gel, dev->scissor);
  279.         if (stroke->dash_len > 0)
  280.                 fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth);
  281.         else
  282.                 fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth);
  283.         fz_sort_gel(dev->gel);
  284.  
  285.         bbox = fz_bound_gel(dev->gel);
  286.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  287.  
  288.         if (fz_is_empty_rect(bbox))
  289.                 return;
  290.  
  291.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  292.                 fz_knockout_begin(dev);
  293.  
  294.         fz_convert_color(colorspace, color, model, colorfv);
  295.         for (i = 0; i < model->n; i++)
  296.                 colorbv[i] = colorfv[i] * 255;
  297.         colorbv[i] = alpha * 255;
  298.  
  299.         fz_scan_convert(dev->gel, 0, bbox, dev->dest, colorbv);
  300.         if (dev->shape)
  301.         {
  302.                 fz_reset_gel(dev->gel, dev->scissor);
  303.                 if (stroke->dash_len > 0)
  304.                         fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth);
  305.                 else
  306.                         fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth);
  307.                 fz_sort_gel(dev->gel);
  308.  
  309.                 colorbv[0] = 255;
  310.                 fz_scan_convert(dev->gel, 0, bbox, dev->shape, colorbv);
  311.         }
  312.  
  313.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  314.                 fz_knockout_end(dev);
  315. }
  316.  
  317. static void
  318. fz_draw_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
  319. {
  320.         fz_draw_device *dev = user;
  321.         fz_colorspace *model = dev->dest->colorspace;
  322.         float expansion = fz_matrix_expansion(ctm);
  323.         float flatness = 0.3f / expansion;
  324.         fz_pixmap *mask, *dest, *shape;
  325.         fz_bbox bbox;
  326.  
  327.         if (dev->top == STACK_SIZE)
  328.         {
  329.                 fz_warn("assert: too many buffers on stack");
  330.                 return;
  331.         }
  332.  
  333.         fz_reset_gel(dev->gel, dev->scissor);
  334.         fz_flatten_fill_path(dev->gel, path, ctm, flatness);
  335.         fz_sort_gel(dev->gel);
  336.  
  337.         bbox = fz_bound_gel(dev->gel);
  338.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  339.         if (rect)
  340.                 bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));
  341.  
  342.         if (fz_is_empty_rect(bbox) || fz_is_rect_gel(dev->gel))
  343.         {
  344.                 dev->stack[dev->top].scissor = dev->scissor;
  345.                 dev->stack[dev->top].mask = NULL;
  346.                 dev->stack[dev->top].dest = NULL;
  347.                 dev->stack[dev->top].shape = dev->shape;
  348.                 dev->stack[dev->top].blendmode = dev->blendmode;
  349.                 dev->scissor = bbox;
  350. #ifdef DUMP_GROUP_BLENDS
  351.                 dump_spaces(dev->top, "Clip (rectangular) begin\n");
  352. #endif
  353.                 dev->top++;
  354.                 return;
  355.         }
  356.  
  357.         mask = fz_new_pixmap_with_rect(NULL, bbox);
  358.         fz_clear_pixmap(mask);
  359.         dest = fz_new_pixmap_with_rect(model, bbox);
  360.         /* FIXME: See note #1 */
  361.         fz_clear_pixmap(dest);
  362.         if (dev->shape)
  363.         {
  364.                 shape = fz_new_pixmap_with_rect(NULL, bbox);
  365.                 fz_clear_pixmap(shape);
  366.         }
  367.         else
  368.                 shape = NULL;
  369.  
  370.         fz_scan_convert(dev->gel, even_odd, bbox, mask, NULL);
  371.  
  372.         dev->stack[dev->top].scissor = dev->scissor;
  373.         dev->stack[dev->top].mask = mask;
  374.         dev->stack[dev->top].dest = dev->dest;
  375.         dev->stack[dev->top].shape = dev->shape;
  376.         /* FIXME: See note #1 */
  377.         dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
  378.         dev->scissor = bbox;
  379.         dev->dest = dest;
  380.         dev->shape = shape;
  381. #ifdef DUMP_GROUP_BLENDS
  382.         dump_spaces(dev->top, "Clip (non-rectangular) begin\n");
  383. #endif
  384.         dev->top++;
  385. }
  386.  
  387. static void
  388. fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
  389. {
  390.         fz_draw_device *dev = user;
  391.         fz_colorspace *model = dev->dest->colorspace;
  392.         float expansion = fz_matrix_expansion(ctm);
  393.         float flatness = 0.3f / expansion;
  394.         float linewidth = stroke->linewidth;
  395.         fz_pixmap *mask, *dest, *shape;
  396.         fz_bbox bbox;
  397.  
  398.         if (dev->top == STACK_SIZE)
  399.         {
  400.                 fz_warn("assert: too many buffers on stack");
  401.                 return;
  402.         }
  403.  
  404.         if (linewidth * expansion < 0.1f)
  405.                 linewidth = 1 / expansion;
  406.  
  407.         fz_reset_gel(dev->gel, dev->scissor);
  408.         if (stroke->dash_len > 0)
  409.                 fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth);
  410.         else
  411.                 fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth);
  412.         fz_sort_gel(dev->gel);
  413.  
  414.         bbox = fz_bound_gel(dev->gel);
  415.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  416.         if (rect)
  417.                 bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));
  418.  
  419.         mask = fz_new_pixmap_with_rect(NULL, bbox);
  420.         fz_clear_pixmap(mask);
  421.         dest = fz_new_pixmap_with_rect(model, bbox);
  422.         /* FIXME: See note #1 */
  423.         fz_clear_pixmap(dest);
  424.         if (dev->shape)
  425.         {
  426.                 shape = fz_new_pixmap_with_rect(NULL, bbox);
  427.                 fz_clear_pixmap(shape);
  428.         }
  429.         else
  430.                 shape = NULL;
  431.  
  432.         if (!fz_is_empty_rect(bbox))
  433.                 fz_scan_convert(dev->gel, 0, bbox, mask, NULL);
  434.  
  435.         dev->stack[dev->top].scissor = dev->scissor;
  436.         dev->stack[dev->top].mask = mask;
  437.         dev->stack[dev->top].dest = dev->dest;
  438.         dev->stack[dev->top].shape = dev->shape;
  439.         /* FIXME: See note #1 */
  440.         dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
  441.         dev->scissor = bbox;
  442.         dev->dest = dest;
  443.         dev->shape = shape;
  444. #ifdef DUMP_GROUP_BLENDS
  445.         dump_spaces(dev->top, "Clip (stroke) begin\n");
  446. #endif
  447.         dev->top++;
  448. }
  449.  
  450. static void
  451. draw_glyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *msk,
  452.         int xorig, int yorig, fz_bbox scissor)
  453. {
  454.         unsigned char *dp, *mp;
  455.         fz_bbox bbox;
  456.         int x, y, w, h;
  457.  
  458.         bbox = fz_bound_pixmap(msk);
  459.         bbox.x0 += xorig;
  460.         bbox.y0 += yorig;
  461.         bbox.x1 += xorig;
  462.         bbox.y1 += yorig;
  463.  
  464.         bbox = fz_intersect_bbox(bbox, scissor); /* scissor < dst */
  465.         x = bbox.x0;
  466.         y = bbox.y0;
  467.         w = bbox.x1 - bbox.x0;
  468.         h = bbox.y1 - bbox.y0;
  469.  
  470.         mp = msk->samples + ((y - msk->y - yorig) * msk->w + (x - msk->x - xorig));
  471.         dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
  472.  
  473.         assert(msk->n == 1);
  474.  
  475.         while (h--)
  476.         {
  477.                 if (dst->colorspace)
  478.                         fz_paint_span_with_color(dp, mp, dst->n, w, colorbv);
  479.                 else
  480.                         fz_paint_span(dp, mp, 1, w, 255);
  481.                 dp += dst->w * dst->n;
  482.                 mp += msk->w;
  483.         }
  484. }
  485.  
  486. static void
  487. fz_draw_fill_text(void *user, fz_text *text, fz_matrix ctm,
  488.         fz_colorspace *colorspace, float *color, float alpha)
  489. {
  490.         fz_draw_device *dev = user;
  491.         fz_colorspace *model = dev->dest->colorspace;
  492.         unsigned char colorbv[FZ_MAX_COLORS + 1];
  493.         unsigned char shapebv;
  494.         float colorfv[FZ_MAX_COLORS];
  495.         fz_matrix tm, trm;
  496.         fz_pixmap *glyph;
  497.         int i, x, y, gid;
  498.  
  499.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  500.                 fz_knockout_begin(dev);
  501.  
  502.         fz_convert_color(colorspace, color, model, colorfv);
  503.         for (i = 0; i < model->n; i++)
  504.                 colorbv[i] = colorfv[i] * 255;
  505.         colorbv[i] = alpha * 255;
  506.         shapebv = 255;
  507.  
  508.         tm = text->trm;
  509.  
  510.         for (i = 0; i < text->len; i++)
  511.         {
  512.                 gid = text->items[i].gid;
  513.                 if (gid < 0)
  514.                         continue;
  515.  
  516.                 tm.e = text->items[i].x;
  517.                 tm.f = text->items[i].y;
  518.                 trm = fz_concat(tm, ctm);
  519.                 x = floorf(trm.e);
  520.                 y = floorf(trm.f);
  521.                 trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
  522.                 trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
  523.  
  524.                 glyph = fz_render_glyph(dev->cache, text->font, gid, trm, model);
  525.                 if (glyph)
  526.                 {
  527.                         if (glyph->n == 1)
  528.                         {
  529.                                 draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor);
  530.                                 if (dev->shape)
  531.                                         draw_glyph(&shapebv, dev->shape, glyph, x, y, dev->scissor);
  532.                         }
  533.                         else
  534.                         {
  535.                                 fz_matrix ctm = {glyph->w, 0.0, 0.0, -glyph->h, x + glyph->x, y + glyph->y + glyph->h};
  536.                                 fz_paint_image(dev->dest, dev->scissor, dev->shape, glyph, ctm, alpha * 255);
  537.                         }
  538.                         fz_drop_pixmap(glyph);
  539.                 }
  540.         }
  541.  
  542.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  543.                 fz_knockout_end(dev);
  544. }
  545.  
  546. static void
  547. fz_draw_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm,
  548.         fz_colorspace *colorspace, float *color, float alpha)
  549. {
  550.         fz_draw_device *dev = user;
  551.         fz_colorspace *model = dev->dest->colorspace;
  552.         unsigned char colorbv[FZ_MAX_COLORS + 1];
  553.         float colorfv[FZ_MAX_COLORS];
  554.         fz_matrix tm, trm;
  555.         fz_pixmap *glyph;
  556.         int i, x, y, gid;
  557.  
  558.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  559.                 fz_knockout_begin(dev);
  560.  
  561.         fz_convert_color(colorspace, color, model, colorfv);
  562.         for (i = 0; i < model->n; i++)
  563.                 colorbv[i] = colorfv[i] * 255;
  564.         colorbv[i] = alpha * 255;
  565.  
  566.         tm = text->trm;
  567.  
  568.         for (i = 0; i < text->len; i++)
  569.         {
  570.                 gid = text->items[i].gid;
  571.                 if (gid < 0)
  572.                         continue;
  573.  
  574.                 tm.e = text->items[i].x;
  575.                 tm.f = text->items[i].y;
  576.                 trm = fz_concat(tm, ctm);
  577.                 x = floorf(trm.e);
  578.                 y = floorf(trm.f);
  579.                 trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
  580.                 trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
  581.  
  582.                 glyph = fz_render_stroked_glyph(dev->cache, text->font, gid, trm, ctm, stroke);
  583.                 if (glyph)
  584.                 {
  585.                         draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor);
  586.                         if (dev->shape)
  587.                                 draw_glyph(colorbv, dev->shape, glyph, x, y, dev->scissor);
  588.                         fz_drop_pixmap(glyph);
  589.                 }
  590.         }
  591.  
  592.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  593.                 fz_knockout_end(dev);
  594. }
  595.  
  596. static void
  597. fz_draw_clip_text(void *user, fz_text *text, fz_matrix ctm, int accumulate)
  598. {
  599.         fz_draw_device *dev = user;
  600.         fz_colorspace *model = dev->dest->colorspace;
  601.         fz_bbox bbox;
  602.         fz_pixmap *mask, *dest, *shape;
  603.         fz_matrix tm, trm;
  604.         fz_pixmap *glyph;
  605.         int i, x, y, gid;
  606.  
  607.         /* If accumulate == 0 then this text object is guaranteed complete */
  608.         /* If accumulate == 1 then this text object is the first (or only) in a sequence */
  609.         /* If accumulate == 2 then this text object is a continuation */
  610.  
  611.         if (dev->top == STACK_SIZE)
  612.         {
  613.                 fz_warn("assert: too many buffers on stack");
  614.                 return;
  615.         }
  616.  
  617.         if (accumulate == 0)
  618.         {
  619.                 /* make the mask the exact size needed */
  620.                 bbox = fz_round_rect(fz_bound_text(text, ctm));
  621.                 bbox = fz_intersect_bbox(bbox, dev->scissor);
  622.         }
  623.         else
  624.         {
  625.                 /* be conservative about the size of the mask needed */
  626.                 bbox = dev->scissor;
  627.         }
  628.  
  629.         if (accumulate == 0 || accumulate == 1)
  630.         {
  631.                 mask = fz_new_pixmap_with_rect(NULL, bbox);
  632.                 fz_clear_pixmap(mask);
  633.                 dest = fz_new_pixmap_with_rect(model, bbox);
  634.                 /* FIXME: See note #1 */
  635.                 fz_clear_pixmap(dest);
  636.                 if (dev->shape)
  637.                 {
  638.                         shape = fz_new_pixmap_with_rect(NULL, bbox);
  639.                         fz_clear_pixmap(shape);
  640.                 }
  641.                 else
  642.                         shape = NULL;
  643.  
  644.                 dev->stack[dev->top].scissor = dev->scissor;
  645.                 dev->stack[dev->top].mask = mask;
  646.                 dev->stack[dev->top].dest = dev->dest;
  647.                 dev->stack[dev->top].shape = dev->shape;
  648.                 /* FIXME: See note #1 */
  649.                 dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
  650.                 dev->scissor = bbox;
  651.                 dev->dest = dest;
  652.                 dev->shape = shape;
  653. #ifdef DUMP_GROUP_BLENDS
  654.                 dump_spaces(dev->top, "Clip (text) begin\n");
  655. #endif
  656.                 dev->top++;
  657.         }
  658.         else
  659.         {
  660.                 mask = dev->stack[dev->top-1].mask;
  661.         }
  662.  
  663.         if (!fz_is_empty_rect(bbox))
  664.         {
  665.                 tm = text->trm;
  666.  
  667.                 for (i = 0; i < text->len; i++)
  668.                 {
  669.                         gid = text->items[i].gid;
  670.                         if (gid < 0)
  671.                                 continue;
  672.  
  673.                         tm.e = text->items[i].x;
  674.                         tm.f = text->items[i].y;
  675.                         trm = fz_concat(tm, ctm);
  676.                         x = floorf(trm.e);
  677.                         y = floorf(trm.f);
  678.                         trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
  679.                         trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
  680.  
  681.                         glyph = fz_render_glyph(dev->cache, text->font, gid, trm, model);
  682.                         if (glyph)
  683.                         {
  684.                                 draw_glyph(NULL, mask, glyph, x, y, bbox);
  685.                                 if (dev->shape)
  686.                                         draw_glyph(NULL, dev->shape, glyph, x, y, bbox);
  687.                                 fz_drop_pixmap(glyph);
  688.                         }
  689.                 }
  690.         }
  691. }
  692.  
  693. static void
  694. fz_draw_clip_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm)
  695. {
  696.         fz_draw_device *dev = user;
  697.         fz_colorspace *model = dev->dest->colorspace;
  698.         fz_bbox bbox;
  699.         fz_pixmap *mask, *dest, *shape;
  700.         fz_matrix tm, trm;
  701.         fz_pixmap *glyph;
  702.         int i, x, y, gid;
  703.  
  704.         if (dev->top == STACK_SIZE)
  705.         {
  706.                 fz_warn("assert: too many buffers on stack");
  707.                 return;
  708.         }
  709.  
  710.         /* make the mask the exact size needed */
  711.         bbox = fz_round_rect(fz_bound_text(text, ctm));
  712.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  713.  
  714.         mask = fz_new_pixmap_with_rect(NULL, bbox);
  715.         fz_clear_pixmap(mask);
  716.         dest = fz_new_pixmap_with_rect(model, bbox);
  717.         /* FIXME: See note #1 */
  718.         fz_clear_pixmap(dest);
  719.         if (dev->shape)
  720.         {
  721.                 shape = fz_new_pixmap_with_rect(NULL, bbox);
  722.                 fz_clear_pixmap(shape);
  723.         }
  724.         else
  725.                 shape = dev->shape;
  726.  
  727.         dev->stack[dev->top].scissor = dev->scissor;
  728.         dev->stack[dev->top].mask = mask;
  729.         dev->stack[dev->top].dest = dev->dest;
  730.         dev->stack[dev->top].shape = dev->shape;
  731.         /* FIXME: See note #1 */
  732.         dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
  733.         dev->scissor = bbox;
  734.         dev->dest = dest;
  735.         dev->shape = shape;
  736. #ifdef DUMP_GROUP_BLENDS
  737.         dump_spaces(dev->top, "Clip (stroke text) begin\n");
  738. #endif
  739.         dev->top++;
  740.  
  741.         if (!fz_is_empty_rect(bbox))
  742.         {
  743.                 tm = text->trm;
  744.  
  745.                 for (i = 0; i < text->len; i++)
  746.                 {
  747.                         gid = text->items[i].gid;
  748.                         if (gid < 0)
  749.                                 continue;
  750.  
  751.                         tm.e = text->items[i].x;
  752.                         tm.f = text->items[i].y;
  753.                         trm = fz_concat(tm, ctm);
  754.                         x = floorf(trm.e);
  755.                         y = floorf(trm.f);
  756.                         trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
  757.                         trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
  758.  
  759.                         glyph = fz_render_stroked_glyph(dev->cache, text->font, gid, trm, ctm, stroke);
  760.                         if (glyph)
  761.                         {
  762.                                 draw_glyph(NULL, mask, glyph, x, y, bbox);
  763.                                 if (dev->shape)
  764.                                         draw_glyph(NULL, dev->shape, glyph, x, y, bbox);
  765.                                 fz_drop_pixmap(glyph);
  766.                         }
  767.                 }
  768.         }
  769. }
  770.  
  771. static void
  772. fz_draw_ignore_text(void *user, fz_text *text, fz_matrix ctm)
  773. {
  774. }
  775.  
  776. static void
  777. fz_draw_fill_shade(void *user, fz_shade *shade, fz_matrix ctm, float alpha)
  778. {
  779.         fz_draw_device *dev = user;
  780.         fz_colorspace *model = dev->dest->colorspace;
  781.         fz_pixmap *dest = dev->dest;
  782.         fz_rect bounds;
  783.         fz_bbox bbox, scissor;
  784.         float colorfv[FZ_MAX_COLORS];
  785.         unsigned char colorbv[FZ_MAX_COLORS + 1];
  786.  
  787.         bounds = fz_bound_shade(shade, ctm);
  788.         bbox = fz_intersect_bbox(fz_round_rect(bounds), dev->scissor);
  789.         scissor = dev->scissor;
  790.  
  791.         // TODO: proper clip by shade->bbox
  792.  
  793.         if (fz_is_empty_rect(bbox))
  794.                 return;
  795.  
  796.         if (!model)
  797.         {
  798.                 fz_warn("cannot render shading directly to an alpha mask");
  799.                 return;
  800.         }
  801.  
  802.         if (alpha < 1)
  803.         {
  804.                 dest = fz_new_pixmap_with_rect(dev->dest->colorspace, bbox);
  805.                 fz_clear_pixmap(dest);
  806.         }
  807.  
  808.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  809.                 fz_knockout_begin(dev);
  810.  
  811.         if (shade->use_background)
  812.         {
  813.                 unsigned char *s;
  814.                 int x, y, n, i;
  815.                 fz_convert_color(shade->colorspace, shade->background, model, colorfv);
  816.                 for (i = 0; i < model->n; i++)
  817.                         colorbv[i] = colorfv[i] * 255;
  818.                 colorbv[i] = 255;
  819.  
  820.                 n = dest->n;
  821.                 for (y = scissor.y0; y < scissor.y1; y++)
  822.                 {
  823.                         s = dest->samples + ((scissor.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n;
  824.                         for (x = scissor.x0; x < scissor.x1; x++)
  825.                         {
  826.                                 for (i = 0; i < n; i++)
  827.                                         *s++ = colorbv[i];
  828.                         }
  829.                 }
  830.                 if (dev->shape)
  831.                 {
  832.                         for (y = scissor.y0; y < scissor.y1; y++)
  833.                         {
  834.                                 s = dev->shape->samples + (scissor.x0 - dev->shape->x) + (y - dev->shape->y) * dev->shape->w;
  835.                                 for (x = scissor.x0; x < scissor.x1; x++)
  836.                                 {
  837.                                         *s++ = 255;
  838.                                 }
  839.                         }
  840.                 }
  841.         }
  842.  
  843.         fz_paint_shade(shade, ctm, dest, bbox);
  844.         if (dev->shape)
  845.                 fz_clear_pixmap_rect_with_color(dev->shape, 255, bbox);
  846.  
  847.         if (alpha < 1)
  848.         {
  849.                 fz_paint_pixmap(dev->dest, dest, alpha * 255);
  850.                 fz_drop_pixmap(dest);
  851.         }
  852.  
  853.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  854.                 fz_knockout_end(dev);
  855. }
  856.  
  857. static fz_pixmap *
  858. fz_transform_pixmap(fz_pixmap *image, fz_matrix *ctm, int x, int y, int dx, int dy, int gridfit)
  859. {
  860.         fz_pixmap *scaled;
  861.  
  862.         if (ctm->a != 0 && ctm->b == 0 && ctm->c == 0 && ctm->d != 0)
  863.         {
  864.                 /* Unrotated or X-flip or Y-flip or XY-flip */
  865.                 scaled = fz_scale_pixmap_gridfit(image, ctm->e, ctm->f, ctm->a, ctm->d, gridfit);
  866.                 if (scaled == NULL)
  867.                         return NULL;
  868.                 ctm->a = scaled->w;
  869.                 ctm->d = scaled->h;
  870.                 ctm->e = scaled->x;
  871.                 ctm->f = scaled->y;
  872.                 return scaled;
  873.         }
  874.  
  875.         if (ctm->a == 0 && ctm->b != 0 && ctm->c != 0 && ctm->d == 0)
  876.         {
  877.                 /* Other orthogonal flip/rotation cases */
  878.                 scaled = fz_scale_pixmap_gridfit(image, ctm->f, ctm->e, ctm->b, ctm->c, gridfit);
  879.                 if (scaled == NULL)
  880.                         return NULL;
  881.                 ctm->b = scaled->w;
  882.                 ctm->c = scaled->h;
  883.                 ctm->f = scaled->x;
  884.                 ctm->e = scaled->y;
  885.                 return scaled;
  886.         }
  887.  
  888.         /* Downscale, non rectilinear case */
  889.         if (dx > 0 && dy > 0)
  890.         {
  891.                 scaled = fz_scale_pixmap(image, 0, 0, (float)dx, (float)dy);
  892.                 return scaled;
  893.         }
  894.  
  895.         return NULL;
  896. }
  897.  
  898. static void
  899. fz_draw_fill_image(void *user, fz_pixmap *image, fz_matrix ctm, float alpha)
  900. {
  901.         fz_draw_device *dev = user;
  902.         fz_colorspace *model = dev->dest->colorspace;
  903.         fz_pixmap *converted = NULL;
  904.         fz_pixmap *scaled = NULL;
  905.         int after;
  906.         int dx, dy;
  907.  
  908.         if (!model)
  909.         {
  910.                 fz_warn("cannot render image directly to an alpha mask");
  911.                 return;
  912.         }
  913.  
  914.         if (image->w == 0 || image->h == 0)
  915.                 return;
  916.  
  917.         /* convert images with more components (cmyk->rgb) before scaling */
  918.         /* convert images with fewer components (gray->rgb after scaling */
  919.         /* convert images with expensive colorspace transforms after scaling */
  920.  
  921.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  922.                 fz_knockout_begin(dev);
  923.  
  924.         after = 0;
  925.         if (image->colorspace == fz_device_gray)
  926.                 after = 1;
  927.  
  928.         if (image->colorspace != model && !after)
  929.         {
  930.                 converted = fz_new_pixmap_with_rect(model, fz_bound_pixmap(image));
  931.                 fz_convert_pixmap(image, converted);
  932.                 image = converted;
  933.         }
  934.  
  935.         dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
  936.         dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
  937.         if (dx < image->w && dy < image->h)
  938.         {
  939.                 int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
  940.                 scaled = fz_transform_pixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit);
  941.                 if (scaled == NULL)
  942.                 {
  943.                         if (dx < 1)
  944.                                 dx = 1;
  945.                         if (dy < 1)
  946.                                 dy = 1;
  947.                         scaled = fz_scale_pixmap(image, image->x, image->y, dx, dy);
  948.                 }
  949.                 if (scaled != NULL)
  950.                         image = scaled;
  951.         }
  952.  
  953.         if (image->colorspace != model)
  954.         {
  955.                 if ((image->colorspace == fz_device_gray && model == fz_device_rgb) ||
  956.                         (image->colorspace == fz_device_gray && model == fz_device_bgr))
  957.                 {
  958.                         /* We have special case rendering code for gray -> rgb/bgr */
  959.                 }
  960.                 else
  961.                 {
  962.                         converted = fz_new_pixmap_with_rect(model, fz_bound_pixmap(image));
  963.                         fz_convert_pixmap(image, converted);
  964.                         image = converted;
  965.                 }
  966.         }
  967.  
  968.         fz_paint_image(dev->dest, dev->scissor, dev->shape, image, ctm, alpha * 255);
  969.  
  970.         if (scaled)
  971.                 fz_drop_pixmap(scaled);
  972.         if (converted)
  973.                 fz_drop_pixmap(converted);
  974.  
  975.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  976.                 fz_knockout_end(dev);
  977. }
  978.  
  979. static void
  980. fz_draw_fill_image_mask(void *user, fz_pixmap *image, fz_matrix ctm,
  981.         fz_colorspace *colorspace, float *color, float alpha)
  982. {
  983.         fz_draw_device *dev = user;
  984.         fz_colorspace *model = dev->dest->colorspace;
  985.         unsigned char colorbv[FZ_MAX_COLORS + 1];
  986.         float colorfv[FZ_MAX_COLORS];
  987.         fz_pixmap *scaled = NULL;
  988.         int dx, dy;
  989.         int i;
  990.  
  991.         if (image->w == 0 || image->h == 0)
  992.                 return;
  993.  
  994.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  995.                 fz_knockout_begin(dev);
  996.  
  997.         dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
  998.         dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
  999.         if (dx < image->w && dy < image->h)
  1000.         {
  1001.                 int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
  1002.                 scaled = fz_transform_pixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit);
  1003.                 if (scaled == NULL)
  1004.                 {
  1005.                         if (dx < 1)
  1006.                                 dx = 1;
  1007.                         if (dy < 1)
  1008.                                 dy = 1;
  1009.                         scaled = fz_scale_pixmap(image, image->x, image->y, dx, dy);
  1010.                 }
  1011.                 if (scaled != NULL)
  1012.                         image = scaled;
  1013.         }
  1014.  
  1015.         fz_convert_color(colorspace, color, model, colorfv);
  1016.         for (i = 0; i < model->n; i++)
  1017.                 colorbv[i] = colorfv[i] * 255;
  1018.         colorbv[i] = alpha * 255;
  1019.  
  1020.         fz_paint_image_with_color(dev->dest, dev->scissor, dev->shape, image, ctm, colorbv);
  1021.  
  1022.         if (scaled)
  1023.                 fz_drop_pixmap(scaled);
  1024.  
  1025.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  1026.                 fz_knockout_begin(dev);
  1027. }
  1028.  
  1029. static void
  1030. fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
  1031. {
  1032.         fz_draw_device *dev = user;
  1033.         fz_colorspace *model = dev->dest->colorspace;
  1034.         fz_bbox bbox;
  1035.         fz_pixmap *mask, *dest, *shape;
  1036.         fz_pixmap *scaled = NULL;
  1037.         int dx, dy;
  1038.  
  1039.         if (dev->top == STACK_SIZE)
  1040.         {
  1041.                 fz_warn("assert: too many buffers on stack");
  1042.                 return;
  1043.         }
  1044.  
  1045. #ifdef DUMP_GROUP_BLENDS
  1046.         dump_spaces(dev->top, "Clip (image mask) begin\n");
  1047. #endif
  1048.  
  1049.         if (image->w == 0 || image->h == 0)
  1050.         {
  1051.                 dev->stack[dev->top].scissor = dev->scissor;
  1052.                 dev->stack[dev->top].mask = NULL;
  1053.                 dev->stack[dev->top].dest = NULL;
  1054.                 dev->stack[dev->top].blendmode = dev->blendmode;
  1055.                 dev->scissor = fz_empty_bbox;
  1056.                 dev->top++;
  1057.                 return;
  1058.         }
  1059.  
  1060.         bbox = fz_round_rect(fz_transform_rect(ctm, fz_unit_rect));
  1061.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  1062.         if (rect)
  1063.                 bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));
  1064.  
  1065.         mask = fz_new_pixmap_with_rect(NULL, bbox);
  1066.         fz_clear_pixmap(mask);
  1067.         dest = fz_new_pixmap_with_rect(model, bbox);
  1068.         /* FIXME: See note #1 */
  1069.         fz_clear_pixmap(dest);
  1070.         if (dev->shape)
  1071.         {
  1072.                 shape = fz_new_pixmap_with_rect(NULL, bbox);
  1073.                 fz_clear_pixmap(shape);
  1074.         }
  1075.         else
  1076.                 shape = NULL;
  1077.  
  1078.         dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
  1079.         dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
  1080.         if (dx < image->w && dy < image->h)
  1081.         {
  1082.                 int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
  1083.                 scaled = fz_transform_pixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit);
  1084.                 if (scaled == NULL)
  1085.                 {
  1086.                         if (dx < 1)
  1087.                                 dx = 1;
  1088.                         if (dy < 1)
  1089.                                 dy = 1;
  1090.                         scaled = fz_scale_pixmap(image, image->x, image->y, dx, dy);
  1091.                 }
  1092.                 if (scaled != NULL)
  1093.                         image = scaled;
  1094.         }
  1095.  
  1096.         fz_paint_image(mask, bbox, dev->shape, image, ctm, 255);
  1097.  
  1098.         if (scaled)
  1099.                 fz_drop_pixmap(scaled);
  1100.  
  1101.         dev->stack[dev->top].scissor = dev->scissor;
  1102.         dev->stack[dev->top].mask = mask;
  1103.         dev->stack[dev->top].dest = dev->dest;
  1104.         dev->stack[dev->top].shape = dev->shape;
  1105.         /* FIXME: See note #1 */
  1106.         dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
  1107.         dev->scissor = bbox;
  1108.         dev->dest = dest;
  1109.         dev->shape = shape;
  1110.         dev->top++;
  1111. }
  1112.  
  1113. static void
  1114. fz_draw_pop_clip(void *user)
  1115. {
  1116.         fz_draw_device *dev = user;
  1117.         fz_pixmap *mask, *dest, *shape;
  1118.         if (dev->top > 0)
  1119.         {
  1120.                 dev->top--;
  1121.                 dev->scissor = dev->stack[dev->top].scissor;
  1122.                 mask = dev->stack[dev->top].mask;
  1123.                 dest = dev->stack[dev->top].dest;
  1124.                 shape = dev->stack[dev->top].shape;
  1125.                 dev->blendmode = dev->stack[dev->top].blendmode;
  1126.  
  1127.                 /* We can get here with mask == NULL if the clipping actually
  1128.                  * resolved to a rectangle earlier. In this case, we will
  1129.                  * have a dest, and the shape will be unchanged.
  1130.                  */
  1131.                 if (mask)
  1132.                 {
  1133.                         assert(dest);
  1134.  
  1135. #ifdef DUMP_GROUP_BLENDS
  1136.                         dump_spaces(dev->top, "");
  1137.                         fz_dump_blend(dev->dest, "Clipping ");
  1138.                         if (dev->shape)
  1139.                                 fz_dump_blend(dev->shape, "/");
  1140.                         fz_dump_blend(dest, " onto ");
  1141.                         if (shape)
  1142.                                 fz_dump_blend(shape, "/");
  1143.                         fz_dump_blend(mask, " with ");
  1144. #endif
  1145.                         fz_paint_pixmap_with_mask(dest, dev->dest, mask);
  1146.                         if (shape != NULL)
  1147.                         {
  1148.                                 assert(shape != dev->shape);
  1149.                                 fz_paint_pixmap_with_mask(shape, dev->shape, mask);
  1150.                                 fz_drop_pixmap(dev->shape);
  1151.                                 dev->shape = shape;
  1152.                         }
  1153.                         fz_drop_pixmap(mask);
  1154.                         fz_drop_pixmap(dev->dest);
  1155.                         dev->dest = dest;
  1156. #ifdef DUMP_GROUP_BLENDS
  1157.                         fz_dump_blend(dev->dest, " to get ");
  1158.                         if (dev->shape)
  1159.                                 fz_dump_blend(dev->shape, "/");
  1160.                         printf("\n");
  1161. #endif
  1162.                 }
  1163.                 else
  1164.                 {
  1165. #ifdef DUMP_GROUP_BLENDS
  1166.                         dump_spaces(dev->top, "Clip End\n");
  1167. #endif
  1168.                         assert(dest == NULL);
  1169.                         assert(shape == dev->shape);
  1170.                 }
  1171.         }
  1172. }
  1173.  
  1174. static void
  1175. fz_draw_begin_mask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv)
  1176. {
  1177.         fz_draw_device *dev = user;
  1178.         fz_pixmap *dest;
  1179.         fz_pixmap *shape = dev->shape;
  1180.         fz_bbox bbox;
  1181.  
  1182.         if (dev->top == STACK_SIZE)
  1183.         {
  1184.                 fz_warn("assert: too many buffers on stack");
  1185.                 return;
  1186.         }
  1187.  
  1188.         bbox = fz_round_rect(rect);
  1189.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  1190.         dest = fz_new_pixmap_with_rect(fz_device_gray, bbox);
  1191.         if (dev->shape)
  1192.         {
  1193.                 /* FIXME: If we ever want to support AIS true, then we
  1194.                  * probably want to create a shape pixmap here, using:
  1195.                  *     shape = fz_new_pixmap_with_rect(NULL, bbox);
  1196.                  * then, in the end_mask code, we create the mask from this
  1197.                  * rather than dest.
  1198.                  */
  1199.                 shape = NULL;
  1200.         }
  1201.  
  1202.         if (luminosity)
  1203.         {
  1204.                 float bc;
  1205.                 if (!colorspace)
  1206.                         colorspace = fz_device_gray;
  1207.                 fz_convert_color(colorspace, colorfv, fz_device_gray, &bc);
  1208.                 fz_clear_pixmap_with_color(dest, bc * 255);
  1209.                 if (shape)
  1210.                         fz_clear_pixmap_with_color(shape, 255);
  1211.         }
  1212.         else
  1213.         {
  1214.                 fz_clear_pixmap(dest);
  1215.                 if (shape)
  1216.                         fz_clear_pixmap(shape);
  1217.         }
  1218.  
  1219.         dev->stack[dev->top].scissor = dev->scissor;
  1220.         dev->stack[dev->top].dest = dev->dest;
  1221.         dev->stack[dev->top].luminosity = luminosity;
  1222.         dev->stack[dev->top].shape = dev->shape;
  1223.         dev->stack[dev->top].blendmode = dev->blendmode;
  1224. #ifdef DUMP_GROUP_BLENDS
  1225.         dump_spaces(dev->top, "Mask begin\n");
  1226. #endif
  1227.         dev->top++;
  1228.  
  1229.         dev->scissor = bbox;
  1230.         dev->dest = dest;
  1231.         dev->shape = shape;
  1232. }
  1233.  
  1234. static void
  1235. fz_draw_end_mask(void *user)
  1236. {
  1237.         fz_draw_device *dev = user;
  1238.         fz_pixmap *mask = dev->dest;
  1239.         fz_pixmap *maskshape = dev->shape;
  1240.         fz_pixmap *temp, *dest;
  1241.         fz_bbox bbox;
  1242.         int luminosity;
  1243.  
  1244.         if (dev->top == STACK_SIZE)
  1245.         {
  1246.                 fz_warn("assert: too many buffers on stack");
  1247.                 return;
  1248.         }
  1249.  
  1250.         if (dev->top > 0)
  1251.         {
  1252.                 /* pop soft mask buffer */
  1253.                 dev->top--;
  1254.                 luminosity = dev->stack[dev->top].luminosity;
  1255.                 dev->scissor = dev->stack[dev->top].scissor;
  1256.                 dev->dest = dev->stack[dev->top].dest;
  1257.                 dev->shape = dev->stack[dev->top].shape;
  1258.  
  1259.                 /* convert to alpha mask */
  1260.                 temp = fz_alpha_from_gray(mask, luminosity);
  1261.                 fz_drop_pixmap(mask);
  1262.                 fz_drop_pixmap(maskshape);
  1263.  
  1264.                 /* create new dest scratch buffer */
  1265.                 bbox = fz_bound_pixmap(temp);
  1266.                 dest = fz_new_pixmap_with_rect(dev->dest->colorspace, bbox);
  1267.                 /* FIXME: See note #1 */
  1268.                 fz_clear_pixmap(dest);
  1269.  
  1270.                 /* push soft mask as clip mask */
  1271.                 dev->stack[dev->top].scissor = dev->scissor;
  1272.                 dev->stack[dev->top].mask = temp;
  1273.                 dev->stack[dev->top].dest = dev->dest;
  1274.                 /* FIXME: See note #1 */
  1275.                 dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
  1276.                 /* If we have a shape, then it'll need to be masked with the
  1277.                  * clip mask when we pop. So create a new shape now. */
  1278.                 if (dev->shape)
  1279.                 {
  1280.                         dev->stack[dev->top].shape = dev->shape;
  1281.                         dev->shape = fz_new_pixmap_with_rect(NULL, bbox);
  1282.                         fz_clear_pixmap(dev->shape);
  1283.                 }
  1284.                 dev->scissor = bbox;
  1285.                 dev->dest = dest;
  1286. #ifdef DUMP_GROUP_BLENDS
  1287.                 dump_spaces(dev->top, "Mask -> Clip\n");
  1288. #endif
  1289.                 dev->top++;
  1290.         }
  1291. }
  1292.  
  1293. static void
  1294. fz_draw_begin_group(void *user, fz_rect rect, int isolated, int knockout, int blendmode, float alpha)
  1295. {
  1296.         fz_draw_device *dev = user;
  1297.         fz_colorspace *model = dev->dest->colorspace;
  1298.         fz_bbox bbox;
  1299.         fz_pixmap *dest, *shape;
  1300.  
  1301.         if (dev->top == STACK_SIZE)
  1302.         {
  1303.                 fz_warn("assert: too many buffers on stack");
  1304.                 return;
  1305.         }
  1306.  
  1307.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  1308.                 fz_knockout_begin(dev);
  1309.  
  1310.         bbox = fz_round_rect(rect);
  1311.         bbox = fz_intersect_bbox(bbox, dev->scissor);
  1312.         dest = fz_new_pixmap_with_rect(model, bbox);
  1313.  
  1314. #ifndef ATTEMPT_KNOCKOUT_AND_ISOLATED
  1315.         knockout = 0;
  1316.         isolated = 1;
  1317. #endif
  1318.  
  1319.         if (isolated)
  1320.         {
  1321.                 fz_clear_pixmap(dest);
  1322.         }
  1323.         else
  1324.         {
  1325.                 fz_copy_pixmap_rect(dest, dev->dest, bbox);
  1326.         }
  1327.  
  1328.         if (blendmode == 0 && alpha == 1.0 && isolated)
  1329.         {
  1330.                 /* We can render direct to any existing shape plane. If there
  1331.                  * isn't one, we don't need to make one. */
  1332.                 shape = dev->shape;
  1333.         }
  1334.         else
  1335.         {
  1336.                 shape = fz_new_pixmap_with_rect(NULL, bbox);
  1337.                 fz_clear_pixmap(shape);
  1338.         }
  1339.  
  1340.         dev->stack[dev->top].alpha = alpha;
  1341.         dev->stack[dev->top].blendmode = dev->blendmode;
  1342.         dev->stack[dev->top].scissor = dev->scissor;
  1343.         dev->stack[dev->top].dest = dev->dest;
  1344.         dev->stack[dev->top].shape = dev->shape;
  1345. #ifdef DUMP_GROUP_BLENDS
  1346.         dump_spaces(dev->top, "Group Begin\n");
  1347. #endif
  1348.         dev->top++;
  1349.  
  1350.         dev->scissor = bbox;
  1351.         dev->dest = dest;
  1352.         dev->shape = shape;
  1353.         dev->blendmode = blendmode | (isolated ? FZ_BLEND_ISOLATED : 0) | (knockout ? FZ_BLEND_KNOCKOUT : 0);
  1354. }
  1355.  
  1356. static void
  1357. fz_draw_end_group(void *user)
  1358. {
  1359.         fz_draw_device *dev = user;
  1360.         fz_pixmap *group = dev->dest;
  1361.         fz_pixmap *shape = dev->shape;
  1362.         int blendmode;
  1363.         int isolated;
  1364.         float alpha;
  1365.  
  1366.         if (dev->top > 0)
  1367.         {
  1368.                 dev->top--;
  1369.                 alpha = dev->stack[dev->top].alpha;
  1370.                 blendmode = dev->blendmode & FZ_BLEND_MODEMASK;
  1371.                 isolated = dev->blendmode & FZ_BLEND_ISOLATED;
  1372.                 dev->blendmode = dev->stack[dev->top].blendmode;
  1373.                 dev->shape = dev->stack[dev->top].shape;
  1374.                 dev->dest = dev->stack[dev->top].dest;
  1375.                 dev->scissor = dev->stack[dev->top].scissor;
  1376.  
  1377. #ifdef DUMP_GROUP_BLENDS
  1378.                 dump_spaces(dev->top, "");
  1379.                 fz_dump_blend(group, "Blending ");
  1380.                 if (shape)
  1381.                         fz_dump_blend(shape, "/");
  1382.                 fz_dump_blend(dev->dest, " onto ");
  1383.                 if (dev->shape)
  1384.                         fz_dump_blend(dev->shape, "/");
  1385.                 if (alpha != 1.0f)
  1386.                         printf(" (alpha %g)", alpha);
  1387.                 if (blendmode != 0)
  1388.                         printf(" (blend %d)", blendmode);
  1389.                 if (isolated != 0)
  1390.                         printf(" (isolated)");
  1391.                 if (blendmode & FZ_BLEND_KNOCKOUT)
  1392.                         printf(" (knockout)");
  1393. #endif
  1394.                 if ((blendmode == 0) && (shape == NULL))
  1395.                         fz_paint_pixmap(dev->dest, group, alpha * 255);
  1396.                 else
  1397.                         fz_blend_pixmap(dev->dest, group, alpha * 255, blendmode, isolated, shape);
  1398.  
  1399.                 fz_drop_pixmap(group);
  1400.                 if (shape != dev->shape)
  1401.                 {
  1402.                         if (dev->shape)
  1403.                         {
  1404.                                 fz_paint_pixmap(dev->shape, shape, alpha * 255);
  1405.                         }
  1406.                         fz_drop_pixmap(shape);
  1407.                 }
  1408. #ifdef DUMP_GROUP_BLENDS
  1409.                 fz_dump_blend(dev->dest, " to get ");
  1410.                 if (dev->shape)
  1411.                         fz_dump_blend(dev->shape, "/");
  1412.                 printf("\n");
  1413. #endif
  1414.         }
  1415.  
  1416.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  1417.                 fz_knockout_end(dev);
  1418. }
  1419.  
  1420. static void
  1421. fz_draw_begin_tile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
  1422. {
  1423.         fz_draw_device *dev = user;
  1424.         fz_colorspace *model = dev->dest->colorspace;
  1425.         fz_pixmap *dest;
  1426.         fz_bbox bbox;
  1427.  
  1428.         /* area, view, xstep, ystep are in pattern space */
  1429.         /* ctm maps from pattern space to device space */
  1430.  
  1431.         if (dev->top == STACK_SIZE)
  1432.         {
  1433.                 fz_warn("assert: too many buffers on stack");
  1434.                 return;
  1435.         }
  1436.  
  1437.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  1438.                 fz_knockout_begin(dev);
  1439.  
  1440.         bbox = fz_round_rect(fz_transform_rect(ctm, view));
  1441.         dest = fz_new_pixmap_with_rect(model, bbox);
  1442.         /* FIXME: See note #1 */
  1443.         fz_clear_pixmap(dest);
  1444.  
  1445.         dev->stack[dev->top].scissor = dev->scissor;
  1446.         dev->stack[dev->top].dest = dev->dest;
  1447.         dev->stack[dev->top].shape = dev->shape;
  1448.         /* FIXME: See note #1 */
  1449.         dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
  1450.         dev->stack[dev->top].xstep = xstep;
  1451.         dev->stack[dev->top].ystep = ystep;
  1452.         dev->stack[dev->top].area = area;
  1453.         dev->stack[dev->top].ctm = ctm;
  1454. #ifdef DUMP_GROUP_BLENDS
  1455.         dump_spaces(dev->top, "Tile begin\n");
  1456. #endif
  1457.         dev->top++;
  1458.  
  1459.         dev->scissor = bbox;
  1460.         dev->dest = dest;
  1461. }
  1462.  
  1463. static void
  1464. fz_draw_end_tile(void *user)
  1465. {
  1466.         fz_draw_device *dev = user;
  1467.         fz_pixmap *tile = dev->dest;
  1468.         float xstep, ystep;
  1469.         fz_matrix ctm, ttm;
  1470.         fz_rect area;
  1471.         int x0, y0, x1, y1, x, y;
  1472.  
  1473.         if (dev->top > 0)
  1474.         {
  1475.                 dev->top--;
  1476. #ifdef DUMP_GROUP_BLENDS
  1477.                 dump_spaces(dev->top, "Tile end\n");
  1478. #endif
  1479.                 xstep = dev->stack[dev->top].xstep;
  1480.                 ystep = dev->stack[dev->top].ystep;
  1481.                 area = dev->stack[dev->top].area;
  1482.                 ctm = dev->stack[dev->top].ctm;
  1483.                 dev->scissor = dev->stack[dev->top].scissor;
  1484.                 dev->dest = dev->stack[dev->top].dest;
  1485.                 dev->blendmode = dev->stack[dev->top].blendmode;
  1486.  
  1487.  
  1488.                 x0 = floorf(area.x0 / xstep);
  1489.                 y0 = floorf(area.y0 / ystep);
  1490.                 x1 = ceilf(area.x1 / xstep);
  1491.                 y1 = ceilf(area.y1 / ystep);
  1492.  
  1493.                 ctm.e = tile->x;
  1494.                 ctm.f = tile->y;
  1495.  
  1496.                 for (y = y0; y < y1; y++)
  1497.                 {
  1498.                         for (x = x0; x < x1; x++)
  1499.                         {
  1500.                                 ttm = fz_concat(fz_translate(x * xstep, y * ystep), ctm);
  1501.                                 tile->x = ttm.e;
  1502.                                 tile->y = ttm.f;
  1503.                                 fz_paint_pixmap_with_rect(dev->dest, tile, 255, dev->scissor);
  1504.                         }
  1505.                 }
  1506.  
  1507.                 fz_drop_pixmap(tile);
  1508.         }
  1509.  
  1510.         if (dev->blendmode & FZ_BLEND_KNOCKOUT)
  1511.                 fz_knockout_begin(dev);
  1512. }
  1513.  
  1514. static void
  1515. fz_draw_free_user(void *user)
  1516. {
  1517.         fz_draw_device *dev = user;
  1518.         /* TODO: pop and free the stacks */
  1519.         if (dev->top > 0)
  1520.                 fz_warn("items left on stack in draw device: %d", dev->top);
  1521.         fz_free_gel(dev->gel);
  1522.         fz_free(dev);
  1523. }
  1524.  
  1525. fz_device *
  1526. fz_new_draw_device(fz_glyph_cache *cache, fz_pixmap *dest)
  1527. {
  1528.         fz_device *dev;
  1529.         fz_draw_device *ddev = fz_malloc(sizeof(fz_draw_device));
  1530.         ddev->cache = cache;
  1531.         ddev->gel = fz_new_gel();
  1532.         ddev->dest = dest;
  1533.         ddev->shape = NULL;
  1534.         ddev->top = 0;
  1535.         ddev->blendmode = 0;
  1536.         ddev->flags = 0;
  1537.  
  1538.         ddev->scissor.x0 = dest->x;
  1539.         ddev->scissor.y0 = dest->y;
  1540.         ddev->scissor.x1 = dest->x + dest->w;
  1541.         ddev->scissor.y1 = dest->y + dest->h;
  1542.  
  1543.         dev = fz_new_device(ddev);
  1544.         dev->free_user = fz_draw_free_user;
  1545.  
  1546.         dev->fill_path = fz_draw_fill_path;
  1547.         dev->stroke_path = fz_draw_stroke_path;
  1548.         dev->clip_path = fz_draw_clip_path;
  1549.         dev->clip_stroke_path = fz_draw_clip_stroke_path;
  1550.  
  1551.         dev->fill_text = fz_draw_fill_text;
  1552.         dev->stroke_text = fz_draw_stroke_text;
  1553.         dev->clip_text = fz_draw_clip_text;
  1554.         dev->clip_stroke_text = fz_draw_clip_stroke_text;
  1555.         dev->ignore_text = fz_draw_ignore_text;
  1556.  
  1557.         dev->fill_image_mask = fz_draw_fill_image_mask;
  1558.         dev->clip_image_mask = fz_draw_clip_image_mask;
  1559.         dev->fill_image = fz_draw_fill_image;
  1560.         dev->fill_shade = fz_draw_fill_shade;
  1561.  
  1562.         dev->pop_clip = fz_draw_pop_clip;
  1563.  
  1564.         dev->begin_mask = fz_draw_begin_mask;
  1565.         dev->end_mask = fz_draw_end_mask;
  1566.         dev->begin_group = fz_draw_begin_group;
  1567.         dev->end_group = fz_draw_end_group;
  1568.  
  1569.         dev->begin_tile = fz_draw_begin_tile;
  1570.         dev->end_tile = fz_draw_end_tile;
  1571.  
  1572.         return dev;
  1573. }
  1574.  
  1575. fz_device *
  1576. fz_new_draw_device_type3(fz_glyph_cache *cache, fz_pixmap *dest)
  1577. {
  1578.         fz_device *dev = fz_new_draw_device(cache, dest);
  1579.         fz_draw_device *ddev = dev->user;
  1580.         ddev->flags |= FZ_DRAWDEV_FLAGS_TYPE3;
  1581.         return dev;
  1582. }
  1583.