static fz_obj * resolve_dest(pdf_xref *xref, fz_obj *dest) { if (fz_is_name(xref->ctx, dest) || fz_is_string(xref->ctx, dest)) { dest = pdf_lookup_dest(xref, dest); return resolve_dest(xref, dest); } else if (fz_is_array(xref->ctx, dest)) { return dest; } else if (fz_is_dict(xref->ctx, dest)) { dest = fz_dict_gets(xref->ctx, dest, "D"); return resolve_dest(xref, dest); } else if (fz_is_indirect(dest)) return dest; return NULL; }
static fz_link * pdf_load_link(pdf_document *xref, pdf_obj *dict, fz_matrix page_ctm) { pdf_obj *dest = NULL; pdf_obj *action; pdf_obj *obj; fz_rect bbox; fz_context *ctx = xref->ctx; fz_link_dest ld; dest = NULL; obj = pdf_dict_gets(dict, "Rect"); if (obj) bbox = pdf_to_rect(ctx, obj); else bbox = fz_empty_rect; bbox = fz_transform_rect(page_ctm, bbox); obj = pdf_dict_gets(dict, "Dest"); if (obj) { dest = resolve_dest(xref, obj); ld = pdf_parse_link_dest(xref, dest); } else { action = pdf_dict_gets(dict, "A"); /* fall back to additional action button's down/up action */ if (!action) action = pdf_dict_getsa(pdf_dict_gets(dict, "AA"), "U", "D"); ld = pdf_parse_action(xref, action); } if (ld.kind == FZ_LINK_NONE) return NULL; return fz_new_link(ctx, bbox, ld); }
fz_link_dest pdf_parse_link_dest(pdf_document *xref, pdf_obj *dest) { fz_link_dest ld; pdf_obj *obj; int l_from_2 = 0; int b_from_3 = 0; int r_from_4 = 0; int t_from_5 = 0; int t_from_3 = 0; int t_from_2 = 0; int z_from_4 = 0; dest = resolve_dest(xref, dest); if (dest == NULL || !pdf_is_array(dest)) { ld.kind = FZ_LINK_NONE; return ld; } obj = pdf_array_get(dest, 0); if (pdf_is_int(obj)) ld.ld.gotor.page = pdf_to_int(obj); else ld.ld.gotor.page = pdf_lookup_page_number(xref, obj); 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 = pdf_array_get(dest, 1); if (!pdf_is_name(obj)) return ld; if (!strcmp("XYZ", pdf_to_name(obj))) { l_from_2 = t_from_3 = z_from_4 = 1; ld.ld.gotor.flags |= fz_link_flag_r_is_zoom; } else if ((!strcmp("Fit", pdf_to_name(obj))) || (!strcmp("FitB", pdf_to_name(obj)))) { ld.ld.gotor.flags |= fz_link_flag_fit_h; ld.ld.gotor.flags |= fz_link_flag_fit_v; } else if ((!strcmp("FitH", pdf_to_name(obj))) || (!strcmp("FitBH", pdf_to_name(obj)))) { t_from_2 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_h; } else if ((!strcmp("FitV", pdf_to_name(obj))) || (!strcmp("FitBV", pdf_to_name(obj)))) { l_from_2 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_v; } else if (!strcmp("FitR", pdf_to_name(obj))) { l_from_2 = b_from_3 = r_from_4 = t_from_5 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_h; ld.ld.gotor.flags |= fz_link_flag_fit_v; } if (l_from_2) { obj = pdf_array_get(dest, 2); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_l_valid; ld.ld.gotor.lt.x = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_l_valid; ld.ld.gotor.lt.x = pdf_to_real(obj); } } if (b_from_3) { obj = pdf_array_get(dest, 3); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_b_valid; ld.ld.gotor.rb.y = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_b_valid; ld.ld.gotor.rb.y = pdf_to_real(obj); } } if (r_from_4) { obj = pdf_array_get(dest, 4); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_real(obj); } } if (t_from_5 || t_from_3 || t_from_2) { if (t_from_5) obj = pdf_array_get(dest, 5); else if (t_from_3) obj = pdf_array_get(dest, 3); else obj = pdf_array_get(dest, 2); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_t_valid; ld.ld.gotor.lt.y = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_t_valid; ld.ld.gotor.lt.y = pdf_to_real(obj); } } if (z_from_4) { obj = pdf_array_get(dest, 4); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_real(obj); } } /* Duplicate the values out for the sake of stupid clients */ 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; }
char * pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest) { pdf_obj *obj; char buf[256]; const char *ld; int page; int x, y; dest = resolve_dest(ctx, doc, dest); if (dest == NULL) { fz_warn(ctx, "undefined link destination"); return NULL; } if (pdf_is_name(ctx, dest)) { ld = pdf_to_name(ctx, dest); return fz_strdup(ctx, ld); } else if (pdf_is_string(ctx, dest)) { ld = pdf_to_str_buf(ctx, dest); return fz_strdup(ctx, ld); } obj = pdf_array_get(ctx, dest, 0); if (pdf_is_int(ctx, obj)) page = pdf_to_int(ctx, obj); else { fz_try(ctx) page = pdf_lookup_page_number(ctx, doc, obj); fz_catch(ctx) page = -1; } x = y = 0; obj = pdf_array_get(ctx, dest, 1); if (pdf_name_eq(ctx, obj, PDF_NAME_XYZ)) { x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 3)); } else if (pdf_name_eq(ctx, obj, PDF_NAME_FitR)) { x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 5)); } else if (pdf_name_eq(ctx, obj, PDF_NAME_FitH) || pdf_name_eq(ctx, obj, PDF_NAME_FitBH)) y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); else if (pdf_name_eq(ctx, obj, PDF_NAME_FitV) || pdf_name_eq(ctx, obj, PDF_NAME_FitBV)) x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); if (page >= 0) { if (x != 0 || y != 0) fz_snprintf(buf, sizeof buf, "#%d,%d,%d", page + 1, x, y); else fz_snprintf(buf, sizeof buf, "#%d", page + 1); return fz_strdup(ctx, buf); } return NULL; }
pdf_link * pdf_load_link(pdf_xref *xref, fz_obj *dict) { fz_obj *dest; fz_obj *action; fz_obj *obj; fz_rect bbox; pdf_link_kind kind; fz_context *ctx = xref->ctx; dest = NULL; obj = fz_dict_gets(ctx, dict, "Rect"); if (obj) bbox = pdf_to_rect(ctx, obj); else bbox = fz_empty_rect; obj = fz_dict_gets(ctx, dict, "Dest"); if (obj) { kind = PDF_LINK_GOTO; dest = resolve_dest(xref, obj); } action = fz_dict_gets(ctx, dict, "A"); /* fall back to additional action button's down/up action */ if (!action) action = fz_dict_getsa(ctx, fz_dict_gets(ctx, dict, "AA"), "U", "D"); if (action) { obj = fz_dict_gets(ctx, action, "S"); if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "GoTo")) { kind = PDF_LINK_GOTO; dest = resolve_dest(xref, fz_dict_gets(ctx, action, "D")); } else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "URI")) { kind = PDF_LINK_URI; dest = fz_dict_gets(ctx, action, "URI"); } else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "Launch")) { kind = PDF_LINK_LAUNCH; dest = fz_dict_gets(ctx, action, "F"); } else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "Named")) { kind = PDF_LINK_NAMED; dest = fz_dict_gets(ctx, action, "N"); } else if (fz_is_name(ctx, obj) && (!strcmp(fz_to_name(ctx, obj), "GoToR"))) { kind = PDF_LINK_ACTION; dest = action; } else { dest = NULL; } } if (dest) { pdf_link *link = fz_malloc(ctx, sizeof(pdf_link)); link->kind = kind; link->rect = bbox; link->dest = fz_keep_obj(dest); link->next = NULL; return link; } return NULL; }
char * pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest) { pdf_obj *obj, *pageobj; fz_rect mediabox; fz_matrix pagectm; const char *ld; int page, x, y, h; dest = resolve_dest(ctx, doc, dest); if (dest == NULL) { fz_warn(ctx, "undefined link destination"); return NULL; } if (pdf_is_name(ctx, dest)) { ld = pdf_to_name(ctx, dest); return fz_strdup(ctx, ld); } else if (pdf_is_string(ctx, dest)) { ld = pdf_to_str_buf(ctx, dest); return fz_strdup(ctx, ld); } pageobj = pdf_array_get(ctx, dest, 0); if (pdf_is_int(ctx, pageobj)) { page = pdf_to_int(ctx, pageobj); pageobj = pdf_lookup_page_obj(ctx, doc, page); } else { fz_try(ctx) page = pdf_lookup_page_number(ctx, doc, pageobj); fz_catch(ctx) page = -1; } if (page < 0) return NULL; obj = pdf_array_get(ctx, dest, 1); if (obj) { /* Link coords use a coordinate space that does not seem to respect Rotate or UserUnit. */ /* All we need to do is figure out the page height to flip the coordinate space. */ pdf_page_obj_transform(ctx, pageobj, &mediabox, &pagectm); mediabox = fz_transform_rect(mediabox, pagectm); h = mediabox.y1 - mediabox.y0; if (pdf_name_eq(ctx, obj, PDF_NAME(XYZ))) { x = pdf_array_get_int(ctx, dest, 2); y = h - pdf_array_get_int(ctx, dest, 3); } else if (pdf_name_eq(ctx, obj, PDF_NAME(FitR))) { x = pdf_array_get_int(ctx, dest, 2); y = h - pdf_array_get_int(ctx, dest, 5); } else if (pdf_name_eq(ctx, obj, PDF_NAME(FitH)) || pdf_name_eq(ctx, obj, PDF_NAME(FitBH))) { x = 0; y = h - pdf_array_get_int(ctx, dest, 2); } else if (pdf_name_eq(ctx, obj, PDF_NAME(FitV)) || pdf_name_eq(ctx, obj, PDF_NAME(FitBV))) { x = pdf_array_get_int(ctx, dest, 2); y = 0; } else { x = 0; y = 0; } return fz_asprintf(ctx, "#%d,%d,%d", page + 1, x, y); } return fz_asprintf(ctx, "#%d", page + 1); }