From d442ada2f85d91077ef8cc20d43a48d832037635 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Wed, 28 Dec 2011 14:09:26 +0000 Subject: Outline/link destination tweaks. Move 'kind' into the fz_link_dest structure (as this makes more sense). Put an fz_link_dest rather than just a page number into the outlines structure. Correct parsing of actions and dests from pdf outlines. --- apps/pdfapp.c | 8 +-- fitz/base_link.c | 20 +++--- fitz/doc_outline.c | 4 +- fitz/fitz.h | 98 ++++++++++++++----------- pdf/mupdf.h | 2 +- pdf/pdf_annot.c | 204 ++++++++++++++++++++++++++++------------------------- pdf/pdf_outline.c | 50 ++++++------- xps/xps_outline.c | 4 +- 8 files changed, 210 insertions(+), 180 deletions(-) diff --git a/apps/pdfapp.c b/apps/pdfapp.c index cf136261..c701e350 100644 --- a/apps/pdfapp.c +++ b/apps/pdfapp.c @@ -1037,10 +1037,10 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta wincursor(app, HAND); if (btn == 1 && state == 1) { - if (link->kind == FZ_LINK_URI) - pdfapp_gotouri(app, link->dest.uri.uri); - else if (link->kind == FZ_LINK_GOTO) - pdfapp_gotopage(app, link->dest.gotor.page); + if (link->dest.kind == FZ_LINK_URI) + pdfapp_gotouri(app, link->dest.ld.uri.uri); + else if (link->dest.kind == FZ_LINK_GOTO) + pdfapp_gotopage(app, link->dest.ld.gotor.page); return; } } diff --git a/fitz/base_link.c b/fitz/base_link.c index 3f25c82d..de19dbf1 100644 --- a/fitz/base_link.c +++ b/fitz/base_link.c @@ -1,29 +1,30 @@ #include "fitz.h" static void -free_link_dest(fz_context *ctx, fz_link_kind kind, fz_link_dest *dest) +free_link_dest(fz_context *ctx, fz_link_dest *dest) { - switch(kind) + switch(dest->kind) { + case FZ_LINK_NONE: case FZ_LINK_GOTO: break; case FZ_LINK_URI: - fz_free(ctx, dest->uri.uri); + fz_free(ctx, dest->ld.uri.uri); break; case FZ_LINK_LAUNCH: - fz_free(ctx, dest->launch.file_spec); + fz_free(ctx, dest->ld.launch.file_spec); break; case FZ_LINK_NAMED: - fz_free(ctx, dest->named.named); + fz_free(ctx, dest->ld.named.named); break; case FZ_LINK_GOTOR: - fz_free(ctx, dest->gotor.file_spec); + fz_free(ctx, dest->ld.gotor.file_spec); break; } } fz_link * -fz_new_link(fz_context *ctx, fz_link_kind kind, fz_rect bbox, fz_link_dest dest) +fz_new_link(fz_context *ctx, fz_rect bbox, fz_link_dest dest) { fz_link *link; @@ -33,10 +34,9 @@ fz_new_link(fz_context *ctx, fz_link_kind kind, fz_rect bbox, fz_link_dest dest) } fz_catch(ctx) { - free_link_dest(ctx, kind, &dest); + free_link_dest(ctx, &dest); fz_rethrow(ctx); } - link->kind = kind; link->dest = dest; link->rect = bbox; link->next = NULL; @@ -51,7 +51,7 @@ fz_free_link(fz_context *ctx, fz_link *link) while (link) { next = link->next; - free_link_dest(ctx, link->kind, &link->dest); + free_link_dest(ctx, &link->dest); fz_free(ctx, link); link = next; } diff --git a/fitz/doc_outline.c b/fitz/doc_outline.c index f6d07405..9de3f482 100644 --- a/fitz/doc_outline.c +++ b/fitz/doc_outline.c @@ -18,7 +18,7 @@ fz_debug_outline_xml(fz_outline *outline, int level) { while (outline) { - printf("title, outline->page); + printf("title, outline->dest.ld.gotor.page); if (outline->down) { printf(">\n"); @@ -41,7 +41,7 @@ fz_debug_outline(fz_outline *outline, int level) { for (i = 0; i < level; i++) putchar('\t'); - printf("%s\t%d\n", outline->title, outline->page); + printf("%s\t%d\n", outline->title, outline->dest.ld.gotor.page); if (outline->down) fz_debug_outline(outline->down, level + 1); outline = outline->next; diff --git a/fitz/fitz.h b/fitz/fitz.h index 9ac43d48..d79d39f2 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1160,24 +1160,6 @@ void fz_free_display_list(fz_context *ctx, fz_display_list *list); fz_device *fz_new_list_device(fz_context *ctx, fz_display_list *list); void fz_execute_display_list(fz_display_list *list, fz_device *dev, fz_matrix ctm, fz_bbox area); -/* - * Document interface. - */ - -typedef struct fz_outline_s fz_outline; - -struct fz_outline_s -{ - fz_context *ctx; - char *title; - int page; - fz_outline *next; - fz_outline *down; -}; - -void fz_debug_outline_xml(fz_outline *outline, int level); -void fz_debug_outline(fz_outline *outline, int level); -void fz_free_outline(fz_outline *outline); /* * Plotting functions. @@ -1237,11 +1219,12 @@ enum typedef struct fz_link_s fz_link; -typedef union fz_link_dest_s fz_link_dest; +typedef struct fz_link_dest_s fz_link_dest; typedef enum fz_link_kind_e { - FZ_LINK_GOTO = 0, + FZ_LINK_NONE = 0, + FZ_LINK_GOTO, FZ_LINK_URI, FZ_LINK_LAUNCH, FZ_LINK_NAMED, @@ -1258,39 +1241,70 @@ enum { fz_link_flag_r_is_zoom = 64 /* rb.x is actually a zoom figure */ }; -union fz_link_dest_s +struct fz_link_dest_s { - struct { - int page; - int flags; - fz_point lt; - fz_point rb; - char *file_spec; - int new_window; - } gotor; - struct { - char *uri; - int is_map; - } uri; - struct { - char *file_spec; - int new_window; - } launch; - struct { - char *named; - } named; + fz_link_kind kind; + union + { + struct + { + int page; + int flags; + fz_point lt; + fz_point rb; + char *file_spec; + int new_window; + } + gotor; + struct + { + char *uri; + int is_map; + } + uri; + struct + { + char *file_spec; + int new_window; + } + launch; + struct + { + char *named; + } + named; + } + ld; }; struct fz_link_s { - fz_link_kind kind; fz_rect rect; fz_link_dest dest; fz_link *next; }; -fz_link *fz_new_link(fz_context *ctx, fz_link_kind, fz_rect bbox, fz_link_dest dest); +fz_link *fz_new_link(fz_context *ctx, fz_rect bbox, fz_link_dest dest); void fz_free_link(fz_context *ctx, fz_link *); +/* + * Document interface. + */ + +typedef struct fz_outline_s fz_outline; + +struct fz_outline_s +{ + fz_context *ctx; + char *title; + fz_link_dest dest; + fz_outline *next; + fz_outline *down; +}; + +void fz_debug_outline_xml(fz_outline *outline, int level); +void fz_debug_outline(fz_outline *outline, int level); +void fz_free_outline(fz_outline *outline); + #endif diff --git a/pdf/mupdf.h b/pdf/mupdf.h index ca173b12..bc912987 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -421,7 +421,7 @@ struct pdf_annot_s }; fz_link_dest pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest); - +fz_link_dest pdf_parse_action(pdf_xref *xref, fz_obj *action); fz_obj *pdf_lookup_dest(pdf_xref *xref, fz_obj *needle); fz_obj *pdf_lookup_name(pdf_xref *xref, char *which, fz_obj *needle); fz_obj *pdf_load_name_tree(pdf_xref *xref, char *which); diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c index ba4d509d..e9145077 100644 --- a/pdf/pdf_annot.c +++ b/pdf/pdf_annot.c @@ -34,19 +34,26 @@ pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest) fz_obj *obj; int read = 0; + dest = resolve_dest(xref, dest); + if (dest == NULL || !fz_is_array(dest)) + { + ld.kind = FZ_LINK_NONE; + return ld; + } obj = fz_array_get(dest, 0); if (fz_is_int(obj)) - ld.gotor.page = fz_to_int(obj)-1; + ld.ld.gotor.page = fz_to_int(obj)-1; else - ld.gotor.page = pdf_find_page_number(xref, obj); + ld.ld.gotor.page = pdf_find_page_number(xref, obj); - ld.gotor.flags = 0; - ld.gotor.lt.x = 0; - ld.gotor.lt.y = 0; - ld.gotor.rb.x = 0; - ld.gotor.rb.y = 0; - ld.gotor.file_spec = NULL; - ld.gotor.new_window = 0; + ld.kind = FZ_LINK_GOTO; + ld.ld.gotor.flags = 0; + ld.ld.gotor.lt.x = 0; + ld.ld.gotor.lt.y = 0; + ld.ld.gotor.rb.x = 0; + ld.ld.gotor.rb.y = 0; + ld.ld.gotor.file_spec = NULL; + ld.ld.gotor.new_window = 0; obj = fz_array_get(dest, 1); if (!fz_is_name(obj)) @@ -55,29 +62,29 @@ pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest) if (!strcmp("XYZ", fz_to_name(obj))) { read = 1+16; - ld.gotor.flags |= fz_link_flag_r_is_zoom; + ld.ld.gotor.flags |= fz_link_flag_r_is_zoom; } else if ((!strcmp("Fit", fz_to_name(obj))) || (!strcmp("FitB", fz_to_name(obj)))) { read = 0; - ld.gotor.flags |= fz_link_flag_fit_h; - ld.gotor.flags |= fz_link_flag_fit_v; + ld.ld.gotor.flags |= fz_link_flag_fit_h; + ld.ld.gotor.flags |= fz_link_flag_fit_v; } else if ((!strcmp("FitH", fz_to_name(obj))) || (!strcmp("FitBH", fz_to_name(obj)))) { read = 32; - ld.gotor.flags |= fz_link_flag_fit_h; + ld.ld.gotor.flags |= fz_link_flag_fit_h; } else if ((!strcmp("FitV", fz_to_name(obj))) || (!strcmp("FitBV", fz_to_name(obj)))) { read = 1; - ld.gotor.flags |= fz_link_flag_fit_v; + ld.ld.gotor.flags |= fz_link_flag_fit_v; } else if (!strcmp("FitR", fz_to_name(obj))) { read = 1+2+4+8; - ld.gotor.flags |= fz_link_flag_fit_h; - ld.gotor.flags |= fz_link_flag_fit_v; + ld.ld.gotor.flags |= fz_link_flag_fit_h; + ld.ld.gotor.flags |= fz_link_flag_fit_v; } if (read & 1) @@ -85,13 +92,13 @@ pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest) obj = fz_array_get(dest, 2); if (fz_is_int(obj)) { - ld.gotor.flags |= fz_link_flag_l_valid; - ld.gotor.lt.x = fz_to_int(obj); + ld.ld.gotor.flags |= fz_link_flag_l_valid; + ld.ld.gotor.lt.x = fz_to_int(obj); } else if (fz_is_real(obj)) { - ld.gotor.flags |= fz_link_flag_l_valid; - ld.gotor.lt.x = fz_to_real(obj); + ld.ld.gotor.flags |= fz_link_flag_l_valid; + ld.ld.gotor.lt.x = fz_to_real(obj); } } if (read & 2) @@ -99,13 +106,13 @@ pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest) obj = fz_array_get(dest, 3); if (fz_is_int(obj)) { - ld.gotor.flags |= fz_link_flag_b_valid; - ld.gotor.rb.y = fz_to_int(obj); + ld.ld.gotor.flags |= fz_link_flag_b_valid; + ld.ld.gotor.rb.y = fz_to_int(obj); } else if (fz_is_real(obj)) { - ld.gotor.flags |= fz_link_flag_b_valid; - ld.gotor.rb.y = fz_to_real(obj); + ld.ld.gotor.flags |= fz_link_flag_b_valid; + ld.ld.gotor.rb.y = fz_to_real(obj); } } if (read & 4) @@ -113,13 +120,13 @@ pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest) obj = fz_array_get(dest, 4); if (fz_is_int(obj)) { - ld.gotor.flags |= fz_link_flag_r_valid; - ld.gotor.rb.x = fz_to_int(obj); + ld.ld.gotor.flags |= fz_link_flag_r_valid; + ld.ld.gotor.rb.x = fz_to_int(obj); } else if (fz_is_real(obj)) { - ld.gotor.flags |= fz_link_flag_r_valid; - ld.gotor.rb.x = fz_to_real(obj); + ld.ld.gotor.flags |= fz_link_flag_r_valid; + ld.ld.gotor.rb.x = fz_to_real(obj); } } if (read & (8+16+32)) @@ -132,13 +139,13 @@ pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest) obj = fz_array_get(dest, 2); if (fz_is_int(obj)) { - ld.gotor.flags |= fz_link_flag_t_valid; - ld.gotor.lt.x = fz_to_int(obj); + ld.ld.gotor.flags |= fz_link_flag_t_valid; + ld.ld.gotor.lt.x = fz_to_int(obj); } else if (fz_is_real(obj)) { - ld.gotor.flags |= fz_link_flag_t_valid; - ld.gotor.lt.x = fz_to_real(obj); + ld.ld.gotor.flags |= fz_link_flag_t_valid; + ld.ld.gotor.lt.x = fz_to_real(obj); } } if (read & 16) @@ -146,26 +153,72 @@ pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest) obj = fz_array_get(dest, 4); if (fz_is_int(obj)) { - ld.gotor.flags |= fz_link_flag_r_valid; - ld.gotor.rb.x = fz_to_int(obj); + ld.ld.gotor.flags |= fz_link_flag_r_valid; + ld.ld.gotor.rb.x = fz_to_int(obj); } else if (fz_is_real(obj)) { - ld.gotor.flags |= fz_link_flag_r_valid; - ld.gotor.rb.x = fz_to_real(obj); + ld.ld.gotor.flags |= fz_link_flag_r_valid; + ld.ld.gotor.rb.x = fz_to_real(obj); } } /* Duplicate the values out for the sake of stupid clients */ - if ((ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid)) == fz_link_flag_l_valid) - ld.gotor.rb.x = ld.gotor.lt.x; - if ((ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid | fz_link_flag_r_is_zoom)) == fz_link_flag_r_valid) - ld.gotor.lt.x = ld.gotor.rb.x; - if ((ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_t_valid) - ld.gotor.rb.y = ld.gotor.lt.y; - if ((ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_b_valid) - ld.gotor.lt.y = ld.gotor.rb.y; + if ((ld.ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid)) == fz_link_flag_l_valid) + ld.ld.gotor.rb.x = ld.ld.gotor.lt.x; + if ((ld.ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid | fz_link_flag_r_is_zoom)) == fz_link_flag_r_valid) + ld.ld.gotor.lt.x = ld.ld.gotor.rb.x; + if ((ld.ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_t_valid) + ld.ld.gotor.rb.y = ld.ld.gotor.lt.y; + if ((ld.ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_b_valid) + ld.ld.gotor.lt.y = ld.ld.gotor.rb.y; + + return ld; +} + +fz_link_dest +pdf_parse_action(pdf_xref *xref, fz_obj *action) +{ + fz_link_dest ld; + fz_obj *obj, *dest; + fz_context *ctx = xref->ctx; + + ld.kind = FZ_LINK_NONE; + if (!action) + return ld; + + obj = fz_dict_gets(action, "S"); + if (!strcmp(fz_to_name(obj), "GoTo")) + { + dest = fz_dict_gets(action, "D"); + ld = pdf_parse_link_dest(xref, dest); + } + else if (!strcmp(fz_to_name(obj), "URI")) + { + ld.kind = FZ_LINK_URI; + ld.ld.uri.is_map = fz_to_int(fz_dict_gets(action, "IsMap")); + ld.ld.uri.uri = pdf_to_utf8(ctx, fz_dict_gets(action, "URI")); + } + else if (!strcmp(fz_to_name(obj), "Launch")) + { + ld.kind = FZ_LINK_LAUNCH; + ld.ld.launch.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F")); + ld.ld.launch.new_window = fz_to_int(fz_dict_gets(action, "NewWindow")); + } + else if (!strcmp(fz_to_name(obj), "Named")) + { + ld.kind = FZ_LINK_NAMED; + ld.ld.named.named = pdf_to_utf8(ctx, fz_dict_gets(action, "N")); + } + else if (!strcmp(fz_to_name(obj), "GoToR")) + { + dest = fz_dict_gets(action, "D"); + ld = pdf_parse_link_dest(xref, dest); + ld.kind = FZ_LINK_GOTOR; + ld.ld.gotor.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F")); + ld.ld.gotor.new_window = fz_to_int(fz_dict_gets(action, "NewWindow")); + } return ld; } @@ -177,6 +230,7 @@ pdf_load_link(pdf_xref *xref, fz_obj *dict) fz_obj *obj; fz_rect bbox; fz_context *ctx = xref->ctx; + fz_link_dest ld; dest = NULL; @@ -189,63 +243,21 @@ pdf_load_link(pdf_xref *xref, fz_obj *dict) obj = fz_dict_gets(dict, "Dest"); if (obj) { - fz_link_dest ld; dest = resolve_dest(xref, obj); ld = pdf_parse_link_dest(xref, dest); - return fz_new_link(ctx, FZ_LINK_GOTO, bbox, ld); } - - action = fz_dict_gets(dict, "A"); - - /* fall back to additional action button's down/up action */ - if (!action) - action = fz_dict_getsa(fz_dict_gets(dict, "AA"), "U", "D"); - - if (action) + else { - obj = fz_dict_gets(action, "S"); - if (!fz_is_name(obj)) - { - } - else if (!strcmp(fz_to_name(obj), "GoTo")) - { - fz_link_dest ld; - dest = resolve_dest(xref, fz_dict_gets(action, "D")); - ld = pdf_parse_link_dest(xref, dest); - return fz_new_link(ctx, FZ_LINK_GOTO, bbox, ld); - } - else if (!strcmp(fz_to_name(obj), "URI")) - { - fz_link_dest ld; - ld.uri.is_map = fz_to_int(fz_dict_gets(action, "IsMap")); - ld.uri.uri = pdf_to_utf8(ctx, fz_dict_gets(action, "URI")); - return fz_new_link(ctx, FZ_LINK_URI, bbox, ld); - } - else if (!strcmp(fz_to_name(obj), "Launch")) - { - fz_link_dest ld; - ld.launch.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F")); - ld.launch.new_window = fz_to_int(fz_dict_gets(action, "NewWindow")); - return fz_new_link(ctx, FZ_LINK_LAUNCH, bbox, ld); - } - else if (!strcmp(fz_to_name(obj), "Named")) - { - fz_link_dest ld; - ld.named.named = pdf_to_utf8(ctx, fz_dict_gets(action, "N")); - return fz_new_link(ctx, FZ_LINK_NAMED, bbox, ld); - } - else if (!strcmp(fz_to_name(obj), "GoToR")) - { - fz_link_dest ld; - dest = resolve_dest(xref, fz_dict_gets(action, "D")); - ld = pdf_parse_link_dest(xref, dest); - ld.gotor.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F")); - ld.gotor.new_window = fz_to_int(fz_dict_gets(action, "NewWindow")); - return fz_new_link(ctx, FZ_LINK_GOTOR, bbox, ld); - } - } + action = fz_dict_gets(dict, "A"); + /* fall back to additional action button's down/up action */ + if (!action) + action = fz_dict_getsa(fz_dict_gets(dict, "AA"), "U", "D"); - return NULL; + ld = pdf_parse_action(xref, action); + } + if (ld.kind == FZ_LINK_NONE) + return NULL; + return fz_new_link(ctx, bbox, ld); } void diff --git a/pdf/pdf_outline.c b/pdf/pdf_outline.c index 3f6b745b..be43d709 100644 --- a/pdf/pdf_outline.c +++ b/pdf/pdf_outline.c @@ -5,38 +5,40 @@ static fz_outline * pdf_load_outline_imp(pdf_xref *xref, fz_obj *dict) { fz_context *ctx = xref->ctx; - fz_outline *node; + fz_outline *node, *first = NULL; fz_obj *obj; if (fz_is_null(dict)) return NULL; - node = fz_malloc_struct(ctx, fz_outline); - node->ctx = ctx; - node->title = NULL; - node->page = 0; - node->down = NULL; - node->next = NULL; - - obj = fz_dict_gets(dict, "Title"); - if (obj) - node->title = pdf_to_utf8(ctx, obj); - - if (fz_dict_gets(dict, "Dest") || fz_dict_gets(dict, "A")) + while (dict) { - fz_link_dest ld = pdf_parse_link_dest(xref, dict); - node->page = ld.gotor.page; + node = fz_malloc_struct(ctx, fz_outline); + node->ctx = ctx; + node->title = NULL; + node->dest.kind = FZ_LINK_NONE; + node->down = NULL; + node->next = NULL; + if (first == NULL) + first = node; + + obj = fz_dict_gets(dict, "Title"); + if (obj) + node->title = pdf_to_utf8(ctx, obj); + + if ((obj = fz_dict_gets(dict, "Dest"))) + node->dest = pdf_parse_link_dest(xref, obj); + else if ((obj = fz_dict_gets(dict, "A"))) + node->dest = pdf_parse_action(xref, obj); + + obj = fz_dict_gets(dict, "First"); + if (obj) + node->down = pdf_load_outline_imp(xref, obj); + + dict = fz_dict_gets(dict, "Next"); } - obj = fz_dict_gets(dict, "First"); - if (obj) - node->down = pdf_load_outline_imp(xref, obj); - - obj = fz_dict_gets(dict, "Next"); - if (obj) - node->next = pdf_load_outline_imp(xref, obj); - - return node; + return first; } fz_outline * diff --git a/xps/xps_outline.c b/xps/xps_outline.c index 6252a6c1..30357491 100644 --- a/xps/xps_outline.c +++ b/xps/xps_outline.c @@ -33,7 +33,9 @@ xps_parse_document_outline(xps_document *doc, xml_element *root) entry = fz_malloc_struct(doc->ctx, fz_outline); entry->title = fz_strdup(doc->ctx, description); - entry->page = xps_find_link_target(doc, target); + entry->dest.kind = FZ_LINK_GOTO; + entry->dest.ld.gotor.flags = 0; + entry->dest.ld.gotor.page = xps_find_link_target(doc, target); entry->down = NULL; entry->next = NULL; -- cgit v1.2.3