From f22be2b82fe1afe733dd0e6c3ab9d26a39acd39b Mon Sep 17 00:00:00 2001
From: Robin Watts <robin.watts@artifex.com>
Date: Fri, 7 Oct 2016 19:56:00 +0100
Subject: Bug 697123: epub: Adjust anchor positions using fragments.

---
 source/html/epub-doc.c | 51 +++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 7 deletions(-)

(limited to 'source/html')

diff --git a/source/html/epub-doc.c b/source/html/epub-doc.c
index 19b8c0a8..fbcc1a86 100644
--- a/source/html/epub-doc.c
+++ b/source/html/epub-doc.c
@@ -34,6 +34,35 @@ struct epub_page_s
 	int number;
 };
 
+static int
+find_anchor_flow(fz_html_flow *flow, const char *anchor, float page_h, int *page)
+{
+	while (flow)
+	{
+		if (flow->type == FLOW_ANCHOR && !strcmp(anchor, flow->content.text))
+		{
+			*page += (int)(flow->y / page_h);
+			return 1;
+		}
+		flow = flow->next;
+	}
+	return 0;
+}
+
+static int
+find_anchor(fz_html *box, const char *anchor, float page_h, int *page)
+{
+	while (box)
+	{
+		if (box->flow_head && find_anchor_flow(box->flow_head, anchor, page_h, page))
+			return 1;
+		if (box->down && find_anchor(box->down, anchor, page_h, page))
+			return 1;
+		box = box->next;
+	}
+	return 0;
+}
+
 static void
 epub_update_link_dests(fz_context *ctx, epub_document *doc, fz_outline *node)
 {
@@ -43,13 +72,24 @@ epub_update_link_dests(fz_context *ctx, epub_document *doc, fz_outline *node)
 	{
 		if (node->dest.kind == FZ_LINK_GOTO)
 		{
+			const char *dest = node->dest.ld.gotor.dest;
+			const char *s = strchr(dest, '#');
+			int n = s ? s - dest : strlen(dest);
+			if (s && s[1] == 0)
+				s = NULL;
+
 			for (ch = doc->spine; ch; ch = ch->next)
 			{
-				if (!strcmp(ch->path, node->dest.ld.gotor.dest))
+				if (strncmp(ch->path, dest, n) || ch->path[n] != 0)
+					continue;
+				node->dest.ld.gotor.page = ch->start;
+				if (s)
 				{
-					node->dest.ld.gotor.page = ch->start;
-					break;
+					/* Search for a matching fragment */
+					if (find_anchor(ch->box, s+1, ch->page_h, &node->dest.ld.gotor.page))
+						continue;
 				}
+				break;
 			}
 		}
 		epub_update_link_dests(ctx, doc, node->down);
@@ -240,7 +280,7 @@ epub_parse_chapter(fz_context *ctx, epub_document *doc, const char *path)
 static fz_outline *
 epub_parse_ncx_imp(fz_context *ctx, epub_document *doc, fz_xml *node, char *base_uri)
 {
-	char path[2048], *s;
+	char path[2048];
 	fz_outline *outline, *head, **tailp;
 
 	head = NULL;
@@ -258,9 +298,6 @@ epub_parse_ncx_imp(fz_context *ctx, epub_document *doc, fz_xml *node, char *base
 			fz_strlcat(path, content, sizeof path);
 			fz_urldecode(path);
 			fz_cleanname(path);
-			s = strchr(path, '#');
-			if (s)
-				*s = 0;
 
 			*tailp = outline = fz_new_outline(ctx);
 			tailp = &(*tailp)->next;
-- 
cgit v1.2.3