diff options
Diffstat (limited to 'Build/source/texk/dvipdfm-x/xsrc/pdfdoc.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/xsrc/pdfdoc.c | 183 |
1 files changed, 167 insertions, 16 deletions
diff --git a/Build/source/texk/dvipdfm-x/xsrc/pdfdoc.c b/Build/source/texk/dvipdfm-x/xsrc/pdfdoc.c index 539ad1ab763..73ee86c8c38 100644 --- a/Build/source/texk/dvipdfm-x/xsrc/pdfdoc.c +++ b/Build/source/texk/dvipdfm-x/xsrc/pdfdoc.c @@ -236,6 +236,9 @@ typedef struct pdf_doc struct name_dict *names; + int check_gotos; + struct ht_table gotos; + struct { int outline_open_depth; double annot_grow; @@ -368,9 +371,11 @@ doc_get_page_entry (pdf_doc *p, unsigned long page_no) static void pdf_doc_init_page_tree (pdf_doc *p, double media_width, double media_height); static void pdf_doc_close_page_tree (pdf_doc *p); -static void pdf_doc_init_names (pdf_doc *p); +static void pdf_doc_init_names (pdf_doc *p, int check_gotos); static void pdf_doc_close_names (pdf_doc *p); +static void pdf_doc_add_goto (pdf_obj *annot_dict); + static void pdf_doc_init_docinfo (pdf_doc *p); static void pdf_doc_close_docinfo (pdf_doc *p); @@ -1355,6 +1360,8 @@ pdf_doc_bookmarks_add (pdf_obj *dict, int is_open) p->outlines.current = item; + pdf_doc_add_goto(dict); + return; } @@ -1397,7 +1404,7 @@ static const char *name_dict_categories[] = { #define NUM_NAME_CATEGORY (sizeof(name_dict_categories)/sizeof(name_dict_categories[0])) static void -pdf_doc_init_names (pdf_doc *p) +pdf_doc_init_names (pdf_doc *p, int check_gotos) { int i; @@ -1411,6 +1418,9 @@ pdf_doc_init_names (pdf_doc *p) p->names[NUM_NAME_CATEGORY].category = NULL; p->names[NUM_NAME_CATEGORY].data = NULL; + p->check_gotos = check_gotos; + ht_init_table(&p->gotos, (void (*) (void *)) pdf_release_obj); + return; } @@ -1438,6 +1448,136 @@ pdf_doc_add_names (const char *category, } static void +pdf_doc_add_goto (pdf_obj *annot_dict) +{ + pdf_obj *subtype = NULL, *A = NULL, *S = NULL, *D = NULL, *D_new, *dict; + const char *dest, *key; + + if (!pdoc.check_gotos) + return; + + /* + * An annotation dictionary coming from an annotation special + * must have a "Subtype". An annotation dictionary coming from + * an outline special has none. + */ + subtype = pdf_deref_obj(pdf_lookup_dict(annot_dict, "Subtype")); + if (subtype) { + if (PDF_OBJ_UNDEFINED(subtype)) + goto undefined; + else if (!PDF_OBJ_NAMETYPE(subtype)) + goto error; + else if (strcmp(pdf_name_value(subtype), "Link")) + goto cleanup; + } + + dict = annot_dict; + key = "Dest"; + D = pdf_deref_obj(pdf_lookup_dict(annot_dict, key)); + if (PDF_OBJ_UNDEFINED(D)) + goto undefined; + + A = pdf_deref_obj(pdf_lookup_dict(annot_dict, "A")); + if (A) { + if (PDF_OBJ_UNDEFINED(A)) + goto undefined; + else if (D || !PDF_OBJ_DICTTYPE(A)) + goto error; + else { + S = pdf_deref_obj(pdf_lookup_dict(A, "S")); + if (PDF_OBJ_UNDEFINED(S)) + goto undefined; + else if (!PDF_OBJ_NAMETYPE(S)) + goto error; + else if (strcmp(pdf_name_value(S), "GoTo")) + goto cleanup; + + dict = A; + key = "D"; + D = pdf_deref_obj(pdf_lookup_dict(A, key)); + } + } + + if (PDF_OBJ_STRINGTYPE(D)) + dest = (char *) pdf_string_value(D); +#if 0 + /* Names as destinations are not supported by dvipdfmx */ + else if (PDF_OBJ_NAMETYPE(D)) + dest = pdf_name_value(D); +#endif + else if (PDF_OBJ_ARRAYTYPE(D)) + goto cleanup; + else if (PDF_OBJ_UNDEFINED(D)) + goto undefined; + else + goto error; + + D_new = ht_lookup_table(&pdoc.gotos, dest, strlen(dest)); + if (!D_new) { + char buf[10]; + + /* We use hexadecimal notation for our numeric destinations. + * Other bases (e.g., 10+26 or 10+2*26) would be more efficient. + */ + sprintf(buf, "%lx", ht_table_size(&pdoc.gotos)); + D_new = pdf_new_string(buf, strlen(buf)); + ht_append_table(&pdoc.gotos, dest, strlen(dest), D_new); + } + + { + pdf_obj *key_obj = pdf_new_name(key); + if (!pdf_add_dict(dict, key_obj, pdf_link_obj(D_new))) + pdf_release_obj(key_obj); + } + + cleanup: + if (subtype) + pdf_release_obj(subtype); + if (A) + pdf_release_obj(A); + if (S) + pdf_release_obj(S); + if (D) + pdf_release_obj(D); + + return; + + error: + WARN("Unknown PDF annotation format. Output file may be broken."); + goto cleanup; + + undefined: + WARN("Cannot optimize PDF annotations. Output file may be broken." + " Please restart with option \"-C 0x10\"\n"); + goto cleanup; +} + +#ifndef XETEX +static void +warn_undef_dests (struct ht_table *dests, struct ht_table *gotos) +{ + struct ht_iter iter; + + if (ht_set_iter(gotos, &iter) < 0) + return; + + do { + int keylen; + char *key = ht_iter_getkey(&iter, &keylen); + if (!ht_lookup_table(dests, key, keylen)) { + char *dest = NEW(keylen+1, char); + memcpy(dest, key, keylen); + dest[keylen] = 0; + WARN("PDF destination \"%s\" not defined.", dest); + RELEASE(dest); + } + } while (ht_iter_next(&iter) >= 0); + + ht_clear_iter(&iter); +} +#endif + +static void pdf_doc_close_names (pdf_doc *p) { pdf_obj *tmp; @@ -1445,15 +1585,20 @@ pdf_doc_close_names (pdf_doc *p) for (i = 0; p->names[i].category != NULL; i++) { if (p->names[i].data) { + struct ht_table *data = p->names[i].data; pdf_obj *name_tree; + long count; + + name_tree = pdf_names_create_tree(data, &count, NULL); - name_tree = pdf_names_create_tree(p->names[i].data); - if (!p->root.names) { - p->root.names = pdf_new_dict(); + if (name_tree) { + if (!p->root.names) { + p->root.names = pdf_new_dict(); + } + pdf_add_dict(p->root.names, + pdf_new_name(p->names[i].category), pdf_ref_obj(name_tree)); + pdf_release_obj(name_tree); } - pdf_add_dict(p->root.names, - pdf_new_name(p->names[i].category), pdf_ref_obj(name_tree)); - pdf_release_obj(name_tree); pdf_delete_name_tree(&p->names[i].data); } } @@ -1480,12 +1625,15 @@ pdf_doc_close_names (pdf_doc *p) RELEASE(p->names); p->names = NULL; + ht_clear_table(&p->gotos); + return; } void -pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, pdf_obj *annot_dict) +pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, + pdf_obj *annot_dict, int new_annot) { pdf_doc *p = &pdoc; pdf_page *page; @@ -1496,7 +1644,6 @@ pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, pdf_obj *annot_dict) if (!page->annots) page->annots = pdf_new_array(); -#if 1 { pdf_rect mediabox; @@ -1517,7 +1664,6 @@ pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, pdf_obj *annot_dict) rect->llx, rect->lly, rect->urx, rect->ury); } } -#endif rect_array = pdf_new_array(); pdf_add_array(rect_array, pdf_new_number(ROUND(rect->llx - annot_grow, 0.001))); @@ -1528,6 +1674,9 @@ pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, pdf_obj *annot_dict) pdf_add_array(page->annots, pdf_ref_obj(annot_dict)); + if (new_annot) + pdf_doc_add_goto(annot_dict); + return; } @@ -2211,7 +2360,8 @@ void pdf_open_document (const char *filename, int do_encryption, double media_width, double media_height, - double annot_grow_amount, int bookmark_open_depth) + double annot_grow_amount, int bookmark_open_depth, + int check_gotos) { pdf_doc *p = &pdoc; @@ -2238,14 +2388,15 @@ pdf_open_document (const char *filename, pdf_doc_init_bookmarks(p, bookmark_open_depth); pdf_doc_init_articles (p); - pdf_doc_init_names (p); + pdf_doc_init_names (p, check_gotos); pdf_doc_init_page_tree(p, media_width, media_height); if (do_encryption) { pdf_obj *encrypt = pdf_encrypt_obj(); - pdf_set_encrypt(encrypt, pdf_enc_id_array()); + pdf_set_encrypt(encrypt); pdf_release_obj(encrypt); } + pdf_set_id(pdf_enc_id_array()); /* Create a default name for thumbnail image files */ if (manual_thumb_enabled) { @@ -2515,8 +2666,8 @@ pdf_doc_break_annot (void) /* Copy dict */ annot_dict = pdf_new_dict(); pdf_merge_dict(annot_dict, breaking_state.annot_dict); - pdf_doc_add_annot(pdf_doc_current_page_number(), - &(breaking_state.rect), annot_dict); + pdf_doc_add_annot(pdf_doc_current_page_number(), &(breaking_state.rect), + annot_dict, 0); pdf_release_obj(annot_dict); } reset_box(); |