summaryrefslogtreecommitdiff
path: root/source/pdf
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2014-03-20 15:20:25 +0100
committerRobin Watts <robin.watts@artifex.com>2014-03-25 16:44:42 +0000
commit95361b7f10880776f0db3030030842d94ba341a9 (patch)
tree4d14b9474d0f3a970349b4ff722b86822a7330e4 /source/pdf
parentdb6353067cf545f4ca6fd854c8e8b4c4145dc537 (diff)
downloadmupdf-95361b7f10880776f0db3030030842d94ba341a9.tar.xz
Break dependency of pdf-annot.c to graphics library.
Diffstat (limited to 'source/pdf')
-rw-r--r--source/pdf/pdf-annot-edit.c480
-rw-r--r--source/pdf/pdf-annot.c481
2 files changed, 481 insertions, 480 deletions
diff --git a/source/pdf/pdf-annot-edit.c b/source/pdf/pdf-annot-edit.c
new file mode 100644
index 00000000..1e82accb
--- /dev/null
+++ b/source/pdf/pdf-annot-edit.c
@@ -0,0 +1,480 @@
+#include "mupdf/pdf.h"
+
+#define TEXT_ANNOT_SIZE (25.0)
+
+static const char *annot_type_str(fz_annot_type type)
+{
+ switch (type)
+ {
+ case FZ_ANNOT_TEXT: return "Text";
+ case FZ_ANNOT_LINK: return "Link";
+ case FZ_ANNOT_FREETEXT: return "FreeText";
+ case FZ_ANNOT_LINE: return "Line";
+ case FZ_ANNOT_SQUARE: return "Square";
+ case FZ_ANNOT_CIRCLE: return "Circle";
+ case FZ_ANNOT_POLYGON: return "Polygon";
+ case FZ_ANNOT_POLYLINE: return "PolyLine";
+ case FZ_ANNOT_HIGHLIGHT: return "Highlight";
+ case FZ_ANNOT_UNDERLINE: return "Underline";
+ case FZ_ANNOT_SQUIGGLY: return "Squiggly";
+ case FZ_ANNOT_STRIKEOUT: return "StrikeOut";
+ case FZ_ANNOT_STAMP: return "Stamp";
+ case FZ_ANNOT_CARET: return "Caret";
+ case FZ_ANNOT_INK: return "Ink";
+ case FZ_ANNOT_POPUP: return "Popup";
+ case FZ_ANNOT_FILEATTACHMENT: return "FileAttachment";
+ case FZ_ANNOT_SOUND: return "Sound";
+ case FZ_ANNOT_MOVIE: return "Movie";
+ case FZ_ANNOT_WIDGET: return "Widget";
+ case FZ_ANNOT_SCREEN: return "Screen";
+ case FZ_ANNOT_PRINTERMARK: return "PrinterMark";
+ case FZ_ANNOT_TRAPNET: return "TrapNet";
+ case FZ_ANNOT_WATERMARK: return "Watermark";
+ case FZ_ANNOT_3D: return "3D";
+ default: return "";
+ }
+}
+
+void
+pdf_update_annot(pdf_document *doc, pdf_annot *annot)
+{
+ pdf_obj *obj, *ap, *as, *n;
+ fz_context *ctx = doc->ctx;
+
+ if (doc->update_appearance)
+ doc->update_appearance(doc, annot);
+
+ obj = annot->obj;
+
+ ap = pdf_dict_gets(obj, "AP");
+ as = pdf_dict_gets(obj, "AS");
+
+ if (pdf_is_dict(ap))
+ {
+ pdf_hotspot *hp = &doc->hotspot;
+
+ n = NULL;
+
+ if (hp->num == pdf_to_num(obj)
+ && hp->gen == pdf_to_gen(obj)
+ && (hp->state & HOTSPOT_POINTER_DOWN))
+ {
+ n = pdf_dict_gets(ap, "D"); /* down state */
+ }
+
+ if (n == NULL)
+ n = pdf_dict_gets(ap, "N"); /* normal state */
+
+ /* lookup current state in sub-dictionary */
+ if (!pdf_is_stream(doc, pdf_to_num(n), pdf_to_gen(n)))
+ n = pdf_dict_get(n, as);
+
+ pdf_drop_xobject(ctx, annot->ap);
+ annot->ap = NULL;
+
+ if (pdf_is_stream(doc, pdf_to_num(n), pdf_to_gen(n)))
+ {
+ fz_try(ctx)
+ {
+ annot->ap = pdf_load_xobject(doc, n);
+ pdf_transform_annot(annot);
+ annot->ap_iteration = annot->ap->iteration;
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
+ fz_warn(ctx, "ignoring broken annotation");
+ }
+ }
+ }
+}
+
+pdf_annot *
+pdf_create_annot(pdf_document *doc, pdf_page *page, fz_annot_type type)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_annot *annot = NULL;
+ pdf_obj *annot_obj = pdf_new_dict(doc, 0);
+ pdf_obj *ind_obj = NULL;
+
+ fz_var(annot);
+ fz_var(ind_obj);
+ fz_try(ctx)
+ {
+ int ind_obj_num;
+ fz_rect rect = {0.0, 0.0, 0.0, 0.0};
+ const char *type_str = annot_type_str(type);
+ pdf_obj *annot_arr = pdf_dict_gets(page->me, "Annots");
+ if (annot_arr == NULL)
+ {
+ annot_arr = pdf_new_array(doc, 0);
+ pdf_dict_puts_drop(page->me, "Annots", annot_arr);
+ }
+
+ pdf_dict_puts_drop(annot_obj, "Type", pdf_new_name(doc, "Annot"));
+
+ pdf_dict_puts_drop(annot_obj, "Subtype", pdf_new_name(doc, type_str));
+ pdf_dict_puts_drop(annot_obj, "Rect", pdf_new_rect(doc, &rect));
+
+ /* Make printable as default */
+ pdf_dict_puts_drop(annot_obj, "F", pdf_new_int(doc, F_Print));
+
+ annot = fz_malloc_struct(ctx, pdf_annot);
+ annot->page = page;
+ annot->rect = rect;
+ annot->pagerect = rect;
+ annot->ap = NULL;
+ annot->widget_type = PDF_WIDGET_TYPE_NOT_WIDGET;
+ annot->annot_type = type;
+
+ /*
+ Both annotation object and annotation structure are now created.
+ Insert the object in the hierarchy and the structure in the
+ page's array.
+ */
+ ind_obj_num = pdf_create_object(doc);
+ pdf_update_object(doc, ind_obj_num, annot_obj);
+ ind_obj = pdf_new_indirect(doc, ind_obj_num, 0);
+ pdf_array_push(annot_arr, ind_obj);
+ annot->obj = pdf_keep_obj(ind_obj);
+
+ /*
+ Linking must be done after any call that might throw because
+ pdf_free_annot below actually frees a list. Put the new annot
+ at the end of the list, so that it will be drawn last.
+ */
+ *page->annot_tailp = annot;
+ page->annot_tailp = &annot->next;
+
+ doc->dirty = 1;
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(annot_obj);
+ pdf_drop_obj(ind_obj);
+ }
+ fz_catch(ctx)
+ {
+ pdf_free_annot(ctx, annot);
+ fz_rethrow(ctx);
+ }
+
+ return annot;
+}
+
+void
+pdf_delete_annot(pdf_document *doc, pdf_page *page, pdf_annot *annot)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_annot **annotptr;
+ pdf_obj *old_annot_arr;
+ pdf_obj *annot_arr;
+
+ if (annot == NULL)
+ return;
+
+ /* Remove annot from page's list */
+ for (annotptr = &page->annots; *annotptr; annotptr = &(*annotptr)->next)
+ {
+ if (*annotptr == annot)
+ break;
+ }
+
+ /* Check the passed annotation was of this page */
+ if (*annotptr == NULL)
+ return;
+
+ *annotptr = annot->next;
+ /* If the removed annotation was the last in the list adjust the end pointer */
+ if (*annotptr == NULL)
+ page->annot_tailp = annotptr;
+
+ /* Stick it in the deleted list */
+ annot->next = page->deleted_annots;
+ page->deleted_annots = annot;
+
+ pdf_drop_xobject(ctx, annot->ap);
+ annot->ap = NULL;
+
+ /* Recreate the "Annots" array with this annot removed */
+ old_annot_arr = pdf_dict_gets(page->me, "Annots");
+
+ if (old_annot_arr)
+ {
+ int i, n = pdf_array_len(old_annot_arr);
+ annot_arr = pdf_new_array(doc, n?(n-1):0);
+
+ fz_try(ctx)
+ {
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *obj = pdf_array_get(old_annot_arr, i);
+
+ if (obj != annot->obj)
+ pdf_array_push(annot_arr, obj);
+ }
+
+ if (pdf_is_indirect(old_annot_arr))
+ pdf_update_object(doc, pdf_to_num(old_annot_arr), annot_arr);
+ else
+ pdf_dict_puts(page->me, "Annots", annot_arr);
+
+ if (pdf_is_indirect(annot->obj))
+ pdf_delete_object(doc, pdf_to_num(annot->obj));
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(annot_arr);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+ }
+
+ pdf_drop_obj(annot->obj);
+ annot->obj = NULL;
+ doc->dirty = 1;
+}
+
+void
+pdf_set_markup_annot_quadpoints(pdf_document *doc, pdf_annot *annot, fz_point *qp, int n)
+{
+ fz_matrix ctm;
+ pdf_obj *arr = pdf_new_array(doc, n*2);
+ int i;
+
+ fz_invert_matrix(&ctm, &annot->page->ctm);
+
+ pdf_dict_puts_drop(annot->obj, "QuadPoints", arr);
+
+ for (i = 0; i < n; i++)
+ {
+ fz_point pt = qp[i];
+ pdf_obj *r;
+
+ fz_transform_point(&pt, &ctm);
+ r = pdf_new_real(doc, pt.x);
+ pdf_array_push_drop(arr, r);
+ r = pdf_new_real(doc, pt.y);
+ pdf_array_push_drop(arr, r);
+ }
+}
+
+static void update_rect(fz_context *ctx, pdf_annot *annot)
+{
+ pdf_to_rect(ctx, pdf_dict_gets(annot->obj, "Rect"), &annot->rect);
+ annot->pagerect = annot->rect;
+ fz_transform_rect(&annot->pagerect, &annot->page->ctm);
+}
+
+void
+pdf_set_ink_annot_list(pdf_document *doc, pdf_annot *annot, fz_point *pts, int *counts, int ncount, float color[3], float thickness)
+{
+ fz_context *ctx = doc->ctx;
+ fz_matrix ctm;
+ pdf_obj *list = pdf_new_array(doc, ncount);
+ pdf_obj *bs, *col;
+ fz_rect rect;
+ int i, k = 0;
+
+ fz_invert_matrix(&ctm, &annot->page->ctm);
+
+ pdf_dict_puts_drop(annot->obj, "InkList", list);
+
+ for (i = 0; i < ncount; i++)
+ {
+ int j;
+ pdf_obj *arc = pdf_new_array(doc, counts[i]);
+
+ pdf_array_push_drop(list, arc);
+
+ for (j = 0; j < counts[i]; j++)
+ {
+ fz_point pt = pts[k];
+
+ fz_transform_point(&pt, &ctm);
+
+ if (i == 0 && j == 0)
+ {
+ rect.x0 = rect.x1 = pt.x;
+ rect.y0 = rect.y1 = pt.y;
+ }
+ else
+ {
+ fz_include_point_in_rect(&rect, &pt);
+ }
+
+ pdf_array_push_drop(arc, pdf_new_real(doc, pt.x));
+ pdf_array_push_drop(arc, pdf_new_real(doc, pt.y));
+ k++;
+ }
+ }
+
+ /*
+ Expand the rectangle by thickness all around. We cannot use
+ fz_expand_rect because the rectangle might be empty in the
+ single point case
+ */
+ if (k > 0)
+ {
+ rect.x0 -= thickness;
+ rect.y0 -= thickness;
+ rect.x1 += thickness;
+ rect.y1 += thickness;
+ }
+
+ pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &rect));
+ update_rect(ctx, annot);
+
+ bs = pdf_new_dict(doc, 1);
+ pdf_dict_puts_drop(annot->obj, "BS", bs);
+ pdf_dict_puts_drop(bs, "W", pdf_new_real(doc, thickness));
+
+ col = pdf_new_array(doc, 3);
+ pdf_dict_puts_drop(annot->obj, "C", col);
+ for (i = 0; i < 3; i++)
+ pdf_array_push_drop(col, pdf_new_real(doc, color[i]));
+}
+
+static void find_free_font_name(pdf_obj *fdict, char *buf, int buf_size)
+{
+ int i;
+
+ /* Find a number X such that /FX doesn't occur as a key in fdict */
+ for (i = 0; 1; i++)
+ {
+ snprintf(buf, buf_size, "F%d", i);
+
+ if (!pdf_dict_gets(fdict, buf))
+ break;
+ }
+}
+
+void pdf_set_text_annot_position(pdf_document *doc, pdf_annot *annot, fz_point pt)
+{
+ fz_matrix ctm;
+ fz_rect rect;
+ int flags;
+
+ fz_invert_matrix(&ctm, &annot->page->ctm);
+ rect.x0 = pt.x;
+ rect.x1 = pt.x + TEXT_ANNOT_SIZE;
+ rect.y0 = pt.y;
+ rect.y1 = pt.y + TEXT_ANNOT_SIZE;
+ fz_transform_rect(&rect, &ctm);
+
+ pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &rect));
+
+ flags = pdf_to_int(pdf_dict_gets(annot->obj, "F"));
+ flags |= (F_NoZoom|F_NoRotate);
+ pdf_dict_puts_drop(annot->obj, "F", pdf_new_int(doc, flags));
+
+ update_rect(doc->ctx, annot);
+}
+
+void pdf_set_annot_contents(pdf_document *doc, pdf_annot *annot, char *text)
+{
+ pdf_dict_puts_drop(annot->obj, "Contents", pdf_new_string(doc, text, strlen(text)));
+}
+
+char *pdf_annot_contents(pdf_document *doc, pdf_annot *annot)
+{
+ return pdf_to_str_buf(pdf_dict_getp(annot->obj, "Contents"));
+}
+
+void pdf_set_free_text_details(pdf_document *doc, pdf_annot *annot, fz_point *pos, char *text, char *font_name, float font_size, float color[3])
+{
+ fz_context *ctx = doc->ctx;
+ char nbuf[32];
+ pdf_obj *dr;
+ pdf_obj *form_fonts;
+ pdf_obj *font = NULL;
+ pdf_obj *ref;
+ pdf_font_desc *font_desc = NULL;
+ pdf_da_info da_info;
+ fz_buffer *fzbuf = NULL;
+ fz_matrix ctm;
+ fz_point page_pos;
+
+ fz_invert_matrix(&ctm, &annot->page->ctm);
+
+ dr = pdf_dict_gets(annot->page->me, "Resources");
+ if (!dr)
+ {
+ dr = pdf_new_dict(doc, 1);
+ pdf_dict_putp_drop(annot->page->me, "Resources", dr);
+ }
+
+ /* Ensure the resource dictionary includes a font dict */
+ form_fonts = pdf_dict_gets(dr, "Font");
+ if (!form_fonts)
+ {
+ form_fonts = pdf_new_dict(doc, 1);
+ pdf_dict_puts_drop(dr, "Font", form_fonts);
+ /* form_fonts is still valid if execution continues past the above call */
+ }
+
+ fz_var(fzbuf);
+ fz_var(font);
+ fz_try(ctx)
+ {
+ unsigned char *da_str;
+ int da_len;
+ fz_rect bounds;
+
+ find_free_font_name(form_fonts, nbuf, sizeof(nbuf));
+
+ font = pdf_new_dict(doc, 5);
+ ref = pdf_new_ref(doc, font);
+ pdf_dict_puts_drop(form_fonts, nbuf, ref);
+
+ pdf_dict_puts_drop(font, "Type", pdf_new_name(doc, "Font"));
+ pdf_dict_puts_drop(font, "Subtype", pdf_new_name(doc, "Type1"));
+ pdf_dict_puts_drop(font, "BaseFont", pdf_new_name(doc, font_name));
+ pdf_dict_puts_drop(font, "Encoding", pdf_new_name(doc, "WinAnsiEncoding"));
+
+ memcpy(da_info.col, color, sizeof(float)*3);
+ da_info.col_size = 3;
+ da_info.font_name = nbuf;
+ da_info.font_size = font_size;
+
+ fzbuf = fz_new_buffer(ctx, 0);
+ pdf_fzbuf_print_da(ctx, fzbuf, &da_info);
+
+ da_len = fz_buffer_storage(ctx, fzbuf, &da_str);
+ pdf_dict_puts_drop(annot->obj, "DA", pdf_new_string(doc, (char *)da_str, da_len));
+
+ /* FIXME: should convert to WinAnsiEncoding */
+ pdf_dict_puts_drop(annot->obj, "Contents", pdf_new_string(doc, text, strlen(text)));
+
+ font_desc = pdf_load_font(doc, NULL, font, 0);
+ pdf_measure_text(ctx, font_desc, (unsigned char *)text, strlen(text), &bounds);
+
+ page_pos = *pos;
+ fz_transform_point(&page_pos, &ctm);
+
+ bounds.x0 *= font_size;
+ bounds.x1 *= font_size;
+ bounds.y0 *= font_size;
+ bounds.y1 *= font_size;
+
+ bounds.x0 += page_pos.x;
+ bounds.x1 += page_pos.x;
+ bounds.y0 += page_pos.y;
+ bounds.y1 += page_pos.y;
+
+ pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &bounds));
+ update_rect(ctx, annot);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(font);
+ fz_drop_buffer(ctx, fzbuf);
+ pdf_drop_font(ctx, font_desc);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
diff --git a/source/pdf/pdf-annot.c b/source/pdf/pdf-annot.c
index 1fcbbcf4..c3440c63 100644
--- a/source/pdf/pdf-annot.c
+++ b/source/pdf/pdf-annot.c
@@ -1,7 +1,5 @@
#include "mupdf/pdf.h"
-#define TEXT_ANNOT_SIZE (25.0)
-
static pdf_obj *
resolve_dest_rec(pdf_document *doc, pdf_obj *dest, fz_link_kind kind, int depth)
{
@@ -383,7 +381,7 @@ pdf_free_annot(fz_context *ctx, pdf_annot *annot)
}
}
-static void
+void
pdf_transform_annot(pdf_annot *annot)
{
fz_rect bbox = annot->ap->bbox;
@@ -462,39 +460,6 @@ fz_annot_type pdf_annot_obj_type(pdf_obj *obj)
return -1;
}
-static const char *annot_type_str(fz_annot_type type)
-{
- switch (type)
- {
- case FZ_ANNOT_TEXT: return "Text";
- case FZ_ANNOT_LINK: return "Link";
- case FZ_ANNOT_FREETEXT: return "FreeText";
- case FZ_ANNOT_LINE: return "Line";
- case FZ_ANNOT_SQUARE: return "Square";
- case FZ_ANNOT_CIRCLE: return "Circle";
- case FZ_ANNOT_POLYGON: return "Polygon";
- case FZ_ANNOT_POLYLINE: return "PolyLine";
- case FZ_ANNOT_HIGHLIGHT: return "Highlight";
- case FZ_ANNOT_UNDERLINE: return "Underline";
- case FZ_ANNOT_SQUIGGLY: return "Squiggly";
- case FZ_ANNOT_STRIKEOUT: return "StrikeOut";
- case FZ_ANNOT_STAMP: return "Stamp";
- case FZ_ANNOT_CARET: return "Caret";
- case FZ_ANNOT_INK: return "Ink";
- case FZ_ANNOT_POPUP: return "Popup";
- case FZ_ANNOT_FILEATTACHMENT: return "FileAttachment";
- case FZ_ANNOT_SOUND: return "Sound";
- case FZ_ANNOT_MOVIE: return "Movie";
- case FZ_ANNOT_WIDGET: return "Widget";
- case FZ_ANNOT_SCREEN: return "Screen";
- case FZ_ANNOT_PRINTERMARK: return "PrinterMark";
- case FZ_ANNOT_TRAPNET: return "TrapNet";
- case FZ_ANNOT_WATERMARK: return "Watermark";
- case FZ_ANNOT_3D: return "3D";
- default: return "";
- }
-}
-
void
pdf_load_annots(pdf_document *doc, pdf_page *page, pdf_obj *annots)
{
@@ -624,60 +589,6 @@ pdf_load_annots(pdf_document *doc, pdf_page *page, pdf_obj *annots)
page->annot_tailp = itr;
}
-void
-pdf_update_annot(pdf_document *doc, pdf_annot *annot)
-{
- pdf_obj *obj, *ap, *as, *n;
- fz_context *ctx = doc->ctx;
-
- if (doc->update_appearance)
- doc->update_appearance(doc, annot);
-
- obj = annot->obj;
-
- ap = pdf_dict_gets(obj, "AP");
- as = pdf_dict_gets(obj, "AS");
-
- if (pdf_is_dict(ap))
- {
- pdf_hotspot *hp = &doc->hotspot;
-
- n = NULL;
-
- if (hp->num == pdf_to_num(obj)
- && hp->gen == pdf_to_gen(obj)
- && (hp->state & HOTSPOT_POINTER_DOWN))
- {
- n = pdf_dict_gets(ap, "D"); /* down state */
- }
-
- if (n == NULL)
- n = pdf_dict_gets(ap, "N"); /* normal state */
-
- /* lookup current state in sub-dictionary */
- if (!pdf_is_stream(doc, pdf_to_num(n), pdf_to_gen(n)))
- n = pdf_dict_get(n, as);
-
- pdf_drop_xobject(ctx, annot->ap);
- annot->ap = NULL;
-
- if (pdf_is_stream(doc, pdf_to_num(n), pdf_to_gen(n)))
- {
- fz_try(ctx)
- {
- annot->ap = pdf_load_xobject(doc, n);
- pdf_transform_annot(annot);
- annot->ap_iteration = annot->ap->iteration;
- }
- fz_catch(ctx)
- {
- fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
- fz_warn(ctx, "ignoring broken annotation");
- }
- }
- }
-}
-
pdf_annot *
pdf_first_annot(pdf_document *doc, pdf_page *page)
{
@@ -708,393 +619,3 @@ pdf_annot_type(pdf_annot *annot)
{
return annot->annot_type;
}
-
-pdf_annot *
-pdf_create_annot(pdf_document *doc, pdf_page *page, fz_annot_type type)
-{
- fz_context *ctx = doc->ctx;
- pdf_annot *annot = NULL;
- pdf_obj *annot_obj = pdf_new_dict(doc, 0);
- pdf_obj *ind_obj = NULL;
-
- fz_var(annot);
- fz_var(ind_obj);
- fz_try(ctx)
- {
- int ind_obj_num;
- fz_rect rect = {0.0, 0.0, 0.0, 0.0};
- const char *type_str = annot_type_str(type);
- pdf_obj *annot_arr = pdf_dict_gets(page->me, "Annots");
- if (annot_arr == NULL)
- {
- annot_arr = pdf_new_array(doc, 0);
- pdf_dict_puts_drop(page->me, "Annots", annot_arr);
- }
-
- pdf_dict_puts_drop(annot_obj, "Type", pdf_new_name(doc, "Annot"));
-
- pdf_dict_puts_drop(annot_obj, "Subtype", pdf_new_name(doc, type_str));
- pdf_dict_puts_drop(annot_obj, "Rect", pdf_new_rect(doc, &rect));
-
- /* Make printable as default */
- pdf_dict_puts_drop(annot_obj, "F", pdf_new_int(doc, F_Print));
-
- annot = fz_malloc_struct(ctx, pdf_annot);
- annot->page = page;
- annot->rect = rect;
- annot->pagerect = rect;
- annot->ap = NULL;
- annot->widget_type = PDF_WIDGET_TYPE_NOT_WIDGET;
- annot->annot_type = type;
-
- /*
- Both annotation object and annotation structure are now created.
- Insert the object in the hierarchy and the structure in the
- page's array.
- */
- ind_obj_num = pdf_create_object(doc);
- pdf_update_object(doc, ind_obj_num, annot_obj);
- ind_obj = pdf_new_indirect(doc, ind_obj_num, 0);
- pdf_array_push(annot_arr, ind_obj);
- annot->obj = pdf_keep_obj(ind_obj);
-
- /*
- Linking must be done after any call that might throw because
- pdf_free_annot below actually frees a list. Put the new annot
- at the end of the list, so that it will be drawn last.
- */
- *page->annot_tailp = annot;
- page->annot_tailp = &annot->next;
-
- doc->dirty = 1;
- }
- fz_always(ctx)
- {
- pdf_drop_obj(annot_obj);
- pdf_drop_obj(ind_obj);
- }
- fz_catch(ctx)
- {
- pdf_free_annot(ctx, annot);
- fz_rethrow(ctx);
- }
-
- return annot;
-}
-
-void
-pdf_delete_annot(pdf_document *doc, pdf_page *page, pdf_annot *annot)
-{
- fz_context *ctx = doc->ctx;
- pdf_annot **annotptr;
- pdf_obj *old_annot_arr;
- pdf_obj *annot_arr;
-
- if (annot == NULL)
- return;
-
- /* Remove annot from page's list */
- for (annotptr = &page->annots; *annotptr; annotptr = &(*annotptr)->next)
- {
- if (*annotptr == annot)
- break;
- }
-
- /* Check the passed annotation was of this page */
- if (*annotptr == NULL)
- return;
-
- *annotptr = annot->next;
- /* If the removed annotation was the last in the list adjust the end pointer */
- if (*annotptr == NULL)
- page->annot_tailp = annotptr;
-
- /* Stick it in the deleted list */
- annot->next = page->deleted_annots;
- page->deleted_annots = annot;
-
- pdf_drop_xobject(ctx, annot->ap);
- annot->ap = NULL;
-
- /* Recreate the "Annots" array with this annot removed */
- old_annot_arr = pdf_dict_gets(page->me, "Annots");
-
- if (old_annot_arr)
- {
- int i, n = pdf_array_len(old_annot_arr);
- annot_arr = pdf_new_array(doc, n?(n-1):0);
-
- fz_try(ctx)
- {
- for (i = 0; i < n; i++)
- {
- pdf_obj *obj = pdf_array_get(old_annot_arr, i);
-
- if (obj != annot->obj)
- pdf_array_push(annot_arr, obj);
- }
-
- if (pdf_is_indirect(old_annot_arr))
- pdf_update_object(doc, pdf_to_num(old_annot_arr), annot_arr);
- else
- pdf_dict_puts(page->me, "Annots", annot_arr);
-
- if (pdf_is_indirect(annot->obj))
- pdf_delete_object(doc, pdf_to_num(annot->obj));
- }
- fz_always(ctx)
- {
- pdf_drop_obj(annot_arr);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- }
-
- pdf_drop_obj(annot->obj);
- annot->obj = NULL;
- doc->dirty = 1;
-}
-
-void
-pdf_set_markup_annot_quadpoints(pdf_document *doc, pdf_annot *annot, fz_point *qp, int n)
-{
- fz_matrix ctm;
- pdf_obj *arr = pdf_new_array(doc, n*2);
- int i;
-
- fz_invert_matrix(&ctm, &annot->page->ctm);
-
- pdf_dict_puts_drop(annot->obj, "QuadPoints", arr);
-
- for (i = 0; i < n; i++)
- {
- fz_point pt = qp[i];
- pdf_obj *r;
-
- fz_transform_point(&pt, &ctm);
- r = pdf_new_real(doc, pt.x);
- pdf_array_push_drop(arr, r);
- r = pdf_new_real(doc, pt.y);
- pdf_array_push_drop(arr, r);
- }
-}
-
-static void update_rect(fz_context *ctx, pdf_annot *annot)
-{
- pdf_to_rect(ctx, pdf_dict_gets(annot->obj, "Rect"), &annot->rect);
- annot->pagerect = annot->rect;
- fz_transform_rect(&annot->pagerect, &annot->page->ctm);
-}
-
-void
-pdf_set_ink_annot_list(pdf_document *doc, pdf_annot *annot, fz_point *pts, int *counts, int ncount, float color[3], float thickness)
-{
- fz_context *ctx = doc->ctx;
- fz_matrix ctm;
- pdf_obj *list = pdf_new_array(doc, ncount);
- pdf_obj *bs, *col;
- fz_rect rect;
- int i, k = 0;
-
- fz_invert_matrix(&ctm, &annot->page->ctm);
-
- pdf_dict_puts_drop(annot->obj, "InkList", list);
-
- for (i = 0; i < ncount; i++)
- {
- int j;
- pdf_obj *arc = pdf_new_array(doc, counts[i]);
-
- pdf_array_push_drop(list, arc);
-
- for (j = 0; j < counts[i]; j++)
- {
- fz_point pt = pts[k];
-
- fz_transform_point(&pt, &ctm);
-
- if (i == 0 && j == 0)
- {
- rect.x0 = rect.x1 = pt.x;
- rect.y0 = rect.y1 = pt.y;
- }
- else
- {
- fz_include_point_in_rect(&rect, &pt);
- }
-
- pdf_array_push_drop(arc, pdf_new_real(doc, pt.x));
- pdf_array_push_drop(arc, pdf_new_real(doc, pt.y));
- k++;
- }
- }
-
- /*
- Expand the rectangle by thickness all around. We cannot use
- fz_expand_rect because the rectangle might be empty in the
- single point case
- */
- if (k > 0)
- {
- rect.x0 -= thickness;
- rect.y0 -= thickness;
- rect.x1 += thickness;
- rect.y1 += thickness;
- }
-
- pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &rect));
- update_rect(ctx, annot);
-
- bs = pdf_new_dict(doc, 1);
- pdf_dict_puts_drop(annot->obj, "BS", bs);
- pdf_dict_puts_drop(bs, "W", pdf_new_real(doc, thickness));
-
- col = pdf_new_array(doc, 3);
- pdf_dict_puts_drop(annot->obj, "C", col);
- for (i = 0; i < 3; i++)
- pdf_array_push_drop(col, pdf_new_real(doc, color[i]));
-}
-
-static void find_free_font_name(pdf_obj *fdict, char *buf, int buf_size)
-{
- int i;
-
- /* Find a number X such that /FX doesn't occur as a key in fdict */
- for (i = 0; 1; i++)
- {
- snprintf(buf, buf_size, "F%d", i);
-
- if (!pdf_dict_gets(fdict, buf))
- break;
- }
-}
-
-void pdf_set_text_annot_position(pdf_document *doc, pdf_annot *annot, fz_point pt)
-{
- fz_matrix ctm;
- fz_rect rect;
- int flags;
-
- fz_invert_matrix(&ctm, &annot->page->ctm);
- rect.x0 = pt.x;
- rect.x1 = pt.x + TEXT_ANNOT_SIZE;
- rect.y0 = pt.y;
- rect.y1 = pt.y + TEXT_ANNOT_SIZE;
- fz_transform_rect(&rect, &ctm);
-
- pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &rect));
-
- flags = pdf_to_int(pdf_dict_gets(annot->obj, "F"));
- flags |= (F_NoZoom|F_NoRotate);
- pdf_dict_puts_drop(annot->obj, "F", pdf_new_int(doc, flags));
-
- update_rect(doc->ctx, annot);
-}
-
-void pdf_set_annot_contents(pdf_document *doc, pdf_annot *annot, char *text)
-{
- pdf_dict_puts_drop(annot->obj, "Contents", pdf_new_string(doc, text, strlen(text)));
-}
-
-char *pdf_annot_contents(pdf_document *doc, pdf_annot *annot)
-{
- return pdf_to_str_buf(pdf_dict_getp(annot->obj, "Contents"));
-}
-
-void pdf_set_free_text_details(pdf_document *doc, pdf_annot *annot, fz_point *pos, char *text, char *font_name, float font_size, float color[3])
-{
- fz_context *ctx = doc->ctx;
- char nbuf[32];
- pdf_obj *dr;
- pdf_obj *form_fonts;
- pdf_obj *font = NULL;
- pdf_obj *ref;
- pdf_font_desc *font_desc = NULL;
- pdf_da_info da_info;
- fz_buffer *fzbuf = NULL;
- fz_matrix ctm;
- fz_point page_pos;
-
- fz_invert_matrix(&ctm, &annot->page->ctm);
-
- dr = pdf_dict_gets(annot->page->me, "Resources");
- if (!dr)
- {
- dr = pdf_new_dict(doc, 1);
- pdf_dict_putp_drop(annot->page->me, "Resources", dr);
- }
-
- /* Ensure the resource dictionary includes a font dict */
- form_fonts = pdf_dict_gets(dr, "Font");
- if (!form_fonts)
- {
- form_fonts = pdf_new_dict(doc, 1);
- pdf_dict_puts_drop(dr, "Font", form_fonts);
- /* form_fonts is still valid if execution continues past the above call */
- }
-
- fz_var(fzbuf);
- fz_var(font);
- fz_try(ctx)
- {
- unsigned char *da_str;
- int da_len;
- fz_rect bounds;
-
- find_free_font_name(form_fonts, nbuf, sizeof(nbuf));
-
- font = pdf_new_dict(doc, 5);
- ref = pdf_new_ref(doc, font);
- pdf_dict_puts_drop(form_fonts, nbuf, ref);
-
- pdf_dict_puts_drop(font, "Type", pdf_new_name(doc, "Font"));
- pdf_dict_puts_drop(font, "Subtype", pdf_new_name(doc, "Type1"));
- pdf_dict_puts_drop(font, "BaseFont", pdf_new_name(doc, font_name));
- pdf_dict_puts_drop(font, "Encoding", pdf_new_name(doc, "WinAnsiEncoding"));
-
- memcpy(da_info.col, color, sizeof(float)*3);
- da_info.col_size = 3;
- da_info.font_name = nbuf;
- da_info.font_size = font_size;
-
- fzbuf = fz_new_buffer(ctx, 0);
- pdf_fzbuf_print_da(ctx, fzbuf, &da_info);
-
- da_len = fz_buffer_storage(ctx, fzbuf, &da_str);
- pdf_dict_puts_drop(annot->obj, "DA", pdf_new_string(doc, (char *)da_str, da_len));
-
- /* FIXME: should convert to WinAnsiEncoding */
- pdf_dict_puts_drop(annot->obj, "Contents", pdf_new_string(doc, text, strlen(text)));
-
- font_desc = pdf_load_font(doc, NULL, font, 0);
- pdf_measure_text(ctx, font_desc, (unsigned char *)text, strlen(text), &bounds);
-
- page_pos = *pos;
- fz_transform_point(&page_pos, &ctm);
-
- bounds.x0 *= font_size;
- bounds.x1 *= font_size;
- bounds.y0 *= font_size;
- bounds.y1 *= font_size;
-
- bounds.x0 += page_pos.x;
- bounds.x1 += page_pos.x;
- bounds.y0 += page_pos.y;
- bounds.y1 += page_pos.y;
-
- pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &bounds));
- update_rect(ctx, annot);
- }
- fz_always(ctx)
- {
- pdf_drop_obj(font);
- fz_drop_buffer(ctx, fzbuf);
- pdf_drop_font(ctx, font_desc);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
-}