summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2017-02-02 15:55:40 +0100
committerTor Andersson <tor.andersson@artifex.com>2017-02-06 17:10:40 +0100
commitc100c4c77a88782ba5c4634994171db611952d44 (patch)
tree5dc9e03790f4eebd0586ed21510465ad8f831a85
parent931f3d9a6c3ab0fbfa3e365fe040e1b86c47e9fc (diff)
downloadmupdf-c100c4c77a88782ba5c4634994171db611952d44.tar.xz
Add bookmarks so we can find a location after reflowing a document.
-rw-r--r--include/mupdf/fitz/document.h17
-rw-r--r--include/mupdf/html.h2
-rw-r--r--platform/java/example/Viewer.java4
-rw-r--r--platform/java/mupdf_native.c36
-rw-r--r--platform/java/mupdf_native.h16
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/Document.java3
-rw-r--r--source/fitz/document.c14
-rw-r--r--source/html/epub-doc.c35
-rw-r--r--source/html/html-doc.c18
-rw-r--r--source/html/html-layout.c85
10 files changed, 227 insertions, 3 deletions
diff --git a/include/mupdf/fitz/document.h b/include/mupdf/fitz/document.h
index d7dbd447..c66dc2ca 100644
--- a/include/mupdf/fitz/document.h
+++ b/include/mupdf/fitz/document.h
@@ -16,6 +16,7 @@ typedef struct fz_document_s fz_document;
typedef struct fz_document_handler_s fz_document_handler;
typedef struct fz_page_s fz_page;
typedef struct fz_annot_s fz_annot;
+typedef intptr_t fz_bookmark;
typedef enum
{
@@ -36,6 +37,8 @@ typedef int (fz_document_resolve_link_fn)(fz_context *ctx, fz_document *doc, con
typedef int (fz_document_count_pages_fn)(fz_context *ctx, fz_document *doc);
typedef fz_page *(fz_document_load_page_fn)(fz_context *ctx, fz_document *doc, int number);
typedef int (fz_document_lookup_metadata_fn)(fz_context *ctx, fz_document *doc, const char *key, char *buf, int size);
+typedef fz_bookmark (fz_document_make_bookmark_fn)(fz_context *ctx, fz_document *doc, int page);
+typedef int (fz_document_lookup_bookmark_fn)(fz_context *ctx, fz_document *doc, fz_bookmark mark);
typedef fz_link *(fz_page_load_links_fn)(fz_context *ctx, fz_page *page);
typedef fz_rect *(fz_page_bound_page_fn)(fz_context *ctx, fz_page *page, fz_rect *);
@@ -100,6 +103,8 @@ struct fz_document_s
fz_document_has_permission_fn *has_permission;
fz_document_load_outline_fn *load_outline;
fz_document_layout_fn *layout;
+ fz_document_make_bookmark_fn *make_bookmark;
+ fz_document_lookup_bookmark_fn *lookup_bookmark;
fz_document_resolve_link_fn *resolve_link;
fz_document_count_pages_fn *count_pages;
fz_document_load_page_fn *load_page;
@@ -217,6 +222,18 @@ int fz_is_document_reflowable(fz_context *ctx, fz_document *doc);
void fz_layout_document(fz_context *ctx, fz_document *doc, float w, float h, float em);
/*
+ Create a bookmark for the given page, which can be used to find the
+ same location after the document has been laid out with different
+ parameters.
+*/
+fz_bookmark fz_make_bookmark(fz_context *ctx, fz_document *doc, int page);
+
+/*
+ Find a bookmark and return its page number.
+*/
+int fz_lookup_bookmark(fz_context *ctx, fz_document *doc, fz_bookmark mark);
+
+/*
fz_count_pages: Return the number of pages in document
May return 0 for documents with no pages.
diff --git a/include/mupdf/html.h b/include/mupdf/html.h
index be0808d1..e23a606d 100644
--- a/include/mupdf/html.h
+++ b/include/mupdf/html.h
@@ -283,5 +283,7 @@ void fz_draw_html(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, fz_html
float fz_find_html_target(fz_context *ctx, fz_html *html, const char *id);
fz_link *fz_load_html_links(fz_context *ctx, fz_html *html, int page, const char *base_uri);
void fz_drop_html(fz_context *ctx, fz_html *html);
+fz_bookmark fz_make_html_bookmark(fz_context *ctx, fz_html *html, int page);
+int fz_lookup_html_bookmark(fz_context *ctx, fz_html *html, fz_bookmark mark);
#endif
diff --git a/platform/java/example/Viewer.java b/platform/java/example/Viewer.java
index 1361a538..a924cf4b 100644
--- a/platform/java/example/Viewer.java
+++ b/platform/java/example/Viewer.java
@@ -383,12 +383,12 @@ public class Viewer extends Frame implements WindowListener, ActionListener, Ite
}
if (layoutEm != oldLayoutEm) {
- float oldPos = (pageNumber + 0.5f) / (float)pageCount;
+ long mark = doc.makeBookmark(pageNumber);
doc.layout(layoutWidth, layoutHeight, layoutEm);
updateOutline();
pageCount = doc.countPages();
pageLabel.setText("/ " + pageCount);
- pageNumber = (int)(oldPos * pageCount);
+ pageNumber = doc.findBookmark(mark);
}
if (zoomLevel != oldZoomLevel || pageNumber != oldPageNumber || layoutEm != oldLayoutEm || searchHits != oldSearchHits)
diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c
index cbb3dd7a..aec932c4 100644
--- a/platform/java/mupdf_native.c
+++ b/platform/java/mupdf_native.c
@@ -4222,6 +4222,42 @@ FUN(Document_loadOutline)(JNIEnv *env, jobject self)
return joutline;
}
+JNIEXPORT jlong JNICALL
+FUN(Document_makeBookmark)(JNIEnv *env, jobject self, jint page)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *doc = from_Document(env, self);
+ fz_bookmark mark = 0;
+
+ fz_try(ctx)
+ mark = fz_make_bookmark(ctx, doc, page);
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ return 0;
+ }
+
+ return mark;
+}
+
+JNIEXPORT jint JNICALL
+FUN(Document_findBookmark)(JNIEnv *env, jobject self, jlong mark)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *doc = from_Document(env, self);
+ int page = -1;
+
+ fz_try(ctx)
+ page = fz_lookup_bookmark(ctx, doc, mark);
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ return -1;
+ }
+
+ return page;
+}
+
JNIEXPORT jobject JNICALL
FUN(Document_toPDFDocument)(JNIEnv *env, jobject self)
{
diff --git a/platform/java/mupdf_native.h b/platform/java/mupdf_native.h
index 3e6c51b3..8b0b2fe3 100644
--- a/platform/java/mupdf_native.h
+++ b/platform/java/mupdf_native.h
@@ -683,6 +683,22 @@ JNIEXPORT void JNICALL Java_com_artifex_mupdf_fitz_Document_layout
/*
* Class: com_artifex_mupdf_fitz_Document
+ * Method: makeBookmark
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL Java_com_artifex_mupdf_fitz_Document_makeBookmark
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: com_artifex_mupdf_fitz_Document
+ * Method: findBookmark
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_artifex_mupdf_fitz_Document_findBookmark
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_artifex_mupdf_fitz_Document
* Method: isUnencryptedPDF
* Signature: ()Z
*/
diff --git a/platform/java/src/com/artifex/mupdf/fitz/Document.java b/platform/java/src/com/artifex/mupdf/fitz/Document.java
index 29cad4db..1fc21c13 100644
--- a/platform/java/src/com/artifex/mupdf/fitz/Document.java
+++ b/platform/java/src/com/artifex/mupdf/fitz/Document.java
@@ -49,6 +49,9 @@ public class Document
public native boolean isReflowable();
public native void layout(float width, float height, float em);
+ public native long makeBookmark(int page);
+ public native int findBookmark(long mark);
+
public native boolean isUnencryptedPDF();
public native PDFDocument toPDFDocument();
diff --git a/source/fitz/document.c b/source/fitz/document.c
index 684c8523..41abb736 100644
--- a/source/fitz/document.c
+++ b/source/fitz/document.c
@@ -182,6 +182,20 @@ fz_is_document_reflowable(fz_context *ctx, fz_document *doc)
return doc ? doc->is_reflowable : 0;
}
+fz_bookmark fz_make_bookmark(fz_context *ctx, fz_document *doc, int page)
+{
+ if (doc && doc->make_bookmark)
+ return doc->make_bookmark(ctx, doc, page);
+ return (fz_bookmark)page;
+}
+
+int fz_lookup_bookmark(fz_context *ctx, fz_document *doc, fz_bookmark mark)
+{
+ if (doc && doc->lookup_bookmark)
+ return doc->lookup_bookmark(ctx, doc, mark);
+ return (int)mark;
+}
+
int
fz_needs_password(fz_context *ctx, fz_document *doc)
{
diff --git a/source/html/epub-doc.c b/source/html/epub-doc.c
index d220816d..3cfa3f06 100644
--- a/source/html/epub-doc.c
+++ b/source/html/epub-doc.c
@@ -178,6 +178,39 @@ epub_load_links(fz_context *ctx, fz_page *page_)
return NULL;
}
+static fz_bookmark
+epub_make_bookmark(fz_context *ctx, fz_document *doc_, int n)
+{
+ epub_document *doc = (epub_document*)doc_;
+ epub_chapter *ch;
+ int count = 0;
+
+ for (ch = doc->spine; ch; ch = ch->next)
+ {
+ int cn = ceilf(ch->html->root->h / ch->html->page_h);
+ if (n < count + cn)
+ return fz_make_html_bookmark(ctx, ch->html, n - count);
+ count += cn;
+ }
+
+ return 0;
+}
+
+static int
+epub_lookup_bookmark(fz_context *ctx, fz_document *doc_, fz_bookmark mark)
+{
+ epub_document *doc = (epub_document*)doc_;
+ epub_chapter *ch;
+
+ for (ch = doc->spine; ch; ch = ch->next)
+ {
+ int p = fz_lookup_html_bookmark(ctx, ch->html, mark);
+ if (p != -1)
+ return ch->start + p;
+ }
+ return -1;
+}
+
static fz_page *
epub_load_page(fz_context *ctx, fz_document *doc_, int number)
{
@@ -440,6 +473,8 @@ epub_init(fz_context *ctx, fz_archive *zip)
doc->super.layout = epub_layout;
doc->super.load_outline = epub_load_outline;
doc->super.resolve_link = epub_resolve_link;
+ doc->super.make_bookmark = epub_make_bookmark;
+ doc->super.lookup_bookmark = epub_lookup_bookmark;
doc->super.count_pages = epub_count_pages;
doc->super.load_page = epub_load_page;
doc->super.lookup_metadata = epub_lookup_metadata;
diff --git a/source/html/html-doc.c b/source/html/html-doc.c
index c19d5049..47225c06 100644
--- a/source/html/html-doc.c
+++ b/source/html/html-doc.c
@@ -97,6 +97,20 @@ htdoc_load_links(fz_context *ctx, fz_page *page_)
return fz_load_html_links(ctx, doc->html, page->number, "");
}
+static fz_bookmark
+htdoc_make_bookmark(fz_context *ctx, fz_document *doc_, int page)
+{
+ html_document *doc = (html_document*)doc_;
+ return fz_make_html_bookmark(ctx, doc->html, page);
+}
+
+static int
+htdoc_lookup_bookmark(fz_context *ctx, fz_document *doc_, fz_bookmark mark)
+{
+ html_document *doc = (html_document*)doc_;
+ return fz_lookup_html_bookmark(ctx, doc->html, mark);
+}
+
static fz_page *
htdoc_load_page(fz_context *ctx, fz_document *doc_, int number)
{
@@ -111,7 +125,7 @@ htdoc_load_page(fz_context *ctx, fz_document *doc_, int number)
return (fz_page*)page;
}
-int
+static int
htdoc_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, int size)
{
if (!strcmp(key, "format"))
@@ -162,6 +176,8 @@ htdoc_open_document(fz_context *ctx, const char *filename)
doc->super.drop_document = htdoc_drop_document;
doc->super.layout = htdoc_layout;
doc->super.resolve_link = htdoc_resolve_link;
+ doc->super.make_bookmark = htdoc_make_bookmark;
+ doc->super.lookup_bookmark = htdoc_lookup_bookmark;
doc->super.count_pages = htdoc_count_pages;
doc->super.load_page = htdoc_load_page;
doc->super.lookup_metadata = htdoc_lookup_metadata;
diff --git a/source/html/html-layout.c b/source/html/html-layout.c
index f06e6cbd..1cac935b 100644
--- a/source/html/html-layout.c
+++ b/source/html/html-layout.c
@@ -2101,6 +2101,91 @@ fz_find_html_target(fz_context *ctx, fz_html *html, const char *id)
return find_box_target(html->root, id);
}
+static fz_html_flow *
+make_flow_bookmark(fz_context *ctx, fz_html_flow *flow, float y)
+{
+ while (flow)
+ {
+ if (flow->y >= y)
+ return flow;
+ flow = flow->next;
+ }
+ return NULL;
+}
+
+static fz_html_flow *
+make_box_bookmark(fz_context *ctx, fz_html_box *box, float y)
+{
+ fz_html_flow *mark;
+ while (box)
+ {
+ if (box->type == BOX_FLOW)
+ {
+ if (box->y >= y)
+ {
+ mark = make_flow_bookmark(ctx, box->flow_head, y);
+ if (mark)
+ return mark;
+ }
+ }
+ else
+ {
+ mark = make_box_bookmark(ctx, box->down, y);
+ if (mark)
+ return mark;
+ }
+ box = box->next;
+ }
+ return NULL;
+}
+
+fz_bookmark
+fz_make_html_bookmark(fz_context *ctx, fz_html *html, int page)
+{
+ return (fz_bookmark)make_box_bookmark(ctx, html->root, page * html->page_h);
+}
+
+static int
+lookup_flow_bookmark(fz_context *ctx, fz_html_flow *flow, fz_html_flow *mark)
+{
+ while (flow)
+ {
+ if (flow == mark)
+ return 1;
+ flow = flow->next;
+ }
+ return 0;
+}
+
+static int
+lookup_box_bookmark(fz_context *ctx, fz_html_box *box, fz_html_flow *mark)
+{
+ while (box)
+ {
+ if (box->type == BOX_FLOW)
+ {
+ if (lookup_flow_bookmark(ctx, box->flow_head, mark))
+ return 1;
+ }
+ else
+ {
+ if (lookup_box_bookmark(ctx, box->down, mark))
+ return 1;
+ }
+ box = box->next;
+ }
+ return 0;
+}
+
+int
+fz_lookup_html_bookmark(fz_context *ctx, fz_html *html, fz_bookmark mark)
+{
+ fz_html_flow *flow = (fz_html_flow*)mark;
+ if (flow && lookup_box_bookmark(ctx, html->root, flow))
+ return (int)(flow->y / html->page_h);
+ return -1;
+}
+
static char *concat_text(fz_context *ctx, fz_xml *root)
{
fz_xml *node;