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. #include "mupdf.h"
  3.  
  4. #define TILE
  5.  
  6. typedef struct pdf_material_s pdf_material;
  7. typedef struct pdf_gstate_s pdf_gstate;
  8. typedef struct pdf_csi_s pdf_csi;
  9.  
  10. enum
  11. {
  12.         PDF_FILL,
  13.         PDF_STROKE,
  14. };
  15.  
  16. enum
  17. {
  18.         PDF_MAT_NONE,
  19.         PDF_MAT_COLOR,
  20.         PDF_MAT_PATTERN,
  21.         PDF_MAT_SHADE,
  22. };
  23.  
  24. struct pdf_material_s
  25. {
  26.         int kind;
  27.         fz_colorspace *colorspace;
  28.         pdf_pattern *pattern;
  29.         fz_shade *shade;
  30.         float alpha;
  31.         float v[32];
  32. };
  33.  
  34. struct pdf_gstate_s
  35. {
  36.         fz_matrix ctm;
  37.         int clip_depth;
  38.  
  39.         /* path stroking */
  40.         fz_stroke_state stroke_state;
  41.  
  42.         /* materials */
  43.         pdf_material stroke;
  44.         pdf_material fill;
  45.  
  46.         /* text state */
  47.         float char_space;
  48.         float word_space;
  49.         float scale;
  50.         float leading;
  51.         pdf_font_desc *font;
  52.         float size;
  53.         int render;
  54.         float rise;
  55.  
  56.         /* transparency */
  57.         int blendmode;
  58.         pdf_xobject *softmask;
  59.         fz_matrix softmask_ctm;
  60.         float softmask_bc[FZ_MAX_COLORS];
  61.         int luminosity;
  62. };
  63.  
  64. struct pdf_csi_s
  65. {
  66.         fz_device *dev;
  67.         pdf_xref *xref;
  68.  
  69.         /* usage mode for optional content groups */
  70.         char *target; /* "View", "Print", "Export" */
  71.  
  72.         /* interpreter stack */
  73.         fz_obj *obj;
  74.         char name[256];
  75.         unsigned char string[256];
  76.         int string_len;
  77.         float stack[32];
  78.         int top;
  79.  
  80.         int xbalance;
  81.         int in_text;
  82.  
  83.         /* path object state */
  84.         fz_path *path;
  85.  
  86.         /* text object state */
  87.         fz_text *text;
  88.         fz_matrix tlm;
  89.         fz_matrix tm;
  90.         int text_mode;
  91.         int accumulate;
  92.  
  93.         /* graphics state */
  94.         fz_matrix top_ctm;
  95.         pdf_gstate gstate[64];
  96.         int gtop;
  97. };
  98.  
  99. static fz_error pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents);
  100. static fz_error pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform);
  101. static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what);
  102.  
  103.  
  104. static int
  105. pdf_is_hidden_ocg(fz_obj *xobj, char *target)
  106. {
  107.         char target_state[16];
  108.         fz_obj *obj;
  109.  
  110.         fz_strlcpy(target_state, target, sizeof target_state);
  111.         fz_strlcat(target_state, "State", sizeof target_state);
  112.  
  113.         obj = fz_dict_gets(xobj, "OC");
  114.         obj = fz_dict_gets(obj, "OCGs");
  115.         if (fz_is_array(obj))
  116.                 obj = fz_array_get(obj, 0);
  117.         obj = fz_dict_gets(obj, "Usage");
  118.         obj = fz_dict_gets(obj, target);
  119.         obj = fz_dict_gets(obj, target_state);
  120.         return !strcmp(fz_to_name(obj), "OFF");
  121. }
  122.  
  123. /*
  124.  * Emit graphics calls to device.
  125.  */
  126.  
  127. static void
  128. pdf_begin_group(pdf_csi *csi, fz_rect bbox)
  129. {
  130.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  131.         fz_error error;
  132.  
  133.         if (gstate->softmask)
  134.         {
  135.                 pdf_xobject *softmask = gstate->softmask;
  136.                 fz_rect bbox = fz_transform_rect(gstate->softmask_ctm, softmask->bbox);
  137.                 fz_matrix save_ctm = gstate->ctm;
  138.  
  139.                 gstate->softmask = NULL;
  140.                 gstate->ctm = gstate->softmask_ctm;
  141.  
  142.                 fz_begin_mask(csi->dev, bbox, gstate->luminosity,
  143.                         softmask->colorspace, gstate->softmask_bc);
  144.                 error = pdf_run_xobject(csi, NULL, softmask, fz_identity);
  145.                 if (error)
  146.                         fz_catch(error, "cannot run softmask");
  147.                 fz_end_mask(csi->dev);
  148.  
  149.                 gstate->softmask = softmask;
  150.                 gstate->ctm = save_ctm;
  151.         }
  152.  
  153.         if (gstate->blendmode)
  154.                 fz_begin_group(csi->dev, bbox, 1, 0, gstate->blendmode, 1);
  155. }
  156.  
  157. static void
  158. pdf_end_group(pdf_csi *csi)
  159. {
  160.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  161.  
  162.         if (gstate->blendmode)
  163.                 fz_end_group(csi->dev);
  164.  
  165.         if (gstate->softmask)
  166.                 fz_pop_clip(csi->dev);
  167. }
  168.  
  169. static void
  170. pdf_show_shade(pdf_csi *csi, fz_shade *shd)
  171. {
  172.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  173.         fz_rect bbox;
  174.  
  175.         bbox = fz_bound_shade(shd, gstate->ctm);
  176.  
  177.         pdf_begin_group(csi, bbox);
  178.  
  179.         fz_fill_shade(csi->dev, shd, gstate->ctm, gstate->fill.alpha);
  180.  
  181.         pdf_end_group(csi);
  182. }
  183.  
  184. static void
  185. pdf_show_image(pdf_csi *csi, fz_pixmap *image)
  186. {
  187.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  188.         fz_rect bbox;
  189.  
  190.         bbox = fz_transform_rect(gstate->ctm, fz_unit_rect);
  191.  
  192.         if (image->mask)
  193.         {
  194.                 /* apply blend group even though we skip the softmask */
  195.                 if (gstate->blendmode)
  196.                         fz_begin_group(csi->dev, bbox, 0, 0, gstate->blendmode, 1);
  197.                 fz_clip_image_mask(csi->dev, image->mask, &bbox, gstate->ctm);
  198.         }
  199.         else
  200.                 pdf_begin_group(csi, bbox);
  201.  
  202.         if (!image->colorspace)
  203.         {
  204.  
  205.                 switch (gstate->fill.kind)
  206.                 {
  207.                 case PDF_MAT_NONE:
  208.                         break;
  209.                 case PDF_MAT_COLOR:
  210.                         fz_fill_image_mask(csi->dev, image, gstate->ctm,
  211.                                 gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
  212.                         break;
  213.                 case PDF_MAT_PATTERN:
  214.                         if (gstate->fill.pattern)
  215.                         {
  216.                                 fz_clip_image_mask(csi->dev, image, &bbox, gstate->ctm);
  217.                                 pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
  218.                                 fz_pop_clip(csi->dev);
  219.                         }
  220.                         break;
  221.                 case PDF_MAT_SHADE:
  222.                         if (gstate->fill.shade)
  223.                         {
  224.                                 fz_clip_image_mask(csi->dev, image, &bbox, gstate->ctm);
  225.                                 fz_fill_shade(csi->dev, gstate->fill.shade, gstate->ctm, gstate->fill.alpha);
  226.                                 fz_pop_clip(csi->dev);
  227.                         }
  228.                         break;
  229.                 }
  230.         }
  231.         else
  232.         {
  233.                 fz_fill_image(csi->dev, image, gstate->ctm, gstate->fill.alpha);
  234.         }
  235.  
  236.         if (image->mask)
  237.         {
  238.                 fz_pop_clip(csi->dev);
  239.                 if (gstate->blendmode)
  240.                         fz_end_group(csi->dev);
  241.         }
  242.         else
  243.                 pdf_end_group(csi);
  244. }
  245.  
  246. static void pdf_show_clip(pdf_csi *csi, int even_odd)
  247. {
  248.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  249.  
  250.         gstate->clip_depth++;
  251.         fz_clip_path(csi->dev, csi->path, NULL, even_odd, gstate->ctm);
  252. }
  253.  
  254. static void
  255. pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd)
  256. {
  257.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  258.         fz_path *path;
  259.         fz_rect bbox;
  260.  
  261.         path = csi->path;
  262.         csi->path = fz_new_path();
  263.  
  264.         if (doclose)
  265.                 fz_closepath(path);
  266.  
  267.         if (dostroke)
  268.                 bbox = fz_bound_path(path, &gstate->stroke_state, gstate->ctm);
  269.         else
  270.                 bbox = fz_bound_path(path, NULL, gstate->ctm);
  271.  
  272.         if (dofill || dostroke)
  273.                 pdf_begin_group(csi, bbox);
  274.  
  275.         if (dofill)
  276.         {
  277.                 switch (gstate->fill.kind)
  278.                 {
  279.                 case PDF_MAT_NONE:
  280.                         break;
  281.                 case PDF_MAT_COLOR:
  282.                         fz_fill_path(csi->dev, path, even_odd, gstate->ctm,
  283.                                 gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
  284.                         break;
  285.                 case PDF_MAT_PATTERN:
  286.                         if (gstate->fill.pattern)
  287.                         {
  288.                                 fz_clip_path(csi->dev, path, NULL, even_odd, gstate->ctm);
  289.                                 pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
  290.                                 fz_pop_clip(csi->dev);
  291.                         }
  292.                         break;
  293.                 case PDF_MAT_SHADE:
  294.                         if (gstate->fill.shade)
  295.                         {
  296.                                 fz_clip_path(csi->dev, path, NULL, even_odd, gstate->ctm);
  297.                                 fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
  298.                                 fz_pop_clip(csi->dev);
  299.                         }
  300.                         break;
  301.                 }
  302.         }
  303.  
  304.         if (dostroke)
  305.         {
  306.                 switch (gstate->stroke.kind)
  307.                 {
  308.                 case PDF_MAT_NONE:
  309.                         break;
  310.                 case PDF_MAT_COLOR:
  311.                         fz_stroke_path(csi->dev, path, &gstate->stroke_state, gstate->ctm,
  312.                                 gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
  313.                         break;
  314.                 case PDF_MAT_PATTERN:
  315.                         if (gstate->stroke.pattern)
  316.                         {
  317.                                 fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm);
  318.                                 pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
  319.                                 fz_pop_clip(csi->dev);
  320.                         }
  321.                         break;
  322.                 case PDF_MAT_SHADE:
  323.                         if (gstate->stroke.shade)
  324.                         {
  325.                                 fz_clip_stroke_path(csi->dev, path, &bbox, &gstate->stroke_state, gstate->ctm);
  326.                                 fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
  327.                                 fz_pop_clip(csi->dev);
  328.                         }
  329.                         break;
  330.                 }
  331.         }
  332.  
  333.         if (dofill || dostroke)
  334.                 pdf_end_group(csi);
  335.  
  336.         fz_free_path(path);
  337. }
  338.  
  339. /*
  340.  * Assemble and emit text
  341.  */
  342.  
  343. static void
  344. pdf_flush_text(pdf_csi *csi)
  345. {
  346.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  347.         fz_text *text;
  348.         int dofill = 0;
  349.         int dostroke = 0;
  350.         int doclip = 0;
  351.         int doinvisible = 0;
  352.         fz_rect bbox;
  353.  
  354.         if (!csi->text)
  355.                 return;
  356.         text = csi->text;
  357.         csi->text = NULL;
  358.  
  359.         dofill = dostroke = doclip = doinvisible = 0;
  360.         switch (csi->text_mode)
  361.         {
  362.         case 0: dofill = 1; break;
  363.         case 1: dostroke = 1; break;
  364.         case 2: dofill = dostroke = 1; break;
  365.         case 3: doinvisible = 1; break;
  366.         case 4: dofill = doclip = 1; break;
  367.         case 5: dostroke = doclip = 1; break;
  368.         case 6: dofill = dostroke = doclip = 1; break;
  369.         case 7: doclip = 1; break;
  370.         }
  371.  
  372.         bbox = fz_bound_text(text, gstate->ctm);
  373.  
  374.         pdf_begin_group(csi, bbox);
  375.  
  376.         if (doinvisible)
  377.                 fz_ignore_text(csi->dev, text, gstate->ctm);
  378.  
  379.         if (doclip)
  380.         {
  381.                 if (csi->accumulate < 2)
  382.                         gstate->clip_depth++;
  383.                 fz_clip_text(csi->dev, text, gstate->ctm, csi->accumulate);
  384.                 csi->accumulate = 2;
  385.         }
  386.  
  387.         if (dofill)
  388.         {
  389.                 switch (gstate->fill.kind)
  390.                 {
  391.                 case PDF_MAT_NONE:
  392.                         break;
  393.                 case PDF_MAT_COLOR:
  394.                         fz_fill_text(csi->dev, text, gstate->ctm,
  395.                                 gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
  396.                         break;
  397.                 case PDF_MAT_PATTERN:
  398.                         if (gstate->fill.pattern)
  399.                         {
  400.                                 fz_clip_text(csi->dev, text, gstate->ctm, 0);
  401.                                 pdf_show_pattern(csi, gstate->fill.pattern, bbox, PDF_FILL);
  402.                                 fz_pop_clip(csi->dev);
  403.                         }
  404.                         break;
  405.                 case PDF_MAT_SHADE:
  406.                         if (gstate->fill.shade)
  407.                         {
  408.                                 fz_clip_text(csi->dev, text, gstate->ctm, 0);
  409.                                 fz_fill_shade(csi->dev, gstate->fill.shade, csi->top_ctm, gstate->fill.alpha);
  410.                                 fz_pop_clip(csi->dev);
  411.                         }
  412.                         break;
  413.                 }
  414.         }
  415.  
  416.         if (dostroke)
  417.         {
  418.                 switch (gstate->stroke.kind)
  419.                 {
  420.                 case PDF_MAT_NONE:
  421.                         break;
  422.                 case PDF_MAT_COLOR:
  423.                         fz_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm,
  424.                                 gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
  425.                         break;
  426.                 case PDF_MAT_PATTERN:
  427.                         if (gstate->stroke.pattern)
  428.                         {
  429.                                 fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
  430.                                 pdf_show_pattern(csi, gstate->stroke.pattern, bbox, PDF_FILL);
  431.                                 fz_pop_clip(csi->dev);
  432.                         }
  433.                         break;
  434.                 case PDF_MAT_SHADE:
  435.                         if (gstate->stroke.shade)
  436.                         {
  437.                                 fz_clip_stroke_text(csi->dev, text, &gstate->stroke_state, gstate->ctm);
  438.                                 fz_fill_shade(csi->dev, gstate->stroke.shade, csi->top_ctm, gstate->stroke.alpha);
  439.                                 fz_pop_clip(csi->dev);
  440.                         }
  441.                         break;
  442.                 }
  443.         }
  444.  
  445.         pdf_end_group(csi);
  446.  
  447.         fz_free_text(text);
  448. }
  449.  
  450. static void
  451. pdf_show_char(pdf_csi *csi, int cid)
  452. {
  453.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  454.         pdf_font_desc *fontdesc = gstate->font;
  455.         fz_matrix tsm, trm;
  456.         float w0, w1, tx, ty;
  457.         pdf_hmtx h;
  458.         pdf_vmtx v;
  459.         int gid;
  460.         int ucsbuf[8];
  461.         int ucslen;
  462.         int i;
  463.  
  464.         tsm.a = gstate->size * gstate->scale;
  465.         tsm.b = 0;
  466.         tsm.c = 0;
  467.         tsm.d = gstate->size;
  468.         tsm.e = 0;
  469.         tsm.f = gstate->rise;
  470.  
  471.         ucslen = 0;
  472.         if (fontdesc->to_unicode)
  473.                 ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf);
  474.         if (ucslen == 0 && cid < fontdesc->cid_to_ucs_len)
  475.         {
  476.                 ucsbuf[0] = fontdesc->cid_to_ucs[cid];
  477.                 ucslen = 1;
  478.         }
  479.         if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0))
  480.         {
  481.                 ucsbuf[0] = '?';
  482.                 ucslen = 1;
  483.         }
  484.  
  485.         gid = pdf_font_cid_to_gid(fontdesc, cid);
  486.  
  487.         if (fontdesc->wmode == 1)
  488.         {
  489.                 v = pdf_get_vmtx(fontdesc, cid);
  490.                 tsm.e -= v.x * gstate->size * 0.001f;
  491.                 tsm.f -= v.y * gstate->size * 0.001f;
  492.         }
  493.  
  494.         trm = fz_concat(tsm, csi->tm);
  495.  
  496.         /* flush buffered text if face or matrix or rendermode has changed */
  497.         if (!csi->text ||
  498.                 fontdesc->font != csi->text->font ||
  499.                 fontdesc->wmode != csi->text->wmode ||
  500.                 fabsf(trm.a - csi->text->trm.a) > FLT_EPSILON ||
  501.                 fabsf(trm.b - csi->text->trm.b) > FLT_EPSILON ||
  502.                 fabsf(trm.c - csi->text->trm.c) > FLT_EPSILON ||
  503.                 fabsf(trm.d - csi->text->trm.d) > FLT_EPSILON ||
  504.                 gstate->render != csi->text_mode)
  505.         {
  506.                 pdf_flush_text(csi);
  507.  
  508.                 csi->text = fz_new_text(fontdesc->font, trm, fontdesc->wmode);
  509.                 csi->text->trm.e = 0;
  510.                 csi->text->trm.f = 0;
  511.                 csi->text_mode = gstate->render;
  512.         }
  513.  
  514.         /* add glyph to textobject */
  515.         fz_add_text(csi->text, gid, ucsbuf[0], trm.e, trm.f);
  516.  
  517.         /* add filler glyphs for one-to-many unicode mapping */
  518.         for (i = 1; i < ucslen; i++)
  519.                 fz_add_text(csi->text, -1, ucsbuf[i], trm.e, trm.f);
  520.  
  521.         if (fontdesc->wmode == 0)
  522.         {
  523.                 h = pdf_get_hmtx(fontdesc, cid);
  524.                 w0 = h.w * 0.001f;
  525.                 tx = (w0 * gstate->size + gstate->char_space) * gstate->scale;
  526.                 csi->tm = fz_concat(fz_translate(tx, 0), csi->tm);
  527.         }
  528.  
  529.         if (fontdesc->wmode == 1)
  530.         {
  531.                 w1 = v.w * 0.001f;
  532.                 ty = w1 * gstate->size + gstate->char_space;
  533.                 csi->tm = fz_concat(fz_translate(0, ty), csi->tm);
  534.         }
  535. }
  536.  
  537. static void
  538. pdf_show_space(pdf_csi *csi, float tadj)
  539. {
  540.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  541.         pdf_font_desc *fontdesc = gstate->font;
  542.  
  543.         if (!fontdesc)
  544.         {
  545.                 fz_warn("cannot draw text since font and size not set");
  546.                 return;
  547.         }
  548.  
  549.         if (fontdesc->wmode == 0)
  550.                 csi->tm = fz_concat(fz_translate(tadj * gstate->scale, 0), csi->tm);
  551.         else
  552.                 csi->tm = fz_concat(fz_translate(0, tadj), csi->tm);
  553. }
  554.  
  555. static void
  556. pdf_show_string(pdf_csi *csi, unsigned char *buf, int len)
  557. {
  558.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  559.         pdf_font_desc *fontdesc = gstate->font;
  560.         unsigned char *end = buf + len;
  561.         int cpt, cid;
  562.  
  563.         if (!fontdesc)
  564.         {
  565.                 fz_warn("cannot draw text since font and size not set");
  566.                 return;
  567.         }
  568.  
  569.         while (buf < end)
  570.         {
  571.                 buf = pdf_decode_cmap(fontdesc->encoding, buf, &cpt);
  572.                 cid = pdf_lookup_cmap(fontdesc->encoding, cpt);
  573.                 if (cid >= 0)
  574.                         pdf_show_char(csi, cid);
  575.                 else
  576.                         fz_warn("cannot encode character with code point %#x", cpt);
  577.                 if (cpt == 32)
  578.                         pdf_show_space(csi, gstate->word_space);
  579.         }
  580. }
  581.  
  582. static void
  583. pdf_show_text(pdf_csi *csi, fz_obj *text)
  584. {
  585.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  586.         int i;
  587.  
  588.         if (fz_is_array(text))
  589.         {
  590.                 for (i = 0; i < fz_array_len(text); i++)
  591.                 {
  592.                         fz_obj *item = fz_array_get(text, i);
  593.                         if (fz_is_string(item))
  594.                                 pdf_show_string(csi, (unsigned char *)fz_to_str_buf(item), fz_to_str_len(item));
  595.                         else
  596.                                 pdf_show_space(csi, - fz_to_real(item) * gstate->size * 0.001f);
  597.                 }
  598.         }
  599.         else if (fz_is_string(text))
  600.         {
  601.                 pdf_show_string(csi, (unsigned char *)fz_to_str_buf(text), fz_to_str_len(text));
  602.         }
  603. }
  604.  
  605. /*
  606.  * Interpreter and graphics state stack.
  607.  */
  608.  
  609. static void
  610. pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm)
  611. {
  612.         gs->ctm = ctm;
  613.         gs->clip_depth = 0;
  614.  
  615.         gs->stroke_state.start_cap = 0;
  616.         gs->stroke_state.dash_cap = 0;
  617.         gs->stroke_state.end_cap = 0;
  618.         gs->stroke_state.linejoin = 0;
  619.         gs->stroke_state.linewidth = 1;
  620.         gs->stroke_state.miterlimit = 10;
  621.         gs->stroke_state.dash_phase = 0;
  622.         gs->stroke_state.dash_len = 0;
  623.         memset(gs->stroke_state.dash_list, 0, sizeof(gs->stroke_state.dash_list));
  624.  
  625.         gs->stroke.kind = PDF_MAT_COLOR;
  626.         gs->stroke.colorspace = fz_keep_colorspace(fz_device_gray);
  627.         gs->stroke.v[0] = 0;
  628.         gs->stroke.pattern = NULL;
  629.         gs->stroke.shade = NULL;
  630.         gs->stroke.alpha = 1;
  631.  
  632.         gs->fill.kind = PDF_MAT_COLOR;
  633.         gs->fill.colorspace = fz_keep_colorspace(fz_device_gray);
  634.         gs->fill.v[0] = 0;
  635.         gs->fill.pattern = NULL;
  636.         gs->fill.shade = NULL;
  637.         gs->fill.alpha = 1;
  638.  
  639.         gs->char_space = 0;
  640.         gs->word_space = 0;
  641.         gs->scale = 1;
  642.         gs->leading = 0;
  643.         gs->font = NULL;
  644.         gs->size = -1;
  645.         gs->render = 0;
  646.         gs->rise = 0;
  647.  
  648.         gs->blendmode = 0;
  649.         gs->softmask = NULL;
  650.         gs->softmask_ctm = fz_identity;
  651.         gs->luminosity = 0;
  652. }
  653.  
  654. static pdf_csi *
  655. pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *target)
  656. {
  657.         pdf_csi *csi;
  658.  
  659.         csi = fz_malloc(sizeof(pdf_csi));
  660.         csi->xref = xref;
  661.         csi->dev = dev;
  662.         csi->target = target;
  663.  
  664.         csi->top = 0;
  665.         csi->obj = NULL;
  666.         csi->name[0] = 0;
  667.         csi->string_len = 0;
  668.         memset(csi->stack, 0, sizeof csi->stack);
  669.  
  670.         csi->xbalance = 0;
  671.         csi->in_text = 0;
  672.  
  673.         csi->path = fz_new_path();
  674.  
  675.         csi->text = NULL;
  676.         csi->tlm = fz_identity;
  677.         csi->tm = fz_identity;
  678.         csi->text_mode = 0;
  679.         csi->accumulate = 1;
  680.  
  681.         csi->top_ctm = ctm;
  682.         pdf_init_gstate(&csi->gstate[0], ctm);
  683.         csi->gtop = 0;
  684.  
  685.         return csi;
  686. }
  687.  
  688. static void
  689. pdf_clear_stack(pdf_csi *csi)
  690. {
  691.         int i;
  692.  
  693.         if (csi->obj)
  694.                 fz_drop_obj(csi->obj);
  695.         csi->obj = NULL;
  696.  
  697.         csi->name[0] = 0;
  698.         csi->string_len = 0;
  699.         for (i = 0; i < csi->top; i++)
  700.                 csi->stack[i] = 0;
  701.  
  702.         csi->top = 0;
  703. }
  704.  
  705. static pdf_material *
  706. pdf_keep_material(pdf_material *mat)
  707. {
  708.         if (mat->colorspace)
  709.                 fz_keep_colorspace(mat->colorspace);
  710.         if (mat->pattern)
  711.                 pdf_keep_pattern(mat->pattern);
  712.         if (mat->shade)
  713.                 fz_keep_shade(mat->shade);
  714.         return mat;
  715. }
  716.  
  717. static pdf_material *
  718. pdf_drop_material(pdf_material *mat)
  719. {
  720.         if (mat->colorspace)
  721.                 fz_drop_colorspace(mat->colorspace);
  722.         if (mat->pattern)
  723.                 pdf_drop_pattern(mat->pattern);
  724.         if (mat->shade)
  725.                 fz_drop_shade(mat->shade);
  726.         return mat;
  727. }
  728.  
  729. static void
  730. pdf_gsave(pdf_csi *csi)
  731. {
  732.         pdf_gstate *gs = csi->gstate + csi->gtop;
  733.  
  734.         if (csi->gtop == nelem(csi->gstate) - 1)
  735.         {
  736.                 fz_warn("gstate overflow in content stream");
  737.                 return;
  738.         }
  739.  
  740.         memcpy(&csi->gstate[csi->gtop + 1], &csi->gstate[csi->gtop], sizeof(pdf_gstate));
  741.  
  742.         csi->gtop ++;
  743.  
  744.         pdf_keep_material(&gs->stroke);
  745.         pdf_keep_material(&gs->fill);
  746.         if (gs->font)
  747.                 pdf_keep_font(gs->font);
  748.         if (gs->softmask)
  749.                 pdf_keep_xobject(gs->softmask);
  750. }
  751.  
  752. static void
  753. pdf_grestore(pdf_csi *csi)
  754. {
  755.         pdf_gstate *gs = csi->gstate + csi->gtop;
  756.         int clip_depth = gs->clip_depth;
  757.  
  758.         if (csi->gtop == 0)
  759.         {
  760.                 fz_warn("gstate underflow in content stream");
  761.                 return;
  762.         }
  763.  
  764.         pdf_drop_material(&gs->stroke);
  765.         pdf_drop_material(&gs->fill);
  766.         if (gs->font)
  767.                 pdf_drop_font(gs->font);
  768.         if (gs->softmask)
  769.                 pdf_drop_xobject(gs->softmask);
  770.  
  771.         csi->gtop --;
  772.  
  773.         gs = csi->gstate + csi->gtop;
  774.         while (clip_depth > gs->clip_depth)
  775.         {
  776.                 fz_pop_clip(csi->dev);
  777.                 clip_depth--;
  778.         }
  779. }
  780.  
  781. static void
  782. pdf_free_csi(pdf_csi *csi)
  783. {
  784.         while (csi->gtop)
  785.                 pdf_grestore(csi);
  786.  
  787.         pdf_drop_material(&csi->gstate[0].fill);
  788.         pdf_drop_material(&csi->gstate[0].stroke);
  789.         if (csi->gstate[0].font)
  790.                 pdf_drop_font(csi->gstate[0].font);
  791.         if (csi->gstate[0].softmask)
  792.                 pdf_drop_xobject(csi->gstate[0].softmask);
  793.  
  794.         while (csi->gstate[0].clip_depth--)
  795.                 fz_pop_clip(csi->dev);
  796.  
  797.         if (csi->path) fz_free_path(csi->path);
  798.         if (csi->text) fz_free_text(csi->text);
  799.  
  800.         pdf_clear_stack(csi);
  801.  
  802.         fz_free(csi);
  803. }
  804.  
  805. /*
  806.  * Material state
  807.  */
  808.  
  809. static void
  810. pdf_set_colorspace(pdf_csi *csi, int what, fz_colorspace *colorspace)
  811. {
  812.         pdf_gstate *gs = csi->gstate + csi->gtop;
  813.         pdf_material *mat;
  814.  
  815.         pdf_flush_text(csi);
  816.  
  817.         mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
  818.  
  819.         fz_drop_colorspace(mat->colorspace);
  820.  
  821.         mat->kind = PDF_MAT_COLOR;
  822.         mat->colorspace = fz_keep_colorspace(colorspace);
  823.  
  824.         mat->v[0] = 0;
  825.         mat->v[1] = 0;
  826.         mat->v[2] = 0;
  827.         mat->v[3] = 1;
  828. }
  829.  
  830. static void
  831. pdf_set_color(pdf_csi *csi, int what, float *v)
  832. {
  833.         pdf_gstate *gs = csi->gstate + csi->gtop;
  834.         pdf_material *mat;
  835.         int i;
  836.  
  837.         pdf_flush_text(csi);
  838.  
  839.         mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
  840.  
  841.         switch (mat->kind)
  842.         {
  843.         case PDF_MAT_PATTERN:
  844.         case PDF_MAT_COLOR:
  845.                 if (!strcmp(mat->colorspace->name, "Lab"))
  846.                 {
  847.                         mat->v[0] = v[0] / 100;
  848.                         mat->v[1] = (v[1] + 100) / 200;
  849.                         mat->v[2] = (v[2] + 100) / 200;
  850.                 }
  851.                 for (i = 0; i < mat->colorspace->n; i++)
  852.                         mat->v[i] = v[i];
  853.                 break;
  854.         default:
  855.                 fz_warn("color incompatible with material");
  856.         }
  857. }
  858.  
  859. static void
  860. pdf_set_shade(pdf_csi *csi, int what, fz_shade *shade)
  861. {
  862.         pdf_gstate *gs = csi->gstate + csi->gtop;
  863.         pdf_material *mat;
  864.  
  865.         pdf_flush_text(csi);
  866.  
  867.         mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
  868.  
  869.         if (mat->shade)
  870.                 fz_drop_shade(mat->shade);
  871.  
  872.         mat->kind = PDF_MAT_SHADE;
  873.         mat->shade = fz_keep_shade(shade);
  874. }
  875.  
  876. static void
  877. pdf_set_pattern(pdf_csi *csi, int what, pdf_pattern *pat, float *v)
  878. {
  879.         pdf_gstate *gs = csi->gstate + csi->gtop;
  880.         pdf_material *mat;
  881.  
  882.         pdf_flush_text(csi);
  883.  
  884.         mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
  885.  
  886.         if (mat->pattern)
  887.                 pdf_drop_pattern(mat->pattern);
  888.  
  889.         mat->kind = PDF_MAT_PATTERN;
  890.         if (pat)
  891.                 mat->pattern = pdf_keep_pattern(pat);
  892.         else
  893.                 mat->pattern = NULL;
  894.  
  895.         if (v)
  896.                 pdf_set_color(csi, what, v);
  897. }
  898.  
  899. static void
  900. pdf_unset_pattern(pdf_csi *csi, int what)
  901. {
  902.         pdf_gstate *gs = csi->gstate + csi->gtop;
  903.         pdf_material *mat;
  904.         mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
  905.         if (mat->kind == PDF_MAT_PATTERN)
  906.         {
  907.                 if (mat->pattern)
  908.                         pdf_drop_pattern(mat->pattern);
  909.                 mat->pattern = NULL;
  910.                 mat->kind = PDF_MAT_COLOR;
  911.         }
  912. }
  913.  
  914. /*
  915.  * Patterns, XObjects and ExtGState
  916.  */
  917.  
  918. static void
  919. pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what)
  920. {
  921.         pdf_gstate *gstate;
  922.         fz_matrix ptm, invptm;
  923.         fz_matrix oldtopctm;
  924.         fz_error error;
  925.         int x0, y0, x1, y1;
  926.         int oldtop;
  927.  
  928.         pdf_gsave(csi);
  929.         gstate = csi->gstate + csi->gtop;
  930.  
  931.         if (pat->ismask)
  932.         {
  933.                 pdf_unset_pattern(csi, PDF_FILL);
  934.                 pdf_unset_pattern(csi, PDF_STROKE);
  935.                 if (what == PDF_FILL)
  936.                 {
  937.                         pdf_drop_material(&gstate->stroke);
  938.                         pdf_keep_material(&gstate->fill);
  939.                         gstate->stroke = gstate->fill;
  940.                 }
  941.                 if (what == PDF_STROKE)
  942.                 {
  943.                         pdf_drop_material(&gstate->fill);
  944.                         pdf_keep_material(&gstate->stroke);
  945.                         gstate->fill = gstate->stroke;
  946.                 }
  947.         }
  948.         else
  949.         {
  950.                 // TODO: unset only the current fill/stroke or both?
  951.                 pdf_unset_pattern(csi, what);
  952.         }
  953.  
  954.         /* don't apply softmasks to objects in the pattern as well */
  955.         if (gstate->softmask)
  956.         {
  957.                 pdf_drop_xobject(gstate->softmask);
  958.                 gstate->softmask = NULL;
  959.         }
  960.  
  961.         ptm = fz_concat(pat->matrix, csi->top_ctm);
  962.         invptm = fz_invert_matrix(ptm);
  963.  
  964.         /* patterns are painted using the ctm in effect at the beginning of the content stream */
  965.         /* get bbox of shape in pattern space for stamping */
  966.         area = fz_transform_rect(invptm, area);
  967.         x0 = floorf(area.x0 / pat->xstep);
  968.         y0 = floorf(area.y0 / pat->ystep);
  969.         x1 = ceilf(area.x1 / pat->xstep);
  970.         y1 = ceilf(area.y1 / pat->ystep);
  971.  
  972.         oldtopctm = csi->top_ctm;
  973.         oldtop = csi->gtop;
  974.  
  975. #ifdef TILE
  976.         if ((x1 - x0) * (y1 - y0) > 0)
  977.         {
  978.                 fz_begin_tile(csi->dev, area, pat->bbox, pat->xstep, pat->ystep, ptm);
  979.                 gstate->ctm = ptm;
  980.                 csi->top_ctm = gstate->ctm;
  981.                 pdf_gsave(csi);
  982.                 error = pdf_run_buffer(csi, pat->resources, pat->contents);
  983.                 if (error)
  984.                         fz_catch(error, "cannot render pattern tile");
  985.                 pdf_grestore(csi);
  986.                 while (oldtop < csi->gtop)
  987.                         pdf_grestore(csi);
  988.                 fz_end_tile(csi->dev);
  989.         }
  990. #else
  991.         {
  992.                 int x, y;
  993.                 for (y = y0; y < y1; y++)
  994.                 {
  995.                         for (x = x0; x < x1; x++)
  996.                         {
  997.                                 gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm);
  998.                                 csi->top_ctm = gstate->ctm;
  999.                                 error = pdf_run_csi_buffer(csi, pat->resources, pat->contents);
  1000.                                 while (oldtop < csi->gtop)
  1001.                                         pdf_grestore(csi);
  1002.                                 if (error)
  1003.                                 {
  1004.                                         fz_catch(error, "cannot render pattern tile");
  1005.                                         goto cleanup;
  1006.                                 }
  1007.                         }
  1008.                 }
  1009.         }
  1010. cleanup:
  1011. #endif
  1012.  
  1013.         csi->top_ctm = oldtopctm;
  1014.  
  1015.         pdf_grestore(csi);
  1016. }
  1017.  
  1018. static fz_error
  1019. pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform)
  1020. {
  1021.         fz_error error;
  1022.         pdf_gstate *gstate;
  1023.         fz_matrix oldtopctm;
  1024.         int oldtop;
  1025.         int popmask;
  1026.  
  1027.         pdf_gsave(csi);
  1028.  
  1029.         gstate = csi->gstate + csi->gtop;
  1030.         oldtop = csi->gtop;
  1031.         popmask = 0;
  1032.  
  1033.         /* apply xobject's transform matrix */
  1034.         transform = fz_concat(xobj->matrix, transform);
  1035.         gstate->ctm = fz_concat(transform, gstate->ctm);
  1036.  
  1037.         /* apply soft mask, create transparency group and reset state */
  1038.         if (xobj->transparency)
  1039.         {
  1040.                 if (gstate->softmask)
  1041.                 {
  1042.                         pdf_xobject *softmask = gstate->softmask;
  1043.                         fz_rect bbox = fz_transform_rect(gstate->ctm, xobj->bbox);
  1044.  
  1045.                         gstate->softmask = NULL;
  1046.                         popmask = 1;
  1047.  
  1048.                         fz_begin_mask(csi->dev, bbox, gstate->luminosity,
  1049.                                 softmask->colorspace, gstate->softmask_bc);
  1050.                         error = pdf_run_xobject(csi, resources, softmask, fz_identity);
  1051.                         if (error)
  1052.                                 return fz_rethrow(error, "cannot run softmask");
  1053.                         fz_end_mask(csi->dev);
  1054.  
  1055.                         pdf_drop_xobject(softmask);
  1056.                 }
  1057.  
  1058.                 fz_begin_group(csi->dev,
  1059.                         fz_transform_rect(gstate->ctm, xobj->bbox),
  1060.                         xobj->isolated, xobj->knockout, gstate->blendmode, gstate->fill.alpha);
  1061.  
  1062.                 gstate->blendmode = 0;
  1063.                 gstate->stroke.alpha = 1;
  1064.                 gstate->fill.alpha = 1;
  1065.         }
  1066.  
  1067.         /* clip to the bounds */
  1068.  
  1069.         fz_moveto(csi->path, xobj->bbox.x0, xobj->bbox.y0);
  1070.         fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y0);
  1071.         fz_lineto(csi->path, xobj->bbox.x1, xobj->bbox.y1);
  1072.         fz_lineto(csi->path, xobj->bbox.x0, xobj->bbox.y1);
  1073.         fz_closepath(csi->path);
  1074.         pdf_show_clip(csi, 0);
  1075.         pdf_show_path(csi, 0, 0, 0, 0);
  1076.  
  1077.         /* run contents */
  1078.  
  1079.         oldtopctm = csi->top_ctm;
  1080.         csi->top_ctm = gstate->ctm;
  1081.  
  1082.         if (xobj->resources)
  1083.                 resources = xobj->resources;
  1084.  
  1085.         error = pdf_run_buffer(csi, resources, xobj->contents);
  1086.         if (error)
  1087.                 fz_catch(error, "cannot interpret XObject stream");
  1088.  
  1089.         csi->top_ctm = oldtopctm;
  1090.  
  1091.         while (oldtop < csi->gtop)
  1092.                 pdf_grestore(csi);
  1093.  
  1094.         pdf_grestore(csi);
  1095.  
  1096.         /* wrap up transparency stacks */
  1097.  
  1098.         if (xobj->transparency)
  1099.         {
  1100.                 fz_end_group(csi->dev);
  1101.                 if (popmask)
  1102.                         fz_pop_clip(csi->dev);
  1103.         }
  1104.  
  1105.         return fz_okay;
  1106. }
  1107.  
  1108. static fz_error
  1109. pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate)
  1110. {
  1111.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1112.         fz_colorspace *colorspace;
  1113.         int i, k;
  1114.  
  1115.         pdf_flush_text(csi);
  1116.  
  1117.         for (i = 0; i < fz_dict_len(extgstate); i++)
  1118.         {
  1119.                 fz_obj *key = fz_dict_get_key(extgstate, i);
  1120.                 fz_obj *val = fz_dict_get_val(extgstate, i);
  1121.                 char *s = fz_to_name(key);
  1122.  
  1123.                 if (!strcmp(s, "Font"))
  1124.                 {
  1125.                         if (fz_is_array(val) && fz_array_len(val) == 2)
  1126.                         {
  1127.                                 fz_error error;
  1128.                                 fz_obj *font = fz_array_get(val, 0);
  1129.  
  1130.                                 if (gstate->font)
  1131.                                 {
  1132.                                         pdf_drop_font(gstate->font);
  1133.                                         gstate->font = NULL;
  1134.                                 }
  1135.  
  1136.                                 error = pdf_load_font(&gstate->font, csi->xref, rdb, font);
  1137.                                 if (error)
  1138.                                         return fz_rethrow(error, "cannot load font (%d %d R)", fz_to_num(font), fz_to_gen(font));
  1139.                                 if (!gstate->font)
  1140.                                         return fz_throw("cannot find font in store");
  1141.                                 gstate->size = fz_to_real(fz_array_get(val, 1));
  1142.                         }
  1143.                         else
  1144.                                 return fz_throw("malformed /Font dictionary");
  1145.                 }
  1146.  
  1147.                 else if (!strcmp(s, "LC"))
  1148.                 {
  1149.                         gstate->stroke_state.start_cap = fz_to_int(val);
  1150.                         gstate->stroke_state.dash_cap = fz_to_int(val);
  1151.                         gstate->stroke_state.end_cap = fz_to_int(val);
  1152.                 }
  1153.                 else if (!strcmp(s, "LW"))
  1154.                         gstate->stroke_state.linewidth = fz_to_real(val);
  1155.                 else if (!strcmp(s, "LJ"))
  1156.                         gstate->stroke_state.linejoin = fz_to_int(val);
  1157.                 else if (!strcmp(s, "ML"))
  1158.                         gstate->stroke_state.miterlimit = fz_to_real(val);
  1159.  
  1160.                 else if (!strcmp(s, "D"))
  1161.                 {
  1162.                         if (fz_is_array(val) && fz_array_len(val) == 2)
  1163.                         {
  1164.                                 fz_obj *dashes = fz_array_get(val, 0);
  1165.                                 gstate->stroke_state.dash_len = MAX(fz_array_len(dashes), 32);
  1166.                                 for (k = 0; k < gstate->stroke_state.dash_len; k++)
  1167.                                         gstate->stroke_state.dash_list[k] = fz_to_real(fz_array_get(dashes, k));
  1168.                                 gstate->stroke_state.dash_phase = fz_to_real(fz_array_get(val, 1));
  1169.                         }
  1170.                         else
  1171.                                 return fz_throw("malformed /D");
  1172.                 }
  1173.  
  1174.                 else if (!strcmp(s, "CA"))
  1175.                         gstate->stroke.alpha = fz_to_real(val);
  1176.  
  1177.                 else if (!strcmp(s, "ca"))
  1178.                         gstate->fill.alpha = fz_to_real(val);
  1179.  
  1180.                 else if (!strcmp(s, "BM"))
  1181.                 {
  1182.                         if (fz_is_array(val))
  1183.                                 val = fz_array_get(val, 0);
  1184.                         gstate->blendmode = fz_find_blendmode(fz_to_name(val));
  1185.                 }
  1186.  
  1187.                 else if (!strcmp(s, "SMask"))
  1188.                 {
  1189.                         if (fz_is_dict(val))
  1190.                         {
  1191.                                 fz_error error;
  1192.                                 pdf_xobject *xobj;
  1193.                                 fz_obj *group, *luminosity, *bc;
  1194.  
  1195.                                 if (gstate->softmask)
  1196.                                 {
  1197.                                         pdf_drop_xobject(gstate->softmask);
  1198.                                         gstate->softmask = NULL;
  1199.                                 }
  1200.  
  1201.                                 group = fz_dict_gets(val, "G");
  1202.                                 if (!group)
  1203.                                         return fz_throw("cannot load softmask xobject (%d %d R)", fz_to_num(val), fz_to_gen(val));
  1204.                                 error = pdf_load_xobject(&xobj, csi->xref, group);
  1205.                                 if (error)
  1206.                                         return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_to_num(val), fz_to_gen(val));
  1207.  
  1208.                                 colorspace = xobj->colorspace;
  1209.                                 if (!colorspace)
  1210.                                         colorspace = fz_device_gray;
  1211.  
  1212.                                 gstate->softmask_ctm = fz_concat(xobj->matrix, gstate->ctm);
  1213.                                 gstate->softmask = xobj;
  1214.                                 for (k = 0; k < colorspace->n; k++)
  1215.                                         gstate->softmask_bc[k] = 0;
  1216.  
  1217.                                 bc = fz_dict_gets(val, "BC");
  1218.                                 if (fz_is_array(bc))
  1219.                                 {
  1220.                                         for (k = 0; k < colorspace->n; k++)
  1221.                                                 gstate->softmask_bc[k] = fz_to_real(fz_array_get(bc, k));
  1222.                                 }
  1223.  
  1224.                                 luminosity = fz_dict_gets(val, "S");
  1225.                                 if (fz_is_name(luminosity) && !strcmp(fz_to_name(luminosity), "Luminosity"))
  1226.                                         gstate->luminosity = 1;
  1227.                                 else
  1228.                                         gstate->luminosity = 0;
  1229.                         }
  1230.                         else if (fz_is_name(val) && !strcmp(fz_to_name(val), "None"))
  1231.                         {
  1232.                                 if (gstate->softmask)
  1233.                                 {
  1234.                                         pdf_drop_xobject(gstate->softmask);
  1235.                                         gstate->softmask = NULL;
  1236.                                 }
  1237.                         }
  1238.                 }
  1239.  
  1240.                 else if (!strcmp(s, "TR"))
  1241.                 {
  1242.                         if (fz_is_name(val) && strcmp(fz_to_name(val), "Identity"))
  1243.                                 fz_warn("ignoring transfer function");
  1244.                 }
  1245.         }
  1246.  
  1247.         return fz_okay;
  1248. }
  1249.  
  1250. /*
  1251.  * Operators
  1252.  */
  1253.  
  1254. static void pdf_run_BDC(pdf_csi *csi)
  1255. {
  1256. }
  1257.  
  1258. static fz_error pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file)
  1259. {
  1260.         int ch;
  1261.         fz_error error;
  1262.         char *buf = csi->xref->scratch;
  1263.         int buflen = sizeof(csi->xref->scratch);
  1264.         fz_pixmap *img;
  1265.         fz_obj *obj;
  1266.  
  1267.         error = pdf_parse_dict(&obj, csi->xref, file, buf, buflen);
  1268.         if (error)
  1269.                 return fz_rethrow(error, "cannot parse inline image dictionary");
  1270.  
  1271.         /* read whitespace after ID keyword */
  1272.         ch = fz_read_byte(file);
  1273.         if (ch == '\r')
  1274.                 if (fz_peek_byte(file) == '\n')
  1275.                         fz_read_byte(file);
  1276.  
  1277.         error = pdf_load_inline_image(&img, csi->xref, rdb, obj, file);
  1278.         fz_drop_obj(obj);
  1279.         if (error)
  1280.                 return fz_rethrow(error, "cannot load inline image");
  1281.  
  1282.         pdf_show_image(csi, img);
  1283.  
  1284.         fz_drop_pixmap(img);
  1285.  
  1286.         /* find EI */
  1287.         ch = fz_read_byte(file);
  1288.         while (ch != 'E' && ch != EOF)
  1289.                 ch = fz_read_byte(file);
  1290.         ch = fz_read_byte(file);
  1291.         if (ch != 'I')
  1292.                 return fz_rethrow(error, "syntax error after inline image");
  1293.  
  1294.         return fz_okay;
  1295. }
  1296.  
  1297. static void pdf_run_B(pdf_csi *csi)
  1298. {
  1299.         pdf_show_path(csi, 0, 1, 1, 0);
  1300. }
  1301.  
  1302. static void pdf_run_BMC(pdf_csi *csi)
  1303. {
  1304. }
  1305.  
  1306. static void pdf_run_BT(pdf_csi *csi)
  1307. {
  1308.         csi->in_text = 1;
  1309.         csi->tm = fz_identity;
  1310.         csi->tlm = fz_identity;
  1311. }
  1312.  
  1313. static void pdf_run_BX(pdf_csi *csi)
  1314. {
  1315.         csi->xbalance ++;
  1316. }
  1317.  
  1318. static void pdf_run_Bstar(pdf_csi *csi)
  1319. {
  1320.         pdf_show_path(csi, 0, 1, 1, 1);
  1321. }
  1322.  
  1323. static fz_error pdf_run_cs_imp(pdf_csi *csi, fz_obj *rdb, int what)
  1324. {
  1325.         fz_colorspace *colorspace;
  1326.         fz_obj *obj, *dict;
  1327.         fz_error error;
  1328.  
  1329.         if (!strcmp(csi->name, "Pattern"))
  1330.         {
  1331.                 pdf_set_pattern(csi, what, NULL, NULL);
  1332.         }
  1333.         else
  1334.         {
  1335.                 if (!strcmp(csi->name, "DeviceGray"))
  1336.                         colorspace = fz_keep_colorspace(fz_device_gray);
  1337.                 else if (!strcmp(csi->name, "DeviceRGB"))
  1338.                         colorspace = fz_keep_colorspace(fz_device_rgb);
  1339.                 else if (!strcmp(csi->name, "DeviceCMYK"))
  1340.                         colorspace = fz_keep_colorspace(fz_device_cmyk);
  1341.                 else
  1342.                 {
  1343.                         dict = fz_dict_gets(rdb, "ColorSpace");
  1344.                         if (!dict)
  1345.                                 return fz_throw("cannot find ColorSpace dictionary");
  1346.                         obj = fz_dict_gets(dict, csi->name);
  1347.                         if (!obj)
  1348.                                 return fz_throw("cannot find colorspace resource '%s'", csi->name);
  1349.                         error = pdf_load_colorspace(&colorspace, csi->xref, obj);
  1350.                         if (error)
  1351.                                 return fz_rethrow(error, "cannot load colorspace (%d 0 R)", fz_to_num(obj));
  1352.                 }
  1353.  
  1354.                 pdf_set_colorspace(csi, what, colorspace);
  1355.  
  1356.                 fz_drop_colorspace(colorspace);
  1357.         }
  1358.         return fz_okay;
  1359. }
  1360.  
  1361. static void pdf_run_CS(pdf_csi *csi, fz_obj *rdb)
  1362. {
  1363.         fz_error error;
  1364.         error = pdf_run_cs_imp(csi, rdb, PDF_STROKE);
  1365.         if (error)
  1366.                 fz_catch(error, "cannot set colorspace");
  1367. }
  1368.  
  1369. static void pdf_run_cs(pdf_csi *csi, fz_obj *rdb)
  1370. {
  1371.         fz_error error;
  1372.         error = pdf_run_cs_imp(csi, rdb, PDF_FILL);
  1373.         if (error)
  1374.                 fz_catch(error, "cannot set colorspace");
  1375. }
  1376.  
  1377. static void pdf_run_DP(pdf_csi *csi)
  1378. {
  1379. }
  1380.  
  1381. static fz_error pdf_run_Do(pdf_csi *csi, fz_obj *rdb)
  1382. {
  1383.         fz_obj *dict;
  1384.         fz_obj *obj;
  1385.         fz_obj *subtype;
  1386.         fz_error error;
  1387.  
  1388.         dict = fz_dict_gets(rdb, "XObject");
  1389.         if (!dict)
  1390.                 return fz_throw("cannot find XObject dictionary when looking for: '%s'", csi->name);
  1391.  
  1392.         obj = fz_dict_gets(dict, csi->name);
  1393.         if (!obj)
  1394.                 return fz_throw("cannot find xobject resource: '%s'", csi->name);
  1395.  
  1396.         subtype = fz_dict_gets(obj, "Subtype");
  1397.         if (!fz_is_name(subtype))
  1398.                 return fz_throw("no XObject subtype specified");
  1399.  
  1400.         if (pdf_is_hidden_ocg(obj, csi->target))
  1401.                 return fz_okay;
  1402.  
  1403.         if (!strcmp(fz_to_name(subtype), "Form") && fz_dict_gets(obj, "Subtype2"))
  1404.                 subtype = fz_dict_gets(obj, "Subtype2");
  1405.  
  1406.         if (!strcmp(fz_to_name(subtype), "Form"))
  1407.         {
  1408.                 pdf_xobject *xobj;
  1409.  
  1410.                 error = pdf_load_xobject(&xobj, csi->xref, obj);
  1411.                 if (error)
  1412.                         return fz_rethrow(error, "cannot load xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
  1413.  
  1414.                 /* Inherit parent resources, in case this one was empty XXX check where it's loaded */
  1415.                 if (!xobj->resources)
  1416.                         xobj->resources = fz_keep_obj(rdb);
  1417.  
  1418.                 error = pdf_run_xobject(csi, xobj->resources, xobj, fz_identity);
  1419.                 if (error)
  1420.                         return fz_rethrow(error, "cannot draw xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
  1421.  
  1422.                 pdf_drop_xobject(xobj);
  1423.         }
  1424.  
  1425.         else if (!strcmp(fz_to_name(subtype), "Image"))
  1426.         {
  1427.                 if ((csi->dev->hints & FZ_IGNORE_IMAGE) == 0)
  1428.                 {
  1429.                         fz_pixmap *img;
  1430.                         error = pdf_load_image(&img, csi->xref, obj);
  1431.                         if (error)
  1432.                                 return fz_rethrow(error, "cannot load image (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
  1433.                         pdf_show_image(csi, img);
  1434.                         fz_drop_pixmap(img);
  1435.                 }
  1436.         }
  1437.  
  1438.         else if (!strcmp(fz_to_name(subtype), "PS"))
  1439.         {
  1440.                 fz_warn("ignoring XObject with subtype PS");
  1441.         }
  1442.  
  1443.         else
  1444.         {
  1445.                 return fz_throw("unknown XObject subtype: '%s'", fz_to_name(subtype));
  1446.         }
  1447.  
  1448.         return fz_okay;
  1449. }
  1450.  
  1451. static void pdf_run_EMC(pdf_csi *csi)
  1452. {
  1453. }
  1454.  
  1455. static void pdf_run_ET(pdf_csi *csi)
  1456. {
  1457.         pdf_flush_text(csi);
  1458.         csi->accumulate = 1;
  1459.         csi->in_text = 0;
  1460. }
  1461.  
  1462. static void pdf_run_EX(pdf_csi *csi)
  1463. {
  1464.         csi->xbalance --;
  1465. }
  1466.  
  1467. static void pdf_run_F(pdf_csi *csi)
  1468. {
  1469.         pdf_show_path(csi, 0, 1, 0, 0);
  1470. }
  1471.  
  1472. static void pdf_run_G(pdf_csi *csi)
  1473. {
  1474.         pdf_set_colorspace(csi, PDF_STROKE, fz_device_gray);
  1475.         pdf_set_color(csi, PDF_STROKE, csi->stack);
  1476. }
  1477.  
  1478. static void pdf_run_J(pdf_csi *csi)
  1479. {
  1480.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1481.         gstate->stroke_state.start_cap = csi->stack[0];
  1482.         gstate->stroke_state.dash_cap = csi->stack[0];
  1483.         gstate->stroke_state.end_cap = csi->stack[0];
  1484. }
  1485.  
  1486. static void pdf_run_K(pdf_csi *csi)
  1487. {
  1488.         pdf_set_colorspace(csi, PDF_STROKE, fz_device_cmyk);
  1489.         pdf_set_color(csi, PDF_STROKE, csi->stack);
  1490. }
  1491.  
  1492. static void pdf_run_M(pdf_csi *csi)
  1493. {
  1494.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1495.         gstate->stroke_state.miterlimit = csi->stack[0];
  1496. }
  1497.  
  1498. static void pdf_run_MP(pdf_csi *csi)
  1499. {
  1500. }
  1501.  
  1502. static void pdf_run_Q(pdf_csi *csi)
  1503. {
  1504.         pdf_grestore(csi);
  1505. }
  1506.  
  1507. static void pdf_run_RG(pdf_csi *csi)
  1508. {
  1509.         pdf_set_colorspace(csi, PDF_STROKE, fz_device_rgb);
  1510.         pdf_set_color(csi, PDF_STROKE, csi->stack);
  1511. }
  1512.  
  1513. static void pdf_run_S(pdf_csi *csi)
  1514. {
  1515.         pdf_show_path(csi, 0, 0, 1, 0);
  1516. }
  1517.  
  1518. static fz_error pdf_run_SC_imp(pdf_csi *csi, fz_obj *rdb, int what, pdf_material *mat)
  1519. {
  1520.         fz_error error;
  1521.         fz_obj *patterntype;
  1522.         fz_obj *dict;
  1523.         fz_obj *obj;
  1524.         int kind;
  1525.  
  1526.         kind = mat->kind;
  1527.         if (csi->name[0])
  1528.                 kind = PDF_MAT_PATTERN;
  1529.  
  1530.         switch (kind)
  1531.         {
  1532.         case PDF_MAT_NONE:
  1533.                 return fz_throw("cannot set color in mask objects");
  1534.  
  1535.         case PDF_MAT_COLOR:
  1536.                 pdf_set_color(csi, what, csi->stack);
  1537.                 break;
  1538.  
  1539.         case PDF_MAT_PATTERN:
  1540.                 dict = fz_dict_gets(rdb, "Pattern");
  1541.                 if (!dict)
  1542.                         return fz_throw("cannot find Pattern dictionary");
  1543.  
  1544.                 obj = fz_dict_gets(dict, csi->name);
  1545.                 if (!obj)
  1546.                         return fz_throw("cannot find pattern resource '%s'", csi->name);
  1547.  
  1548.                 patterntype = fz_dict_gets(obj, "PatternType");
  1549.  
  1550.                 if (fz_to_int(patterntype) == 1)
  1551.                 {
  1552.                         pdf_pattern *pat;
  1553.                         error = pdf_load_pattern(&pat, csi->xref, obj);
  1554.                         if (error)
  1555.                                 return fz_rethrow(error, "cannot load pattern (%d 0 R)", fz_to_num(obj));
  1556.                         pdf_set_pattern(csi, what, pat, csi->top > 0 ? csi->stack : NULL);
  1557.                         pdf_drop_pattern(pat);
  1558.                 }
  1559.                 else if (fz_to_int(patterntype) == 2)
  1560.                 {
  1561.                         fz_shade *shd;
  1562.                         error = pdf_load_shading(&shd, csi->xref, obj);
  1563.                         if (error)
  1564.                                 return fz_rethrow(error, "cannot load shading (%d 0 R)", fz_to_num(obj));
  1565.                         pdf_set_shade(csi, what, shd);
  1566.                         fz_drop_shade(shd);
  1567.                 }
  1568.                 else
  1569.                 {
  1570.                         return fz_throw("unknown pattern type: %d", fz_to_int(patterntype));
  1571.                 }
  1572.                 break;
  1573.  
  1574.         case PDF_MAT_SHADE:
  1575.                 return fz_throw("cannot set color in shade objects");
  1576.         }
  1577.  
  1578.         return fz_okay;
  1579. }
  1580.  
  1581. static void pdf_run_SC(pdf_csi *csi, fz_obj *rdb)
  1582. {
  1583.         fz_error error;
  1584.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1585.         error = pdf_run_SC_imp(csi, rdb, PDF_STROKE, &gstate->stroke);
  1586.         if (error)
  1587.                 fz_catch(error, "cannot set color and colorspace");
  1588. }
  1589.  
  1590. static void pdf_run_sc(pdf_csi *csi, fz_obj *rdb)
  1591. {
  1592.         fz_error error;
  1593.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1594.         error = pdf_run_SC_imp(csi, rdb, PDF_FILL, &gstate->fill);
  1595.         if (error)
  1596.                 fz_catch(error, "cannot set color and colorspace");
  1597. }
  1598.  
  1599. static void pdf_run_Tc(pdf_csi *csi)
  1600. {
  1601.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1602.         gstate->char_space = csi->stack[0];
  1603. }
  1604.  
  1605. static void pdf_run_Tw(pdf_csi *csi)
  1606. {
  1607.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1608.         gstate->word_space = csi->stack[0];
  1609. }
  1610.  
  1611. static void pdf_run_Tz(pdf_csi *csi)
  1612. {
  1613.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1614.         float a = csi->stack[0] / 100;
  1615.         pdf_flush_text(csi);
  1616.         gstate->scale = a;
  1617. }
  1618.  
  1619. static void pdf_run_TL(pdf_csi *csi)
  1620. {
  1621.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1622.         gstate->leading = csi->stack[0];
  1623. }
  1624.  
  1625. static fz_error pdf_run_Tf(pdf_csi *csi, fz_obj *rdb)
  1626. {
  1627.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1628.         fz_error error;
  1629.         fz_obj *dict;
  1630.         fz_obj *obj;
  1631.  
  1632.         gstate->size = csi->stack[0];
  1633.         if (gstate->font)
  1634.                 pdf_drop_font(gstate->font);
  1635.         gstate->font = NULL;
  1636.  
  1637.         dict = fz_dict_gets(rdb, "Font");
  1638.         if (!dict)
  1639.                 return fz_throw("cannot find Font dictionary");
  1640.  
  1641.         obj = fz_dict_gets(dict, csi->name);
  1642.         if (!obj)
  1643.                 return fz_throw("cannot find font resource: '%s'", csi->name);
  1644.  
  1645.         error = pdf_load_font(&gstate->font, csi->xref, rdb, obj);
  1646.         if (error)
  1647.                 return fz_rethrow(error, "cannot load font (%d 0 R)", fz_to_num(obj));
  1648.  
  1649.         return fz_okay;
  1650. }
  1651.  
  1652. static void pdf_run_Tr(pdf_csi *csi)
  1653. {
  1654.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1655.         gstate->render = csi->stack[0];
  1656. }
  1657.  
  1658. static void pdf_run_Ts(pdf_csi *csi)
  1659. {
  1660.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1661.         gstate->rise = csi->stack[0];
  1662. }
  1663.  
  1664. static void pdf_run_Td(pdf_csi *csi)
  1665. {
  1666.         fz_matrix m = fz_translate(csi->stack[0], csi->stack[1]);
  1667.         csi->tlm = fz_concat(m, csi->tlm);
  1668.         csi->tm = csi->tlm;
  1669. }
  1670.  
  1671. static void pdf_run_TD(pdf_csi *csi)
  1672. {
  1673.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1674.         fz_matrix m;
  1675.  
  1676.         gstate->leading = -csi->stack[1];
  1677.         m = fz_translate(csi->stack[0], csi->stack[1]);
  1678.         csi->tlm = fz_concat(m, csi->tlm);
  1679.         csi->tm = csi->tlm;
  1680. }
  1681.  
  1682. static void pdf_run_Tm(pdf_csi *csi)
  1683. {
  1684.         csi->tm.a = csi->stack[0];
  1685.         csi->tm.b = csi->stack[1];
  1686.         csi->tm.c = csi->stack[2];
  1687.         csi->tm.d = csi->stack[3];
  1688.         csi->tm.e = csi->stack[4];
  1689.         csi->tm.f = csi->stack[5];
  1690.         csi->tlm = csi->tm;
  1691. }
  1692.  
  1693. static void pdf_run_Tstar(pdf_csi *csi)
  1694. {
  1695.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1696.         fz_matrix m = fz_translate(0, -gstate->leading);
  1697.         csi->tlm = fz_concat(m, csi->tlm);
  1698.         csi->tm = csi->tlm;
  1699. }
  1700.  
  1701. static void pdf_run_Tj(pdf_csi *csi)
  1702. {
  1703.         if (csi->string_len)
  1704.                 pdf_show_string(csi, csi->string, csi->string_len);
  1705.         else
  1706.                 pdf_show_text(csi, csi->obj);
  1707. }
  1708.  
  1709. static void pdf_run_TJ(pdf_csi *csi)
  1710. {
  1711.         if (csi->string_len)
  1712.                 pdf_show_string(csi, csi->string, csi->string_len);
  1713.         else
  1714.                 pdf_show_text(csi, csi->obj);
  1715. }
  1716.  
  1717. static void pdf_run_W(pdf_csi *csi)
  1718. {
  1719.         pdf_show_clip(csi, 0);
  1720. }
  1721.  
  1722. static void pdf_run_Wstar(pdf_csi *csi)
  1723. {
  1724.         pdf_show_clip(csi, 1);
  1725. }
  1726.  
  1727. static void pdf_run_b(pdf_csi *csi)
  1728. {
  1729.         pdf_show_path(csi, 1, 1, 1, 0);
  1730. }
  1731.  
  1732. static void pdf_run_bstar(pdf_csi *csi)
  1733. {
  1734.         pdf_show_path(csi, 1, 1, 1, 1);
  1735. }
  1736.  
  1737. static void pdf_run_c(pdf_csi *csi)
  1738. {
  1739.         float a, b, c, d, e, f;
  1740.         a = csi->stack[0];
  1741.         b = csi->stack[1];
  1742.         c = csi->stack[2];
  1743.         d = csi->stack[3];
  1744.         e = csi->stack[4];
  1745.         f = csi->stack[5];
  1746.         fz_curveto(csi->path, a, b, c, d, e, f);
  1747. }
  1748.  
  1749. static void pdf_run_cm(pdf_csi *csi)
  1750. {
  1751.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1752.         fz_matrix m;
  1753.  
  1754.         m.a = csi->stack[0];
  1755.         m.b = csi->stack[1];
  1756.         m.c = csi->stack[2];
  1757.         m.d = csi->stack[3];
  1758.         m.e = csi->stack[4];
  1759.         m.f = csi->stack[5];
  1760.  
  1761.         gstate->ctm = fz_concat(m, gstate->ctm);
  1762. }
  1763.  
  1764. static void pdf_run_d(pdf_csi *csi)
  1765. {
  1766.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1767.         fz_obj *array;
  1768.         int i;
  1769.  
  1770.         array = csi->obj;
  1771.         gstate->stroke_state.dash_len = MIN(fz_array_len(array), nelem(gstate->stroke_state.dash_list));
  1772.         for (i = 0; i < gstate->stroke_state.dash_len; i++)
  1773.                 gstate->stroke_state.dash_list[i] = fz_to_real(fz_array_get(array, i));
  1774.         gstate->stroke_state.dash_phase = csi->stack[0];
  1775. }
  1776.  
  1777. static void pdf_run_d0(pdf_csi *csi)
  1778. {
  1779.         csi->dev->flags |= FZ_CHARPROC_COLOR;
  1780. }
  1781.  
  1782. static void pdf_run_d1(pdf_csi *csi)
  1783. {
  1784.         csi->dev->flags |= FZ_CHARPROC_MASK;
  1785. }
  1786.  
  1787. static void pdf_run_f(pdf_csi *csi)
  1788. {
  1789.         pdf_show_path(csi, 0, 1, 0, 0);
  1790. }
  1791.  
  1792. static void pdf_run_fstar(pdf_csi *csi)
  1793. {
  1794.         pdf_show_path(csi, 0, 1, 0, 1);
  1795. }
  1796.  
  1797. static void pdf_run_g(pdf_csi *csi)
  1798. {
  1799.         pdf_set_colorspace(csi, PDF_FILL, fz_device_gray);
  1800.         pdf_set_color(csi, PDF_FILL, csi->stack);
  1801. }
  1802.  
  1803. static fz_error pdf_run_gs(pdf_csi *csi, fz_obj *rdb)
  1804. {
  1805.         fz_error error;
  1806.         fz_obj *dict;
  1807.         fz_obj *obj;
  1808.  
  1809.         dict = fz_dict_gets(rdb, "ExtGState");
  1810.         if (!dict)
  1811.                 return fz_throw("cannot find ExtGState dictionary");
  1812.  
  1813.         obj = fz_dict_gets(dict, csi->name);
  1814.         if (!obj)
  1815.                 return fz_throw("cannot find extgstate resource '%s'", csi->name);
  1816.  
  1817.         error = pdf_run_extgstate(csi, rdb, obj);
  1818.         if (error)
  1819.                 return fz_rethrow(error, "cannot set ExtGState (%d 0 R)", fz_to_num(obj));
  1820.         return fz_okay;
  1821. }
  1822.  
  1823. static void pdf_run_h(pdf_csi *csi)
  1824. {
  1825.         fz_closepath(csi->path);
  1826. }
  1827.  
  1828. static void pdf_run_i(pdf_csi *csi)
  1829. {
  1830. }
  1831.  
  1832. static void pdf_run_j(pdf_csi *csi)
  1833. {
  1834.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1835.         gstate->stroke_state.linejoin = csi->stack[0];
  1836. }
  1837.  
  1838. static void pdf_run_k(pdf_csi *csi)
  1839. {
  1840.         pdf_set_colorspace(csi, PDF_FILL, fz_device_cmyk);
  1841.         pdf_set_color(csi, PDF_FILL, csi->stack);
  1842. }
  1843.  
  1844. static void pdf_run_l(pdf_csi *csi)
  1845. {
  1846.         float a, b;
  1847.         a = csi->stack[0];
  1848.         b = csi->stack[1];
  1849.         fz_lineto(csi->path, a, b);
  1850. }
  1851.  
  1852. static void pdf_run_m(pdf_csi *csi)
  1853. {
  1854.         float a, b;
  1855.         a = csi->stack[0];
  1856.         b = csi->stack[1];
  1857.         fz_moveto(csi->path, a, b);
  1858. }
  1859.  
  1860. static void pdf_run_n(pdf_csi *csi)
  1861. {
  1862.         pdf_show_path(csi, 0, 0, 0, 0);
  1863. }
  1864.  
  1865. static void pdf_run_q(pdf_csi *csi)
  1866. {
  1867.         pdf_gsave(csi);
  1868. }
  1869.  
  1870. static void pdf_run_re(pdf_csi *csi)
  1871. {
  1872.         float x, y, w, h;
  1873.  
  1874.         x = csi->stack[0];
  1875.         y = csi->stack[1];
  1876.         w = csi->stack[2];
  1877.         h = csi->stack[3];
  1878.  
  1879.         fz_moveto(csi->path, x, y);
  1880.         fz_lineto(csi->path, x + w, y);
  1881.         fz_lineto(csi->path, x + w, y + h);
  1882.         fz_lineto(csi->path, x, y + h);
  1883.         fz_closepath(csi->path);
  1884. }
  1885.  
  1886. static void pdf_run_rg(pdf_csi *csi)
  1887. {
  1888.         pdf_set_colorspace(csi, PDF_FILL, fz_device_rgb);
  1889.         pdf_set_color(csi, PDF_FILL, csi->stack);
  1890. }
  1891.  
  1892. static void pdf_run_ri(pdf_csi *csi)
  1893. {
  1894. }
  1895.  
  1896. static void pdf_run(pdf_csi *csi)
  1897. {
  1898.         pdf_show_path(csi, 1, 0, 1, 0);
  1899. }
  1900.  
  1901. static fz_error pdf_run_sh(pdf_csi *csi, fz_obj *rdb)
  1902. {
  1903.         fz_obj *dict;
  1904.         fz_obj *obj;
  1905.         fz_shade *shd;
  1906.         fz_error error;
  1907.  
  1908.         dict = fz_dict_gets(rdb, "Shading");
  1909.         if (!dict)
  1910.                 return fz_throw("cannot find shading dictionary");
  1911.  
  1912.         obj = fz_dict_gets(dict, csi->name);
  1913.         if (!obj)
  1914.                 return fz_throw("cannot find shading resource: '%s'", csi->name);
  1915.  
  1916.         if ((csi->dev->hints & FZ_IGNORE_SHADE) == 0)
  1917.         {
  1918.                 error = pdf_load_shading(&shd, csi->xref, obj);
  1919.                 if (error)
  1920.                         return fz_rethrow(error, "cannot load shading (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
  1921.                 pdf_show_shade(csi, shd);
  1922.                 fz_drop_shade(shd);
  1923.         }
  1924.         return fz_okay;
  1925. }
  1926.  
  1927. static void pdf_run_v(pdf_csi *csi)
  1928. {
  1929.         float a, b, c, d;
  1930.         a = csi->stack[0];
  1931.         b = csi->stack[1];
  1932.         c = csi->stack[2];
  1933.         d = csi->stack[3];
  1934.         fz_curvetov(csi->path, a, b, c, d);
  1935. }
  1936.  
  1937. static void pdf_run_w(pdf_csi *csi)
  1938. {
  1939.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1940.         pdf_flush_text(csi); /* linewidth affects stroked text rendering mode */
  1941.         gstate->stroke_state.linewidth = csi->stack[0];
  1942. }
  1943.  
  1944. static void pdf_run_y(pdf_csi *csi)
  1945. {
  1946.         float a, b, c, d;
  1947.         a = csi->stack[0];
  1948.         b = csi->stack[1];
  1949.         c = csi->stack[2];
  1950.         d = csi->stack[3];
  1951.         fz_curvetoy(csi->path, a, b, c, d);
  1952. }
  1953.  
  1954. static void pdf_run_squote(pdf_csi *csi)
  1955. {
  1956.         fz_matrix m;
  1957.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1958.  
  1959.         m = fz_translate(0, -gstate->leading);
  1960.         csi->tlm = fz_concat(m, csi->tlm);
  1961.         csi->tm = csi->tlm;
  1962.  
  1963.         if (csi->string_len)
  1964.                 pdf_show_string(csi, csi->string, csi->string_len);
  1965.         else
  1966.                 pdf_show_text(csi, csi->obj);
  1967. }
  1968.  
  1969. static void pdf_run_dquote(pdf_csi *csi)
  1970. {
  1971.         fz_matrix m;
  1972.         pdf_gstate *gstate = csi->gstate + csi->gtop;
  1973.  
  1974.         gstate->word_space = csi->stack[0];
  1975.         gstate->char_space = csi->stack[1];
  1976.  
  1977.         m = fz_translate(0, -gstate->leading);
  1978.         csi->tlm = fz_concat(m, csi->tlm);
  1979.         csi->tm = csi->tlm;
  1980.  
  1981.         if (csi->string_len)
  1982.                 pdf_show_string(csi, csi->string, csi->string_len);
  1983.         else
  1984.                 pdf_show_text(csi, csi->obj);
  1985. }
  1986.  
  1987. #define A(a) (a)
  1988. #define B(a,b) (a | b << 8)
  1989. #define C(a,b,c) (a | b << 8 | c << 16)
  1990.  
  1991. static fz_error
  1992. pdf_run_keyword(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf)
  1993. {
  1994.         fz_error error;
  1995.         int key;
  1996.  
  1997.         key = buf[0];
  1998.         if (buf[1])
  1999.         {
  2000.                 key |= buf[1] << 8;
  2001.                 if (buf[2])
  2002.                 {
  2003.                         key |= buf[2] << 16;
  2004.                         if (buf[3])
  2005.                                 key = 0;
  2006.                 }
  2007.         }
  2008.  
  2009.         switch (key)
  2010.         {
  2011.         case A('"'): pdf_run_dquote(csi); break;
  2012.         case A('\''): pdf_run_squote(csi); break;
  2013.         case A('B'): pdf_run_B(csi); break;
  2014.         case B('B','*'): pdf_run_Bstar(csi); break;
  2015.         case C('B','D','C'): pdf_run_BDC(csi); break;
  2016.         case B('B','I'):
  2017.                 error = pdf_run_BI(csi, rdb, file);
  2018.                 if (error)
  2019.                         return fz_rethrow(error, "cannot draw inline image");
  2020.                 break;
  2021.         case C('B','M','C'): pdf_run_BMC(csi); break;
  2022.         case B('B','T'): pdf_run_BT(csi); break;
  2023.         case B('B','X'): pdf_run_BX(csi); break;
  2024.         case B('C','S'): pdf_run_CS(csi, rdb); break;
  2025.         case B('D','P'): pdf_run_DP(csi); break;
  2026.         case B('D','o'):
  2027.                 error = pdf_run_Do(csi, rdb);
  2028.                 if (error)
  2029.                         fz_catch(error, "cannot draw xobject/image");
  2030.                 break;
  2031.         case C('E','M','C'): pdf_run_EMC(csi); break;
  2032.         case B('E','T'): pdf_run_ET(csi); break;
  2033.         case B('E','X'): pdf_run_EX(csi); break;
  2034.         case A('F'): pdf_run_F(csi); break;
  2035.         case A('G'): pdf_run_G(csi); break;
  2036.         case A('J'): pdf_run_J(csi); break;
  2037.         case A('K'): pdf_run_K(csi); break;
  2038.         case A('M'): pdf_run_M(csi); break;
  2039.         case B('M','P'): pdf_run_MP(csi); break;
  2040.         case A('Q'): pdf_run_Q(csi); break;
  2041.         case B('R','G'): pdf_run_RG(csi); break;
  2042.         case A('S'): pdf_run_S(csi); break;
  2043.         case B('S','C'): pdf_run_SC(csi, rdb); break;
  2044.         case C('S','C','N'): pdf_run_SC(csi, rdb); break;
  2045.         case B('T','*'): pdf_run_Tstar(csi); break;
  2046.         case B('T','D'): pdf_run_TD(csi); break;
  2047.         case B('T','J'): pdf_run_TJ(csi); break;
  2048.         case B('T','L'): pdf_run_TL(csi); break;
  2049.         case B('T','c'): pdf_run_Tc(csi); break;
  2050.         case B('T','d'): pdf_run_Td(csi); break;
  2051.         case B('T','f'):
  2052.                 error = pdf_run_Tf(csi, rdb);
  2053.                 if (error)
  2054.                         fz_catch(error, "cannot set font");
  2055.                 break;
  2056.         case B('T','j'): pdf_run_Tj(csi); break;
  2057.         case B('T','m'): pdf_run_Tm(csi); break;
  2058.         case B('T','r'): pdf_run_Tr(csi); break;
  2059.         case B('T','s'): pdf_run_Ts(csi); break;
  2060.         case B('T','w'): pdf_run_Tw(csi); break;
  2061.         case B('T','z'): pdf_run_Tz(csi); break;
  2062.         case A('W'): pdf_run_W(csi); break;
  2063.         case B('W','*'): pdf_run_Wstar(csi); break;
  2064.         case A('b'): pdf_run_b(csi); break;
  2065.         case B('b','*'): pdf_run_bstar(csi); break;
  2066.         case A('c'): pdf_run_c(csi); break;
  2067.         case B('c','m'): pdf_run_cm(csi); break;
  2068.         case B('c','s'): pdf_run_cs(csi, rdb); break;
  2069.         case A('d'): pdf_run_d(csi); break;
  2070.         case B('d','0'): pdf_run_d0(csi); break;
  2071.         case B('d','1'): pdf_run_d1(csi); break;
  2072.         case A('f'): pdf_run_f(csi); break;
  2073.         case B('f','*'): pdf_run_fstar(csi); break;
  2074.         case A('g'): pdf_run_g(csi); break;
  2075.         case B('g','s'):
  2076.                 error = pdf_run_gs(csi, rdb);
  2077.                 if (error)
  2078.                         fz_catch(error, "cannot set graphics state");
  2079.                 break;
  2080.         case A('h'): pdf_run_h(csi); break;
  2081.         case A('i'): pdf_run_i(csi); break;
  2082.         case A('j'): pdf_run_j(csi); break;
  2083.         case A('k'): pdf_run_k(csi); break;
  2084.         case A('l'): pdf_run_l(csi); break;
  2085.         case A('m'): pdf_run_m(csi); break;
  2086.         case A('n'): pdf_run_n(csi); break;
  2087.         case A('q'): pdf_run_q(csi); break;
  2088.         case B('r','e'): pdf_run_re(csi); break;
  2089.         case B('r','g'): pdf_run_rg(csi); break;
  2090.         case B('r','i'): pdf_run_ri(csi); break;
  2091.         case A('s'): pdf_run(csi); break;
  2092.         case B('s','c'): pdf_run_sc(csi, rdb); break;
  2093.         case C('s','c','n'): pdf_run_sc(csi, rdb); break;
  2094.         case B('s','h'):
  2095.                 error = pdf_run_sh(csi, rdb);
  2096.                 if (error)
  2097.                         fz_catch(error, "cannot draw shading");
  2098.                 break;
  2099.         case A('v'): pdf_run_v(csi); break;
  2100.         case A('w'): pdf_run_w(csi); break;
  2101.         case A('y'): pdf_run_y(csi); break;
  2102.         default:
  2103.                 if (!csi->xbalance)
  2104.                         fz_warn("unknown keyword: '%s'", buf);
  2105.                 break;
  2106.         }
  2107.  
  2108.         return fz_okay;
  2109. }
  2110.  
  2111. static fz_error
  2112. pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen)
  2113. {
  2114.         fz_error error;
  2115.         int tok, len, in_array;
  2116.  
  2117.         /* make sure we have a clean slate if we come here from flush_text */
  2118.         pdf_clear_stack(csi);
  2119.         in_array = 0;
  2120.  
  2121.         while (1)
  2122.         {
  2123.                 if (csi->top == nelem(csi->stack) - 1)
  2124.                         return fz_throw("stack overflow");
  2125.  
  2126.                 error = pdf_lex(&tok, file, buf, buflen, &len);
  2127.                 if (error)
  2128.                         return fz_rethrow(error, "lexical error in content stream");
  2129.  
  2130.                 if (in_array)
  2131.                 {
  2132.                         if (tok == PDF_TOK_CLOSE_ARRAY)
  2133.                         {
  2134.                                 in_array = 0;
  2135.                         }
  2136.                         else if (tok == PDF_TOK_INT || tok == PDF_TOK_REAL)
  2137.                         {
  2138.                                 pdf_gstate *gstate = csi->gstate + csi->gtop;
  2139.                                 pdf_show_space(csi, -fz_atof(buf) * gstate->size * 0.001f);
  2140.                         }
  2141.                         else if (tok == PDF_TOK_STRING)
  2142.                         {
  2143.                                 pdf_show_string(csi, (unsigned char *)buf, len);
  2144.                         }
  2145.                         else if (tok == PDF_TOK_KEYWORD)
  2146.                         {
  2147.                                 if (!strcmp(buf, "Tw") || !strcmp(buf, "Tc"))
  2148.                                         fz_warn("ignoring keyword '%s' inside array", buf);
  2149.                                 else
  2150.                                         return fz_throw("syntax error in array");
  2151.                         }
  2152.                         else if (tok == PDF_TOK_EOF)
  2153.                                 return fz_okay;
  2154.                         else
  2155.                                 return fz_throw("syntax error in array");
  2156.                 }
  2157.  
  2158.                 else switch (tok)
  2159.                 {
  2160.                 case PDF_TOK_ENDSTREAM:
  2161.                 case PDF_TOK_EOF:
  2162.                         return fz_okay;
  2163.  
  2164.                 case PDF_TOK_OPEN_ARRAY:
  2165.                         if (!csi->in_text)
  2166.                         {
  2167.                                 error = pdf_parse_array(&csi->obj, csi->xref, file, buf, buflen);
  2168.                                 if (error)
  2169.                                         return fz_rethrow(error, "cannot parse array");
  2170.                         }
  2171.                         else
  2172.                         {
  2173.                                 in_array = 1;
  2174.                         }
  2175.                         break;
  2176.  
  2177.                 case PDF_TOK_OPEN_DICT:
  2178.                         error = pdf_parse_dict(&csi->obj, csi->xref, file, buf, buflen);
  2179.                         if (error)
  2180.                                 return fz_rethrow(error, "cannot parse dictionary");
  2181.                         break;
  2182.  
  2183.                 case PDF_TOK_NAME:
  2184.                         fz_strlcpy(csi->name, buf, sizeof(csi->name));
  2185.                         break;
  2186.  
  2187.                 case PDF_TOK_INT:
  2188.                         csi->stack[csi->top] = atoi(buf);
  2189.                         csi->top ++;
  2190.                         break;
  2191.  
  2192.                 case PDF_TOK_REAL:
  2193.                         csi->stack[csi->top] = fz_atof(buf);
  2194.                         csi->top ++;
  2195.                         break;
  2196.  
  2197.                 case PDF_TOK_STRING:
  2198.                         if (len <= sizeof(csi->string))
  2199.                         {
  2200.                                 memcpy(csi->string, buf, len);
  2201.                                 csi->string_len = len;
  2202.                         }
  2203.                         else
  2204.                         {
  2205.                                 csi->obj = fz_new_string(buf, len);
  2206.                         }
  2207.                         break;
  2208.  
  2209.                 case PDF_TOK_KEYWORD:
  2210.                         error = pdf_run_keyword(csi, rdb, file, buf);
  2211.                         if (error)
  2212.                                 return fz_rethrow(error, "cannot run keyword");
  2213.                         pdf_clear_stack(csi);
  2214.                         break;
  2215.  
  2216.                 default:
  2217.                         return fz_throw("syntax error in content stream");
  2218.                 }
  2219.         }
  2220. }
  2221.  
  2222. /*
  2223.  * Entry points
  2224.  */
  2225.  
  2226. static fz_error
  2227. pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents)
  2228. {
  2229.         fz_error error;
  2230.         int len = sizeof csi->xref->scratch;
  2231.         char *buf = fz_malloc(len); /* we must be re-entrant for type3 fonts */
  2232.         fz_stream *file = fz_open_buffer(contents);
  2233.         int save_in_text = csi->in_text;
  2234.         csi->in_text = 0;
  2235.         error = pdf_run_stream(csi, rdb, file, buf, len);
  2236.         csi->in_text = save_in_text;
  2237.         fz_close(file);
  2238.         fz_free(buf);
  2239.         if (error)
  2240.                 return fz_rethrow(error, "cannot parse content stream");
  2241.         return fz_okay;
  2242. }
  2243.  
  2244. fz_error
  2245. pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *target)
  2246. {
  2247.         pdf_csi *csi;
  2248.         fz_error error;
  2249.         pdf_annot *annot;
  2250.         int flags;
  2251.  
  2252.         if (page->transparency)
  2253.                 fz_begin_group(dev, fz_transform_rect(ctm, page->mediabox), 1, 0, 0, 1);
  2254.  
  2255.         csi = pdf_new_csi(xref, dev, ctm, target);
  2256.         error = pdf_run_buffer(csi, page->resources, page->contents);
  2257.         pdf_free_csi(csi);
  2258.         if (error)
  2259.                 return fz_rethrow(error, "cannot parse page content stream");
  2260.  
  2261.         for (annot = page->annots; annot; annot = annot->next)
  2262.         {
  2263.                 flags = fz_to_int(fz_dict_gets(annot->obj, "F"));
  2264.  
  2265.                 /* TODO: NoZoom and NoRotate */
  2266.                 if (flags & (1 << 0)) /* Invisible */
  2267.                         continue;
  2268.                 if (flags & (1 << 1)) /* Hidden */
  2269.                         continue;
  2270.                 if (flags & (1 << 5)) /* NoView */
  2271.                         continue;
  2272.  
  2273.                 if (pdf_is_hidden_ocg(annot->obj, target))
  2274.                         continue;
  2275.  
  2276.                 csi = pdf_new_csi(xref, dev, ctm, target);
  2277.                 error = pdf_run_xobject(csi, page->resources, annot->ap, annot->matrix);
  2278.                 pdf_free_csi(csi);
  2279.                 if (error)
  2280.                         return fz_rethrow(error, "cannot parse annotation appearance stream");
  2281.         }
  2282.  
  2283.         if (page->transparency)
  2284.                 fz_end_group(dev);
  2285.  
  2286.         return fz_okay;
  2287. }
  2288.  
  2289. fz_error
  2290. pdf_run_page(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm)
  2291. {
  2292.         return pdf_run_page_with_usage(xref, page, dev, ctm, "View");
  2293. }
  2294.  
  2295. fz_error
  2296. pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm)
  2297. {
  2298.         pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View");
  2299.         fz_error error = pdf_run_buffer(csi, resources, contents);
  2300.         pdf_free_csi(csi);
  2301.         if (error)
  2302.                 return fz_rethrow(error, "cannot parse glyph content stream");
  2303.         return fz_okay;
  2304. }
  2305.