diff --git a/src/document/document.c b/src/document/document.c index f183082bf..f3b88078a 100644 --- a/src/document/document.c +++ b/src/document/document.c @@ -325,6 +325,7 @@ reset_document(struct document *document) mem_free_set(&document->links, NULL); document->nlinks = 0; } + mem_free_set(&document->reverse_link_lookup, NULL); if (document->data) { int pos; @@ -391,6 +392,7 @@ done_document(struct document *document) mem_free(document->links); } + mem_free_set(&document->reverse_link_lookup, NULL); if (document->data) { int pos; diff --git a/src/document/document.h b/src/document/document.h index 9cd5ab4a1..0257d0b08 100644 --- a/src/document/document.h +++ b/src/document/document.h @@ -137,6 +137,7 @@ struct link { int npoints; int number; + unsigned int tabindex; /** This is supposed to be the colour-pair of the link, but the actual * colours on the canvas can differ--e.g., with image links. */ @@ -153,6 +154,11 @@ struct link { } data; }; +struct reverse_link_lookup { + int number; + int i; +}; + #define get_link_index(document, link) (link - document->links) #define link_is_textinput(link) \ @@ -271,6 +277,8 @@ struct document { struct line *data; struct link *links; + + struct reverse_link_lookup *reverse_link_lookup; /** @name Arrays with one item per rendered document's line. * @{ */ struct link **lines1; /**< The first link on the line. */ diff --git a/src/document/html/renderer.c b/src/document/html/renderer.c index fd7c1a575..69d34fa7c 100644 --- a/src/document/html/renderer.c +++ b/src/document/html/renderer.c @@ -1309,7 +1309,7 @@ new_link(struct html_context *html_context, const char *name, int namelen) link = &document->links[document->nlinks++]; link->number = link_number - 1; - if (document->options.use_tabindex) link->number += elformat.tabindex; + link->tabindex = document->options.use_tabindex ? elformat.tabindex : 0; link->accesskey = elformat.accesskey; link->title = null_or_stracpy(elformat.title); link->where_img = null_or_stracpy(elformat.image); diff --git a/src/document/renderer.c b/src/document/renderer.c index 169699da3..dc320170f 100644 --- a/src/document/renderer.c +++ b/src/document/renderer.c @@ -358,6 +358,14 @@ comp_links(const void *v1, const void *v2) assert(l1 && l2); if_assert_failed return 0; + if (l1->tabindex < l2->tabindex) { + return -1; + } + + if (l1->tabindex > l2->tabindex) { + return 1; + } + if (l1->number < l2->number) { return -1; } @@ -369,6 +377,26 @@ comp_links(const void *v1, const void *v2) return 0; } +static int +comp_ints(const void *v1, const void *v2) +{ + const struct reverse_link_lookup *l1 = (const struct reverse_link_lookup *)v1, *l2 = (const struct reverse_link_lookup *)v2; + + assert(l1 && l2); + if_assert_failed return 0; + + if (l1->number < l2->number) { + return -1; + } + + if (l1->number > l2->number) { + return 1; + } + + return 0; +} + + void sort_links(struct document *document) { @@ -420,6 +448,21 @@ sort_links(struct document *document) document->lines1[j] = &document->links[i]; } } + mem_free_set(&document->reverse_link_lookup, NULL); + + if (document->options.use_tabindex) { + document->reverse_link_lookup = mem_alloc(document->nlinks * sizeof(*document->reverse_link_lookup)); + + if (document->reverse_link_lookup) { + for (i = 0; i < document->nlinks; i++) { + struct link *link = &document->links[i]; + + document->reverse_link_lookup[i].number = link->number; + document->reverse_link_lookup[i].i = i; + } + qsort(document->reverse_link_lookup, document->nlinks, sizeof(*document->reverse_link_lookup), comp_ints); + } + } document->links_sorted = 1; } diff --git a/src/viewer/text/link.c b/src/viewer/text/link.c index 24f4047f2..86a4aeacb 100644 --- a/src/viewer/text/link.c +++ b/src/viewer/text/link.c @@ -1281,6 +1281,15 @@ jump_to_link_number(struct session *ses, struct document_view *doc_view, int n) current_link_hover(doc_view); } +static int +compare(const void *a, const void *b) +{ + int na = ((struct reverse_link_lookup *)a)->number; + int nb = ((struct reverse_link_lookup *)b)->number; + + return na - nb; +} + /** This is common backend for goto_link_number() and try_document_key(). */ static void goto_link_number_do(struct session *ses, struct document_view *doc_view, int n) @@ -1289,6 +1298,18 @@ goto_link_number_do(struct session *ses, struct document_view *doc_view, int n) assert(ses && doc_view && doc_view->document); if_assert_failed return; + + struct document *document = doc_view->document; + + if (document->reverse_link_lookup) { + struct reverse_link_lookup key = { .number = n+1, .i = 0 }; + struct reverse_link_lookup *res = bsearch(&key, document->reverse_link_lookup, document->nlinks, sizeof(*res), compare); + + if (res == NULL) { + return; + } + n = res->i; + } if (n < 0 || n >= doc_view->document->nlinks) return; jump_to_link_number(ses, doc_view, n);