diff options
author | Robin Watts <robin.watts@artifex.com> | 2016-11-09 17:41:43 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2016-11-11 13:18:39 +0000 |
commit | da50c6f300e565c8eedf4ce252c44b5ddbb95cee (patch) | |
tree | d63891b1494b45046973cbc1ab3b4435821fc3f1 /source/pdf/pdf-interpret.c | |
parent | a1d18b804019ad89841f289c465755d7feebe823 (diff) | |
download | mupdf-da50c6f300e565c8eedf4ce252c44b5ddbb95cee.tar.xz |
Add pdf_layer configuration API.
Add API to:
* allow enumeration of layer configs (OCCDs) within PDF files.
* allow selection of layer configs.
* allow enumeration of the "UI" (or "Human readable") form of layer
configs.
* allow selection/toggling of entries in the UI.
Diffstat (limited to 'source/pdf/pdf-interpret.c')
-rw-r--r-- | source/pdf/pdf-interpret.c | 226 |
1 files changed, 6 insertions, 220 deletions
diff --git a/source/pdf/pdf-interpret.c b/source/pdf/pdf-interpret.c index 58999373..4a8a2a46 100644 --- a/source/pdf/pdf-interpret.c +++ b/source/pdf/pdf-interpret.c @@ -81,220 +81,6 @@ load_font_or_hail_mary(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj return desc; } -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; -} - -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, *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_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME_Properties), 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_dict_get(ctx, ocg, PDF_NAME_Type); - - if (pdf_name_eq(ctx, type, PDF_NAME_OCG)) - { - /* An Optional Content Group */ - int default_value = 0; - int num = pdf_to_num(ctx, ocg); - int len = desc->len; - int i; - pdf_obj *es; - - /* by default an OCG is visible, unless it's explicitly hidden */ - for (i = 0; i < len; i++) - { - if (desc->ocgs[i].num == num) - { - 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_get(ctx, ocg, PDF_NAME_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_get(ctx, ocg, PDF_NAME_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); - es = pdf_dict_gets(ctx, obj2, event_state); - if (pdf_name_eq(ctx, es, PDF_NAME_OFF)) - { - return 1; - } - if (pdf_name_eq(ctx, es, PDF_NAME_ON)) - { - return 0; - } - return default_value; - } - else if (pdf_name_eq(ctx, type, PDF_NAME_OCMD)) - { - /* An Optional Content Membership Dictionary */ - pdf_obj *name; - int combine, on; - - obj = pdf_dict_get(ctx, ocg, PDF_NAME_VE); - if (pdf_is_array(ctx, obj)) { - /* FIXME: Calculate visibility from array */ - return 0; - } - name = pdf_dict_get(ctx, ocg, PDF_NAME_P); - /* Set combine; Bit 0 set => AND, Bit 1 set => true means - * Off, otherwise true means On */ - if (pdf_name_eq(ctx, name, PDF_NAME_AllOn)) - { - combine = 1; - } - else if (pdf_name_eq(ctx, name, PDF_NAME_AnyOff)) - { - combine = 2; - } - else if (pdf_name_eq(ctx, name, PDF_NAME_AllOff)) - { - 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_get(ctx, ocg, PDF_NAME_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 fz_image * parse_inline_image(fz_context *ctx, pdf_csi *csi, fz_stream *stm) { @@ -530,7 +316,7 @@ pdf_process_Do(fz_context *ctx, pdf_processor *proc, pdf_csi *csi) 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_get(ctx, xobj, PDF_NAME_OC))) + if (pdf_is_hidden_ocg(ctx, csi->doc->ocg, csi->rdb, proc->usage, pdf_dict_get(ctx, xobj, PDF_NAME_OC))) return; if (pdf_name_eq(ctx, subtype, PDF_NAME_Form)) @@ -726,7 +512,7 @@ pdf_process_BDC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi) if (!pdf_name_eq(ctx, pdf_dict_get(ctx, cooked, PDF_NAME_Type), PDF_NAME_OCG)) return; - if (pdf_is_hidden_ocg(ctx, csi->doc->ocg, csi->rdb, proc->event, cooked)) + if (pdf_is_hidden_ocg(ctx, csi->doc->ocg, csi->rdb, proc->usage, cooked)) ++proc->hidden; } @@ -1263,18 +1049,18 @@ pdf_process_annot(fz_context *ctx, pdf_processor *proc, pdf_document *doc, pdf_p if (flags & (PDF_ANNOT_IS_INVISIBLE | PDF_ANNOT_IS_HIDDEN)) return; - if (proc->event) + if (proc->usage) { - if (!strcmp(proc->event, "Print") && !(flags & PDF_ANNOT_IS_PRINT)) + if (!strcmp(proc->usage, "Print") && !(flags & PDF_ANNOT_IS_PRINT)) return; - if (!strcmp(proc->event, "View") && (flags & PDF_ANNOT_IS_NO_VIEW)) + if (!strcmp(proc->usage, "View") && (flags & PDF_ANNOT_IS_NO_VIEW)) return; } /* TODO: NoZoom and NoRotate */ /* XXX what resources, if any, to use for this check? */ - if (pdf_is_hidden_ocg(ctx, doc->ocg, NULL, proc->event, pdf_dict_get(ctx, annot->obj, PDF_NAME_OC))) + if (pdf_is_hidden_ocg(ctx, doc->ocg, NULL, proc->usage, pdf_dict_get(ctx, annot->obj, PDF_NAME_OC))) return; if (proc->op_q && proc->op_cm && proc->op_Do_form && proc->op_Q && annot->ap) |