diff options
Diffstat (limited to 'source/pdf/pdf-interpret.c')
-rw-r--r-- | source/pdf/pdf-interpret.c | 1314 |
1 files changed, 967 insertions, 347 deletions
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) { |