diff options
Diffstat (limited to 'src/pdf_bridge.c')
| -rw-r--r-- | src/pdf_bridge.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/pdf_bridge.c b/src/pdf_bridge.c index 8e433fde..bdc7b891 100644 --- a/src/pdf_bridge.c +++ b/src/pdf_bridge.c @@ -27,6 +27,8 @@ struct pardes_pdf_document { fz_stext_page *cached_text; fz_display_list *cached_display_list; fz_rect cached_bounds; + fz_link *cached_links; + int cached_links_loaded; /* Promote only a page which is rendered twice without changing pages. */ int display_list_candidate_page_number; @@ -126,12 +128,15 @@ pardes_pdf_free_document(pardes_pdf_document *document) static void pardes_pdf_drop_cached_page(pardes_pdf_document *document) { + fz_drop_link(document->ctx, document->cached_links); fz_drop_display_list(document->ctx, document->cached_display_list); fz_drop_stext_page(document->ctx, document->cached_text); fz_drop_page(document->ctx, document->cached_page); document->cached_display_list = NULL; document->cached_text = NULL; document->cached_page = NULL; + document->cached_links = NULL; + document->cached_links_loaded = 0; document->cached_page_number = -1; document->display_list_candidate_page_number = -1; } @@ -994,6 +999,85 @@ pardes_pdf_point_inside_quad(pardes_pdf_point point, pardes_pdf_quad quad) } int +pardes_pdf_link_at( + pardes_pdf_document *document, + int page_number, + pardes_pdf_point point, + pardes_pdf_link *out) +{ + fz_context *ctx; + + if (out == NULL) + return PARDES_PDF_ERROR; + memset(out, 0, sizeof(*out)); + out->page = -1; + if (document == NULL || page_number < 0 || + page_number >= document->page_count) + return PARDES_PDF_ERROR; + if (!pardes_pdf_valid_point(point) || point.x < 0 || point.x > 1 || + point.y < 0 || point.y > 1) + return PARDES_PDF_OK; + + ctx = document->ctx; + fz_try(ctx) + { + fz_link *link; + fz_point page_point; + pardes_pdf_cache_page(document, page_number, 0); + if (!document->cached_links_loaded) { + document->cached_links = fz_load_links(ctx, document->cached_page); + document->cached_links_loaded = 1; + } + page_point = pardes_pdf_point_to_page(document, point); + for (link = document->cached_links; link != NULL; link = link->next) { + size_t len; + int destination_kind; + int destination_page = -1; + fz_link_dest destination = fz_make_link_dest_none(); + if (!pardes_pdf_valid_bounds(link->rect) || + !fz_is_point_inside_rect(page_point, link->rect) || + link->uri == NULL || link->uri[0] == 0) + continue; + for (len = 0; len <= PARDES_PDF_MAX_LINK_URI_BYTES && + link->uri[len] != 0; ++len) + ; + if (len > PARDES_PDF_MAX_LINK_URI_BYTES) + continue; + destination_kind = PARDES_PDF_OUTLINE_DESTINATION_EXTERNAL; + if (!fz_is_external_link(ctx, link->uri)) { + destination = fz_resolve_link_dest(ctx, document->doc, link->uri); + if (destination.loc.chapter >= 0 && destination.loc.page >= 0) + destination_page = fz_page_number_from_location( + ctx, document->doc, destination.loc); + if (destination_page >= 0 && destination_page < document->page_count) + destination_kind = PARDES_PDF_OUTLINE_DESTINATION_INTERNAL; + else if (link->uri[0] == '#') + continue; + } + out->quad = pardes_pdf_quad_from_page( + document, fz_quad_from_rect(link->rect)); + out->destination_kind = destination_kind; + if (destination_kind == PARDES_PDF_OUTLINE_DESTINATION_INTERNAL) { + out->page = destination_page; + out->has_x = isfinite(destination.x); + out->has_y = isfinite(destination.y); + if (out->has_x) out->x = destination.x; + if (out->has_y) out->y = destination.y; + } + out->uri = (const unsigned char *)link->uri; + out->uri_len = len; + break; + } + } + fz_catch(ctx) + { + memset(out, 0, sizeof(*out)); + return PARDES_PDF_ERROR; + } + return PARDES_PDF_OK; +} + +int pardes_pdf_copy_selection( pardes_pdf_document *document, int page_number, @@ -1041,6 +1125,43 @@ pardes_pdf_drop_owned_text(pardes_pdf_document *document, void *text) fz_free(document->ctx, text); } +int +pardes_pdf_copy_rectangle( + pardes_pdf_document *document, + int page_number, + pardes_pdf_quad quad, + pardes_pdf_owned_text *out) +{ + fz_context *ctx; + char *text = NULL; + fz_quad native; + if (document == NULL || out == NULL || page_number < 0 || + page_number >= document->page_count || !pardes_pdf_valid_quad(quad)) + return PARDES_PDF_ERROR; + memset(out, 0, sizeof(*out)); + ctx = document->ctx; + fz_var(text); + fz_try(ctx) + { + pardes_pdf_cache_page(document, page_number, 1); + native.ul = pardes_pdf_point_to_page(document, quad.ul); + native.ur = pardes_pdf_point_to_page(document, quad.ur); + native.ll = pardes_pdf_point_to_page(document, quad.ll); + native.lr = pardes_pdf_point_to_page(document, quad.lr); + text = fz_copy_rectangle(ctx, document->cached_text, + fz_rect_from_quad(native), 0); + } + fz_catch(ctx) + { + fz_free(ctx, text); + return PARDES_PDF_ERROR; + } + out->handle = text; + out->data = (const unsigned char *)text; + out->len = text == NULL ? 0 : strlen(text); + return PARDES_PDF_OK; +} + typedef struct pardes_pdf_outline_measurement { size_t item_count; size_t bytes_len; |
