summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mupdf/pdf/document.h125
-rw-r--r--include/mupdf/pdf/interpret.h4
-rw-r--r--include/mupdf/pdf/page.h7
-rw-r--r--platform/win32/libmupdf.vcproj8
-rw-r--r--resources/pdf/names.txt3
-rw-r--r--source/pdf/pdf-imp.h9
-rw-r--r--source/pdf/pdf-interpret.c226
-rw-r--r--source/pdf/pdf-layer.c715
-rw-r--r--source/pdf/pdf-op-run.c4
-rw-r--r--source/pdf/pdf-run.c20
-rw-r--r--source/pdf/pdf-xref.c161
11 files changed, 879 insertions, 403 deletions
diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h
index 5b9632ff..4cb4c819 100644
--- a/include/mupdf/pdf/document.h
+++ b/include/mupdf/pdf/document.h
@@ -119,20 +119,125 @@ int pdf_lookup_metadata(fz_context *ctx, pdf_document *doc, const char *key, cha
fz_outline *pdf_load_outline(fz_context *ctx, pdf_document *doc);
-typedef struct pdf_ocg_entry_s pdf_ocg_entry;
+/*
+ pdf_count_layer_configs: Get the number of layer
+ configurations defined in this document.
+
+ doc: The document in question.
+*/
+int pdf_count_layer_configs(fz_context *ctx, pdf_document *doc);
-struct pdf_ocg_entry_s
+typedef struct
{
- int num;
- int state;
-};
+ const char *name;
+ const char *creator;
+} pdf_layer_config;
+
+/*
+ pdf_layer_config_info: Fetch the name (and
+ optionally creator) of the given layer config.
+
+ doc: The document in question.
+
+ config_num: A value in the 0..n-1 range, where n is the
+ value returned from pdf_count_layer_configs.
+
+ info: Pointer to structure to fill in. Pointers within
+ this structure may be set to NULL if no information is
+ available.
+*/
+void pdf_layer_config_info(fz_context *ctx, pdf_document *doc, int config_num, pdf_layer_config *info);
+
+/*
+ pdf_select_layer_config: Set the current configuration.
+ This updates the visibility of the optional content groups
+ within the document.
+
+ doc: The document in question.
+
+ config_num: A value in the 0..n-1 range, where n is the
+ value returned from pdf_count_layer_configs.
+*/
+void pdf_select_layer_config(fz_context *ctx, pdf_document *doc, int config_num);
+
+/*
+ pdf_count_layer_config_ui: Returns the number of entries in the
+ 'UI' for this layer configuration.
+
+ doc: The document in question.
+*/
+int pdf_count_layer_config_ui(fz_context *ctx, pdf_document *doc);
+
+/*
+ pdf_select_layer_ui: Select a checkbox/radiobox
+ within the 'UI' for this layer configuration.
+
+ Selecting a UI entry that is a radiobox may disable
+ other UI entries.
+
+ doc: The document in question.
-struct pdf_ocg_descriptor_s
+ ui: A value in the 0..m-1 range, where m is the value
+ returned by pdf_count_layer_config_ui.
+*/
+void pdf_select_layer_config_ui(fz_context *ctx, pdf_document *doc, int ui);
+
+/*
+ pdf_deselect_layer_ui: Select a checkbox/radiobox
+ within the 'UI' for this layer configuration.
+
+ doc: The document in question.
+
+ ui: A value in the 0..m-1 range, where m is the value
+ returned by pdf_count_layer_config_ui.
+*/
+void pdf_deselect_layer_config_ui(fz_context *ctx, pdf_document *doc, int ui);
+
+/*
+ pdf_toggle_layer_config_ui: Toggle a checkbox/radiobox
+ within the 'UI' for this layer configuration.
+
+ Toggling a UI entry that is a radiobox may disable
+ other UI entries.
+
+ doc: The document in question.
+
+ ui: A value in the 0..m-1 range, where m is the value
+ returned by pdf_count_layer_config_ui.
+*/
+void pdf_toggle_layer_config_ui(fz_context *ctx, pdf_document *doc, int ui);
+
+typedef enum
{
- int len;
- pdf_ocg_entry *ocgs;
- pdf_obj *intent;
-};
+ PDF_LAYER_UI_LABEL = 0,
+ PDF_LAYER_UI_CHECKBOX = 1,
+ PDF_LAYER_UI_RADIOBOX = 2
+} pdf_layer_config_ui_type;
+
+typedef struct
+{
+ const char *text;
+ int depth;
+ pdf_layer_config_ui_type type;
+ int selected;
+ int locked;
+} pdf_layer_config_ui;
+
+/*
+ pdf_layer_config_ui_info: Get the info for a given
+ entry in the layer config ui.
+
+ doc: The document in question.
+
+ ui: A value in the 0..m-1 range, where m is the value
+ returned by pdf_count_layer_config_ui.
+
+ info: Pointer to a structure to fill in with information
+ about the requested ui entry.
+*/
+void pdf_layer_config_ui_info(fz_context *ctx, pdf_document *doc, int ui, pdf_layer_config_ui *info);
+
+int pdf_is_hidden_ocg(fz_context *ctx, pdf_ocg_descriptor *desc, pdf_obj *rdb, const char *usage, pdf_obj *ocg);
/*
pdf_update_page: update a page for the sake of changes caused by a call
diff --git a/include/mupdf/pdf/interpret.h b/include/mupdf/pdf/interpret.h
index 07460221..b7b85fff 100644
--- a/include/mupdf/pdf/interpret.h
+++ b/include/mupdf/pdf/interpret.h
@@ -127,7 +127,7 @@ struct pdf_processor_s
void (*op_END)(fz_context *ctx, pdf_processor *proc);
/* interpreter state that persists across content streams */
- const char *event;
+ const char *usage;
int hidden;
};
@@ -155,7 +155,7 @@ struct pdf_csi_s
};
/* Functions to set up pdf_process structures */
-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_processor *pdf_new_run_processor(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, const char *usage, pdf_gstate *gstate, int nested);
pdf_processor *pdf_new_buffer_processor(fz_context *ctx, fz_buffer *buffer, int ahxencode);
pdf_processor *pdf_new_filter_processor(fz_context *ctx, pdf_processor *chain, pdf_document *doc, pdf_obj *old_res, pdf_obj *new_res);
diff --git a/include/mupdf/pdf/page.h b/include/mupdf/pdf/page.h
index a5a60be8..407fcc09 100644
--- a/include/mupdf/pdf/page.h
+++ b/include/mupdf/pdf/page.h
@@ -65,7 +65,7 @@ fz_rect *pdf_bound_page(fz_context *ctx, pdf_page *page, fz_rect *);
void pdf_run_page(fz_context *ctx, pdf_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie);
/*
- pdf_run_page: Interpret a loaded page and render it on a device.
+ pdf_run_page_with_usage: Interpret a loaded page and render it on a device.
page: A page loaded by pdf_load_page.
@@ -74,10 +74,13 @@ void pdf_run_page(fz_context *ctx, pdf_page *page, fz_device *dev, const fz_matr
ctm: A transformation matrix applied to the objects on the page,
e.g. to scale or rotate the page contents as desired.
+ usage: The 'usage' for displaying the file (typically
+ 'View', 'Print' or 'Export'). NULL means 'View'.
+
cookie: A pointer to an optional fz_cookie structure that can be used
to track progress, collect errors etc.
*/
-void pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, char *event, fz_cookie *cookie);
+void pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, const char *usage, fz_cookie *cookie);
/*
pdf_run_page_contents: Interpret a loaded page and render it on a device.
diff --git a/platform/win32/libmupdf.vcproj b/platform/win32/libmupdf.vcproj
index f7134220..69193a9a 100644
--- a/platform/win32/libmupdf.vcproj
+++ b/platform/win32/libmupdf.vcproj
@@ -2031,6 +2031,10 @@
>
</File>
<File
+ RelativePath="..\..\source\pdf\pdf-imp.h"
+ >
+ </File>
+ <File
RelativePath="..\..\source\pdf\pdf-interpret-imp.h"
>
</File>
@@ -2047,6 +2051,10 @@
>
</File>
<File
+ RelativePath="..\..\source\pdf\pdf-layer.c"
+ >
+ </File>
+ <File
RelativePath="..\..\source\pdf\pdf-lex.c"
>
</File>
diff --git a/resources/pdf/names.txt b/resources/pdf/names.txt
index 57228c15..30f4f60d 100644
--- a/resources/pdf/names.txt
+++ b/resources/pdf/names.txt
@@ -214,6 +214,7 @@ Limits
Line
Linearized
Link
+Locked
Luminosity
M
MK
@@ -249,6 +250,7 @@ Of
Off
OpenType
Opt
+Order
Ordering
Outlines
P
@@ -275,6 +277,7 @@ Push
Q
QuadPoints
R
+RBGroups
RGB
RI
RL
diff --git a/source/pdf/pdf-imp.h b/source/pdf/pdf-imp.h
new file mode 100644
index 00000000..37605c51
--- /dev/null
+++ b/source/pdf/pdf-imp.h
@@ -0,0 +1,9 @@
+#ifndef MUPDF_PDF_IMP_H
+#define MUPDF_PDF_IMP_H
+
+#include "mupdf/pdf.h"
+
+void pdf_read_ocg(fz_context *ctx, pdf_document *doc);
+void pdf_drop_ocg(fz_context *ctx, pdf_document *doc);
+
+#endif
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)
diff --git a/source/pdf/pdf-layer.c b/source/pdf/pdf-layer.c
new file mode 100644
index 00000000..70dfcd50
--- /dev/null
+++ b/source/pdf/pdf-layer.c
@@ -0,0 +1,715 @@
+#include "mupdf/fitz.h"
+#include "pdf-imp.h"
+
+/*
+ Notes on OCGs etc.
+
+ PDF Documents may contain Optional Content Groups. Which of
+ these is shown at any given time is dependent on which
+ Optional Content Configuration Dictionary is in force at the
+ time.
+
+ A pdf_document, once loaded, contains some state saying which
+ OCGs are enabled/disabled, and which 'Intent' (or 'Intents')
+ a file is being used for. This information is held outside of
+ the actual PDF file.
+
+ An Intent (just 'View' or 'Design' or 'All', according to
+ PDF 2.0, but theoretically more) says which OCGs to consider
+ or ignore in calculating the visibility of content. The
+ Intent (or Intents, for there can be an array) is set by the
+ current OCCD.
+
+ When first loaded, we turn all OCGs on, then load the default
+ OCCD. This may turn some OCGs off, and sets the document Intent.
+
+ Callers can ask how many OCCDs there are, read the names/creators
+ for each, and then select any one of them. That updates which
+ OCGs are selected, and resets the Intent.
+
+ Once an OCCD has been selected, a caller can enumerate the
+ 'displayable configuration'. This is a list of labels/radio
+ buttons/check buttons that can be used to enable/disable
+ given OCGs. The caller can then enable/disable OCGs by
+ asking to select (or toggle) given entries in that list.
+
+ Thus the handling of radio button groups, and 'locked'
+ elements is kept within the core of MuPDF.
+
+ Finally, the caller can set the 'usage' for a document. This
+ can be 'View', 'Print', or 'Export'.
+*/
+
+typedef struct
+{
+ pdf_obj *obj;
+ int state;
+} pdf_ocg_entry;
+
+typedef struct
+{
+ int ocg;
+ const char *name;
+ int depth;
+ unsigned int button_flags : 2;
+ unsigned int locked : 1;
+} pdf_ocg_ui;
+
+struct pdf_ocg_descriptor_s
+{
+ int current;
+ int num_configs;
+
+ int len;
+ pdf_ocg_entry *ocgs;
+
+ pdf_obj *intent;
+ char *usage;
+
+ int num_ui_entries;
+ pdf_ocg_ui *ui;
+};
+
+int
+pdf_count_layer_configs(fz_context *ctx, pdf_document *doc)
+{
+ /* If no OCProperties, then no OCGs */
+ if (!doc || !doc->ocg)
+ return 0;
+ return doc->ocg->num_configs;
+}
+
+
+static int
+count_entries(fz_context *ctx, pdf_obj *obj)
+{
+ int len = pdf_array_len(ctx, obj);
+ int i;
+ int count = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ pdf_obj *o = pdf_array_get(ctx, obj, i);
+ count += (pdf_is_array(ctx, o) ? count_entries(ctx, o) : 1);
+ }
+ return count;
+}
+
+static pdf_ocg_ui *
+populate_ui(fz_context *ctx, pdf_ocg_descriptor *desc, pdf_ocg_ui *ui, pdf_obj *order, int depth, pdf_obj *rbgroups, pdf_obj *locked)
+{
+ int len = pdf_array_len(ctx, order);
+ int i, j;
+
+ for (i = 0; i < len; i++)
+ {
+ pdf_obj *o = pdf_array_get(ctx, order, i);
+ if (pdf_is_array(ctx, o))
+ {
+ ui = populate_ui(ctx, desc, ui, o, depth+1, rbgroups, locked);
+ continue;
+ }
+ ui->depth = depth;
+ if (pdf_is_string(ctx, o))
+ {
+ ui->ocg = -1;
+ ui->name = pdf_to_str_buf(ctx, o);
+ ui->button_flags = PDF_LAYER_UI_LABEL;
+ ui->locked = 1;
+ ui++;
+ continue;
+ }
+
+ for (j = 0; j < desc->len; j++)
+ {
+ if (!pdf_objcmp_resolve(ctx, o, desc->ocgs[j].obj))
+ break;
+ }
+ if (j == desc->len)
+ continue; /* OCG not found in main list! Just ignore it */
+ ui->ocg = j;
+ ui->name = pdf_to_str_buf(ctx, pdf_dict_get(ctx, o, PDF_NAME_Name));
+ ui->button_flags = pdf_array_contains(ctx, o, rbgroups) ? PDF_LAYER_UI_RADIOBOX : PDF_LAYER_UI_CHECKBOX;
+ ui->locked = pdf_array_contains(ctx, o, locked);
+ ui++;
+ }
+ return ui;
+}
+
+static void
+drop_ui(fz_context *ctx, pdf_ocg_descriptor *desc)
+{
+ if (!desc)
+ return;
+
+ fz_free(ctx, desc->ui);
+ desc->ui = NULL;
+}
+
+static void
+load_ui(fz_context *ctx, pdf_ocg_descriptor *desc, pdf_obj *ocprops, pdf_obj *occg)
+{
+ pdf_obj *order;
+ pdf_obj *rbgroups;
+ pdf_obj *locked;
+ int count;
+
+ /* Count the number of entries */
+ order = pdf_dict_get(ctx, occg, PDF_NAME_Order);
+ count = count_entries(ctx, order);
+ rbgroups = pdf_dict_get(ctx, occg, PDF_NAME_RBGroups);
+ locked = pdf_dict_get(ctx, occg, PDF_NAME_Locked);
+
+ desc->num_ui_entries = count;
+ desc->ui = Memento_label(fz_calloc(ctx, count, sizeof(pdf_ocg_ui)), "pdf_ocg_ui");
+ fz_try(ctx)
+ {
+ (void)populate_ui(ctx, desc, desc->ui, order, 0, rbgroups, locked);
+ }
+ fz_catch(ctx)
+ {
+ drop_ui(ctx, desc);
+ fz_rethrow(ctx);
+ }
+}
+
+void
+pdf_select_layer_config(fz_context *ctx, pdf_document *doc, int config)
+{
+ int i, j, len, len2;
+ pdf_ocg_descriptor *desc = doc->ocg;
+ pdf_obj *obj, *cobj;
+ pdf_obj *name;
+
+ obj = pdf_dict_get(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root), PDF_NAME_OCProperties);
+ if (!obj)
+ {
+ if (config == 0)
+ return;
+ else
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Unknown Layer config (None known!)");
+ }
+
+ cobj = pdf_array_get(ctx, pdf_dict_get(ctx, obj, PDF_NAME_Configs), config);
+ if (!cobj)
+ {
+ if (config != 0)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal Layer config");
+ cobj = pdf_dict_get(ctx, obj, PDF_NAME_D);
+ if (!cobj)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "No default Layer config");
+ }
+
+ pdf_drop_obj(ctx, desc->intent);
+ desc->intent = pdf_keep_obj(ctx, pdf_dict_get(ctx, cobj, PDF_NAME_Intent));
+
+ len = desc->len;
+ name = pdf_dict_get(ctx, cobj, PDF_NAME_BaseState);
+ if (pdf_name_eq(ctx, name, PDF_NAME_Unchanged))
+ {
+ /* Do nothing */
+ }
+ else if (pdf_name_eq(ctx, name, PDF_NAME_OFF))
+ {
+ for (i = 0; i < len; i++)
+ {
+ desc->ocgs[i].state = 0;
+ }
+ }
+ else /* Default to ON */
+ {
+ for (i = 0; i < len; i++)
+ {
+ desc->ocgs[i].state = 1;
+ }
+ }
+
+ obj = pdf_dict_get(ctx, cobj, PDF_NAME_ON);
+ len2 = pdf_array_len(ctx, obj);
+ for (i = 0; i < len2; i++)
+ {
+ pdf_obj *o = pdf_array_get(ctx, obj, i);
+ for (j=0; j < len; j++)
+ {
+ if (!pdf_objcmp_resolve(ctx, desc->ocgs[j].obj, o))
+ {
+ desc->ocgs[j].state = 1;
+ break;
+ }
+ }
+ }
+
+ obj = pdf_dict_get(ctx, cobj, PDF_NAME_OFF);
+ len2 = pdf_array_len(ctx, obj);
+ for (i = 0; i < len2; i++)
+ {
+ pdf_obj *o = pdf_array_get(ctx, obj, i);
+ for (j=0; j < len; j++)
+ {
+ if (!pdf_objcmp_resolve(ctx, desc->ocgs[j].obj, o))
+ {
+ desc->ocgs[j].state = 0;
+ break;
+ }
+ }
+ }
+
+ desc->current = config;
+
+ drop_ui(ctx, desc);
+ load_ui(ctx, desc, obj, cobj);
+}
+
+void
+pdf_layer_config_info(fz_context *ctx, pdf_document *doc, int config_num, pdf_layer_config *info)
+{
+ pdf_obj *ocprops;
+ pdf_obj *obj;
+
+ if (!info)
+ return;
+
+ info->name = NULL;
+ info->creator = NULL;
+
+ if (doc == NULL || doc->ocg == NULL)
+ return;
+ if (config_num < 0 || config_num >= doc->ocg->num_configs)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Invalid layer config number");
+
+ ocprops = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/OCProperties");
+ if (!ocprops)
+ return;
+
+ obj = pdf_dict_get(ctx, ocprops, PDF_NAME_Configs);
+ if (pdf_is_array(ctx, obj))
+ obj = pdf_array_get(ctx, obj, config_num);
+ else if (config_num == 0)
+ obj = pdf_dict_get(ctx, ocprops, PDF_NAME_D);
+ else
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Invalid layer config number");
+
+ info->creator = pdf_to_str_buf(ctx, pdf_dict_get(ctx, obj, PDF_NAME_Creator));
+ info->name = pdf_to_str_buf(ctx, pdf_dict_get(ctx, obj, PDF_NAME_Name));
+}
+
+void
+pdf_drop_ocg(fz_context *ctx, pdf_document *doc)
+{
+ pdf_ocg_descriptor *desc;
+ int i;
+
+ if (!doc)
+ return;
+ desc = doc->ocg;
+ if (!desc)
+ return;
+
+ pdf_drop_obj(ctx, desc->intent);
+ for (i = 0; i < desc->len; i++)
+ pdf_drop_obj(ctx, desc->ocgs[i].obj);
+ fz_free(ctx, desc->ocgs);
+ fz_free(ctx, desc);
+}
+
+static void
+clear_radio_group(fz_context *ctx, pdf_document *doc, pdf_obj *ocg)
+{
+ pdf_obj *rbgroups = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/OCProperties/RBGroups");
+ int len, i;
+
+ len = pdf_array_len(ctx, rbgroups);
+ for (i = 0; i < len; i++)
+ {
+ pdf_obj *group = pdf_array_get(ctx, rbgroups, i);
+
+ if (pdf_array_contains(ctx, ocg, group))
+ {
+ int len2 = pdf_array_len(ctx, group);
+ int j;
+
+ for (j = 0; j < len2; j++)
+ {
+ pdf_obj *g = pdf_array_get(ctx, group, j);
+ int k;
+ for (k = 0; k < doc->ocg->len; k++)
+ {
+ pdf_ocg_entry *s = &doc->ocg->ocgs[k];
+
+ if (!pdf_objcmp_resolve(ctx, s->obj, g))
+ s->state = 0;
+ }
+ }
+ }
+ }
+}
+
+int pdf_count_layer_config_ui(fz_context *ctx, pdf_document *doc)
+{
+ if (doc == NULL || doc->ocg == NULL)
+ return 0;
+
+ return doc->ocg->num_ui_entries;
+}
+
+void pdf_select_layer_config_ui(fz_context *ctx, pdf_document *doc, int ui)
+{
+ pdf_ocg_ui *entry;
+
+ if (doc == NULL || doc->ocg == NULL)
+ return;
+
+ if (ui < 0 || ui >= doc->ocg->num_ui_entries)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Out of range UI entry selected");
+
+ entry = &doc->ocg->ui[ui];
+ if (entry->button_flags != PDF_LAYER_UI_RADIOBOX &&
+ entry->button_flags != PDF_LAYER_UI_CHECKBOX)
+ return;
+ if (entry->locked)
+ return;
+
+ if (entry->button_flags == PDF_LAYER_UI_RADIOBOX)
+ clear_radio_group(ctx, doc, doc->ocg->ocgs[entry->ocg].obj);
+
+ doc->ocg->ocgs[entry->ocg].state = 1;
+}
+
+void pdf_toggle_layer_config_ui(fz_context *ctx, pdf_document *doc, int ui)
+{
+ pdf_ocg_ui *entry;
+ int selected;
+
+ if (doc == NULL || doc->ocg == NULL)
+ return;
+
+ if (ui < 0 || ui >= doc->ocg->num_ui_entries)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Out of range UI entry toggled");
+
+ entry = &doc->ocg->ui[ui];
+ if (entry->button_flags != PDF_LAYER_UI_RADIOBOX &&
+ entry->button_flags != PDF_LAYER_UI_CHECKBOX)
+ return;
+ if (entry->locked)
+ return;
+
+ selected = doc->ocg->ocgs[entry->ocg].state;
+
+ if (entry->button_flags == PDF_LAYER_UI_RADIOBOX)
+ clear_radio_group(ctx, doc, doc->ocg->ocgs[entry->ocg].obj);
+
+ doc->ocg->ocgs[entry->ocg].state = !selected;
+}
+
+void pdf_deselect_layer_ui(fz_context *ctx, pdf_document *doc, int ui)
+{
+ pdf_ocg_ui *entry;
+
+ if (doc == NULL || doc->ocg == NULL)
+ return;
+
+ if (ui < 0 || ui >= doc->ocg->num_ui_entries)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Out of range UI entry deselected");
+
+ entry = &doc->ocg->ui[ui];
+ if (entry->button_flags != PDF_LAYER_UI_RADIOBOX &&
+ entry->button_flags != PDF_LAYER_UI_CHECKBOX)
+ return;
+ if (entry->locked)
+ return;
+
+ doc->ocg->ocgs[entry->ocg].state = 0;
+}
+
+void
+pdf_layer_config_ui_info(fz_context *ctx, pdf_document *doc, int ui, pdf_layer_config_ui *info)
+{
+ pdf_ocg_ui *entry;
+
+ if (!info)
+ return;
+
+ info->depth = 0;
+ info->locked = 0;
+ info->selected = 0;
+ info->text = NULL;
+ info->type = 0;
+
+ if (doc == NULL || doc->ocg == NULL)
+ return;
+
+ if (ui < 0 || ui >= doc->ocg->num_ui_entries)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Out of range UI entry selected");
+
+ entry = &doc->ocg->ui[ui];
+ info->type = entry->button_flags;
+ info->depth = entry->depth;
+ info->selected = doc->ocg->ocgs[entry->ocg].state;
+ info->locked = entry->locked;
+ info->text = entry->name;
+}
+
+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(fz_context *ctx, pdf_ocg_descriptor *desc, pdf_obj *rdb, const char *usage, 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 usage, everything is visible */
+ if (!usage)
+ 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, usage, 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 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 (!pdf_objcmp_resolve(ctx, desc->ocgs[i].obj, ocg))
+ {
+ default_value = !desc->ocgs[i].state;
+ 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, usage);
+ 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, usage, 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, usage, 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;
+}
+
+void
+pdf_read_ocg(fz_context *ctx, pdf_document *doc)
+{
+ pdf_obj *obj, *ocg, *configs;
+ int len, i, num_configs;
+ pdf_ocg_descriptor *desc;
+
+ fz_var(desc);
+
+ obj = pdf_dict_get(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root), PDF_NAME_OCProperties);
+ if (!obj)
+ return;
+
+ configs = pdf_dict_get(ctx, obj, PDF_NAME_Configs);
+ if (configs == NULL)
+ num_configs = 1;
+ else if (!pdf_is_array(ctx, configs))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Invalid Configs value");
+ else
+ num_configs = pdf_array_len(ctx, configs);
+
+ ocg = pdf_dict_get(ctx, obj, PDF_NAME_OCGs);
+ if (!ocg || !pdf_is_array(ctx, ocg))
+ /* Not ever supposed to happen, but live with it. */
+ return;
+ len = pdf_array_len(ctx, ocg);
+ fz_try(ctx)
+ {
+ desc = fz_malloc_struct(ctx, pdf_ocg_descriptor);
+ desc->num_configs = num_configs;
+ desc->len = len;
+ desc->ocgs = fz_calloc(ctx, len, sizeof(*desc->ocgs));
+ desc->intent = NULL;
+ for (i=0; i < len; i++)
+ {
+ pdf_obj *o = pdf_array_get(ctx, ocg, i);
+ desc->ocgs[i].obj = pdf_keep_obj(ctx, o);
+ desc->ocgs[i].state = 1;
+ }
+ doc->ocg = desc;
+ }
+ fz_catch(ctx)
+ {
+ if (desc)
+ fz_free(ctx, desc->ocgs);
+ fz_free(ctx, desc);
+ fz_rethrow(ctx);
+ }
+
+ pdf_select_layer_config(ctx, doc, 0);
+}
diff --git a/source/pdf/pdf-op-run.c b/source/pdf/pdf-op-run.c
index 89bbf008..00d1957d 100644
--- a/source/pdf/pdf-op-run.c
+++ b/source/pdf/pdf-op-run.c
@@ -2018,11 +2018,11 @@ pdf_drop_run_processor(fz_context *ctx, pdf_processor *proc)
}
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_new_run_processor(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, const char *usage, pdf_gstate *gstate, int nested)
{
pdf_run_processor *proc = pdf_new_processor(ctx, sizeof *proc);
{
- proc->super.event = event;
+ proc->super.usage = usage;
proc->super.drop_processor = pdf_drop_run_processor;
diff --git a/source/pdf/pdf-run.c b/source/pdf/pdf-run.c
index f806b120..ba8b30b7 100644
--- a/source/pdf/pdf-run.c
+++ b/source/pdf/pdf-run.c
@@ -1,7 +1,7 @@
#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)
+pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *annot, fz_device *dev, const fz_matrix *ctm, const char *usage, fz_cookie *cookie)
{
fz_matrix local_ctm, page_ctm;
fz_rect mediabox;
@@ -10,7 +10,7 @@ pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf
pdf_page_transform(ctx, page, &mediabox, &page_ctm);
fz_concat(&local_ctm, &page_ctm, ctm);
- proc = pdf_new_run_processor(ctx, dev, &local_ctm, event, NULL, 0);
+ proc = pdf_new_run_processor(ctx, dev, &local_ctm, usage, NULL, 0);
fz_try(ctx)
pdf_process_annot(ctx, proc, doc, page, annot, cookie);
fz_always(ctx)
@@ -19,7 +19,8 @@ pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf
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)
+static void
+pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, const char *usage, fz_cookie *cookie)
{
fz_matrix local_ctm, page_ctm;
pdf_obj *resources;
@@ -36,7 +37,7 @@ static void pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc,
if (page->transparency)
fz_begin_group(ctx, dev, fz_transform_rect(&mediabox, &local_ctm), 1, 0, 0, 1);
- proc = pdf_new_run_processor(ctx, dev, &local_ctm, event, NULL, 0);
+ proc = pdf_new_run_processor(ctx, dev, &local_ctm, usage, NULL, 0);
fz_try(ctx)
pdf_process_contents(ctx, proc, doc, resources, contents, cookie);
fz_always(ctx)
@@ -100,7 +101,8 @@ void pdf_run_annot(fz_context *ctx, pdf_annot *annot, fz_device *dev, const fz_m
fz_throw(ctx, FZ_ERROR_TRYLATER, "incomplete rendering");
}
-static void pdf_run_page_annots_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, char *event, fz_cookie *cookie)
+static void
+pdf_run_page_annots_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, const char *usage, fz_cookie *cookie)
{
pdf_annot *annot;
@@ -122,12 +124,12 @@ static void pdf_run_page_annots_with_usage(fz_context *ctx, pdf_document *doc, p
cookie->progress++;
}
- pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, event, cookie);
+ pdf_run_annot_with_usage(ctx, doc, page, annot, dev, ctm, usage, cookie);
}
}
void
-pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, char *event, fz_cookie *cookie)
+pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, const char *usage, fz_cookie *cookie)
{
int nocache = !!(dev->hints & FZ_NO_CACHE);
@@ -135,8 +137,8 @@ pdf_run_page_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_d
pdf_mark_xref(ctx, doc);
fz_try(ctx)
{
- pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, event, cookie);
- pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, event, cookie);
+ pdf_run_page_contents_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
+ pdf_run_page_annots_with_usage(ctx, doc, page, dev, ctm, usage, cookie);
}
fz_always(ctx)
{
diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c
index 41dd9984..1af2d391 100644
--- a/source/pdf/pdf-xref.c
+++ b/source/pdf/pdf-xref.c
@@ -1,4 +1,4 @@
-#include "mupdf/pdf.h"
+#include "pdf-imp.h"
#include "mupdf/fitz/document.h"
#undef DEBUG_PROGESSIVE_ADVANCE
@@ -241,7 +241,7 @@ pdf_xref_entry *pdf_get_populating_xref_entry(fz_context *ctx, pdf_document *doc
* xref. */
pdf_xref_entry *pdf_get_xref_entry(fz_context *ctx, pdf_document *doc, int i)
{
- pdf_xref *xref;
+ pdf_xref *xref = NULL;
pdf_xref_subsec *sub;
int j;
@@ -1277,161 +1277,6 @@ pdf_load_linear(fz_context *ctx, pdf_document *doc)
}
}
-void
-pdf_ocg_set_config(fz_context *ctx, pdf_document *doc, int config)
-{
- int i, j, len, len2;
- pdf_ocg_descriptor *desc = doc->ocg;
- pdf_obj *obj, *cobj;
- pdf_obj *name;
-
- obj = pdf_dict_get(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root), PDF_NAME_OCProperties);
- if (!obj)
- {
- if (config == 0)
- return;
- else
- fz_throw(ctx, FZ_ERROR_GENERIC, "Unknown OCG config (None known!)");
- }
- if (config == 0)
- {
- cobj = pdf_dict_get(ctx, obj, PDF_NAME_D);
- if (!cobj)
- fz_throw(ctx, FZ_ERROR_GENERIC, "No default OCG config");
- }
- else
- {
- cobj = pdf_array_get(ctx, pdf_dict_get(ctx, obj, PDF_NAME_Configs), config);
- if (!cobj)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal OCG config");
- }
-
- pdf_drop_obj(ctx, desc->intent);
- desc->intent = pdf_dict_get(ctx, cobj, PDF_NAME_Intent);
- if (desc->intent)
- pdf_keep_obj(ctx, desc->intent);
-
- len = desc->len;
- name = pdf_dict_get(ctx, cobj, PDF_NAME_BaseState);
- if (pdf_name_eq(ctx, name, PDF_NAME_Unchanged))
- {
- /* Do nothing */
- }
- else if (pdf_name_eq(ctx, name, PDF_NAME_OFF))
- {
- for (i = 0; i < len; i++)
- {
- desc->ocgs[i].state = 0;
- }
- }
- else /* Default to ON */
- {
- for (i = 0; i < len; i++)
- {
- desc->ocgs[i].state = 1;
- }
- }
-
- obj = pdf_dict_get(ctx, cobj, PDF_NAME_ON);
- len2 = pdf_array_len(ctx, obj);
- for (i = 0; i < len2; i++)
- {
- pdf_obj *o = pdf_array_get(ctx, obj, i);
- int n = pdf_to_num(ctx, o);
- for (j=0; j < len; j++)
- {
- if (desc->ocgs[j].num == n)
- {
- desc->ocgs[j].state = 1;
- break;
- }
- }
- }
-
- obj = pdf_dict_get(ctx, cobj, PDF_NAME_OFF);
- len2 = pdf_array_len(ctx, obj);
- for (i = 0; i < len2; i++)
- {
- pdf_obj *o = pdf_array_get(ctx, obj, i);
- int n = pdf_to_num(ctx, o);
- for (j=0; j < len; j++)
- {
- if (desc->ocgs[j].num == n)
- {
- desc->ocgs[j].state = 0;
- break;
- }
- }
- }
-
- /* FIXME: Should make 'num configs' available in the descriptor. */
- /* FIXME: Should copy out 'Intent' here into the descriptor, and remove
- * csi->intent in favour of that. */
- /* FIXME: Should copy 'AS' into the descriptor, and visibility
- * decisions should respect it. */
- /* FIXME: Make 'Order' available via the descriptor (when we have an
- * app that needs it) */
- /* FIXME: Make 'ListMode' available via the descriptor (when we have
- * an app that needs it) */
- /* FIXME: Make 'RBGroups' available via the descriptor (when we have
- * an app that needs it) */
- /* FIXME: Make 'Locked' available via the descriptor (when we have
- * an app that needs it) */
-}
-
-static void
-pdf_read_ocg(fz_context *ctx, pdf_document *doc)
-{
- pdf_obj *obj, *ocg;
- int len, i;
- pdf_ocg_descriptor *desc;
-
- fz_var(desc);
-
- obj = pdf_dict_get(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root), PDF_NAME_OCProperties);
- if (!obj)
- return;
- ocg = pdf_dict_get(ctx, obj, PDF_NAME_OCGs);
- if (!ocg || !pdf_is_array(ctx, ocg))
- /* Not ever supposed to happen, but live with it. */
- return;
- len = pdf_array_len(ctx, ocg);
- fz_try(ctx)
- {
- desc = fz_malloc_struct(ctx, pdf_ocg_descriptor);
- desc->len = len;
- desc->ocgs = fz_calloc(ctx, len, sizeof(*desc->ocgs));
- desc->intent = NULL;
- for (i=0; i < len; i++)
- {
- pdf_obj *o = pdf_array_get(ctx, ocg, i);
- desc->ocgs[i].num = pdf_to_num(ctx, o);
- desc->ocgs[i].state = 1;
- }
- doc->ocg = desc;
- }
- fz_catch(ctx)
- {
- if (desc)
- fz_free(ctx, desc->ocgs);
- fz_free(ctx, desc);
- fz_rethrow(ctx);
- }
-
- pdf_ocg_set_config(ctx, doc, 0);
-}
-
-static void
-pdf_drop_ocg(fz_context *ctx, pdf_ocg_descriptor *desc)
-{
- if (!desc)
- return;
-
- pdf_drop_obj(ctx, desc->intent);
- fz_free(ctx, desc->ocgs);
- fz_free(ctx, desc);
-}
-
/*
* Initialize and load xref tables.
* If password is not null, try to decrypt.
@@ -1631,7 +1476,7 @@ pdf_drop_document_imp(fz_context *ctx, pdf_document *doc)
}
fz_free(ctx, doc->type3_fonts);
- pdf_drop_ocg(ctx, doc->ocg);
+ pdf_drop_ocg(ctx, doc);
pdf_empty_store(ctx, doc);