summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2011-12-23 12:59:24 +0000
committerRobin Watts <robin.watts@artifex.com>2011-12-23 13:18:42 +0000
commit73e548cdd564c6c2099ceafaa4019a7dbb188a30 (patch)
treee2d0b498abf0f0057d7d565d6b465226e6491d60
parentcc4dd0f8358d3de1594cc530b8f2691bccf194f0 (diff)
downloadmupdf-73e548cdd564c6c2099ceafaa4019a7dbb188a30.tar.xz
Generalise pdf_links to be fz_links.
Move to a non-pdf specific type for links. PDF specific parsing is done in pdf_annots.c as before, but the essential type (and handling functions for that type) are in a new file fitz/base_link.c. The new type is more expressive than before; specifically all the possible PDF modes are expressable in it. Hopefully this should allow XPS links to be represented too.
-rw-r--r--android/jni/Core.mk1
-rw-r--r--apps/pdfapp.c32
-rw-r--r--apps/pdfapp.h2
-rw-r--r--fitz/base_link.c57
-rw-r--r--fitz/fitz.h60
-rw-r--r--pdf/mupdf.h27
-rw-r--r--pdf/pdf_annot.c224
-rw-r--r--pdf/pdf_outline.c7
-rw-r--r--pdf/pdf_page.c2
-rw-r--r--win32/libmupdf.vcproj4
10 files changed, 317 insertions, 99 deletions
diff --git a/android/jni/Core.mk b/android/jni/Core.mk
index 259f0398..0ed43751 100644
--- a/android/jni/Core.mk
+++ b/android/jni/Core.mk
@@ -25,6 +25,7 @@ LOCAL_SRC_FILES := \
$(MY_ROOT)/fitz/base_geometry.c \
$(MY_ROOT)/fitz/base_getopt.c \
$(MY_ROOT)/fitz/base_hash.c \
+ $(MY_ROOT)/fitz/base_link.c \
$(MY_ROOT)/fitz/base_memory.c \
$(MY_ROOT)/fitz/base_object.c \
$(MY_ROOT)/fitz/base_string.c \
diff --git a/apps/pdfapp.c b/apps/pdfapp.c
index 849b0d18..cf136261 100644
--- a/apps/pdfapp.c
+++ b/apps/pdfapp.c
@@ -238,7 +238,7 @@ void pdfapp_close(pdfapp_t *app)
app->page_text = NULL;
if (app->page_links)
- pdf_free_link(app->ctx, app->page_links);
+ fz_free_link(app->ctx, app->page_links);
app->page_links = NULL;
if (app->doctitle)
@@ -394,7 +394,7 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
if (app->page_text)
fz_free_text_span(app->ctx, app->page_text);
if (app->page_links)
- pdf_free_link(app->ctx, app->page_links);
+ fz_free_link(app->ctx, app->page_links);
if (app->xref)
pdfapp_loadpage_pdf(app);
@@ -467,25 +467,13 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
fz_flush_warnings(app->ctx);
}
-static void pdfapp_gotouri(pdfapp_t *app, fz_obj *uri)
+static void pdfapp_gotouri(pdfapp_t *app, char *uri)
{
- char *buf;
- int n = fz_to_str_len(uri);
- buf = fz_malloc(app->ctx, n + 1);
- memcpy(buf, fz_to_str_buf(uri), n);
- buf[n] = 0;
- winopenuri(app, buf);
- fz_free(app->ctx, buf);
+ winopenuri(app, uri);
}
-static void pdfapp_gotopage(pdfapp_t *app, fz_obj *obj)
+static void pdfapp_gotopage(pdfapp_t *app, int number)
{
- int number;
-
- number = pdf_find_page_number(app->xref, obj);
- if (number < 0)
- return;
-
if (app->histlen + 1 == 256)
{
memmove(app->hist, app->hist + 1, sizeof(int) * 255);
@@ -1025,7 +1013,7 @@ void pdfapp_onkey(pdfapp_t *app, int c)
void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state)
{
- pdf_link *link;
+ fz_link *link;
fz_matrix ctm;
fz_point p;
@@ -1049,10 +1037,10 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta
wincursor(app, HAND);
if (btn == 1 && state == 1)
{
- if (link->kind == PDF_LINK_URI)
- pdfapp_gotouri(app, link->dest);
- else if (link->kind == PDF_LINK_GOTO)
- pdfapp_gotopage(app, fz_array_get(link->dest, 0)); /* [ pageobj ... ] */
+ if (link->kind == FZ_LINK_URI)
+ pdfapp_gotouri(app, link->dest.uri.uri);
+ else if (link->kind == FZ_LINK_GOTO)
+ pdfapp_gotopage(app, link->dest.gotor.page);
return;
}
}
diff --git a/apps/pdfapp.h b/apps/pdfapp.h
index c9fe1d4f..22b6ad0d 100644
--- a/apps/pdfapp.h
+++ b/apps/pdfapp.h
@@ -49,7 +49,7 @@ struct pdfapp_s
float page_rotate;
fz_display_list *page_list;
fz_text_span *page_text;
- pdf_link *page_links;
+ fz_link *page_links;
/* snapback history */
int hist[256];
diff --git a/fitz/base_link.c b/fitz/base_link.c
new file mode 100644
index 00000000..d8d7e3ab
--- /dev/null
+++ b/fitz/base_link.c
@@ -0,0 +1,57 @@
+#include "fitz.h"
+
+static void
+free_link_dest(fz_context *ctx, fz_link_kind kind, fz_link_dest *dest)
+{
+ switch(kind)
+ {
+ case FZ_LINK_GOTO:
+ break;
+ case FZ_LINK_URI:
+ fz_free(ctx, dest->uri.uri);
+ break;
+ case FZ_LINK_LAUNCH:
+ fz_free(ctx, dest->launch.file_spec);
+ break;
+ case FZ_LINK_NAMED:
+ fz_free(ctx, dest->named.named);
+ break;
+ case FZ_LINK_GOTOR:
+ fz_free(ctx, dest->gotor.file_spec);
+ break;
+ }
+}
+
+fz_link *
+fz_new_link(fz_context *ctx, fz_link_kind kind, fz_rect bbox, fz_link_dest dest)
+{
+ fz_link *link;
+
+ fz_try(ctx)
+ {
+ link = fz_malloc_struct(ctx, fz_link);
+ }
+ fz_catch(ctx)
+ {
+ free_link_dest(ctx, kind, &dest);
+ fz_rethrow(ctx);
+ }
+ link->kind = kind;
+ link->rect = bbox;
+ link->next = NULL;
+ return link;
+}
+
+void
+fz_free_link(fz_context *ctx, fz_link *link)
+{
+ fz_link *next;
+
+ while (link)
+ {
+ next = link->next;
+ free_link_dest(ctx, link->kind, &link->dest);
+ fz_free(ctx, link);
+ link = next;
+ }
+}
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 589f22ee..9ac43d48 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -1233,4 +1233,64 @@ enum
FZ_BLEND_KNOCKOUT = 32
};
+/* Links */
+
+typedef struct fz_link_s fz_link;
+
+typedef union fz_link_dest_s fz_link_dest;
+
+typedef enum fz_link_kind_e
+{
+ FZ_LINK_GOTO = 0,
+ FZ_LINK_URI,
+ FZ_LINK_LAUNCH,
+ FZ_LINK_NAMED,
+ FZ_LINK_GOTOR
+} fz_link_kind;
+
+enum {
+ fz_link_flag_l_valid = 1, /* lt.x is valid */
+ fz_link_flag_t_valid = 2, /* lt.y is valid */
+ fz_link_flag_r_valid = 4, /* rb.x is valid */
+ fz_link_flag_b_valid = 8, /* rb.y is valid */
+ fz_link_flag_fit_h = 16, /* Fit horizontally */
+ fz_link_flag_fit_v = 32, /* Fit vertically */
+ fz_link_flag_r_is_zoom = 64 /* rb.x is actually a zoom figure */
+};
+
+union fz_link_dest_s
+{
+ struct {
+ int page;
+ int flags;
+ fz_point lt;
+ fz_point rb;
+ char *file_spec;
+ int new_window;
+ } gotor;
+ struct {
+ char *uri;
+ int is_map;
+ } uri;
+ struct {
+ char *file_spec;
+ int new_window;
+ } launch;
+ struct {
+ char *named;
+ } named;
+};
+
+
+struct fz_link_s
+{
+ fz_link_kind kind;
+ fz_rect rect;
+ fz_link_dest dest;
+ fz_link *next;
+};
+
+fz_link *fz_new_link(fz_context *ctx, fz_link_kind, fz_rect bbox, fz_link_dest dest);
+void fz_free_link(fz_context *ctx, fz_link *);
+
#endif
diff --git a/pdf/mupdf.h b/pdf/mupdf.h
index 7db1ca36..ca173b12 100644
--- a/pdf/mupdf.h
+++ b/pdf/mupdf.h
@@ -409,26 +409,8 @@ void pdf_debug_font(pdf_font_desc *fontdesc);
* Interactive features
*/
-typedef struct pdf_link_s pdf_link;
typedef struct pdf_annot_s pdf_annot;
-typedef enum pdf_link_kind_e
-{
- PDF_LINK_GOTO = 0,
- PDF_LINK_URI,
- PDF_LINK_LAUNCH,
- PDF_LINK_NAMED,
- PDF_LINK_ACTION,
-} pdf_link_kind;
-
-struct pdf_link_s
-{
- pdf_link_kind kind;
- fz_rect rect;
- fz_obj *dest;
- pdf_link *next;
-};
-
struct pdf_annot_s
{
fz_obj *obj;
@@ -438,15 +420,16 @@ struct pdf_annot_s
pdf_annot *next;
};
+fz_link_dest pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest);
+
fz_obj *pdf_lookup_dest(pdf_xref *xref, fz_obj *needle);
fz_obj *pdf_lookup_name(pdf_xref *xref, char *which, fz_obj *needle);
fz_obj *pdf_load_name_tree(pdf_xref *xref, char *which);
fz_outline *pdf_load_outline(pdf_xref *xref);
-pdf_link *pdf_load_link(pdf_xref *xref, fz_obj *dict);
-void pdf_load_links(pdf_link **, pdf_xref *, fz_obj *annots);
-void pdf_free_link(fz_context *ctx, pdf_link *link);
+fz_link *pdf_load_link(pdf_xref *xref, fz_obj *dict);
+void pdf_load_links(fz_link **, pdf_xref *, fz_obj *annots);
void pdf_load_annots(pdf_annot **, pdf_xref *, fz_obj *annots);
void pdf_free_annot(fz_context *ctx, pdf_annot *link);
@@ -464,7 +447,7 @@ struct pdf_page_s
int transparency;
fz_obj *resources;
fz_buffer *contents;
- pdf_link *links;
+ fz_link *links;
pdf_annot *annots;
};
diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c
index 79bdb4ff..ba4d509d 100644
--- a/pdf/pdf_annot.c
+++ b/pdf/pdf_annot.c
@@ -1,21 +1,6 @@
#include "fitz.h"
#include "mupdf.h"
-void
-pdf_free_link(fz_context *ctx, pdf_link *link)
-{
- pdf_link *next;
-
- while (link)
- {
- next = link->next;
- if (link->dest)
- fz_drop_obj(link->dest);
- fz_free(ctx, link);
- link = next;
- }
-}
-
static fz_obj *
resolve_dest(pdf_xref *xref, fz_obj *dest)
{
@@ -42,14 +27,155 @@ resolve_dest(pdf_xref *xref, fz_obj *dest)
return NULL;
}
-pdf_link *
+fz_link_dest
+pdf_parse_link_dest(pdf_xref *xref, fz_obj *dest)
+{
+ fz_link_dest ld;
+ fz_obj *obj;
+ int read = 0;
+
+ obj = fz_array_get(dest, 0);
+ if (fz_is_int(obj))
+ ld.gotor.page = fz_to_int(obj)-1;
+ else
+ ld.gotor.page = pdf_find_page_number(xref, obj);
+
+ ld.gotor.flags = 0;
+ ld.gotor.lt.x = 0;
+ ld.gotor.lt.y = 0;
+ ld.gotor.rb.x = 0;
+ ld.gotor.rb.y = 0;
+ ld.gotor.file_spec = NULL;
+ ld.gotor.new_window = 0;
+
+ obj = fz_array_get(dest, 1);
+ if (!fz_is_name(obj))
+ return ld;
+
+ if (!strcmp("XYZ", fz_to_name(obj)))
+ {
+ read = 1+16;
+ ld.gotor.flags |= fz_link_flag_r_is_zoom;
+ }
+ else if ((!strcmp("Fit", fz_to_name(obj))) || (!strcmp("FitB", fz_to_name(obj))))
+ {
+ read = 0;
+ ld.gotor.flags |= fz_link_flag_fit_h;
+ ld.gotor.flags |= fz_link_flag_fit_v;
+ }
+ else if ((!strcmp("FitH", fz_to_name(obj))) || (!strcmp("FitBH", fz_to_name(obj))))
+ {
+ read = 32;
+ ld.gotor.flags |= fz_link_flag_fit_h;
+ }
+ else if ((!strcmp("FitV", fz_to_name(obj))) || (!strcmp("FitBV", fz_to_name(obj))))
+ {
+ read = 1;
+ ld.gotor.flags |= fz_link_flag_fit_v;
+ }
+ else if (!strcmp("FitR", fz_to_name(obj)))
+ {
+ read = 1+2+4+8;
+ ld.gotor.flags |= fz_link_flag_fit_h;
+ ld.gotor.flags |= fz_link_flag_fit_v;
+ }
+
+ if (read & 1)
+ {
+ obj = fz_array_get(dest, 2);
+ if (fz_is_int(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_l_valid;
+ ld.gotor.lt.x = fz_to_int(obj);
+ }
+ else if (fz_is_real(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_l_valid;
+ ld.gotor.lt.x = fz_to_real(obj);
+ }
+ }
+ if (read & 2)
+ {
+ obj = fz_array_get(dest, 3);
+ if (fz_is_int(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_b_valid;
+ ld.gotor.rb.y = fz_to_int(obj);
+ }
+ else if (fz_is_real(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_b_valid;
+ ld.gotor.rb.y = fz_to_real(obj);
+ }
+ }
+ if (read & 4)
+ {
+ obj = fz_array_get(dest, 4);
+ if (fz_is_int(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_r_valid;
+ ld.gotor.rb.x = fz_to_int(obj);
+ }
+ else if (fz_is_real(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_r_valid;
+ ld.gotor.rb.x = fz_to_real(obj);
+ }
+ }
+ if (read & (8+16+32))
+ {
+ if (read & 8)
+ obj = fz_array_get(dest, 5);
+ else if (read & 16)
+ obj = fz_array_get(dest, 3);
+ else
+ obj = fz_array_get(dest, 2);
+ if (fz_is_int(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_t_valid;
+ ld.gotor.lt.x = fz_to_int(obj);
+ }
+ else if (fz_is_real(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_t_valid;
+ ld.gotor.lt.x = fz_to_real(obj);
+ }
+ }
+ if (read & 16)
+ {
+ obj = fz_array_get(dest, 4);
+ if (fz_is_int(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_r_valid;
+ ld.gotor.rb.x = fz_to_int(obj);
+ }
+ else if (fz_is_real(obj))
+ {
+ ld.gotor.flags |= fz_link_flag_r_valid;
+ ld.gotor.rb.x = fz_to_real(obj);
+ }
+ }
+
+ /* Duplicate the values out for the sake of stupid clients */
+ if ((ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid)) == fz_link_flag_l_valid)
+ ld.gotor.rb.x = ld.gotor.lt.x;
+ if ((ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid | fz_link_flag_r_is_zoom)) == fz_link_flag_r_valid)
+ ld.gotor.lt.x = ld.gotor.rb.x;
+ if ((ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_t_valid)
+ ld.gotor.rb.y = ld.gotor.lt.y;
+ if ((ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_b_valid)
+ ld.gotor.lt.y = ld.gotor.rb.y;
+
+ return ld;
+}
+
+fz_link *
pdf_load_link(pdf_xref *xref, fz_obj *dict)
{
- fz_obj *dest;
+ fz_obj *dest = NULL;
fz_obj *action;
fz_obj *obj;
fz_rect bbox;
- pdf_link_kind kind;
fz_context *ctx = xref->ctx;
dest = NULL;
@@ -63,8 +189,10 @@ pdf_load_link(pdf_xref *xref, fz_obj *dict)
obj = fz_dict_gets(dict, "Dest");
if (obj)
{
- kind = PDF_LINK_GOTO;
+ fz_link_dest ld;
dest = resolve_dest(xref, obj);
+ ld = pdf_parse_link_dest(xref, dest);
+ return fz_new_link(ctx, FZ_LINK_GOTO, bbox, ld);
}
action = fz_dict_gets(dict, "A");
@@ -76,54 +204,54 @@ pdf_load_link(pdf_xref *xref, fz_obj *dict)
if (action)
{
obj = fz_dict_gets(action, "S");
- if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "GoTo"))
+ if (!fz_is_name(obj))
{
- kind = PDF_LINK_GOTO;
- dest = resolve_dest(xref, fz_dict_gets(action, "D"));
}
- else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "URI"))
+ else if (!strcmp(fz_to_name(obj), "GoTo"))
{
- kind = PDF_LINK_URI;
- dest = fz_dict_gets(action, "URI");
+ fz_link_dest ld;
+ dest = resolve_dest(xref, fz_dict_gets(action, "D"));
+ ld = pdf_parse_link_dest(xref, dest);
+ return fz_new_link(ctx, FZ_LINK_GOTO, bbox, ld);
}
- else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Launch"))
+ else if (!strcmp(fz_to_name(obj), "URI"))
{
- kind = PDF_LINK_LAUNCH;
- dest = fz_dict_gets(action, "F");
+ fz_link_dest ld;
+ ld.uri.is_map = fz_to_int(fz_dict_gets(action, "IsMap"));
+ ld.uri.uri = pdf_to_utf8(ctx, fz_dict_gets(action, "URI"));
+ return fz_new_link(ctx, FZ_LINK_URI, bbox, ld);
}
- else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Named"))
+ else if (!strcmp(fz_to_name(obj), "Launch"))
{
- kind = PDF_LINK_NAMED;
- dest = fz_dict_gets(action, "N");
+ fz_link_dest ld;
+ ld.launch.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F"));
+ ld.launch.new_window = fz_to_int(fz_dict_gets(action, "NewWindow"));
+ return fz_new_link(ctx, FZ_LINK_LAUNCH, bbox, ld);
}
- else if (fz_is_name(obj) && (!strcmp(fz_to_name(obj), "GoToR")))
+ else if (!strcmp(fz_to_name(obj), "Named"))
{
- kind = PDF_LINK_ACTION;
- dest = action;
+ fz_link_dest ld;
+ ld.named.named = pdf_to_utf8(ctx, fz_dict_gets(action, "N"));
+ return fz_new_link(ctx, FZ_LINK_NAMED, bbox, ld);
}
- else
+ else if (!strcmp(fz_to_name(obj), "GoToR"))
{
- dest = NULL;
+ fz_link_dest ld;
+ dest = resolve_dest(xref, fz_dict_gets(action, "D"));
+ ld = pdf_parse_link_dest(xref, dest);
+ ld.gotor.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F"));
+ ld.gotor.new_window = fz_to_int(fz_dict_gets(action, "NewWindow"));
+ return fz_new_link(ctx, FZ_LINK_GOTOR, bbox, ld);
}
}
- if (dest)
- {
- pdf_link *link = fz_malloc_struct(ctx, pdf_link);
- link->kind = kind;
- link->rect = bbox;
- link->dest = fz_keep_obj(dest);
- link->next = NULL;
- return link;
- }
-
return NULL;
}
void
-pdf_load_links(pdf_link **linkp, pdf_xref *xref, fz_obj *annots)
+pdf_load_links(fz_link **linkp, pdf_xref *xref, fz_obj *annots)
{
- pdf_link *link, *head, *tail;
+ fz_link *link, *head, *tail;
fz_obj *obj;
int i, n;
diff --git a/pdf/pdf_outline.c b/pdf/pdf_outline.c
index 8a33d8e2..3f6b745b 100644
--- a/pdf/pdf_outline.c
+++ b/pdf/pdf_outline.c
@@ -5,7 +5,6 @@ static fz_outline *
pdf_load_outline_imp(pdf_xref *xref, fz_obj *dict)
{
fz_context *ctx = xref->ctx;
- pdf_link *link;
fz_outline *node;
fz_obj *obj;
@@ -25,10 +24,8 @@ pdf_load_outline_imp(pdf_xref *xref, fz_obj *dict)
if (fz_dict_gets(dict, "Dest") || fz_dict_gets(dict, "A"))
{
- link = pdf_load_link(xref, dict);
- if (link && link->kind == PDF_LINK_GOTO)
- node->page = pdf_find_page_number(xref, fz_array_get(link->dest, 0));
- pdf_free_link(xref->ctx, link);
+ fz_link_dest ld = pdf_parse_link_dest(xref, dict);
+ node->page = ld.gotor.page;
}
obj = fz_dict_gets(dict, "First");
diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c
index a9e99e52..05af3b60 100644
--- a/pdf/pdf_page.c
+++ b/pdf/pdf_page.c
@@ -363,7 +363,7 @@ pdf_free_page(fz_context *ctx, pdf_page *page)
if (page->contents)
fz_drop_buffer(ctx, page->contents);
if (page->links)
- pdf_free_link(ctx, page->links);
+ fz_free_link(ctx, page->links);
if (page->annots)
pdf_free_annot(ctx, page->annots);
fz_free(ctx, page);
diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj
index 663f0268..bd24cb54 100644
--- a/win32/libmupdf.vcproj
+++ b/win32/libmupdf.vcproj
@@ -355,6 +355,10 @@
>
</File>
<File
+ RelativePath="..\fitz\base_link.c"
+ >
+ </File>
+ <File
RelativePath="..\fitz\base_memory.c"
>
</File>