From 54d7093e80e419b8aa18ffe33a4a3ff4fda25140 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Tue, 15 Nov 2011 15:23:25 +0000 Subject: Fix clipping error. When reverting the clip path handling, I made a mistake. We need to set up the clip before starting any local group to ensure correct nesting. --- pdf/pdf_interpret.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'pdf') diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index 4f26f04a..9b2a788b 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -263,15 +263,15 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd) else bbox = fz_bound_path(path, NULL, gstate->ctm); - if (dofill || dostroke) - pdf_begin_group(csi, bbox); - if (csi->clip) { gstate->clip_depth++; fz_clip_path(csi->dev, path, NULL, csi->clip_even_odd, gstate->ctm); } + if (dofill || dostroke) + pdf_begin_group(csi, bbox); + if (dofill) { switch (gstate->fill.kind) -- cgit v1.2.3 From db360fac468dc89b45c89bd30374b61b27c221b1 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Tue, 15 Nov 2011 18:37:21 +0000 Subject: AES encryption tweak; strings can be 0 bytes long Do not emit a warning if AES strings are 0 bytes long. --- pdf/pdf_crypt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'pdf') diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c index 4dd4c4e1..81ee5649 100644 --- a/pdf/pdf_crypt.c +++ b/pdf/pdf_crypt.c @@ -729,7 +729,11 @@ pdf_crypt_obj_imp(pdf_crypt *crypt, fz_obj *obj, unsigned char *key, int keylen) if (crypt->strf.method == PDF_CRYPT_AESV2 || crypt->strf.method == PDF_CRYPT_AESV3) { - if (n & 15 || n < 32) + if (n == 0) + { + /* Empty strings are permissible */ + } + else if (n & 15 || n < 32) fz_warn("invalid string length for aes encryption"); else { -- cgit v1.2.3 From 8f8794063127610db433c5dd0f6e7f5241308c6f Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Tue, 15 Nov 2011 19:22:30 +0000 Subject: Bug 692478: Honour decode arrays for jpx images Add simple code to read decode array and apply it to a jpx image after loading. Solves bug. --- pdf/pdf_image.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'pdf') diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index e1901100..50292092 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -329,6 +329,18 @@ pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict) } } + obj = fz_dict_getsa(dict, "Decode", "D"); + if (obj) + { + float decode[FZ_MAX_COLORS * 2]; + int i; + + for (i = 0; i < img->n * 2; i++) + decode[i] = fz_to_real(fz_array_get(obj, i)); + + fz_decode_tile(img, decode); + } + *imgp = img; return fz_okay; } -- cgit v1.2.3 From 84037901d3838b85f7c4d61b191376ce2e32b909 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Tue, 15 Nov 2011 20:20:05 +0000 Subject: Bug 692424: make repair cope better with missing endobj Previously when parsing an object with a missing endobj, the code would consume the header of the following object. Here we amend the code to give up searching for an endobj if it finds an integer (presumed to be the start of the next object). We backtrack over that integer and carry on. --- pdf/pdf_repair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'pdf') diff --git a/pdf/pdf_repair.c b/pdf/pdf_repair.c index 067fe2cf..08adcb99 100644 --- a/pdf/pdf_repair.c +++ b/pdf/pdf_repair.c @@ -68,14 +68,20 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, while ( tok != PDF_TOK_STREAM && tok != PDF_TOK_ENDOBJ && tok != PDF_TOK_ERROR && - tok != PDF_TOK_EOF ) + tok != PDF_TOK_EOF && + tok != PDF_TOK_INT ) { error = pdf_lex(&tok, file, buf, cap, &len); if (error) return fz_rethrow(error, "cannot scan for endobj or stream token"); } - if (tok == PDF_TOK_STREAM) + if (tok == PDF_TOK_INT) + { + while (len-- > 0) + fz_unread_byte(file); + } + else if (tok == PDF_TOK_STREAM) { int c = fz_read_byte(file); if (c == '\r') { -- cgit v1.2.3 From 0ab03af67d5e35ab305e5915e38e71e2c7f6306a Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 24 Nov 2011 16:10:40 +0000 Subject: Bug 692506: Improve repairing by accepting broken dictionaries. Adopt Zenikos patch from bug 692506; if a dict fails to parse, then create an empty one and continue. The repaired document will be incomplete, but we may well get something useful out of it. --- pdf/pdf_repair.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'pdf') diff --git a/pdf/pdf_repair.c b/pdf/pdf_repair.c index 08adcb99..dc376dc3 100644 --- a/pdf/pdf_repair.c +++ b/pdf/pdf_repair.c @@ -36,7 +36,10 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, /* Send NULL xref so we don't try to resolve references */ error = pdf_parse_dict(&dict, NULL, file, buf, cap); if (error) - return fz_rethrow(error, "cannot parse object"); + { + fz_catch(error, "cannot parse object - repair will be incomplete"); + dict = fz_new_dict(2); + } obj = fz_dict_gets(dict, "Type"); if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "XRef")) -- cgit v1.2.3 From 7aeb37fc5be2388ad71d9eab04b539c2c49f024e Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 24 Nov 2011 20:27:47 +0000 Subject: Fix *STUPID* error in recent clipping changes. Once we've applied the clipping path, don't clip again on every subsequent path. --- pdf/pdf_interpret.c | 1 + 1 file changed, 1 insertion(+) (limited to 'pdf') diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index 9b2a788b..752d9426 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -267,6 +267,7 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd) { gstate->clip_depth++; fz_clip_path(csi->dev, path, NULL, csi->clip_even_odd, gstate->ctm); + csi->clip = 0; } if (dofill || dostroke) -- cgit v1.2.3 From 6e14149d3e915f559f99276a525862e28d6f0478 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 24 Nov 2011 19:28:25 +0000 Subject: First cut at support for OCGs in mupdf (bug 692314) When opening a file, create a pdf_ocg_descriptor that lists the OCGs in a file. Add a new function to allow us to set the configuration in use (currently just the default one). This sets the states of the OCGs as appropriate. When decoding the file respect the states of the OCGs. This results in Invite.pdf rendering correctly. There is more to be done in this area (with automatic setting of OCGs by language/zoom level etc), but this is a good start. --- pdf/mupdf.h | 19 +++- pdf/pdf_interpret.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++----- pdf/pdf_xref.c | 159 +++++++++++++++++++++++++++++++ 3 files changed, 421 insertions(+), 27 deletions(-) (limited to 'pdf') diff --git a/pdf/mupdf.h b/pdf/mupdf.h index 22e087f9..e03f6efc 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -45,6 +45,8 @@ char *pdf_from_ucs2(unsigned short *str); typedef struct pdf_xref_entry_s pdf_xref_entry; typedef struct pdf_crypt_s pdf_crypt; +typedef struct pdf_ocg_descriptor_s pdf_ocg_descriptor; +typedef struct pdf_ocg_entry_s pdf_ocg_entry; struct pdf_xref_entry_s { @@ -55,6 +57,20 @@ struct pdf_xref_entry_s int type; /* 0=unset (f)ree i(n)use (o)bjstm */ }; +struct pdf_ocg_entry_s +{ + int num; + int gen; + int state; +}; + +struct pdf_ocg_descriptor_s +{ + int len; + pdf_ocg_entry *ocgs; + fz_obj *intent; +}; + struct pdf_xref_s { fz_stream *file; @@ -63,6 +79,7 @@ struct pdf_xref_s int file_size; pdf_crypt *crypt; fz_obj *trailer; + pdf_ocg_descriptor *ocg; int len; pdf_xref_entry *table; @@ -474,7 +491,7 @@ void pdf_free_page(pdf_page *page); * Content stream parsing */ -fz_error pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *target); +fz_error pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *event); fz_error pdf_run_page(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm); fz_error pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm); diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index 752d9426..55e66e61 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -67,7 +67,7 @@ struct pdf_csi_s pdf_xref *xref; /* usage mode for optional content groups */ - char *target; /* "View", "Print", "Export" */ + char *event; /* "View", "Print", "Export" */ /* interpreter stack */ fz_obj *obj; @@ -79,6 +79,7 @@ struct pdf_csi_s int xbalance; int in_text; + int in_hidden_ocg; /* path object state */ fz_path *path; @@ -102,24 +103,194 @@ static fz_error pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents); static fz_error pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform); static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what); +static int +ocg_intents_include(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 == NULL) + return (strcmp(name, "View") == 0); + + if (fz_is_name(desc->intent)) + { + char *intent = fz_to_name(desc->intent); + if (strcmp(intent, "All") == 0) + return 1; + return (strcmp(intent, name) == 0); + } + if (!fz_is_array(desc->intent)) + return 0; + + len = fz_array_len(desc->intent); + for (i=0; i < len; i++) + { + char *intent = fz_to_name(fz_array_get(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_obj *xobj, char *target) +pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) { - char target_state[16]; - fz_obj *obj; + char event_state[16]; + fz_obj *obj, *obj2; + char *type; + pdf_ocg_descriptor *desc = csi->xref->ocg; + + /* If no ocg descriptor, everything is visible */ + if (desc == NULL) + return 0; + + /* If we've been handed a name, look it up in the properties. */ + if (fz_is_name(ocg)) + { + ocg = fz_dict_gets(fz_dict_gets(rdb, "Properties"), fz_to_name(ocg)); + } + /* If we haven't been given an ocg at all, then we're visible */ + if (ocg == NULL) + return 0; + + fz_strlcpy(event_state, csi->event, sizeof event_state); + fz_strlcat(event_state, "State", sizeof event_state); + + type = fz_to_name(fz_dict_gets(ocg, "Type")); + + if (strcmp(type, "OCG") == 0) + { + /* An Optional Content Group */ + int num = fz_to_num(ocg); + int gen = fz_to_gen(ocg); + int len = desc->len; + int i; - fz_strlcpy(target_state, target, sizeof target_state); - fz_strlcat(target_state, "State", sizeof target_state); + for (i = 0; i < len; i++) + { + if (desc->ocgs[i].num == num && desc->ocgs[i].gen == gen) + { + if (desc->ocgs[i].state == 0) + return 1; /* If off, hidden */ + break; + } + } + + /* Check Intents; if our intent is not part of the set given + * by the current config, we should ignore it. */ + obj = fz_dict_gets(ocg, "Intent"); + if (fz_is_name(obj)) + { + /* If it doesn't match, it's hidden */ + if (ocg_intents_include(desc, fz_to_name(obj)) == 0) + return 1; + } + else if (fz_is_array(obj)) + { + int match = 0; + len = fz_array_len(obj); + for (i=0; i