pdf_annot * pdf_create_annot(fz_context *ctx, pdf_page *page, fz_annot_type type) { pdf_annot *annot = NULL; pdf_document *doc = page->doc; pdf_obj *annot_obj = pdf_new_dict(ctx, 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.0f, 0.0f, 0.0f, 0.0f}; const char *type_str; pdf_obj *annot_arr; type_str = pdf_string_from_annot_type(ctx, type); if (type == PDF_ANNOT_UNKNOWN) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot create unknown annotation"); annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME_Annots); if (annot_arr == NULL) { annot_arr = pdf_new_array(ctx, doc, 0); pdf_dict_put_drop(ctx, page->obj, PDF_NAME_Annots, annot_arr); } pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Type, PDF_NAME_Annot); pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Subtype, pdf_new_name(ctx, doc, type_str)); pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &rect)); /* Make printable as default */ pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_F, pdf_new_int(ctx, doc, PDF_ANNOT_IS_PRINT)); annot = pdf_new_annot(ctx, page); annot->ap = NULL; /* 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(ctx, doc); pdf_update_object(ctx, doc, ind_obj_num, annot_obj); ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0); pdf_array_push(ctx, annot_arr, ind_obj); annot->obj = pdf_keep_obj(ctx, ind_obj); /* Linking must be done after any call that might throw because pdf_drop_annots 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(ctx, annot_obj); pdf_drop_obj(ctx, ind_obj); } fz_catch(ctx) { pdf_drop_annots(ctx, annot); fz_rethrow(ctx); } return annot; }
void pdf_load_annots(fz_context *ctx, pdf_page *page, pdf_obj *annots) { pdf_document *doc = page->doc; pdf_annot *annot, **itr; pdf_obj *obj, *ap, *as, *n; int i, len, keep_annot; fz_var(annot); fz_var(itr); fz_var(keep_annot); itr = &page->annots; len = pdf_array_len(ctx, annots); /* Create an initial linked list of pdf_annot structures with only the obj field filled in. We do this because update_appearance has the potential to change the annot array, so we don't want to be iterating through the array while that happens. */ fz_try(ctx) { for (i = 0; i < len; i++) { obj = pdf_array_get(ctx, annots, i); annot = pdf_new_annot(ctx, page); *itr = annot; annot->obj = pdf_keep_obj(ctx, obj); itr = &annot->next; } } fz_catch(ctx) { pdf_drop_annots(ctx, page->annots); page->annots = NULL; fz_rethrow(ctx); } /* Iterate through the newly created annot linked list, using a double pointer to facilitate deleting broken annotations. */ itr = &page->annots; while (*itr) { annot = *itr; fz_try(ctx) { pdf_hotspot *hp = &doc->hotspot; n = NULL; if (doc->update_appearance) doc->update_appearance(ctx, doc, annot); obj = annot->obj; ap = pdf_dict_get(ctx, obj, PDF_NAME_AP); as = pdf_dict_get(ctx, obj, PDF_NAME_AS); /* We only collect annotations with an appearance * stream into this list, so remove any that don't * (such as links) and continue. */ keep_annot = pdf_is_dict(ctx, ap); if (!keep_annot) break; if (hp->num == pdf_to_num(ctx, obj) && (hp->state & HOTSPOT_POINTER_DOWN)) { n = pdf_dict_get(ctx, ap, PDF_NAME_D); /* down state */ } if (n == NULL) n = pdf_dict_get(ctx, ap, PDF_NAME_N); /* normal state */ /* lookup current state in sub-dictionary */ if (!pdf_is_stream(ctx, n)) n = pdf_dict_get(ctx, n, as); annot->ap = NULL; if (pdf_is_stream(ctx, n)) { annot->ap = pdf_load_xobject(ctx, doc, n); annot->ap_iteration = annot->ap->iteration; } else fz_warn(ctx, "no appearance stream for annotation %d 0 R", pdf_to_num(ctx, annot->obj)); if (obj == doc->focus_obj) doc->focus = annot; /* Move to next item in the linked list */ itr = &annot->next; } fz_catch(ctx) { if (fz_caught(ctx) == FZ_ERROR_TRYLATER) { pdf_drop_annots(ctx, page->annots); page->annots = NULL; fz_rethrow(ctx); } keep_annot = 0; fz_warn(ctx, "ignoring broken annotation"); } if (!keep_annot) { /* Move to next item in the linked list, dropping this one */ *itr = annot->next; annot->next = NULL; /* Required because pdf_drop_annots follows the "next" chain */ pdf_drop_annots(ctx, annot); } } page->annot_tailp = itr; }