static void do_links(fz_link *link, int xofs, int yofs) { fz_rect r; float x, y; x = ui.x; y = ui.y; xofs -= page_tex.x; yofs -= page_tex.y; glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); while (link) { r = link->rect; fz_transform_rect(&r, &page_ctm); if (x >= xofs + r.x0 && x < xofs + r.x1 && y >= yofs + r.y0 && y < yofs + r.y1) { ui.hot = link; if (!ui.active && ui.down) ui.active = link; } if (ui.hot == link || showlinks) { if (ui.active == link && ui.hot == link) glColor4f(0, 0, 1, 0.4f); else if (ui.hot == link) glColor4f(0, 0, 1, 0.2f); else glColor4f(0, 0, 1, 0.1f); glRectf(xofs + r.x0, yofs + r.y0, xofs + r.x1, yofs + r.y1); } if (ui.active == link && !ui.down) { if (ui.hot == link) { if (fz_is_external_link(ctx, link->uri)) open_browser(link->uri); else { jump_to_page(fz_resolve_link(ctx, doc, link->uri, NULL, NULL)); ui_needs_update = 1; } } } link = link->next; } glDisable(GL_BLEND); }
static void build_index(fz_context* ctx, fz_document* document, fz_outline* outline, girara_tree_node_t* root) { if (outline == NULL || root == NULL) { return; } while (outline != NULL) { zathura_index_element_t* index_element = zathura_index_element_new(outline->title); zathura_link_target_t target = { ZATHURA_LINK_DESTINATION_UNKNOWN, NULL, 0, -1, -1, -1, -1, 0 }; zathura_link_type_t type = ZATHURA_LINK_INVALID; zathura_rectangle_t rect = { .x1 = 0, .y1 = 0, .x2 = 0, .y2 = 0 }; if (outline->uri == NULL) { type = ZATHURA_LINK_NONE; } else if (fz_is_external_link(ctx, outline->uri) == 1) { if (strstr(outline->uri, "file://") == outline->uri) { type = ZATHURA_LINK_GOTO_REMOTE; target.value = outline->uri; } else { type = ZATHURA_LINK_URI; target.value = outline->uri; } } else { float x = 0; float y = 0; type = ZATHURA_LINK_GOTO_DEST; target.destination_type = ZATHURA_LINK_DESTINATION_XYZ; target.page_number = fz_resolve_link(ctx, document, outline->uri, &x, &y); target.left = x; target.top = y; target.zoom = 0.0; } index_element->link = zathura_link_new(type, rect, target); if (index_element->link == NULL) { outline = outline->next; continue; } girara_tree_node_t* node = girara_node_append_data(root, index_element); if (outline->down != NULL) { build_index(ctx, document, outline->down, node); } outline = outline->next; } }
char * pdf_parse_link_action(fz_context *ctx, pdf_document *doc, pdf_obj *action, int pagenum) { pdf_obj *obj, *dest, *file_spec; if (!action) return NULL; obj = pdf_dict_get(ctx, action, PDF_NAME_S); if (pdf_name_eq(ctx, PDF_NAME_GoTo, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_D); return pdf_parse_link_dest(ctx, doc, dest); } else if (pdf_name_eq(ctx, PDF_NAME_URI, obj)) { /* URI entries are ASCII strings */ const char *uri = pdf_to_str_buf(ctx, pdf_dict_get(ctx, action, PDF_NAME_URI)); if (!fz_is_external_link(ctx, uri)) { pdf_obj *uri_base_obj = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/URI/Base"); const char *uri_base = uri_base_obj ? pdf_to_str_buf(ctx, uri_base_obj) : "file://"; char *new_uri = fz_malloc(ctx, strlen(uri_base) + strlen(uri) + 1); strcpy(new_uri, uri_base); strcat(new_uri, uri); return new_uri; } return fz_strdup(ctx, uri); } else if (pdf_name_eq(ctx, PDF_NAME_Launch, obj)) { file_spec = pdf_dict_get(ctx, action, PDF_NAME_F); return pdf_parse_file_spec(ctx, doc, file_spec, NULL); } else if (pdf_name_eq(ctx, PDF_NAME_GoToR, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_D); file_spec = pdf_dict_get(ctx, action, PDF_NAME_F); return pdf_parse_file_spec(ctx, doc, file_spec, dest); } else if (pdf_name_eq(ctx, PDF_NAME_Named, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_N); if (pdf_name_eq(ctx, PDF_NAME_FirstPage, dest)) pagenum = 0; else if (pdf_name_eq(ctx, PDF_NAME_LastPage, dest)) pagenum = pdf_count_pages(ctx, doc) - 1; else if (pdf_name_eq(ctx, PDF_NAME_PrevPage, dest) && pagenum >= 0) { if (pagenum > 0) pagenum--; } else if (pdf_name_eq(ctx, PDF_NAME_NextPage, dest) && pagenum >= 0) { if (pagenum < pdf_count_pages(ctx, doc) - 1) pagenum++; } else return NULL; return fz_asprintf(ctx, "#%d", pagenum + 1); } return NULL; }