235 lines
4.2 KiB
C
235 lines
4.2 KiB
C
#include "fitz.h"
|
|
#include "mupdf.h"
|
|
|
|
void
|
|
pdf_free_link(pdf_link *link)
|
|
{
|
|
if (link->next)
|
|
pdf_free_link(link->next);
|
|
if (link->dest)
|
|
fz_drop_obj(link->dest);
|
|
fz_free(link);
|
|
}
|
|
|
|
static fz_obj *
|
|
resolve_dest(pdf_xref *xref, fz_obj *dest)
|
|
{
|
|
if (fz_is_name(dest) || fz_is_string(dest))
|
|
{
|
|
dest = pdf_lookup_dest(xref, dest);
|
|
return resolve_dest(xref, dest);
|
|
}
|
|
|
|
else if (fz_is_array(dest))
|
|
{
|
|
return dest;
|
|
}
|
|
|
|
else if (fz_is_dict(dest))
|
|
{
|
|
dest = fz_dict_gets(dest, "D");
|
|
return resolve_dest(xref, dest);
|
|
}
|
|
|
|
else if (fz_is_indirect(dest))
|
|
return dest;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
pdf_link *
|
|
pdf_load_link(pdf_xref *xref, fz_obj *dict)
|
|
{
|
|
fz_obj *dest;
|
|
fz_obj *action;
|
|
fz_obj *obj;
|
|
fz_rect bbox;
|
|
pdf_link_kind kind;
|
|
|
|
dest = NULL;
|
|
|
|
obj = fz_dict_gets(dict, "Rect");
|
|
if (obj)
|
|
bbox = pdf_to_rect(obj);
|
|
else
|
|
bbox = fz_empty_rect;
|
|
|
|
obj = fz_dict_gets(dict, "Dest");
|
|
if (obj)
|
|
{
|
|
kind = PDF_LINK_GOTO;
|
|
dest = resolve_dest(xref, obj);
|
|
}
|
|
|
|
action = fz_dict_gets(dict, "A");
|
|
|
|
/* fall back to additional action button's down/up action */
|
|
if (!action)
|
|
action = fz_dict_getsa(fz_dict_gets(dict, "AA"), "U", "D");
|
|
|
|
if (action)
|
|
{
|
|
obj = fz_dict_gets(action, "S");
|
|
if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "GoTo"))
|
|
{
|
|
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"))
|
|
{
|
|
kind = PDF_LINK_URI;
|
|
dest = fz_dict_gets(action, "URI");
|
|
}
|
|
else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Launch"))
|
|
{
|
|
kind = PDF_LINK_LAUNCH;
|
|
dest = fz_dict_gets(action, "F");
|
|
}
|
|
else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Named"))
|
|
{
|
|
kind = PDF_LINK_NAMED;
|
|
dest = fz_dict_gets(action, "N");
|
|
}
|
|
else if (fz_is_name(obj) && (!strcmp(fz_to_name(obj), "GoToR")))
|
|
{
|
|
kind = PDF_LINK_ACTION;
|
|
dest = action;
|
|
}
|
|
else
|
|
{
|
|
dest = NULL;
|
|
}
|
|
}
|
|
|
|
if (dest)
|
|
{
|
|
pdf_link *link = fz_malloc(sizeof(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_link *link, *head, *tail;
|
|
fz_obj *obj;
|
|
int i;
|
|
|
|
head = tail = NULL;
|
|
link = NULL;
|
|
|
|
for (i = 0; i < fz_array_len(annots); i++)
|
|
{
|
|
obj = fz_array_get(annots, i);
|
|
link = pdf_load_link(xref, obj);
|
|
if (link)
|
|
{
|
|
if (!head)
|
|
head = tail = link;
|
|
else
|
|
{
|
|
tail->next = link;
|
|
tail = link;
|
|
}
|
|
}
|
|
}
|
|
|
|
*linkp = head;
|
|
}
|
|
|
|
void
|
|
pdf_free_annot(pdf_annot *annot)
|
|
{
|
|
if (annot->next)
|
|
pdf_free_annot(annot->next);
|
|
if (annot->ap)
|
|
pdf_drop_xobject(annot->ap);
|
|
if (annot->obj)
|
|
fz_drop_obj(annot->obj);
|
|
fz_free(annot);
|
|
}
|
|
|
|
static void
|
|
pdf_transform_annot(pdf_annot *annot)
|
|
{
|
|
fz_matrix matrix = annot->ap->matrix;
|
|
fz_rect bbox = annot->ap->bbox;
|
|
fz_rect rect = annot->rect;
|
|
float w, h, x, y;
|
|
|
|
bbox = fz_transform_rect(matrix, bbox);
|
|
w = (rect.x1 - rect.x0) / (bbox.x1 - bbox.x0);
|
|
h = (rect.y1 - rect.y0) / (bbox.y1 - bbox.y0);
|
|
x = rect.x0 - bbox.x0;
|
|
y = rect.y0 - bbox.y0;
|
|
|
|
annot->matrix = fz_concat(fz_scale(w, h), fz_translate(x, y));
|
|
}
|
|
|
|
void
|
|
pdf_load_annots(pdf_annot **annotp, pdf_xref *xref, fz_obj *annots)
|
|
{
|
|
pdf_annot *annot, *head, *tail;
|
|
fz_obj *obj, *ap, *as, *n, *rect;
|
|
pdf_xobject *form;
|
|
fz_error error;
|
|
int i;
|
|
|
|
head = tail = NULL;
|
|
annot = NULL;
|
|
|
|
for (i = 0; i < fz_array_len(annots); i++)
|
|
{
|
|
obj = fz_array_get(annots, i);
|
|
|
|
rect = fz_dict_gets(obj, "Rect");
|
|
ap = fz_dict_gets(obj, "AP");
|
|
as = fz_dict_gets(obj, "AS");
|
|
if (fz_is_dict(ap))
|
|
{
|
|
n = fz_dict_gets(ap, "N"); /* normal state */
|
|
|
|
/* lookup current state in sub-dictionary */
|
|
if (!pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
|
|
n = fz_dict_get(n, as);
|
|
|
|
if (pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
|
|
{
|
|
error = pdf_load_xobject(&form, xref, n);
|
|
if (error)
|
|
{
|
|
fz_catch(error, "ignoring broken annotation");
|
|
continue;
|
|
}
|
|
|
|
annot = fz_malloc(sizeof(pdf_annot));
|
|
annot->obj = fz_keep_obj(obj);
|
|
annot->rect = pdf_to_rect(rect);
|
|
annot->ap = form;
|
|
annot->next = NULL;
|
|
|
|
pdf_transform_annot(annot);
|
|
|
|
if (annot)
|
|
{
|
|
if (!head)
|
|
head = tail = annot;
|
|
else
|
|
{
|
|
tail->next = annot;
|
|
tail = annot;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*annotp = head;
|
|
}
|