diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2015-02-26 15:16:34 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2015-03-24 13:42:44 +0000 |
commit | e0f638b398b2362f5843ea0c1907f678cfa8e278 (patch) | |
tree | 0f771d162c7f2c18f18bb12c8be86cdca06aaaeb /source | |
parent | 4b3c02180d49403a4e477e494ed233ac2c672bd8 (diff) | |
download | mupdf-e0f638b398b2362f5843ea0c1907f678cfa8e278.tar.xz |
Don't pass interpreter context to pdf_processor opcode callbacks.
Update buffer and filter processors.
Filter both colors and stroke states.
Move OCG hiding logic into interpreter.
Diffstat (limited to 'source')
-rw-r--r-- | source/fitz/draw-blend.c | 2 | ||||
-rw-r--r-- | source/fitz/list-device.c | 2 | ||||
-rw-r--r-- | source/html/css-parse.c | 2 | ||||
-rw-r--r-- | source/pdf/pdf-clean.c | 74 | ||||
-rw-r--r-- | source/pdf/pdf-interpret-imp.h | 158 | ||||
-rw-r--r-- | source/pdf/pdf-interpret.c | 1314 | ||||
-rw-r--r-- | source/pdf/pdf-object.c | 4 | ||||
-rw-r--r-- | source/pdf/pdf-op-buffer.c | 1166 | ||||
-rw-r--r-- | source/pdf/pdf-op-filter.c | 1625 | ||||
-rw-r--r-- | source/pdf/pdf-op-run.c | 2006 | ||||
-rw-r--r-- | source/pdf/pdf-pattern.c | 38 | ||||
-rw-r--r-- | source/pdf/pdf-run.c | 37 | ||||
-rw-r--r-- | source/pdf/pdf-stream.c | 3 | ||||
-rw-r--r-- | source/pdf/pdf-write.c | 2 | ||||
-rw-r--r-- | source/pdf/pdf-xobject.c | 2 |
15 files changed, 3089 insertions, 3346 deletions
diff --git a/source/fitz/draw-blend.c b/source/fitz/draw-blend.c index 62666fc5..ea5d30bc 100644 --- a/source/fitz/draw-blend.c +++ b/source/fitz/draw-blend.c @@ -25,7 +25,7 @@ static const char *fz_blendmode_names[] = "Luminosity", }; -int fz_lookup_blendmode(char *name) +int fz_lookup_blendmode(const char *name) { int i; for (i = 0; i < nelem(fz_blendmode_names); i++) diff --git a/source/fitz/list-device.c b/source/fitz/list-device.c index fc2bb3f8..738499b1 100644 --- a/source/fitz/list-device.c +++ b/source/fitz/list-device.c @@ -954,7 +954,7 @@ fz_list_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_ma &rect, NULL, /* path */ NULL, /* color */ - NULL, /* colorspace */ + NULL, /* colorspace */ &alpha, /* alpha */ ctm, NULL, /* stroke */ diff --git a/source/html/css-parse.c b/source/html/css-parse.c index e3ddd48f..91958a98 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -414,7 +414,7 @@ restart: { buf->color = (a << 20) | (b << 12) | (c << 4); } - sprintf(buf->string, "%06x", buf->color); // XXX + sprintf(buf->string, "%06x", buf->color); return CSS_COLOR; colorerror: fz_css_error(buf, "invalid color"); diff --git a/source/pdf/pdf-clean.c b/source/pdf/pdf-clean.c index 4bdaae7b..399d9339 100644 --- a/source/pdf/pdf-clean.c +++ b/source/pdf/pdf-clean.c @@ -1,18 +1,21 @@ -#include "pdf-interpret-imp.h" +#include "mupdf/pdf.h" static void pdf_clean_stream_object(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_obj *orig_res, fz_cookie *cookie, int own_res) { - pdf_process process, process2; - fz_buffer *buffer; + pdf_processor *proc_buffer = NULL; + pdf_processor *proc_filter = NULL; pdf_obj *res = NULL; pdf_obj *ref = NULL; + fz_buffer *buffer; if (!obj) return; fz_var(res); fz_var(ref); + fz_var(proc_buffer); + fz_var(proc_filter); buffer = fz_new_buffer(ctx, 1024); @@ -27,10 +30,10 @@ pdf_clean_stream_object(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_ob res = pdf_new_dict(ctx, doc, 1); - pdf_init_process_buffer(ctx, &process2, buffer); - pdf_init_process_filter(ctx, &process, &process2, res); + proc_buffer = pdf_new_buffer_processor(ctx, buffer); + proc_filter = pdf_new_filter_processor(ctx, proc_buffer, doc, orig_res, res); - pdf_process_stream_object(ctx, doc, obj, &process, orig_res, cookie); + pdf_process_contents(ctx, proc_filter, doc, orig_res, obj, cookie); pdf_update_stream(ctx, doc, obj, buffer, 0); @@ -42,6 +45,8 @@ pdf_clean_stream_object(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_ob } fz_always(ctx) { + pdf_drop_processor(ctx, proc_filter); + pdf_drop_processor(ctx, proc_buffer); fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, res); pdf_drop_obj(ctx, ref); @@ -55,15 +60,17 @@ pdf_clean_stream_object(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_ob static void pdf_clean_type3(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_obj *orig_res, fz_cookie *cookie) { - pdf_process process, process2; - fz_buffer *buffer; - int i, l; + pdf_processor *proc_buffer = NULL; + pdf_processor *proc_filter = NULL; pdf_obj *res = NULL; pdf_obj *ref = NULL; pdf_obj *charprocs; + int i, l; fz_var(res); fz_var(ref); + fz_var(proc_buffer); + fz_var(proc_filter); fz_try(ctx) { @@ -79,19 +86,27 @@ pdf_clean_type3(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_obj *orig_ for (i = 0; i < l; i++) { - pdf_obj *key = pdf_dict_get_key(ctx, charprocs, i); pdf_obj *val = pdf_dict_get_val(ctx, charprocs, i); + fz_buffer *buffer = fz_new_buffer(ctx, 1024); + fz_try(ctx) + { + proc_buffer = pdf_new_buffer_processor(ctx, buffer); + proc_filter = pdf_new_filter_processor(ctx, proc_buffer, doc, orig_res, res); - buffer = fz_new_buffer(ctx, 1024); - pdf_init_process_buffer(ctx, &process2, buffer); - pdf_init_process_filter(ctx, &process, &process2, res); - - pdf_process_stream_object(ctx, doc, val, &process, orig_res, cookie); + pdf_process_contents(ctx, proc_filter, doc, orig_res, val, cookie); - pdf_update_stream(ctx, doc, val, buffer, 0); - pdf_dict_put(ctx, charprocs, key, val); - fz_drop_buffer(ctx, buffer); - buffer = NULL; + pdf_update_stream(ctx, doc, val, buffer, 0); + } + fz_always(ctx) + { + pdf_drop_processor(ctx, proc_filter); + pdf_drop_processor(ctx, proc_buffer); + fz_drop_buffer(ctx, buffer); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } } /* ProcSet - no cleaning possible. Inherit this from the old dict. */ @@ -102,7 +117,6 @@ pdf_clean_type3(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_obj *orig_ } fz_always(ctx) { - fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, res); pdf_drop_obj(ctx, ref); } @@ -114,28 +128,33 @@ pdf_clean_type3(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_obj *orig_ void pdf_clean_page_contents(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_cookie *cookie, pdf_page_contents_process_fn *proc_fn, void *proc_arg) { - pdf_process process, process2; - fz_buffer *buffer = fz_new_buffer(ctx, 1024); - pdf_obj *contents; + pdf_processor *proc_buffer = NULL; + pdf_processor *proc_filter = NULL; pdf_obj *new_obj = NULL; pdf_obj *new_ref = NULL; pdf_obj *res = NULL; pdf_obj *ref = NULL; pdf_obj *obj; + pdf_obj *contents; + fz_buffer *buffer; fz_var(new_obj); fz_var(new_ref); fz_var(res); fz_var(ref); + fz_var(proc_buffer); + fz_var(proc_filter); + + buffer = fz_new_buffer(ctx, 1024); fz_try(ctx) { res = pdf_new_dict(ctx, doc, 1); - pdf_init_process_buffer(ctx, &process2, buffer); - pdf_init_process_filter(ctx, &process, &process2, res); + proc_buffer = pdf_new_buffer_processor(ctx, buffer); + proc_filter = pdf_new_filter_processor(ctx, proc_buffer, doc, page->resources, res); - pdf_process_stream_object(ctx, doc, page->contents, &process, page->resources, cookie); + pdf_process_contents(ctx, proc_filter, doc, page->resources, page->contents, cookie); contents = page->contents; if (pdf_is_array(ctx, contents)) @@ -247,7 +266,6 @@ void pdf_clean_page_contents(fz_context *ctx, pdf_document *doc, pdf_page *page, (*proc_fn)(ctx, buffer, res, proc_arg); pdf_update_stream(ctx, doc, contents, buffer, 0); - pdf_drop_obj(ctx, page->resources); ref = pdf_new_ref(ctx, doc, res); page->resources = pdf_keep_obj(ctx, ref); @@ -255,6 +273,8 @@ void pdf_clean_page_contents(fz_context *ctx, pdf_document *doc, pdf_page *page, } fz_always(ctx) { + pdf_drop_processor(ctx, proc_filter); + pdf_drop_processor(ctx, proc_buffer); fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, new_obj); pdf_drop_obj(ctx, new_ref); diff --git a/source/pdf/pdf-interpret-imp.h b/source/pdf/pdf-interpret-imp.h deleted file mode 100644 index 9c72bfe2..00000000 --- a/source/pdf/pdf-interpret-imp.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef PDF_INTERPRET_IMP_H -#define PDF_INTERPRET_IMP_H - -#include "mupdf/pdf.h" - -typedef struct pdf_csi_s pdf_csi; -typedef struct pdf_gstate_s pdf_gstate; - -typedef void (*pdf_operator_fn)(pdf_csi *, void *user); -typedef void (*pdf_process_annot_fn)(pdf_csi *csi, void *user, pdf_obj *resources, pdf_annot *annot); -typedef void (*pdf_process_stream_fn)(pdf_csi *csi, void *user, pdf_lexbuf *buf); -typedef void (*pdf_process_contents_fn)(pdf_csi *csi, void *user, pdf_obj *resources, pdf_obj *contents); - -typedef enum { - /* The first section of op's all run without a try/catch */ - PDF_OP_dquote, - PDF_OP_squote, - PDF_OP_B, - PDF_OP_Bstar, - PDF_OP_BDC, - PDF_OP_BI, - PDF_OP_BMC, - PDF_OP_BT, - PDF_OP_BX, - PDF_OP_CS, - PDF_OP_DP, - PDF_OP_EMC, - PDF_OP_ET, - PDF_OP_EX, - PDF_OP_F, - PDF_OP_G, - PDF_OP_J, - PDF_OP_K, - PDF_OP_M, - PDF_OP_MP, - PDF_OP_Q, - PDF_OP_RG, - PDF_OP_S, - PDF_OP_SC, - PDF_OP_SCN, - PDF_OP_Tstar, - PDF_OP_TD, - PDF_OP_TJ, - PDF_OP_TL, - PDF_OP_Tc, - PDF_OP_Td, - PDF_OP_Tj, - PDF_OP_Tm, - PDF_OP_Tr, - PDF_OP_Ts, - PDF_OP_Tw, - PDF_OP_Tz, - PDF_OP_W, - PDF_OP_Wstar, - PDF_OP_b, - PDF_OP_bstar, - PDF_OP_c, - PDF_OP_cm, - PDF_OP_cs, - PDF_OP_d, - PDF_OP_d0, - PDF_OP_d1, - PDF_OP_f, - PDF_OP_fstar, - PDF_OP_g, - PDF_OP_h, - PDF_OP_i, - PDF_OP_j, - PDF_OP_k, - PDF_OP_l, - PDF_OP_m, - PDF_OP_n, - PDF_OP_q, - PDF_OP_re, - PDF_OP_rg, - PDF_OP_ri, - PDF_OP_s, - PDF_OP_sc, - PDF_OP_scn, - PDF_OP_v, - PDF_OP_w, - PDF_OP_y, - /* ops in this second section require additional try/catch handling */ - PDF_OP_Do, - PDF_OP_Tf, - PDF_OP_gs, - PDF_OP_sh, - /* END is used to signify end of stream (finalise and close down) */ - PDF_OP_END, - /* And finally we have a max */ - PDF_OP_MAX -} PDF_OP; - -typedef struct pdf_processor_s { - pdf_operator_fn op_table[PDF_OP_MAX]; - pdf_process_annot_fn process_annot; - pdf_process_stream_fn process_stream; - pdf_process_contents_fn process_contents; -} pdf_processor; - -typedef struct pdf_process_s -{ - const pdf_processor *processor; - void *state; -} pdf_process; - -struct pdf_csi_s -{ - fz_context *ctx; - pdf_document *doc; - - /* Current resource dict and file. These are in here to reduce param - * passing. */ - pdf_obj *rdb; - fz_stream *file; - - /* Operator table */ - pdf_process process; - - /* interpreter stack */ - pdf_obj *obj; - char name[256]; - unsigned char string[256]; - int string_len; - float stack[32]; - int top; - fz_image *img; - - int xbalance; - int in_text; - - fz_rect d1_rect; - - /* cookie support */ - fz_cookie *cookie; -}; - -static inline void pdf_process_op(pdf_csi *csi, int op, const pdf_process *process) -{ - process->processor->op_table[op](csi, process->state); -} - -/* Helper functions for the filter implementations to call */ -void pdf_process_contents_object(pdf_csi *csi, pdf_obj *rdb, pdf_obj *contents); -void pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf); - -/* Functions to set up pdf_process structures */ -pdf_process *pdf_init_process_run(fz_context *ctx, pdf_process *process, fz_device *dev, const fz_matrix *ctm, const char *event, pdf_gstate *gstate, int nested); -pdf_process *pdf_init_process_buffer(fz_context *ctx, pdf_process *process, fz_buffer *buffer); -pdf_process *pdf_init_process_filter(fz_context *ctx, pdf_process *process, pdf_process *underlying, pdf_obj *resources); - -/* Functions to actually use the pdf_process structures to process - * annotations, glyphs and general stream objects */ -void pdf_process_annot(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *annot, const pdf_process *process, fz_cookie *cookie); -void pdf_process_glyph(fz_context *ctx, pdf_document *doc, pdf_obj *resources, fz_buffer *contents, pdf_process *process); -void pdf_process_stream_object(fz_context *ctx, pdf_document *doc, pdf_obj *obj, const pdf_process *process, pdf_obj *res, fz_cookie *cookie); - -#endif diff --git a/source/pdf/pdf-interpret.c b/source/pdf/pdf-interpret.c index a3df4c77..0961b742 100644 --- a/source/pdf/pdf-interpret.c +++ b/source/pdf/pdf-interpret.c @@ -1,307 +1,997 @@ -#include "pdf-interpret-imp.h" +#include "mupdf/pdf.h" -static pdf_csi * -pdf_new_csi(fz_context *ctx, pdf_document *doc, fz_cookie *cookie, const pdf_process *process) +void * +pdf_new_processor(fz_context *ctx, int size) { - pdf_csi *csi = NULL; + return Memento_label(fz_calloc(ctx, 1, size), "pdf_processor"); +} + +void +pdf_drop_processor(fz_context *ctx, pdf_processor *proc) +{ + if (proc && proc->drop_imp) + proc->drop_imp(ctx, proc); + fz_free(ctx, proc); +} + +static void +pdf_init_csi(fz_context *ctx, pdf_csi *csi, pdf_document *doc, pdf_obj *rdb, pdf_lexbuf *buf, fz_cookie *cookie) +{ + memset(csi, 0, sizeof *csi); + csi->doc = doc; + csi->rdb = rdb; + csi->buf = buf; + csi->cookie = cookie; +} + +static void +pdf_clear_stack(fz_context *ctx, pdf_csi *csi) +{ + int i; + + pdf_drop_obj(ctx, csi->obj); + csi->obj = NULL; - fz_var(csi); + csi->name[0] = 0; + csi->string_len = 0; + for (i = 0; i < csi->top; i++) + csi->stack[i] = 0; + + csi->top = 0; +} + +static pdf_font_desc * +load_font_or_hail_mary(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *font, int depth, fz_cookie *cookie) +{ + pdf_font_desc *desc; fz_try(ctx) { - csi = fz_malloc_struct(ctx, pdf_csi); - csi->ctx = ctx; /* FIXME */ - csi->doc = doc; /* FIXME */ + desc = pdf_load_font(ctx, doc, rdb, font, depth); + } + fz_catch(ctx) + { + if (fz_caught(ctx) == FZ_ERROR_TRYLATER && cookie && cookie->incomplete_ok) + { + desc = NULL; + cookie->incomplete++; + } + else + { + fz_rethrow(ctx); + } + } + if (desc == NULL) + desc = pdf_load_hail_mary_font(ctx, doc); + return desc; +} - csi->in_text = 0; +static int +ocg_intents_include(fz_context *ctx, pdf_ocg_descriptor *desc, char *name) +{ + int i, len; - csi->top = 0; - csi->obj = NULL; - csi->name[0] = 0; - csi->string_len = 0; - memset(csi->stack, 0, sizeof csi->stack); + if (strcmp(name, "All") == 0) + return 1; - csi->process = *process; + /* In the absence of a specified intent, it's 'View' */ + if (!desc->intent) + return (strcmp(name, "View") == 0); - csi->xbalance = 0; - csi->cookie = cookie; + if (pdf_is_name(ctx, desc->intent)) + { + char *intent = pdf_to_name(ctx, desc->intent); + if (strcmp(intent, "All") == 0) + return 1; + return (strcmp(intent, name) == 0); } - fz_catch(ctx) + if (!pdf_is_array(ctx, desc->intent)) + return 0; + + len = pdf_array_len(ctx, desc->intent); + for (i=0; i < len; i++) { - pdf_process_op(csi, PDF_OP_END, process); - fz_free(ctx, csi); - fz_rethrow(ctx); + char *intent = pdf_to_name(ctx, pdf_array_get(ctx, desc->intent, i)); + if (strcmp(intent, "All") == 0) + return 1; + if (strcmp(intent, name) == 0) + return 1; + } + return 0; +} + +static int +pdf_is_hidden_ocg(fz_context *ctx, pdf_ocg_descriptor *desc, pdf_obj *rdb, const char *event, pdf_obj *ocg) +{ + char event_state[16]; + pdf_obj *obj, *obj2; + char *type; + + /* Avoid infinite recursions */ + if (pdf_obj_marked(ctx, ocg)) + return 0; + + /* If no event, everything is visible */ + if (!event) + return 0; + + /* If no ocg descriptor, everything is visible */ + if (!desc) + return 0; + + /* If we've been handed a name, look it up in the properties. */ + if (pdf_is_name(ctx, ocg)) + { + ocg = pdf_dict_gets(ctx, pdf_dict_gets(ctx, rdb, "Properties"), pdf_to_name(ctx, ocg)); + } + /* If we haven't been given an ocg at all, then we're visible */ + if (!ocg) + return 0; + + fz_strlcpy(event_state, event, sizeof event_state); + fz_strlcat(event_state, "State", sizeof event_state); + + type = pdf_to_name(ctx, pdf_dict_gets(ctx, ocg, "Type")); + + if (strcmp(type, "OCG") == 0) + { + /* An Optional Content Group */ + int default_value = 0; + int num = pdf_to_num(ctx, ocg); + int gen = pdf_to_gen(ctx, ocg); + int len = desc->len; + int i; + + /* by default an OCG is visible, unless it's explicitly hidden */ + for (i = 0; i < len; i++) + { + if (desc->ocgs[i].num == num && desc->ocgs[i].gen == gen) + { + default_value = desc->ocgs[i].state == 0; + break; + } + } + + /* Check Intents; if our intent is not part of the set given + * by the current config, we should ignore it. */ + obj = pdf_dict_gets(ctx, ocg, "Intent"); + if (pdf_is_name(ctx, obj)) + { + /* If it doesn't match, it's hidden */ + if (ocg_intents_include(ctx, desc, pdf_to_name(ctx, obj)) == 0) + return 1; + } + else if (pdf_is_array(ctx, obj)) + { + int match = 0; + len = pdf_array_len(ctx, obj); + for (i=0; i<len; i++) { + match |= ocg_intents_include(ctx, desc, pdf_to_name(ctx, pdf_array_get(ctx, obj, i))); + if (match) + break; + } + /* If we don't match any, it's hidden */ + if (match == 0) + return 1; + } + else + { + /* If it doesn't match, it's hidden */ + if (ocg_intents_include(ctx, desc, "View") == 0) + return 1; + } + + /* FIXME: Currently we do a very simple check whereby we look + * at the Usage object (an Optional Content Usage Dictionary) + * and check to see if the corresponding 'event' key is on + * or off. + * + * Really we should only look at Usage dictionaries that + * correspond to entries in the AS list in the OCG config. + * Given that we don't handle Zoom or User, or Language + * dicts, this is not really a problem. */ + obj = pdf_dict_gets(ctx, ocg, "Usage"); + if (!pdf_is_dict(ctx, obj)) + return default_value; + /* FIXME: Should look at Zoom (and return hidden if out of + * max/min range) */ + /* FIXME: Could provide hooks to the caller to check if + * User is appropriate - if not return hidden. */ + obj2 = pdf_dict_gets(ctx, obj, event); + if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, obj2, event_state)), "OFF") == 0) + { + return 1; + } + if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, obj2, event_state)), "ON") == 0) + { + return 0; + } + return default_value; } + else if (strcmp(type, "OCMD") == 0) + { + /* An Optional Content Membership Dictionary */ + char *name; + int combine, on; + + obj = pdf_dict_gets(ctx, ocg, "VE"); + if (pdf_is_array(ctx, obj)) { + /* FIXME: Calculate visibility from array */ + return 0; + } + name = pdf_to_name(ctx, pdf_dict_gets(ctx, ocg, "P")); + /* Set combine; Bit 0 set => AND, Bit 1 set => true means + * Off, otherwise true means On */ + if (strcmp(name, "AllOn") == 0) + { + combine = 1; + } + else if (strcmp(name, "AnyOff") == 0) + { + combine = 2; + } + else if (strcmp(name, "AllOff") == 0) + { + combine = 3; + } + else /* Assume it's the default (AnyOn) */ + { + combine = 0; + } - return csi; + if (pdf_mark_obj(ctx, ocg)) + return 0; /* Should never happen */ + fz_try(ctx) + { + obj = pdf_dict_gets(ctx, ocg, "OCGs"); + on = combine & 1; + if (pdf_is_array(ctx, obj)) { + int i, len; + len = pdf_array_len(ctx, obj); + for (i = 0; i < len; i++) + { + int hidden = pdf_is_hidden_ocg(ctx, desc, rdb, event, pdf_array_get(ctx, obj, i)); + if ((combine & 1) == 0) + hidden = !hidden; + if (combine & 2) + on &= hidden; + else + on |= hidden; + } + } + else + { + on = pdf_is_hidden_ocg(ctx, desc, rdb, event, obj); + if ((combine & 1) == 0) + on = !on; + } + } + fz_always(ctx) + { + pdf_unmark_obj(ctx, ocg); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + return !on; + } + /* No idea what sort of object this is - be visible */ + return 0; } -static void -pdf_clear_stack(pdf_csi *csi) +static fz_image * +parse_inline_image(fz_context *ctx, pdf_csi *csi, fz_stream *stm) { - fz_context *ctx = csi->ctx; + pdf_document *doc = csi->doc; + pdf_obj *rdb = csi->rdb; + pdf_obj *obj = NULL; + fz_image *img = NULL; + int ch, found; - int i; + fz_var(obj); + fz_var(img); - fz_drop_image(ctx, csi->img); - csi->img = NULL; + fz_try(ctx) + { + obj = pdf_parse_dict(ctx, doc, stm, &doc->lexbuf.base); - pdf_drop_obj(ctx, csi->obj); - csi->obj = NULL; + /* read whitespace after ID keyword */ + ch = fz_read_byte(ctx, stm); + if (ch == '\r') + if (fz_peek_byte(ctx, stm) == '\n') + fz_read_byte(ctx, stm); - csi->name[0] = 0; - csi->string_len = 0; - for (i = 0; i < csi->top; i++) - csi->stack[i] = 0; + img = pdf_load_inline_image(ctx, doc, rdb, obj, stm); - csi->top = 0; + /* find EI */ + found = 0; + ch = fz_read_byte(ctx, stm); + do + { + while (ch != 'E' && ch != EOF) + ch = fz_read_byte(ctx, stm); + if (ch == 'E') + { + ch = fz_read_byte(ctx, stm); + if (ch == 'I') + { + ch = fz_peek_byte(ctx, stm); + if (ch == ' ' || ch <= 32 || ch == EOF || ch == '<' || ch == '/') + { + found = 1; + break; + } + } + } + } while (ch != EOF); + if (!found) + fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error after inline image"); + } + fz_catch(ctx) + { + pdf_drop_obj(ctx, obj); + fz_drop_image(ctx, img); + fz_rethrow(ctx); + } + + return img; } static void -pdf_drop_csi(pdf_csi *csi) +pdf_process_extgstate(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, pdf_obj *dict) { - fz_context *ctx = csi->ctx; + pdf_obj *obj; - pdf_process_op(csi, PDF_OP_END, &csi->process); - fz_free(ctx, csi); -} + obj = pdf_dict_gets(ctx, dict, "LW"); + if (pdf_is_number(ctx, obj) && proc->op_w) + proc->op_w(ctx, proc, pdf_to_real(ctx, obj)); -#define A(a) (a) -#define B(a,b) (a | b << 8) -#define C(a,b,c) (a | b << 8 | c << 16) + obj = pdf_dict_gets(ctx, dict, "LC"); + if (pdf_is_int(ctx, obj) && proc->op_J) + proc->op_J(ctx, proc, pdf_to_int(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "LJ"); + if (pdf_is_int(ctx, obj) && proc->op_j) + proc->op_j(ctx, proc, pdf_to_int(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "ML"); + if (pdf_is_number(ctx, obj) && proc->op_M) + proc->op_M(ctx, proc, pdf_to_real(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "D"); + if (pdf_is_array(ctx, obj) && proc->op_d) + { + pdf_obj *dash_array = pdf_array_get(ctx, obj, 0); + pdf_obj *dash_phase = pdf_array_get(ctx, obj, 1); + proc->op_d(ctx, proc, dash_array, pdf_to_real(ctx, dash_phase)); + } + + obj = pdf_dict_gets(ctx, dict, "RI"); + if (pdf_is_name(ctx, obj) && proc->op_ri) + proc->op_ri(ctx, proc, pdf_to_name(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "FL"); + if (pdf_is_number(ctx, obj) && proc->op_i) + proc->op_i(ctx, proc, pdf_to_real(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "Font"); + if (pdf_is_array(ctx, obj) && proc->op_Tf) + { + pdf_obj *font_ref = pdf_array_get(ctx, obj, 0); + pdf_obj *font_size = pdf_array_get(ctx, obj, 1); + pdf_font_desc *font = load_font_or_hail_mary(ctx, csi->doc, csi->rdb, font_ref, 0, csi->cookie); + fz_try(ctx) + proc->op_Tf(ctx, proc, "ExtGState", font, pdf_to_real(ctx, font_size)); + fz_always(ctx) + pdf_drop_font(ctx, font); + fz_catch(ctx) + fz_rethrow(ctx); + } + + /* transfer functions */ + + obj = pdf_dict_gets(ctx, dict, "TR2"); + if (pdf_is_name(ctx, obj)) + if (strcmp(pdf_to_name(ctx, obj), "Identity") && strcmp(pdf_to_name(ctx, obj), "Default")) + fz_warn(ctx, "ignoring transfer function"); + if (!obj) /* TR is ignored in the presence of TR2 */ + { + pdf_obj *tr = pdf_dict_gets(ctx, dict, "TR"); + if (pdf_is_name(ctx, tr)) + if (strcmp(pdf_to_name(ctx, tr), "Identity")) + fz_warn(ctx, "ignoring transfer function"); + } + + /* transparency state */ + + obj = pdf_dict_gets(ctx, dict, "CA"); + if (pdf_is_number(ctx, obj) && proc->op_gs_CA) + proc->op_gs_CA(ctx, proc, pdf_to_real(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "ca"); + if (pdf_is_number(ctx, obj) && proc->op_gs_ca) + proc->op_gs_ca(ctx, proc, pdf_to_real(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "BM"); + if (pdf_is_array(ctx, obj)) + obj = pdf_array_get(ctx, obj, 0); + if (pdf_is_name(ctx, obj) && proc->op_gs_BM) + proc->op_gs_BM(ctx, proc, pdf_to_name(ctx, obj)); + + obj = pdf_dict_gets(ctx, dict, "SMask"); + if (proc->op_gs_SMask) + { + if (pdf_is_dict(ctx, obj)) + { + pdf_xobject *xobj; + pdf_obj *group, *s, *bc, *tr; + float softmask_bc[FZ_MAX_COLORS]; + fz_colorspace *colorspace; + int k, luminosity; + + fz_var(xobj); + + group = pdf_dict_gets(ctx, obj, "G"); + if (!group) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load softmask xobject (%d %d R)", pdf_to_num(ctx, obj), pdf_to_gen(ctx, obj)); + xobj = pdf_load_xobject(ctx, csi->doc, group); + + fz_try(ctx) + { + colorspace = xobj->colorspace; + if (!colorspace) + colorspace = fz_device_gray(ctx); + + for (k = 0; k < colorspace->n; k++) + softmask_bc[k] = 0; + + bc = pdf_dict_gets(ctx, obj, "BC"); + if (pdf_is_array(ctx, bc)) + { + for (k = 0; k < colorspace->n; k++) + softmask_bc[k] = pdf_to_real(ctx, pdf_array_get(ctx, bc, k)); + } + + s = pdf_dict_gets(ctx, obj, "S"); + if (pdf_is_name(ctx, s) && !strcmp(pdf_to_name(ctx, s), "Luminosity")) + luminosity = 1; + else + luminosity = 0; + + tr = pdf_dict_gets(ctx, obj, "TR"); + if (tr && strcmp(pdf_to_name(ctx, tr), "Identity")) + fz_warn(ctx, "ignoring transfer function"); + + proc->op_gs_SMask(ctx, proc, xobj, csi->rdb, softmask_bc, luminosity); + } + fz_always(ctx) + { + pdf_drop_xobject(ctx, xobj); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + } + else if (pdf_is_name(ctx, obj) && !strcmp(pdf_to_name(ctx, obj), "None")) + { + proc->op_gs_SMask(ctx, proc, NULL, NULL, NULL, 0); + } + } +} static void -parse_inline_image(pdf_csi *csi) +pdf_process_Do(fz_context *ctx, pdf_processor *proc, pdf_csi *csi) { - fz_context *ctx = csi->ctx; - pdf_document *doc = csi->doc; + pdf_obj *xres, *xobj, *subtype; + + xres = pdf_dict_gets(ctx, csi->rdb, "XObject"); + if (!xres) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find XObject dictionary"); + xobj = pdf_dict_gets(ctx, xres, csi->name); + if (!xobj) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find XObject resource '%s'", csi->name); + subtype = pdf_dict_gets(ctx, xobj, "Subtype"); + if (!strcmp(pdf_to_name(ctx, subtype), "Form") && pdf_dict_gets(ctx, xobj, "Subtype2")) + subtype = pdf_dict_gets(ctx, xobj, "Subtype2"); + if (!pdf_is_name(ctx, subtype)) + fz_throw(ctx, FZ_ERROR_GENERIC, "no XObject subtype specified"); + + if (pdf_is_hidden_ocg(ctx, csi->doc->ocg, csi->rdb, proc->event, pdf_dict_gets(ctx, xobj, "OC"))) + return; - pdf_obj *rdb = csi->rdb; - fz_stream *file = csi->file; - int ch, found; + if (!strcmp(pdf_to_name(ctx, subtype), "Form")) + { + if (proc->op_Do_form) + { + pdf_xobject *form = pdf_load_xobject(ctx, csi->doc, xobj); - fz_drop_image(ctx, csi->img); - csi->img = NULL; - pdf_drop_obj(ctx, csi->obj); - csi->obj = NULL; + fz_try(ctx) + proc->op_Do_form(ctx, proc, csi->name, form, csi->rdb); + fz_always(ctx) + pdf_drop_xobject(ctx, form); + fz_catch(ctx) + fz_rethrow(ctx); + } + } - csi->obj = pdf_parse_dict(ctx, doc, file, &doc->lexbuf.base); + else if (!strcmp(pdf_to_name(ctx, subtype), "Image")) + { + if (proc->op_Do_image) + { + fz_image *image = pdf_load_image(ctx, csi->doc, xobj); + fz_try(ctx) + proc->op_Do_image(ctx, proc, csi->name, image); + fz_always(ctx) + fz_drop_image(ctx, image); + fz_catch(ctx) + fz_rethrow(ctx); + } + } - /* read whitespace after ID keyword */ - ch = fz_read_byte(ctx, file); - if (ch == '\r') - if (fz_peek_byte(ctx, file) == '\n') - fz_read_byte(ctx, file); + else if (!strcmp(pdf_to_name(ctx, subtype), "PS")) + fz_warn(ctx, "ignoring XObject with subtype PS"); + else + fz_warn(ctx, "ignoring XObject with unknown subtype: '%s'", pdf_to_name(ctx, subtype)); +} - fz_try(ctx) +static void +pdf_process_CS(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, int stroke) +{ + if (!proc->op_CS || !proc->op_cs) + return; + + if (!strcmp(csi->name, "Pattern")) { - csi->img = pdf_load_inline_image(ctx, doc, rdb, csi->obj, file); + if (stroke) + proc->op_CS(ctx, proc, "Pattern", NULL); + else + proc->op_cs(ctx, proc, "Pattern", NULL); } - fz_catch(ctx) + else { - fz_rethrow(ctx); + fz_colorspace *cs; + + if (!strcmp(csi->name, "DeviceGray")) + cs = fz_keep_colorspace(ctx, fz_device_gray(ctx)); + else if (!strcmp(csi->name, "DeviceRGB")) + cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); + else if (!strcmp(csi->name, "DeviceCMYK")) + cs = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); + else + { + pdf_obj *csres, *csobj; + csres = pdf_dict_gets(ctx, csi->rdb, "ColorSpace"); + if (!csres) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ColorSpace dictionary"); + csobj = pdf_dict_gets(ctx, csres, csi->name); + if (!csobj) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ColorSpace resource '%s'", csi->name); + cs = pdf_load_colorspace(ctx, csi->doc, csobj); + } + + fz_try(ctx) + { + if (stroke) + proc->op_CS(ctx, proc, csi->name, cs); + else + proc->op_cs(ctx, proc, csi->name, cs); + } + fz_always(ctx) + fz_drop_colorspace(ctx, cs); + fz_catch(ctx) + fz_rethrow(ctx); } +} - /* find EI */ - found = 0; - ch = fz_read_byte(ctx, file); - do +static void +pdf_process_SC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, int stroke) +{ + if (csi->name[0]) { - while (ch != 'E' && ch != EOF) - ch = fz_read_byte(ctx, file); - if (ch == 'E') + pdf_obj *patres, *patobj, *type; + + patres = pdf_dict_gets(ctx, csi->rdb, "Pattern"); + if (!patres) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Pattern dictionary"); + patobj = pdf_dict_gets(ctx, patres, csi->name); + if (!patobj) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Pattern resource '%s'", csi->name); + + type = pdf_dict_gets(ctx, patobj, "PatternType"); + + if (pdf_to_int(ctx, type) == 1) { - ch = fz_read_byte(ctx, file); - if (ch == 'I') + if (proc->op_SC_pattern && proc->op_sc_pattern) { - ch = fz_peek_byte(ctx, file); - if (ch == ' ' || ch <= 32 || ch == EOF || ch == '<' || ch == '/') + pdf_pattern *pat = pdf_load_pattern(ctx, csi->doc, patobj); + fz_try(ctx) { - found = 1; - break; + if (stroke) + proc->op_SC_pattern(ctx, proc, csi->name, pat, csi->top, csi->stack); + else + proc->op_sc_pattern(ctx, proc, csi->name, pat, csi->top, csi->stack); } + fz_always(ctx) + pdf_drop_pattern(ctx, pat); + fz_catch(ctx) + fz_rethrow(ctx); } } - } while (ch != EOF); - if (!found) - fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error after inline image"); + + else if (pdf_to_int(ctx, type) == 2) + { + if (proc->op_SC_shade && proc->op_sc_shade) + { + fz_shade *shade = pdf_load_shading(ctx, csi->doc, patobj); + fz_try(ctx) + { + if (stroke) + proc->op_SC_shade(ctx, proc, csi->name, shade); + else + proc->op_sc_shade(ctx, proc, csi->name, shade); + } + fz_always(ctx) + fz_drop_shade(ctx, shade); + fz_catch(ctx) + fz_rethrow(ctx); + } + } + + else + { + fz_throw(ctx, FZ_ERROR_GENERIC, "unknown pattern type: %d", pdf_to_int(ctx, type)); + } + } + + else + { + if (proc->op_SC_color && proc->op_sc_color) + { + if (stroke) + proc->op_SC_color(ctx, proc, csi->top, csi->stack); + else + proc->op_sc_color(ctx, proc, csi->top, csi->stack); + } + } } -static int -pdf_run_keyword(pdf_csi *csi, char *buf) +static pdf_obj * +resolve_properties(fz_context *ctx, pdf_csi *csi, pdf_obj *obj) +{ + if (pdf_is_name(ctx, obj)) + return pdf_dict_gets(ctx, pdf_dict_gets(ctx, csi->rdb, "Properties"), pdf_to_name(ctx, obj)); + else + return obj; +} + +static void +pdf_process_BDC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, const char *name, pdf_obj *properties) { - fz_context *ctx = csi->ctx; + if (proc->op_BDC) + proc->op_BDC(ctx, proc, name, properties); + /* Already hidden, no need to look further */ + if (proc->hidden > 0) + { + ++proc->hidden; + return; + } + + /* We only look at OC groups here */ + if (strcmp(name, "OC")) + return; + + /* No Properties array, or name not found, means visible. */ + if (!properties) + return; + + /* Wrong type of property */ + if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, properties, "Type")), "OCG")) + return; + + if (pdf_is_hidden_ocg(ctx, csi->doc->ocg, csi->rdb, proc->event, properties)) + ++proc->hidden; +} + +static void +pdf_process_BMC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, const char *name) +{ + if (proc->op_BMC) + proc->op_BMC(ctx, proc, name); + if (proc->hidden > 0) + ++proc->hidden; +} + +static void +pdf_process_EMC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi) +{ + if (proc->op_EMC) + proc->op_EMC(ctx, proc); + if (proc->hidden > 0) + --proc->hidden; +} + +static void +pdf_process_gsave(fz_context *ctx, pdf_processor *proc, pdf_csi *csi) +{ + if (proc->op_q) + proc->op_q(ctx, proc); + ++csi->gstate; +} + +static void +pdf_process_grestore(fz_context *ctx, pdf_processor *proc, pdf_csi *csi) +{ + if (csi->gstate > 0) + { + if (proc->op_Q) + proc->op_Q(ctx, proc); + --csi->gstate; + } +} + +static void +pdf_process_end(fz_context *ctx, pdf_processor *proc, pdf_csi *csi) +{ + while (csi->gstate > 0) + pdf_process_grestore(ctx, proc, csi); + if (proc->op_END) + proc->op_END(ctx, proc); +} + +#define A(a) (a) +#define B(a,b) (a | b << 8) +#define C(a,b,c) (a | b << 8 | c << 16) + +static int +pdf_process_keyword(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, fz_stream *stm, char *word) +{ + float *s = csi->stack; int key; - PDF_OP op; - key = buf[0]; - if (buf[1]) + key = word[0]; + if (word[1]) { - key |= buf[1] << 8; - if (buf[2]) + key |= word[1] << 8; + if (word[2]) { - key |= buf[2] << 16; - if (buf[3]) + key |= word[2] << 16; + if (word[3]) key = 0; } } switch (key) { - case A('"'): op = PDF_OP_dquote; break; - case A('\''): op = PDF_OP_squote; break; - case A('B'): op = PDF_OP_B; break; - case B('B','*'): op = PDF_OP_Bstar; break; - case C('B','D','C'): op = PDF_OP_BDC; break; - case B('B','I'): op = PDF_OP_BI; break; - case C('B','M','C'): op = PDF_OP_BMC; break; - case B('B','T'): - op = PDF_OP_BT; - csi->in_text = 1; - break; - case B('B','X'): - op = PDF_OP_BX; - csi->xbalance++; - break; - case B('C','S'): op = PDF_OP_CS; break; - case B('D','P'): op = PDF_OP_DP; break; - case B('D','o'): op = PDF_OP_Do; break; - case C('E','M','C'): op = PDF_OP_EMC; break; - case B('E','T'): - op = PDF_OP_ET; - csi->in_text = 0; - break; - case B('E','X'): - op = PDF_OP_EX; - csi->xbalance--; - break; - case A('F'): op = PDF_OP_F; break; - case A('G'): op = PDF_OP_G; break; - case A('J'): op = PDF_OP_J; break; - case A('K'): op = PDF_OP_K; break; - case A('M'): op = PDF_OP_M; break; - case B('M','P'): op = PDF_OP_MP; break; - case A('Q'): op = PDF_OP_Q; break; - case B('R','G'): op = PDF_OP_RG; break; - case A('S'): op = PDF_OP_S; break; - case B('S','C'): op = PDF_OP_SC; break; - case C('S','C','N'): op = PDF_OP_SCN; break; - case B('T','*'): op = PDF_OP_Tstar; break; - case B('T','D'): op = PDF_OP_TD; break; - case B('T','J'): op = PDF_OP_TJ; break; - case B('T','L'): op = PDF_OP_TL; break; - case B('T','c'): op = PDF_OP_Tc; break; - case B('T','d'): op = PDF_OP_Td; break; - case B('T','f'): op = PDF_OP_Tf; break; - case B('T','j'): op = PDF_OP_Tj; break; - case B('T','m'): op = PDF_OP_Tm; break; - case B('T','r'): op = PDF_OP_Tr; break; - case B('T','s'): op = PDF_OP_Ts; break; - case B('T','w'): op = PDF_OP_Tw; break; - case B('T','z'): op = PDF_OP_Tz; break; - case A('W'): op = PDF_OP_W; break; - case B('W','*'): op = PDF_OP_Wstar; break; - case A('b'): op = PDF_OP_b; break; - case B('b','*'): op = PDF_OP_bstar; break; - case A('c'): op = PDF_OP_c; break; - case B('c','m'): op = PDF_OP_cm; break; - case B('c','s'): op = PDF_OP_cs; break; - case A('d'): op = PDF_OP_d; break; - case B('d','0'): op = PDF_OP_d0; break; - case B('d','1'): op = PDF_OP_d1; break; - case A('f'): op = PDF_OP_f; break; - case B('f','*'): op = PDF_OP_fstar; break; - case A('g'): op = PDF_OP_g; break; - case B('g','s'): op = PDF_OP_gs; break; - case A('h'): op = PDF_OP_h; break; - case A('i'): op = PDF_OP_i; break; - case A('j'): op = PDF_OP_j; break; - case A('k'): op = PDF_OP_k; break; - case A('l'): op = PDF_OP_l; break; - case A('m'): op = PDF_OP_m; break; - case A('n'): op = PDF_OP_n; break; - case A('q'): op = PDF_OP_q; break; - case B('r','e'): op = PDF_OP_re; break; - case B('r','g'): op = PDF_OP_rg; break; - case B('r','i'): op = PDF_OP_ri; break; - case A('s'): op = PDF_OP_s; break; - case B('s','c'): op = PDF_OP_sc; break; - case C('s','c','n'): op = PDF_OP_scn; break; - case B('s','h'): op = PDF_OP_sh; break; - case A('v'): op = PDF_OP_v; break; - case A('w'): op = PDF_OP_w; break; - case A('y'): op = PDF_OP_y; break; default: if (!csi->xbalance) { - fz_warn(ctx, "unknown keyword: '%s'", buf); + fz_warn(ctx, "unknown keyword: '%s'", word); return 1; } - return 0; - } + break; - if (op == PDF_OP_BI) - { - parse_inline_image(csi); - } + /* general graphics state */ + case A('w'): if (proc->op_w) proc->op_w(ctx, proc, s[0]); break; + case A('j'): if (proc->op_j) proc->op_j(ctx, proc, s[0]); break; + case A('J'): if (proc->op_J) proc->op_J(ctx, proc, s[0]); break; + case A('M'): if (proc->op_M) proc->op_M(ctx, proc, s[0]); break; + case A('d'): if (proc->op_d) proc->op_d(ctx, proc, csi->obj, s[0]); break; + case B('r','i'): if (proc->op_ri) proc->op_ri(ctx, proc, csi->name); break; + case A('i'): if (proc->op_i) proc->op_i(ctx, proc, s[0]); break; - if (op < PDF_OP_Do) - { - pdf_process_op(csi, op, &csi->process); - } - else if (op < PDF_OP_END) - { - fz_try(ctx) + case B('g','s'): { - pdf_process_op(csi, op, &csi->process); + pdf_obj *gsres, *gsobj; + gsres = pdf_dict_gets(ctx, csi->rdb, "ExtGState"); + if (!gsres) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ExtGState dictionary"); + gsobj = pdf_dict_gets(ctx, gsres, csi->name); + if (!gsobj) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ExtGState resource '%s'", csi->name); + if (proc->op_gs_begin) + proc->op_gs_begin(ctx, proc, csi->name, gsobj); + pdf_process_extgstate(ctx, proc, csi, gsobj); + if (proc->op_gs_end) + proc->op_gs_end(ctx, proc); } - fz_catch(ctx) + break; + + /* special graphics state */ + case A('q'): pdf_process_gsave(ctx, proc, csi); break; + case A('Q'): pdf_process_grestore(ctx, proc, csi); break; + case B('c','m'): if (proc->op_cm) proc->op_cm(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break; + + /* path construction */ + case A('m'): if (proc->op_m) proc->op_m(ctx, proc, s[0], s[1]); break; + case A('l'): if (proc->op_l) proc->op_l(ctx, proc, s[0], s[1]); break; + case A('c'): if (proc->op_c) proc->op_c(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break; + case A('v'): if (proc->op_v) proc->op_v(ctx, proc, s[0], s[1], s[2], s[3]); break; + case A('y'): if (proc->op_y) proc->op_y(ctx, proc, s[0], s[1], s[2], s[3]); break; + case A('h'): if (proc->op_h) proc->op_h(ctx, proc); break; + case B('r','e'): if (proc->op_re) proc->op_re(ctx, proc, s[0], s[1], s[2], s[3]); break; + + /* path painting */ + case A('S'): if (proc->op_S) proc->op_S(ctx, proc); break; + case A('s'): if (proc->op_s) proc->op_s(ctx, proc); break; + case A('F'): if (proc->op_F) proc->op_F(ctx, proc); break; + case A('f'): if (proc->op_f) proc->op_f(ctx, proc); break; + case B('f','*'): if (proc->op_fstar) proc->op_fstar(ctx, proc); break; + case A('B'): if (proc->op_B) proc->op_B(ctx, proc); break; + case B('B','*'): if (proc->op_Bstar) proc->op_Bstar(ctx, proc); break; + case A('b'): if (proc->op_b) proc->op_b(ctx, proc); break; + case B('b','*'): if (proc->op_bstar) proc->op_bstar(ctx, proc); break; + case A('n'): if (proc->op_n) proc->op_n(ctx, proc); break; + + /* path clipping */ + case A('W'): if (proc->op_W) proc->op_W(ctx, proc); break; + case B('W','*'): if (proc->op_Wstar) proc->op_Wstar(ctx, proc); break; + + /* text objects */ + case B('B','T'): csi->in_text = 1; if (proc->op_BT) proc->op_BT(ctx, proc); break; + case B('E','T'): csi->in_text = 0; if (proc->op_ET) proc->op_ET(ctx, proc); break; + + /* text state */ + case B('T','c'): if (proc->op_Tc) proc->op_Tc(ctx, proc, s[0]); break; + case B('T','w'): if (proc->op_Tw) proc->op_Tw(ctx, proc, s[0]); break; + case B('T','z'): if (proc->op_Tz) proc->op_Tz(ctx, proc, s[0]); break; + case B('T','L'): if (proc->op_TL) proc->op_TL(ctx, proc, s[0]); break; + case B('T','r'): if (proc->op_Tr) proc->op_Tr(ctx, proc, s[0]); break; + case B('T','s'): if (proc->op_Ts) proc->op_Ts(ctx, proc, s[0]); break; + + case B('T','f'): + if (proc->op_Tf) + { + pdf_obj *fontres, *fontobj; + pdf_font_desc *font; + fontres = pdf_dict_gets(ctx, csi->rdb, "Font"); + if (!fontres) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Font dictionary"); + fontobj = pdf_dict_gets(ctx, fontres, csi->name); + if (!fontobj) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Font resource '%s'", csi->name); + font = load_font_or_hail_mary(ctx, csi->doc, csi->rdb, fontobj, 0, csi->cookie); + fz_try(ctx) + proc->op_Tf(ctx, proc, csi->name, font, s[0]); break; + fz_always(ctx) + pdf_drop_font(ctx, font); + fz_catch(ctx) + fz_rethrow(ctx); + } + break; + + /* text positioning */ + case B('T','d'): if (proc->op_Td) proc->op_Td(ctx, proc, s[0], s[1]); break; + case B('T','D'): if (proc->op_TD) proc->op_TD(ctx, proc, s[0], s[1]); break; + case B('T','m'): if (proc->op_Tm) proc->op_Tm(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break; + case B('T','*'): if (proc->op_Tstar) proc->op_Tstar(ctx, proc); break; + + /* text showing */ + case B('T','J'): if (proc->op_TJ) proc->op_TJ(ctx, proc, csi->obj); break; + case B('T','j'): + if (proc->op_Tj) + { + if (csi->string_len > 0) + proc->op_Tj(ctx, proc, csi->string, csi->string_len); + else + proc->op_Tj(ctx, proc, pdf_to_str_buf(ctx, csi->obj), pdf_to_str_len(ctx, csi->obj)); + } + break; + case A('\''): + if (proc->op_squote) { - fz_rethrow_if(ctx, FZ_ERROR_ABORT); - switch (op) + if (csi->string_len > 0) + proc->op_squote(ctx, proc, csi->string, csi->string_len); + else + proc->op_squote(ctx, proc, pdf_to_str_buf(ctx, csi->obj), pdf_to_str_len(ctx, csi->obj)); + } + break; + case A('"'): + if (proc->op_dquote) + { + if (csi->string_len > 0) + proc->op_dquote(ctx, proc, s[0], s[1], csi->string, csi->string_len); + else + proc->op_dquote(ctx, proc, s[0], s[1], pdf_to_str_buf(ctx, csi->obj), pdf_to_str_len(ctx, csi->obj)); + } + break; + + /* type 3 fonts */ + case B('d','0'): if (proc->op_d0) proc->op_d0(ctx, proc, s[0], s[1]); break; + case B('d','1'): if (proc->op_d1) proc->op_d1(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break; + + /* color */ + case B('C','S'): pdf_process_CS(ctx, proc, csi, 1); break; + case B('c','s'): pdf_process_CS(ctx, proc, csi, 0); break; + case B('S','C'): pdf_process_SC(ctx, proc, csi, 1); break; + case B('s','c'): pdf_process_SC(ctx, proc, csi, 0); break; + case C('S','C','N'): pdf_process_SC(ctx, proc, csi, 1); break; + case C('s','c','n'): pdf_process_SC(ctx, proc, csi, 0); break; + + case A('G'): if (proc->op_G) proc->op_G(ctx, proc, s[0]); break; + case A('g'): if (proc->op_g) proc->op_g(ctx, proc, s[0]); break; + case B('R','G'): if (proc->op_RG) proc->op_RG(ctx, proc, s[0], s[1], s[2]); break; + case B('r','g'): if (proc->op_rg) proc->op_rg(ctx, proc, s[0], s[1], s[2]); break; + case A('K'): if (proc->op_K) proc->op_K(ctx, proc, s[0], s[1], s[2], s[3]); break; + case A('k'): if (proc->op_k) proc->op_k(ctx, proc, s[0], s[1], s[2], s[3]); break; + + /* shadings, images, xobjects */ + case B('B','I'): + { + fz_image *img = parse_inline_image(ctx, csi, stm); + fz_try(ctx) { - case PDF_OP_Do: - fz_rethrow_message(ctx, "cannot draw xobject/image"); - break; - case PDF_OP_Tf: - fz_rethrow_message(ctx, "cannot set font"); - break; - case PDF_OP_gs: - fz_rethrow_message(ctx, "cannot set graphics state"); - break; - case PDF_OP_sh: - fz_rethrow_message(ctx, "cannot draw shading"); - break; - default: - fz_rethrow(ctx); /* Should never happen */ + if (proc->op_BI) + proc->op_BI(ctx, proc, img); } + fz_always(ctx) + fz_drop_image(ctx, img); + fz_catch(ctx) + fz_rethrow(ctx); } + break; + + case B('s','h'): + if (proc->op_sh) + { + pdf_obj *shaderes, *shadeobj; + fz_shade *shade; + shaderes = pdf_dict_gets(ctx, csi->rdb, "Shading"); + if (!shaderes) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Shading dictionary"); + shadeobj = pdf_dict_gets(ctx, shaderes, csi->name); + if (!shadeobj) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Shading resource '%s'", csi->name); + shade = pdf_load_shading(ctx, csi->doc, shadeobj); + fz_try(ctx) + proc->op_sh(ctx, proc, csi->name, shade); + fz_always(ctx) + fz_drop_shade(ctx, shade); + fz_catch(ctx) + fz_rethrow(ctx); + } + break; + + case B('D','o'): pdf_process_Do(ctx, proc, csi); break; + + /* marked content */ + case B('M','P'): if (proc->op_MP) proc->op_MP(ctx, proc, csi->name); break; + case B('D','P'): if (proc->op_DP) proc->op_DP(ctx, proc, csi->name, resolve_properties(ctx, csi, csi->obj)); break; + case C('B','M','C'): pdf_process_BMC(ctx, proc, csi, csi->name); break; + case C('B','D','C'): pdf_process_BDC(ctx, proc, csi, csi->name, resolve_properties(ctx, csi, csi->obj)); break; + case C('E','M','C'): pdf_process_EMC(ctx, proc, csi); break; + + /* compatibility */ + case B('B','X'): ++csi->xbalance; if (proc->op_BX) proc->op_BX(ctx, proc); break; + case B('E','X'): --csi->xbalance; if (proc->op_EX) proc->op_EX(ctx, proc); break; } + return 0; } -void -pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) +static void +pdf_process_stream(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, fz_stream *stm) { - fz_context *ctx = csi->ctx; pdf_document *doc = csi->doc; + pdf_lexbuf *buf = csi->buf; + fz_cookie *cookie = csi->cookie; - fz_stream *file = csi->file; pdf_token tok = PDF_TOK_ERROR; int in_text_array = 0; int ignoring_errors = 0; /* make sure we have a clean slate if we come here from flush_text */ - pdf_clear_stack(csi); + pdf_clear_stack(ctx, csi); fz_var(in_text_array); fz_var(tok); - if (csi->cookie) + if (cookie) { - csi->cookie->progress_max = -1; - csi->cookie->progress = 0; + cookie->progress_max = -1; + cookie->progress = 0; } do @@ -311,17 +1001,17 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) do { /* Check the cookie */ - if (csi->cookie) + if (cookie) { - if (csi->cookie->abort) + if (cookie->abort) { tok = PDF_TOK_EOF; break; } - csi->cookie->progress++; + cookie->progress++; } - tok = pdf_lex(ctx, file, buf); + tok = pdf_lex(ctx, stm, buf); if (in_text_array) { @@ -352,7 +1042,7 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) { csi->stack[0] = pdf_to_real(ctx, o); pdf_array_delete(ctx, csi->obj, l-1); - if (pdf_run_keyword(csi, buf->scratch) == 0) + if (pdf_process_keyword(ctx, proc, csi, stm, buf->scratch) == 0) break; } } @@ -382,7 +1072,7 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) } else { - csi->obj = pdf_parse_array(ctx, doc, file, buf); + csi->obj = pdf_parse_array(ctx, doc, stm, buf); } break; @@ -392,7 +1082,7 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) pdf_drop_obj(ctx, csi->obj); csi->obj = NULL; } - csi->obj = pdf_parse_dict(ctx, doc, file, buf); + csi->obj = pdf_parse_dict(ctx, doc, stm, buf); break; case PDF_TOK_NAME: @@ -442,11 +1132,11 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) break; case PDF_TOK_KEYWORD: - if (pdf_run_keyword(csi, buf->scratch)) + if (pdf_process_keyword(ctx, proc, csi, stm, buf->scratch)) { tok = PDF_TOK_EOF; } - pdf_clear_stack(csi); + pdf_clear_stack(ctx, csi); break; default: @@ -457,20 +1147,20 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) } fz_always(ctx) { - pdf_clear_stack(csi); + pdf_clear_stack(ctx, csi); } fz_catch(ctx) { int caught; - if (!csi->cookie) + if (!cookie) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); } else if ((caught = fz_caught(ctx)) == FZ_ERROR_TRYLATER) { - if (csi->cookie->incomplete_ok) - csi->cookie->incomplete++; + if (cookie->incomplete_ok) + cookie->incomplete++; else fz_rethrow(ctx); } @@ -480,7 +1170,7 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) } else { - csi->cookie->errors++; + cookie->errors++; } if (!ignoring_errors) { @@ -495,169 +1185,99 @@ pdf_process_stream(pdf_csi *csi, pdf_lexbuf *buf) while (tok != PDF_TOK_EOF); } -/* - * Entry points - */ - -static void -pdf_process_contents_stream(pdf_csi *csi, pdf_obj *rdb, fz_stream *file) +void +pdf_process_contents(fz_context *ctx, pdf_processor *proc, pdf_document *doc, pdf_obj *rdb, pdf_obj *stmobj, fz_cookie *cookie) { - fz_context *ctx = csi->ctx; - - pdf_lexbuf *buf; - int save_in_text; - pdf_obj *save_obj; - pdf_obj *save_rdb = csi->rdb; - fz_stream *save_file = csi->file; - - fz_var(buf); + pdf_csi csi; + pdf_lexbuf buf; + fz_stream *stm = NULL; - if (file == NULL) + if (!stmobj) return; - buf = fz_malloc(ctx, sizeof(*buf)); /* we must be re-entrant for type3 fonts */ - pdf_lexbuf_init(ctx, buf, PDF_LEXBUF_SMALL); - save_in_text = csi->in_text; - csi->in_text = 0; - save_obj = csi->obj; - csi->obj = NULL; - csi->rdb = rdb; - csi->file = file; - fz_try(ctx) - { - csi->process.processor->process_stream(csi, csi->process.state, buf); - } - fz_always(ctx) - { - csi->in_text = save_in_text; - pdf_drop_obj(ctx, csi->obj); - csi->obj = save_obj; - csi->rdb = save_rdb; - csi->file = save_file; - pdf_lexbuf_fin(ctx, buf); - fz_free(ctx, buf); - } - fz_catch(ctx) - { - fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); - fz_rethrow_if(ctx, FZ_ERROR_ABORT); - fz_warn(ctx, "Content stream parsing error - rendering truncated"); - } -} + fz_var(stm); -void -pdf_process_annot(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *annot, const pdf_process *process, fz_cookie *cookie) -{ - pdf_csi *csi; - int flags; + pdf_lexbuf_init(ctx, &buf, PDF_LEXBUF_SMALL); + pdf_init_csi(ctx, &csi, doc, rdb, &buf, cookie); - csi = pdf_new_csi(ctx, doc, cookie, process); fz_try(ctx) { - flags = pdf_to_int(ctx, pdf_dict_gets(ctx, annot->obj, "F")); - - /* Check not invisible (bit 0) and hidden (bit 1) */ - /* TODO: NoZoom and NoRotate */ - if (flags & ((1 << 0) | (1 << 1))) - break; - - csi->process.processor->process_annot(csi, csi->process.state, page->resources, annot); + stm = pdf_open_contents_stream(ctx, doc, stmobj); + pdf_process_stream(ctx, proc, &csi, stm); + pdf_process_end(ctx, proc, &csi); } fz_always(ctx) { - pdf_drop_csi(csi); + fz_drop_stream(ctx, stm); + pdf_clear_stack(ctx, &csi); + pdf_lexbuf_fin(ctx, &buf); } fz_catch(ctx) { - fz_rethrow_message(ctx, "cannot parse annotation appearance stream"); + fz_rethrow_if(ctx, FZ_ERROR_ABORT); + fz_rethrow_message(ctx, "cannot parse content stream"); } } void -pdf_process_contents_object(pdf_csi *csi, pdf_obj *rdb, pdf_obj *contents) +pdf_process_annot(fz_context *ctx, pdf_processor *proc, pdf_document *doc, pdf_page *page, pdf_annot *annot, fz_cookie *cookie) { - fz_context *ctx = csi->ctx; - pdf_document *doc = csi->doc; - - fz_stream *file = NULL; + int flags = pdf_to_int(ctx, pdf_dict_gets(ctx, annot->obj, "F")); - if (contents == NULL) + if (flags & (F_Invisible | F_Hidden)) return; - file = pdf_open_contents_stream(ctx, doc, contents); - fz_try(ctx) + if (proc->event) { - pdf_process_contents_stream(csi, rdb, file); + if (!strcmp(proc->event, "Print") && !(flags & F_Print)) + return; + if (!strcmp(proc->event, "View") && (flags & F_NoView)) + return; } - fz_always(ctx) - { - fz_drop_stream(ctx, file); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} -static void -pdf_process_contents_buffer(pdf_csi *csi, pdf_obj *rdb, fz_buffer *contents) -{ - fz_context *ctx = csi->ctx; + /* TODO: NoZoom and NoRotate */ - fz_stream *file = NULL; - - if (contents == NULL) + /* XXX what resources, if any, to use for this check? */ + if (pdf_is_hidden_ocg(ctx, doc->ocg, NULL, proc->event, pdf_dict_gets(ctx, annot->obj, "OC"))) return; - file = fz_open_buffer(ctx, contents); - fz_try(ctx) + if (proc->op_q && proc->op_cm && proc->op_Do_form && proc->op_Q) { - pdf_process_contents_stream(csi, rdb, file); - } - fz_always(ctx) - { - fz_drop_stream(ctx, file); - } - fz_catch(ctx) - { - fz_rethrow(ctx); + proc->op_q(ctx, proc); + proc->op_cm(ctx, proc, + annot->matrix.a, annot->matrix.b, annot->matrix.c, + annot->matrix.d, annot->matrix.e, annot->matrix.f); + proc->op_Do_form(ctx, proc, "Annot", annot->ap, page->resources); + proc->op_Q(ctx, proc); } } void -pdf_process_stream_object(fz_context *ctx, pdf_document *doc, pdf_obj *obj, const pdf_process *process, pdf_obj *res, fz_cookie *cookie) +pdf_process_glyph(fz_context *ctx, pdf_processor *proc, pdf_document *doc, pdf_obj *rdb, fz_buffer *contents) { - pdf_csi *csi; + pdf_csi csi; + pdf_lexbuf buf; + fz_stream *stm = NULL; - csi = pdf_new_csi(ctx, doc, cookie, process); - fz_try(ctx) - { - csi->process.processor->process_contents(csi, csi->process.state, res, obj); - } - fz_always(ctx) - { - pdf_drop_csi(csi); - } - fz_catch(ctx) - { - fz_rethrow_if(ctx, FZ_ERROR_ABORT); - fz_rethrow_message(ctx, "cannot parse content stream"); - } -} + fz_var(stm); -void -pdf_process_glyph(fz_context *ctx, pdf_document *doc, pdf_obj *resources, fz_buffer *contents, pdf_process *process) -{ - pdf_csi *csi; + if (!contents) + return; + + pdf_lexbuf_init(ctx, &buf, PDF_LEXBUF_SMALL); + pdf_init_csi(ctx, &csi, doc, rdb, &buf, NULL); - csi = pdf_new_csi(ctx, doc, NULL, process); fz_try(ctx) { - pdf_process_contents_buffer(csi, resources, contents); + fz_stream *stm = fz_open_buffer(ctx, contents); + pdf_process_stream(ctx, proc, &csi, stm); + pdf_process_end(ctx, proc, &csi); } fz_always(ctx) { - pdf_drop_csi(csi); + fz_drop_stream(ctx, stm); + pdf_clear_stack(ctx, &csi); + pdf_lexbuf_fin(ctx, &buf); } fz_catch(ctx) { diff --git a/source/pdf/pdf-object.c b/source/pdf/pdf-object.c index 1a0b9abf..0ed9667d 100644 --- a/source/pdf/pdf-object.c +++ b/source/pdf/pdf-object.c @@ -1745,13 +1745,13 @@ int pdf_output_obj(fz_context *ctx, fz_output *out, pdf_obj *obj, int tight) if ((n + 1) < sizeof buf) { pdf_sprint_obj(ctx, buf, sizeof buf, obj, tight); - fz_printf(ctx, out, "%s\n", buf); + fz_puts(ctx, out, buf); } else { ptr = fz_malloc(ctx, n + 1); pdf_sprint_obj(ctx, ptr, n + 1, obj, tight); - fz_printf(ctx, out, "%s\n", ptr); + fz_puts(ctx, out, buf); fz_free(ctx, ptr); } return n; diff --git a/source/pdf/pdf-op-buffer.c b/source/pdf/pdf-op-buffer.c index e2bbd343..cdea4c78 100644 --- a/source/pdf/pdf-op-buffer.c +++ b/source/pdf/pdf-op-buffer.c @@ -1,939 +1,889 @@ -#include "pdf-interpret-imp.h" +#include "mupdf/pdf.h" -typedef struct pdf_buffer_state_s +typedef struct pdf_output_processor_s pdf_output_processor; + +struct pdf_output_processor_s { - fz_context *ctx; - fz_buffer *buffer; + pdf_processor super; fz_output *out; -} -pdf_buffer_state; + int extgstate; +}; + +/* general graphics state */ static void -put_hexstring(fz_context *ctx, fz_output *out, pdf_csi *csi) +pdf_out_w(fz_context *ctx, pdf_processor *proc, float linewidth) { - int i; - - fz_printf(ctx, out, "<"); - for (i = 0; i < csi->string_len; i++) - fz_printf(ctx, out, "%02x", csi->string[i]); - fz_printf(ctx, out, ">"); + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + fz_printf(ctx, out, "%f w\n", linewidth); } static void -put_string(fz_context *ctx, fz_output *out, pdf_csi *csi) +pdf_out_j(fz_context *ctx, pdf_processor *proc, int linejoin) { - int i; - - for (i=0; i < csi->string_len; i++) - if (csi->string[i] < 32 || csi->string[i] >= 127) - break; - if (i < csi->string_len) - put_hexstring(ctx, out, csi); - else - { - fz_printf(ctx, out, "("); - for (i = 0; i < csi->string_len; i++) - { - char c = csi->string[i]; - switch (c) - { - case '(': - fz_printf(ctx, out, "\\("); - break; - case ')': - fz_printf(ctx, out, "\\)"); - break; - case '\\': - fz_printf(ctx, out, "\\\\"); - break; - default: - fz_printf(ctx, out, "%c", csi->string[i]); - break; - } - } - fz_printf(ctx, out, ")"); - } + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + fz_printf(ctx, out, "%d j\n", linejoin); } static void -put_string_or_obj(fz_context *ctx, fz_output *out, pdf_csi *csi) +pdf_out_J(fz_context *ctx, pdf_processor *proc, int linecap) { - if (csi->string_len) - put_string(ctx, out, csi); - else - pdf_output_obj(ctx, out, csi->obj, 1); + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + fz_printf(ctx, out, "%d J\n", linecap); } static void -pdf_buffer_dquote(pdf_csi *csi, void *state_) +pdf_out_M(fz_context *ctx, pdf_processor *proc, float a) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f ", csi->stack[0], csi->stack[1]); - put_string_or_obj(state->ctx, state->out, csi); - fz_printf(state->ctx, state->out, " \"\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + fz_printf(ctx, out, "%f M\n", a); } static void -pdf_buffer_squote(pdf_csi *csi, void *state_) +pdf_out_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - put_string_or_obj(state->ctx, state->out, csi); - fz_printf(state->ctx, state->out, " \'\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + { + pdf_output_obj(ctx, out, array, 1); + fz_printf(ctx, out, " %f d\n", phase); + } } static void -pdf_buffer_B(pdf_csi *csi, void *state_) +pdf_out_ri(fz_context *ctx, pdf_processor *proc, const char *intent) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "B\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + fz_printf(ctx, out, "/%s ri\n", intent); } static void -pdf_buffer_Bstar(pdf_csi *csi, void *state_) +pdf_out_i(fz_context *ctx, pdf_processor *proc, float flatness) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "B*\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + fz_printf(ctx, out, "%f i\n", flatness); } static void -pdf_buffer_BDC(pdf_csi *csi, void *state_) +pdf_out_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s ", csi->name); - pdf_output_obj(state->ctx, state->out, csi->obj, 1); - fz_printf(state->ctx, state->out, " BDC\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + ((pdf_output_processor*)proc)->extgstate = 1; + fz_printf(ctx, out, "/%s gs\n", name); } static void -pdf_buffer_BI(pdf_csi *csi, void *state_) +pdf_out_gs_end(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - int len, i; - unsigned char *data; - fz_compressed_buffer *cbuf; - fz_buffer *buffer; - const char *match; - const char *match2; - pdf_obj *filter; - fz_context *ctx = csi->ctx; - - if (csi->img == NULL) - return; - cbuf = csi->img->buffer; - if (cbuf == NULL) - return; - buffer = cbuf->buffer; - if (buffer == NULL) - return; - - /* Tweak the /Filter entry in csi->obj to match the buffer params */ - switch (cbuf->params.type) - { - case FZ_IMAGE_JPEG: - match = "DCTDecode"; - match2 = "DCT"; - break; - case FZ_IMAGE_FAX: - match = "CCITTFaxDecode"; - match2 = "CCF"; - break; - case FZ_IMAGE_RAW: - match = NULL; - match2 = NULL; - break; - case FZ_IMAGE_RLD: - match = "RunLengthDecode"; - match2 = "RL"; - break; - case FZ_IMAGE_FLATE: - match = "FlateDecode"; - match2 = "Fl"; - break; - case FZ_IMAGE_LZW: - match = "LZWDecode"; - match2 = "LZW"; - break; - default: - fz_warn(ctx, "Unsupported type (%d) of inline image", cbuf->params.type); - return; - } - - filter = pdf_dict_gets(ctx, csi->obj, "Filter"); - if (filter == NULL) - filter = pdf_dict_gets(ctx, csi->obj, "F"); - if (match == NULL) - { - /* Remove any filter entry (e.g. Ascii85Decode) */ - if (filter) - { - pdf_dict_dels(ctx, csi->obj, "Filter"); - pdf_dict_dels(ctx, csi->obj, "F"); - } - pdf_dict_dels(ctx, csi->obj, "DecodeParms"); - pdf_dict_dels(ctx, csi->obj, "DP"); - } - else if (pdf_is_array(ctx, filter)) - { - int l = pdf_array_len(ctx, filter); - pdf_obj *o = (l == 0 ? NULL : pdf_array_get(ctx, filter, l-1)); - const char *fil = pdf_to_name(ctx, o); - - if (l == 0 || (strcmp(fil, match) && strcmp(fil, match2))) - { - fz_warn(ctx, "Unexpected Filter configuration in inline image"); - return; - } - pdf_dict_puts(ctx, csi->obj, "F", o); - - o = pdf_dict_gets(ctx, csi->obj, "DecodeParms"); - if (o == NULL) - o = pdf_dict_gets(ctx, csi->obj, "DP"); - if (o) - { - o = pdf_array_get(ctx, o, l-1); - if (o) - pdf_dict_puts(ctx, csi->obj, "DP", o); - else - pdf_dict_dels(ctx, csi->obj, "DP"); - pdf_dict_dels(ctx, csi->obj, "DecodeParms"); - } - } - else - { - /* It's a singleton. It must be correct */ - } - - fz_printf(state->ctx, state->out, "BI\n"); - - len = pdf_dict_len(ctx, csi->obj); - for (i = 0; i < len; i++) - { - pdf_output_obj(state->ctx, state->out, pdf_dict_get_key(ctx, csi->obj, i), 1); - pdf_output_obj(state->ctx, state->out, pdf_dict_get_val(ctx, csi->obj, i), 1); - } - fz_printf(state->ctx, state->out, "ID\n"); - - buffer = csi->img->buffer->buffer; - len = buffer->len; - data = buffer->data; - for (i = 0; i < len; i++) - { - fz_printf(state->ctx, state->out, "%c", data[i]); - } - - fz_printf(state->ctx, state->out, "\nEI\n"); + ((pdf_output_processor*)proc)->extgstate = 0; } +/* special graphics state */ + static void -pdf_buffer_BMC(pdf_csi *csi, void *state_) +pdf_out_q(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s BMC\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "q\n"); } static void -pdf_buffer_BT(pdf_csi *csi, void *state_) +pdf_out_Q(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "BT\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "Q\n"); } static void -pdf_buffer_BX(pdf_csi *csi, void *state_) +pdf_out_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "BX\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f %f %f cm\n", a, b, c, d, e, f); } +/* path construction */ + static void -pdf_buffer_CS(pdf_csi *csi, void *state_) +pdf_out_m(fz_context *ctx, pdf_processor *proc, float x, float y) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s CS\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f m\n", x, y); } static void -pdf_buffer_DP(pdf_csi *csi, void *state_) +pdf_out_l(fz_context *ctx, pdf_processor *proc, float x, float y) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s ", csi->name); - pdf_output_obj(state->ctx, state->out, csi->obj, 1); - fz_printf(state->ctx, state->out, " DP\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f l\n", x, y); } static void -pdf_buffer_EMC(pdf_csi *csi, void *state_) +pdf_out_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "EMC\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f %f %f c\n", x1, y1, x2, y2, x3, y3); } static void -pdf_buffer_ET(pdf_csi *csi, void *state_) +pdf_out_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "ET\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f v\n", x2, y2, x3, y3); } static void -pdf_buffer_EX(pdf_csi *csi, void *state_) +pdf_out_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "EX\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f y\n", x1, y1, x3, y3); } static void -pdf_buffer_F(pdf_csi *csi, void *state_) +pdf_out_h(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "F\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "h\n"); } static void -pdf_buffer_G(pdf_csi *csi, void *state_) +pdf_out_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f G\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f re\n", x, y, w, h); } +/* path painting */ + static void -pdf_buffer_J(pdf_csi *csi, void *state_) +pdf_out_S(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%d J\n", (int)csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "S\n"); } static void -pdf_buffer_K(pdf_csi *csi, void *state_) +pdf_out_s(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f %f K\n", csi->stack[0], - csi->stack[1], csi->stack[2], csi->stack[3]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "s\n"); } static void -pdf_buffer_M(pdf_csi *csi, void *state_) +pdf_out_F(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f M\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "F\n"); } static void -pdf_buffer_MP(pdf_csi *csi, void *state_) +pdf_out_f(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s MP\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "f\n"); } static void -pdf_buffer_Q(pdf_csi *csi, void *state_) +pdf_out_fstar(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "Q\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "f*\n"); } static void -pdf_buffer_RG(pdf_csi *csi, void *state_) +pdf_out_B(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f RG\n", csi->stack[0], csi->stack[1], csi->stack[2]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "B\n"); } static void -pdf_buffer_S(pdf_csi *csi, void *state_) +pdf_out_Bstar(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "S\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "B*\n"); } static void -pdf_buffer_SC(pdf_csi *csi, void *state_) +pdf_out_b(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - int i; - - for (i = 0; i < csi->top; i++) - fz_printf(state->ctx, state->out, "%f ", csi->stack[i]); - fz_printf(state->ctx, state->out, "SC\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "b\n"); } static void -pdf_buffer_SCN(pdf_csi *csi, void *state_) +pdf_out_bstar(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - int i; - - for (i = 0; i < csi->top; i++) - fz_printf(state->ctx, state->out, "%f ", csi->stack[i]); - if (csi->name[0]) - fz_printf(state->ctx, state->out, "/%s ", csi->name); - fz_printf(state->ctx, state->out, "SCN\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "b*\n"); } static void -pdf_buffer_Tstar(pdf_csi *csi, void *state_) +pdf_out_n(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "T*\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "n\n"); } +/* clipping paths */ + static void -pdf_buffer_TD(pdf_csi *csi, void *state_) +pdf_out_W(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f TD\n", csi->stack[0], csi->stack[1]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "W\n"); } static void -pdf_buffer_TJ(pdf_csi *csi, void *state_) +pdf_out_Wstar(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - pdf_output_obj(state->ctx, state->out, csi->obj, 1); - fz_printf(state->ctx, state->out, " TJ\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "W*\n"); } +/* text objects */ + static void -pdf_buffer_TL(pdf_csi *csi, void *state_) +pdf_out_BT(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f TL\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "BT\n"); } static void -pdf_buffer_Tc(pdf_csi *csi, void *state_) +pdf_out_ET(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f Tc\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "ET\n"); } +/* text state */ + static void -pdf_buffer_Td(pdf_csi *csi, void *state_) +pdf_out_Tc(fz_context *ctx, pdf_processor *proc, float charspace) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f Td\n", csi->stack[0], csi->stack[1]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f Tc\n", charspace); } static void -pdf_buffer_Tj(pdf_csi *csi, void *state_) +pdf_out_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - put_string_or_obj(state->ctx, state->out, csi); - fz_printf(state->ctx, state->out, " Tj\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f Tw\n", wordspace); } static void -pdf_buffer_Tm(pdf_csi *csi, void *state_) +pdf_out_Tz(fz_context *ctx, pdf_processor *proc, float scale) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f %f %f %f Tm\n", - csi->stack[0], csi->stack[1], csi->stack[2], - csi->stack[3], csi->stack[4], csi->stack[5]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f Tz\n", scale); } static void -pdf_buffer_Tr(pdf_csi *csi, void *state_) +pdf_out_TL(fz_context *ctx, pdf_processor *proc, float leading) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f Tr\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f TL\n", leading); } static void -pdf_buffer_Ts(pdf_csi *csi, void *state_) +pdf_out_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f Ts\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + if (!((pdf_output_processor*)proc)->extgstate) + fz_printf(ctx, out, "/%s %f Tf\n", name, size); } static void -pdf_buffer_Tw(pdf_csi *csi, void *state_) +pdf_out_Tr(fz_context *ctx, pdf_processor *proc, int render) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f Tw\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%d Tr\n", render); } static void -pdf_buffer_Tz(pdf_csi *csi, void *state_) +pdf_out_Ts(fz_context *ctx, pdf_processor *proc, float rise) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f Tz\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f Ts\n", rise); } +/* text positioning */ + static void -pdf_buffer_W(pdf_csi *csi, void *state_) +pdf_out_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "W\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f Td\n", tx, ty); } static void -pdf_buffer_Wstar(pdf_csi *csi, void *state_) +pdf_out_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "W*\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f TD\n", tx, ty); } static void -pdf_buffer_b(pdf_csi *csi, void *state_) +pdf_out_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "b\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f %f %f Tm\n", a, b, c, d, e, f); } static void -pdf_buffer_bstar(pdf_csi *csi, void *state_) +pdf_out_Tstar(fz_context *ctx, pdf_processor *proc) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "b*\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "T*\n"); } +/* text showing */ + static void -pdf_buffer_c(pdf_csi *csi, void *state_) +put_string(fz_context *ctx, fz_output *out, const unsigned char *str, int len) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; + int i; + + for (i = 0; i < len; ++i) + if (str[i] < 32 || str[i] >= 127) + break; - fz_printf(state->ctx, state->out, "%f %f %f %f %f %f c\n", - csi->stack[0], csi->stack[1], csi->stack[2], - csi->stack[3], csi->stack[4], csi->stack[5]); + if (i < len) + { + fz_printf(ctx, out, "<"); + for (i = 0; i < len; ++i) + fz_printf(ctx, out, "%02x", str[i]); + fz_printf(ctx, out, ">"); + } + else + { + fz_printf(ctx, out, "("); + for (i = 0; i < len; ++i) + { + unsigned char c = str[i]; + if (c == '(' || c == ')' || c == '\\') + fz_putc(ctx, out, '\\'); + fz_putc(ctx, out, c); + } + fz_printf(ctx, out, ")"); + } } static void -pdf_buffer_cm(pdf_csi *csi, void *state_) +pdf_out_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f %f %f %f cm\n", - csi->stack[0], csi->stack[1], csi->stack[2], - csi->stack[3], csi->stack[4], csi->stack[5]); + fz_output *out = ((pdf_output_processor*)proc)->out; + pdf_output_obj(ctx, out, array, 1); + fz_printf(ctx, out, " TJ\n"); } static void -pdf_buffer_cs(pdf_csi *csi, void *state_) +pdf_out_Tj(fz_context *ctx, pdf_processor *proc, char *str, int len) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s cs\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + put_string(ctx, out, (const unsigned char *)str, len); + fz_printf(ctx, out, " Tj\n"); } static void -pdf_buffer_d(pdf_csi *csi, void *state_) +pdf_out_squote(fz_context *ctx, pdf_processor *proc, char *str, int len) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - pdf_output_obj(state->ctx, state->out, csi->obj, 1); - fz_printf(state->ctx, state->out, " %f d\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + put_string(ctx, out, (const unsigned char *)str, len); + fz_printf(ctx, out, " '\n"); } static void -pdf_buffer_d0(pdf_csi *csi, void *state_) +pdf_out_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, int len) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f d0\n", csi->stack[0], csi->stack[1]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f ", aw, ac); + put_string(ctx, out, (const unsigned char *)str, len); + fz_printf(ctx, out, " \"\n"); } +/* type 3 fonts */ + static void -pdf_buffer_d1(pdf_csi *csi, void *state_) +pdf_out_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f %f %f %f d1\n", - csi->stack[0], csi->stack[1], csi->stack[2], - csi->stack[3], csi->stack[4], csi->stack[5]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f d0\n", wx, wy); } static void -pdf_buffer_f(pdf_csi *csi, void *state_) +pdf_out_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "f\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f %f %f d1\n", wx, wy, llx, lly, urx, ury); } +/* color */ + static void -pdf_buffer_fstar(pdf_csi *csi, void *state_) +pdf_out_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "f*\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s CS\n", name); } static void -pdf_buffer_g(pdf_csi *csi, void *state_) +pdf_out_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f g\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s cs\n", name); } static void -pdf_buffer_h(pdf_csi *csi, void *state_) +pdf_out_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "h\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + int i; + for (i = 0; i < n; ++i) + fz_printf(ctx, out, "%f ", color[i]); + fz_printf(ctx, out, "/%s SCN\n", name); } static void -pdf_buffer_i(pdf_csi *csi, void *state_) +pdf_out_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f i\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + int i; + for (i = 0; i < n; ++i) + fz_printf(ctx, out, "%f ", color[i]); + fz_printf(ctx, out, "/%s scn\n", name); } static void -pdf_buffer_j(pdf_csi *csi, void *state_) +pdf_out_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%d j\n", (int)csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s SCN\n", name); } static void -pdf_buffer_k(pdf_csi *csi, void *state_) +pdf_out_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f %f k\n", csi->stack[0], - csi->stack[1], csi->stack[2], csi->stack[3]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s scn\n", name); } static void -pdf_buffer_l(pdf_csi *csi, void *state_) +pdf_out_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f l\n", csi->stack[0], csi->stack[1]); + fz_output *out = ((pdf_output_processor*)proc)->out; + int i; + for (i = 0; i < n; ++i) + fz_printf(ctx, out, "%f ", color[i]); + fz_printf(ctx, out, "SCN\n"); } static void -pdf_buffer_m(pdf_csi *csi, void *state_) +pdf_out_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f m\n", csi->stack[0], csi->stack[1]); + fz_output *out = ((pdf_output_processor*)proc)->out; + int i; + for (i = 0; i < n; ++i) + fz_printf(ctx, out, "%f ", color[i]); + fz_printf(ctx, out, "scn\n"); } static void -pdf_buffer_n(pdf_csi *csi, void *state_) +pdf_out_G(fz_context *ctx, pdf_processor *proc, float g) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "n\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f G\n", g); } static void -pdf_buffer_q(pdf_csi *csi, void *state_) +pdf_out_g(fz_context *ctx, pdf_processor *proc, float g) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "q\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f g\n", g); } static void -pdf_buffer_re(pdf_csi *csi, void *state_) +pdf_out_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f %f re\n", csi->stack[0], - csi->stack[1], csi->stack[2], csi->stack[3]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f RG\n", r, g, b); } static void -pdf_buffer_rg(pdf_csi *csi, void *state_) +pdf_out_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f rg\n", - csi->stack[0], csi->stack[1], csi->stack[2]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f rg\n", r, g, b); } static void -pdf_buffer_ri(pdf_csi *csi, void *state_) +pdf_out_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s ri\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f K\n", c, m, y, k); } static void -pdf_buffer_s(pdf_csi *csi, void *state_) +pdf_out_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "s\n"); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "%f %f %f %f k\n", c, m, y, k); } +/* shadings, images, xobjects */ + static void -pdf_buffer_sc(pdf_csi *csi, void *state_) +pdf_out_BI(fz_context *ctx, pdf_processor *proc, fz_image *img) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_compressed_buffer *cbuf; + fz_buffer *buf; int i; - for (i = 0; i < csi->top; i++) - fz_printf(state->ctx, state->out, "%f ", csi->stack[i]); - fz_printf(state->ctx, state->out, "sc\n"); -} + if (img == NULL) + return; + cbuf = img->buffer; + if (cbuf == NULL) + return; + buf = cbuf->buffer; + if (buf == NULL) + return; -static void -pdf_buffer_scn(pdf_csi *csi, void *state_) -{ - pdf_buffer_state *state = (pdf_buffer_state *)state_; - int i; + fz_printf(ctx, out, "BI\n"); + fz_printf(ctx, out, "/W %d\n", img->w); + fz_printf(ctx, out, "/H %d\n", img->h); + fz_printf(ctx, out, "/BPC %d\n", img->bpc); + if (img->imagemask) + fz_printf(ctx, out, "/IM true\n"); + else if (img->colorspace == fz_device_gray(ctx)) + fz_printf(ctx, out, "/CS/G\n"); + else if (img->colorspace == fz_device_rgb(ctx)) + fz_printf(ctx, out, "/CS/RGB\n"); + else if (img->colorspace == fz_device_cmyk(ctx)) + fz_printf(ctx, out, "/CS/CMYK\n"); + else if (fz_colorspace_is_indexed(ctx, img->colorspace)) + fz_printf(ctx, out, "/CS/I\n"); + if (img->interpolate) + fz_printf(ctx, out, "/I true\n"); + fz_printf(ctx, out, "/D["); + for (i = 0; i < img->n * 2; ++i) + { + if (i > 0) + fz_putc(ctx, out, ' '); + fz_printf(ctx, out, "%g", img->decode[i]); + } + fz_printf(ctx, out, "]\n"); - for (i = 0; i < csi->top; i++) - fz_printf(state->ctx, state->out, "%f ", csi->stack[i]); - if (csi->name[0]) - fz_printf(state->ctx, state->out, "/%s ", csi->name); - fz_printf(state->ctx, state->out, "scn\n"); -} + switch (cbuf->params.type) + { + default: + fz_throw(ctx, FZ_ERROR_GENERIC, "unknown compressed buffer type"); + break; -static void -pdf_buffer_v(pdf_csi *csi, void *state_) -{ - pdf_buffer_state *state = (pdf_buffer_state *)state_; + case FZ_IMAGE_JPEG: + fz_printf(ctx, out, "/F/DCT\n"); + if (cbuf->params.u.jpeg.color_transform != -1) + fz_printf(ctx, out, "/DP<</ColorTransform %d>>\n", + cbuf->params.u.jpeg.color_transform); + break; + + case FZ_IMAGE_FAX: + fz_printf(ctx, out, "/F/CCF\n"); + fz_printf(ctx, out, "/DP<<\n"); + fz_printf(ctx, out, "/K %d\n", cbuf->params.u.fax.k); + if (cbuf->params.u.fax.columns != 1728) + fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.fax.columns); + if (cbuf->params.u.fax.rows > 0) + fz_printf(ctx, out, "/Rows %d\n", cbuf->params.u.fax.rows); + if (cbuf->params.u.fax.end_of_line) + fz_printf(ctx, out, "/EndOfLine true\n"); + if (cbuf->params.u.fax.encoded_byte_align) + fz_printf(ctx, out, "/EncodedByteAlign true\n"); + if (!cbuf->params.u.fax.end_of_block) + fz_printf(ctx, out, "/EndOfBlock false\n"); + if (cbuf->params.u.fax.black_is_1) + fz_printf(ctx, out, "/BlackIs1 true\n"); + if (cbuf->params.u.fax.damaged_rows_before_error > 0) + fz_printf(ctx, out, "/DamagedRowsBeforeError %d\n", + cbuf->params.u.fax.damaged_rows_before_error); + fz_printf(ctx, out, ">>\n"); + break; + + case FZ_IMAGE_RAW: + break; + + case FZ_IMAGE_RLD: + fz_printf(ctx, out, "/F/RL\n"); + break; + + case FZ_IMAGE_FLATE: + fz_printf(ctx, out, "/F/Fl\n"); + if (cbuf->params.u.flate.predictor > 1) + { + fz_printf(ctx, out, "/DP<<\n"); + fz_printf(ctx, out, "/Predictor %d\n", cbuf->params.u.flate.predictor); + if (cbuf->params.u.flate.columns != 1) + fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.flate.columns); + if (cbuf->params.u.flate.colors != 1) + fz_printf(ctx, out, "/Colors %d\n", cbuf->params.u.flate.colors); + if (cbuf->params.u.flate.bpc != 8) + fz_printf(ctx, out, "/BitsPerComponent %d\n", cbuf->params.u.flate.bpc); + fz_printf(ctx, out, ">>\n"); + } + break; + + case FZ_IMAGE_LZW: + fz_printf(ctx, out, "/F/LZW\n"); + if (cbuf->params.u.lzw.predictor > 1) + { + fz_printf(ctx, out, "/DP<<\n"); + fz_printf(ctx, out, "/Predictor %d\n", cbuf->params.u.lzw.predictor); + if (cbuf->params.u.lzw.columns != 1) + fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.lzw.columns); + if (cbuf->params.u.lzw.colors != 1) + fz_printf(ctx, out, "/Colors %d\n", cbuf->params.u.lzw.colors); + if (cbuf->params.u.lzw.bpc != 8) + fz_printf(ctx, out, "/BitsPerComponent %d\n", cbuf->params.u.lzw.bpc); + if (cbuf->params.u.lzw.early_change != 1) + fz_printf(ctx, out, "/EarlyChange %d\n", cbuf->params.u.lzw.early_change); + fz_printf(ctx, out, ">>\n"); + } + break; + } - fz_printf(state->ctx, state->out, "%f %f %f %f v\n", csi->stack[0], - csi->stack[1], csi->stack[2], csi->stack[3]); + fz_printf(ctx, out, "ID\n"); + fz_write(ctx, out, buf->data, buf->len); + fz_printf(ctx, out, "\nEI\n"); } static void -pdf_buffer_w(pdf_csi *csi, void *state_) +pdf_out_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f w\n", csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s sh\n", name); } static void -pdf_buffer_y(pdf_csi *csi, void *state_) +pdf_out_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "%f %f %f %f y\n", csi->stack[0], - csi->stack[1], csi->stack[2], csi->stack[3]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s Do\n", name); } static void -pdf_buffer_Do(pdf_csi *csi, void *state_) +pdf_out_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_xobject *xobj, pdf_obj *page_resources) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s Do\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s Do\n", name); } +/* marked content */ + static void -pdf_buffer_Tf(pdf_csi *csi, void *state_) +pdf_out_MP(fz_context *ctx, pdf_processor *proc, const char *tag) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s %f Tf\n", csi->name, csi->stack[0]); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s MP\n", tag); } static void -pdf_buffer_gs(pdf_csi *csi, void *state_) +pdf_out_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *properties) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s gs\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s ", tag); + pdf_output_obj(ctx, out, properties, 1); + fz_printf(ctx, out, " DP\n"); } static void -pdf_buffer_sh(pdf_csi *csi, void *state_) +pdf_out_BMC(fz_context *ctx, pdf_processor *proc, const char *tag) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_printf(state->ctx, state->out, "/%s sh\n", csi->name); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s BMC\n", tag); } static void -free_processor_buffer(pdf_csi *csi, void *state_) +pdf_out_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *properties) { - pdf_buffer_state *state = (pdf_buffer_state *)state_; - - fz_drop_output(state->ctx, state->out); - fz_free(state->ctx, state); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "/%s ", tag); + pdf_output_obj(ctx, out, properties, 1); + fz_printf(ctx, out, " BDC\n"); } static void -process_annot(pdf_csi *csi, void *state, pdf_obj *resources, pdf_annot *annot) +pdf_out_EMC(fz_context *ctx, pdf_processor *proc) { - fz_context *ctx = csi->ctx; - pdf_xobject *xobj = annot->ap; - - /* Avoid infinite recursion */ - if (xobj == NULL || pdf_mark_obj(ctx, xobj->me)) - return; + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "EMC\n"); +} - fz_try(ctx) - { - if (xobj->resources) - resources = xobj->resources; +/* compatibility */ - pdf_process_contents_object(csi, resources, xobj->contents); - } - fz_always(ctx) - { - pdf_unmark_obj(ctx, xobj->me); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } +static void +pdf_out_BX(fz_context *ctx, pdf_processor *proc) +{ + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "BX\n"); } static void -process_stream(pdf_csi *csi, void *state, pdf_lexbuf *buf) +pdf_out_EX(fz_context *ctx, pdf_processor *proc) { - pdf_process_stream(csi, buf); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_printf(ctx, out, "EX\n"); } static void -process_contents(pdf_csi *csi, void *state, pdf_obj *resources, pdf_obj *contents) +pdf_drop_imp_output_processor(fz_context *ctx, pdf_processor *proc) { - pdf_process_contents_object(csi, resources, contents); + fz_output *out = ((pdf_output_processor*)proc)->out; + fz_drop_output(ctx, out); } -static const pdf_processor pdf_processor_buffer = +static pdf_processor * +pdf_new_output_processor(fz_context *ctx, fz_output *out) { + pdf_output_processor *proc = pdf_new_processor(ctx, sizeof *proc); { - pdf_buffer_dquote, - pdf_buffer_squote, - pdf_buffer_B, - pdf_buffer_Bstar, - pdf_buffer_BDC, - pdf_buffer_BI, - pdf_buffer_BMC, - pdf_buffer_BT, - pdf_buffer_BX, - pdf_buffer_CS, - pdf_buffer_DP, - pdf_buffer_EMC, - pdf_buffer_ET, - pdf_buffer_EX, - pdf_buffer_F, - pdf_buffer_G, - pdf_buffer_J, - pdf_buffer_K, - pdf_buffer_M, - pdf_buffer_MP, - pdf_buffer_Q, - pdf_buffer_RG, - pdf_buffer_S, - pdf_buffer_SC, - pdf_buffer_SCN, - pdf_buffer_Tstar, - pdf_buffer_TD, - pdf_buffer_TJ, - pdf_buffer_TL, - pdf_buffer_Tc, - pdf_buffer_Td, - pdf_buffer_Tj, - pdf_buffer_Tm, - pdf_buffer_Tr, - pdf_buffer_Ts, - pdf_buffer_Tw, - pdf_buffer_Tz, - pdf_buffer_W, - pdf_buffer_Wstar, - pdf_buffer_b, - pdf_buffer_bstar, - pdf_buffer_c, - pdf_buffer_cm, - pdf_buffer_cs, - pdf_buffer_d, - pdf_buffer_d0, - pdf_buffer_d1, - pdf_buffer_f, - pdf_buffer_fstar, - pdf_buffer_g, - pdf_buffer_h, - pdf_buffer_i, - pdf_buffer_j, - pdf_buffer_k, - pdf_buffer_l, - pdf_buffer_m, - pdf_buffer_n, - pdf_buffer_q, - pdf_buffer_re, - pdf_buffer_rg, - pdf_buffer_ri, - pdf_buffer_s, - pdf_buffer_sc, - pdf_buffer_scn, - pdf_buffer_v, - pdf_buffer_w, - pdf_buffer_y, - pdf_buffer_Do, - pdf_buffer_Tf, - pdf_buffer_gs, - pdf_buffer_sh, - free_processor_buffer - }, - process_annot, - process_stream, - process_contents -}; + proc->super.drop_imp = pdf_drop_imp_output_processor; + + /* general graphics state */ + proc->super.op_w = pdf_out_w; + proc->super.op_j = pdf_out_j; + proc->super.op_J = pdf_out_J; + proc->super.op_M = pdf_out_M; + proc->super.op_d = pdf_out_d; + proc->super.op_ri = pdf_out_ri; + proc->super.op_i = pdf_out_i; + proc->super.op_gs_begin = pdf_out_gs_begin; + proc->super.op_gs_end = pdf_out_gs_end; + + /* transparency graphics state */ + proc->super.op_gs_BM = NULL; + proc->super.op_gs_CA = NULL; + proc->super.op_gs_ca = NULL; + proc->super.op_gs_SMask = NULL; + + /* special graphics state */ + proc->super.op_q = pdf_out_q; + proc->super.op_Q = pdf_out_Q; + proc->super.op_cm = pdf_out_cm; + + /* path construction */ + proc->super.op_m = pdf_out_m; + proc->super.op_l = pdf_out_l; + proc->super.op_c = pdf_out_c; + proc->super.op_v = pdf_out_v; + proc->super.op_y = pdf_out_y; + proc->super.op_h = pdf_out_h; + proc->super.op_re = pdf_out_re; + + /* path painting */ + proc->super.op_S = pdf_out_S; + proc->super.op_s = pdf_out_s; + proc->super.op_F = pdf_out_F; + proc->super.op_f = pdf_out_f; + proc->super.op_fstar = pdf_out_fstar; + proc->super.op_B = pdf_out_B; + proc->super.op_Bstar = pdf_out_Bstar; + proc->super.op_b = pdf_out_b; + proc->super.op_bstar = pdf_out_bstar; + proc->super.op_n = pdf_out_n; + + /* clipping paths */ + proc->super.op_W = pdf_out_W; + proc->super.op_Wstar = pdf_out_Wstar; + + /* text objects */ + proc->super.op_BT = pdf_out_BT; + proc->super.op_ET = pdf_out_ET; + + /* text state */ + proc->super.op_Tc = pdf_out_Tc; + proc->super.op_Tw = pdf_out_Tw; + proc->super.op_Tz = pdf_out_Tz; + proc->super.op_TL = pdf_out_TL; + proc->super.op_Tf = pdf_out_Tf; + proc->super.op_Tr = pdf_out_Tr; + proc->super.op_Ts = pdf_out_Ts; + + /* text positioning */ + proc->super.op_Td = pdf_out_Td; + proc->super.op_TD = pdf_out_TD; + proc->super.op_Tm = pdf_out_Tm; + proc->super.op_Tstar = pdf_out_Tstar; + + /* text showing */ + proc->super.op_TJ = pdf_out_TJ; + proc->super.op_Tj = pdf_out_Tj; + proc->super.op_squote = pdf_out_squote; + proc->super.op_dquote = pdf_out_dquote; + + /* type 3 fonts */ + proc->super.op_d0 = pdf_out_d0; + proc->super.op_d1 = pdf_out_d1; + + /* color */ + proc->super.op_CS = pdf_out_CS; + proc->super.op_cs = pdf_out_cs; + proc->super.op_SC_color = pdf_out_SC_color; + proc->super.op_sc_color = pdf_out_sc_color; + proc->super.op_SC_pattern = pdf_out_SC_pattern; + proc->super.op_sc_pattern = pdf_out_sc_pattern; + proc->super.op_SC_shade = pdf_out_SC_shade; + proc->super.op_sc_shade = pdf_out_sc_shade; + + proc->super.op_G = pdf_out_G; + proc->super.op_g = pdf_out_g; + proc->super.op_RG = pdf_out_RG; + proc->super.op_rg = pdf_out_rg; + proc->super.op_K = pdf_out_K; + proc->super.op_k = pdf_out_k; + + /* shadings, images, xobjects */ + proc->super.op_BI = pdf_out_BI; + proc->super.op_sh = pdf_out_sh; + proc->super.op_Do_image = pdf_out_Do_image; + proc->super.op_Do_form = pdf_out_Do_form; + + /* marked content */ + proc->super.op_MP = pdf_out_MP; + proc->super.op_DP = pdf_out_DP; + proc->super.op_BMC = pdf_out_BMC; + proc->super.op_BDC = pdf_out_BDC; + proc->super.op_EMC = pdf_out_EMC; + + /* compatibility */ + proc->super.op_BX = pdf_out_BX; + proc->super.op_EX = pdf_out_EX; + } -pdf_process *pdf_init_process_buffer(fz_context *ctx, pdf_process *process, fz_buffer *buffer) -{ - fz_output *out = fz_new_output_with_buffer(ctx, buffer); - pdf_buffer_state *p = NULL; + proc->out = out; - fz_var(p); + return (pdf_processor*)proc; +} +pdf_processor * +pdf_new_buffer_processor(fz_context *ctx, fz_buffer *buffer) +{ + pdf_processor *proc; + fz_output *out = fz_new_output_with_buffer(ctx, buffer); fz_try(ctx) { - p = fz_malloc_struct(ctx, pdf_buffer_state); - p->buffer = buffer; - p->out = out; - p->ctx = ctx; + proc = pdf_new_output_processor(ctx, out); } fz_catch(ctx) { fz_drop_output(ctx, out); fz_rethrow(ctx); } - - process->state = p; - process->processor = &pdf_processor_buffer; - return process; + return proc; } diff --git a/source/pdf/pdf-op-filter.c b/source/pdf/pdf-op-filter.c index ec08b305..c030f468 100644 --- a/source/pdf/pdf-op-filter.c +++ b/source/pdf/pdf-op-filter.c @@ -1,11 +1,11 @@ -#include "pdf-interpret-imp.h" +#include "mupdf/pdf.h" typedef struct filter_gstate_s filter_gstate; typedef enum { FLUSH_CTM = 1, - FLUSH_COLOR = 2, + FLUSH_COLOR_F = 2, FLUSH_COLOR_S = 4, FLUSH_ALL = 7, @@ -19,76 +19,74 @@ struct filter_gstate_s int pushed; fz_matrix ctm; fz_matrix current_ctm; - float color[FZ_MAX_COLORS]; - int color_n; - float current_color[FZ_MAX_COLORS]; - int current_color_n; - float color_s[FZ_MAX_COLORS]; - int color_s_n; - float current_color_s[FZ_MAX_COLORS]; - int current_color_s_n; - char cs[256]; - char cs_s[256]; - char cs_name[256]; - char cs_name_s[256]; - char current_cs[256]; - char current_cs_s[256]; - char current_cs_name[256]; - char current_cs_name_s[256]; + struct + { + char name[256]; + fz_colorspace *cs; + } cs, CS, current_cs, current_CS; + struct + { + char name[256]; + pdf_pattern *pat; + fz_shade *shd; + int n; + float c[FZ_MAX_COLORS]; + } sc, SC, current_sc, current_SC; + struct + { + fz_linecap linecap; + fz_linejoin linejoin; + float linewidth; + float miterlimit; + } stroke, current_stroke; }; -typedef struct pdf_filter_state_s +typedef struct pdf_filter_processor_s { - pdf_process process; - fz_context *ctx; + pdf_processor super; + pdf_processor *chain; filter_gstate *gstate; - pdf_obj *resources; -} pdf_filter_state; + pdf_document *doc; + pdf_obj *old_rdb, *new_rdb; +} pdf_filter_processor; -static void insert_resource_name(pdf_csi *csi, pdf_filter_state *state, const char *key, const char *name) +static void +copy_resource(fz_context *ctx, pdf_filter_processor *p, const char *key, const char *name) { - fz_context *ctx = csi->ctx; - pdf_obj *xobj; - pdf_obj *obj; + pdf_obj *res, *obj; - if (!state->resources || !name || name[0] == 0) + if (!name || name[0] == 0) return; - xobj = pdf_dict_gets(ctx, csi->rdb, key); - obj = pdf_dict_gets(ctx, xobj, name); - - xobj = pdf_dict_gets(ctx, state->resources, key); - if (xobj == NULL) { - xobj = pdf_new_dict(csi->ctx, csi->doc, 1); - pdf_dict_puts_drop(ctx, state->resources, key, xobj); + res = pdf_dict_gets(ctx, p->old_rdb, key); + obj = pdf_dict_gets(ctx, res, name); + if (obj) + { + res = pdf_dict_gets(ctx, p->new_rdb, key); + if (!res) + { + res = pdf_new_dict(ctx, p->doc, 1); + pdf_dict_puts_drop(ctx, p->new_rdb, key, res); + } + pdf_dict_putp(ctx, res, name, obj); } - pdf_dict_putp(ctx, xobj, name, obj); } -static void insert_resource(pdf_csi *csi, pdf_filter_state *state, const char *key) -{ - insert_resource_name(csi, state, key, csi->name); -} - -static inline void call_op(pdf_csi *csi, pdf_filter_state *state, int op) -{ - pdf_process_op(csi, op, &state->process); -} - -static void filter_push(pdf_csi *csi, pdf_filter_state *state) +static void +filter_push(fz_context *ctx, pdf_filter_processor *p) { - filter_gstate *gstate = state->gstate; - filter_gstate *new_gstate = fz_malloc_struct(state->ctx, filter_gstate); - + filter_gstate *gstate = p->gstate; + filter_gstate *new_gstate = fz_malloc_struct(ctx, filter_gstate); *new_gstate = *gstate; new_gstate->pushed = 0; new_gstate->next = gstate; - state->gstate = new_gstate; + p->gstate = new_gstate; } -static int filter_pop(pdf_csi *csi, pdf_filter_state *state) +static int +filter_pop(fz_context *ctx, pdf_filter_processor *p) { - filter_gstate *gstate = state->gstate; + filter_gstate *gstate = p->gstate; filter_gstate *old = gstate->next; /* We are at the top, so nothing to pop! */ @@ -96,88 +94,47 @@ static int filter_pop(pdf_csi *csi, pdf_filter_state *state) return 1; if (gstate->pushed) - call_op(csi, state, PDF_OP_Q); + if (p->chain->op_Q) + p->chain->op_Q(ctx, p->chain); - fz_free(state->ctx, gstate); - state->gstate = old; + fz_free(ctx, gstate); + p->gstate = old; return 0; } -static void forward(pdf_csi *csi, pdf_filter_state *state, int op, float *f_argv, int f_argc, char *arg) -{ - int top = csi->top; - int to_save = top; - float save_f[FZ_MAX_COLORS]; - char save_name[sizeof(csi->name)]; - int i; - - /* Store the stack */ - if (to_save > f_argc) - to_save = 6; - for (i = 0; i < to_save; i++) - { - save_f[i] = csi->stack[i]; - csi->stack[i] = f_argv[i]; - } - for (;i < f_argc; i++) - { - csi->stack[i] = f_argv[i]; - } - csi->top = f_argc; - - /* Store the name */ - fz_strlcpy(save_name, csi->name, sizeof(csi->name)); - if (arg) - { - fz_strlcpy(csi->name, arg, sizeof(csi->name)); - } - else - { - csi->name[0] = 0; - } - - call_op(csi, state, op); - - /* Restore the name */ - fz_strlcpy(csi->name, save_name, sizeof(save_name)); - - /* Restore the stack */ - for (i = 0; i < to_save; i++) - csi->stack[i] = save_f[i]; - csi->top = top; -} - /* We never allow the topmost gstate to be changed. This allows us * to pop back to the zeroth level and be sure that our gstate is * sane. This is important for being able to add new operators at * the end of pages in a sane way. */ static filter_gstate * -gstate_to_update(pdf_csi *csi, pdf_filter_state *state) +gstate_to_update(fz_context *ctx, pdf_filter_processor *p) { - filter_gstate *gstate = state->gstate; + filter_gstate *gstate = p->gstate; /* If we're not the top, that's fine */ if (gstate->next != NULL) return gstate; /* We are the top. Push a group, so we're not */ - filter_push(csi, state); - gstate = state->gstate; + filter_push(ctx, p); + gstate = p->gstate; gstate->pushed = 1; - call_op(csi, state, PDF_OP_q); + if (p->chain->op_q) + p->chain->op_q(ctx, p->chain); - return state->gstate; + return p->gstate; } -static void filter_flush(pdf_csi *csi, pdf_filter_state *state, int flush) +static void filter_flush(fz_context *ctx, pdf_filter_processor *p, int flush) { - filter_gstate *gstate = state->gstate; + filter_gstate *gstate = gstate_to_update(ctx, p); int i; if (gstate->pushed == 0) { gstate->pushed = 1; - call_op(csi, state, PDF_OP_q); + if (p->chain->op_q) + p->chain->op_q(ctx, p->chain); } if (flush & FLUSH_CTM) @@ -188,7 +145,15 @@ static void filter_flush(pdf_csi *csi, pdf_filter_state *state, int flush) { fz_matrix current = gstate->current_ctm; - forward(csi, state, PDF_OP_cm, (float *)&gstate->ctm.a, 6, NULL); + if (p->chain->op_cm) + p->chain->op_cm(ctx, p->chain, + gstate->ctm.a, + gstate->ctm.b, + gstate->ctm.c, + gstate->ctm.d, + gstate->ctm.e, + gstate->ctm.f); + fz_concat(&gstate->current_ctm, ¤t, &gstate->ctm); gstate->ctm.a = 1; gstate->ctm.b = 0; @@ -198,1036 +163,1094 @@ static void filter_flush(pdf_csi *csi, pdf_filter_state *state, int flush) gstate->ctm.f = 0; } } - if (flush & FLUSH_COLOR) + + if (flush & FLUSH_COLOR_F) { - if (strcmp(gstate->cs, gstate->current_cs) || - gstate->color_n != gstate->current_color_n) + if (gstate->cs.cs == fz_device_gray(ctx) && !gstate->sc.pat && !gstate->sc.shd && gstate->sc.n == 1) { - /* Colorspace has changed. Send both colorspace (and - * color if we have it. */ - if (!strcmp(gstate->cs, "DeviceRGB")) - { - forward(csi, state, PDF_OP_rg, gstate->color, 3, NULL); - } - else if (!strcmp(gstate->cs, "DeviceGray")) - { - forward(csi, state, PDF_OP_g, gstate->color, 1, NULL); - } - else if (!strcmp(gstate->cs, "DeviceCMYK")) - { - forward(csi, state, PDF_OP_k, gstate->color, 4, NULL); - } - else if (gstate->cs_name[0]) - { - if (strcmp(gstate->cs, gstate->current_cs)) - { - forward(csi, state, PDF_OP_cs, NULL, 0, gstate->cs); - } - forward(csi, state, PDF_OP_scn, gstate->color, gstate->color_n, gstate->cs_name); - } - else if (gstate->color_n > 0) - { - if (strcmp(gstate->cs, gstate->current_cs)) - { - forward(csi, state, PDF_OP_cs, NULL, 0, gstate->cs); - } - forward(csi, state, PDF_OP_scn, gstate->color, gstate->color_n, NULL); - } - else - { - forward(csi, state, PDF_OP_cs, NULL, 0, gstate->cs); - } - strcpy(gstate->current_cs, gstate->cs); - strcpy(gstate->current_cs_name, gstate->cs_name); - gstate->current_color_n = gstate->color_n; - for (i = 0; i < gstate->color_n; i++) - gstate->current_color[i] = gstate->color[i]; + if (p->chain->op_g) + p->chain->op_g(ctx, p->chain, gstate->sc.c[0]); + goto done_sc; } - else if (strcmp(gstate->cs_name, gstate->current_cs_name)) + if (gstate->cs.cs == fz_device_rgb(ctx) && !gstate->sc.pat && !gstate->sc.shd && gstate->sc.n == 3) { - /* Pattern name has changed */ - forward(csi, state, PDF_OP_scn, gstate->color, gstate->color_n, gstate->cs_name); - strcpy(gstate->current_cs_name, gstate->cs_name); + if (p->chain->op_rg) + p->chain->op_rg(ctx, p->chain, gstate->sc.c[0], gstate->sc.c[1], gstate->sc.c[2]); + goto done_sc; } - else + if (gstate->cs.cs == fz_device_cmyk(ctx) && !gstate->sc.pat && !gstate->sc.shd && gstate->sc.n == 4) { - /* Has the color changed? */ - for (i = 0; i < gstate->color_n; i++) - { - if (gstate->color[i] != gstate->current_color[i]) - break; - } - if (i == gstate->color_n) - { - /* The color has not changed. Do nothing. */ - } - else if (!strcmp(gstate->cs, "DeviceRGB")) - { - forward(csi, state, PDF_OP_rg, gstate->color, 3, NULL); - } - else if (!strcmp(gstate->cs, "DeviceGray")) - { - forward(csi, state, PDF_OP_g, gstate->color, 1, NULL); - } - else if (!strcmp(gstate->cs, "DeviceCMYK")) + if (p->chain->op_k) + p->chain->op_k(ctx, p->chain, gstate->sc.c[0], gstate->sc.c[1], gstate->sc.c[2], gstate->sc.c[3]); + goto done_sc; + } + + if (strcmp(gstate->cs.name, gstate->current_cs.name)) + { + if (p->chain->op_cs) + p->chain->op_cs(ctx, p->chain, gstate->cs.name, gstate->cs.cs); + } + + /* pattern or shading */ + if (gstate->sc.name[0]) + { + int emit = 0; + if (strcmp(gstate->sc.name, gstate->current_sc.name)) + emit = 1; + if (gstate->sc.n != gstate->current_sc.n) + emit = 1; + else + for (i = 0; i < gstate->sc.n; ++i) + if (gstate->sc.c[i] != gstate->current_sc.c[i]) + emit = 1; + if (emit) { - forward(csi, state, PDF_OP_k, gstate->color, 4, NULL); + if (gstate->sc.pat) + if (p->chain->op_sc_pattern) + p->chain->op_sc_pattern(ctx, p->chain, gstate->sc.name, gstate->sc.pat, gstate->sc.n, gstate->sc.c); + if (gstate->sc.shd) + if (p->chain->op_sc_shade) + p->chain->op_sc_shade(ctx, p->chain, gstate->sc.name, gstate->sc.shd); } + } + + /* plain color */ + else + { + int emit = 0; + if (gstate->sc.n != gstate->current_sc.n) + emit = 1; else + for (i = 0; i < gstate->sc.n; ++i) + if (gstate->sc.c[i] != gstate->current_sc.c[i]) + emit = 1; + if (emit) { - forward(csi, state, PDF_OP_scn, gstate->color, gstate->color_n, NULL); + if (p->chain->op_sc_color) + p->chain->op_sc_color(ctx, p->chain, gstate->sc.n, gstate->sc.c); } - for (; i < gstate->color_n; i++) - gstate->current_color[i] = gstate->color[i]; } + +done_sc: + gstate->current_cs = gstate->cs; + gstate->current_sc = gstate->sc; } + if (flush & FLUSH_COLOR_S) { - if (strcmp(gstate->cs_s, gstate->current_cs_s) || - gstate->color_s_n != gstate->current_color_s_n) + if (gstate->CS.cs == fz_device_gray(ctx) && !gstate->SC.pat && !gstate->SC.shd && gstate->SC.n == 1) { - /* Colorspace has changed. Send both colorspace (and - * color if we have it. */ - if (!strcmp(gstate->cs_s, "DeviceRGB")) - { - forward(csi, state, PDF_OP_RG, gstate->color_s, 3, NULL); - } - else if (!strcmp(gstate->cs_s, "DeviceGray")) - { - forward(csi, state, PDF_OP_G, gstate->color_s, 1, NULL); - } - else if (!strcmp(gstate->cs_s, "DeviceCMYK")) - { - forward(csi, state, PDF_OP_K, gstate->color_s, 4, NULL); - } - else if (gstate->cs_name_s[0]) - { - if (strcmp(gstate->cs_s, gstate->current_cs_s)) - { - forward(csi, state, PDF_OP_CS, NULL, 0, gstate->cs_s); - } - forward(csi, state, PDF_OP_SCN, gstate->color_s, gstate->color_s_n, gstate->cs_name_s); - } - else if (gstate->color_s_n > 0) - { - if (strcmp(gstate->cs_s, gstate->current_cs_s)) - { - forward(csi, state, PDF_OP_CS, NULL, 0, gstate->cs_s); - } - forward(csi, state, PDF_OP_SCN, gstate->color_s, gstate->color_s_n, NULL); - } - else - { - forward(csi, state, PDF_OP_CS, NULL, 0, gstate->cs_s); - } - strcpy(gstate->current_cs_s, gstate->cs_s); - strcpy(gstate->current_cs_name_s, gstate->cs_name_s); - gstate->current_color_s_n = gstate->color_s_n; - for (i = 0; i < gstate->color_s_n; i++) - gstate->current_color_s[i] = gstate->color_s[i]; + if (p->chain->op_G) + p->chain->op_G(ctx, p->chain, gstate->SC.c[0]); + goto done_SC; } - else if (strcmp(gstate->cs_name_s, gstate->current_cs_name_s)) + if (gstate->CS.cs == fz_device_rgb(ctx) && !gstate->SC.pat && !gstate->SC.shd && gstate->SC.n == 3) { - /* Pattern name has changed */ - forward(csi, state, PDF_OP_SCN, gstate->color_s, gstate->color_s_n, gstate->cs_name_s); - strcpy(gstate->current_cs_name_s, gstate->cs_name_s); + if (p->chain->op_RG) + p->chain->op_RG(ctx, p->chain, gstate->SC.c[0], gstate->SC.c[1], gstate->SC.c[2]); + goto done_SC; } - else + if (gstate->CS.cs == fz_device_cmyk(ctx) && !gstate->SC.pat && !gstate->SC.shd && gstate->SC.n == 4) { - /* Has the color changed? */ - int i; + if (p->chain->op_K) + p->chain->op_K(ctx, p->chain, gstate->SC.c[0], gstate->SC.c[1], gstate->SC.c[2], gstate->SC.c[3]); + goto done_SC; + } - for (i = 0; i < gstate->color_s_n; i++) - { - if (gstate->color_s[i] != gstate->current_color_s[i]) - break; - } - if (i == gstate->color_s_n) - { - /* The color has not changed. Do nothing. */ - } - else if (!strcmp(gstate->cs_s, "DeviceRGB")) - { - forward(csi, state, PDF_OP_RG, gstate->color_s, 3, NULL); - } - else if (!strcmp(gstate->cs_s, "DeviceGray")) - { - forward(csi, state, PDF_OP_G, gstate->color_s, 1, NULL); - } - else if (!strcmp(gstate->cs_s, "DeviceCMYK")) + if (strcmp(gstate->CS.name, gstate->current_CS.name)) + { + if (p->chain->op_CS) + p->chain->op_CS(ctx, p->chain, gstate->CS.name, gstate->CS.cs); + } + + /* pattern or shading */ + if (gstate->SC.name[0]) + { + int emit = 0; + if (strcmp(gstate->SC.name, gstate->current_SC.name)) + emit = 1; + if (gstate->SC.n != gstate->current_SC.n) + emit = 1; + else + for (i = 0; i < gstate->SC.n; ++i) + if (gstate->SC.c[i] != gstate->current_SC.c[i]) + emit = 1; + if (emit) { - forward(csi, state, PDF_OP_K, gstate->color_s, 4, NULL); + if (gstate->SC.pat) + if (p->chain->op_SC_pattern) + p->chain->op_SC_pattern(ctx, p->chain, gstate->SC.name, gstate->SC.pat, gstate->SC.n, gstate->SC.c); + if (gstate->SC.shd) + if (p->chain->op_SC_shade) + p->chain->op_SC_shade(ctx, p->chain, gstate->SC.name, gstate->SC.shd); } + } + + /* plain color */ + else + { + int emit = 0; + if (gstate->SC.n != gstate->current_SC.n) + emit = 1; else + for (i = 0; i < gstate->SC.n; ++i) + if (gstate->SC.c[i] != gstate->current_SC.c[i]) + emit = 1; + if (emit) { - forward(csi, state, PDF_OP_SCN, gstate->color_s, gstate->color_s_n, NULL); + if (p->chain->op_SC_color) + p->chain->op_SC_color(ctx, p->chain, gstate->SC.n, gstate->SC.c); } - for (; i < gstate->color_s_n; i++) - gstate->current_color_s[i] = gstate->color_s[i]; } + +done_SC: + gstate->current_CS = gstate->CS; + gstate->current_SC = gstate->SC; + } + + if (flush & FLUSH_STROKE) + { + if (gstate->stroke.linecap != gstate->current_stroke.linecap) + { + if (p->chain->op_J) + p->chain->op_J(ctx, p->chain, gstate->stroke.linecap); + } + if (gstate->stroke.linejoin != gstate->current_stroke.linejoin) + { + if (p->chain->op_j) + p->chain->op_j(ctx, p->chain, gstate->stroke.linejoin); + } + if (gstate->stroke.linewidth != gstate->current_stroke.linewidth) + { + if (p->chain->op_w) + p->chain->op_w(ctx, p->chain, gstate->stroke.linewidth); + } + if (gstate->stroke.miterlimit != gstate->current_stroke.miterlimit) + { + if (p->chain->op_M) + p->chain->op_M(ctx, p->chain, gstate->stroke.linewidth); + } + gstate->current_stroke = gstate->stroke; } } +/* general graphics state */ + static void -pdf_filter_dquote(pdf_csi *csi, void *state_) +pdf_filter_w(fz_context *ctx, pdf_processor *proc, float linewidth) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_dquote); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + gstate->stroke.linewidth = linewidth; } static void -pdf_filter_squote(pdf_csi *csi, void *state_) +pdf_filter_j(fz_context *ctx, pdf_processor *proc, int linejoin) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_squote); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + gstate->stroke.linejoin = linejoin; } static void -pdf_filter_B(pdf_csi *csi, void *state_) +pdf_filter_J(fz_context *ctx, pdf_processor *proc, int linecap) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_B); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + gstate->stroke.linecap = linecap; } static void -pdf_filter_Bstar(pdf_csi *csi, void *state_) +pdf_filter_M(fz_context *ctx, pdf_processor *proc, float miterlimit) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_Bstar); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + gstate->stroke.miterlimit = miterlimit; } static void -pdf_filter_BDC(pdf_csi *csi, void *state_) +pdf_filter_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - insert_resource_name(csi, state, "Properties", pdf_to_name(csi->ctx, csi->obj)); - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_BDC); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_d) + p->chain->op_d(ctx, p->chain, array, phase); } static void -pdf_filter_BI(pdf_csi *csi, void *state_) +pdf_filter_ri(fz_context *ctx, pdf_processor *proc, const char *intent) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_FILL); - call_op(csi, state, PDF_OP_BI); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_ri) + p->chain->op_ri(ctx, p->chain, intent); } static void -pdf_filter_BMC(pdf_csi *csi, void *state_) +pdf_filter_i(fz_context *ctx, pdf_processor *proc, float flatness) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_BMC); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_i) + p->chain->op_i(ctx, p->chain, flatness); } static void -pdf_filter_BT(pdf_csi *csi, void *state_) +pdf_filter_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_BT); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_gs_begin) + p->chain->op_gs_begin(ctx, p->chain, name, extgstate); + copy_resource(ctx, p, "ExtGState", name); } static void -pdf_filter_BX(pdf_csi *csi, void *state_) +pdf_filter_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_BX); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + if (p->chain->op_gs_BM) + p->chain->op_gs_BM(ctx, p->chain, blendmode); } static void -pdf_filter_CS(pdf_csi *csi, void *state_) +pdf_filter_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - - insert_resource(csi, state, "ColorSpace"); - - fz_strlcpy(gstate->cs_s, csi->name, sizeof(gstate->cs_s)); - gstate->current_color_s_n = 0; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + if (p->chain->op_gs_CA) + p->chain->op_gs_CA(ctx, p->chain, alpha); } static void -pdf_filter_DP(pdf_csi *csi, void *state_) +pdf_filter_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - insert_resource_name(csi, state, "Properties", pdf_to_name(csi->ctx, csi->obj)); - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_DP); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + if (p->chain->op_gs_ca) + p->chain->op_gs_ca(ctx, p->chain, alpha); } static void -pdf_filter_EMC(pdf_csi *csi, void *state_) +pdf_filter_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_xobject *smask, pdf_obj *page_resources, float *bc, int luminosity) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_EMC); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + if (p->chain->op_gs_SMask) + p->chain->op_gs_SMask(ctx, p->chain, smask, page_resources, bc, luminosity); } static void -pdf_filter_ET(pdf_csi *csi, void *state_) +pdf_filter_gs_end(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_ET); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + if (p->chain->op_gs_end) + p->chain->op_gs_end(ctx, p->chain); } +/* special graphics state */ + static void -pdf_filter_EX(pdf_csi *csi, void *state_) +pdf_filter_q(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_EX); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_push(ctx, p); } static void -pdf_filter_F(pdf_csi *csi, void *state_) +pdf_filter_Q(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_FILL); - call_op(csi, state, PDF_OP_F); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_pop(ctx, p); } static void -pdf_filter_G(pdf_csi *csi, void *state_) +pdf_filter_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + fz_matrix old, ctm; - strcpy(gstate->cs_s, "DeviceGray"); - strcpy(gstate->cs_name_s, ""); - gstate->color_s[0] = csi->stack[0]; - gstate->color_s_n = 1; -} + /* If we're being given an identity matrix, don't bother sending it */ + if (a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0) + return; -static void -pdf_filter_J(pdf_csi *csi, void *state_) -{ - pdf_filter_state *state = (pdf_filter_state *)state_; + ctm.a = a; + ctm.b = b; + ctm.c = c; + ctm.d = d; + ctm.e = e; + ctm.f = f; - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_J); + old = gstate->ctm; + fz_concat(&gstate->ctm, &ctm, &old); } +/* path construction */ + static void -pdf_filter_K(pdf_csi *csi, void *state_) +pdf_filter_m(fz_context *ctx, pdf_processor *proc, float x, float y) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - - strcpy(gstate->cs_s, "DeviceCMYK"); - strcpy(gstate->cs_name_s, ""); - gstate->color_s[0] = csi->stack[0]; - gstate->color_s[1] = csi->stack[1]; - gstate->color_s[2] = csi->stack[2]; - gstate->color_s[3] = csi->stack[3]; - gstate->color_s_n = 4; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_m) + p->chain->op_m(ctx, p->chain, x, y); } static void -pdf_filter_M(pdf_csi *csi, void *state_) +pdf_filter_l(fz_context *ctx, pdf_processor *proc, float x, float y) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_M); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_l) + p->chain->op_l(ctx, p->chain, x, y); } static void -pdf_filter_MP(pdf_csi *csi, void *state_) +pdf_filter_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_MP); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_c) + p->chain->op_c(ctx, p->chain, x1, y1, x2, y2, x3, y3); } static void -pdf_filter_Q(pdf_csi *csi, void *state_) +pdf_filter_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_pop(csi, state); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_v) + p->chain->op_v(ctx, p->chain, x2, y2, x3, y3); } static void -pdf_filter_RG(pdf_csi *csi, void *state_) +pdf_filter_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - - strcpy(gstate->cs_s, "DeviceRGB"); - strcpy(gstate->cs_name_s, ""); - gstate->color_s[0] = csi->stack[0]; - gstate->color_s[1] = csi->stack[1]; - gstate->color_s[2] = csi->stack[2]; - gstate->color_s_n = 3; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_y) + p->chain->op_y(ctx, p->chain, x1, y1, x3, y3); } static void -pdf_filter_S(pdf_csi *csi, void *state_) +pdf_filter_h(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_STROKE); - call_op(csi, state, PDF_OP_S); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_h) + p->chain->op_h(ctx, p->chain); } static void -pdf_filter_SCN(pdf_csi *csi, void *state_) +pdf_filter_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - int i; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_re) + p->chain->op_re(ctx, p->chain, x, y, w, h); +} - if (csi->name[0]) - insert_resource(csi, state, "Pattern"); +/* path painting */ - fz_strlcpy(gstate->cs_name_s, csi->name, sizeof(csi->name)); - for (i = 0; i < csi->top; i++) - { - gstate->color_s[i] = csi->stack[i]; - } - gstate->color_s_n = csi->top; +static void +pdf_filter_S(fz_context *ctx, pdf_processor *proc) +{ + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_STROKE); + if (p->chain->op_S) + p->chain->op_S(ctx, p->chain); } static void -pdf_filter_Tstar(pdf_csi *csi, void *state_) +pdf_filter_s(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_Tstar); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_STROKE); + if (p->chain->op_s) + p->chain->op_s(ctx, p->chain); } static void -pdf_filter_TD(pdf_csi *csi, void *state_) +pdf_filter_F(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_TD); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_FILL); + if (p->chain->op_F) + p->chain->op_F(ctx, p->chain); } static void -pdf_filter_TJ(pdf_csi *csi, void *state_) +pdf_filter_f(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_TJ); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_FILL); + if (p->chain->op_f) + p->chain->op_f(ctx, p->chain); } static void -pdf_filter_TL(pdf_csi *csi, void *state_) +pdf_filter_fstar(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_TL); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_FILL); + if (p->chain->op_fstar) + p->chain->op_fstar(ctx, p->chain); } static void -pdf_filter_Tc(pdf_csi *csi, void *state_) +pdf_filter_B(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_Tc); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_B) + p->chain->op_B(ctx, p->chain); } static void -pdf_filter_Td(pdf_csi *csi, void *state_) +pdf_filter_Bstar(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_Td); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_Bstar) + p->chain->op_Bstar(ctx, p->chain); } static void -pdf_filter_Tj(pdf_csi *csi, void *state_) +pdf_filter_b(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_Tj); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_b) + p->chain->op_b(ctx, p->chain); } static void -pdf_filter_Tm(pdf_csi *csi, void *state_) +pdf_filter_bstar(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_Tm); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_bstar) + p->chain->op_bstar(ctx, p->chain); } static void -pdf_filter_Tr(pdf_csi *csi, void *state_) +pdf_filter_n(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_Tr); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_n) + p->chain->op_n(ctx, p->chain); } +/* clipping paths */ + static void -pdf_filter_Ts(pdf_csi *csi, void *state_) +pdf_filter_W(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_Ts); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_W) + p->chain->op_W(ctx, p->chain); } static void -pdf_filter_Tw(pdf_csi *csi, void *state_) +pdf_filter_Wstar(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_Tw); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_Wstar) + p->chain->op_Wstar(ctx, p->chain); } +/* text objects */ + static void -pdf_filter_Tz(pdf_csi *csi, void *state_) +pdf_filter_BT(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_Tz); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_BT) + p->chain->op_BT(ctx, p->chain); } static void -pdf_filter_W(pdf_csi *csi, void *state_) +pdf_filter_ET(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_W); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_ET) + p->chain->op_ET(ctx, p->chain); } +/* text state */ + static void -pdf_filter_Wstar(pdf_csi *csi, void *state_) +pdf_filter_Tc(fz_context *ctx, pdf_processor *proc, float charspace) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_Wstar); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_Tc) + p->chain->op_Tc(ctx, p->chain, charspace); } static void -pdf_filter_b(pdf_csi *csi, void *state_) +pdf_filter_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_b); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_Tw) + p->chain->op_Tw(ctx, p->chain, wordspace); } static void -pdf_filter_bstar(pdf_csi *csi, void *state_) +pdf_filter_Tz(fz_context *ctx, pdf_processor *proc, float scale) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_bstar); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_Tz) + p->chain->op_Tz(ctx, p->chain, scale); } static void -pdf_filter_c(pdf_csi *csi, void *state_) +pdf_filter_TL(fz_context *ctx, pdf_processor *proc, float leading) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_c); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_TL) + p->chain->op_TL(ctx, p->chain, leading); } static void -pdf_filter_cm(pdf_csi *csi, void *state_) +pdf_filter_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - fz_matrix old, ctm; - - ctm.a = (csi->top > 0 ? csi->stack[0] : 0.0); - ctm.b = (csi->top > 1 ? csi->stack[1] : 0.0); - ctm.c = (csi->top > 2 ? csi->stack[2] : 0.0); - ctm.d = (csi->top > 3 ? csi->stack[3] : 0.0); - ctm.e = (csi->top > 4 ? csi->stack[4] : 0.0); - ctm.f = (csi->top > 5 ? csi->stack[5] : 0.0); - - /* If we're being given an identity matrix, don't bother sending it */ - if (ctm.a == 1 && ctm.b == 0 && ctm.c == 0 && ctm.d == 1 && - ctm.e == 0.0f && ctm.f == 0) - return; - - old = gstate->ctm; - fz_concat(&gstate->ctm, &ctm, &old); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_Tf) + p->chain->op_Tf(ctx, p->chain, name, font, size); + copy_resource(ctx, p, "Font", name); } static void -pdf_filter_cs(pdf_csi *csi, void *state_) +pdf_filter_Tr(fz_context *ctx, pdf_processor *proc, int render) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - - insert_resource(csi, state, "ColorSpace"); - - fz_strlcpy(gstate->cs, csi->name, sizeof(csi->name)); - gstate->color_n = 0; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_Tr) + p->chain->op_Tr(ctx, p->chain, render); } static void -pdf_filter_d(pdf_csi *csi, void *state_) +pdf_filter_Ts(fz_context *ctx, pdf_processor *proc, float rise) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_d); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_Ts) + p->chain->op_Ts(ctx, p->chain, rise); } +/* text positioning */ + static void -pdf_filter_d0(pdf_csi *csi, void *state_) +pdf_filter_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - call_op(csi, state, PDF_OP_d0); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_Td) + p->chain->op_Td(ctx, p->chain, tx, ty); } static void -pdf_filter_d1(pdf_csi *csi, void *state_) +pdf_filter_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - call_op(csi, state, PDF_OP_d1); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_TD) + p->chain->op_TD(ctx, p->chain, tx, ty); } static void -pdf_filter_f(pdf_csi *csi, void *state_) +pdf_filter_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_FILL); - call_op(csi, state, PDF_OP_f); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_Tm) + p->chain->op_Tm(ctx, p->chain, a, b, c, d, e, f); } static void -pdf_filter_fstar(pdf_csi *csi, void *state_) +pdf_filter_Tstar(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_FILL); - call_op(csi, state, PDF_OP_fstar); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_CTM); + if (p->chain->op_Tstar) + p->chain->op_Tstar(ctx, p->chain); } +/* text showing */ + static void -pdf_filter_g(pdf_csi *csi, void *state_) +pdf_filter_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - - strcpy(gstate->cs, "DeviceGray"); - strcpy(gstate->cs_name, ""); - gstate->color[0] = csi->stack[0]; - gstate->color_n = 1; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_TJ) + p->chain->op_TJ(ctx, p->chain, array); } static void -pdf_filter_h(pdf_csi *csi, void *state_) +pdf_filter_Tj(fz_context *ctx, pdf_processor *proc, char *str, int len) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_h); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_Tj) + p->chain->op_Tj(ctx, p->chain, str, len); } static void -pdf_filter_i(pdf_csi *csi, void *state_) +pdf_filter_squote(fz_context *ctx, pdf_processor *proc, char *str, int len) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_i); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_squote) + p->chain->op_squote(ctx, p->chain, str, len); } static void -pdf_filter_j(pdf_csi *csi, void *state_) +pdf_filter_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, int len) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_j); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_dquote) + p->chain->op_dquote(ctx, p->chain, aw, ac, str, len); } +/* type 3 fonts */ + static void -pdf_filter_k(pdf_csi *csi, void *state_) +pdf_filter_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - - strcpy(gstate->cs, "DeviceCMYK"); - strcpy(gstate->cs_name, ""); - gstate->color[0] = csi->stack[0]; - gstate->color[1] = csi->stack[1]; - gstate->color[2] = csi->stack[2]; - gstate->color[3] = csi->stack[3]; - gstate->color_n = 4; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_d0) + p->chain->op_d0(ctx, p->chain, wx, wy); } static void -pdf_filter_l(pdf_csi *csi, void *state_) +pdf_filter_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_l); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_d1) + p->chain->op_d1(ctx, p->chain, wx, wy, llx, lly, urx, ury); } +/* color */ + static void -pdf_filter_m(pdf_csi *csi, void *state_) +pdf_filter_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_m); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + fz_strlcpy(gstate->CS.name, name, sizeof gstate->CS.name); + gstate->CS.cs = cs; + copy_resource(ctx, p, "ColorSpace", name); } static void -pdf_filter_n(pdf_csi *csi, void *state_) +pdf_filter_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_n); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + fz_strlcpy(gstate->cs.name, name, sizeof gstate->cs.name); + gstate->cs.cs = cs; + copy_resource(ctx, p, "ColorSpace", name); } static void -pdf_filter_q(pdf_csi *csi, void *state_) +pdf_filter_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_push(csi, state); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + int i; + fz_strlcpy(gstate->SC.name, name, sizeof gstate->SC.name); + gstate->SC.pat = pat; + gstate->SC.shd = NULL; + gstate->SC.n = n; + for (i = 0; i < n; ++i) + gstate->SC.c[i] = color[i]; + copy_resource(ctx, p, "Pattern", name); } static void -pdf_filter_re(pdf_csi *csi, void *state_) +pdf_filter_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_re); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + int i; + fz_strlcpy(gstate->sc.name, name, sizeof gstate->sc.name); + gstate->sc.pat = pat; + gstate->sc.shd = NULL; + gstate->sc.n = n; + for (i = 0; i < n; ++i) + gstate->sc.c[i] = color[i]; + copy_resource(ctx, p, "Pattern", name); } static void -pdf_filter_rg(pdf_csi *csi, void *state_) +pdf_filter_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); - - strcpy(gstate->cs, "DeviceRGB"); - strcpy(gstate->cs_name, ""); - gstate->color[0] = csi->stack[0]; - gstate->color[1] = csi->stack[1]; - gstate->color[2] = csi->stack[2]; - gstate->color_n = 3; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + fz_strlcpy(gstate->SC.name, name, sizeof gstate->SC.name); + gstate->SC.pat = NULL; + gstate->SC.shd = shade; + gstate->SC.n = 0; + copy_resource(ctx, p, "Pattern", name); } static void -pdf_filter_ri(pdf_csi *csi, void *state_) +pdf_filter_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_ri); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + fz_strlcpy(gstate->sc.name, name, sizeof gstate->sc.name); + gstate->sc.pat = NULL; + gstate->sc.shd = shade; + gstate->sc.n = 0; + copy_resource(ctx, p, "Pattern", name); } static void -pdf_filter_s(pdf_csi *csi, void *state_) +pdf_filter_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_STROKE); - call_op(csi, state, PDF_OP_s); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); + int i; + gstate->SC.name[0] = 0; + gstate->SC.pat = NULL; + gstate->SC.shd = NULL; + gstate->SC.n = n; + for (i = 0; i < n; ++i) + gstate->SC.c[i] = color[i]; } static void -pdf_filter_scn(pdf_csi *csi, void *state_) +pdf_filter_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { - pdf_filter_state *state = (pdf_filter_state *)state_; - filter_gstate *gstate = gstate_to_update(csi, state); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_gstate *gstate = gstate_to_update(ctx, p); int i; - - if (csi->name[0]) - insert_resource(csi, state, "Pattern"); - - fz_strlcpy(gstate->cs_name, csi->name, sizeof(csi->name)); - for (i = 0; i < csi->top; i++) - { - gstate->color[i] = csi->stack[i]; - } - gstate->color_n = csi->top; + gstate->sc.name[0] = 0; + gstate->sc.pat = NULL; + gstate->sc.shd = NULL; + gstate->sc.n = n; + for (i = 0; i < n; ++i) + gstate->sc.c[i] = color[i]; } static void -pdf_filter_v(pdf_csi *csi, void *state_) +pdf_filter_G(fz_context *ctx, pdf_processor *proc, float g) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_v); + float color[1] = { g }; + pdf_filter_CS(ctx, proc, "DeviceGray", fz_device_gray(ctx)); + pdf_filter_SC_color(ctx, proc, 1, color); } static void -pdf_filter_w(pdf_csi *csi, void *state_) +pdf_filter_g(fz_context *ctx, pdf_processor *proc, float g) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_w); + float color[1] = { g }; + pdf_filter_cs(ctx, proc, "DeviceGray", fz_device_gray(ctx)); + pdf_filter_sc_color(ctx, proc, 1, color); } static void -pdf_filter_y(pdf_csi *csi, void *state_) +pdf_filter_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - filter_flush(csi, state, FLUSH_CTM); - call_op(csi, state, PDF_OP_y); + float color[3] = { r, g, b }; + pdf_filter_CS(ctx, proc, "DeviceRGB", fz_device_rgb(ctx)); + pdf_filter_SC_color(ctx, proc, 3, color); } static void -pdf_filter_Do(pdf_csi *csi, void *state_) +pdf_filter_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - insert_resource(csi, state, "XObject"); - - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_Do); + float color[3] = { r, g, b }; + pdf_filter_cs(ctx, proc, "DeviceRGB", fz_device_rgb(ctx)); + pdf_filter_sc_color(ctx, proc, 3, color); } static void -pdf_filter_Tf(pdf_csi *csi, void *state_) +pdf_filter_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - insert_resource(csi, state, "Font"); - - filter_flush(csi, state, 0); - call_op(csi, state, PDF_OP_Tf); + float color[4] = { c, m, y, k }; + pdf_filter_CS(ctx, proc, "DeviceCMYK", fz_device_cmyk(ctx)); + pdf_filter_SC_color(ctx, proc, 4, color); } static void -pdf_filter_gs(pdf_csi *csi, void *state_) +pdf_filter_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { - pdf_filter_state *state = (pdf_filter_state *)state_; + float color[4] = { c, m, y, k }; + pdf_filter_cs(ctx, proc, "DeviceCMYK", fz_device_cmyk(ctx)); + pdf_filter_sc_color(ctx, proc, 4, color); +} - insert_resource(csi, state, "ExtGState"); +/* shadings, images, xobjects */ - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_gs); +static void +pdf_filter_BI(fz_context *ctx, pdf_processor *proc, fz_image *img) +{ + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_BI) + p->chain->op_BI(ctx, p->chain, img); } static void -pdf_filter_sh(pdf_csi *csi, void *state_) +pdf_filter_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_filter_state *state = (pdf_filter_state *)state_; - - insert_resource(csi, state, "Shading"); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_sh) + p->chain->op_sh(ctx, p->chain, name, shade); + copy_resource(ctx, p, "Shading", name); +} - filter_flush(csi, state, FLUSH_ALL); - call_op(csi, state, PDF_OP_sh); +static void +pdf_filter_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image) +{ + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_Do_image) + p->chain->op_Do_image(ctx, p->chain, name, image); + copy_resource(ctx, p, "XObject", name); } static void -free_processor_filter(pdf_csi *csi, void *state_) +pdf_filter_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_xobject *xobj, pdf_obj *page_resources) { - pdf_filter_state *state = (pdf_filter_state *)state_; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, FLUSH_ALL); + if (p->chain->op_Do_form) + p->chain->op_Do_form(ctx, p->chain, name, xobj, page_resources); + copy_resource(ctx, p, "XObject", name); +} - /* csi can permissibly be NULL, but only in the case when we have - * failed while setting up csi. So there is nothing to pop. */ - if (csi) - { - while (!filter_pop(csi, state)) - { - /* Nothing to do in the loop, all work done above */ - } - } +/* marked content */ - call_op(csi, state, PDF_OP_END); - fz_free(state->ctx, state->gstate); - fz_free(state->ctx, state); +static void +pdf_filter_MP(fz_context *ctx, pdf_processor *proc, const char *tag) +{ + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_MP) + p->chain->op_MP(ctx, p->chain, tag); } static void -process_annot(pdf_csi *csi, void *state, pdf_obj *resources, pdf_annot *annot) +pdf_filter_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *properties) { - fz_context *ctx = csi->ctx; - pdf_xobject *xobj = annot->ap; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_DP) + p->chain->op_DP(ctx, p->chain, tag, properties); +} - /* Avoid infinite recursion */ - if (xobj == NULL || pdf_mark_obj(ctx, xobj->me)) - return; +static void +pdf_filter_BMC(fz_context *ctx, pdf_processor *proc, const char *tag) +{ + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_BMC) + p->chain->op_BMC(ctx, p->chain, tag); +} - fz_try(ctx) - { - if (xobj->resources) - resources = xobj->resources; +static void +pdf_filter_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *properties) +{ + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_BDC) + p->chain->op_BDC(ctx, p->chain, tag, properties); +} - pdf_process_contents_object(csi, resources, xobj->contents); - } - fz_always(ctx) - { - pdf_unmark_obj(ctx, xobj->me); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } +static void +pdf_filter_EMC(fz_context *ctx, pdf_processor *proc) +{ + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_EMC) + p->chain->op_EMC(ctx, p->chain); } +/* compatibility */ + static void -process_stream(pdf_csi *csi, void *state, pdf_lexbuf *buf) +pdf_filter_BX(fz_context *ctx, pdf_processor *proc) { - pdf_process_stream(csi, buf); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_BX) + p->chain->op_BX(ctx, p->chain); } static void -process_contents(pdf_csi *csi, void *state, pdf_obj *resources, pdf_obj *contents) +pdf_filter_EX(fz_context *ctx, pdf_processor *proc) { - pdf_process_contents_object(csi, resources, contents); + pdf_filter_processor *p = (pdf_filter_processor*)proc; + filter_flush(ctx, p, 0); + if (p->chain->op_EX) + p->chain->op_EX(ctx, p->chain); } -static const pdf_processor pdf_processor_filter = +static void +pdf_filter_END(fz_context *ctx, pdf_processor *proc) { + pdf_filter_processor *p = (pdf_filter_processor*)proc; + while (!filter_pop(ctx, p)) { - pdf_filter_dquote, - pdf_filter_squote, - pdf_filter_B, - pdf_filter_Bstar, - pdf_filter_BDC, - pdf_filter_BI, - pdf_filter_BMC, - pdf_filter_BT, - pdf_filter_BX, - pdf_filter_CS, - pdf_filter_DP, - pdf_filter_EMC, - pdf_filter_ET, - pdf_filter_EX, - pdf_filter_F, - pdf_filter_G, - pdf_filter_J, - pdf_filter_K, - pdf_filter_M, - pdf_filter_MP, - pdf_filter_Q, - pdf_filter_RG, - pdf_filter_S, - pdf_filter_SCN, - pdf_filter_SCN, - pdf_filter_Tstar, - pdf_filter_TD, - pdf_filter_TJ, - pdf_filter_TL, - pdf_filter_Tc, - pdf_filter_Td, - pdf_filter_Tj, - pdf_filter_Tm, - pdf_filter_Tr, - pdf_filter_Ts, - pdf_filter_Tw, - pdf_filter_Tz, - pdf_filter_W, - pdf_filter_Wstar, - pdf_filter_b, - pdf_filter_bstar, - pdf_filter_c, - pdf_filter_cm, - pdf_filter_cs, - pdf_filter_d, - pdf_filter_d0, - pdf_filter_d1, - pdf_filter_f, - pdf_filter_fstar, - pdf_filter_g, - pdf_filter_h, - pdf_filter_i, - pdf_filter_j, - pdf_filter_k, - pdf_filter_l, - pdf_filter_m, - pdf_filter_n, - pdf_filter_q, - pdf_filter_re, - pdf_filter_rg, - pdf_filter_ri, - pdf_filter_s, - pdf_filter_scn, - pdf_filter_scn, - pdf_filter_v, - pdf_filter_w, - pdf_filter_y, - pdf_filter_Do, - pdf_filter_Tf, - pdf_filter_gs, - pdf_filter_sh, - free_processor_filter - }, - process_annot, - process_stream, - process_contents -}; + /* Nothing to do in the loop, all work done above */ + } +} -pdf_process * -pdf_init_process_filter(fz_context *ctx, pdf_process *process, pdf_process *underlying, pdf_obj *resources) +static void +pdf_drop_imp_filter_processor(fz_context *ctx, pdf_processor *proc) { - pdf_filter_state *p = NULL; + pdf_filter_processor *p = (pdf_filter_processor*)proc; + fz_free(ctx, p->gstate); +} - fz_var(p); +pdf_processor * +pdf_new_filter_processor(fz_context *ctx, pdf_processor *chain, pdf_document *doc, pdf_obj *old_rdb, pdf_obj *new_rdb) +{ - fz_try(ctx) - { - p = fz_malloc_struct(ctx, pdf_filter_state); - p->ctx = ctx; - p->process = *underlying; - p->gstate = fz_malloc_struct(ctx, filter_gstate); - p->resources = resources; - p->gstate->ctm = fz_identity; - p->gstate->current_ctm = fz_identity; - } - fz_catch(ctx) + pdf_filter_processor *proc = pdf_new_processor(ctx, sizeof *proc); { - fz_free(ctx, p); - pdf_process_op(NULL, PDF_OP_END, underlying); - fz_rethrow(ctx); + proc->super.drop_imp = pdf_drop_imp_filter_processor; + + /* general graphics state */ + proc->super.op_w = pdf_filter_w; + proc->super.op_j = pdf_filter_j; + proc->super.op_J = pdf_filter_J; + proc->super.op_M = pdf_filter_M; + proc->super.op_d = pdf_filter_d; + proc->super.op_ri = pdf_filter_ri; + proc->super.op_i = pdf_filter_i; + proc->super.op_gs_begin = pdf_filter_gs_begin; + proc->super.op_gs_end = pdf_filter_gs_end; + + /* transparency graphics state */ + proc->super.op_gs_BM = pdf_filter_gs_BM; + proc->super.op_gs_CA = pdf_filter_gs_CA; + proc->super.op_gs_ca = pdf_filter_gs_ca; + proc->super.op_gs_SMask = pdf_filter_gs_SMask; + + /* special graphics state */ + proc->super.op_q = pdf_filter_q; + proc->super.op_Q = pdf_filter_Q; + proc->super.op_cm = pdf_filter_cm; + + /* path construction */ + proc->super.op_m = pdf_filter_m; + proc->super.op_l = pdf_filter_l; + proc->super.op_c = pdf_filter_c; + proc->super.op_v = pdf_filter_v; + proc->super.op_y = pdf_filter_y; + proc->super.op_h = pdf_filter_h; + proc->super.op_re = pdf_filter_re; + + /* path painting */ + proc->super.op_S = pdf_filter_S; + proc->super.op_s = pdf_filter_s; + proc->super.op_F = pdf_filter_F; + proc->super.op_f = pdf_filter_f; + proc->super.op_fstar = pdf_filter_fstar; + proc->super.op_B = pdf_filter_B; + proc->super.op_Bstar = pdf_filter_Bstar; + proc->super.op_b = pdf_filter_b; + proc->super.op_bstar = pdf_filter_bstar; + proc->super.op_n = pdf_filter_n; + + /* clipping paths */ + proc->super.op_W = pdf_filter_W; + proc->super.op_Wstar = pdf_filter_Wstar; + + /* text objects */ + proc->super.op_BT = pdf_filter_BT; + proc->super.op_ET = pdf_filter_ET; + + /* text state */ + proc->super.op_Tc = pdf_filter_Tc; + proc->super.op_Tw = pdf_filter_Tw; + proc->super.op_Tz = pdf_filter_Tz; + proc->super.op_TL = pdf_filter_TL; + proc->super.op_Tf = pdf_filter_Tf; + proc->super.op_Tr = pdf_filter_Tr; + proc->super.op_Ts = pdf_filter_Ts; + + /* text positioning */ + proc->super.op_Td = pdf_filter_Td; + proc->super.op_TD = pdf_filter_TD; + proc->super.op_Tm = pdf_filter_Tm; + proc->super.op_Tstar = pdf_filter_Tstar; + + /* text showing */ + proc->super.op_TJ = pdf_filter_TJ; + proc->super.op_Tj = pdf_filter_Tj; + proc->super.op_squote = pdf_filter_squote; + proc->super.op_dquote = pdf_filter_dquote; + + /* type 3 fonts */ + proc->super.op_d0 = pdf_filter_d0; + proc->super.op_d1 = pdf_filter_d1; + + /* color */ + proc->super.op_CS = pdf_filter_CS; + proc->super.op_cs = pdf_filter_cs; + proc->super.op_SC_color = pdf_filter_SC_color; + proc->super.op_sc_color = pdf_filter_sc_color; + proc->super.op_SC_pattern = pdf_filter_SC_pattern; + proc->super.op_sc_pattern = pdf_filter_sc_pattern; + proc->super.op_SC_shade = pdf_filter_SC_shade; + proc->super.op_sc_shade = pdf_filter_sc_shade; + + proc->super.op_G = pdf_filter_G; + proc->super.op_g = pdf_filter_g; + proc->super.op_RG = pdf_filter_RG; + proc->super.op_rg = pdf_filter_rg; + proc->super.op_K = pdf_filter_K; + proc->super.op_k = pdf_filter_k; + + /* shadings, images, xobjects */ + proc->super.op_BI = pdf_filter_BI; + proc->super.op_sh = pdf_filter_sh; + proc->super.op_Do_image = pdf_filter_Do_image; + proc->super.op_Do_form = pdf_filter_Do_form; + + /* marked content */ + proc->super.op_MP = pdf_filter_MP; + proc->super.op_DP = pdf_filter_DP; + proc->super.op_BMC = pdf_filter_BMC; + proc->super.op_BDC = pdf_filter_BDC; + proc->super.op_EMC = pdf_filter_EMC; + + /* compatibility */ + proc->super.op_BX = pdf_filter_BX; + proc->super.op_EX = pdf_filter_EX; + + proc->super.op_END = pdf_filter_END; } - process->state = p; - process->processor = &pdf_processor_filter; - return process; + proc->chain = chain; + proc->doc = doc; + proc->old_rdb = old_rdb; + proc->new_rdb = new_rdb; + + proc->gstate = fz_malloc_struct(ctx, filter_gstate); + proc->gstate->ctm = fz_identity; + proc->gstate->current_ctm = fz_identity; + + proc->gstate->stroke = proc->gstate->stroke; + proc->gstate->current_stroke = proc->gstate->stroke; + + return (pdf_processor*)proc; } diff --git a/source/pdf/pdf-op-run.c b/source/pdf/pdf-op-run.c index 204d3c23..2bdd3b55 100644 --- a/source/pdf/pdf-op-run.c +++ b/source/pdf/pdf-op-run.c @@ -1,4 +1,4 @@ -#include "pdf-interpret-imp.h" +#include "mupdf/pdf.h" #define TILE @@ -7,6 +7,9 @@ */ typedef struct pdf_material_s pdf_material; +typedef struct pdf_run_processor_s pdf_run_processor; + +static void pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_xobject *xobj, pdf_obj *page_resources, const fz_matrix *transform); enum { @@ -58,25 +61,23 @@ struct pdf_gstate_s /* transparency */ int blendmode; pdf_xobject *softmask; + pdf_obj *softmask_resources; fz_matrix softmask_ctm; float softmask_bc[FZ_MAX_COLORS]; int luminosity; }; -typedef struct pdf_run_state_s +struct pdf_run_processor_s { - fz_context *ctx; + pdf_processor super; fz_device *dev; - pdf_csi *csi; int nested_depth; - int in_hidden_ocg; /* path object state */ fz_path *path; int clip; int clip_even_odd; - const char *event; /* text object state */ fz_text *text; @@ -92,250 +93,33 @@ typedef struct pdf_run_state_s int gtop; int gbot; int gparent; -} -pdf_run_state; +}; typedef struct softmask_save_s softmask_save; struct softmask_save_s { pdf_xobject *softmask; + pdf_obj *page_resources; fz_matrix ctm; }; -static void -run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, const fz_matrix *transform); - -static int -ocg_intents_include(fz_context *ctx, pdf_ocg_descriptor *desc, char *name) -{ - int i, len; - - if (strcmp(name, "All") == 0) - return 1; - - /* In the absence of a specified intent, it's 'View' */ - if (!desc->intent) - return (strcmp(name, "View") == 0); - - if (pdf_is_name(ctx, desc->intent)) - { - char *intent = pdf_to_name(ctx, desc->intent); - if (strcmp(intent, "All") == 0) - return 1; - return (strcmp(intent, name) == 0); - } - if (!pdf_is_array(ctx, desc->intent)) - return 0; - - len = pdf_array_len(ctx, desc->intent); - for (i=0; i < len; i++) - { - char *intent = pdf_to_name(ctx, pdf_array_get(ctx, desc->intent, i)); - if (strcmp(intent, "All") == 0) - return 1; - if (strcmp(intent, name) == 0) - return 1; - } - return 0; -} - -int -pdf_is_hidden_ocg(pdf_obj *ocg, pdf_csi *csi, pdf_run_state *pr, pdf_obj *rdb) -{ - char event_state[16]; - pdf_obj *obj, *obj2; - char *type; - pdf_ocg_descriptor *desc = csi->doc->ocg; - fz_context *ctx = csi->ctx; - - /* Avoid infinite recursions */ - if (pdf_obj_marked(ctx, ocg)) - return 0; - - /* If no ocg descriptor, everything is visible */ - if (!desc) - return 0; - - /* If we've been handed a name, look it up in the properties. */ - if (pdf_is_name(ctx, ocg)) - { - ocg = pdf_dict_gets(ctx, pdf_dict_gets(ctx, rdb, "Properties"), pdf_to_name(ctx, ocg)); - } - /* If we haven't been given an ocg at all, then we're visible */ - if (!ocg) - return 0; - - fz_strlcpy(event_state, pr->event, sizeof event_state); - fz_strlcat(event_state, "State", sizeof event_state); - - type = pdf_to_name(ctx, pdf_dict_gets(ctx, ocg, "Type")); - - if (strcmp(type, "OCG") == 0) - { - /* An Optional Content Group */ - int default_value = 0; - int num = pdf_to_num(ctx, ocg); - int gen = pdf_to_gen(ctx, ocg); - int len = desc->len; - int i; - - /* by default an OCG is visible, unless it's explicitly hidden */ - for (i = 0; i < len; i++) - { - if (desc->ocgs[i].num == num && desc->ocgs[i].gen == gen) - { - default_value = desc->ocgs[i].state == 0; - break; - } - } - - /* Check Intents; if our intent is not part of the set given - * by the current config, we should ignore it. */ - obj = pdf_dict_gets(ctx, ocg, "Intent"); - if (pdf_is_name(ctx, obj)) - { - /* If it doesn't match, it's hidden */ - if (ocg_intents_include(ctx, desc, pdf_to_name(ctx, obj)) == 0) - return 1; - } - else if (pdf_is_array(ctx, obj)) - { - int match = 0; - len = pdf_array_len(ctx, obj); - for (i=0; i<len; i++) { - match |= ocg_intents_include(ctx, desc, pdf_to_name(ctx, pdf_array_get(ctx, obj, i))); - if (match) - break; - } - /* If we don't match any, it's hidden */ - if (match == 0) - return 1; - } - else - { - /* If it doesn't match, it's hidden */ - if (ocg_intents_include(ctx, desc, "View") == 0) - return 1; - } - - /* FIXME: Currently we do a very simple check whereby we look - * at the Usage object (an Optional Content Usage Dictionary) - * and check to see if the corresponding 'event' key is on - * or off. - * - * Really we should only look at Usage dictionaries that - * correspond to entries in the AS list in the OCG config. - * Given that we don't handle Zoom or User, or Language - * dicts, this is not really a problem. */ - obj = pdf_dict_gets(ctx, ocg, "Usage"); - if (!pdf_is_dict(ctx, obj)) - return default_value; - /* FIXME: Should look at Zoom (and return hidden if out of - * max/min range) */ - /* FIXME: Could provide hooks to the caller to check if - * User is appropriate - if not return hidden. */ - obj2 = pdf_dict_gets(ctx, obj, pr->event); - if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, obj2, event_state)), "OFF") == 0) - { - return 1; - } - if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, obj2, event_state)), "ON") == 0) - { - return 0; - } - return default_value; - } - else if (strcmp(type, "OCMD") == 0) - { - /* An Optional Content Membership Dictionary */ - char *name; - int combine, on; - - obj = pdf_dict_gets(ctx, ocg, "VE"); - if (pdf_is_array(ctx, obj)) { - /* FIXME: Calculate visibility from array */ - return 0; - } - name = pdf_to_name(ctx, pdf_dict_gets(ctx, ocg, "P")); - /* Set combine; Bit 0 set => AND, Bit 1 set => true means - * Off, otherwise true means On */ - if (strcmp(name, "AllOn") == 0) - { - combine = 1; - } - else if (strcmp(name, "AnyOff") == 0) - { - combine = 2; - } - else if (strcmp(name, "AllOff") == 0) - { - combine = 3; - } - else /* Assume it's the default (AnyOn) */ - { - combine = 0; - } - - if (pdf_mark_obj(ctx, ocg)) - return 0; /* Should never happen */ - fz_try(ctx) - { - obj = pdf_dict_gets(ctx, ocg, "OCGs"); - on = combine & 1; - if (pdf_is_array(ctx, obj)) { - int i, len; - len = pdf_array_len(ctx, obj); - for (i = 0; i < len; i++) - { - int hidden; - hidden = pdf_is_hidden_ocg(pdf_array_get(ctx, obj, i), csi, pr, rdb); - if ((combine & 1) == 0) - hidden = !hidden; - if (combine & 2) - on &= hidden; - else - on |= hidden; - } - } - else - { - on = pdf_is_hidden_ocg(obj, csi, pr, rdb); - if ((combine & 1) == 0) - on = !on; - } - } - fz_always(ctx) - { - pdf_unmark_obj(ctx, ocg); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } - return !on; - } - /* No idea what sort of object this is - be visible */ - return 0; -} - static pdf_gstate * -begin_softmask(pdf_csi *csi, pdf_run_state *pr, softmask_save *save) +begin_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save) { pdf_gstate *gstate = pr->gstate + pr->gtop; pdf_xobject *softmask = gstate->softmask; fz_rect mask_bbox; - fz_context *ctx; fz_matrix save_tm, save_tlm, save_ctm; save->softmask = softmask; if (softmask == NULL) return gstate; + save->page_resources = gstate->softmask_resources; save->ctm = gstate->softmask_ctm; save_ctm = gstate->ctm; mask_bbox = softmask->bbox; - ctx = pr->ctx; save_tm = pr->tm; save_tlm = pr->tlm; @@ -347,21 +131,21 @@ begin_softmask(pdf_csi *csi, pdf_run_state *pr, softmask_save *save) fz_transform_rect(&mask_bbox, &gstate->softmask_ctm); } gstate->softmask = NULL; + gstate->softmask_resources = NULL; gstate->ctm = gstate->softmask_ctm; fz_begin_mask(ctx, pr->dev, &mask_bbox, gstate->luminosity, softmask->colorspace, gstate->softmask_bc); fz_try(ctx) { - run_xobject(csi, pr, csi->rdb, softmask, &fz_identity); + pdf_run_xobject(ctx, pr, softmask, save->page_resources, &fz_identity); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); /* FIXME: Ignore error - nasty, but if we throw from * here the clip stack would be messed up. */ - if (csi->cookie) - csi->cookie->errors++; + /* TODO: pass cookie here to increase the cookie error count */ } fz_end_mask(ctx, pr->dev); @@ -376,61 +160,60 @@ begin_softmask(pdf_csi *csi, pdf_run_state *pr, softmask_save *save) } static void -end_softmask(pdf_csi *csi, pdf_run_state *pr, softmask_save *save) +end_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; if (save->softmask == NULL) return; gstate->softmask = save->softmask; + gstate->softmask_resources = save->page_resources; gstate->softmask_ctm = save->ctm; fz_pop_clip(ctx, pr->dev); } static pdf_gstate * -pdf_begin_group(pdf_csi *csi, pdf_run_state *pr, const fz_rect *bbox, softmask_save *softmask) +pdf_begin_group(fz_context *ctx, pdf_run_processor *pr, const fz_rect *bbox, softmask_save *softmask) { - pdf_gstate *gstate = begin_softmask(csi, pr, softmask); + pdf_gstate *gstate = begin_softmask(ctx, pr, softmask); if (gstate->blendmode) - fz_begin_group(pr->ctx, pr->dev, bbox, 1, 0, gstate->blendmode, 1); + fz_begin_group(ctx, pr->dev, bbox, 1, 0, gstate->blendmode, 1); return pr->gstate + pr->gtop; } static void -pdf_end_group(pdf_csi *csi, pdf_run_state *pr, softmask_save *softmask) +pdf_end_group(fz_context *ctx, pdf_run_processor *pr, softmask_save *softmask) { pdf_gstate *gstate = pr->gstate + pr->gtop; if (gstate->blendmode) - fz_end_group(pr->ctx, pr->dev); + fz_end_group(ctx, pr->dev); - end_softmask(csi, pr, softmask); + end_softmask(ctx, pr, softmask); } static void -pdf_show_shade(pdf_csi *csi, pdf_run_state *pr, fz_shade *shd) +pdf_show_shade(fz_context *ctx, pdf_run_processor *pr, fz_shade *shd) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; fz_rect bbox; softmask_save softmask = { NULL }; - if (pr->in_hidden_ocg > 0) + if (pr->super.hidden) return; fz_bound_shade(ctx, shd, &gstate->ctm, &bbox); - gstate = pdf_begin_group(csi, pr, &bbox, &softmask); + gstate = pdf_begin_group(ctx, pr, &bbox, &softmask); /* FIXME: The gstate->ctm in the next line may be wrong; maybe * it should be the parent gstates ctm? */ fz_fill_shade(ctx, pr->dev, shd, &gstate->ctm, gstate->fill.alpha); - pdf_end_group(csi, pr, &softmask); + pdf_end_group(ctx, pr, &softmask); } static pdf_material * @@ -473,9 +256,8 @@ pdf_copy_pattern_gstate(fz_context *ctx, pdf_gstate *gs, const pdf_gstate *old) } static void -pdf_unset_pattern(pdf_run_state *pr, int what) +pdf_unset_pattern(fz_context *ctx, pdf_run_processor *pr, int what) { - fz_context *ctx = pr->ctx; pdf_gstate *gs = pr->gstate + pr->gtop; pdf_material *mat; mat = what == PDF_FILL ? &gs->fill : &gs->stroke; @@ -497,6 +279,8 @@ pdf_keep_gstate(fz_context *ctx, pdf_gstate *gs) pdf_keep_font(ctx, gs->font); if (gs->softmask) pdf_keep_xobject(ctx, gs->softmask); + if (gs->softmask_resources) + pdf_keep_obj(ctx, gs->softmask_resources); fz_keep_stroke_state(ctx, gs->stroke_state); } @@ -509,14 +293,14 @@ pdf_drop_gstate(fz_context *ctx, pdf_gstate *gs) pdf_drop_font(ctx, gs->font); if (gs->softmask) pdf_drop_xobject(ctx, gs->softmask); + if (gs->softmask_resources) + pdf_drop_obj(ctx, gs->softmask_resources); fz_drop_stroke_state(ctx, gs->stroke_state); } static void -pdf_gsave(pdf_run_state *pr) +pdf_gsave(fz_context *ctx, pdf_run_processor *pr) { - fz_context *ctx = pr->ctx; - if (pr->gtop == pr->gcap-1) { pr->gstate = fz_resize_array(ctx, pr->gstate, pr->gcap*2, sizeof(pdf_gstate)); @@ -530,9 +314,8 @@ pdf_gsave(pdf_run_state *pr) } static void -pdf_grestore(pdf_run_state *pr) +pdf_grestore(fz_context *ctx, pdf_run_processor *pr) { - fz_context *ctx = pr->ctx; pdf_gstate *gs = pr->gstate + pr->gtop; int clip_depth = gs->clip_depth; @@ -562,26 +345,25 @@ pdf_grestore(pdf_run_state *pr) } static void -pdf_show_pattern(pdf_csi *csi, pdf_run_state *pr, pdf_pattern *pat, pdf_gstate *pat_gstate, const fz_rect *area, int what) +pdf_show_pattern(fz_context *ctx, pdf_run_processor *pr, pdf_pattern *pat, pdf_gstate *pat_gstate, const fz_rect *area, int what) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate; int gparent_save; fz_matrix ptm, invptm, gparent_save_ctm; int x0, y0, x1, y1; float fx0, fy0, fx1, fy1; - int oldtop; fz_rect local_area; - pdf_gsave(pr); + pdf_gsave(ctx, pr); gstate = pr->gstate + pr->gtop; + /* Patterns are run with the gstate of the parent */ pdf_copy_pattern_gstate(ctx, gstate, pat_gstate); if (pat->ismask) { - pdf_unset_pattern(pr, PDF_FILL); - pdf_unset_pattern(pr, PDF_STROKE); + pdf_unset_pattern(ctx, pr, PDF_FILL); + pdf_unset_pattern(ctx, pr, PDF_STROKE); if (what == PDF_FILL) { pdf_drop_material(ctx, &gstate->stroke); @@ -598,7 +380,7 @@ pdf_show_pattern(pdf_csi *csi, pdf_run_state *pr, pdf_pattern *pat, pdf_gstate * else { // TODO: unset only the current fill/stroke or both? - pdf_unset_pattern(pr, what); + pdf_unset_pattern(ctx, pr, what); } /* don't apply soft masks to objects in the pattern as well */ @@ -638,8 +420,6 @@ pdf_show_pattern(pdf_csi *csi, pdf_run_state *pr, pdf_pattern *pat, pdf_gstate * float t = fy0; fy0 = fy1; fy1 = t; } - oldtop = pr->gtop; - #ifdef TILE /* We have tried various formulations in the past, but this one is * best we've found; only use it as a tile if a whole repeat is @@ -652,12 +432,20 @@ pdf_show_pattern(pdf_csi *csi, pdf_run_state *pr, pdf_pattern *pat, pdf_gstate * { fz_begin_tile(ctx, pr->dev, &local_area, &pat->bbox, pat->xstep, pat->ystep, &ptm); gstate->ctm = ptm; - pdf_gsave(pr); - pdf_process_contents_object(csi, pat->resources, pat->contents); - pdf_grestore(pr); - while (oldtop < pr->gtop) - pdf_grestore(pr); - fz_end_tile(ctx, pr->dev); + pdf_gsave(ctx, pr); + fz_try(ctx) + { + pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL); + } + fz_always(ctx) + { + pdf_grestore(ctx, pr); + fz_end_tile(ctx, pr->dev); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } } else { @@ -686,21 +474,13 @@ pdf_show_pattern(pdf_csi *csi, pdf_run_state *pr, pdf_pattern *pat, pdf_gstate * { gstate->ctm = ptm; fz_pre_translate(&gstate->ctm, x * pat->xstep, y * pat->ystep); - pdf_gsave(pr); + pdf_gsave(ctx, pr); fz_try(ctx) - { - pdf_process_contents_object(csi, pat->resources, pat->contents); - } + pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL); fz_always(ctx) - { - pdf_grestore(pr); - while (oldtop < pr->gtop) - pdf_grestore(pr); - } + pdf_grestore(ctx, pr); fz_catch(ctx) - { fz_rethrow_message(ctx, "cannot render pattern tile"); - } } } } @@ -715,19 +495,18 @@ pdf_show_pattern(pdf_csi *csi, pdf_run_state *pr, pdf_pattern *pat, pdf_gstate * fz_rethrow(ctx); } - pdf_grestore(pr); + pdf_grestore(ctx, pr); } static void -pdf_show_image(pdf_csi *csi, pdf_run_state *pr, fz_image *image) +pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; fz_matrix image_ctm; fz_rect bbox; softmask_save softmask = { NULL }; - if (pr->in_hidden_ocg > 0) + if (pr->super.hidden) return; /* PDF has images bottom-up, so flip them right side up here */ @@ -745,7 +524,7 @@ pdf_show_image(pdf_csi *csi, pdf_run_state *pr, fz_image *image) fz_clip_image_mask(ctx, pr->dev, image->mask, &bbox, &image_ctm); } else - gstate = pdf_begin_group(csi, pr, &bbox, &softmask); + gstate = pdf_begin_group(ctx, pr, &bbox, &softmask); if (!image->colorspace) { @@ -762,7 +541,7 @@ pdf_show_image(pdf_csi *csi, pdf_run_state *pr, fz_image *image) if (gstate->fill.pattern) { fz_clip_image_mask(ctx, pr->dev, image, &bbox, &image_ctm); - pdf_show_pattern(csi, pr, gstate->fill.pattern, &pr->gstate[gstate->fill.gstate_num], &bbox, PDF_FILL); + pdf_show_pattern(ctx, pr, gstate->fill.pattern, &pr->gstate[gstate->fill.gstate_num], &bbox, PDF_FILL); fz_pop_clip(ctx, pr->dev); } break; @@ -788,13 +567,12 @@ pdf_show_image(pdf_csi *csi, pdf_run_state *pr, fz_image *image) fz_end_group(ctx, pr->dev); } else - pdf_end_group(csi, pr, &softmask); + pdf_end_group(ctx, pr, &softmask); } static void -pdf_show_path(pdf_csi *csi, pdf_run_state *pr, int doclose, int dofill, int dostroke, int even_odd) +pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, int dostroke, int even_odd) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; fz_path *path; fz_rect bbox; @@ -831,11 +609,11 @@ pdf_show_path(pdf_csi *csi, pdf_run_state *pr, int doclose, int dofill, int dost pr->clip = 0; } - if (pr->in_hidden_ocg > 0) + if (pr->super.hidden) dostroke = dofill = 0; if (dofill || dostroke) - gstate = pdf_begin_group(csi, pr, &bbox, &softmask); + gstate = pdf_begin_group(ctx, pr, &bbox, &softmask); if (dofill && dostroke) { @@ -869,7 +647,7 @@ pdf_show_path(pdf_csi *csi, pdf_run_state *pr, int doclose, int dofill, int dost if (gstate->fill.pattern) { fz_clip_path(ctx, pr->dev, path, &bbox, even_odd, &gstate->ctm); - pdf_show_pattern(csi, pr, gstate->fill.pattern, &pr->gstate[gstate->fill.gstate_num], &bbox, PDF_FILL); + pdf_show_pattern(ctx, pr, gstate->fill.pattern, &pr->gstate[gstate->fill.gstate_num], &bbox, PDF_FILL); fz_pop_clip(ctx, pr->dev); } break; @@ -899,7 +677,7 @@ pdf_show_path(pdf_csi *csi, pdf_run_state *pr, int doclose, int dofill, int dost if (gstate->stroke.pattern) { fz_clip_stroke_path(ctx, pr->dev, path, &bbox, gstate->stroke_state, &gstate->ctm); - pdf_show_pattern(csi, pr, gstate->stroke.pattern, &pr->gstate[gstate->stroke.gstate_num], &bbox, PDF_STROKE); + pdf_show_pattern(ctx, pr, gstate->stroke.pattern, &pr->gstate[gstate->stroke.gstate_num], &bbox, PDF_STROKE); fz_pop_clip(ctx, pr->dev); } break; @@ -918,7 +696,7 @@ pdf_show_path(pdf_csi *csi, pdf_run_state *pr, int doclose, int dofill, int dost fz_end_group(ctx, pr->dev); if (dofill || dostroke) - pdf_end_group(csi, pr, &softmask); + pdf_end_group(ctx, pr, &softmask); } fz_always(ctx) { @@ -935,7 +713,7 @@ pdf_show_path(pdf_csi *csi, pdf_run_state *pr, int doclose, int dofill, int dost */ static pdf_gstate * -pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) +pdf_flush_text(fz_context *ctx, pdf_run_processor *pr) { pdf_gstate *gstate = pr->gstate + pr->gtop; fz_text *text; @@ -943,7 +721,6 @@ pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) int dostroke; int doclip; int doinvisible; - fz_context *ctx = pr->ctx; softmask_save softmask = { NULL }; if (!pr->text) @@ -964,7 +741,7 @@ pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) case 7: doclip = 1; break; } - if (pr->in_hidden_ocg > 0) + if (pr->super.hidden) dostroke = dofill = 0; fz_try(ctx) @@ -977,7 +754,7 @@ pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) if (text->len == 0) break; - gstate = pdf_begin_group(csi, pr, &tb, &softmask); + gstate = pdf_begin_group(ctx, pr, &tb, &softmask); if (doinvisible) fz_ignore_text(ctx, pr->dev, text, &gstate->ctm); @@ -996,7 +773,7 @@ pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) if (gstate->fill.pattern) { fz_clip_text(ctx, pr->dev, text, &gstate->ctm, 0); - pdf_show_pattern(csi, pr, gstate->fill.pattern, &pr->gstate[gstate->fill.gstate_num], &tb, PDF_FILL); + pdf_show_pattern(ctx, pr, gstate->fill.pattern, &pr->gstate[gstate->fill.gstate_num], &tb, PDF_FILL); fz_pop_clip(ctx, pr->dev); } break; @@ -1026,7 +803,7 @@ pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) if (gstate->stroke.pattern) { fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, &gstate->ctm); - pdf_show_pattern(csi, pr, gstate->stroke.pattern, &pr->gstate[gstate->stroke.gstate_num], &tb, PDF_STROKE); + pdf_show_pattern(ctx, pr, gstate->stroke.pattern, &pr->gstate[gstate->stroke.gstate_num], &tb, PDF_STROKE); fz_pop_clip(ctx, pr->dev); } break; @@ -1049,7 +826,7 @@ pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) pr->accumulate = 2; } - pdf_end_group(csi, pr, &softmask); + pdf_end_group(ctx, pr, &softmask); } fz_always(ctx) { @@ -1064,9 +841,8 @@ pdf_flush_text(pdf_csi *csi, pdf_run_state *pr) } static void -pdf_show_char(pdf_csi *csi, pdf_run_state *pr, int cid) +pdf_show_char(fz_context *ctx, pdf_run_processor *pr, int cid) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; pdf_font_desc *fontdesc = gstate->font; fz_matrix tsm, trm; @@ -1130,7 +906,7 @@ pdf_show_char(pdf_csi *csi, pdf_run_state *pr, int cid) gstate->render != pr->text_mode || render_direct) { - gstate = pdf_flush_text(csi, pr); + gstate = pdf_flush_text(ctx, pr); pr->text = fz_new_text(ctx, fontdesc->font, &trm, fontdesc->wmode); pr->text->trm.e = 0; @@ -1177,9 +953,8 @@ pdf_show_char(pdf_csi *csi, pdf_run_state *pr, int cid) } static void -pdf_show_space(pdf_run_state *pr, float tadj) +pdf_show_space(fz_context *ctx, pdf_run_processor *pr, float tadj) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; pdf_font_desc *fontdesc = gstate->font; @@ -1196,9 +971,8 @@ pdf_show_space(pdf_run_state *pr, float tadj) } static void -pdf_show_string(pdf_csi *csi, pdf_run_state *pr, unsigned char *buf, int len) +pdf_show_string(fz_context *ctx, pdf_run_processor *pr, unsigned char *buf, int len) { - fz_context *ctx = pr->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; pdf_font_desc *fontdesc = gstate->font; unsigned char *end = buf + len; @@ -1218,18 +992,17 @@ pdf_show_string(pdf_csi *csi, pdf_run_state *pr, unsigned char *buf, int len) cid = pdf_lookup_cmap(fontdesc->encoding, cpt); if (cid >= 0) - pdf_show_char(csi, pr, cid); + pdf_show_char(ctx, pr, cid); else fz_warn(ctx, "cannot encode character"); if (cpt == 32 && w == 1) - pdf_show_space(pr, gstate->word_space); + pdf_show_space(ctx, pr, gstate->word_space); } } static void -pdf_show_text(pdf_csi *csi, pdf_run_state *pr, pdf_obj *text) +pdf_show_text(fz_context *ctx, pdf_run_processor *pr, pdf_obj *text) { - fz_context *ctx = csi->ctx; pdf_gstate *gstate = pr->gstate + pr->gtop; int i; @@ -1240,14 +1013,14 @@ pdf_show_text(pdf_csi *csi, pdf_run_state *pr, pdf_obj *text) { pdf_obj *item = pdf_array_get(ctx, text, i); if (pdf_is_string(ctx, item)) - pdf_show_string(csi, pr, (unsigned char *)pdf_to_str_buf(ctx, item), pdf_to_str_len(ctx, item)); + pdf_show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, item), pdf_to_str_len(ctx, item)); else - pdf_show_space(pr, - pdf_to_real(ctx, item) * gstate->size * 0.001f); + pdf_show_space(ctx, pr, - pdf_to_real(ctx, item) * gstate->size * 0.001f); } } else if (pdf_is_string(ctx, text)) { - pdf_show_string(csi, pr, (unsigned char *)pdf_to_str_buf(ctx, text), pdf_to_str_len(ctx, text)); + pdf_show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, text), pdf_to_str_len(ctx, text)); } } @@ -1290,6 +1063,7 @@ pdf_init_gstate(fz_context *ctx, pdf_gstate *gs, const fz_matrix *ctm) gs->blendmode = 0; gs->softmask = NULL; + gs->softmask_resources = NULL; gs->softmask_ctm = fz_identity; gs->luminosity = 0; } @@ -1307,15 +1081,14 @@ pdf_copy_gstate(fz_context *ctx, pdf_gstate *gs, pdf_gstate *old) */ static void -pdf_set_colorspace(pdf_csi *csi, pdf_run_state *pr, int what, fz_colorspace *colorspace) +pdf_set_colorspace(fz_context *ctx, pdf_run_processor *pr, int what, fz_colorspace *colorspace) { - fz_context *ctx = pr->ctx; - pdf_gstate *gs; + pdf_gstate *gstate = pr->gstate + pr->gtop; pdf_material *mat; - gs = pdf_flush_text(csi, pr); + gstate = pdf_flush_text(ctx, pr); - mat = what == PDF_FILL ? &gs->fill : &gs->stroke; + mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke; fz_drop_colorspace(ctx, mat->colorspace); @@ -1336,16 +1109,15 @@ pdf_set_colorspace(pdf_csi *csi, pdf_run_state *pr, int what, fz_colorspace *col } static void -pdf_set_color(pdf_csi *csi, pdf_run_state *pr, int what, float *v) +pdf_set_color(fz_context *ctx, pdf_run_processor *pr, int what, float *v) { - fz_context *ctx = pr->ctx; - pdf_gstate *gs; + pdf_gstate *gstate = pr->gstate + pr->gtop; pdf_material *mat; int i; - gs = pdf_flush_text(csi, pr); + gstate = pdf_flush_text(ctx, pr); - mat = what == PDF_FILL ? &gs->fill : &gs->stroke; + mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke; switch (mat->kind) { @@ -1362,16 +1134,17 @@ pdf_set_color(pdf_csi *csi, pdf_run_state *pr, int what, float *v) default: fz_warn(ctx, "color incompatible with material"); } + + mat->gstate_num = pr->gparent; } static void -pdf_set_shade(pdf_csi *csi, pdf_run_state *pr, int what, fz_shade *shade) +pdf_set_shade(fz_context *ctx, pdf_run_processor *pr, int what, fz_shade *shade) { - fz_context *ctx = pr->ctx; pdf_gstate *gs; pdf_material *mat; - gs = pdf_flush_text(csi, pr); + gs = pdf_flush_text(ctx, pr); mat = what == PDF_FILL ? &gs->fill : &gs->stroke; @@ -1380,16 +1153,17 @@ pdf_set_shade(pdf_csi *csi, pdf_run_state *pr, int what, fz_shade *shade) mat->kind = PDF_MAT_SHADE; mat->shade = fz_keep_shade(ctx, shade); + + mat->gstate_num = pr->gparent; } static void -pdf_set_pattern(pdf_csi *csi, pdf_run_state *pr, int what, pdf_pattern *pat, float *v) +pdf_set_pattern(fz_context *ctx, pdf_run_processor *pr, int what, pdf_pattern *pat, float *v) { - fz_context *ctx = pr->ctx; pdf_gstate *gs; pdf_material *mat; - gs = pdf_flush_text(csi, pr); + gs = pdf_flush_text(ctx, pr); mat = what == PDF_FILL ? &gs->fill : &gs->stroke; @@ -1401,216 +1175,26 @@ pdf_set_pattern(pdf_csi *csi, pdf_run_state *pr, int what, pdf_pattern *pat, flo mat->pattern = pdf_keep_pattern(ctx, pat); else mat->pattern = NULL; - mat->gstate_num = pr->gparent; if (v) - pdf_set_color(csi, pr, what, v); -} - -static pdf_font_desc * -load_font_or_hail_mary(pdf_csi *csi, pdf_obj *rdb, pdf_obj *font, int depth) -{ - fz_context *ctx = csi->ctx; - pdf_document *doc = csi->doc; - pdf_font_desc *desc; - - fz_try(ctx) - { - desc = pdf_load_font(ctx, doc, rdb, font, depth); - } - fz_catch(ctx) - { - if (fz_caught(ctx) != FZ_ERROR_TRYLATER) - fz_rethrow(ctx); - if (!csi->cookie || !csi->cookie->incomplete_ok) - fz_rethrow(ctx); - desc = NULL; - csi->cookie->incomplete++; - } - if (desc == NULL) - desc = pdf_load_hail_mary_font(ctx, doc); - return desc; -} - -static void -pdf_run_extgstate(pdf_csi *csi, pdf_run_state *pr, pdf_obj *rdb, pdf_obj *extgstate) -{ - fz_context *ctx = pr->ctx; - pdf_gstate *gstate; - fz_colorspace *colorspace; - int i, k, n; - - gstate = pdf_flush_text(csi, pr); - - n = pdf_dict_len(ctx, extgstate); - for (i = 0; i < n; i++) - { - pdf_obj *key = pdf_dict_get_key(ctx, extgstate, i); - pdf_obj *val = pdf_dict_get_val(ctx, extgstate, i); - char *s = pdf_to_name(ctx, key); - - if (!strcmp(s, "Font")) - { - if (pdf_is_array(ctx, val) && pdf_array_len(ctx, val) == 2) - { - pdf_obj *font = pdf_array_get(ctx, val, 0); - - if (gstate->font) - { - pdf_drop_font(ctx, gstate->font); - gstate->font = NULL; - } - - gstate->font = load_font_or_hail_mary(csi, rdb, font, pr->nested_depth); - if (!gstate->font) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find font in store"); - gstate->size = pdf_to_real(ctx, pdf_array_get(ctx, val, 1)); - } - else - fz_throw(ctx, FZ_ERROR_GENERIC, "malformed /Font dictionary"); - } - - else if (!strcmp(s, "LC")) - { - pr->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); - gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); - gstate->stroke_state->start_cap = pdf_to_int(ctx, val); - gstate->stroke_state->dash_cap = pdf_to_int(ctx, val); - gstate->stroke_state->end_cap = pdf_to_int(ctx, val); - } - else if (!strcmp(s, "LW")) - { - pr->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; - gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); - gstate->stroke_state->linewidth = pdf_to_real(ctx, val); - } - else if (!strcmp(s, "LJ")) - { - pr->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; - gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); - gstate->stroke_state->linejoin = pdf_to_int(ctx, val); - } - else if (!strcmp(s, "ML")) - { - pr->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; - gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); - gstate->stroke_state->miterlimit = pdf_to_real(ctx, val); - } - - else if (!strcmp(s, "D")) - { - if (pdf_is_array(ctx, val) && pdf_array_len(ctx, val) == 2) - { - pdf_obj *dashes = pdf_array_get(ctx, val, 0); - int len = pdf_array_len(ctx, dashes); - gstate->stroke_state = fz_unshare_stroke_state_with_dash_len(ctx, gstate->stroke_state, len); - gstate->stroke_state->dash_len = len; - for (k = 0; k < len; k++) - gstate->stroke_state->dash_list[k] = pdf_to_real(ctx, pdf_array_get(ctx, dashes, k)); - gstate->stroke_state->dash_phase = pdf_to_real(ctx, pdf_array_get(ctx, val, 1)); - } - else - fz_throw(ctx, FZ_ERROR_GENERIC, "malformed /D"); - } - - else if (!strcmp(s, "CA")) - gstate->stroke.alpha = fz_clamp(pdf_to_real(ctx, val), 0, 1); - - else if (!strcmp(s, "ca")) - gstate->fill.alpha = fz_clamp(pdf_to_real(ctx, val), 0, 1); - - else if (!strcmp(s, "BM")) - { - if (pdf_is_array(ctx, val)) - val = pdf_array_get(ctx, val, 0); - gstate->blendmode = fz_lookup_blendmode(pdf_to_name(ctx, val)); - } - - else if (!strcmp(s, "SMask")) - { - if (pdf_is_dict(ctx, val)) - { - pdf_xobject *xobj; - pdf_obj *group, *luminosity, *bc, *tr; - - if (gstate->softmask) - { - pdf_drop_xobject(ctx, gstate->softmask); - gstate->softmask = NULL; - } - - group = pdf_dict_gets(ctx, val, "G"); - if (!group) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load softmask xobject (%d %d R)", pdf_to_num(ctx, val), pdf_to_gen(ctx, val)); - xobj = pdf_load_xobject(ctx, csi->doc, group); - - colorspace = xobj->colorspace; - if (!colorspace) - colorspace = fz_device_gray(ctx); + pdf_set_color(ctx, pr, what, v); - /* The softmask_ctm no longer has the softmask matrix rolled into it, as this - * causes the softmask matrix to be applied twice. */ - gstate->softmask_ctm = gstate->ctm; - gstate->softmask = xobj; - for (k = 0; k < colorspace->n; k++) - gstate->softmask_bc[k] = 0; - - bc = pdf_dict_gets(ctx, val, "BC"); - if (pdf_is_array(ctx, bc)) - { - for (k = 0; k < colorspace->n; k++) - gstate->softmask_bc[k] = pdf_to_real(ctx, pdf_array_get(ctx, bc, k)); - } - - luminosity = pdf_dict_gets(ctx, val, "S"); - if (pdf_is_name(ctx, luminosity) && !strcmp(pdf_to_name(ctx, luminosity), "Luminosity")) - gstate->luminosity = 1; - else - gstate->luminosity = 0; - - tr = pdf_dict_gets(ctx, val, "TR"); - if (tr && strcmp(pdf_to_name(ctx, tr), "Identity")) - fz_warn(ctx, "ignoring transfer function"); - } - else if (pdf_is_name(ctx, val) && !strcmp(pdf_to_name(ctx, val), "None")) - { - if (gstate->softmask) - { - pdf_drop_xobject(ctx, gstate->softmask); - gstate->softmask = NULL; - } - } - } - - else if (!strcmp(s, "TR2")) - { - if (strcmp(pdf_to_name(ctx, val), "Identity") && strcmp(pdf_to_name(ctx, val), "Default")) - fz_warn(ctx, "ignoring transfer function"); - } - - else if (!strcmp(s, "TR")) - { - /* TR is ignored in the presence of TR2 */ - pdf_obj *tr2 = pdf_dict_gets(ctx, extgstate, "TR2"); - if (tr2 && strcmp(pdf_to_name(ctx, val), "Identity")) - fz_warn(ctx, "ignoring transfer function"); - } - } + mat->gstate_num = pr->gparent; } static void -run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, const fz_matrix *transform) +pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_xobject *xobj, pdf_obj *page_resources, const fz_matrix *transform) { - fz_context *ctx = csi->ctx; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = NULL; int oldtop = 0; fz_matrix local_transform = *transform; softmask_save softmask = { NULL }; int gparent_save; fz_matrix gparent_save_ctm; - pdf_run_state *pr = (pdf_run_state *)state; int cleanup_state = 0; char errmess[256] = ""; + pdf_obj *resources; /* Avoid infinite recursion */ if (xobj == NULL || pdf_mark_obj(ctx, xobj->me)) @@ -1625,7 +1209,7 @@ run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, co fz_try(ctx) { - pdf_gsave(pr); + pdf_gsave(ctx, pr); gstate = pr->gstate + pr->gtop; oldtop = pr->gtop; @@ -1647,13 +1231,12 @@ run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, co /* Remember that we tried to call begin_softmask. Even * if it throws an error, we must call end_softmask. */ cleanup_state = 1; - gstate = begin_softmask(csi, pr, &softmask); + gstate = begin_softmask(ctx, pr, &softmask); /* Remember that we tried to call fz_begin_group. Even * if it throws an error, we must call fz_end_group. */ cleanup_state = 2; - fz_begin_group(ctx, pr->dev, &bbox, - xobj->isolated, xobj->knockout, gstate->blendmode, gstate->fill.alpha); + fz_begin_group(ctx, pr->dev, &bbox, xobj->isolated, xobj->knockout, gstate->blendmode, gstate->fill.alpha); gstate->blendmode = 0; gstate->stroke.alpha = 1; @@ -1663,7 +1246,7 @@ run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, co /* Remember that we tried to save for the clippath. Even if it * throws an error, we must pop it. */ cleanup_state = 3; - pdf_gsave(pr); /* Save here so the clippath doesn't persist */ + pdf_gsave(ctx, pr); /* Save here so the clippath doesn't persist */ /* clip to the bounds */ fz_moveto(ctx, pr->path, xobj->bbox.x0, xobj->bbox.y0); @@ -1672,19 +1255,20 @@ run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, co fz_lineto(ctx, pr->path, xobj->bbox.x0, xobj->bbox.y1); fz_closepath(ctx, pr->path); pr->clip = 1; - pdf_show_path(csi, pr, 0, 0, 0, 0); + pdf_show_path(ctx, pr, 0, 0, 0, 0); /* run contents */ - if (xobj->resources) - resources = xobj->resources; + resources = xobj->resources; + if (!resources) + resources = page_resources; - pdf_process_contents_object(csi, resources, xobj->contents); + pdf_process_contents(ctx, (pdf_processor*)pr, xobj->document, resources, xobj->contents, NULL); } fz_always(ctx) { if (cleanup_state >= 3) - pdf_grestore(pr); /* Remove the clippath */ + pdf_grestore(ctx, pr); /* Remove the clippath */ /* wrap up transparency stacks */ if (xobj->transparency) @@ -1705,7 +1289,7 @@ run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, co { fz_try(ctx) { - end_softmask(csi, pr, &softmask); + end_softmask(ctx, pr, &softmask); } fz_catch(ctx) { @@ -1721,9 +1305,9 @@ run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, co if (gstate) { while (oldtop < pr->gtop) - pdf_grestore(pr); + pdf_grestore(ctx, pr); - pdf_grestore(pr); + pdf_grestore(ctx, pr); } pdf_unmark_obj(ctx, xobj->me); @@ -1738,633 +1322,440 @@ run_xobject(pdf_csi *csi, void *state, pdf_obj *resources, pdf_xobject *xobj, co fz_throw(ctx, FZ_ERROR_GENERIC, "%s", errmess); } -static void pdf_run_BDC(pdf_csi *csi, void *state) -{ - fz_context *ctx = csi->ctx; - pdf_run_state *pr = (pdf_run_state *)state; - pdf_obj *ocg; - pdf_obj *rdb = csi->rdb; - - /* We only understand OC groups so far */ - if (strcmp(csi->name, "OC") != 0) - return; +/* general graphics state */ - /* If we are already in a hidden OCG, then we'll still be hidden - - * just increment the depth so we pop back to visibility when we've - * seen enough EDCs. */ - if (pr->in_hidden_ocg > 0) - { - pr->in_hidden_ocg++; - return; - } - - if (pdf_is_name(ctx, csi->obj)) - { - ocg = pdf_dict_gets(ctx, pdf_dict_gets(ctx, rdb, "Properties"), pdf_to_name(ctx, csi->obj)); - } - else - ocg = csi->obj; +static void pdf_run_w(fz_context *ctx, pdf_processor *proc, float linewidth) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); - if (!ocg) - { - /* No Properties array, or name not found in the properties - * means visible. */ - return; - } - if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, ocg, "Type")), "OCG") != 0) - { - /* Wrong type of property */ - return; - } - if (pdf_is_hidden_ocg(ocg, csi, pr, rdb)) - pr->in_hidden_ocg++; + pr->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; + gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); + gstate->stroke_state->linewidth = linewidth; } -static void pdf_run_BI(pdf_csi *csi, void *state) +static void pdf_run_j(fz_context *ctx, pdf_processor *proc, int linejoin) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); - pdf_show_image(csi, pr, csi->img); + pr->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; + gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); + gstate->stroke_state->linejoin = linejoin; } -static void pdf_run_B(pdf_csi *csi, void *state) +static void pdf_run_J(fz_context *ctx, pdf_processor *proc, int linecap) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); - pdf_show_path(csi, pr, 0, 1, 1, 0); + pr->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); + gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); + gstate->stroke_state->start_cap = linecap; + gstate->stroke_state->dash_cap = linecap; + gstate->stroke_state->end_cap = linecap; } -static void pdf_run_BMC(pdf_csi *csi, void *state) +static void pdf_run_M(fz_context *ctx, pdf_processor *proc, float miterlimit) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); - /* If we are already in a hidden OCG, then we'll still be hidden - - * just increment the depth so we pop back to visibility when we've - * seen enough EDCs. */ - if (pr->in_hidden_ocg > 0) - { - pr->in_hidden_ocg++; - } + pr->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; + gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state); + gstate->stroke_state->miterlimit = miterlimit; } -static void pdf_run_BT(pdf_csi *csi, void *state) +static void pdf_run_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); + int len, i; - pr->tm = fz_identity; - pr->tlm = fz_identity; + len = pdf_array_len(ctx, array); + gstate->stroke_state = fz_unshare_stroke_state_with_dash_len(ctx, gstate->stroke_state, len); + gstate->stroke_state->dash_len = len; + for (i = 0; i < len; i++) + gstate->stroke_state->dash_list[i] = pdf_to_real(ctx, pdf_array_get(ctx, array, i)); + gstate->stroke_state->dash_phase = phase; } -static void pdf_run_BX(pdf_csi *csi, void *state) +static void pdf_run_ri(fz_context *ctx, pdf_processor *proc, const char *intent) { } -static void pdf_run_Bstar(pdf_csi *csi, void *state) +static void pdf_run_i(fz_context *ctx, pdf_processor *proc, float flatness) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 0, 1, 1, 1); } -static void pdf_run_cs_imp(pdf_csi *csi, pdf_run_state *pr, int what) +static void pdf_run_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate) { - fz_context *ctx = pr->ctx; - fz_colorspace *colorspace; - pdf_obj *obj, *dict; - pdf_obj *rdb = csi->rdb; - - if (!strcmp(csi->name, "Pattern")) - { - pdf_set_pattern(csi, pr, what, NULL, NULL); - } - else - { - if (!strcmp(csi->name, "DeviceGray")) - colorspace = fz_device_gray(ctx); /* No fz_keep_colorspace as static */ - else if (!strcmp(csi->name, "DeviceRGB")) - colorspace = fz_device_rgb(ctx); /* No fz_keep_colorspace as static */ - else if (!strcmp(csi->name, "DeviceCMYK")) - colorspace = fz_device_cmyk(ctx); /* No fz_keep_colorspace as static */ - else - { - dict = pdf_dict_gets(ctx, rdb, "ColorSpace"); - if (!dict) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ColorSpace dictionary"); - obj = pdf_dict_gets(ctx, dict, csi->name); - if (!obj) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find colorspace resource '%s'", csi->name); - colorspace = pdf_load_colorspace(ctx, csi->doc, obj); - } - - pdf_set_colorspace(csi, pr, what, colorspace); - - fz_drop_colorspace(ctx, colorspace); - } } -static void pdf_run_CS(pdf_csi *csi, void *state) +static void pdf_run_gs_end(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; +} - pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; +/* transparency graphics state */ - pdf_run_cs_imp(csi, pr, PDF_STROKE); +static void pdf_run_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); + gstate->blendmode = fz_lookup_blendmode(blendmode); } -static void pdf_run_cs(pdf_csi *csi, void *state) +static void pdf_run_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha) { - pdf_run_state *pr = (pdf_run_state *)state; - - pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; - - pdf_run_cs_imp(csi, pr, PDF_FILL); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); + gstate->stroke.alpha = fz_clamp(alpha, 0, 1); } -static void pdf_run_DP(pdf_csi *csi, void *state) +static void pdf_run_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha) { + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); + gstate->fill.alpha = fz_clamp(alpha, 0, 1); } -static void pdf_run_Do(pdf_csi *csi, void *state) +static void pdf_run_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_xobject *smask, pdf_obj *page_resources, float *bc, int luminosity) { - pdf_run_state *pr = (pdf_run_state *)state; - fz_context *ctx = csi->ctx; - pdf_obj *dict; - pdf_obj *obj; - pdf_obj *subtype; - pdf_obj *rdb = csi->rdb; - - dict = pdf_dict_gets(ctx, rdb, "XObject"); - if (!dict) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find XObject dictionary when looking for: '%s'", csi->name); - - obj = pdf_dict_gets(ctx, dict, csi->name); - if (!obj) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find xobject resource: '%s'", csi->name); - - subtype = pdf_dict_gets(ctx, obj, "Subtype"); - if (!pdf_is_name(ctx, subtype)) - fz_throw(ctx, FZ_ERROR_GENERIC, "no XObject subtype specified"); - - if (pdf_is_hidden_ocg(pdf_dict_gets(ctx, obj, "OC"), csi, pr, rdb)) - return; - - if (!strcmp(pdf_to_name(ctx, subtype), "Form") && pdf_dict_gets(ctx, obj, "Subtype2")) - subtype = pdf_dict_gets(ctx, obj, "Subtype2"); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); + int i; - if (!strcmp(pdf_to_name(ctx, subtype), "Form")) + if (gstate->softmask) { - pdf_xobject *xobj; - - xobj = pdf_load_xobject(ctx, csi->doc, obj); - - /* Inherit parent resources, in case this one was empty XXX check where it's loaded */ - if (!xobj->resources) - xobj->resources = pdf_keep_obj(ctx, rdb); - - fz_try(ctx) - { - run_xobject(csi, state, xobj->resources, xobj, &fz_identity); - } - fz_always(ctx) - { - pdf_drop_xobject(ctx, xobj); - } - fz_catch(ctx) - { - fz_rethrow_message(ctx, "cannot draw xobject (%d %d R)", pdf_to_num(ctx, obj), pdf_to_gen(ctx, obj)); - } + pdf_drop_xobject(ctx, gstate->softmask); + gstate->softmask = NULL; + pdf_drop_obj(ctx, gstate->softmask_resources); + gstate->softmask_resources = NULL; } - else if (!strcmp(pdf_to_name(ctx, subtype), "Image")) + if (smask) { - if ((pr->dev->hints & FZ_IGNORE_IMAGE) == 0) - { - fz_image *img = pdf_load_image(ctx, csi->doc, obj); - - fz_try(ctx) - { - pdf_show_image(csi, pr, img); - } - fz_always(ctx) - { - fz_drop_image(ctx, img); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } - } + fz_colorspace *cs = smask->colorspace; + if (!cs) + cs = fz_device_gray(ctx); + gstate->softmask_ctm = gstate->ctm; + gstate->softmask = pdf_keep_xobject(ctx, smask); + gstate->softmask_resources = pdf_keep_obj(ctx, page_resources); + for (i = 0; i < cs->n; ++i) + gstate->softmask_bc[i] = bc[i]; + gstate->luminosity = luminosity; } +} - else if (!strcmp(pdf_to_name(ctx, subtype), "PS")) - { - fz_warn(ctx, "ignoring XObject with subtype PS"); - } +/* special graphics state */ - else - { - fz_throw(ctx, FZ_ERROR_GENERIC, "unknown XObject subtype: '%s'", pdf_to_name(ctx, subtype)); - } +static void pdf_run_q(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gsave(ctx, pr); } -static void pdf_run_EMC(pdf_csi *csi, void *state) +static void pdf_run_Q(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - - if (pr->in_hidden_ocg > 0) - pr->in_hidden_ocg--; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_grestore(ctx, pr); } -static void pdf_run_ET(pdf_csi *csi, void *state) +static void pdf_run_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); + fz_matrix m; - pdf_flush_text(csi, pr); - pr->accumulate = 1; + m.a = a; + m.b = b; + m.c = c; + m.d = d; + m.e = e; + m.f = f; + fz_concat(&gstate->ctm, &m, &gstate->ctm); } -static void pdf_run_EX(pdf_csi *csi, void *state) +/* path construction */ + +static void pdf_run_m(fz_context *ctx, pdf_processor *proc, float x, float y) { + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_moveto(ctx, pr->path, x, y); } -static void pdf_run_F(pdf_csi *csi, void *state) +static void pdf_run_l(fz_context *ctx, pdf_processor *proc, float x, float y) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 0, 1, 0, 0); + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_lineto(ctx, pr->path, x, y); } - -static void pdf_run_G(pdf_csi *csi, void *state) +static void pdf_run_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3) { - pdf_run_state *pr = (pdf_run_state *)state; - - pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; - pdf_set_colorspace(csi, pr, PDF_STROKE, fz_device_gray(csi->ctx)); - pdf_set_color(csi, pr, PDF_STROKE, csi->stack); + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_curveto(ctx, pr->path, x1, y1, x2, y2, x3, y3); } -static void pdf_run_J(pdf_csi *csi, void *state) +static void pdf_run_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate = pr->gstate + pr->gtop; - - pr->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); - gstate->stroke_state = fz_unshare_stroke_state(csi->ctx, gstate->stroke_state); - gstate->stroke_state->start_cap = csi->stack[0]; - gstate->stroke_state->dash_cap = csi->stack[0]; - gstate->stroke_state->end_cap = csi->stack[0]; + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_curvetov(ctx, pr->path, x2, y2, x3, y3); } -static void pdf_run_K(pdf_csi *csi, void *state) +static void pdf_run_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3) { - pdf_run_state *pr = (pdf_run_state *)state; - - pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; - pdf_set_colorspace(csi, pr, PDF_STROKE, fz_device_cmyk(csi->ctx)); - pdf_set_color(csi, pr, PDF_STROKE, csi->stack); + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_curvetoy(ctx, pr->path, x1, y1, x3, y3); } -static void pdf_run_M(pdf_csi *csi, void *state) +static void pdf_run_h(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate = pr->gstate + pr->gtop; - - pr->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; - gstate->stroke_state = fz_unshare_stroke_state(csi->ctx, gstate->stroke_state); - gstate->stroke_state->miterlimit = csi->stack[0]; + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_closepath(ctx, pr->path); } -static void pdf_run_MP(pdf_csi *csi, void *state) +static void pdf_run_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h) { + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_moveto(ctx, pr->path, x, y); + fz_lineto(ctx, pr->path, x + w, y); + fz_lineto(ctx, pr->path, x + w, y + h); + fz_lineto(ctx, pr->path, x, y + h); + fz_closepath(ctx, pr->path); } -static void pdf_run_Q(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; +/* path painting */ - pdf_grestore(pr); +static void pdf_run_S(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 0, 0, 1, 0); } -static void pdf_run_RG(pdf_csi *csi, void *state) +static void pdf_run_s(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - - pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; - pdf_set_colorspace(csi, pr, PDF_STROKE, fz_device_rgb(csi->ctx)); - pdf_set_color(csi, pr, PDF_STROKE, csi->stack); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 1, 0, 1, 0); } -static void pdf_run_S(pdf_csi *csi, void *state) +static void pdf_run_F(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 0, 0, 1, 0); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 0, 1, 0, 0); } -static void pdf_run_SC_imp(pdf_csi *csi, pdf_run_state *pr, int what, pdf_material *mat) +static void pdf_run_f(fz_context *ctx, pdf_processor *proc) { - fz_context *ctx = pr->ctx; - pdf_obj *patterntype; - pdf_obj *dict; - pdf_obj *obj; - int kind; - pdf_obj *rdb = csi->rdb; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 0, 1, 0, 0); +} - kind = mat->kind; - if (csi->name[0]) - kind = PDF_MAT_PATTERN; +static void pdf_run_fstar(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 0, 1, 0, 1); +} - switch (kind) - { - case PDF_MAT_NONE: - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set color in mask objects"); +static void pdf_run_B(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 0, 1, 1, 0); +} - case PDF_MAT_COLOR: - pdf_set_color(csi, pr, what, csi->stack); - break; +static void pdf_run_Bstar(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 0, 1, 1, 1); +} - case PDF_MAT_PATTERN: - dict = pdf_dict_gets(ctx, rdb, "Pattern"); - if (!dict) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Pattern dictionary"); +static void pdf_run_b(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 1, 1, 1, 0); +} - obj = pdf_dict_gets(ctx, dict, csi->name); - if (!obj) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find pattern resource '%s'", csi->name); +static void pdf_run_bstar(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 1, 1, 1, 1); +} - patterntype = pdf_dict_gets(ctx, obj, "PatternType"); +static void pdf_run_n(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_path(ctx, pr, 0, 0, 0, 0); +} - if (pdf_to_int(ctx, patterntype) == 1) - { - pdf_pattern *pat; - pat = pdf_load_pattern(ctx, csi->doc, obj); - pdf_set_pattern(csi, pr, what, pat, csi->top > 0 ? csi->stack : NULL); - pdf_drop_pattern(ctx, pat); - } - else if (pdf_to_int(ctx, patterntype) == 2) - { - fz_shade *shd; - shd = pdf_load_shading(ctx, csi->doc, obj); - pdf_set_shade(csi, pr, what, shd); - fz_drop_shade(ctx, shd); - } - else - { - fz_throw(ctx, FZ_ERROR_GENERIC, "unknown pattern type: %d", pdf_to_int(ctx, patterntype)); - } - break; +/* clipping paths */ - case PDF_MAT_SHADE: - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set color in shade objects"); - } - mat->gstate_num = pr->gparent; +static void pdf_run_W(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->clip = 1; + pr->clip_even_odd = 0; } -static void pdf_run_SC(pdf_csi *csi, void *state) +static void pdf_run_Wstar(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate = pr->gstate + pr->gtop; - - pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; - pdf_run_SC_imp(csi, pr, PDF_STROKE, &gstate->stroke); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->clip = 1; + pr->clip_even_odd = 1; } -static void pdf_run_sc(pdf_csi *csi, void *state) +/* text objects */ + +static void pdf_run_BT(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate = pr->gstate + pr->gtop; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->tm = fz_identity; + pr->tlm = fz_identity; +} - pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; - pdf_run_SC_imp(csi, pr, PDF_FILL, &gstate->fill); +static void pdf_run_ET(fz_context *ctx, pdf_processor *proc) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_flush_text(ctx, pr); + pr->accumulate = 1; } -static void pdf_run_Tc(pdf_csi *csi, void *state) +/* text state */ + +static void pdf_run_Tc(fz_context *ctx, pdf_processor *proc, float charspace) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - - gstate->char_space = csi->stack[0]; + gstate->char_space = charspace; } -static void pdf_run_Tw(pdf_csi *csi, void *state) +static void pdf_run_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - - gstate->word_space = csi->stack[0]; + gstate->word_space = wordspace; } -static void pdf_run_Tz(pdf_csi *csi, void *state) +static void pdf_run_Tz(fz_context *ctx, pdf_processor *proc, float scale) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate; - float a = csi->stack[0] / 100; - - gstate = pdf_flush_text(csi, pr); - gstate->scale = a; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pdf_flush_text(ctx, pr); + gstate->scale = scale / 100; } -static void pdf_run_TL(pdf_csi *csi, void *state) +static void pdf_run_TL(fz_context *ctx, pdf_processor *proc, float leading) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - - gstate->leading = csi->stack[0]; + gstate->leading = leading; } -static void pdf_run_Tf(pdf_csi *csi, void *state) +static void pdf_run_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size) { - pdf_run_state *pr = (pdf_run_state *)state; - fz_context *ctx = csi->ctx; - pdf_obj *rdb = csi->rdb; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - pdf_obj *dict; - pdf_obj *obj; - - gstate->size = csi->stack[0]; if (gstate->font) pdf_drop_font(ctx, gstate->font); - gstate->font = NULL; - - dict = pdf_dict_gets(ctx, rdb, "Font"); - if (!dict) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Font dictionary"); - - obj = pdf_dict_gets(ctx, dict, csi->name); - if (!obj) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find font resource: '%s'", csi->name); - - gstate->font = load_font_or_hail_mary(csi, rdb, obj, pr->nested_depth); + gstate->font = pdf_keep_font(ctx, font); + gstate->size = size; } -static void pdf_run_Tr(pdf_csi *csi, void *state) +static void pdf_run_Tr(fz_context *ctx, pdf_processor *proc, int render) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - - gstate->render = csi->stack[0]; + gstate->render = render; } -static void pdf_run_Ts(pdf_csi *csi, void *state) +static void pdf_run_Ts(fz_context *ctx, pdf_processor *proc, float rise) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - - gstate->rise = csi->stack[0]; + gstate->rise = rise; } -static void pdf_run_Td(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; +/* text positioning */ - fz_pre_translate(&pr->tlm, csi->stack[0], csi->stack[1]); +static void pdf_run_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; + fz_pre_translate(&pr->tlm, tx, ty); pr->tm = pr->tlm; } -static void pdf_run_TD(pdf_csi *csi, void *state) +static void pdf_run_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - - gstate->leading = -csi->stack[1]; - fz_pre_translate(&pr->tlm, csi->stack[0], csi->stack[1]); + gstate->leading = -ty; + fz_pre_translate(&pr->tlm, tx, ty); pr->tm = pr->tlm; } -static void pdf_run_Tm(pdf_csi *csi, void *state) +static void pdf_run_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { - pdf_run_state *pr = (pdf_run_state *)state; - - pr->tm.a = csi->stack[0]; - pr->tm.b = csi->stack[1]; - pr->tm.c = csi->stack[2]; - pr->tm.d = csi->stack[3]; - pr->tm.e = csi->stack[4]; - pr->tm.f = csi->stack[5]; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->tm.a = a; + pr->tm.b = b; + pr->tm.c = c; + pr->tm.d = d; + pr->tm.e = e; + pr->tm.f = f; pr->tlm = pr->tm; } -static void pdf_run_Tstar(pdf_csi *csi, void *state) +static void pdf_run_Tstar(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - fz_pre_translate(&pr->tlm, 0, -gstate->leading); pr->tm = pr->tlm; } -static void pdf_run_Tj(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; - - if (csi->string_len) - pdf_show_string(csi, pr, csi->string, csi->string_len); - else - pdf_show_text(csi, pr, csi->obj); -} - -static void pdf_run_TJ(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; - - if (csi->string_len) - pdf_show_string(csi, pr, csi->string, csi->string_len); - else - pdf_show_text(csi, pr, csi->obj); -} - -static void pdf_run_W(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; +/* text showing */ - pr->clip = 1; - pr->clip_even_odd = 0; -} - -static void pdf_run_Wstar(pdf_csi *csi, void *state) +static void pdf_run_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *obj) { - pdf_run_state *pr = (pdf_run_state *)state; - - pr->clip = 1; - pr->clip_even_odd = 1; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_text(ctx, pr, obj); } -static void pdf_run_b(pdf_csi *csi, void *state) +static void pdf_run_Tj(fz_context *ctx, pdf_processor *proc, char *string, int string_len) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 1, 1, 1, 0); -} - -static void pdf_run_bstar(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 1, 1, 1, 1); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_show_string(ctx, pr, (unsigned char *)string, string_len); } -static void pdf_run_c(pdf_csi *csi, void *state) +static void pdf_run_squote(fz_context *ctx, pdf_processor *proc, char *string, int string_len) { - pdf_run_state *pr = (pdf_run_state *)state; - float a, b, c, d, e, f; - - a = csi->stack[0]; - b = csi->stack[1]; - c = csi->stack[2]; - d = csi->stack[3]; - e = csi->stack[4]; - f = csi->stack[5]; - fz_curveto(csi->ctx, pr->path, a, b, c, d, e, f); -} - -static void pdf_run_cm(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate; - fz_matrix m; - - gstate = pdf_flush_text(csi, pr); - m.a = csi->stack[0]; - m.b = csi->stack[1]; - m.c = csi->stack[2]; - m.d = csi->stack[3]; - m.e = csi->stack[4]; - m.f = csi->stack[5]; - - fz_concat(&gstate->ctm, &m, &gstate->ctm); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pdf_gstate *gstate = pr->gstate + pr->gtop; + fz_pre_translate(&pr->tlm, 0, -gstate->leading); + pr->tm = pr->tlm; + pdf_show_string(ctx, pr, (unsigned char*)string, string_len); } -static void pdf_run_d(pdf_csi *csi, void *state) +static void pdf_run_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *string, int string_len) { - fz_context *ctx = csi->ctx; - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; pdf_gstate *gstate = pr->gstate + pr->gtop; - pdf_obj *array; - int i; - int len; - - array = csi->obj; - len = pdf_array_len(ctx, array); - gstate->stroke_state = fz_unshare_stroke_state_with_dash_len(csi->ctx, gstate->stroke_state, len); - gstate->stroke_state->dash_len = len; - for (i = 0; i < len; i++) - gstate->stroke_state->dash_list[i] = pdf_to_real(ctx, pdf_array_get(ctx, array, i)); - gstate->stroke_state->dash_phase = csi->stack[0]; + gstate->word_space = aw; + gstate->char_space = ac; + fz_pre_translate(&pr->tlm, 0, -gstate->leading); + pr->tm = pr->tlm; + pdf_show_string(ctx, pr, (unsigned char*)string, string_len); } -static void pdf_run_d0(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; +/* type 3 fonts */ +static void pdf_run_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; if (pr->nested_depth > 1) return; pr->dev->flags |= FZ_DEVFLAG_COLOR; } -static void pdf_run_d1(pdf_csi *csi, void *state) +static void pdf_run_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury) { - pdf_run_state *pr = (pdf_run_state *)state; - + pdf_run_processor *pr = (pdf_run_processor *)proc; if (pr->nested_depth > 1) return; pr->dev->flags |= FZ_DEVFLAG_MASK | FZ_DEVFLAG_BBOX_DEFINED; @@ -2376,266 +1767,195 @@ static void pdf_run_d1(pdf_csi *csi, void *state) FZ_DEVFLAG_LINEJOIN_UNDEFINED | FZ_DEVFLAG_MITERLIMIT_UNDEFINED | FZ_DEVFLAG_LINEWIDTH_UNDEFINED); - - pr->dev->d1_rect.x0 = fz_min(csi->stack[2], csi->stack[4]); - pr->dev->d1_rect.y0 = fz_min(csi->stack[3], csi->stack[5]); - pr->dev->d1_rect.x1 = fz_max(csi->stack[2], csi->stack[4]); - pr->dev->d1_rect.y1 = fz_max(csi->stack[3], csi->stack[5]); + pr->dev->d1_rect.x0 = fz_min(llx, urx); + pr->dev->d1_rect.y0 = fz_min(lly, ury); + pr->dev->d1_rect.x1 = fz_max(llx, urx); + pr->dev->d1_rect.y1 = fz_max(lly, ury); } -static void pdf_run_f(pdf_csi *csi, void *state) -{ - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 0, 1, 0, 0); -} +/* color */ -static void pdf_run_fstar(pdf_csi *csi, void *state) +static void pdf_run_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 0, 1, 0, 1); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + if (!strcmp(name, "Pattern")) + pdf_set_pattern(ctx, pr, PDF_STROKE, NULL, NULL); + else + pdf_set_colorspace(ctx, pr, PDF_STROKE, colorspace); } -static void pdf_run_g(pdf_csi *csi, void *state) +static void pdf_run_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace) { - pdf_run_state *pr = (pdf_run_state *)state; - + pdf_run_processor *pr = (pdf_run_processor *)proc; pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; - pdf_set_colorspace(csi, pr, PDF_FILL, fz_device_gray(csi->ctx)); - pdf_set_color(csi, pr, PDF_FILL, csi->stack); + if (!strcmp(name, "Pattern")) + pdf_set_pattern(ctx, pr, PDF_FILL, NULL, NULL); + else + pdf_set_colorspace(ctx, pr, PDF_FILL, colorspace); } -static void pdf_run_gs(pdf_csi *csi, void *state) +static void pdf_run_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_obj *dict; - pdf_obj *obj; - fz_context *ctx = csi->ctx; - pdf_obj *rdb = csi->rdb; - - dict = pdf_dict_gets(ctx, rdb, "ExtGState"); - if (!dict) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ExtGState dictionary"); - - obj = pdf_dict_gets(ctx, dict, csi->name); - if (!obj) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find extgstate resource '%s'", csi->name); - - pdf_run_extgstate(csi, pr, rdb, obj); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + pdf_set_color(ctx, pr, PDF_STROKE, color); } -static void pdf_run_h(pdf_csi *csi, void *state) +static void pdf_run_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { - pdf_run_state *pr = (pdf_run_state *)state; - - fz_closepath(csi->ctx, pr->path); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; + pdf_set_color(ctx, pr, PDF_FILL, color); } -static void pdf_run_i(pdf_csi *csi, void *state) +static void pdf_run_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + pdf_set_pattern(ctx, pr, PDF_STROKE, pat, color); } -static void pdf_run_j(pdf_csi *csi, void *state) +static void pdf_run_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate = pr->gstate + pr->gtop; - - pr->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; - gstate->stroke_state = fz_unshare_stroke_state(csi->ctx, gstate->stroke_state); - gstate->stroke_state->linejoin = csi->stack[0]; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; + pdf_set_pattern(ctx, pr, PDF_FILL, pat, color); } -static void pdf_run_k(pdf_csi *csi, void *state) +static void pdf_run_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + pdf_set_shade(ctx, pr, PDF_STROKE, shade); +} +static void pdf_run_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) +{ + pdf_run_processor *pr = (pdf_run_processor *)proc; pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; - pdf_set_colorspace(csi, pr, PDF_FILL, fz_device_cmyk(csi->ctx)); - pdf_set_color(csi, pr, PDF_FILL, csi->stack); + pdf_set_shade(ctx, pr, PDF_FILL, shade); } -static void pdf_run_l(pdf_csi *csi, void *state) +static void pdf_run_G(fz_context *ctx, pdf_processor *proc, float g) { - pdf_run_state *pr = (pdf_run_state *)state; - float a, b; - - a = csi->stack[0]; - b = csi->stack[1]; - fz_lineto(csi->ctx, pr->path, a, b); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_gray(ctx)); + pdf_set_color(ctx, pr, PDF_STROKE, &g); } -static void pdf_run_m(pdf_csi *csi, void *state) +static void pdf_run_g(fz_context *ctx, pdf_processor *proc, float g) { - pdf_run_state *pr = (pdf_run_state *)state; - float a, b; - - a = csi->stack[0]; - b = csi->stack[1]; - fz_moveto(csi->ctx, pr->path, a, b); + pdf_run_processor *pr = (pdf_run_processor *)proc; + pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; + pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_gray(ctx)); + pdf_set_color(ctx, pr, PDF_FILL, &g); } -static void pdf_run_n(pdf_csi *csi, void *state) +static void pdf_run_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 0, 0, 0, 0); + pdf_run_processor *pr = (pdf_run_processor *)proc; + float color[4] = {c, m, y, k}; + pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_cmyk(ctx)); + pdf_set_color(ctx, pr, PDF_STROKE, color); } -static void pdf_run_q(pdf_csi *csi, void *state) +static void pdf_run_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_gsave(pr); + pdf_run_processor *pr = (pdf_run_processor *)proc; + float color[4] = {c, m, y, k}; + pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; + pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_cmyk(ctx)); + pdf_set_color(ctx, pr, PDF_FILL, color); } -static void pdf_run_re(pdf_csi *csi, void *state) +static void pdf_run_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { - pdf_run_state *pr = (pdf_run_state *)state; - fz_context *ctx = csi->ctx; - float x, y, w, h; - - x = csi->stack[0]; - y = csi->stack[1]; - w = csi->stack[2]; - h = csi->stack[3]; - - fz_moveto(ctx, pr->path, x, y); - fz_lineto(ctx, pr->path, x + w, y); - fz_lineto(ctx, pr->path, x + w, y + h); - fz_lineto(ctx, pr->path, x, y + h); - fz_closepath(ctx, pr->path); + pdf_run_processor *pr = (pdf_run_processor *)proc; + float color[3] = {r, g, b}; + pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; + pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_rgb(ctx)); + pdf_set_color(ctx, pr, PDF_STROKE, color); } -static void pdf_run_rg(pdf_csi *csi, void *state) +static void pdf_run_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { - pdf_run_state *pr = (pdf_run_state *)state; - + pdf_run_processor *pr = (pdf_run_processor *)proc; + float color[3] = {r, g, b}; pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; - pdf_set_colorspace(csi, pr, PDF_FILL, fz_device_rgb(csi->ctx)); - pdf_set_color(csi, pr, PDF_FILL, csi->stack); + pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_rgb(ctx)); + pdf_set_color(ctx, pr, PDF_FILL, color); } -static void pdf_run_ri(pdf_csi *csi, void *state) +/* shadings, images, xobjects */ + +static void pdf_run_BI(fz_context *ctx, pdf_processor *proc, fz_image *image) { + pdf_run_processor *pr = (pdf_run_processor *)proc; + if ((pr->dev->hints & FZ_IGNORE_IMAGE) == 0) + pdf_show_image(ctx, pr, image); } -static void pdf_run_s(pdf_csi *csi, void *state) +static void pdf_run_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { - pdf_run_state *pr = (pdf_run_state *)state; - - pdf_show_path(csi, pr, 1, 0, 1, 0); + pdf_run_processor *pr = (pdf_run_processor *)proc; + if ((pr->dev->hints & FZ_IGNORE_SHADE) == 0) + pdf_show_shade(ctx, pr, shade); } -static void pdf_run_sh(pdf_csi *csi, void *state) +static void pdf_run_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image) { - pdf_run_state *pr = (pdf_run_state *)state; - fz_context *ctx = csi->ctx; - pdf_obj *rdb = csi->rdb; - pdf_obj *dict; - pdf_obj *obj; - fz_shade *shd; + pdf_run_processor *pr = (pdf_run_processor *)proc; + if ((pr->dev->hints & FZ_IGNORE_IMAGE) == 0) + pdf_show_image(ctx, pr, image); +} - dict = pdf_dict_gets(ctx, rdb, "Shading"); - if (!dict) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find shading dictionary"); +static void pdf_run_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_xobject *xobj, pdf_obj *page_resources) +{ + pdf_run_xobject(ctx, (pdf_run_processor*)proc, xobj, page_resources, &fz_identity); +} - obj = pdf_dict_gets(ctx, dict, csi->name); - if (!obj) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find shading resource: '%s'", csi->name); +/* marked content */ - if ((pr->dev->hints & FZ_IGNORE_SHADE) == 0) - { - shd = pdf_load_shading(ctx, csi->doc, obj); - - fz_try(ctx) - { - pdf_show_shade(csi, pr, shd); - } - fz_always(ctx) - { - fz_drop_shade(ctx, shd); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } - } +static void pdf_run_MP(fz_context *ctx, pdf_processor *proc, const char *tag) +{ } -static void pdf_run_v(pdf_csi *csi, void *state) +static void pdf_run_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *properties) { - pdf_run_state *pr = (pdf_run_state *)state; - float a, b, c, d; - - a = csi->stack[0]; - b = csi->stack[1]; - c = csi->stack[2]; - d = csi->stack[3]; - fz_curvetov(csi->ctx, pr->path, a, b, c, d); } -static void pdf_run_w(pdf_csi *csi, void *state) +static void pdf_run_BMC(fz_context *ctx, pdf_processor *proc, const char *tag) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate; - - gstate = pdf_flush_text(csi, pr); /* linewidth affects stroked text rendering mode */ - pr->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; - gstate->stroke_state = fz_unshare_stroke_state(csi->ctx, gstate->stroke_state); - gstate->stroke_state->linewidth = csi->stack[0]; } -static void pdf_run_y(pdf_csi *csi, void *state) +static void pdf_run_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *properties) { - pdf_run_state *pr = (pdf_run_state *)state; - float a, b, c, d; - - a = csi->stack[0]; - b = csi->stack[1]; - c = csi->stack[2]; - d = csi->stack[3]; - fz_curvetoy(csi->ctx, pr->path, a, b, c, d); } -static void pdf_run_squote(pdf_csi *csi, void *state) +static void pdf_run_EMC(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate = pr->gstate + pr->gtop; +} - fz_pre_translate(&pr->tlm, 0, -gstate->leading); - pr->tm = pr->tlm; +/* compatibility */ - if (csi->string_len) - pdf_show_string(csi, pr, csi->string, csi->string_len); - else - pdf_show_text(csi, pr, csi->obj); +static void pdf_run_BX(fz_context *ctx, pdf_processor *proc) +{ } -static void pdf_run_dquote(pdf_csi *csi, void *state) +static void pdf_run_EX(fz_context *ctx, pdf_processor *proc) { - pdf_run_state *pr = (pdf_run_state *)state; - pdf_gstate *gstate = pr->gstate + pr->gtop; - - gstate->word_space = csi->stack[0]; - gstate->char_space = csi->stack[1]; - - fz_pre_translate(&pr->tlm, 0, -gstate->leading); - pr->tm = pr->tlm; - - if (csi->string_len) - pdf_show_string(csi, pr, csi->string, csi->string_len); - else - pdf_show_text(csi, pr, csi->obj); } -static void free_processor_normal(pdf_csi *csi, void *state) +static void +pdf_run_drop_imp(fz_context *ctx, pdf_processor *proc) { - fz_context *ctx = csi->ctx; - pdf_run_state *pr = (pdf_run_state *)state; + pdf_run_processor *pr = (pdf_run_processor *)proc; while (pr->gtop) - pdf_grestore(pr); + pdf_grestore(ctx, pr); pdf_drop_material(ctx, &pr->gstate[0].fill); pdf_drop_material(ctx, &pr->gstate[0].stroke); @@ -2648,218 +1968,172 @@ static void free_processor_normal(pdf_csi *csi, void *state) while (pr->gstate[0].clip_depth--) fz_pop_clip(ctx, pr->dev); - if (pr->path) fz_drop_path(ctx, pr->path); - if (pr->text) fz_drop_text(ctx, pr->text); + fz_drop_path(ctx, pr->path); + fz_drop_text(ctx, pr->text); fz_free(ctx, pr->gstate); - fz_free(ctx, pr); -} - -static void -process_annot(pdf_csi *csi, void *state, pdf_obj *resources, pdf_annot *annot) -{ - pdf_run_state *pr = (pdf_run_state *)state; - fz_context *ctx = pr->ctx; - int flags; - - if (pdf_is_hidden_ocg(pdf_dict_gets(ctx, annot->obj, "OC"), csi, pr, resources)) - return; - - flags = pdf_to_int(ctx, pdf_dict_gets(ctx, annot->obj, "F")); - if (!strcmp(pr->event, "Print") && !(flags & (1 << 2))) /* Print */ - return; - if (!strcmp(pr->event, "View") && (flags & (1 << 5))) /* NoView */ - return; - - fz_try(ctx) - { - /* We need to save an extra level here to allow for level 0 - * to be the 'parent' gstate level. */ - pdf_gsave(pr); - run_xobject(csi, state, resources, annot->ap, &annot->matrix); - } - fz_catch(ctx) - { - while (pr->gtop > 0) - pdf_grestore(pr); - fz_rethrow(ctx); - } -} - -static void -process_stream(pdf_csi *csi, void *state, pdf_lexbuf *buf) -{ - pdf_run_state *pr = (pdf_run_state *)state; - fz_context *ctx = pr->ctx; - int save_gbot; - - save_gbot = pr->gbot; - pr->gbot = pr->gtop; - fz_try(ctx) - { - pdf_process_stream(csi, buf); - } - fz_always(ctx) - { - while (pr->gtop > pr->gbot) - pdf_grestore(pr); - pr->gbot = save_gbot; - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } } -static void -process_contents(pdf_csi *csi, void *state, pdf_obj *resources, pdf_obj *contents) -{ - pdf_run_state *pr = (pdf_run_state *)state; - fz_context *ctx = pr->ctx; +pdf_processor * +pdf_new_run_processor(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, const char *event, pdf_gstate *gstate, int nested) +{ + pdf_run_processor *proc = pdf_new_processor(ctx, sizeof *proc); + { + proc->super.event = event; + + proc->super.drop_imp = pdf_run_drop_imp; + + /* general graphics state */ + proc->super.op_w = pdf_run_w; + proc->super.op_j = pdf_run_j; + proc->super.op_J = pdf_run_J; + proc->super.op_M = pdf_run_M; + proc->super.op_d = pdf_run_d; + proc->super.op_ri = pdf_run_ri; + proc->super.op_i = pdf_run_i; + proc->super.op_gs_begin = pdf_run_gs_begin; + proc->super.op_gs_end = pdf_run_gs_end; + + /* transparency graphics state */ + proc->super.op_gs_BM = pdf_run_gs_BM; + proc->super.op_gs_CA = pdf_run_gs_CA; + proc->super.op_gs_ca = pdf_run_gs_ca; + proc->super.op_gs_SMask = pdf_run_gs_SMask; + + /* special graphics state */ + proc->super.op_q = pdf_run_q; + proc->super.op_Q = pdf_run_Q; + proc->super.op_cm = pdf_run_cm; + + /* path construction */ + proc->super.op_m = pdf_run_m; + proc->super.op_l = pdf_run_l; + proc->super.op_c = pdf_run_c; + proc->super.op_v = pdf_run_v; + proc->super.op_y = pdf_run_y; + proc->super.op_h = pdf_run_h; + proc->super.op_re = pdf_run_re; + + /* path painting */ + proc->super.op_S = pdf_run_S; + proc->super.op_s = pdf_run_s; + proc->super.op_F = pdf_run_F; + proc->super.op_f = pdf_run_f; + proc->super.op_fstar = pdf_run_fstar; + proc->super.op_B = pdf_run_B; + proc->super.op_Bstar = pdf_run_Bstar; + proc->super.op_b = pdf_run_b; + proc->super.op_bstar = pdf_run_bstar; + proc->super.op_n = pdf_run_n; + + /* clipping paths */ + proc->super.op_W = pdf_run_W; + proc->super.op_Wstar = pdf_run_Wstar; + + /* text objects */ + proc->super.op_BT = pdf_run_BT; + proc->super.op_ET = pdf_run_ET; + + /* text state */ + proc->super.op_Tc = pdf_run_Tc; + proc->super.op_Tw = pdf_run_Tw; + proc->super.op_Tz = pdf_run_Tz; + proc->super.op_TL = pdf_run_TL; + proc->super.op_Tf = pdf_run_Tf; + proc->super.op_Tr = pdf_run_Tr; + proc->super.op_Ts = pdf_run_Ts; + + /* text positioning */ + proc->super.op_Td = pdf_run_Td; + proc->super.op_TD = pdf_run_TD; + proc->super.op_Tm = pdf_run_Tm; + proc->super.op_Tstar = pdf_run_Tstar; + + /* text showing */ + proc->super.op_TJ = pdf_run_TJ; + proc->super.op_Tj = pdf_run_Tj; + proc->super.op_squote = pdf_run_squote; + proc->super.op_dquote = pdf_run_dquote; + + /* type 3 fonts */ + proc->super.op_d0 = pdf_run_d0; + proc->super.op_d1 = pdf_run_d1; + + /* color */ + proc->super.op_CS = pdf_run_CS; + proc->super.op_cs = pdf_run_cs; + proc->super.op_SC_color = pdf_run_SC_color; + proc->super.op_sc_color = pdf_run_sc_color; + proc->super.op_SC_pattern = pdf_run_SC_pattern; + proc->super.op_sc_pattern = pdf_run_sc_pattern; + proc->super.op_SC_shade = pdf_run_SC_shade; + proc->super.op_sc_shade = pdf_run_sc_shade; + + proc->super.op_G = pdf_run_G; + proc->super.op_g = pdf_run_g; + proc->super.op_RG = pdf_run_RG; + proc->super.op_rg = pdf_run_rg; + proc->super.op_K = pdf_run_K; + proc->super.op_k = pdf_run_k; + + /* shadings, images, xobjects */ + proc->super.op_BI = pdf_run_BI; + proc->super.op_sh = pdf_run_sh; + proc->super.op_Do_image = pdf_run_Do_image; + proc->super.op_Do_form = pdf_run_Do_form; + + /* marked content */ + proc->super.op_MP = pdf_run_MP; + proc->super.op_DP = pdf_run_DP; + proc->super.op_BMC = pdf_run_BMC; + proc->super.op_BDC = pdf_run_BDC; + proc->super.op_EMC = pdf_run_EMC; + + /* compatibility */ + proc->super.op_BX = pdf_run_BX; + proc->super.op_EX = pdf_run_EX; + } + + proc->dev = dev; + + proc->nested_depth = nested; + + proc->path = NULL; + proc->clip = 0; + proc->clip_even_odd = 0; + + proc->text = NULL; + proc->tlm = fz_identity; + proc->tm = fz_identity; + proc->text_mode = 0; + proc->accumulate = 1; fz_try(ctx) { - /* We need to save an extra level here to allow for level 0 - * to be the 'parent' gstate level. */ - pdf_gsave(pr); - pdf_process_contents_object(csi, resources, contents); - } - fz_always(ctx) - { - while (pr->gtop > 0) - pdf_grestore(pr); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } -} + proc->path = fz_new_path(ctx); -const pdf_processor pdf_processor_normal = -{ - { - pdf_run_dquote, - pdf_run_squote, - pdf_run_B, - pdf_run_Bstar, - pdf_run_BDC, - pdf_run_BI, - pdf_run_BMC, - pdf_run_BT, - pdf_run_BX, - pdf_run_CS, - pdf_run_DP, - pdf_run_EMC, - pdf_run_ET, - pdf_run_EX, - pdf_run_F, - pdf_run_G, - pdf_run_J, - pdf_run_K, - pdf_run_M, - pdf_run_MP, - pdf_run_Q, - pdf_run_RG, - pdf_run_S, - pdf_run_SC, - pdf_run_SC, /* SCN */ - pdf_run_Tstar, - pdf_run_TD, - pdf_run_TJ, - pdf_run_TL, - pdf_run_Tc, - pdf_run_Td, - pdf_run_Tj, - pdf_run_Tm, - pdf_run_Tr, - pdf_run_Ts, - pdf_run_Tw, - pdf_run_Tz, - pdf_run_W, - pdf_run_Wstar, - pdf_run_b, - pdf_run_bstar, - pdf_run_c, - pdf_run_cm, - pdf_run_cs, - pdf_run_d, - pdf_run_d0, - pdf_run_d1, - pdf_run_f, - pdf_run_fstar, - pdf_run_g, - pdf_run_h, - pdf_run_i, - pdf_run_j, - pdf_run_k, - pdf_run_l, - pdf_run_m, - pdf_run_n, - pdf_run_q, - pdf_run_re, - pdf_run_rg, - pdf_run_ri, - pdf_run_s, - pdf_run_sc, - pdf_run_sc, /* scn */ - pdf_run_v, - pdf_run_w, - pdf_run_y, - pdf_run_Do, - pdf_run_Tf, - pdf_run_gs, - pdf_run_sh, - free_processor_normal - }, - process_annot, - process_stream, - process_contents -}; - -pdf_process *pdf_init_process_run(fz_context *ctx, pdf_process *process, fz_device *dev, const fz_matrix *ctm, const char *event, pdf_gstate *gstate, int nested) -{ - pdf_run_state *pr; + proc->gcap = 64; + proc->gstate = fz_malloc_array(ctx, proc->gcap, sizeof(pdf_gstate)); - pr = fz_malloc_struct(ctx, pdf_run_state); - fz_try(ctx) - { - pr->ctx = ctx; - pr->dev = dev; - pr->in_hidden_ocg = 0; - pr->event = event; - - pr->path = fz_new_path(ctx); - pr->clip = 0; - pr->clip_even_odd = 0; - - pr->text = NULL; - pr->tlm = fz_identity; - pr->tm = fz_identity; - pr->text_mode = 0; - pr->accumulate = 1; - - pr->gcap = 64; - pr->gstate = fz_malloc_array(ctx, pr->gcap, sizeof(pdf_gstate)); - - pr->nested_depth = nested; - pdf_init_gstate(ctx, &pr->gstate[0], ctm); + pdf_init_gstate(ctx, &proc->gstate[0], ctm); if (gstate) { - pdf_copy_gstate(ctx, &pr->gstate[0], gstate); - pr->gstate[0].ctm = *ctm; + pdf_copy_gstate(ctx, &proc->gstate[0], gstate); + proc->gstate[0].ctm = *ctm; } - pr->gtop = 0; - pr->gbot = 0; - pr->gparent = 0; + proc->gtop = 0; + proc->gbot = 0; + proc->gparent = 0; } fz_catch(ctx) { - fz_drop_path(ctx, pr->path); - fz_free(ctx, pr); + fz_drop_path(ctx, proc->path); + fz_free(ctx, proc); fz_rethrow(ctx); } - process->state = pr; - process->processor = &pdf_processor_normal; - return process; + /* We need to save an extra level to allow for level 0 to be the parent gstate level. */ + pdf_gsave(ctx, proc); + + return (pdf_processor*)proc; } diff --git a/source/pdf/pdf-pattern.c b/source/pdf/pdf-pattern.c index 93fbdd3e..32fd077c 100644 --- a/source/pdf/pdf-pattern.c +++ b/source/pdf/pdf-pattern.c @@ -16,7 +16,6 @@ static void pdf_drop_pattern_imp(fz_context *ctx, fz_storable *pat_) { pdf_pattern *pat = (pdf_pattern *)pat_; - if (pat->resources) pdf_drop_obj(ctx, pat->resources); if (pat->contents) @@ -45,38 +44,39 @@ pdf_load_pattern(fz_context *ctx, pdf_document *doc, pdf_obj *dict) pat = fz_malloc_struct(ctx, pdf_pattern); FZ_INIT_STORABLE(pat, 1, pdf_drop_pattern_imp); + pat->document = doc; pat->resources = NULL; pat->contents = NULL; - /* Store pattern now, to avoid possible recursion if objects refer back to this one */ - pdf_store_item(ctx, dict, pat, pdf_pattern_size(pat)); + fz_try(ctx) + { + /* Store pattern now, to avoid possible recursion if objects refer back to this one */ + pdf_store_item(ctx, dict, pat, pdf_pattern_size(pat)); - pat->ismask = pdf_to_int(ctx, pdf_dict_gets(ctx, dict, "PaintType")) == 2; - pat->xstep = pdf_to_real(ctx, pdf_dict_gets(ctx, dict, "XStep")); - pat->ystep = pdf_to_real(ctx, pdf_dict_gets(ctx, dict, "YStep")); + pat->ismask = pdf_to_int(ctx, pdf_dict_gets(ctx, dict, "PaintType")) == 2; + pat->xstep = pdf_to_real(ctx, pdf_dict_gets(ctx, dict, "XStep")); + pat->ystep = pdf_to_real(ctx, pdf_dict_gets(ctx, dict, "YStep")); - obj = pdf_dict_gets(ctx, dict, "BBox"); - pdf_to_rect(ctx, obj, &pat->bbox); + obj = pdf_dict_gets(ctx, dict, "BBox"); + pdf_to_rect(ctx, obj, &pat->bbox); - obj = pdf_dict_gets(ctx, dict, "Matrix"); - if (obj) - pdf_to_matrix(ctx, obj, &pat->matrix); - else - pat->matrix = fz_identity; + obj = pdf_dict_gets(ctx, dict, "Matrix"); + if (obj) + pdf_to_matrix(ctx, obj, &pat->matrix); + else + pat->matrix = fz_identity; - pat->resources = pdf_dict_gets(ctx, dict, "Resources"); - if (pat->resources) - pdf_keep_obj(ctx, pat->resources); + pat->resources = pdf_dict_gets(ctx, dict, "Resources"); + if (pat->resources) + pdf_keep_obj(ctx, pat->resources); - fz_try(ctx) - { pat->contents = pdf_keep_obj(ctx, dict); } fz_catch(ctx) { pdf_remove_item(ctx, pdf_drop_pattern_imp, dict); pdf_drop_pattern(ctx, pat); - fz_rethrow_message(ctx, "cannot load pattern stream (%d %d R)", pdf_to_num(ctx, dict), pdf_to_gen(ctx, dict)); + fz_rethrow_message(ctx, "cannot load pattern (%d %d R)", pdf_to_num(ctx, dict), pdf_to_gen(ctx, dict)); } return pat; } diff --git a/source/pdf/pdf-run.c b/source/pdf/pdf-run.c index e6f3d5b9..57807cc2 100644 --- a/source/pdf/pdf-run.c +++ b/source/pdf/pdf-run.c @@ -1,22 +1,26 @@ -#include "pdf-interpret-imp.h" +#include "mupdf/pdf.h" static void pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *annot, fz_device *dev, const fz_matrix *ctm, char *event, fz_cookie *cookie) { fz_matrix local_ctm; - pdf_process process; + pdf_processor *proc; fz_concat(&local_ctm, &page->ctm, ctm); - pdf_init_process_run(ctx, &process, dev, &local_ctm, event, NULL, 0); - - pdf_process_annot(ctx, doc, page, annot, &process, cookie); + proc = pdf_new_run_processor(ctx, dev, &local_ctm, event, NULL, 0); + fz_try(ctx) + pdf_process_annot(ctx, proc, doc, page, annot, cookie); + fz_always(ctx) + pdf_drop_processor(ctx, proc); + fz_catch(ctx) + fz_rethrow(ctx); } static void pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, char *event, fz_cookie *cookie) { fz_matrix local_ctm; - pdf_process process; + pdf_processor *proc; fz_concat(&local_ctm, &page->ctm, ctm); @@ -26,9 +30,14 @@ static void pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, fz_begin_group(ctx, dev, fz_transform_rect(&mediabox, &local_ctm), 1, 0, 0, 1); } - pdf_init_process_run(ctx, &process, dev, &local_ctm, event, NULL, 0); + proc = pdf_new_run_processor(ctx, dev, &local_ctm, event, NULL, 0); - pdf_process_stream_object(ctx, doc, page->contents, &process, page->resources, cookie); + fz_try(ctx) + pdf_process_contents(ctx, proc, doc, page->resources, page->contents, cookie); + fz_always(ctx) + pdf_drop_processor(ctx, proc); + fz_catch(ctx) + fz_rethrow(ctx); if (page->transparency) fz_end_group(ctx, dev); @@ -147,12 +156,16 @@ pdf_run_page(fz_context *ctx, pdf_page *page, fz_device *dev, const fz_matrix *c void pdf_run_glyph(fz_context *ctx, pdf_document *doc, pdf_obj *resources, fz_buffer *contents, fz_device *dev, const fz_matrix *ctm, void *gstate, int nested_depth) { - pdf_process process; + pdf_processor *proc; if (nested_depth > 10) fz_throw(ctx, FZ_ERROR_GENERIC, "Too many nestings of Type3 glyphs"); - pdf_init_process_run(ctx, &process, dev, ctm, "View", gstate, nested_depth+1); - - pdf_process_glyph(ctx, doc, resources, contents, &process); + proc = pdf_new_run_processor(ctx, dev, ctm, "View", gstate, nested_depth+1); + fz_try(ctx) + pdf_process_glyph(ctx, proc, doc, resources, contents); + fz_always(ctx) + pdf_drop_processor(ctx, proc); + fz_catch(ctx) + fz_rethrow(ctx); } diff --git a/source/pdf/pdf-stream.c b/source/pdf/pdf-stream.c index 2335e67a..15fdd29a 100644 --- a/source/pdf/pdf-stream.c +++ b/source/pdf/pdf-stream.c @@ -620,6 +620,5 @@ pdf_open_contents_stream(fz_context *ctx, pdf_document *doc, pdf_obj *obj) if (pdf_is_stream(ctx, doc, num, gen)) return pdf_open_image_stream(ctx, doc, num, gen, num, gen, NULL); - fz_warn(ctx, "pdf object stream missing (%d %d R)", num, gen); - return NULL; + fz_throw(ctx, FZ_ERROR_GENERIC, "pdf object stream missing (%d %d R)", num, gen); } diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c index ac97e6e4..a9dd7423 100644 --- a/source/pdf/pdf-write.c +++ b/source/pdf/pdf-write.c @@ -2408,7 +2408,7 @@ make_hint_stream(fz_context *ctx, pdf_document *doc, pdf_write_options *opts) fz_try(ctx) { make_page_offset_hints(ctx, doc, opts, buf); - pdf_update_stream(ctx, doc, pdf_load_object(ctx, doc, pdf_xref_len(ctx, doc)-1, 0), buf, 0); // XXX + pdf_update_stream(ctx, doc, pdf_load_object(ctx, doc, pdf_xref_len(ctx, doc)-1, 0), buf, 0); opts->hintstream_len = buf->len; fz_drop_buffer(ctx, buf); } diff --git a/source/pdf/pdf-xobject.c b/source/pdf/pdf-xobject.c index b9afa857..404616ae 100644 --- a/source/pdf/pdf-xobject.c +++ b/source/pdf/pdf-xobject.c @@ -46,6 +46,7 @@ pdf_load_xobject(fz_context *ctx, pdf_document *doc, pdf_obj *dict) form = fz_malloc_struct(ctx, pdf_xobject); FZ_INIT_STORABLE(form, 1, pdf_drop_xobject_imp); + form->document = doc; form->resources = NULL; form->contents = NULL; form->colorspace = NULL; @@ -181,6 +182,7 @@ pdf_new_xobject(fz_context *ctx, pdf_document *doc, const fz_rect *bbox, const f form = fz_malloc_struct(ctx, pdf_xobject); FZ_INIT_STORABLE(form, 1, pdf_drop_xobject_imp); + form->document = doc; form->resources = NULL; form->contents = NULL; form->colorspace = NULL; |