% pdftables.w % % Copyright 2009-2010 Taco Hoekwater % % This file is part of LuaTeX. % % LuaTeX is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free % Software Foundation; either version 2 of the License, or (at your % option) any later version. % % LuaTeX is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public % License for more details. % % You should have received a copy of the GNU General Public License along % with LuaTeX; if not, see . @ @c #include "ptexlib.h" @ @c const char *pdf_obj_typenames[PDF_OBJ_TYPE_MAX + 1] = { "font", "outline", "dest", "obj", "xform", "ximage", "thread", "pagestream", "page", "pages", "catalog", "info", "link", "annot", "annots", "bead", "beads", "objstm", "others" }; int pdf_last_annot; int pdf_last_link; int pdf_last_obj; int pdf_retval; /* global multi-purpose return value */ int pdf_cur_form; /* the form being output */ @ AVL sort entry into |avl_table[]| @c static int compare_info(const void *pa, const void *pb, void *param) { const oentry *a = (const oentry *) pa; const oentry *b = (const oentry *) pb; (void) param; if (a->u_type == b->u_type) { if (a->u_type == union_type_int) return ((a->u.int0 < b->u.int0 ? -1 : (a->u.int0 > b->u.int0 ? 1 : 0))); else /* string type */ return strcmp(a->u.str0, b->u.str0); } else if (a->u_type == union_type_int) { return -1; } else { return 1; } } static void avl_put_obj(PDF pdf, int t, oentry * oe) { void **pp; if (pdf->obj_tree[t] == NULL) { pdf->obj_tree[t] = avl_create(compare_info, NULL, &avl_xallocator); if (pdf->obj_tree[t] == NULL) formatted_error("pdf backend","avl_create() pdf->obj_tree failed"); } pp = avl_probe(pdf->obj_tree[t], oe); if (pp == NULL) formatted_error("pdf backend","avl_probe() out of memory in insertion"); } static void avl_put_int_obj(PDF pdf, int int0, int objptr, int t) { oentry *oe = xtalloc(1, oentry); oe->u.int0 = int0; oe->u_type = union_type_int; oe->objptr = objptr; avl_put_obj(pdf, t, oe); } static void avl_put_str_obj(PDF pdf, char *str0, int objptr, int t) { oentry *oe = xtalloc(1, oentry); oe->u.str0 = str0; /* no xstrdup() here */ oe->u_type = union_type_cstring; oe->objptr = objptr; avl_put_obj(pdf, t, oe); } static int avl_find_int_obj(PDF pdf, int t, int i) { oentry *p; oentry tmp; tmp.u.int0 = i; tmp.u_type = union_type_int; if (pdf->obj_tree[t] == NULL) return 0; p = (oentry *) avl_find(pdf->obj_tree[t], &tmp); if (p == NULL) return 0; return p->objptr; } static int avl_find_str_obj(PDF pdf, int t, char *s) { oentry *p; oentry tmp; tmp.u.str0 = s; tmp.u_type = union_type_cstring; if (pdf->obj_tree[t] == NULL) return 0; p = (oentry *) avl_find(pdf->obj_tree[t], &tmp); if (p == NULL) return 0; return p->objptr; } @ Create an object with type |t| and identifier |i| @c int pdf_create_obj(PDF pdf, int t, int i) { int a; char *ss = NULL; if (pdf->obj_ptr == sup_obj_tab_size) overflow("indirect objects table size", (unsigned) pdf->obj_tab_size); if (pdf->obj_ptr == pdf->obj_tab_size) { a = pdf->obj_tab_size / 5; if (pdf->obj_tab_size < sup_obj_tab_size - a) pdf->obj_tab_size = pdf->obj_tab_size + a; else pdf->obj_tab_size = sup_obj_tab_size; pdf->obj_tab = xreallocarray(pdf->obj_tab, obj_entry, (unsigned) pdf->obj_tab_size); } pdf->obj_ptr++; obj_info(pdf, pdf->obj_ptr) = i; obj_type(pdf, pdf->obj_ptr) = t; set_obj_fresh(pdf, pdf->obj_ptr); obj_aux(pdf, pdf->obj_ptr) = 0; if (i < 0) { ss = makecstring(-i); avl_put_str_obj(pdf, ss, pdf->obj_ptr, t); } else if (i > 0) avl_put_int_obj(pdf, i, pdf->obj_ptr, t); if (t <= HEAD_TAB_MAX) { obj_link(pdf, pdf->obj_ptr) = pdf->head_tab[t]; pdf->head_tab[t] = pdf->obj_ptr; if ((t == obj_type_dest) && (i < 0)) append_dest_name(pdf, makecstring(-obj_info(pdf, pdf->obj_ptr)), pdf->obj_ptr); /* why not just -i */ } return pdf->obj_ptr; } @ @c int find_obj(PDF pdf, int t, int i, boolean byname) { char *ss = NULL; int ret; if (byname) { ss = makecstring(i); ret = avl_find_str_obj(pdf, t, ss); free(ss); } else { ret = avl_find_int_obj(pdf, t, i); } return ret; } @ The following function finds an object with identifier |i| and type |t|. Identifier |i| is either an integer or a token list index. If no such object exists then it will be created. This function is used mainly to find destination for link annotations and outlines; however it is also used in |ship_out| (to check whether a Page object already exists) so we need to declare it together with subroutines needed in |hlist_out| and |vlist_out|. @c int pdf_get_obj(PDF pdf, int t, int i, boolean byname) { int r; str_number s; if (byname > 0) { s = tokens_to_string(i); r = find_obj(pdf, t, s, true); } else { s = 0; r = find_obj(pdf, t, i, false); } if (r == 0) { if (byname > 0) { r = pdf_create_obj(pdf, t, -s); s = 0; } else { r = pdf_create_obj(pdf, t, i); } if (t == obj_type_dest) set_obj_dest_ptr(pdf, r, null); } if (s != 0) flush_str(s); return r; } @ object checking @c void check_obj_exists(PDF pdf, int objnum) { if (objnum < 0 || objnum > pdf->obj_ptr) normal_error("pdf backend", "cannot find referenced object"); } void check_obj_type(PDF pdf, int t, int objnum) { int u; check_obj_exists(pdf, objnum); u = obj_type(pdf, objnum); if (t != u) { formatted_error("pdf backend", "referenced object has wrong type %s; should be %s", pdf_obj_typenames[u], pdf_obj_typenames[t]); } } @ @c void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, scaled_whd alt_rule, scaled margin) { scaledpos ll, ur; /* positions relative to cur */ scaledpos pos_ll, pos_ur, tmp; posstructure localpos; localpos.dir = pdf->posstruct->dir; ll.h = 0; /* pdf contains current point on page */ if (is_running(alt_rule.dp)) ll.v = depth(parent_box) - cur.v; else ll.v = alt_rule.dp; if (is_running(alt_rule.wd)) ur.h = width(parent_box) - cur.h; else ur.h = alt_rule.wd; if (is_running(alt_rule.ht)) ur.v = -height(parent_box) - cur.v; else ur.v = -alt_rule.ht; synch_pos_with_cur(&localpos, pdf->posstruct, ll); pos_ll = localpos.pos; synch_pos_with_cur(&localpos, pdf->posstruct, ur); pos_ur = localpos.pos; if (pos_ll.h > pos_ur.h) { tmp.h = pos_ll.h; pos_ll.h = pos_ur.h; pos_ur.h = tmp.h; } if (pos_ll.v > pos_ur.v) { tmp.v = pos_ll.v; pos_ll.v = pos_ur.v; pos_ur.v = tmp.v; } if (global_shipping_mode == SHIPPING_PAGE && matrixused()) { matrixtransformrect(pos_ll.h, pos_ll.v, pos_ur.h, pos_ur.v); pos_ll.h = getllx(); pos_ll.v = getlly(); pos_ur.h = geturx(); pos_ur.v = getury(); } pdf_ann_left(p) = pos_ll.h - margin; pdf_ann_bottom(p) = pos_ll.v - margin; pdf_ann_right(p) = pos_ur.h + margin; pdf_ann_top(p) = pos_ur.v + margin; } @ @c void libpdffinish(PDF pdf) { strbuf_free(pdf->fb); xfree(pdf->job_id_string); fm_free(); t1_free(); enc_free(); epdf_free(); ttf_free(); glyph_unicode_free(); zip_free(pdf); }